A '''scripted [list]''' is a Tcl [script] in which every [word] of every [command] becomes a value in the resulting list, with the first word of each command being considered just another value instead of being used as the command name. ** See Also ** [scripted templates]: a twist on scripted lists [Convenient list arguments - larg]: a similar idea from [jcw] ** Description ** One way to look at a Tcl script is as a sequence of words that are separated into commands. It can be useful to represent a list this way, performing the normal substitutions on each word. A convenient way to accomplish this is by splitting the script into commands, passing the words of each command to `[list]` in order to get the desired substitutions, and then concatenating all results together. In other words, what is normally the command name in a script becomes just another item in the resulting list. The advantage is that it isn't necessary to use the backslash character when the list spans multiple lines, and in-line comments are possible. This provides the oft-requested ability to represent a list in source code, using command and variable substitution to form the values in the list, without having to escape the newline between the values, and with the ability to make comments in between elements of the list and comment out some elements of the list. For example a `[switch]` can contain comments between its blocks: ====== set grail 42 switch $answer [sl { #set course for Traal {a lurgid bee} { lindex {Do not be alarmed} } #By Agrajag! $grail { lindex {Oh no, not again.} } #clueless Golgafrinchams default { puts [list whoa $answer] error {get your cave redecorated!} } }] ====== the following procedure provides the described behaviour: ====== proc sl script { concat {*}[lmap part [scriptSplit $script] { if {[string match #* $part]} continue uplevel 1 list $part }] } ====== ** A Twisted Scripted List ** This list is a twist on the standard scripted list in which only the first command in a series of semicolon-separated commands becomes part of the result. The additional commands in such a series of commands might have side effects that influence the composition of the list. The current examples don't show a compelling use case, but perhaps someone will do something interesting with it. '''Example''' ====== set mylist [sl { one two three ;#this is a comment $somevar #ha ha! a two-line \ comment in the list! [some command] {;} ;#literal semicolons must be escaped {some literal} "some $substituted[value]" }] ====== ''' More Complex Example ''' ====== set six six proc some {args} { return {seven eight} } proc value {} { return {nine ten} } proc side {args} { upvar var2 var2 set var2 twelve } set substituted eleven set mylist [sl { one two three ;#this is a comment {four five} $six #this is a a two-line \ comment in the list! [some command] {;} ;#literal semicolons must be escaped "[value] $substituted" only the first command in a line get the special scripted list treatment, \ but then only only the value othe last command in a line counts which \ means that this line is like a comment with [side effects], and its \ result is whatever the last command produces; set var2 }] puts $mylist ====== '''Output''': ======none one two three {four five} six {seven eight} {;} {nine ten eleven} twelve ====== ** Implementation ** ====== proc sl script { set res {} set parts {} foreach part [split $script \n] { lappend parts $part set part [join $parts \n] #add the newline that was stripped because it can make a difference if {[info complete $part\n]} { set parts {} set part [string trim $part] if {$part eq {}} { continue } if {[string index $part 0] eq {#}} { continue } #Here, the double-substitution via uplevel is intended! lappend res {*}[uplevel list $part] } } if {$parts ne {}} { error [list {incomplete parts} [join $parts]] } return $res } ====== ** History ** The following was migrated here from [Additional string functions]: '''Substitution that Preserves Grouping ''' [RHS] 2005-02-23: There have been a number of times where I have wanted a version of '''subst''' that preserves grouping. For example, I want to be able to do the following: ====== % array set myarr [subst { a $x b [getConfigValue something] c { a b c d } }] % array get myArr a 1 b blah c { a b c d } ====== My main reason for this is, when the dataset get large, I tend to find \ line continuations fairly ugly... That, and my emacs config doesn't indent well for multiple levels of line continuations if there's sub levels. In pursuit of the above, I came up with the following: ====== proc gsubst input { set data {} foreach line [split $input \n] { if {[info complete $data]} { append data " $line" } else { append data "\n$line" } } uplevel 1 list $data } ====== The above proc should, in theory, cause the following two to work exactly the same ======none list a 1 \ b $x \ c { 1 2 } \ d [somecommand] gsubst { a 1 b $x c { 1 2 } d [somecommand] } ====== ** Page Authors ** [RHS]: [PYK]: [aspect]: <> list