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.
"