Angel \”Java\” Lopez on Blog

November 28, 2014

SimpleScript (3) The Parser, Expressions and Commands

Previos Post

Let’s visit the Parser, that is a separated module. It starts with a simple declaration:

'use strict';

var lexer;

if (typeof lexer == 'undefined')
    lexer = require('./lexer');

var parser = (function () {
    var TokenType = lexer.TokenType;
    var binoperators = [ "+", "-", "*", "/", "==", "!=", "<", ">", "<=", ">=" ];

It uses and requires the lexer module. After this declaration, there are many expressions and commands. This is the expression “class” for a name (ie, foo):

function NameExpression(name) {
    this.isLeftValue = true;

    this.compile = function () {
        return name;
    };

    this.getName = function () {
        return name;
    }

    this.collectContext = function (context) {
        context.declare(name);
    }
}

In an upcoming post, I will describe the detection and construction of commands and expression. An expression should implement two methods: compile, that returns an string with the compiled JavaScript code associated to the expression, and collectContext, that allows the discover of used variables in an expression/command. In the above code, NameExpression declares its name to a context, an object that is recovering the used variables.

This is an IndexedExpression, composed by an expression and another one for the index (it’s like foo[42+1]):

function IndexedExpression(expr, indexpr) {
    this.isLeftValue = true;

    this.compile = function () {
        return expr.compile() + '[' + indexpr.compile() + ']';
    };

    this.collectContext = function (context) {
        expr.collectContext(context);
    }
}

The collectContext visits the internal expression (I could add the visit of the index expression, too).

There are commands, like IfCommand:

function IfCommand(cond, thencmd, elsecmd) {
    this.compile = function () {
        var code = 'if (' + cond.compile() + ') { ' + thencmd.compile() + ' }';
        if (elsecmd)
            code += ' else { ' + elsecmd.compile() + ' }';
        return code;
    };

    this.collectContext = function (context) {
        cond.collectContext(context);
        thencmd.collectContext(context);
        if (elsecmd)
            elsecmd.collectContext(context);
    }
}

The distinction between commands and expressions is a formal one. Again, a command should implement compile and collectContext. The above code generates a JavaScript if command.

As usual, I followed TDD (Test-Driven Development) workflow. Partial tests example:

exports['Compile string without quotes inside'] = function (test) {
    test.equal(compileExpression("'foo'", test), "'foo'");
    test.equal(compileExpression('"foo"', test), "'foo'");
}

exports['Compile name'] = function (test) {
    test.equal(compileExpression("foo", test), "foo");
}

exports['Qualified name'] = function (test) {
    test.equal(compileExpression("foo.bar", test), "foo.bar");
}

exports['Indexed term'] = function (test) {
    test.equal(compileExpression("foo[bar]", test), "foo[bar]");
}

Remember: No TDD, no paradise! 😉

Next topics: how to recognize and build expressions and commands.

Stay tuned!

Angel “Java” Lopez

http://www.ajlopez.com

http://twitter.com/ajlopez

Blog at WordPress.com.

%d bloggers like this: