Search code examples
javaintegrationrascal

Rascal access the REPL from a java application


Has anyone attempted to "link" in the Rascal command line jar in a java executable and call REPL commands from this java executable? I found a similar question on stackoverflow (Running a Rascal program from outside the REPL), but that doesn't go into details unfortunately.

I also checked the Rascal tutor site, but couldn't find any examples on how to do this. Tijs told me that it's something along the lines of "instantiate an interpreter and then call the import() function, after which the call() function can be called to inject REPL commands).

Is there any example code on how to do, e.g. the following from the tutor site on the REPL but from a java programming context instead of on the command line:

rascal>import demo::lang::Exp::Concrete::NoLayout::Syntax;
ok
rascal>import ParseTree;
ok
rascal>parse(#Exp, "2+3");
sort("Exp"): `2+3`

Solution

  • The following would do the trick; a utility class for the same can be found in rascal/src/org/rascalmpl/interpreter/JavaToRascal.java:

    GlobalEnvironment heap = new GlobalEnvironment();
    IValueFactory vf = ValueFactoryFactory.getValueFactory();
    TypeFactory TF = TypeFactory.getInstance();
    IRascalMonitor mon = new NullRascalMonitor();
    Evaluator eval = new Evaluator(vf, new PrintWriter(System.err), new PrintWriter(System.out), new ModuleEnvironment(ModuleEnvironment.SHELL_MODULE, heap), heap);
    
    
    eval.doImport(mon, "demo::lang::Exp::Concrete::NoLayout::Syntax");
    eval.doImport(mon, "ParseTree");
    eval.eval(mon, "parse(#Exp, \"2+3\");", URIUtil.rootLocation("unknown"));
    

    There is also more efficient ways of interacting with the evaluator, via the pdb.values IValue interfaces to build data and ICalleableValue to call Rascal functions. You can use the above heap object to query its environments to get references to functions and you can use the low level pdb.values API to construct values to pass to these functions.

    Caveat emptor: this code is "internal" API with no guarantee for backward compatibility. I can guarantee that something like this will always be possible.