GWTJep JavaScript mathematical expression parser/evaluator.

GWTInterop - Jep functions exposed to JavaScript

The GWTInterop module exposes a limited set of Jep functionality so that it can be called directly from JavaScript.

Basic functionality

To use the GWTInterop functionality include the following JavaScript

<script type="text/javascript">
    var pageType = "Interop";
    window.jepModuleLoaded = function() {
           jep = new Jep();
    }
</script>

<script type="text/javascript" src="gwtjep/gwtjep.nocache.js"></script>

The jepModuleLoaded function is called once the module is loaded, which in turn creates a new Jep object jep.

Alternatively just include the line

<script type="text/javascript" src="gwtjep/gwtjep.nocache.js"></script>

and create a jep instance when needed, using

    jep = new Jep();

To parse an expression use

    try {
        node1 = jep.parse("y = 2 x+3");
    } catch(e) {
        alert(e);
    }

The value can be set with

    try {
        jep.setVariable("x",5)
    } catch(e) {
        alert(e);
    }

Which can then be evaluated with

    try {
        result1 = jep.evaluate(node1);
        alert(result1);
    } catch(e) {
        alert(e);
    }

And the variable value retrieved with

    result2 = jep.getVariableValue("y")    
    alert(result2);

Forms Example

In this example variable name and values can read from form elements. First input an expressions and press parse, then set the variable and finally press evaluate.

Expression
Result
Variable Value

The JavaScript code:

// ensures the jep object created
function checkJep() {
    if(typeof jep == "undefined") {
        jep = new Jep();
        document.getElementById("errOut").value = "jep constructed"
    }
    else {
        document.getElementById("errOut").value = ""
    }
}

function reportError(str) {
    document.getElementById("errOut").value = str
}

function parse() {
    checkJep()
    const expr = document.getElementById("expression").value
    try {
        node1 = jep.parse(expr)
    } catch(e) { 
        reportError(e) 
    }
}

function eval1() {
    checkJep()
    try {
        let res = jep.evaluate(node1)
        document.getElementById("expVal").value = res
    } catch(e) { reportError(e) }
}

function setVar1() {
    checkJep()
    try {
        const name = document.getElementById("var1Name").value
        const val = document.getElementById("var1Val").valueAsNumber
        let res = jep.setVariable(name,val)
    } catch(e) { reportError(e) }
}

function var1Changed() {
    setVar1();
    eval1();
}

function getVar1() {
    checkJep()
    try {
        const name = document.getElementById("var1Name").value
        let res = jep.getVariableValue(name)
        document.getElementById("var1Val").value = res
    } catch(e) { reportError(e) }
}

function setVar2() {
    checkJep()
    try {
        const name = document.getElementById("var2Name").value
        const val = document.getElementById("var2Val").value
        let res = jep.setVariable(name,Number(val))
    } catch(e) { reportError(e) }
}

function getVar2() {
    checkJep()
    try {
        const name = document.getElementById("var2Name").value
        let res = jep.getVariableValue(name)
        document.getElementById("var2Val").value = res
    } catch(e) { reportError(e) }
}

Note the code needs to catch exceptions. Alternative method that do not throw exceptions are available: jep.parseNE(string), jep.evaluateNE(), jep.setVariableNE(). If these encounter an error the will return null and an internal variable with the message set. The jep.getErrorMsg() command can be used to retrieve this message. For example

    node = jep.parseNE("x-")
    if(node == null) {
        alert(jep.getErrorMsg())
    }

Java source code

Currently only a limited portion of the jep functionality is exposed to JavaScript. This could be expanded by copying or expanding the com.singularsys.client.GWTInterop class. The class start with

@JsType(namespace = JsPackage.GLOBAL, name = "Jep")
public class GWTInterop implements EntryPoint {
    Jep jep;

    /**
     * Creates a Jep instance using the StandardConfigurableParser
     */
    @JsConstructor
    public GWTInterop() {
        jep = new Jep(new StandardConfigurableParser());        
    }
    
    /** 
     * Standard GWT method called when the module is loaded. 
     * Calls the onModLoad() native method which in turn calls
     * the JavaScript jepModuleLoaded() method.
     */
    @Override
    @JsIgnore
    public void onModuleLoad() {
        onModLoad();    
    }

    /**
     * Calls the JavaScript jepModuleLoaded() method.
     */
    @JsIgnore
    protected native void onModLoad() /*-{
        $wnd.jepModuleLoaded();
    }-*/;

Which sets the JavaScript name of the class, adds a constructor that is made viewable from JavaScript with the @JsConstructor annotation. The onModuleLoad method is called by the GWT system when the module is loaded, this calls a native JavaScript method onModLoad() which in turn calls the JavaScript method jepModuleLoaded() discussed at the top of the page.

A couple of wrapper types tagged with @JsType are used for objects parsed to and from JavaScript

    @JsType
    public static class GWTNode {
        Node node;
        GWTNode(Node n) {
            node = n;
        }
    }

    @JsType
    public static class GWTVariable {
        Variable v;
        GWTVariable(Variable n) {
            v = n;
        }
    }

Methods visible to JavaScript are tagged with @JsMethod.

    /**
     * Parse an expression
     * @param S expression
     * @return root node of parse tree or null on ParseException
     * @throws ParseException if an error in parsing
     */
    @JsMethod
    public GWTNode parse(String S) throws ParseException {
        errorMsg="";
        Node res = jep.parse(S);
        return new GWTNode(res);
    }