1 # Creates an anonymous procedure
2 proc lambda
{arglist args
} {
3 tailcall
proc [ref
{} function lambda.finalizer
] $arglist {*}$args
6 proc lambda.finalizer
{name val
} {
10 # Like alias, but creates and returns an anonyous procedure
12 alias
[ref
{} function lambda.finalizer
] {*}$args
15 # Returns the given argument.
16 # Useful with 'local' as follows:
23 proc function
{value
} {
27 # Returns a list of proc filename line ...
28 # with 3 entries for each stack frame (proc),
29 # (deepest level first)
32 foreach level
[range
1 [info level
]] {
33 lassign
[info frame -$level] p f l
34 lappend trace $p $f $l
39 # Returns a human-readable version of a stack trace
40 proc stackdump
{stacktrace
} {
43 foreach {l f p
} [lreverse
$stacktrace] {
49 append result
"in procedure '$p' "
51 append result
"called "
55 append result
"at file \"$f\", line $l"
61 # Sort of replacement for $::errorInfo
62 # Usage: errorInfo error ?stacktrace?
63 proc errorInfo
{msg
{stacktrace
""}} {
64 if {$stacktrace eq
""} {
65 set stacktrace
[info stacktrace
]
67 lassign
$stacktrace p f l
69 set result
"Runtime Error: $f:$l: "
71 append result
"$msg\n"
72 append result
[stackdump
$stacktrace]
74 # Remove the trailing newline
78 # Finds the current executable by searching along the path
79 # Returns the empty string if not found.
80 proc {info nameofexecutable
} {} {
81 if {[info exists
::jim_argv0]} {
82 if {[string match
"*/*" $::jim_argv0]} {
83 return [file join [pwd] $::jim_argv0]
85 foreach path
[split [env PATH
""] $::tcl_platform(pathSeparator
)] {
86 set exec [file join [pwd] [string map
{\\ /} $path] $::jim_argv0]
87 if {[file executable
$exec]} {
95 # Script-based implementation of 'dict with'
96 proc {dict with
} {&dictVar
{args key
} script
} {
98 foreach {n v
} [dict get
$dictVar {*}$key] {
103 catch {uplevel 1 $script} msg opts
104 if {[info exists dictVar
] && ([llength $key] == 0 ||
[dict exists
$dictVar {*}$key])} {
106 if {[info exists var_
$n]} {
107 dict
set dictVar
{*}$key $n [set var_
$n]
109 dict
unset dictVar
{*}$key $n
116 # Script-based implementation of 'dict update'
117 proc {dict
update} {&varName args script
} {
119 foreach {n v
} $args {
121 if {[dict exists
$varName $n]} {
122 set var_
$v [dict get
$varName $n]
125 catch {uplevel 1 $script} msg opts
126 if {[info exists varName
]} {
127 foreach {n v
} $args {
128 if {[info exists var_
$v]} {
129 dict
set varName
$n [set var_
$v]
131 dict
unset varName
$n
138 # Script-based implementation of 'dict merge'
139 # This won't get called in the trivial case of no args
140 proc {dict merge
} {dict args
} {
142 # Check for a valid dict
151 proc {dict replace
} {dictionary
{args
{key value
}}} {
152 if {[llength ${key value
}] % 2} {
153 tailcall
{dict replace
}
155 tailcall dict merge
$dictionary ${key value
}
158 # Script-based implementation of 'dict lappend'
159 proc {dict
lappend} {varName key
{args value
}} {
161 if {[exists dict
] && [dict exists
$dict $key]} {
162 set list [dict get
$dict $key]
164 lappend list {*}$value
165 dict
set dict
$key $list
168 # Script-based implementation of 'dict append'
169 proc {dict
append} {varName key
{args value
}} {
171 if {[exists dict
] && [dict exists
$dict $key]} {
172 set str
[dict get
$dict $key]
175 dict
set dict
$key $str
178 # Script-based implementation of 'dict incr'
179 proc {dict
incr} {varName key
{increment
1}} {
181 if {[exists dict
] && [dict exists
$dict $key]} {
182 set value
[dict get
$dict $key]
184 incr value
$increment
185 dict
set dict
$key $value
188 # Script-based implementation of 'dict remove'
189 proc {dict remove
} {dictionary
{args key
}} {
191 dict
unset dictionary
$k
196 # Script-based implementation of 'dict values'
197 proc {dict values
} {dictionary
{pattern
*}} {
198 dict keys
[lreverse
$dictionary] $pattern
201 # Script-based implementation of 'dict for'
202 proc {dict
for} {vars dictionary script
} {
203 if {[llength $vars] != 2} {
204 return -code error "must have exactly two variable names"
206 dict size
$dictionary
207 tailcall
foreach $vars $dictionary $script