/*
* Here comes the text of your license
* Each line should be prefixed with *
*/
package nars.io;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import nars.storage.Memory;
import nars.config.Parameters;
import nars.io.Output.ERR;
import nars.language.Term;
import nars.operator.Operator;
import nars.operator.SynchronousFunctionOperator;
/**
*
* @author me
*/
public class BindJavascriptExpression implements TextReaction {
ScriptEngine js;
public static final String BINDING_SYMBOL = ":=";
private final Memory memory;
private final Narsese narsese;
public BindJavascriptExpression(Memory memory) {
super();
this.memory = memory;
this.narsese = new Narsese(memory);
}
@Override
public Object react(String input) {
if (input.contains(BINDING_SYMBOL)) {
String[] p = input.split(BINDING_SYMBOL);
if (p.length!=2) {
throw new RuntimeException("Invalid syntax for expression binding");
}
String newOp = Operator.addPrefixIfMissing(p[0].trim());
Operator existing = memory.getOperator(newOp);
if (existing!=null) {
throw new RuntimeException("Unable to bind new expression to existing Operator: " + existing);
}
String proc = p[1].trim();
if (!proc.startsWith("js{")) {
throw new RuntimeException("Unrecognized expression format: " + proc);
}
if (!proc.endsWith("}")) {
throw new RuntimeException("Expression must end with '}'");
}
proc = proc.substring(3, proc.length()-1).trim();
if (js == null) {
ScriptEngineManager factory = new ScriptEngineManager();
js = factory.getEngineByName("JavaScript");
}
final String o = newOp.substring(1);
try {
String jsFunc = "function " + o + "($1, $2, $3, $4, $5, $6) { " + proc + "; }";
js.eval(jsFunc);
js.put("memory", memory);
memory.addOperator(new SynchronousFunctionOperator(newOp) {
@Override
protected Term function(Memory memory, Term[] args) {
StringBuilder argsToParameters = new StringBuilder();
for (int i = 0; i < args.length; i++) {
argsToParameters.append("'").append(args[i].toString()).append("'");
if (args.length-1 != i)
argsToParameters.append(",");
}
Object result = null;
try {
result = js.eval(o + "(" + argsToParameters + ")");
} catch (ScriptException ex) {
throw new RuntimeException("Exception in executing " + this + ": " + ex.toString(), ex);
}
try {
return narsese.parseTerm(result.toString());
} catch (Narsese.InvalidInputException ex) {
memory.emit(ERR.class, ex.toString());
if (Parameters.DEBUG)
ex.printStackTrace();
}
return null;
}
@Override
protected Term getRange() {
return null;
}
});
//memory.emit(OUT.class, "Bound: "+ jsFunc);
} catch (ScriptException ex) {
throw new RuntimeException(ex.toString(), ex);
}
return true;
}
return null;
}
}