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

Statements: 100% (70 / 70)      Branches: 100% (23 / 23)      Functions: 100% (15 / 15)      Lines: 100% (70 / 70)      Ignored: none     

All files » sc/lang/compiler/parser/ » function-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 161 162 163 164 165 166 167 168 169 170 1711     1   1 1                                             1 92                             1 102             1 8 8   6   6     1 194   1   1 92   92   92   92 92 86 81     81   80     1 92 27   65 3   62     1 30   30       24 6 6 6     24   24     1 30   30 28 37 31 22   9 7         24     1 37     10         1 188     1 188   188 35     184     1 184   184 113 112 17   95 19       182      
(function(sc) {
  "use strict";
 
  require("./parser");
 
  var Node = sc.lang.compiler.Node;
  var Parser = sc.lang.compiler.Parser;
 
  /*
    FunctionExpression :
      { FunctionParameterDeclaration(opt) FunctionBody(opt) }
 
    FunctionParameterDeclaration :
         | FunctionParameter |
      args FunctionParameter ;
 
    FunctionParameter :
      FunctionParameterElements
      FunctionParameterElements ... Identifier
                                ... Identifier
 
    FunctionParameterElements :
      FunctionParameterElement
      FunctionParameterElements , FunctionParameterElement
 
    FunctionParameterElement :
      Identifier
      Identifier = parsePrimaryArgExpression
  */
  Parser.addParseMethod("FunctionExpression", function(opts) {
    return new FunctionExpressionParser(this).parse(opts);
  });
 
  /*
    FunctionBody :
      VariableStatements(opt) SourceElements(opt)
 
    VariableStatements :
      VariableStatement
      VariableStatements VariableStatement
 
    SourceElements :
      Expression
      SourceElements ; Expression
  */
  Parser.addParseMethod("FunctionBody", function() {
    return new FunctionExpressionParser(this).parseFunctionBody();
  });
 
  /*
    ClosedFunctionExpression :
      # FunctionExpression
  */
  Parser.addParseMethod("ClosedFunctionExpression", function() {
    var marker = this.createMarker();
    this.expect("#");
 
    var expr = this.parseFunctionExpression({ closed: true });
 
    return marker.update().apply(expr, true);
  });
 
  function FunctionExpressionParser(parent) {
    Parser.call(this, parent);
  }
  sc.libs.extend(FunctionExpressionParser, Parser);
 
  FunctionExpressionParser.prototype.parse = function(opts) {
    opts = opts || {};
 
    var marker = this.createMarker();
 
    this.expect("{");
 
    var node = this.withScope(function() {
      var args = this.parseFunctionParameterDeclaration();
      var body = this.parseFunctionBody();
      return Node.createFunctionExpression(args, body, opts);
    });
 
    this.expect("}");
 
    return marker.update().apply(node);
  };
 
  FunctionExpressionParser.prototype.parseFunctionParameterDeclaration = function() {
    if (this.match("|")) {
      return this.parseFunctionParameter("|");
    }
    if (this.match("arg")) {
      return this.parseFunctionParameter(";");
    }
    return null;
  };
 
  FunctionExpressionParser.prototype.parseFunctionParameter = function(sentinel) {
    this.lex();
 
    var args = {
      list: this.parseFunctionParameterElements(sentinel)
    };
 
    if (this.match("...")) {
      this.lex();
      args.remain = this.parseIdentifier({ variable: true });
      this.addToScope("arg", args.remain.name);
    }
 
    this.expect(sentinel);
 
    return args;
  };
 
  FunctionExpressionParser.prototype.parseFunctionParameterElements = function(sentinel) {
    var elements = [];
 
    if (!this.match("...")) {
      while (this.hasNextToken()) {
        elements.push(this.parseFunctionParameterElement());
        if (this.matchAny([ sentinel, "..." ]) || (sentinel === ";" && !this.match(","))) {
          break;
        }
        if (this.match(",")) {
          this.lex();
        }
      }
    }
 
    return elements;
  };
 
  FunctionExpressionParser.prototype.parseFunctionParameterElement = function() {
    return this.parseDeclarator({
      type: "arg",
      delegate: function() {
        return this.parsePrimaryArgExpression();
      }
    });
  };
 
  FunctionExpressionParser.prototype.parseFunctionBody = function() {
    return this.parseVariableStatements().concat(this.parseSourceElements());
  };
 
  FunctionExpressionParser.prototype.parseVariableStatements = function() {
    var elements = [];
 
    while (this.match("var")) {
      elements.push(this.parseVariableStatement());
    }
 
    return elements;
  };
 
  FunctionExpressionParser.prototype.parseSourceElements = function() {
    var elements = [];
 
    while (this.hasNextToken() && !this.matchAny([ "}", ")" ])) {
      elements.push(this.parseExpression());
      if (this.matchAny([ "}", ")" ])) {
        break;
      }
      if (this.hasNextToken()) {
        this.expect(";");
      }
    }
 
    return elements;
  };
})(sc);