michael@0: // |reftest| skip-if(!xulRuntime.shell) michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* michael@0: * Any copyright is dedicated to the Public Domain. michael@0: * http://creativecommons.org/licenses/publicdomain/ michael@0: */ michael@0: michael@0: (function runtest(main) { michael@0: try { michael@0: main(); michael@0: } catch (exc) { michael@0: print(exc.stack); michael@0: throw exc; michael@0: } michael@0: })(function main() { michael@0: michael@0: var { Pattern, MatchError } = Match; michael@0: michael@0: var _ = Pattern.ANY; michael@0: michael@0: function program(elts) Pattern({ type: "Program", body: elts }) michael@0: function exprStmt(expr) Pattern({ type: "ExpressionStatement", expression: expr }) michael@0: function throwStmt(expr) Pattern({ type: "ThrowStatement", argument: expr }) michael@0: function returnStmt(expr) Pattern({ type: "ReturnStatement", argument: expr }) michael@0: function yieldExpr(expr) Pattern({ type: "YieldExpression", argument: expr }) michael@0: function lit(val) Pattern({ type: "Literal", value: val }) michael@0: function spread(val) Pattern({ type: "SpreadExpression", expression: val}) michael@0: var thisExpr = Pattern({ type: "ThisExpression" }); michael@0: function funDecl(id, params, body, defaults=[], rest=null) Pattern( michael@0: { type: "FunctionDeclaration", michael@0: id: id, michael@0: params: params, michael@0: defaults: defaults, michael@0: body: body, michael@0: rest: rest, michael@0: generator: false }) michael@0: function genFunDecl(id, params, body) Pattern({ type: "FunctionDeclaration", michael@0: id: id, michael@0: params: params, michael@0: defaults: [], michael@0: body: body, michael@0: generator: true }) michael@0: function varDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" }) michael@0: function letDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" }) michael@0: function constDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" }) michael@0: function ident(name) Pattern({ type: "Identifier", name: name }) michael@0: function dotExpr(obj, id) Pattern({ type: "MemberExpression", computed: false, object: obj, property: id }) michael@0: function memExpr(obj, id) Pattern({ type: "MemberExpression", computed: true, object: obj, property: id }) michael@0: function forStmt(init, test, update, body) Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body }) michael@0: function forOfStmt(lhs, rhs, body) Pattern({ type: "ForOfStatement", left: lhs, right: rhs, body: body }) michael@0: function forInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: false }) michael@0: function forEachInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: true }) michael@0: function breakStmt(lab) Pattern({ type: "BreakStatement", label: lab }) michael@0: function continueStmt(lab) Pattern({ type: "ContinueStatement", label: lab }) michael@0: function blockStmt(body) Pattern({ type: "BlockStatement", body: body }) michael@0: var emptyStmt = Pattern({ type: "EmptyStatement" }) michael@0: function ifStmt(test, cons, alt) Pattern({ type: "IfStatement", test: test, alternate: alt, consequent: cons }) michael@0: function labStmt(lab, stmt) Pattern({ type: "LabeledStatement", label: lab, body: stmt }) michael@0: function withStmt(obj, stmt) Pattern({ type: "WithStatement", object: obj, body: stmt }) michael@0: function whileStmt(test, stmt) Pattern({ type: "WhileStatement", test: test, body: stmt }) michael@0: function doStmt(stmt, test) Pattern({ type: "DoWhileStatement", test: test, body: stmt }) michael@0: function switchStmt(disc, cases) Pattern({ type: "SwitchStatement", discriminant: disc, cases: cases }) michael@0: function caseClause(test, stmts) Pattern({ type: "SwitchCase", test: test, consequent: stmts }) michael@0: function defaultClause(stmts) Pattern({ type: "SwitchCase", test: null, consequent: stmts }) michael@0: function catchClause(id, guard, body) Pattern({ type: "CatchClause", param: id, guard: guard, body: body }) michael@0: function tryStmt(body, guarded, unguarded, fin) Pattern({ type: "TryStatement", block: body, guardedHandlers: guarded, handler: unguarded, finalizer: fin }) michael@0: function letStmt(head, body) Pattern({ type: "LetStatement", head: head, body: body }) michael@0: function funExpr(id, args, body, gen) Pattern({ type: "FunctionExpression", michael@0: id: id, michael@0: params: args, michael@0: body: body, michael@0: generator: false }) michael@0: function genFunExpr(id, args, body) Pattern({ type: "FunctionExpression", michael@0: id: id, michael@0: params: args, michael@0: body: body, michael@0: generator: true }) michael@0: function arrowExpr(args, body) Pattern({ type: "ArrowExpression", michael@0: params: args, michael@0: body: body }) michael@0: michael@0: function unExpr(op, arg) Pattern({ type: "UnaryExpression", operator: op, argument: arg }) michael@0: function binExpr(op, left, right) Pattern({ type: "BinaryExpression", operator: op, left: left, right: right }) michael@0: function aExpr(op, left, right) Pattern({ type: "AssignmentExpression", operator: op, left: left, right: right }) michael@0: function updExpr(op, arg, prefix) Pattern({ type: "UpdateExpression", operator: op, argument: arg, prefix: prefix }) michael@0: function logExpr(op, left, right) Pattern({ type: "LogicalExpression", operator: op, left: left, right: right }) michael@0: michael@0: function condExpr(test, cons, alt) Pattern({ type: "ConditionalExpression", test: test, consequent: cons, alternate: alt }) michael@0: function seqExpr(exprs) Pattern({ type: "SequenceExpression", expressions: exprs }) michael@0: function newExpr(callee, args) Pattern({ type: "NewExpression", callee: callee, arguments: args }) michael@0: function callExpr(callee, args) Pattern({ type: "CallExpression", callee: callee, arguments: args }) michael@0: function arrExpr(elts) Pattern({ type: "ArrayExpression", elements: elts }) michael@0: function objExpr(elts) Pattern({ type: "ObjectExpression", properties: elts }) michael@0: function compExpr(body, blocks, filter) Pattern({ type: "ComprehensionExpression", body: body, blocks: blocks, filter: filter }) michael@0: function genExpr(body, blocks, filter) Pattern({ type: "GeneratorExpression", body: body, blocks: blocks, filter: filter }) michael@0: function graphExpr(idx, body) Pattern({ type: "GraphExpression", index: idx, expression: body }) michael@0: function letExpr(head, body) Pattern({ type: "LetExpression", head: head, body: body }) michael@0: function idxExpr(idx) Pattern({ type: "GraphIndexExpression", index: idx }) michael@0: michael@0: function compBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false, of: false }) michael@0: function compEachBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: true, of: false }) michael@0: function compOfBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false, of: true }) michael@0: michael@0: function arrPatt(elts) Pattern({ type: "ArrayPattern", elements: elts }) michael@0: function objPatt(elts) Pattern({ type: "ObjectPattern", properties: elts }) michael@0: michael@0: function localSrc(src) "(function(){ " + src + " })" michael@0: function localPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([patt])))]) michael@0: function blockSrc(src) "(function(){ { " + src + " } })" michael@0: function blockPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([blockStmt([patt])])))]) michael@0: michael@0: function assertBlockStmt(src, patt) { michael@0: blockPatt(patt).assert(Reflect.parse(blockSrc(src))); michael@0: } michael@0: michael@0: function assertBlockExpr(src, patt) { michael@0: assertBlockStmt(src, exprStmt(patt)); michael@0: } michael@0: michael@0: function assertBlockDecl(src, patt, builder) { michael@0: blockPatt(patt).assert(Reflect.parse(blockSrc(src), {builder: builder})); michael@0: } michael@0: michael@0: function assertLocalStmt(src, patt) { michael@0: localPatt(patt).assert(Reflect.parse(localSrc(src))); michael@0: } michael@0: michael@0: function assertLocalExpr(src, patt) { michael@0: assertLocalStmt(src, exprStmt(patt)); michael@0: } michael@0: michael@0: function assertLocalDecl(src, patt) { michael@0: localPatt(patt).assert(Reflect.parse(localSrc(src))); michael@0: } michael@0: michael@0: function assertGlobalStmt(src, patt, builder) { michael@0: program([patt]).assert(Reflect.parse(src, {builder: builder})); michael@0: } michael@0: michael@0: function assertGlobalExpr(src, patt, builder) { michael@0: program([exprStmt(patt)]).assert(Reflect.parse(src, {builder: builder})); michael@0: //assertStmt(src, exprStmt(patt)); michael@0: } michael@0: michael@0: function assertGlobalDecl(src, patt) { michael@0: program([patt]).assert(Reflect.parse(src)); michael@0: } michael@0: michael@0: function assertProg(src, patt) { michael@0: program(patt).assert(Reflect.parse(src)); michael@0: } michael@0: michael@0: function assertStmt(src, patt) { michael@0: assertLocalStmt(src, patt); michael@0: assertGlobalStmt(src, patt); michael@0: assertBlockStmt(src, patt); michael@0: } michael@0: michael@0: function assertExpr(src, patt) { michael@0: assertLocalExpr(src, patt); michael@0: assertGlobalExpr(src, patt); michael@0: assertBlockExpr(src, patt); michael@0: } michael@0: michael@0: function assertDecl(src, patt) { michael@0: assertLocalDecl(src, patt); michael@0: assertGlobalDecl(src, patt); michael@0: assertBlockDecl(src, patt); michael@0: } michael@0: michael@0: function assertError(src, errorType) { michael@0: try { michael@0: Reflect.parse(src); michael@0: } catch (expected if expected instanceof errorType) { michael@0: return; michael@0: } michael@0: throw new Error("expected " + errorType.name + " for " + uneval(src)); michael@0: } michael@0: michael@0: michael@0: // general tests michael@0: michael@0: // NB: These are useful but for now jit-test doesn't do I/O reliably. michael@0: michael@0: //program(_).assert(Reflect.parse(snarf('data/flapjax.txt'))); michael@0: //program(_).assert(Reflect.parse(snarf('data/jquery-1.4.2.txt'))); michael@0: //program(_).assert(Reflect.parse(snarf('data/prototype.js'))); michael@0: //program(_).assert(Reflect.parse(snarf('data/dojo.js.uncompressed.js'))); michael@0: //program(_).assert(Reflect.parse(snarf('data/mootools-1.2.4-core-nc.js'))); michael@0: michael@0: michael@0: // declarations michael@0: michael@0: assertDecl("var x = 1, y = 2, z = 3", michael@0: varDecl([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: lit(2) }, michael@0: { id: ident("z"), init: lit(3) }])); michael@0: assertDecl("var x, y, z", michael@0: varDecl([{ id: ident("x"), init: null }, michael@0: { id: ident("y"), init: null }, michael@0: { id: ident("z"), init: null }])); michael@0: assertDecl("function foo() { }", michael@0: funDecl(ident("foo"), [], blockStmt([]))); michael@0: assertDecl("function foo() { return 42 }", michael@0: funDecl(ident("foo"), [], blockStmt([returnStmt(lit(42))]))); michael@0: michael@0: assertDecl("function foo(...rest) { }", michael@0: funDecl(ident("foo"), [], blockStmt([]), [], ident("rest"))); michael@0: michael@0: assertDecl("function foo(a=4) { }", funDecl(ident("foo"), [ident("a")], blockStmt([]), [lit(4)])); michael@0: assertDecl("function foo(a, b=4) { }", funDecl(ident("foo"), [ident("a"), ident("b")], blockStmt([]), [lit(4)])); michael@0: assertDecl("function foo(a, b=4, ...rest) { }", michael@0: funDecl(ident("foo"), [ident("a"), ident("b")], blockStmt([]), [lit(4)], ident("rest"))); michael@0: assertDecl("function foo(a=(function () {})) { function a() {} }", michael@0: funDecl(ident("foo"), [ident("a")], blockStmt([funDecl(ident("a"), [], blockStmt([]))]), michael@0: [funExpr(ident("a"), [], blockStmt([]))])); michael@0: michael@0: michael@0: // Bug 591437: rebound args have their defs turned into uses michael@0: assertDecl("function f(a) { function a() { } }", michael@0: funDecl(ident("f"), [ident("a")], blockStmt([funDecl(ident("a"), [], blockStmt([]))]))); michael@0: assertDecl("function f(a,b,c) { function b() { } }", michael@0: funDecl(ident("f"), [ident("a"),ident("b"),ident("c")], blockStmt([funDecl(ident("b"), [], blockStmt([]))]))); michael@0: assertDecl("function f(a,[x,y]) { function a() { } }", michael@0: funDecl(ident("f"), michael@0: [ident("a"), arrPatt([ident("x"), ident("y")])], michael@0: blockStmt([funDecl(ident("a"), [], blockStmt([]))]))); michael@0: michael@0: // Bug 632027: array holes should reflect as null michael@0: assertExpr("[,]=[,]", aExpr("=", arrPatt([null]), arrExpr([null]))); michael@0: michael@0: // Bug 591450: this test currently crashes because of a bug in jsparse michael@0: // assertDecl("function f(a,[x,y],b,[w,z],c) { function b() { } }", michael@0: // funDecl(ident("f"), michael@0: // [ident("a"), arrPatt([ident("x"), ident("y")]), ident("b"), arrPatt([ident("w"), ident("z")]), ident("c")], michael@0: // blockStmt([funDecl(ident("b"), [], blockStmt([]))]))); michael@0: michael@0: michael@0: // expressions michael@0: michael@0: assertExpr("true", lit(true)); michael@0: assertExpr("false", lit(false)); michael@0: assertExpr("42", lit(42)); michael@0: assertExpr("(/asdf/)", lit(/asdf/)); michael@0: assertExpr("this", thisExpr); michael@0: assertExpr("foo", ident("foo")); michael@0: assertExpr("foo.bar", dotExpr(ident("foo"), ident("bar"))); michael@0: assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar"))); michael@0: assertExpr("foo['bar']", memExpr(ident("foo"), lit("bar"))); michael@0: assertExpr("foo[42]", memExpr(ident("foo"), lit(42))); michael@0: assertExpr("(function(){})", funExpr(null, [], blockStmt([]))); michael@0: assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([]))); michael@0: assertExpr("(function f(x,y,z) {})", funExpr(ident("f"), [ident("x"),ident("y"),ident("z")], blockStmt([]))); michael@0: assertExpr("a => a", arrowExpr([ident("a")], ident("a"))); michael@0: assertExpr("(a) => a", arrowExpr([ident("a")], ident("a"))); michael@0: assertExpr("a => b => a", arrowExpr([ident("a")], arrowExpr([ident("b")], ident("a")))); michael@0: assertExpr("a => {}", arrowExpr([ident("a")], blockStmt([]))); michael@0: assertExpr("a => ({})", arrowExpr([ident("a")], objExpr([]))); michael@0: assertExpr("(a, b, c) => {}", arrowExpr([ident("a"), ident("b"), ident("c")], blockStmt([]))); michael@0: assertExpr("([a, b]) => {}", arrowExpr([arrPatt([ident("a"), ident("b")])], blockStmt([]))); michael@0: assertExpr("(++x)", updExpr("++", ident("x"), true)); michael@0: assertExpr("(x++)", updExpr("++", ident("x"), false)); michael@0: assertExpr("(+x)", unExpr("+", ident("x"))); michael@0: assertExpr("(-x)", unExpr("-", ident("x"))); michael@0: assertExpr("(!x)", unExpr("!", ident("x"))); michael@0: assertExpr("(~x)", unExpr("~", ident("x"))); michael@0: assertExpr("(delete x)", unExpr("delete", ident("x"))); michael@0: assertExpr("(typeof x)", unExpr("typeof", ident("x"))); michael@0: assertExpr("(void x)", unExpr("void", ident("x"))); michael@0: assertExpr("(x == y)", binExpr("==", ident("x"), ident("y"))); michael@0: assertExpr("(x != y)", binExpr("!=", ident("x"), ident("y"))); michael@0: assertExpr("(x === y)", binExpr("===", ident("x"), ident("y"))); michael@0: assertExpr("(x !== y)", binExpr("!==", ident("x"), ident("y"))); michael@0: assertExpr("(x < y)", binExpr("<", ident("x"), ident("y"))); michael@0: assertExpr("(x <= y)", binExpr("<=", ident("x"), ident("y"))); michael@0: assertExpr("(x > y)", binExpr(">", ident("x"), ident("y"))); michael@0: assertExpr("(x >= y)", binExpr(">=", ident("x"), ident("y"))); michael@0: assertExpr("(x << y)", binExpr("<<", ident("x"), ident("y"))); michael@0: assertExpr("(x >> y)", binExpr(">>", ident("x"), ident("y"))); michael@0: assertExpr("(x >>> y)", binExpr(">>>", ident("x"), ident("y"))); michael@0: assertExpr("(x + y)", binExpr("+", ident("x"), ident("y"))); michael@0: assertExpr("(w + x + y + z)", binExpr("+", binExpr("+", binExpr("+", ident("w"), ident("x")), ident("y")), ident("z"))); michael@0: assertExpr("(x - y)", binExpr("-", ident("x"), ident("y"))); michael@0: assertExpr("(w - x - y - z)", binExpr("-", binExpr("-", binExpr("-", ident("w"), ident("x")), ident("y")), ident("z"))); michael@0: assertExpr("(x * y)", binExpr("*", ident("x"), ident("y"))); michael@0: assertExpr("(x / y)", binExpr("/", ident("x"), ident("y"))); michael@0: assertExpr("(x % y)", binExpr("%", ident("x"), ident("y"))); michael@0: assertExpr("(x | y)", binExpr("|", ident("x"), ident("y"))); michael@0: assertExpr("(x ^ y)", binExpr("^", ident("x"), ident("y"))); michael@0: assertExpr("(x & y)", binExpr("&", ident("x"), ident("y"))); michael@0: assertExpr("(x in y)", binExpr("in", ident("x"), ident("y"))); michael@0: assertExpr("(x instanceof y)", binExpr("instanceof", ident("x"), ident("y"))); michael@0: assertExpr("(x = y)", aExpr("=", ident("x"), ident("y"))); michael@0: assertExpr("(x += y)", aExpr("+=", ident("x"), ident("y"))); michael@0: assertExpr("(x -= y)", aExpr("-=", ident("x"), ident("y"))); michael@0: assertExpr("(x *= y)", aExpr("*=", ident("x"), ident("y"))); michael@0: assertExpr("(x /= y)", aExpr("/=", ident("x"), ident("y"))); michael@0: assertExpr("(x %= y)", aExpr("%=", ident("x"), ident("y"))); michael@0: assertExpr("(x <<= y)", aExpr("<<=", ident("x"), ident("y"))); michael@0: assertExpr("(x >>= y)", aExpr(">>=", ident("x"), ident("y"))); michael@0: assertExpr("(x >>>= y)", aExpr(">>>=", ident("x"), ident("y"))); michael@0: assertExpr("(x |= y)", aExpr("|=", ident("x"), ident("y"))); michael@0: assertExpr("(x ^= y)", aExpr("^=", ident("x"), ident("y"))); michael@0: assertExpr("(x &= y)", aExpr("&=", ident("x"), ident("y"))); michael@0: assertExpr("(x || y)", logExpr("||", ident("x"), ident("y"))); michael@0: assertExpr("(x && y)", logExpr("&&", ident("x"), ident("y"))); michael@0: assertExpr("(w || x || y || z)", logExpr("||", logExpr("||", logExpr("||", ident("w"), ident("x")), ident("y")), ident("z"))) michael@0: assertExpr("(x ? y : z)", condExpr(ident("x"), ident("y"), ident("z"))); michael@0: assertExpr("(x,y)", seqExpr([ident("x"),ident("y")])) michael@0: assertExpr("(x,y,z)", seqExpr([ident("x"),ident("y"),ident("z")])) michael@0: assertExpr("(a,b,c,d,e,f,g)", seqExpr([ident("a"),ident("b"),ident("c"),ident("d"),ident("e"),ident("f"),ident("g")])); michael@0: assertExpr("(new Object)", newExpr(ident("Object"), [])); michael@0: assertExpr("(new Object())", newExpr(ident("Object"), [])); michael@0: assertExpr("(new Object(42))", newExpr(ident("Object"), [lit(42)])); michael@0: assertExpr("(new Object(1,2,3))", newExpr(ident("Object"), [lit(1),lit(2),lit(3)])); michael@0: assertExpr("(String())", callExpr(ident("String"), [])); michael@0: assertExpr("(String(42))", callExpr(ident("String"), [lit(42)])); michael@0: assertExpr("(String(1,2,3))", callExpr(ident("String"), [lit(1),lit(2),lit(3)])); michael@0: assertExpr("[]", arrExpr([])); michael@0: assertExpr("[1]", arrExpr([lit(1)])); michael@0: assertExpr("[1,2]", arrExpr([lit(1),lit(2)])); michael@0: assertExpr("[1,2,3]", arrExpr([lit(1),lit(2),lit(3)])); michael@0: assertExpr("[1,,2,3]", arrExpr([lit(1),null,lit(2),lit(3)])); michael@0: assertExpr("[1,,,2,3]", arrExpr([lit(1),null,null,lit(2),lit(3)])); michael@0: assertExpr("[1,,,2,,3]", arrExpr([lit(1),null,null,lit(2),null,lit(3)])); michael@0: assertExpr("[1,,,2,,,3]", arrExpr([lit(1),null,null,lit(2),null,null,lit(3)])); michael@0: assertExpr("[,1,2,3]", arrExpr([null,lit(1),lit(2),lit(3)])); michael@0: assertExpr("[,,1,2,3]", arrExpr([null,null,lit(1),lit(2),lit(3)])); michael@0: assertExpr("[,,,1,2,3]", arrExpr([null,null,null,lit(1),lit(2),lit(3)])); michael@0: assertExpr("[,,,1,2,3,]", arrExpr([null,null,null,lit(1),lit(2),lit(3)])); michael@0: assertExpr("[,,,1,2,3,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null])); michael@0: assertExpr("[,,,1,2,3,,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null,null])); michael@0: assertExpr("[,,,,,]", arrExpr([null,null,null,null,null])); michael@0: assertExpr("[1, ...a, 2]", arrExpr([lit(1), spread(ident("a")), lit(2)])); michael@0: assertExpr("[,, ...a,, ...b, 42]", arrExpr([null,null, spread(ident("a")),, spread(ident("b")), lit(42)])); michael@0: assertExpr("[1,(2,3)]", arrExpr([lit(1),seqExpr([lit(2),lit(3)])])); michael@0: assertExpr("[,(2,3)]", arrExpr([null,seqExpr([lit(2),lit(3)])])); michael@0: assertExpr("({})", objExpr([])); michael@0: assertExpr("({x:1})", objExpr([{ key: ident("x"), value: lit(1) }])); michael@0: assertExpr("({x:1, y:2})", objExpr([{ key: ident("x"), value: lit(1) }, michael@0: { key: ident("y"), value: lit(2) } ])); michael@0: assertExpr("({x:1, y:2, z:3})", objExpr([{ key: ident("x"), value: lit(1) }, michael@0: { key: ident("y"), value: lit(2) }, michael@0: { key: ident("z"), value: lit(3) } ])); michael@0: assertExpr("({x:1, 'y':2, z:3})", objExpr([{ key: ident("x"), value: lit(1) }, michael@0: { key: lit("y"), value: lit(2) }, michael@0: { key: ident("z"), value: lit(3) } ])); michael@0: assertExpr("({'x':1, 'y':2, z:3})", objExpr([{ key: lit("x"), value: lit(1) }, michael@0: { key: lit("y"), value: lit(2) }, michael@0: { key: ident("z"), value: lit(3) } ])); michael@0: assertExpr("({'x':1, 'y':2, 3:3})", objExpr([{ key: lit("x"), value: lit(1) }, michael@0: { key: lit("y"), value: lit(2) }, michael@0: { key: lit(3), value: lit(3) } ])); michael@0: michael@0: // Bug 571617: eliminate constant-folding michael@0: assertExpr("2 + 3", binExpr("+", lit(2), lit(3))); michael@0: michael@0: // Bug 632026: constant-folding michael@0: assertExpr("typeof(0?0:a)", unExpr("typeof", condExpr(lit(0), lit(0), ident("a")))); michael@0: michael@0: // Bug 632029: constant-folding michael@0: assertExpr("[x for each (x in y) if (false)]", compExpr(ident("x"), [compEachBlock(ident("x"), ident("y"))], lit(false))); michael@0: michael@0: // Bug 632056: constant-folding michael@0: program([exprStmt(ident("f")), michael@0: ifStmt(lit(1), michael@0: funDecl(ident("f"), [], blockStmt([])), michael@0: null)]).assert(Reflect.parse("f; if (1) function f(){}")); michael@0: michael@0: // statements michael@0: michael@0: assertStmt("throw 42", throwStmt(lit(42))); michael@0: assertStmt("for (;;) break", forStmt(null, null, null, breakStmt(null))); michael@0: assertStmt("for (x; y; z) break", forStmt(ident("x"), ident("y"), ident("z"), breakStmt(null))); michael@0: assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z"))); michael@0: assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z"))); michael@0: assertStmt("for (x; ; z) break", forStmt(ident("x"), null, ident("z"), breakStmt(null))); michael@0: assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z"))); michael@0: assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z"))); michael@0: assertStmt("for (x; y; ) break", forStmt(ident("x"), ident("y"), null, breakStmt(null))); michael@0: assertStmt("for (var x; y; ) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), null, breakStmt(null))); michael@0: assertStmt("for (var x = 42; y; ) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), null, breakStmt(null))); michael@0: assertStmt("for (var x in y) break", forInStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), breakStmt(null))); michael@0: assertStmt("for (x in y) break", forInStmt(ident("x"), ident("y"), breakStmt(null))); michael@0: assertStmt("{ }", blockStmt([])); michael@0: assertStmt("{ throw 1; throw 2; throw 3; }", blockStmt([ throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))])); michael@0: assertStmt(";", emptyStmt); michael@0: assertStmt("if (foo) throw 42;", ifStmt(ident("foo"), throwStmt(lit(42)), null)); michael@0: assertStmt("if (foo) throw 42; else true;", ifStmt(ident("foo"), throwStmt(lit(42)), exprStmt(lit(true)))); michael@0: assertStmt("if (foo) { throw 1; throw 2; throw 3; }", michael@0: ifStmt(ident("foo"), michael@0: blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]), michael@0: null)); michael@0: assertStmt("if (foo) { throw 1; throw 2; throw 3; } else true;", michael@0: ifStmt(ident("foo"), michael@0: blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]), michael@0: exprStmt(lit(true)))); michael@0: assertStmt("foo: for(;;) break foo;", labStmt(ident("foo"), forStmt(null, null, null, breakStmt(ident("foo"))))); michael@0: assertStmt("foo: for(;;) continue foo;", labStmt(ident("foo"), forStmt(null, null, null, continueStmt(ident("foo"))))); michael@0: assertStmt("with (obj) { }", withStmt(ident("obj"), blockStmt([]))); michael@0: assertStmt("with (obj) { obj; }", withStmt(ident("obj"), blockStmt([exprStmt(ident("obj"))]))); michael@0: assertStmt("while (foo) { }", whileStmt(ident("foo"), blockStmt([]))); michael@0: assertStmt("while (foo) { foo; }", whileStmt(ident("foo"), blockStmt([exprStmt(ident("foo"))]))); michael@0: assertStmt("do { } while (foo);", doStmt(blockStmt([]), ident("foo"))); michael@0: assertStmt("do { foo; } while (foo)", doStmt(blockStmt([exprStmt(ident("foo"))]), ident("foo"))); michael@0: assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; }", michael@0: switchStmt(ident("foo"), michael@0: [ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]), michael@0: caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]), michael@0: defaultClause([ exprStmt(lit(3)) ]) ])); michael@0: assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; case 42: 42; }", michael@0: switchStmt(ident("foo"), michael@0: [ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]), michael@0: caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]), michael@0: defaultClause([ exprStmt(lit(3)) ]), michael@0: caseClause(lit(42), [ exprStmt(lit(42)) ]) ])); michael@0: assertStmt("try { } catch (e) { }", michael@0: tryStmt(blockStmt([]), michael@0: [], michael@0: catchClause(ident("e"), null, blockStmt([])), michael@0: null)); michael@0: assertStmt("try { } catch (e) { } finally { }", michael@0: tryStmt(blockStmt([]), michael@0: [], michael@0: catchClause(ident("e"), null, blockStmt([])), michael@0: blockStmt([]))); michael@0: assertStmt("try { } finally { }", michael@0: tryStmt(blockStmt([]), michael@0: [], michael@0: null, michael@0: blockStmt([]))); michael@0: assertStmt("try { } catch (e if foo) { } catch (e if bar) { } finally { }", michael@0: tryStmt(blockStmt([]), michael@0: [ catchClause(ident("e"), ident("foo"), blockStmt([])), michael@0: catchClause(ident("e"), ident("bar"), blockStmt([])) ], michael@0: null, michael@0: blockStmt([]))); michael@0: assertStmt("try { } catch (e if foo) { } catch (e if bar) { } catch (e) { } finally { }", michael@0: tryStmt(blockStmt([]), michael@0: [ catchClause(ident("e"), ident("foo"), blockStmt([])), michael@0: catchClause(ident("e"), ident("bar"), blockStmt([])) ], michael@0: catchClause(ident("e"), null, blockStmt([])), michael@0: blockStmt([]))); michael@0: michael@0: // Bug 632028: yield outside of a function should throw michael@0: (function() { michael@0: var threw = false; michael@0: try { michael@0: Reflect.parse("yield 0"); michael@0: } catch (expected) { michael@0: threw = true; michael@0: } michael@0: assertEq(threw, true); michael@0: })(); michael@0: michael@0: // redeclarations (TOK_NAME nodes with lexdef) michael@0: michael@0: assertStmt("function f() { function g() { } function g() { } }", michael@0: funDecl(ident("f"), [], blockStmt([emptyStmt, michael@0: funDecl(ident("g"), [], blockStmt([]))]))); michael@0: michael@0: // Fails due to parser quirks (bug 638577) michael@0: //assertStmt("function f() { function g() { } function g() { return 42 } }", michael@0: // funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])), michael@0: // funDecl(ident("g"), [], blockStmt([returnStmt(lit(42))]))]))); michael@0: michael@0: assertStmt("function f() { var x = 42; var x = 43; }", michael@0: funDecl(ident("f"), [], blockStmt([varDecl([{ id: ident("x"), init: lit(42) }]), michael@0: varDecl([{ id: ident("x"), init: lit(43) }])]))); michael@0: michael@0: michael@0: assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]), michael@0: init: ident("foo") }])); michael@0: michael@0: // Bug 632030: redeclarations between var and funargs, var and function michael@0: assertStmt("function g(x) { var x }", michael@0: funDecl(ident("g"), [ident("x")], blockStmt([varDecl[{ id: ident("x"), init: null }]]))); michael@0: assertProg("f.p = 1; var f; f.p; function f(){}", michael@0: [exprStmt(aExpr("=", dotExpr(ident("f"), ident("p")), lit(1))), michael@0: varDecl([{ id: ident("f"), init: null }]), michael@0: exprStmt(dotExpr(ident("f"), ident("p"))), michael@0: funDecl(ident("f"), [], blockStmt([]))]); michael@0: michael@0: // global let is var michael@0: assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]), michael@0: init: ident("foo") }])); michael@0: // function-global let is var michael@0: assertLocalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]), michael@0: init: ident("foo") }])); michael@0: // block-local let is let michael@0: assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]), michael@0: init: ident("foo") }])); michael@0: michael@0: assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]), michael@0: init: ident("foo") }])); michael@0: michael@0: michael@0: // various combinations of identifiers and destructuring patterns: michael@0: function makePatternCombinations(id, destr) michael@0: [ michael@0: [ id(1) ], michael@0: [ id(1), id(2) ], michael@0: [ id(1), id(2), id(3) ], michael@0: [ id(1), id(2), id(3), id(4) ], michael@0: [ id(1), id(2), id(3), id(4), id(5) ], michael@0: michael@0: [ destr(1) ], michael@0: [ destr(1), destr(2) ], michael@0: [ destr(1), destr(2), destr(3) ], michael@0: [ destr(1), destr(2), destr(3), destr(4) ], michael@0: [ destr(1), destr(2), destr(3), destr(4), destr(5) ], michael@0: michael@0: [ destr(1), id(2) ], michael@0: michael@0: [ destr(1), id(2), id(3) ], michael@0: [ destr(1), id(2), id(3), id(4) ], michael@0: [ destr(1), id(2), id(3), id(4), id(5) ], michael@0: [ destr(1), id(2), id(3), id(4), destr(5) ], michael@0: [ destr(1), id(2), id(3), destr(4) ], michael@0: [ destr(1), id(2), id(3), destr(4), id(5) ], michael@0: [ destr(1), id(2), id(3), destr(4), destr(5) ], michael@0: michael@0: [ destr(1), id(2), destr(3) ], michael@0: [ destr(1), id(2), destr(3), id(4) ], michael@0: [ destr(1), id(2), destr(3), id(4), id(5) ], michael@0: [ destr(1), id(2), destr(3), id(4), destr(5) ], michael@0: [ destr(1), id(2), destr(3), destr(4) ], michael@0: [ destr(1), id(2), destr(3), destr(4), id(5) ], michael@0: [ destr(1), id(2), destr(3), destr(4), destr(5) ], michael@0: michael@0: [ id(1), destr(2) ], michael@0: michael@0: [ id(1), destr(2), id(3) ], michael@0: [ id(1), destr(2), id(3), id(4) ], michael@0: [ id(1), destr(2), id(3), id(4), id(5) ], michael@0: [ id(1), destr(2), id(3), id(4), destr(5) ], michael@0: [ id(1), destr(2), id(3), destr(4) ], michael@0: [ id(1), destr(2), id(3), destr(4), id(5) ], michael@0: [ id(1), destr(2), id(3), destr(4), destr(5) ], michael@0: michael@0: [ id(1), destr(2), destr(3) ], michael@0: [ id(1), destr(2), destr(3), id(4) ], michael@0: [ id(1), destr(2), destr(3), id(4), id(5) ], michael@0: [ id(1), destr(2), destr(3), id(4), destr(5) ], michael@0: [ id(1), destr(2), destr(3), destr(4) ], michael@0: [ id(1), destr(2), destr(3), destr(4), id(5) ], michael@0: [ id(1), destr(2), destr(3), destr(4), destr(5) ] michael@0: ] michael@0: michael@0: // destructuring function parameters michael@0: michael@0: function testParamPatternCombinations(makePattSrc, makePattPatt) { michael@0: var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc); michael@0: var pattPatts = makePatternCombinations(function(n) (ident("x" + n)), makePattPatt); michael@0: michael@0: for (var i = 0; i < pattSrcs.length; i++) { michael@0: function makeSrc(body) ("(function(" + pattSrcs[i].join(",") + ") " + body + ")") michael@0: function makePatt(body) (funExpr(null, pattPatts[i], body)) michael@0: michael@0: // no upvars, block body michael@0: assertExpr(makeSrc("{ }", makePatt(blockStmt([])))); michael@0: // upvars, block body michael@0: assertExpr(makeSrc("{ return [x1,x2,x3,x4,x5]; }"), michael@0: makePatt(blockStmt([returnStmt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))]))); michael@0: // no upvars, expression body michael@0: assertExpr(makeSrc("(0)"), makePatt(lit(0))); michael@0: // upvars, expression body michael@0: assertExpr(makeSrc("[x1,x2,x3,x4,x5]"), michael@0: makePatt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))); michael@0: } michael@0: } michael@0: michael@0: testParamPatternCombinations(function(n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "}"), michael@0: function(n) (objPatt([{ key: ident("a" + n), value: ident("x" + n) }, michael@0: { key: ident("b" + n), value: ident("y" + n) }, michael@0: { key: ident("c" + n), value: ident("z" + n) }]))); michael@0: michael@0: testParamPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "]"), michael@0: function(n) (arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)]))); michael@0: michael@0: michael@0: // destructuring variable declarations michael@0: michael@0: function testVarPatternCombinations(makePattSrc, makePattPatt) { michael@0: var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc); michael@0: var pattPatts = makePatternCombinations(function(n) ({ id: ident("x" + n), init: null }), makePattPatt); michael@0: michael@0: for (var i = 0; i < pattSrcs.length; i++) { michael@0: // variable declarations in blocks michael@0: assertDecl("var " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i])); michael@0: michael@0: assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i])); michael@0: assertLocalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i])); michael@0: assertBlockDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); michael@0: michael@0: assertDecl("const " + pattSrcs[i].join(",") + ";", constDecl(pattPatts[i])); michael@0: michael@0: // variable declarations in for-loop heads michael@0: assertStmt("for (var " + pattSrcs[i].join(",") + "; foo; bar);", michael@0: forStmt(varDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt)); michael@0: assertStmt("for (let " + pattSrcs[i].join(",") + "; foo; bar);", michael@0: letStmt(pattPatts[i], forStmt(null, ident("foo"), ident("bar"), emptyStmt))); michael@0: assertStmt("for (const " + pattSrcs[i].join(",") + "; foo; bar);", michael@0: forStmt(constDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt)); michael@0: } michael@0: } michael@0: michael@0: testVarPatternCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"), michael@0: function (n) ({ id: objPatt([{ key: ident("a" + n), value: ident("x" + n) }, michael@0: { key: ident("b" + n), value: ident("y" + n) }, michael@0: { key: ident("c" + n), value: ident("z" + n) }]), michael@0: init: lit(0) })); michael@0: michael@0: testVarPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "] = 0"), michael@0: function(n) ({ id: arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)]), michael@0: init: lit(0) })); michael@0: michael@0: // destructuring assignment michael@0: michael@0: function testAssignmentCombinations(makePattSrc, makePattPatt) { michael@0: var pattSrcs = makePatternCombinations(function(n) ("x" + n + " = 0"), makePattSrc); michael@0: var pattPatts = makePatternCombinations(function(n) (aExpr("=", ident("x" + n), lit(0))), makePattPatt); michael@0: michael@0: for (var i = 0; i < pattSrcs.length; i++) { michael@0: var src = pattSrcs[i].join(","); michael@0: var patt = pattPatts[i].length === 1 ? pattPatts[i][0] : seqExpr(pattPatts[i]); michael@0: michael@0: // assignment expression statement michael@0: assertExpr("(" + src + ")", patt); michael@0: michael@0: // for-loop head assignment michael@0: assertStmt("for (" + src + "; foo; bar);", michael@0: forStmt(patt, ident("foo"), ident("bar"), emptyStmt)); michael@0: } michael@0: } michael@0: michael@0: testAssignmentCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"), michael@0: function (n) (aExpr("=", michael@0: objPatt([{ key: ident("a" + n), value: ident("x" + n) }, michael@0: { key: ident("b" + n), value: ident("y" + n) }, michael@0: { key: ident("c" + n), value: ident("z" + n) }]), michael@0: lit(0)))); michael@0: michael@0: michael@0: // destructuring in for-in and for-each-in loop heads michael@0: michael@0: var axbycz = objPatt([{ key: ident("a"), value: ident("x") }, michael@0: { key: ident("b"), value: ident("y") }, michael@0: { key: ident("c"), value: ident("z") }]); michael@0: var xyz = arrPatt([ident("x"), ident("y"), ident("z")]); michael@0: michael@0: assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt)); michael@0: assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt)); michael@0: assertStmt("for (var {a:x,b:y,c:z} of foo);", forOfStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for (let {a:x,b:y,c:z} of foo);", forOfStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for ({a:x,b:y,c:z} of foo);", forOfStmt(axbycz, ident("foo"), emptyStmt)); michael@0: assertStmt("for (var [x,y,z] of foo);", forOfStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for (let [x,y,z] of foo);", forOfStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for ([x,y,z] of foo);", forOfStmt(xyz, ident("foo"), emptyStmt)); michael@0: assertStmt("for each (var {a:x,b:y,c:z} in foo);", forEachInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for each (let {a:x,b:y,c:z} in foo);", forEachInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for each ({a:x,b:y,c:z} in foo);", forEachInStmt(axbycz, ident("foo"), emptyStmt)); michael@0: assertStmt("for each (var [x,y,z] in foo);", forEachInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for each (let [x,y,z] in foo);", forEachInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for each ([x,y,z] in foo);", forEachInStmt(xyz, ident("foo"), emptyStmt)); michael@0: assertError("for (const x in foo);", SyntaxError); michael@0: assertError("for (const {a:x,b:y,c:z} in foo);", SyntaxError); michael@0: assertError("for (const [x,y,z] in foo);", SyntaxError); michael@0: assertError("for (const x of foo);", SyntaxError); michael@0: assertError("for (const {a:x,b:y,c:z} of foo);", SyntaxError); michael@0: assertError("for (const [x,y,z] of foo);", SyntaxError); michael@0: assertError("for each (const x in foo);", SyntaxError); michael@0: assertError("for each (const {a:x,b:y,c:z} in foo);", SyntaxError); michael@0: assertError("for each (const [x,y,z] in foo);", SyntaxError); michael@0: michael@0: // destructuring in for-in and for-each-in loop heads with initializers michael@0: michael@0: assertStmt("for (var {a:x,b:y,c:z} = 22 in foo);", forInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for (var [x,y,z] = 22 in foo);", forInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for each (var {a:x,b:y,c:z} = 22 in foo);", forEachInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt)); michael@0: assertStmt("for each (var [x,y,z] = 22 in foo);", forEachInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt)); michael@0: assertError("for (x = 22 in foo);", SyntaxError); michael@0: assertError("for ({a:x,b:y,c:z} = 22 in foo);", SyntaxError); michael@0: assertError("for ([x,y,z] = 22 in foo);", SyntaxError); michael@0: assertError("for (const x = 22 in foo);", SyntaxError); michael@0: assertError("for (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError); michael@0: assertError("for (const [x,y,z] = 22 in foo);", SyntaxError); michael@0: assertError("for each (const x = 22 in foo);", SyntaxError); michael@0: assertError("for each (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError); michael@0: assertError("for each (const [x,y,z] = 22 in foo);", SyntaxError); michael@0: michael@0: // expression closures michael@0: michael@0: assertDecl("function inc(x) (x + 1)", funDecl(ident("inc"), [ident("x")], binExpr("+", ident("x"), lit(1)))); michael@0: assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+"), ident("x"), lit(1))); michael@0: michael@0: // generators michael@0: michael@0: assertDecl("function gen(x) { yield }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))]))); michael@0: assertExpr("(function(x) { yield })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))]))); michael@0: assertDecl("function gen(x) { yield 42 }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))]))); michael@0: assertExpr("(function(x) { yield 42 })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))]))); michael@0: michael@0: // getters and setters michael@0: michael@0: assertExpr("({ get x() { return 42 } })", michael@0: objExpr([ { key: ident("x"), michael@0: value: funExpr(null, [], blockStmt([returnStmt(lit(42))])), michael@0: kind: "get" } ])); michael@0: assertExpr("({ set x(v) { return 42 } })", michael@0: objExpr([ { key: ident("x"), michael@0: value: funExpr(null, [ident("v")], blockStmt([returnStmt(lit(42))])), michael@0: kind: "set" } ])); michael@0: michael@0: // comprehensions michael@0: michael@0: assertExpr("[ x for (x in foo)]", michael@0: compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null)); michael@0: assertExpr("[ [x,y] for (x in foo) for (y in bar)]", michael@0: compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null)); michael@0: assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz)]", michael@0: compExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))], michael@0: null)); michael@0: michael@0: assertExpr("[ x for (x in foo) if (p)]", michael@0: compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p"))); michael@0: assertExpr("[ [x,y] for (x in foo) for (y in bar) if (p)]", michael@0: compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p"))); michael@0: assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) ]", michael@0: compExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))], michael@0: ident("p"))); michael@0: michael@0: assertExpr("[ x for each (x in foo)]", michael@0: compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null)); michael@0: assertExpr("[ [x,y] for each (x in foo) for each (y in bar)]", michael@0: compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null)); michael@0: assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz)]", michael@0: compExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))], michael@0: null)); michael@0: michael@0: assertExpr("[ x for each (x in foo) if (p)]", michael@0: compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p"))); michael@0: assertExpr("[ [x,y] for each (x in foo) for each (y in bar) if (p)]", michael@0: compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p"))); michael@0: assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) ]", michael@0: compExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))], michael@0: ident("p"))); michael@0: michael@0: assertExpr("[ x for (x of foo)]", michael@0: compExpr(ident("x"), [compOfBlock(ident("x"), ident("foo"))], null)); michael@0: assertExpr("[ [x,y] for (x of foo) for (y of bar)]", michael@0: compExpr(arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], null)); michael@0: assertExpr("[ [x,y,z] for (x of foo) for (y of bar) for (z of baz)]", michael@0: compExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))], michael@0: null)); michael@0: michael@0: assertExpr("[ x for (x of foo) if (p)]", michael@0: compExpr(ident("x"), [compOfBlock(ident("x"), ident("foo"))], ident("p"))); michael@0: assertExpr("[ [x,y] for (x of foo) for (y of bar) if (p)]", michael@0: compExpr(arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], ident("p"))); michael@0: assertExpr("[ [x,y,z] for (x of foo) for (y of bar) for (z of baz) if (p) ]", michael@0: compExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))], michael@0: ident("p"))); michael@0: michael@0: // generator expressions michael@0: michael@0: assertExpr("( x for (x in foo))", michael@0: genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null)); michael@0: assertExpr("( [x,y] for (x in foo) for (y in bar))", michael@0: genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null)); michael@0: assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz))", michael@0: genExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))], michael@0: null)); michael@0: michael@0: assertExpr("( x for (x in foo) if (p))", michael@0: genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p"))); michael@0: assertExpr("( [x,y] for (x in foo) for (y in bar) if (p))", michael@0: genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p"))); michael@0: assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) )", michael@0: genExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))], michael@0: ident("p"))); michael@0: michael@0: assertExpr("( x for each (x in foo))", michael@0: genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null)); michael@0: assertExpr("( [x,y] for each (x in foo) for each (y in bar))", michael@0: genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null)); michael@0: assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz))", michael@0: genExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))], michael@0: null)); michael@0: michael@0: assertExpr("( x for each (x in foo) if (p))", michael@0: genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p"))); michael@0: assertExpr("( [x,y] for each (x in foo) for each (y in bar) if (p))", michael@0: genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p"))); michael@0: assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) )", michael@0: genExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))], michael@0: ident("p"))); michael@0: michael@0: assertExpr("( x for (x of foo))", michael@0: genExpr(ident("x"), [compOfBlock(ident("x"), ident("foo"))], null)); michael@0: assertExpr("( [x,y] for (x of foo) for (y of bar))", michael@0: genExpr(arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], null)); michael@0: assertExpr("( [x,y,z] for (x of foo) for (y of bar) for (z of baz))", michael@0: genExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))], michael@0: null)); michael@0: michael@0: assertExpr("( x for (x of foo) if (p))", michael@0: genExpr(ident("x"), [compOfBlock(ident("x"), ident("foo"))], ident("p"))); michael@0: assertExpr("( [x,y] for (x of foo) for (y of bar) if (p))", michael@0: genExpr(arrExpr([ident("x"), ident("y")]), [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar"))], ident("p"))); michael@0: assertExpr("( [x,y,z] for (x of foo) for (y of bar) for (z of baz) if (p) )", michael@0: genExpr(arrExpr([ident("x"), ident("y"), ident("z")]), michael@0: [compOfBlock(ident("x"), ident("foo")), compOfBlock(ident("y"), ident("bar")), compOfBlock(ident("z"), ident("baz"))], michael@0: ident("p"))); michael@0: michael@0: // NOTE: it would be good to test generator expressions both with and without upvars, just like functions above. michael@0: michael@0: michael@0: // let expressions michael@0: michael@0: assertExpr("(let (x=1) x)", letExpr([{ id: ident("x"), init: lit(1) }], ident("x"))); michael@0: assertExpr("(let (x=1,y=2) y)", letExpr([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: lit(2) }], michael@0: ident("y"))); michael@0: assertExpr("(let (x=1,y=2,z=3) z)", letExpr([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: lit(2) }, michael@0: { id: ident("z"), init: lit(3) }], michael@0: ident("z"))); michael@0: assertExpr("(let (x) x)", letExpr([{ id: ident("x"), init: null }], ident("x"))); michael@0: assertExpr("(let (x,y) y)", letExpr([{ id: ident("x"), init: null }, michael@0: { id: ident("y"), init: null }], michael@0: ident("y"))); michael@0: assertExpr("(let (x,y,z) z)", letExpr([{ id: ident("x"), init: null }, michael@0: { id: ident("y"), init: null }, michael@0: { id: ident("z"), init: null }], michael@0: ident("z"))); michael@0: assertExpr("(let (x = 1, y = x) y)", letExpr([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: ident("x") }], michael@0: ident("y"))); michael@0: assertError("(let (x = 1, x = 2) x)", TypeError); michael@0: michael@0: // let statements michael@0: michael@0: assertStmt("let (x=1) { }", letStmt([{ id: ident("x"), init: lit(1) }], blockStmt([]))); michael@0: assertStmt("let (x=1,y=2) { }", letStmt([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: lit(2) }], michael@0: blockStmt([]))); michael@0: assertStmt("let (x=1,y=2,z=3) { }", letStmt([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: lit(2) }, michael@0: { id: ident("z"), init: lit(3) }], michael@0: blockStmt([]))); michael@0: assertStmt("let (x) { }", letStmt([{ id: ident("x"), init: null }], blockStmt([]))); michael@0: assertStmt("let (x,y) { }", letStmt([{ id: ident("x"), init: null }, michael@0: { id: ident("y"), init: null }], michael@0: blockStmt([]))); michael@0: assertStmt("let (x,y,z) { }", letStmt([{ id: ident("x"), init: null }, michael@0: { id: ident("y"), init: null }, michael@0: { id: ident("z"), init: null }], michael@0: blockStmt([]))); michael@0: assertStmt("let (x = 1, y = x) { }", letStmt([{ id: ident("x"), init: lit(1) }, michael@0: { id: ident("y"), init: ident("x") }], michael@0: blockStmt([]))); michael@0: assertError("let (x = 1, x = 2) { }", TypeError); michael@0: michael@0: michael@0: // Bug 632024: no crashing on stack overflow michael@0: try { michael@0: Reflect.parse(Array(3000).join("x + y - ") + "z") michael@0: } catch (e) { } michael@0: michael@0: michael@0: // Source location information michael@0: michael@0: michael@0: var withoutFileOrLine = Reflect.parse("42"); michael@0: var withFile = Reflect.parse("42", {source:"foo.js"}); michael@0: var withFileAndLine = Reflect.parse("42", {source:"foo.js", line:111}); michael@0: michael@0: Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withoutFileOrLine.loc); michael@0: Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withFile.loc); michael@0: Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 111, column: 2 } }).match(withFileAndLine.loc); michael@0: michael@0: var withoutFileOrLine2 = Reflect.parse("foo +\nbar"); michael@0: var withFile2 = Reflect.parse("foo +\nbar", {source:"foo.js"}); michael@0: var withFileAndLine2 = Reflect.parse("foo +\nbar", {source:"foo.js", line:111}); michael@0: michael@0: Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withoutFileOrLine2.loc); michael@0: Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withFile2.loc); michael@0: Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 112, column: 3 } }).match(withFileAndLine2.loc); michael@0: michael@0: var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", {source:"quad.js"}); michael@0: var fourAC = nested.body[0].expression.left.right.arguments[0].right; michael@0: michael@0: Pattern({ source: "quad.js", start: { line: 1, column: 20 }, end: { line: 1, column: 29 } }).match(fourAC.loc); michael@0: michael@0: michael@0: // No source location michael@0: michael@0: assertEq(Reflect.parse("42", {loc:false}).loc, null); michael@0: program([exprStmt(lit(42))]).assert(Reflect.parse("42", {loc:false})); michael@0: michael@0: michael@0: // Builder tests michael@0: michael@0: Pattern("program").match(Reflect.parse("42", {builder:{program:function()"program"}})); michael@0: michael@0: assertGlobalStmt("throw 42", 1, { throwStatement: function() 1 }); michael@0: assertGlobalStmt("for (;;);", 2, { forStatement: function() 2 }); michael@0: assertGlobalStmt("for (x in y);", 3, { forInStatement: function() 3 }); michael@0: assertGlobalStmt("{ }", 4, { blockStatement: function() 4 }); michael@0: assertGlobalStmt("foo: { }", 5, { labeledStatement: function() 5 }); michael@0: assertGlobalStmt("with (o) { }", 6, { withStatement: function() 6 }); michael@0: assertGlobalStmt("while (x) { }", 7, { whileStatement: function() 7 }); michael@0: assertGlobalStmt("do { } while(false);", 8, { doWhileStatement: function() 8 }); michael@0: assertGlobalStmt("switch (x) { }", 9, { switchStatement: function() 9 }); michael@0: assertGlobalStmt("try { } catch(e) { }", 10, { tryStatement: function() 10 }); michael@0: assertGlobalStmt(";", 11, { emptyStatement: function() 11 }); michael@0: assertGlobalStmt("debugger;", 12, { debuggerStatement: function() 12 }); michael@0: assertGlobalStmt("42;", 13, { expressionStatement: function() 13 }); michael@0: assertGlobalStmt("for (;;) break", forStmt(null, null, null, 14), { breakStatement: function() 14 }); michael@0: assertGlobalStmt("for (;;) continue", forStmt(null, null, null, 15), { continueStatement: function() 15 }); michael@0: michael@0: assertBlockDecl("var x", "var", { variableDeclaration: function(kind) kind }); michael@0: assertBlockDecl("let x", "let", { variableDeclaration: function(kind) kind }); michael@0: assertBlockDecl("const x", "const", { variableDeclaration: function(kind) kind }); michael@0: assertBlockDecl("function f() { }", "function", { functionDeclaration: function() "function" }); michael@0: michael@0: assertGlobalExpr("(x,y,z)", 1, { sequenceExpression: function() 1 }); michael@0: assertGlobalExpr("(x ? y : z)", 2, { conditionalExpression: function() 2 }); michael@0: assertGlobalExpr("x + y", 3, { binaryExpression: function() 3 }); michael@0: assertGlobalExpr("delete x", 4, { unaryExpression: function() 4 }); michael@0: assertGlobalExpr("x = y", 5, { assignmentExpression: function() 5 }); michael@0: assertGlobalExpr("x || y", 6, { logicalExpression: function() 6 }); michael@0: assertGlobalExpr("x++", 7, { updateExpression: function() 7 }); michael@0: assertGlobalExpr("new x", 8, { newExpression: function() 8 }); michael@0: assertGlobalExpr("x()", 9, { callExpression: function() 9 }); michael@0: assertGlobalExpr("x.y", 10, { memberExpression: function() 10 }); michael@0: assertGlobalExpr("(function() { })", 11, { functionExpression: function() 11 }); michael@0: assertGlobalExpr("[1,2,3]", 12, { arrayExpression: function() 12 }); michael@0: assertGlobalExpr("({ x: y })", 13, { objectExpression: function() 13 }); michael@0: assertGlobalExpr("this", 14, { thisExpression: function() 14 }); michael@0: assertGlobalExpr("[x for (x in y)]", 17, { comprehensionExpression: function() 17 }); michael@0: assertGlobalExpr("(x for (x in y))", 18, { generatorExpression: function() 18 }); michael@0: assertGlobalExpr("(function() { yield 42 })", genFunExpr(null, [], blockStmt([exprStmt(19)])), { yieldExpression: function() 19 }); michael@0: assertGlobalExpr("(let (x) x)", 20, { letExpression: function() 20 }); michael@0: michael@0: assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: function() 1 }); michael@0: assertGlobalStmt("try { } catch (e) { }", 2, { tryStatement: (function(b, g, u, f) u), catchClause: function() 2 }); michael@0: assertGlobalStmt("try { } catch (e if e instanceof A) { } catch (e if e instanceof B) { }", [2, 2], { tryStatement: (function(b, g, u, f) g), catchClause: function() 2 }); michael@0: assertGlobalStmt("try { } catch (e) { }", tryStmt(blockStmt([]), [], 2, null), { catchClause: function() 2 }); michael@0: assertGlobalStmt("try { } catch (e if e instanceof A) { } catch (e if e instanceof B) { }", michael@0: tryStmt(blockStmt([]), [2, 2], null, null), michael@0: { catchClause: function() 2 }); michael@0: assertGlobalExpr("[x for (y in z) for (x in y)]", compExpr(ident("x"), [3, 3], null), { comprehensionBlock: function() 3 }); michael@0: michael@0: assertGlobalExpr("({ x: y } = z)", aExpr("=", 1, ident("z")), { objectPattern: function() 1 }); michael@0: assertGlobalExpr("({ x: y } = z)", aExpr("=", objPatt([2]), ident("z")), { propertyPattern: function() 2 }); michael@0: assertGlobalExpr("[ x ] = y", aExpr("=", 3, ident("y")), { arrayPattern: function() 3 }); michael@0: michael@0: // Ensure that exceptions thrown by builder methods propagate. michael@0: var thrown = false; michael@0: try { michael@0: Reflect.parse("42", { builder: { program: function() { throw "expected" } } }); michael@0: } catch (e if e === "expected") { michael@0: thrown = true; michael@0: } michael@0: if (!thrown) michael@0: throw new Error("builder exception not propagated"); michael@0: michael@0: // Missing property RHS's in an object literal should throw. michael@0: try { michael@0: Reflect.parse("({foo})"); michael@0: throw new Error("object literal missing property RHS didn't throw"); michael@0: } catch (e if e instanceof SyntaxError) { } michael@0: michael@0: michael@0: // A simple proof-of-concept that the builder API can be used to generate other michael@0: // formats, such as JsonMLAst: michael@0: // michael@0: // http://code.google.com/p/es-lab/wiki/JsonMLASTFormat michael@0: // michael@0: // It's incomplete (e.g., it doesn't convert source-location information and michael@0: // doesn't use all the direct-eval rules), but I think it proves the point. michael@0: michael@0: var JsonMLAst = (function() { michael@0: function reject() { michael@0: throw new SyntaxError("node type not supported"); michael@0: } michael@0: michael@0: function isDirectEval(expr) { michael@0: // an approximation to the actual rules. you get the idea michael@0: return (expr[0] === "IdExpr" && expr[1].name === "eval"); michael@0: } michael@0: michael@0: function functionNode(type) { michael@0: return function(id, args, body, isGenerator, isExpression) { michael@0: if (isExpression) michael@0: body = ["ReturnStmt", {}, body]; michael@0: michael@0: if (!id) michael@0: id = ["Empty"]; michael@0: michael@0: // Patch up the argument node types: s/IdExpr/IdPatt/g michael@0: for (var i = 0; i < args.length; i++) { michael@0: args[i][0] = "IdPatt"; michael@0: } michael@0: michael@0: args.unshift("ParamDecl", {}); michael@0: michael@0: return [type, {}, id, args, body]; michael@0: } michael@0: } michael@0: michael@0: return { michael@0: program: function(stmts) { michael@0: stmts.unshift("Program", {}); michael@0: return stmts; michael@0: }, michael@0: identifier: function(name) { michael@0: return ["IdExpr", { name: name }]; michael@0: }, michael@0: literal: function(val) { michael@0: return ["LiteralExpr", { value: val }]; michael@0: }, michael@0: expressionStatement: function(expr) expr, michael@0: conditionalExpression: function(test, cons, alt) { michael@0: return ["ConditionalExpr", {}, test, cons, alt]; michael@0: }, michael@0: unaryExpression: function(op, expr) { michael@0: return ["UnaryExpr", {op: op}, expr]; michael@0: }, michael@0: binaryExpression: function(op, left, right) { michael@0: return ["BinaryExpr", {op: op}, left, right]; michael@0: }, michael@0: property: function(kind, key, val) { michael@0: return [kind === "init" michael@0: ? "DataProp" michael@0: : kind === "get" michael@0: ? "GetterProp" michael@0: : "SetterProp", michael@0: {name: key[1].name}, val]; michael@0: }, michael@0: functionDeclaration: functionNode("FunctionDecl"), michael@0: variableDeclaration: function(kind, elts) { michael@0: if (kind === "let" || kind === "const") michael@0: throw new SyntaxError("let and const not supported"); michael@0: elts.unshift("VarDecl", {}); michael@0: return elts; michael@0: }, michael@0: variableDeclarator: function(id, init) { michael@0: id[0] = "IdPatt"; michael@0: if (!init) michael@0: return id; michael@0: return ["InitPatt", {}, id, init]; michael@0: }, michael@0: sequenceExpression: function(exprs) { michael@0: var length = exprs.length; michael@0: var result = ["BinaryExpr", {op:","}, exprs[exprs.length - 2], exprs[exprs.length - 1]]; michael@0: for (var i = exprs.length - 3; i >= 0; i--) { michael@0: result = ["BinaryExpr", {op:","}, exprs[i], result]; michael@0: } michael@0: return result; michael@0: }, michael@0: assignmentExpression: function(op, lhs, expr) { michael@0: return ["AssignExpr", {op: op}, lhs, expr]; michael@0: }, michael@0: logicalExpression: function(op, left, right) { michael@0: return [op === "&&" ? "LogicalAndExpr" : "LogicalOrExpr", {}, left, right]; michael@0: }, michael@0: updateExpression: function(expr, op, isPrefix) { michael@0: return ["CountExpr", {isPrefix:isPrefix, op:op}, expr]; michael@0: }, michael@0: newExpression: function(callee, args) { michael@0: args.unshift("NewExpr", {}, callee); michael@0: return args; michael@0: }, michael@0: callExpression: function(callee, args) { michael@0: args.unshift(isDirectEval(callee) ? "EvalExpr" : "CallExpr", {}, callee); michael@0: return args; michael@0: }, michael@0: memberExpression: function(isComputed, expr, member) { michael@0: return ["MemberExpr", {}, expr, isComputed ? member : ["LiteralExpr", {type: "string", value: member[1].name}]]; michael@0: }, michael@0: functionExpression: functionNode("FunctionExpr"), michael@0: arrayExpression: function(elts) { michael@0: for (var i = 0; i < elts.length; i++) { michael@0: if (!elts[i]) michael@0: elts[i] = ["Empty"]; michael@0: } michael@0: elts.unshift("ArrayExpr", {}); michael@0: return elts; michael@0: }, michael@0: objectExpression: function(props) { michael@0: props.unshift("ObjectExpr", {}); michael@0: return props; michael@0: }, michael@0: thisExpression: function() { michael@0: return ["ThisExpr", {}]; michael@0: }, michael@0: michael@0: graphExpression: reject, michael@0: graphIndexExpression: reject, michael@0: comprehensionExpression: reject, michael@0: generatorExpression: reject, michael@0: yieldExpression: reject, michael@0: letExpression: reject, michael@0: michael@0: emptyStatement: function() ["EmptyStmt", {}], michael@0: blockStatement: function(stmts) { michael@0: stmts.unshift("BlockStmt", {}); michael@0: return stmts; michael@0: }, michael@0: labeledStatement: function(lab, stmt) { michael@0: return ["LabelledStmt", {label: lab}, stmt]; michael@0: }, michael@0: ifStatement: function(test, cons, alt) { michael@0: return ["IfStmt", {}, test, cons, alt || ["EmptyStmt", {}]]; michael@0: }, michael@0: switchStatement: function(test, clauses, isLexical) { michael@0: clauses.unshift("SwitchStmt", {}, test); michael@0: return clauses; michael@0: }, michael@0: whileStatement: function(expr, stmt) { michael@0: return ["WhileStmt", {}, expr, stmt]; michael@0: }, michael@0: doWhileStatement: function(stmt, expr) { michael@0: return ["DoWhileStmt", {}, stmt, expr]; michael@0: }, michael@0: forStatement: function(init, test, update, body) { michael@0: return ["ForStmt", {}, init || ["Empty"], test || ["Empty"], update || ["Empty"], body]; michael@0: }, michael@0: forInStatement: function(lhs, rhs, body) { michael@0: return ["ForInStmt", {}, lhs, rhs, body]; michael@0: }, michael@0: breakStatement: function(lab) { michael@0: return lab ? ["BreakStmt", {}, lab] : ["BreakStmt", {}]; michael@0: }, michael@0: continueStatement: function(lab) { michael@0: return lab ? ["ContinueStmt", {}, lab] : ["ContinueStmt", {}]; michael@0: }, michael@0: withStatement: function(expr, stmt) { michael@0: return ["WithStmt", {}, expr, stmt]; michael@0: }, michael@0: returnStatement: function(expr) { michael@0: return expr ? ["ReturnStmt", {}, expr] : ["ReturnStmt", {}]; michael@0: }, michael@0: tryStatement: function(body, catches, fin) { michael@0: if (catches.length > 1) michael@0: throw new SyntaxError("multiple catch clauses not supported"); michael@0: var node = ["TryStmt", body, catches[0] || ["Empty"]]; michael@0: if (fin) michael@0: node.push(fin); michael@0: return node; michael@0: }, michael@0: throwStatement: function(expr) { michael@0: return ["ThrowStmt", {}, expr]; michael@0: }, michael@0: debuggerStatement: function() ["DebuggerStmt", {}], michael@0: letStatement: reject, michael@0: switchCase: function(expr, stmts) { michael@0: if (expr) michael@0: stmts.unshift("SwitchCase", {}, expr); michael@0: else michael@0: stmts.unshift("DefaultCase", {}); michael@0: return stmts; michael@0: }, michael@0: catchClause: function(param, guard, body) { michael@0: if (guard) michael@0: throw new SyntaxError("catch guards not supported"); michael@0: param[0] = "IdPatt"; michael@0: return ["CatchClause", {}, param, body]; michael@0: }, michael@0: comprehensionBlock: reject, michael@0: michael@0: arrayPattern: reject, michael@0: objectPattern: reject, michael@0: propertyPattern: reject, michael@0: }; michael@0: })(); michael@0: michael@0: Pattern(["Program", {}, michael@0: ["BinaryExpr", {op: "+"}, michael@0: ["LiteralExpr", {value: 2}], michael@0: ["BinaryExpr", {op: "*"}, michael@0: ["UnaryExpr", {op: "-"}, ["IdExpr", {name: "x"}]], michael@0: ["IdExpr", {name: "y"}]]]]).match(Reflect.parse("2 + (-x * y)", {loc: false, builder: JsonMLAst})); michael@0: michael@0: reportCompare(true, true); michael@0: michael@0: });