'use strict';var ArgumentsError = require('../error/ArgumentsError');var deepMap = require('../utils/collection/deepMap');function factory (type, config, load, typed) {  var AccessorNode            = load(require('./node/AccessorNode'));  var ArrayNode               = load(require('./node/ArrayNode'));  var AssignmentNode          = load(require('./node/AssignmentNode'));  var BlockNode               = load(require('./node/BlockNode'));  var ConditionalNode         = load(require('./node/ConditionalNode'));  var ConstantNode            = load(require('./node/ConstantNode'));  var FunctionAssignmentNode  = load(require('./node/FunctionAssignmentNode'));  var IndexNode               = load(require('./node/IndexNode'));  var ObjectNode              = load(require('./node/ObjectNode'));  var OperatorNode            = load(require('./node/OperatorNode'));  var ParenthesisNode         = load(require('./node/ParenthesisNode'));  var FunctionNode            = load(require('./node/FunctionNode'));  var RangeNode               = load(require('./node/RangeNode'));  var SymbolNode              = load(require('./node/SymbolNode'));  /**   * Parse an expression. Returns a node tree, which can be evaluated by   * invoking node.eval();   *   * Syntax:   *   *     parse(expr)   *     parse(expr, options)   *     parse([expr1, expr2, expr3, ...])   *     parse([expr1, expr2, expr3, ...], options)   *   * Example:   *   *     var node = parse('sqrt(3^2 + 4^2)');   *     node.compile(math).eval(); // 5   *   *     var scope = {a:3, b:4}   *     var node = parse('a * b'); // 12   *     var code = node.compile(math);   *     code.eval(scope); // 12   *     scope.a = 5;   *     code.eval(scope); // 20   *   *     var nodes = math.parse(['a = 3', 'b = 4', 'a * b']);   *     nodes[2].compile(math).eval(); // 12   *   * @param {string | string[] | Matrix} expr   * @param {{nodes: Object<string, Node>}} [options]  Available options:   *                                                   - `nodes` a set of custom nodes   * @return {Node | Node[]} node   * @throws {Error}   */  function parse (expr, options) {    if (arguments.length != 1 && arguments.length != 2) {      throw new ArgumentsError('parse', arguments.length, 1, 2);    }    // pass extra nodes    extra_nodes = (options && options.nodes) ? options.nodes : {};    if (typeof expr === 'string') {      // parse a single expression      expression = expr;      return parseStart();    }    else if (Array.isArray(expr) || expr instanceof type.Matrix) {      // parse an array or matrix with expressions      return deepMap(expr, function (elem) {        if (typeof elem !== 'string') throw new TypeError('String expected');        expression = elem;        return parseStart();      });    }    else {      // oops      throw new TypeError('String or matrix expected');    }  }  // token types enumeration  var TOKENTYPE = {    NULL : 0,    DELIMITER : 1,    NUMBER : 2,    SYMBOL : 3,    UNKNOWN : 4  };  // map with all delimiters  var DELIMITERS = {    ',': true,    '(': true,    ')': true,    '[': true,    ']': true,    '{': true,    '}': true,    '\"': true,    ';': true,    '+': true,    '-': true,    '*': true,    '.*': true,    '/': true,    './': true,    '%': true,    '^': true,    '.^': true,    '~': true,    '!': true,    '&': true,    '|': true,    '^|': true,    '\'': true,    '=': true,    ':': true,    '?': true,    '==': true,    '!=': true,    '<': true,    '>': true,    '<=': true,    '>=': true,    '<<': true,    '>>': true,    '>>>': true  };  // map with all named delimiters  var NAMED_DELIMITERS = {    'mod': true,    'to': true,    'in': true,    'and': true,    'xor': true,    'or': true,    'not': true  };  var extra_nodes = {};             // current extra nodes  var expression = '';              // current expression  var comment = '';                 // last parsed comment  var index = 0;                    // current index in expr  var c = '';                       // current token character in expr  var token = '';                   // current token  var token_type = TOKENTYPE.NULL;  // type of the token  var nesting_level = 0;            // level of nesting inside parameters, used to ignore newline characters  var conditional_level = null;     // when a conditional is being parsed, the level of the conditional is stored here  /**   * Get the first character from the expression.   * The character is stored into the char c. If the end of the expression is   * reached, the function puts an empty string in c.   * @private   */  function first() {    index = 0;    c = expression.charAt(0);    nesting_level = 0;    conditional_level = null;  }  /**   * Get the next character from the expression.   * The character is stored into the char c. If the end of the expression is   * reached, the function puts an empty string in c.   * @private   */  function next() {    index++;    c = expression.charAt(index);  }  /**   * Preview the previous character from the expression.   * @return {string} cNext   * @private   */  function prevPreview() {    return expression.charAt(index - 1);  }  /**   * Preview the next character from the expression.   * @return {string} cNext   * @private   */  function nextPreview() {    return expression.charAt(index + 1);  }  /**   * Preview the second next character from the expression.   * @return {string} cNext   * @private   */  function nextNextPreview() {    return expression.charAt(index + 2);  }  /**   * Get next token in the current string expr.   * The token and token type are available as token and token_type   * @private   */  function getToken() {    token_type = TOKENTYPE.NULL;    token = '';    comment = '';    // skip over whitespaces    // space, tab, and newline when inside parameters    while (parse.isWhitespace(c, nesting_level)) {      next();    }    // skip comment    if (c == '#') {      while (c != '\n' && c != '') {        comment += c;        next();      }    }    // check for end of expression    if (c == '') {      // token is still empty      token_type = TOKENTYPE.DELIMITER;      return;    }    // check for new line character    if (c == '\n' && !nesting_level) {      token_type = TOKENTYPE.DELIMITER;      token = c;      next();      return;    }    // check for delimiters consisting of 3 characters    var c2 = c + nextPreview();    var c3 = c2 + nextNextPreview();    if (c3.length == 3 && DELIMITERS[c3]) {      token_type = TOKENTYPE.DELIMITER;      token = c3;      next();      next();      next();      return;    }    // check for delimiters consisting of 2 characters    if (c2.length == 2 && DELIMITERS[c2]) {      token_type = TOKENTYPE.DELIMITER;      token = c2;      next();      next();      return;    }    // check for delimiters consisting of 1 character    if (DELIMITERS[c]) {      token_type = TOKENTYPE.DELIMITER;      token = c;      next();      return;    }    // check for a number    if (parse.isDigitDot(c)) {      token_type = TOKENTYPE.NUMBER;      // get number, can have a single dot      if (c == '.') {        token += c;        next();        if (!parse.isDigit(c)) {          // this is no number, it is just a dot (can be dot notation)          token_type = TOKENTYPE.DELIMITER;        }      }      else {        while (parse.isDigit(c)) {          token += c;          next();        }        if (parse.isDecimalMark(c, nextPreview())) {          token += c;          next();        }      }      while (parse.isDigit(c)) {        token += c;        next();      }      // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4"      c2 = nextPreview();      if (c == 'E' || c == 'e') {        if (parse.isDigit(c2) || c2 == '-' || c2 == '+') {          token += c;          next();          if (c == '+' || c == '-') {            token += c;            next();          }          // Scientific notation MUST be followed by an exponent          if (!parse.isDigit(c)) {            throw createSyntaxError('Digit expected, got "' + c + '"');          }          while (parse.isDigit(c)) {            token += c;            next();          }          if (parse.isDecimalMark(c, nextPreview())) {            throw createSyntaxError('Digit expected, got "' + c + '"');          }        }        else if (c2 == '.') {          next();          throw createSyntaxError('Digit expected, got "' + c + '"');        }      }      return;    }    // check for variables, functions, named operators    if (parse.isAlpha(c, prevPreview(), nextPreview())) {      while (parse.isAlpha(c, prevPreview(), nextPreview()) || parse.isDigit(c)) {        token += c;        next();      }      if (NAMED_DELIMITERS.hasOwnProperty(token)) {        token_type = TOKENTYPE.DELIMITER;      }      else {        token_type = TOKENTYPE.SYMBOL;      }      return;    }    // something unknown is found, wrong characters -> a syntax error    token_type = TOKENTYPE.UNKNOWN;    while (c != '') {      token += c;      next();    }    throw createSyntaxError('Syntax error in part "' + token + '"');  }  /**   * Get next token and skip newline tokens   */  function getTokenSkipNewline () {    do {      getToken();    }    while (token == '\n');  }  /**   * Open parameters.   * New line characters will be ignored until closeParams() is called   */  function openParams() {    nesting_level++;  }  /**   * Close parameters.   * New line characters will no longer be ignored   */  function closeParams() {    nesting_level--;  }  /**   * Checks whether the current character `c` is a valid alpha character:   *   * - A latin letter (upper or lower case) Ascii: a-z, A-Z   * - An underscore                        Ascii: _   * - A dollar sign                        Ascii: $   * - A latin letter with accents          Unicode: \u00C0 - \u02AF   * - A greek letter                       Unicode: \u0370 - \u03FF   * - A mathematical alphanumeric symbol   Unicode: \u{1D400} - \u{1D7FF} excluding invalid code points   *   * The previous and next characters are needed to determine whether   * this character is part of a unicode surrogate pair.   *   * @param {string} c      Current character in the expression   * @param {string} cPrev  Previous character   * @param {string} cNext  Next character   * @return {boolean}   */  parse.isAlpha = function isAlpha (c, cPrev, cNext) {    return parse.isValidLatinOrGreek(c)        || parse.isValidMathSymbol(c, cNext)        || parse.isValidMathSymbol(cPrev, c);  };  /**   * Test whether a character is a valid latin, greek, or letter-like character   * @param {string} c   * @return {boolean}   */  parse.isValidLatinOrGreek = function isValidLatinOrGreek (c) {    return /^[a-zA-Z_$\u00C0-\u02AF\u0370-\u03FF\u2100-\u214F]$/.test(c);  };  /**   * Test whether two given 16 bit characters form a surrogate pair of a   * unicode math symbol.   *   * http://unicode-table.com/en/   * http://www.wikiwand.com/en/Mathematical_operators_and_symbols_in_Unicode   *   * Note: In ES6 will be unicode aware:   * http://stackoverflow.com/questions/280712/javascript-unicode-regexes   * https://mathiasbynens.be/notes/es6-unicode-regex   *   * @param {string} high   * @param {string} low   * @return {boolean}   */  parse.isValidMathSymbol = function isValidMathSymbol (high, low) {    return /^[\uD835]$/.test(high) &&        /^[\uDC00-\uDFFF]$/.test(low) &&        /^[^\uDC55\uDC9D\uDCA0\uDCA1\uDCA3\uDCA4\uDCA7\uDCA8\uDCAD\uDCBA\uDCBC\uDCC4\uDD06\uDD0B\uDD0C\uDD15\uDD1D\uDD3A\uDD3F\uDD45\uDD47-\uDD49\uDD51\uDEA6\uDEA7\uDFCC\uDFCD]$/.test(low);  };  /**   * Check whether given character c is a white space character: space, tab, or enter   * @param {string} c   * @param {number} nestingLevel   * @return {boolean}   */  parse.isWhitespace = function isWhitespace (c, nestingLevel) {    // TODO: also take '\r' carriage return as newline? Or does that give problems on mac?    return c == ' ' || c == '\t' || (c == '\n' && nestingLevel > 0);  };  /**   * Test whether the character c is a decimal mark (dot).   * This is the case when it's not the start of a delimiter '.*', './', or '.^'   * @param {string} c   * @param {string} cNext   * @return {boolean}   */  parse.isDecimalMark = function isDecimalMark (c, cNext) {    return c == '.' && cNext !== '/' && cNext !== '*' && cNext !== '^';  };  /**   * checks if the given char c is a digit or dot   * @param {string} c   a string with one character   * @return {boolean}   */  parse.isDigitDot = function isDigitDot (c) {    return ((c >= '0' && c <= '9') || c == '.');  };  /**   * checks if the given char c is a digit   * @param {string} c   a string with one character   * @return {boolean}   */  parse.isDigit = function isDigit (c) {    return (c >= '0' && c <= '9');  };  /**   * Start of the parse levels below, in order of precedence   * @return {Node} node   * @private   */  function parseStart () {    // get the first character in expression    first();    getToken();    var node = parseBlock();    // check for garbage at the end of the expression    // an expression ends with a empty character '' and token_type DELIMITER    if (token != '') {      if (token_type == TOKENTYPE.DELIMITER) {        // user entered a not existing operator like "//"        // TODO: give hints for aliases, for example with "<>" give as hint " did you mean != ?"        throw createError('Unexpected operator ' + token);      }      else {        throw createSyntaxError('Unexpected part "' + token + '"');      }    }    return node;  }  /**   * Parse a block with expressions. Expressions can be separated by a newline   * character '\n', or by a semicolon ';'. In case of a semicolon, no output   * of the preceding line is returned.   * @return {Node} node   * @private   */  function parseBlock () {    var node;    var blocks = [];    var visible;    if (token != '' && token != '\n' && token != ';') {      node = parseAssignment();      node.comment = comment;    }    // TODO: simplify this loop    while (token == '\n' || token == ';') {      if (blocks.length == 0 && node) {        visible = (token != ';');        blocks.push({          node: node,          visible: visible        });      }      getToken();      if (token != '\n' && token != ';' && token != '') {        node = parseAssignment();        node.comment = comment;        visible = (token != ';');        blocks.push({          node: node,          visible: visible        });      }    }    if (blocks.length > 0) {      return new BlockNode(blocks);    }    else {      if (!node) {        node = new ConstantNode('undefined', 'undefined');        node.comment = comment;      }      return node    }  }  /**   * Assignment of a function or variable,   * - can be a variable like 'a=2.3'   * - or a updating an existing variable like 'matrix(2,3:5)=[6,7,8]'   * - defining a function like 'f(x) = x^2'   * @return {Node} node   * @private   */  function parseAssignment () {    var name, args, value, valid;    var node = parseConditional();    if (token == '=') {      if (type.isSymbolNode(node)) {        // parse a variable assignment like 'a = 2/3'        name = node.name;        getTokenSkipNewline();        value = parseAssignment();        return new AssignmentNode(new SymbolNode(name), value);      }      else if (type.isAccessorNode(node)) {        // parse a matrix subset assignment like 'A[1,2] = 4'        getTokenSkipNewline();        value = parseAssignment();        return new AssignmentNode(node.object, node.index, value);      }      // BUG: CWE-94 Improper Control of Generation of Code ('Code Injection')      // else if (type.isFunctionNode(node)) {      // FIXED:      else if (type.isFunctionNode(node) && type.isSymbolNode(node.fn)) {        // parse function assignment like 'f(x) = x^2'        valid = true;        args = [];        name = node.name;        node.args.forEach(function (arg, index) {          if (type.isSymbolNode(arg)) {            args[index] = arg.name;          }          else {            valid = false;          }        });        if (valid) {          getTokenSkipNewline();          value = parseAssignment();          return new FunctionAssignmentNode(name, args, value);        }      }      throw createSyntaxError('Invalid left hand side of assignment operator =');    }    return node;  }  /**   * conditional operation   *   *     condition ? truePart : falsePart   *   * Note: conditional operator is right-associative   *   * @return {Node} node   * @private   */  function parseConditional () {    var node = parseLogicalOr();    while (token == '?') {      // set a conditional level, the range operator will be ignored as long      // as conditional_level == nesting_level.      var prev = conditional_level;      conditional_level = nesting_level;      getTokenSkipNewline();      var condition = node;      var trueExpr = parseAssignment();      if (token != ':') throw createSyntaxError('False part of conditional expression expected');      conditional_level = null;      getTokenSkipNewline();      var falseExpr = parseAssignment(); // Note: check for conditional operator again, right associativity      node = new ConditionalNode(condition, trueExpr, falseExpr);      // restore the previous conditional level      conditional_level = prev;    }    return node;  }  /**   * logical or, 'x or y'   * @return {Node} node   * @private   */  function parseLogicalOr() {    var node = parseLogicalXor();    while (token == 'or') {      getTokenSkipNewline();      node = new OperatorNode('or', 'or', [node, parseLogicalXor()]);    }    return node;  }  /**   * logical exclusive or, 'x xor y'   * @return {Node} node   * @private   */  function parseLogicalXor() {    var node = parseLogicalAnd();    while (token == 'xor') {      getTokenSkipNewline();      node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd()]);    }    return node;  }  /**   * logical and, 'x and y'   * @return {Node} node   * @private   */  function parseLogicalAnd() {    var node = parseBitwiseOr();    while (token == 'and') {      getTokenSkipNewline();      node = new OperatorNode('and', 'and', [node, parseBitwiseOr()]);    }    return node;  }  /**   * bitwise or, 'x | y'   * @return {Node} node   * @private   */  function parseBitwiseOr() {    var node = parseBitwiseXor();    while (token == '|') {      getTokenSkipNewline();      node = new OperatorNode('|', 'bitOr', [node, parseBitwiseXor()]);    }    return node;  }  /**   * bitwise exclusive or (xor), 'x ^| y'   * @return {Node} node   * @private   */  function parseBitwiseXor() {    var node = parseBitwiseAnd();    while (token == '^|') {      getTokenSkipNewline();      node = new OperatorNode('^|', 'bitXor', [node, parseBitwiseAnd()]);    }    return node;  }  /**   * bitwise and, 'x & y'   * @return {Node} node   * @private   */  function parseBitwiseAnd () {    var node = parseRelational();    while (token == '&') {      getTokenSkipNewline();      node = new OperatorNode('&', 'bitAnd', [node, parseRelational()]);    }    return node;  }  /**   * relational operators   * @return {Node} node   * @private   */  function parseRelational () {    var node, operators, name, fn, params;    node = parseShift();    operators = {      '==': 'equal',      '!=': 'unequal',      '<': 'smaller',      '>': 'larger',      '<=': 'smallerEq',      '>=': 'largerEq'    };    while (operators.hasOwnProperty(token)) {      name = token;      fn = operators[name];      getTokenSkipNewline();      params = [node, parseShift()];      node = new OperatorNode(name, fn, params);    }    return node;  }  /**   * Bitwise left shift, bitwise right arithmetic shift, bitwise right logical shift   * @return {Node} node   * @private   */  function parseShift () {    var node, operators, name, fn, params;    node = parseConversion();    operators = {      '<<' : 'leftShift',      '>>' : 'rightArithShift',      '>>>' : 'rightLogShift'    };    while (operators.hasOwnProperty(token)) {      name = token;      fn = operators[name];      getTokenSkipNewline();      params = [node, parseConversion()];      node = new OperatorNode(name, fn, params);    }    return node;  }  /**   * conversion operators 'to' and 'in'   * @return {Node} node   * @private   */  function parseConversion () {    var node, operators, name, fn, params;    node = parseRange();    operators = {      'to' : 'to',      'in' : 'to'   // alias of 'to'    };    while (operators.hasOwnProperty(token)) {      name = token;      fn = operators[name];      getTokenSkipNewline();            if (name === 'in' && token === '') {        // end of expression -> this is the unit 'in' ('inch')        node = new OperatorNode('*', 'multiply', [node, new SymbolNode('in')], true);      }      else {        // operator 'a to b' or 'a in b'        params = [node, parseRange()];        node = new OperatorNode(name, fn, params);      }    }    return node;  }  /**   * parse range, "start:end", "start:step:end", ":", "start:", ":end", etc   * @return {Node} node   * @private   */  function parseRange () {    var node, params = [];    if (token == ':') {      // implicit start=1 (one-based)      node = new ConstantNode('1', 'number');    }    else {      // explicit start      node = parseAddSubtract();    }    if (token == ':' && (conditional_level !== nesting_level)) {      // we ignore the range operator when a conditional operator is being processed on the same level      params.push(node);      // parse step and end      while (token == ':' && params.length < 3) {        getTokenSkipNewline();        if (token == ')' || token == ']' || token == ',' || token == '') {          // implicit end          params.push(new SymbolNode('end'));        }        else {          // explicit end          params.push(parseAddSubtract());        }      }      if (params.length == 3) {        // params = [start, step, end]        node = new RangeNode(params[0], params[2], params[1]); // start, end, step      }      else { // length == 2        // params = [start, end]        node = new RangeNode(params[0], params[1]); // start, end      }    }    return node;  }  /**   * add or subtract   * @return {Node} node   * @private   */  function parseAddSubtract ()  {    var node, operators, name, fn, params;    node = parseMultiplyDivide();    operators = {      '+': 'add',      '-': 'subtract'    };    while (operators.hasOwnProperty(token)) {      name = token;      fn = operators[name];      getTokenSkipNewline();      params = [node, parseMultiplyDivide()];      node = new OperatorNode(name, fn, params);    }    return node;  }  /**   * multiply, divide, modulus   * @return {Node} node   * @private   */  function parseMultiplyDivide () {    var node, last, operators, name, fn;    node = parseUnary();    last = node;    operators = {      '*': 'multiply',      '.*': 'dotMultiply',      '/': 'divide',      './': 'dotDivide',      '%': 'mod',      'mod': 'mod'    };    while (true) {      if (operators.hasOwnProperty(token)) {        // explicit operators        name = token;        fn = operators[name];        getTokenSkipNewline();        last = parseUnary();        node = new OperatorNode(name, fn, [node, last]);      }      else if ((token_type === TOKENTYPE.SYMBOL) ||          (token === 'in' && type.isConstantNode(node)) ||          (token_type === TOKENTYPE.NUMBER &&              !type.isConstantNode(last) &&              (!type.isOperatorNode(last) || last.op === '!')) ||          (token === '(')) {        // parse implicit multiplication        //        // symbol:      implicit multiplication like '2a', '(2+3)a', 'a b'        // number:      implicit multiplication like '(2+3)2'        // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)'        last = parseUnary();        node = new OperatorNode('*', 'multiply', [node, last], true /*implicit*/);      }      else {        break;      }    }    return node;  }  /**   * Unary plus and minus, and logical and bitwise not   * @return {Node} node   * @private   */  function parseUnary () {    var name, params, fn;    var operators = {      '-': 'unaryMinus',      '+': 'unaryPlus',      '~': 'bitNot',      'not': 'not'    };    if (operators.hasOwnProperty(token)) {      fn = operators[token];      name = token;      getTokenSkipNewline();      params = [parseUnary()];      return new OperatorNode(name, fn, params);    }    return parsePow();  }  /**   * power   * Note: power operator is right associative   * @return {Node} node   * @private   */  function parsePow () {    var node, name, fn, params;    node = parseLeftHandOperators();    if (token == '^' || token == '.^') {      name = token;      fn = (name == '^') ? 'pow' : 'dotPow';      getTokenSkipNewline();      params = [node, parseUnary()]; // Go back to unary, we can have '2^-3'      node = new OperatorNode(name, fn, params);    }    return node;  }  /**   * Left hand operators: factorial x!, transpose x'   * @return {Node} node   * @private   */  function parseLeftHandOperators ()  {    var node, operators, name, fn, params;    node = parseCustomNodes();    operators = {      '!': 'factorial',      '\'': 'transpose'    };    while (operators.hasOwnProperty(token)) {      name = token;      fn = operators[name];      getToken();      params = [node];      node = new OperatorNode(name, fn, params);      node = parseAccessors(node);    }    return node;  }  /**   * Parse a custom node handler. A node handler can be used to process   * nodes in a custom way, for example for handling a plot.   *   * A handler must be passed as second argument of the parse function.   * - must extend math.expression.node.Node   * - must contain a function _compile(defs: Object) : string   * - must contain a function find(filter: Object) : Node[]   * - must contain a function toString() : string   * - the constructor is called with a single argument containing all parameters   *   * For example:   *   *     nodes = {   *       'plot': PlotHandler   *     };   *   * The constructor of the handler is called as:   *   *     node = new PlotHandler(params);   *   * The handler will be invoked when evaluating an expression like:   *   *     node = math.parse('plot(sin(x), x)', nodes);   *   * @return {Node} node   * @private   */  function parseCustomNodes () {    var params = [];    if (token_type == TOKENTYPE.SYMBOL && extra_nodes.hasOwnProperty(token)) {      var CustomNode = extra_nodes[token];      getToken();      // parse parameters      if (token == '(') {        params = [];        openParams();        getToken();        if (token != ')') {          params.push(parseAssignment());          // parse a list with parameters          while (token == ',') {            getToken();            params.push(parseAssignment());          }        }        if (token != ')') {          throw createSyntaxError('Parenthesis ) expected');        }        closeParams();        getToken();      }      // create a new custom node      //noinspection JSValidateTypes      return new CustomNode(params);    }    return parseSymbol();  }  /**   * parse symbols: functions, variables, constants, units   * @return {Node} node   * @private   */  function parseSymbol () {    var node, name;    if (token_type == TOKENTYPE.SYMBOL ||        (token_type == TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) {      name = token;      getToken();      // parse function parameters and matrix index      node = new SymbolNode(name);      node = parseAccessors(node);      return node;    }    return parseString();  }  /**   * parse accessors:   * - function invocation in round brackets (...), for example sqrt(2)   * - index enclosed in square brackets [...], for example A[2,3]   * - dot notation for properties, like foo.bar   * @param {Node} node    Node on which to apply the parameters. If there   *                       are no parameters in the expression, the node   *                       itself is returned   * @param {string[]} [types]  Filter the types of notations   *                            can be ['(', '[', '.']   * @return {Node} node   * @private   */  function parseAccessors (node, types) {    var params;    while ((token === '(' || token === '[' || token === '.') &&        (!types || types.indexOf(token) !== -1)) {      params = [];      if (token === '(') {        if (type.isSymbolNode(node) || type.isAccessorNode(node) || type.isFunctionNode(node)) {          // function invocation like fn(2, 3)          openParams();          getToken();          if (token !== ')') {            params.push(parseAssignment());            // parse a list with parameters            while (token === ',') {              getToken();              params.push(parseAssignment());            }          }          if (token !== ')') {            throw createSyntaxError('Parenthesis ) expected');          }          closeParams();          getToken();          node = new FunctionNode(node, params);        }        else {          // implicit multiplication like (2+3)(4+5)          // don't parse it here but let it be handled by parseMultiplyDivide          // with correct precedence          return node;        }      }      else if (token === '[') {        // index notation like variable[2, 3]        openParams();        getToken();        if (token !== ']') {          params.push(parseAssignment());          // parse a list with parameters          while (token === ',') {            getToken();            params.push(parseAssignment());          }        }        if (token !== ']') {          throw createSyntaxError('Parenthesis ] expected');        }        closeParams();        getToken();        node = new AccessorNode(node, new IndexNode(params));      }      else {        // dot notation like variable.prop        getToken();        if (token_type !== TOKENTYPE.SYMBOL) {          throw createSyntaxError('Property name expected after dot');        }        params.push(new ConstantNode(token));        getToken();        var dotNotation = true;        node = new AccessorNode(node, new IndexNode(params, dotNotation));      }    }    return node;  }  /**   * parse a string.   * A string is enclosed by double quotes   * @return {Node} node   * @private   */  function parseString () {    var node, str;    if (token == '"') {      str = parseStringToken();      // create constant      node = new ConstantNode(str, 'string');      // parse index parameters      node = parseAccessors(node);      return node;    }    return parseMatrix();  }  /**   * Parse a string surrounded by double quotes "..."   * @return {string}   */  function parseStringToken () {    var str = '';    while (c != '' && c != '\"') {      if (c == '\\') {        // escape character        str += c;        next();      }      str += c;      next();    }    getToken();    if (token != '"') {      throw createSyntaxError('End of string " expected');    }    getToken();    return str;  }  /**   * parse the matrix   * @return {Node} node   * @private   */  function parseMatrix () {    var array, params, rows, cols;    if (token == '[') {      // matrix [...]      openParams();      getToken();      if (token != ']') {        // this is a non-empty matrix        var row = parseRow();        if (token == ';') {          // 2 dimensional array          rows = 1;          params = [row];          // the rows of the matrix are separated by dot-comma's          while (token == ';') {            getToken();            params[rows] = parseRow();            rows++;          }          if (token != ']') {            throw createSyntaxError('End of matrix ] expected');          }          closeParams();          getToken();          // check if the number of columns matches in all rows          cols = params[0].items.length;          for (var r = 1; r < rows; r++) {            if (params[r].items.length != cols) {              throw createError('Column dimensions mismatch ' +                  '(' + params[r].items.length + ' != ' + cols + ')');            }          }          array = new ArrayNode(params);        }        else {          // 1 dimensional vector          if (token != ']') {            throw createSyntaxError('End of matrix ] expected');          }          closeParams();          getToken();          array = row;        }      }      else {        // this is an empty matrix "[ ]"        closeParams();        getToken();        array = new ArrayNode([]);      }      return parseAccessors(array);    }    return parseObject();  }  /**   * Parse a single comma-separated row from a matrix, like 'a, b, c'   * @return {ArrayNode} node   */  function parseRow () {    var params = [parseAssignment()];    var len = 1;    while (token == ',') {      getToken();      // parse expression      params[len] = parseAssignment();      len++;    }    return new ArrayNode(params);  }  /**   * parse an object, enclosed in angle brackets{...}, for example {value: 2}   * @return {Node} node   * @private   */  function parseObject () {    if (token == '{') {      var key;      var properties = {};      do {        getToken();        if (token != '}') {          // parse key          if (token == '"') {            key = parseStringToken();          }          else if (token_type == TOKENTYPE.SYMBOL) {            key = token;            getToken();          }          else {            throw createSyntaxError('Symbol or string expected as object key');          }          // parse key/value separator          if (token != ':') {            throw createSyntaxError('Colon : expected after object key');          }          getToken();          // parse key          properties[key] = parseAssignment();        }      }      while (token == ',');      if (token != '}') {        throw createSyntaxError('Comma , or bracket } expected after object value');      }      getToken();      var node = new ObjectNode(properties);      // parse index parameters      node = parseAccessors(node);      return node;    }    return parseNumber();  }  /**   * parse a number   * @return {Node} node   * @private   */  function parseNumber () {    var number;    if (token_type == TOKENTYPE.NUMBER) {      // this is a number      number = token;      getToken();      return new ConstantNode(number, 'number');    }    return parseParentheses();  }  /**   * parentheses   * @return {Node} node   * @private   */  function parseParentheses () {    var node;    // check if it is a parenthesized expression    if (token == '(') {      // parentheses (...)      openParams();      getToken();      node = parseAssignment(); // start again      if (token != ')') {        throw createSyntaxError('Parenthesis ) expected');      }      closeParams();      getToken();      node = new ParenthesisNode(node);      node = parseAccessors(node);      return node;    }    return parseEnd();  }  /**   * Evaluated when the expression is not yet ended but expected to end   * @return {Node} res   * @private   */  function parseEnd () {    if (token == '') {      // syntax error or unexpected end of expression      throw createSyntaxError('Unexpected end of expression');    } else if (token === "'") {      throw createSyntaxError('Value expected. Note: strings must be enclosed by double quotes');    } else {      throw createSyntaxError('Value expected');    }  }  /**   * Shortcut for getting the current row value (one based)   * Returns the line of the currently handled expression   * @private   */  /* TODO: implement keeping track on the row number  function row () {    return null;  }  */  /**   * Shortcut for getting the current col value (one based)   * Returns the column (position) where the last token starts   * @private   */  function col () {    return index - token.length + 1;  }  /**   * Create an error   * @param {string} message   * @return {SyntaxError} instantiated error   * @private   */  function createSyntaxError (message) {    var c = col();    var error = new SyntaxError(message + ' (char ' + c + ')');    error['char'] = c;    return error;  }  /**   * Create an error   * @param {string} message   * @return {Error} instantiated error   * @private   */  function createError (message) {    var c = col();    var error = new SyntaxError(message + ' (char ' + c + ')');    error['char'] = c;    return error;  }  return parse;}exports.name = 'parse';exports.path = 'expression';exports.factory = factory;