From 8f96965d368474ca0bc9e8b7ccab0b85d208725e Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Sat, 26 Jul 2014 06:09:29 +0300 Subject: [PATCH] Added `yield` support (completed generators). --- acorn.js | 35 +++++++++++++++++-------- test/tests-harmony.js | 60 +++++++++++++++++++++---------------------- 2 files changed, 55 insertions(+), 40 deletions(-) diff --git a/acorn.js b/acorn.js index aa61b1524d..4101aa783b 100644 --- a/acorn.js +++ b/acorn.js @@ -220,11 +220,12 @@ var lastStart, lastEnd, lastEndLoc; // This is the parser's state. `inFunction` is used to reject - // `return` statements outside of functions, `labels` to verify that - // `break` and `continue` have somewhere to jump to, and `strict` - // indicates whether strict mode is on. + // `return` statements outside of functions, `inGenerator` to + // reject `yield`s outside of generators, `labels` to verify + // that `break` and `continue` have somewhere to jump to, and + // `strict` indicates whether strict mode is on. - var inFunction, labels, strict; + var inFunction, inGenerator, labels, strict; // This counter is used for checking that arrow expressions did // not contain nested parentheses in argument list. @@ -294,6 +295,7 @@ var _this = {keyword: "this"}; var _class = {keyword: "class"}, _extends = {keyword: "extends", beforeExpr: true}, _static = {keyword: "static"}; var _export = {keyword: "export"}, _import = {keyword: "import"}, _from = {keyword: "from"}, _as = {keyword: "as"}; + var _yield = {keyword: "yield", beforeExpr: true}; // The keywords that denote values. @@ -321,7 +323,7 @@ "void": {keyword: "void", prefix: true, beforeExpr: true}, "delete": {keyword: "delete", prefix: true, beforeExpr: true}, "class": _class, "extends": _extends, "static": _static, "of": _of, - "export": _export, "import": _import, "from": _from, "as": _as}; + "export": _export, "import": _import, "from": _from, "as": _as, "yield": _yield}; // Punctuation token types. Again, the `type` property is purely for debugging. @@ -441,7 +443,7 @@ var isEcma5AndLessKeyword = makePredicate(ecma5AndLessKeywords); - var isEcma6Keyword = makePredicate(ecma5AndLessKeywords + " let const class extends static of export import from as"); + var isEcma6Keyword = makePredicate(ecma5AndLessKeywords + " let const class extends static of export import from as yield"); var isKeyword = isEcma5AndLessKeyword; @@ -1247,7 +1249,7 @@ function parseTopLevel(program) { lastStart = lastEnd = tokPos; if (options.locations) lastEndLoc = new Position; - inFunction = strict = null; + inFunction = inGenerator = strict = null; labels = []; readToken(); @@ -1855,6 +1857,9 @@ case _bquote: return parseTemplate(); + case _yield: + return inGenerator ? parseYield() : parseIdent(true); + default: unexpected(); } @@ -2119,11 +2124,11 @@ } else { // Start a new scope with regard to labels and the `inFunction` // flag (restore them to their old value afterwards). - var oldInFunc = inFunction, oldLabels = labels; - inFunction = true; labels = []; + var oldInFunc = inFunction, oldInGen = inGenerator, oldLabels = labels; + inFunction = true; inGenerator = node.generator; labels = []; node.body = parseBlock(true); node.expression = false; - inFunction = oldInFunc; labels = oldLabels; + inFunction = oldInFunc; inGenerator = oldInGen; labels = oldLabels; } // If this is a strict mode function, verify that argument names @@ -2410,4 +2415,14 @@ return nodes; } + // Parses yield expression inside generator. + + function parseYield() { + var node = startNode(); + next(); + node.delegate = parseIsGenerator(); + node.argument = parseExpression(true); + return finishNode(node, "YieldExpression"); + } + }); diff --git a/test/tests-harmony.js b/test/tests-harmony.js index ce1d9415b9..d0ad3c7b16 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -5933,10 +5933,10 @@ test("(function* () { yield v })", { end: {line: 1, column: 23} } }, - range: [16, 24], + range: [16, 23], loc: { start: {line: 1, column: 16}, - end: {line: 1, column: 24} + end: {line: 1, column: 23} } }], range: [14, 25], @@ -5948,10 +5948,10 @@ test("(function* () { yield v })", { rest: null, generator: true, expression: false, - range: [1, 25], + range: [0, 26], loc: { - start: {line: 1, column: 1}, - end: {line: 1, column: 25} + start: {line: 1, column: 0}, + end: {line: 1, column: 26} } }, range: [0, 26], @@ -6002,10 +6002,10 @@ test("(function* () { yield *v })", { end: {line: 1, column: 24} } }, - range: [16, 25], + range: [16, 24], loc: { start: {line: 1, column: 16}, - end: {line: 1, column: 25} + end: {line: 1, column: 24} } }], range: [14, 26], @@ -6017,10 +6017,10 @@ test("(function* () { yield *v })", { rest: null, generator: true, expression: false, - range: [1, 26], + range: [0, 27], loc: { - start: {line: 1, column: 1}, - end: {line: 1, column: 26} + start: {line: 1, column: 0}, + end: {line: 1, column: 27} } }, range: [0, 27], @@ -6077,10 +6077,10 @@ test("function* test () { yield *v }", { end: {line: 1, column: 28} } }, - range: [20, 29], + range: [20, 28], loc: { start: {line: 1, column: 20}, - end: {line: 1, column: 29} + end: {line: 1, column: 28} } }], range: [18, 30], @@ -6164,10 +6164,10 @@ test("var x = { *test () { yield *v } };", { end: {line: 1, column: 29} } }, - range: [21, 30], + range: [21, 29], loc: { start: {line: 1, column: 21}, - end: {line: 1, column: 30} + end: {line: 1, column: 29} } }], range: [19, 31], @@ -6179,9 +6179,9 @@ test("var x = { *test () { yield *v } };", { rest: null, generator: true, expression: false, - range: [19, 31], + range: [16, 31], loc: { - start: {line: 1, column: 19}, + start: {line: 1, column: 16}, end: {line: 1, column: 31} } }, @@ -6310,10 +6310,10 @@ test("(function* () { yield yield 10 })", { end: {line: 1, column: 30} } }, - range: [16, 31], + range: [16, 30], loc: { start: {line: 1, column: 16}, - end: {line: 1, column: 31} + end: {line: 1, column: 30} } }], range: [14, 32], @@ -6325,10 +6325,10 @@ test("(function* () { yield yield 10 })", { rest: null, generator: true, expression: false, - range: [1, 32], + range: [0, 33], loc: { - start: {line: 1, column: 1}, - end: {line: 1, column: 32} + start: {line: 1, column: 0}, + end: {line: 1, column: 33} } }, range: [0, 33], @@ -7619,9 +7619,9 @@ test("class A {*gen(v) { yield v; }}", { rest: null, generator: true, expression: false, - range: [17, 29], + range: [13, 29], loc: { - start: {line: 1, column: 17}, + start: {line: 1, column: 13}, end: {line: 1, column: 29} } }, @@ -7733,9 +7733,9 @@ test("class A { static *gen(v) { yield v; }}", { rest: null, generator: true, expression: false, - range: [25, 37], + range: [21, 37], loc: { - start: {line: 1, column: 25}, + start: {line: 1, column: 21}, end: {line: 1, column: 37} } }, @@ -9887,9 +9887,9 @@ test("var x = {*[test]() { yield *v; }}", { rest: null, generator: true, expression: false, - range: [19, 32], + range: [16, 32], loc: { - start: {line: 1, column: 19}, + start: {line: 1, column: 16}, end: {line: 1, column: 32} } }, @@ -14653,7 +14653,7 @@ test("e => yield* 10", { locations: true }); -testFail("(function () { yield 10 })", "Unexpected token (1:22)", {ecmaVersion: 6}); +testFail("(function () { yield 10 })", "Unexpected token (1:21)", {ecmaVersion: 6}); test("(function () { yield* 10 })", { type: "Program", @@ -14736,9 +14736,9 @@ test("(function () { yield* 10 })", { testFail("(function() { \"use strict\"; f(yield v) })", "Unexpected token (1:36)", {ecmaVersion: 6}); -testFail("var obj = { *test** }", "Unexpected token (1:18)", {ecmaVersion: 6}); +testFail("var obj = { *test** }", "Unexpected token (1:17)", {ecmaVersion: 6}); -testFail("class A extends yield B { }", "Unexpected token (1:23)", {ecmaVersion: 6}); +testFail("class A extends yield B { }", "Unexpected token (1:22)", {ecmaVersion: 6}); testFail("class default", "Unexpected token (1:6)", {ecmaVersion: 6});