JSoarTclSupport - soartech/jsoar GitHub Wiki

Introduction

JSoar includes two interpreters: the DefaultInterpreter and the SoarTclInterface. The Tcl interpreter allows Tcl code to be embedded in Soar files and even directly in Soar productions.

Differences from Scripting support

So how is this different from JSoar's other scripting support? There are a few differences:

  • JSoar's other scripting support is directly through the JVM. That is, those languages are actually interpreted into bytecode. Tcl is just a library that is being used by JSoar.
  • Tcl doesn't support hooking into the JSoar API directly (e.g., you can't write a callback handler).
  • You can embed Tcl directly into your Soar rules, which you can't do with the other scripting languages.

It's not clear if anyone has tried, but you can probably use both Tcl and another scripting language together if desired.

Enabling Tcl support

First, you need the jsoar-tcl.jar file on your classpath (or the jsoar-tcl project in your workspace, if you're using Eclipse and working directly from source).

From the command line, pass the -Djsoar.agent.interpreter=tcl flag to the JVM.

Programmatically, before you create an agent, set the equivalent System property. E.g.,

System.setProperty("jsoar.agent.interpreter","tcl");
ThreadedAgent agent = ThreadedAgent.create();

You might be tempted to create the Tcl interpreter directly and replace the one in the agent (the API makes this possible). But there is more to setting up the interpreter than just instantiating it. If you do this, the default aliases won't be loaded.

Interpretation of Tcl code

With the exception of the tcl RHS function (see below), all Tcl code is evaluated at source time. Thus, any rules referring to Tcl variables or productions that generate Soar code, etc., will be evaluated when the productions are sourced. If you need to delay evaluation of something until runtime, use the tcl RHS function.

tcl RHS function

The tcl RHS function takes a string as an argument, which will be evaluated as Tcl code when the production fires. The result is currently always a string, so if you need it to be something else (e.g., an integer) you'll have to call the appropriate casting function.

Examples:

sp "examples
   (state <s> ^superstate nil)
-->
   (<s> ^result1 (tcl |myProc foo|))
   (<s> ^result2 (tcl |myProc |<s>) # if you want a Soar variable to be substituted, it needs to be outside the string. It will automatically be appended.
   (<s> ^result3 (int (tcl |myProc whatever|))) # If you want a number, cast the result.
"