Thanks AM, I changed it.I reworked the whole thing some, I think it's a lot more functional now. Got rid of the random id's; now they are specified. I'll leave this here in case somebody likes it, but I think the following is much better.
See lego proc manipulation for the improved version.
Here's what I came up with to create and manipulate parts of a proc's body by setting tags for each part of the body. Setting these tags allows me to split up the list accordingly and treat and change parts like changing list items.Functions:
##### _pgetid
# Creates a 10 digit id greater than 0
#####
proc _pgetid {checklist} {
set z 0
while {$z < 1} {
set y [expr { int( rand() * 9 ) }]
set w [expr { int( rand() * 9 ) }]
set r [expr { int( rand() * 9 ) }]
set b [expr { int( rand() * 9 ) }]
set g [expr { int( rand() * 9 ) }]
set l [expr { int( rand() * 9 ) }]
set p [expr { int( rand() * 9 ) }]
set d [expr { int( rand() * 9 ) }]
set q [expr { int( rand() * 9 ) }]
set s 1
set n "$y$w$r$b$g$l$p$d$q$s"
if {[lsearch $checklist $n] < 0} {set z 1}
}
return $n
}
###
###### pinsert
# Inserts code at id'd index position and returns the new codes id, id will be 0000000000 -
# if proc does not exist
######
proc pinsert {name index code} {
set c1 [format %c 1]
if {![llength [info procs $name]]} {
set id 0000000000
set bodylist [list]
set pargs { }
} else {
set idlist [pgetlist $name bodylist]
set id [_pgetid $idlist]
set pargs [info args $name]
}
set code "\#$c1$id$c1\#\n$code\n\#$c1$id$c1\#"
set bodylist [linsert $bodylist $index $code]
uplevel #0 [list proc $name $pargs [join $bodylist \n]]
return $id
}
###
###### preplace
# Removes or replace id's code
# if code is specified it will have the previous codes id
# else id is removed as well
######
proc preplace {name id {code 0}} {
set idlist [pgetlist $name bodylist]
set tmp [lsearch $idlist $id]
set pargs [info args $name]
if {$tmp >= 0} {
if {$code == 0} {
set bodylist [lreplace $bodylist $tmp $tmp]
} else {
set c1 [format %c 1]
set code "\#$c1$id$c1\#\n$code\n\#$c1$id$c1\#"
set bodylist [lreplace $bodylist $tmp $tmp $code]
}
uplevel #0 [list proc $name $pargs [join $bodylist \n]]
}
}
###
###### pargs
# Sets the args of a proc
######
proc pargs {name parg} {
if {[llength [info procs $name]]} { uplevel #0 [list proc $name $parg [info body $name]] }
}
###
###### pgetlist
# 1. It returns a list of all id's in a proc with lindex relative to its code
# 2. Creates a list to varname with the body of a proc split at prior id's
# 3. If the proc has no pinsert id's it tags the existing body with 0000000000
# This means you can easily refer to the initial code in a proc
######
proc pgetlist {name {varname ""}} {
set c1 [format %c 1]
set code [info body $name]
set tmp [string length [string trim $code]]
set code [split $code \n]
set pattern "\#$c1\??????????$c1\#"
set codepos [lsearch -all $code $pattern]
if {[llength $codepos] == 0 && $tmp != 0} {
set id 0000000000
lappend codepos 0 end
set code [linsert $code 0 "\#$c1$id$c1\#"]
lappend code "\#$c1$id$c1\#"
}
set codelist [list]
set idlist [list]
foreach {start end} $codepos {
lappend codelist [join [lrange $code $start $end] \n]
set chunk [lindex $code $start]
lappend idlist [string range $chunk 2 [expr [string length $chunk] - 3]]
}
if {$varname != ""} { uplevel 1 [list set $varname $codelist] }
return $idlist
}
###
############ for debug
#! DEBUG
proc proc_view {name} {
set tmp [split [info body $name] \n]
set tmpa [info args $name]
set tmpres "proc $name \{$tmpa\} \{\n"
foreach {line} $tmp { set tmpres "$tmpres $line\n" }
set tmpres "$tmpres\}\n"
puts "\n############################\n### DEBUG - proc view ###"
puts "$tmpres\###########################\n"
}
#####Functions work almost like the list functions with similar name. Main difference is that code is tagged with a 10 digit random id number instead of a list index. If i think of an easy way to maintain ease of use and efficiency, or if somebody makes a suggestion, I may use some other type of separation id and keep an actual index count like a list. The main problem i saw with this is that when inserting into it causes the other items to change. It would be hard to keep track of what code is where.Example: #############################################
#### LETS TRY IT OUT - create/manipulate "sayit"
#############################################
set code(0) {set say "$say IS"}
set code(1) {set say "$say FUN"}
set code(2) {set say "$say\."}
set code(3) {puts "YOU SAY: [string trim $say]"}
### these will contain the id tags to locate our code
set codeID(0) [pinsert sayit end $code(0)]
set codeID(1) [pinsert sayit end $code(1)]
set codeID(2) [pinsert sayit end $code(2)]
set codeID(3) [pinsert sayit end $code(3)]
pargs sayit {say}
proc_view sayit
sayit "TCL"
### lets change it
preplace sayit $codeID(3) {return [string trim $say]}
puts "- [sayit "THIS"]"
preplace sayit $codeID(0) {set say "$say ARE"}
puts "- [sayit "PUPPIES"]"
### just a tad more technical
## I want to add a word in a specific place,
## so i need to get an Index from an ID
set tmp [pgetlist sayit]
set x [lsearch $tmp $codeID(1)]
set codeID(4) [pinsert sayit $x {set say "$say PROCS"}]
set codeID(5) [pinsert sayit $x {set say "$say TCL"}]
puts "- I THINK: [sayit "THESE"]"
### Removing code
## I realize to do the following i could just proc again, this is just for show
foreach {id} [pgetlist sayit] {
preplace sayit $id
}
proc_view sayit
### lets make it a calculator
set codeID(0) [pinsert sayit 0 {puts "- $args = [expr $args]"}]
pargs sayit {args}
proc_view sayit
sayit (3 + 3 * 2) * 10I'm not as familiar with TCL as some of you fellow wikians. Therefore Suggestions and Corrections are well appreciated. Thanks.- David Myers aka xonecubedAM Some comments, as I promised:The series of assignments:
set y [expr { int( rand() * 9 ) }]
set w [expr { int( rand() * 9 ) }]
set r [expr { int( rand() * 9 ) }]
...can be made more compact:
foreach var {y w r ...} {
set $var [expr {int(rand()*9)}]
}and I do not think it is necessary to use:
uplevel #0 [list proc $name ...]The command:
proc ::$name ...will give the same effect.Just a few remarks :)
