Code coverage report for sc/lang/compiler/parser/binop-expr.js

Statements: 100% (81 / 81)      Branches: 100% (22 / 22)      Functions: 100% (15 / 15)      Lines: 100% (81 / 81)      Ignored: none     

All files » sc/lang/compiler/parser/ » binop-expr.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 1611     1   1 1 1 1                           1 603     1 603 603   1   1 603   603   598 598 566     32   27     1 628 2     626 507 507 44   463 33       549     1 35 35 35 30     1 27 27   27 27 3   3   3 3     27     1 35 26     9   9 9   9 2     7 2         5     1 3 2 2 2 2 2           1 27   27 27 28         27     1 2     1 5     1 463     1 9     1 7 4   3      
(function(sc) {
  "use strict";
 
  require("./parser");
 
  var Token = sc.lang.compiler.Token;
  var Syntax = sc.lang.compiler.Syntax;
  var Node = sc.lang.compiler.Node;
  var Parser = sc.lang.compiler.Parser;
 
  /*
    BinaryExpression :
      CallExpression BinaryExpressionOperator BinaryExpressionAdverb(opts) BinaryExpression
 
    BinaryExpressionOperator :
      /[-+*\/%<=>!?&|@]+/
      LabelLiteral
 
    BinaryExpressionAdverb :
      . Identifier
      . IntegerLiteral
  */
  Parser.addParseMethod("BinaryExpression", function() {
    return new BinaryExpressionParser(this).parse();
  });
 
  function BinaryExpressionParser(parent) {
    Parser.call(this, parent);
    this.binaryPrecedence = sc.config.get("binaryPrecedence");
  }
  sc.libs.extend(BinaryExpressionParser, Parser);
 
  BinaryExpressionParser.prototype.parse = function() {
    var marker = this.createMarker();
 
    var expr = this.parseCallExpression();
 
    var prec = this.calcBinaryPrecedence(this.lookahead);
    if (prec === 0) {
      return expr;
    }
 
    var operator = this.parseBinaryExpressionOperator(prec);
 
    return this.sortByBinaryPrecedence(expr, operator, marker);
  };
 
  BinaryExpressionParser.prototype.calcBinaryPrecedence = function(token) {
    if (token.type === Token.Label) {
      return 255;
    }
 
    if (token.type === Token.Punctuator) {
      var operator = token.value;
      if (operator === "=") {
        return 0;
      }
      if (isBinaryOperator(operator)) {
        return this.binaryPrecedence[operator] || 255;
      }
    }
 
    return 0;
  };
 
  BinaryExpressionParser.prototype.parseBinaryExpressionOperator = function(prec) {
    var operator = this.lex();
    operator.prec = prec;
    operator.adverb = this.parseBinaryExpressionAdverb();
    return operator;
  };
 
  BinaryExpressionParser.prototype.sortByBinaryPrecedence = function(left, operator, marker) {
    var markerStack = [ marker, this.createMarker() ];
    var exprOpStack = [ left, operator, this.parseCallExpression() ];
 
    var prec;
    while ((prec = this.calcBinaryPrecedence(this.lookahead)) > 0) {
      sortByBinaryPrecedence(prec, exprOpStack, markerStack);
 
      operator = this.parseBinaryExpressionOperator(prec);
 
      markerStack.push(this.createMarker());
      exprOpStack.push(operator, this.parseCallExpression());
    }
 
    return reduceBinaryExpressionStack(exprOpStack, markerStack);
  };
 
  BinaryExpressionParser.prototype.parseBinaryExpressionAdverb = function() {
    if (!this.match(".")) {
      return null;
    }
 
    this.lex();
 
    var lookahead = this.lookahead;
    var adverb = this.parsePrimaryExpression();
 
    if (isInteger(adverb)) {
      return adverb;
    }
 
    if (isAdverb(adverb)) {
      return this.createMarker(adverb).update().apply(
        Node.createLiteral({ type: Token.SymbolLiteral, value: adverb.name })
      );
    }
 
    return this.throwUnexpected(lookahead);
  };
 
  function sortByBinaryPrecedence(prec, exprOpStack, markerStack) {
    while (isNeedSort(prec, exprOpStack)) {
      var right    = exprOpStack.pop();
      var operator = exprOpStack.pop();
      var left     = exprOpStack.pop();
      markerStack.pop();
      exprOpStack.push(peek(markerStack).update().apply(
        Node.createBinaryExpression(operator, left, right)
      ));
    }
  }
 
  function reduceBinaryExpressionStack(exprOpStack, markerStack) {
    markerStack.pop();
 
    var expr = exprOpStack.pop();
    while (exprOpStack.length) {
      expr = markerStack.pop().update().apply(
        Node.createBinaryExpression(exprOpStack.pop(), exprOpStack.pop(), expr)
      );
    }
 
    return expr;
  }
 
  function peek(stack) {
    return stack[stack.length - 1];
  }
 
  function isNeedSort(prec, exprOpStack) {
    return exprOpStack.length > 2 && prec <= exprOpStack[exprOpStack.length - 2].prec;
  }
 
  function isBinaryOperator(operator) {
    return (/^[-+*\/%<=>!?&|@]+$/).test(operator);
  }
 
  function isInteger(node) {
    return node.valueType === Token.IntegerLiteral;
  }
 
  function isAdverb(node) {
    if (node.type === Syntax.Identifier) {
      return (/^[a-z]$/).test(node.name.charAt(0));
    }
    return false;
  }
})(sc);