Getting unevaluated tcl arguments - tcl

What I want to do is parse an argument to a tcl proc as a string without any evaluation.
For example if I had a trivial proc that just prints out it's arguments:
proc test { args } {
puts "the args are $args"
}
What I'd like to do is call it with:
test [list [expr 1+1] [expr 2+2]]
And NOT have tcl evaluate the [list [expr 1+1] [expr 2+2]]. Or even if it evaluated
it I'd still like to have the original command line. Thus with the trivial "test"
proc above I'd like to be able to return:
the args are [list [expr 1+1] [expr 2+2]]
Is this possible in tcl 8.4?

You cannot do this with Tcl 8.4 (and before); the language design makes this impossible. The fix is to pass in arguments unevaluated (and enclosed in braces). You can then print them however you like. To get their evaluated form, you need to do this inside your procedure:
set evaluated_x [uplevel 1 [list subst $unevaluated_x]]
That's more than a bit messy!
If you were using Tcl 8.5, you'd have another alternative:
set calling_code [dict get [info frame -1] cmd]
The info frame -1 gets a dictionary holding a description of the current command in the context that called the current procedure, and its cmd key is the actual command string prior to substitution rules being applied. That should be about what you want (though be aware that it includes the command name itself).
This is not available for 8.4, nor will it ever be backported. You might want to upgrade!

When passing the arguments into test, enclose them in braces, e.g.:
test {[list [expr 1+1] [expr 2+2]]}

Related

how lappend $varname1 $varname2 will be executed

I have searched for lappend $var1 $var2, but don't find any exact answer, how it will be executed.
% set a {a b c}
a b c
% set b {d e}
d e
% puts [lappend $c $b]
can't read "c": no such variable >>> here it throws error like variable not exist
% puts [lappend $a $b]
{d e} >>> here it doesn't throw any error, can someone explain it and how to print the value of $a, if $a is a new variable
% puts $$A
can't read "A": no such variable
% puts $$a
$a b c
% puts ${$a}
can't read "$a": no such variable
Tcl's got a two level syntax that it applies rigorously to everything. The first level is the Tcl generic syntax, which takes:
lappend $var1 $var2
and parses it out to three words: lappend, a word obtained by reading the variable var1, and a word obtained by reading the variable var2.
Then Tcl dispatches to the command named by the first word (lappend, a Tcl built-in) which applies command syntax handling. In the case of lappend, it's pretty simple: the first argument names a variable and the second and subsequent arguments are words to append to the list in the named variable.
In your case, the first argument that names a variable is obtained by reading another variable (var1) and the value to append to the list is coming from a variable (var2); a name like a b c d e is a legal variable name in Tcl, but it's really awkward to use. And the chance is very high that you don't want to write that: putting variable names in a variable is usually an indicator of confusing code. You can do it, but you hardly ever want to do it (except when you're using the variable name with upvar). You probably really meant to write:
lappend var1 $var2
Tcl is very exact about the distinction between variable names and variable contents. The $ is not decorative! It's there to say “read this variable, right now”, and $var1 is virtually equivalent to [set var1] in semantic terms. (The $ shorthand was later, a Tcl 2.0 feature from way back in the day!)
Tcl also doesn't allow double-dereferencing with $$vrbl. In the rare cases you need it, you do [set $vrbl]. And if you do that, you probably should immediately see if you can use an array instead as that's typically a better choice…
lappend's first parameter is a variable name, not a value. Therefore, in general, it should be:
lappend var1 $var2
where both var1 and var2 are list variables. See the Tcl lappend man page for more details.

variable substitution - each value becomes an argument

When a variable is substituted and the value is a list, is it possible that each value of the list is regarded as one argument?
Here is an example code:
set a "-nonewline hi"
puts $a
What I really want is after the substitution, the puts command becomes puts -nonewline hi instead of puts "-nonewline hi".
Is it possible?
Yes, you can use something like this:
puts {*}$a
In versions prior to 8.5, you would have to use eval:
eval puts $a

Can proc argument be variable

I just tried the following in tclsh:
proc pp {$ag} { puts hi}
pp whatever
To my surprise, this works fine! I had expected a syntax error because the proc argument is a variable. But it seems tcl takes it fine.
Then I experimented:
proc pp {$ag} { puts "hi $ag"}
pp whatever
and
proc pp {$ag} { puts "hi ${$ag}"}
pp whatever
I got error, can't read "ag": no such variable.
This makes me wondering, can proc argument be variable? If not, why not error out in the first script?
The first case works because you never use the parameter to pp.
When you invoke the proc command, the text of the invocation is evaluated just like in any other command invocation. In all the above cases, the third argument (which will become the argument list of the pp command) is is wrapped in braces, which means it won't be evaluated as a variable but as a string of three characters: "$ag" (i.e. the dollar sign is just a regular character here). This is not an error, and does work, just not the way you seem to expect it to.
It's a bit tricky to get the value of the parameter $ag, though. This works:
proc pp {$ag} {puts "hi [set {$ag}]"}
The dollar notation is actually just syntactic sugar for the unary set command. Sometimes the dollar notation won't work, and you need to fall back to an explicit set.
This does work too, though:
proc pp {$ag} {puts "hi ${$ag}"}
So, in your invocations, the third argument to proc isn't really a variable evaluation, it just looks like one. You can of course use an actual variable evaluation in the invocation of proc:
set foo {bar baz}
proc qux $foo {puts $bar ; puts $baz}
qux abc def
# => abc
# => def
What the Tcl interpreter really sees here is:
proc qux {bar baz} {puts $bar ; puts $baz}
Or you can go really crazy:
set foa {proc qux}
set fob {bar}
lappend fob baz
set foc {puts $bar}
set fod "puts \$baz"
{*}$foa $fob [join [list $foc $fod] { ; }]
Which amounts to the same thing as the previous invocation of proc. (If you don't believe me, try list {*}$foa $fob [join [list $foc $fod] { ; }])
This example just looks (and is) weird, but many times it's actually useful to construct new commands within your program, and in those cases it's really nice that the text used in the invocation of proc, like with any other command, is simply text that the evaluation rules of Tcl can be applied to. You can use any kinds of string or list operations on it and join up pieces of text from various sources, even user input (if you can trust it).
Documentation: Tcl evaluation rules including $ and {*}, join, lappend, list, proc, puts, set

give arguments to a script with eval

I don't really understand how to use the eval arguments.
If the script I want to eval is :
set myscript { puts $::argv }
Then I want to call my script like this :
eval $myscript anArgument
And I expect the output to be "anArgument", but instead I have :
can not find channel named ""
while evaluating {eval $script vvv}
When you invoke eval, the command concatenates all its arguments and attempts to evaluate the resulting list (or string if you will, it's the same thing here). So, first the arguments { puts $::argv } and anArgument are concatenated into the list {puts $::argv anArgument}, and then the interpreter tries to evaluate that. If the value of the global variable argv is an empty list, the actual command invoked will be equivalent to puts {} anArgument. puts will try to use {} as a channel identifier to output to, fail and leave an error message.
Now, if what you wanted to do was to pass anArgument to myscript and then eval it as puts anArgument, you should instead write
set myscript {puts $myarg}
set myarg anArgument
eval $myscript
In the first line, the evaluation of $myarg is postponed because of the quoting braces which turn $ into a regular text character. The variable myarg is then set to a value (this can happen anywhere in the code as long as it comes before the eval). In the third line, the script is evaluated, and at that point the argument $myarg is replaced by the value anArgument, which is then printed.
The sort of invocation you attempted is possible, but then you need to use apply instead of eval, and a closure (anonymous function) instead of a script.
set myfunc {myarg {puts $myarg}}
apply $myfunc anArgument
The global variable argv does not pass arguments to a script which is passed to eval: when tclsh or wish is started by the operating system, any command line arguments given are placed in argv, and the value is never changed during execution unless you change it yourself (don't do that, it's just confusing).
Documentation: apply, eval, puts, set
argv is documented here.

Is there any C scope like utility in tcl

In software development it is often very useful to be able to find the callers of a function because this is the way to understand how code works and what other parts of the program expect from a function. cscope can find the callers and callees of functions, but it is not a compiler and it does that by searching the text for keywords.
I am wondering if there is any such utility in tcl?
Because you can do generation of code at runtime very easily in Tcl, and many APIs use callbacks, it's rather hard to determine statically where a command is called from. Simple searching of the code is probably the simplest way (with a recursive grep on Unixes, and findstr /s on Windows).
However, determining where a command is called from at runtime is much easier, as you can use an execution trace on the command of interest and introspect the call stack at that point (with info level and info frame).
proc foo args {bar $args $args}
proc bar args {puts ">>$args<<"}
proc caller args {
puts "caller-call: [info level -1]"
puts "caller-info: [info frame -1]"
}
trace add execution bar enter caller
foo [expr 1+3] [llength {s p q r}]
Running that interactively gives the output:
caller-call: foo 4 4
caller-info: type eval line 1 cmd {caller {bar {4 4} {4 4}} enter} proc ::foo level 1
>>{4 4} {4 4}<<
You'll get even more if you put it in a file.