The JavaScript part
“Math.js is an extensive math library for JavaScript and Node.js.”
— Project readme
It provides a parse() function.
Example using the NodeJS environment:
var math = require('mathjs')();
var ast = math.parse('xy^(1/2)');
// Fully log the object
var util = require('util');
console.log(util.inspect(ast, {showHidden: false, depth: null}));
Output:
{ op: '^',
fn: 'pow',
params:
[ { name: 'xy' },
{ op: '/',
fn: 'divide',
params:
[ { valueType: 'number', value: '1' },
{ valueType: 'number', value: '2' } ] } ] }
The Java part
I use the Java Nashorn VM (only available in Java >= 8) to execute JavaScript.
Program architecture:
User ---------------> Java
inputs formla |----> Nashorn ----> math.js
|<---------------------|
User <-----------------|
Using the Nashorn engine is quite simple (Exception handling omitted)
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval(readerInstancePointingToMathJsLibrary);
engine.eval(readerInstancePointingToBridgeJavaScript);
The bridge's JavaScript code highly depends on your implementation of AST nodes. We take advantage of Nashorn's ability to create and transfer Java objects in JavaScript to Java. Example:
var math = mathjs();
function convert(formula) {
var ast = math.parse(formula);
var javaAst = /* build your AST with Java objects */
return javaAst;
}
We can now access that function from Java and even pass arbitrary arguments:
Invocable inv = (Invocable) engine;
// Expression is my AST node type in Java
expr = (Expression) inv.invokeFunction("convert", formulaFromUser);
Note: I needed a quick way of parsing mathematical expressions. A parser (either handwritten or generated by a parser generator) is always preferable. Nonetheless, the code above shows how Java Nashorn can be easily integrated.