codeshot
codeshot

Reputation: 1193

Parse a tcl word into a list of tcl commands ready for eval or uplevel

I want to write a function that can be used like this:

my_function {
    cmdA argA_1 argA_2
    cmdB argB_1 argB_2
    cmdC argC_1 argC_2
}

I want to implement my_function by using namespace eval ::my_internal_namespace [uplevel ...], possibly in a loop. Although this is not immediately very useful, I will enhance it later to do more than merely uplevel.

my_internal_namespace would be defined something like this:

namespace eval my_internal_namespace {
  proc cmdA { args } {
      puts "$args"
  }

  proc cmdB { args } {
      puts "$args"
  }

  proc cmdC { args } {
      puts "$args"
  }
}

I think this technique will ultimately allow the caller of my_function to declare some facts and behaviours that they would like from my_function, where the parameters of those facts and behaviours are evaluated in the context of the caller, for example, to get the value of variables or to perform other substitutions in the namespace and scope of the caller.

Upvotes: 0

Views: 120

Answers (1)

Donal Fellows
Donal Fellows

Reputation: 137557

Why not just pass the word to namespace eval directly? That's almost what Tcl does itself in situations like the oo::define command. Evaluate as a script is a wonderfully easy way to parse some trusted code.

namespace eval ::my_internal_namespace $the_user_word

For untrusted code, a safe interpreter is recommended. For these “little language” approaches, you're best to create a basic safe interpreter, hide the remaining commands that you don't want to expose, and add in aliases for all the commands that you want to make available.

set i [interp create -safe]
foreach cmd [$i eval {info commands}] {
    $i hide $cmd
}
foreach cmd {cmdA cmdB cmdC} {
    $i alias $cmd ::my_internal_namespace::$cmd
}
$i eval $the_user_word

This is fairly expensive to just doing a namespace eval; I wouldn't bother if the code is relatively trusted.

Upvotes: 1

Related Questions