1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * Any copyright is dedicated to the Public Domain.
4 * http://creativecommons.org/licenses/publicdomain/
7 var { Pattern, MatchError } = Match;
11 function program(elts) Pattern({ type: "Program", body: elts })
12 function exprStmt(expr) Pattern({ type: "ExpressionStatement", expression: expr })
13 function throwStmt(expr) Pattern({ type: "ThrowStatement", argument: expr })
14 function returnStmt(expr) Pattern({ type: "ReturnStatement", argument: expr })
15 function yieldExpr(expr) Pattern({ type: "YieldExpression", argument: expr })
16 function lit(val) Pattern({ type: "Literal", value: val })
17 var thisExpr = Pattern({ type: "ThisExpression" });
18 function funDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
23 function genFunDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
28 function varDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" })
29 function letDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" })
30 function constDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" })
31 function ident(name) Pattern({ type: "Identifier", name: name })
32 function dotExpr(obj, id) Pattern({ type: "MemberExpression", computed: false, object: obj, property: id })
33 function memExpr(obj, id) Pattern({ type: "MemberExpression", computed: true, object: obj, property: id })
34 function forStmt(init, test, update, body) Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body })
35 function forInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: false })
36 function forEachInStmt(lhs, rhs, body) Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body, each: true })
37 function breakStmt(lab) Pattern({ type: "BreakStatement", label: lab })
38 function continueStmt(lab) Pattern({ type: "ContinueStatement", label: lab })
39 function blockStmt(body) Pattern({ type: "BlockStatement", body: body })
40 var emptyStmt = Pattern({ type: "EmptyStatement" })
41 function ifStmt(test, cons, alt) Pattern({ type: "IfStatement", test: test, alternate: alt, consequent: cons })
42 function labStmt(lab, stmt) Pattern({ type: "LabeledStatement", label: lab, body: stmt })
43 function withStmt(obj, stmt) Pattern({ type: "WithStatement", object: obj, body: stmt })
44 function whileStmt(test, stmt) Pattern({ type: "WhileStatement", test: test, body: stmt })
45 function doStmt(stmt, test) Pattern({ type: "DoWhileStatement", test: test, body: stmt })
46 function switchStmt(disc, cases) Pattern({ type: "SwitchStatement", discriminant: disc, cases: cases })
47 function caseClause(test, stmts) Pattern({ type: "SwitchCase", test: test, consequent: stmts })
48 function defaultClause(stmts) Pattern({ type: "SwitchCase", test: null, consequent: stmts })
49 function catchClause(id, guard, body) Pattern({ type: "CatchClause", param: id, guard: guard, body: body })
50 function tryStmt(body, catches, fin) Pattern({ type: "TryStatement", block: body, handler: catches, finalizer: fin })
51 function letStmt(head, body) Pattern({ type: "LetStatement", head: head, body: body })
52 function funExpr(id, args, body, gen) Pattern({ type: "FunctionExpression",
57 function genFunExpr(id, args, body) Pattern({ type: "FunctionExpression",
63 function unExpr(op, arg) Pattern({ type: "UnaryExpression", operator: op, argument: arg })
64 function binExpr(op, left, right) Pattern({ type: "BinaryExpression", operator: op, left: left, right: right })
65 function aExpr(op, left, right) Pattern({ type: "AssignmentExpression", operator: op, left: left, right: right })
66 function updExpr(op, arg, prefix) Pattern({ type: "UpdateExpression", operator: op, argument: arg, prefix: prefix })
67 function logExpr(op, left, right) Pattern({ type: "LogicalExpression", operator: op, left: left, right: right })
69 function condExpr(test, cons, alt) Pattern({ type: "ConditionalExpression", test: test, consequent: cons, alternate: alt })
70 function seqExpr(exprs) Pattern({ type: "SequenceExpression", expressions: exprs })
71 function newExpr(callee, args) Pattern({ type: "NewExpression", callee: callee, arguments: args })
72 function callExpr(callee, args) Pattern({ type: "CallExpression", callee: callee, arguments: args })
73 function arrExpr(elts) Pattern({ type: "ArrayExpression", elements: elts })
74 function objExpr(elts) Pattern({ type: "ObjectExpression", properties: elts })
75 function compExpr(body, blocks, filter) Pattern({ type: "ComprehensionExpression", body: body, blocks: blocks, filter: filter })
76 function genExpr(body, blocks, filter) Pattern({ type: "GeneratorExpression", body: body, blocks: blocks, filter: filter })
77 function graphExpr(idx, body) Pattern({ type: "GraphExpression", index: idx, expression: body })
78 function letExpr(head, body) Pattern({ type: "LetExpression", head: head, body: body })
79 function idxExpr(idx) Pattern({ type: "GraphIndexExpression", index: idx })
81 function compBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: false })
82 function compEachBlock(left, right) Pattern({ type: "ComprehensionBlock", left: left, right: right, each: true })
84 function arrPatt(elts) Pattern({ type: "ArrayPattern", elements: elts })
85 function objPatt(elts) Pattern({ type: "ObjectPattern", properties: elts })
87 function localSrc(src) "(function(){ " + src + " })"
88 function localPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([patt])))])
89 function blockSrc(src) "(function(){ { " + src + " } })"
90 function blockPatt(patt) program([exprStmt(funExpr(null, [], blockStmt([blockStmt([patt])])))])
92 var xmlAnyName = Pattern({ type: "XMLAnyName" });
94 function xmlQualId(left, right, computed) Pattern({ type: "XMLQualifiedIdentifier", left: left, right: right, computed: computed })
95 function xmlFuncQualId(right, computed) Pattern({ type: "XMLFunctionQualifiedIdentifier", right: right, computed: computed })
96 function xmlAttrSel(id) Pattern({ type: "XMLAttributeSelector", attribute: id })
97 function xmlFilter(left, right) Pattern({ type: "XMLFilterExpression", left: left, right: right })
98 function xmlPointTag(contents) Pattern({ type: "XMLPointTag", contents: contents })
99 function xmlStartTag(contents) Pattern({ type: "XMLStartTag", contents: contents })
100 function xmlEndTag(contents) Pattern({ type: "XMLEndTag", contents: contents })
101 function xmlEscape(expr) Pattern({ type: "XMLEscape", expression: expr })
102 function xmlElt(contents) Pattern({ type: "XMLElement", contents: contents })
103 function xmlAttr(value) Pattern({ type: "XMLAttribute", value: value })
104 function xmlText(text) Pattern({ type: "XMLText", text: text })
105 function xmlPI(target, contents) Pattern({ type: "XMLProcessingInstruction", target: target, contents: contents })
106 function xmlDefNS(ns) Pattern({ type: "XMLDefaultDeclaration", namespace: ns })
107 function xmlName(name) Pattern({ type: "XMLName", contents: name })
108 function xmlComment(contents) Pattern({ type: "XMLComment", contents: contents })
109 function xmlCdata(cdata) Pattern({ type: "XMLCdata", contents: cdata })
111 function assertBlockStmt(src, patt) {
112 blockPatt(patt).assert(Reflect.parse(blockSrc(src)));
115 function assertBlockExpr(src, patt) {
116 assertBlockStmt(src, exprStmt(patt));
119 function assertBlockDecl(src, patt, builder) {
120 blockPatt(patt).assert(Reflect.parse(blockSrc(src), {builder: builder}));
123 function assertLocalStmt(src, patt) {
124 localPatt(patt).assert(Reflect.parse(localSrc(src)));
127 function assertLocalExpr(src, patt) {
128 assertLocalStmt(src, exprStmt(patt));
131 function assertLocalDecl(src, patt) {
132 localPatt(patt).assert(Reflect.parse(localSrc(src)));
135 function assertGlobalStmt(src, patt, builder) {
136 program([patt]).assert(Reflect.parse(src, {builder: builder}));
139 function assertGlobalExpr(src, patt, builder) {
140 program([exprStmt(patt)]).assert(Reflect.parse(src, {builder: builder}));
141 //assertStmt(src, exprStmt(patt));
144 function assertGlobalDecl(src, patt) {
145 program([patt]).assert(Reflect.parse(src));
148 function assertStmt(src, patt) {
149 assertLocalStmt(src, patt);
150 assertGlobalStmt(src, patt);
151 assertBlockStmt(src, patt);
154 function assertExpr(src, patt) {
155 assertLocalExpr(src, patt);
156 assertGlobalExpr(src, patt);
157 assertBlockExpr(src, patt);
160 function assertDecl(src, patt) {
161 assertLocalDecl(src, patt);
162 assertGlobalDecl(src, patt);
163 assertBlockDecl(src, patt);
166 function assertError(src, errorType) {
169 } catch (expected if expected instanceof errorType) {
172 throw new Error("expected " + errorType.name + " for " + uneval(src));
178 // NB: These are useful but for now jit-test doesn't do I/O reliably.
180 //program(_).assert(Reflect.parse(snarf('data/flapjax.txt')));
181 //program(_).assert(Reflect.parse(snarf('data/jquery-1.4.2.txt')));
182 //program(_).assert(Reflect.parse(snarf('data/prototype.js')));
183 //program(_).assert(Reflect.parse(snarf('data/dojo.js.uncompressed.js')));
184 //program(_).assert(Reflect.parse(snarf('data/mootools-1.2.4-core-nc.js')));
189 assertDecl("var x = 1, y = 2, z = 3",
190 varDecl([{ id: ident("x"), init: lit(1) },
191 { id: ident("y"), init: lit(2) },
192 { id: ident("z"), init: lit(3) }]));
193 assertDecl("var x, y, z",
194 varDecl([{ id: ident("x"), init: null },
195 { id: ident("y"), init: null },
196 { id: ident("z"), init: null }]));
197 assertDecl("function foo() { }",
198 funDecl(ident("foo"), [], blockStmt([])));
199 assertDecl("function foo() { return 42 }",
200 funDecl(ident("foo"), [], blockStmt([returnStmt(lit(42))])));
203 // Bug 591437: rebound args have their defs turned into uses
204 assertDecl("function f(a) { function a() { } }",
205 funDecl(ident("f"), [ident("a")], blockStmt([funDecl(ident("a"), [], blockStmt([]))])));
206 assertDecl("function f(a,b,c) { function b() { } }",
207 funDecl(ident("f"), [ident("a"),ident("b"),ident("c")], blockStmt([funDecl(ident("b"), [], blockStmt([]))])));
208 assertDecl("function f(a,[x,y]) { function a() { } }",
210 [ident("a"), arrPatt([ident("x"), ident("y")])],
211 blockStmt([funDecl(ident("a"), [], blockStmt([]))])));
213 // Bug 591450: this test currently crashes because of a bug in jsparse
214 // assertDecl("function f(a,[x,y],b,[w,z],c) { function b() { } }",
215 // funDecl(ident("f"),
216 // [ident("a"), arrPatt([ident("x"), ident("y")]), ident("b"), arrPatt([ident("w"), ident("z")]), ident("c")],
217 // blockStmt([funDecl(ident("b"), [], blockStmt([]))])));
222 assertExpr("true", lit(true));
223 assertExpr("false", lit(false));
224 assertExpr("42", lit(42));
225 assertExpr("(/asdf/)", lit(/asdf/));
226 assertExpr("this", thisExpr);
227 assertExpr("foo", ident("foo"));
228 assertExpr("foo.bar", dotExpr(ident("foo"), ident("bar")));
229 assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar")));
230 assertExpr("(function(){})", funExpr(null, [], blockStmt([])));
231 assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([])));
232 assertExpr("(function f(x,y,z) {})", funExpr(ident("f"), [ident("x"),ident("y"),ident("z")], blockStmt([])));
233 assertExpr("(++x)", updExpr("++", ident("x"), true));
234 assertExpr("(x++)", updExpr("++", ident("x"), false));
235 assertExpr("(+x)", unExpr("+", ident("x")));
236 assertExpr("(-x)", unExpr("-", ident("x")));
237 assertExpr("(!x)", unExpr("!", ident("x")));
238 assertExpr("(~x)", unExpr("~", ident("x")));
239 assertExpr("(delete x)", unExpr("delete", ident("x")));
240 assertExpr("(typeof x)", unExpr("typeof", ident("x")));
241 assertExpr("(void x)", unExpr("void", ident("x")));
242 assertExpr("(x == y)", binExpr("==", ident("x"), ident("y")));
243 assertExpr("(x != y)", binExpr("!=", ident("x"), ident("y")));
244 assertExpr("(x === y)", binExpr("===", ident("x"), ident("y")));
245 assertExpr("(x !== y)", binExpr("!==", ident("x"), ident("y")));
246 assertExpr("(x < y)", binExpr("<", ident("x"), ident("y")));
247 assertExpr("(x <= y)", binExpr("<=", ident("x"), ident("y")));
248 assertExpr("(x > y)", binExpr(">", ident("x"), ident("y")));
249 assertExpr("(x >= y)", binExpr(">=", ident("x"), ident("y")));
250 assertExpr("(x << y)", binExpr("<<", ident("x"), ident("y")));
251 assertExpr("(x >> y)", binExpr(">>", ident("x"), ident("y")));
252 assertExpr("(x >>> y)", binExpr(">>>", ident("x"), ident("y")));
253 assertExpr("(x + y)", binExpr("+", ident("x"), ident("y")));
254 assertExpr("(w + x + y + z)", binExpr("+", ident("w"), binExpr("+", ident("x", binExpr("+", ident("y"), ident("z"))))))
255 assertExpr("(x - y)", binExpr("-", ident("x"), ident("y")));
256 assertExpr("(x * y)", binExpr("*", ident("x"), ident("y")));
257 assertExpr("(x / y)", binExpr("/", ident("x"), ident("y")));
258 assertExpr("(x % y)", binExpr("%", ident("x"), ident("y")));
259 assertExpr("(x | y)", binExpr("|", ident("x"), ident("y")));
260 assertExpr("(x ^ y)", binExpr("^", ident("x"), ident("y")));
261 assertExpr("(x & y)", binExpr("&", ident("x"), ident("y")));
262 assertExpr("(x in y)", binExpr("in", ident("x"), ident("y")));
263 assertExpr("(x instanceof y)", binExpr("instanceof", ident("x"), ident("y")));
264 assertExpr("(x = y)", aExpr("=", ident("x"), ident("y")));
265 assertExpr("(x += y)", aExpr("+=", ident("x"), ident("y")));
266 assertExpr("(x -= y)", aExpr("-=", ident("x"), ident("y")));
267 assertExpr("(x *= y)", aExpr("*=", ident("x"), ident("y")));
268 assertExpr("(x /= y)", aExpr("/=", ident("x"), ident("y")));
269 assertExpr("(x %= y)", aExpr("%=", ident("x"), ident("y")));
270 assertExpr("(x <<= y)", aExpr("<<=", ident("x"), ident("y")));
271 assertExpr("(x >>= y)", aExpr(">>=", ident("x"), ident("y")));
272 assertExpr("(x >>>= y)", aExpr(">>>=", ident("x"), ident("y")));
273 assertExpr("(x |= y)", aExpr("|=", ident("x"), ident("y")));
274 assertExpr("(x ^= y)", aExpr("^=", ident("x"), ident("y")));
275 assertExpr("(x &= y)", aExpr("&=", ident("x"), ident("y")));
276 assertExpr("(x || y)", logExpr("||", ident("x"), ident("y")));
277 assertExpr("(x && y)", logExpr("&&", ident("x"), ident("y")));
278 assertExpr("(w || x || y || z)", logExpr("||", ident("w"), logExpr("||", ident("x", logExpr("||", ident("y"), ident("z"))))))
279 assertExpr("(x ? y : z)", condExpr(ident("x"), ident("y"), ident("z")));
280 assertExpr("(x,y)", seqExpr([ident("x"),ident("y")]))
281 assertExpr("(x,y,z)", seqExpr([ident("x"),ident("y"),ident("z")]))
282 assertExpr("(a,b,c,d,e,f,g)", seqExpr([ident("a"),ident("b"),ident("c"),ident("d"),ident("e"),ident("f"),ident("g")]));
283 assertExpr("(new Object)", newExpr(ident("Object"), []));
284 assertExpr("(new Object())", newExpr(ident("Object"), []));
285 assertExpr("(new Object(42))", newExpr(ident("Object"), [lit(42)]));
286 assertExpr("(new Object(1,2,3))", newExpr(ident("Object"), [lit(1),lit(2),lit(3)]));
287 assertExpr("(String())", callExpr(ident("String"), []));
288 assertExpr("(String(42))", callExpr(ident("String"), [lit(42)]));
289 assertExpr("(String(1,2,3))", callExpr(ident("String"), [lit(1),lit(2),lit(3)]));
290 assertExpr("[]", arrExpr([]));
291 assertExpr("[1]", arrExpr([lit(1)]));
292 assertExpr("[1,2]", arrExpr([lit(1),lit(2)]));
293 assertExpr("[1,2,3]", arrExpr([lit(1),lit(2),lit(3)]));
294 assertExpr("[1,,2,3]", arrExpr([lit(1),,lit(2),lit(3)]));
295 assertExpr("[1,,,2,3]", arrExpr([lit(1),,,lit(2),lit(3)]));
296 assertExpr("[1,,,2,,3]", arrExpr([lit(1),,,lit(2),,lit(3)]));
297 assertExpr("[1,,,2,,,3]", arrExpr([lit(1),,,lit(2),,,lit(3)]));
298 assertExpr("[,1,2,3]", arrExpr([,lit(1),lit(2),lit(3)]));
299 assertExpr("[,,1,2,3]", arrExpr([,,lit(1),lit(2),lit(3)]));
300 assertExpr("[,,,1,2,3]", arrExpr([,,,lit(1),lit(2),lit(3)]));
301 assertExpr("[,,,1,2,3,]", arrExpr([,,,lit(1),lit(2),lit(3)]));
302 assertExpr("[,,,1,2,3,,]", arrExpr([,,,lit(1),lit(2),lit(3),]));
303 assertExpr("[,,,1,2,3,,,]", arrExpr([,,,lit(1),lit(2),lit(3),,]));
304 assertExpr("[,,,,,]", arrExpr([,,,,]));
305 assertExpr("({})", objExpr([]));
306 assertExpr("({x:1})", objExpr([{ key: ident("x"), value: lit(1) }]));
307 assertExpr("({x:1, y:2})", objExpr([{ key: ident("x"), value: lit(1) },
308 { key: ident("y"), value: lit(2) } ]));
309 assertExpr("({x:1, y:2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
310 { key: ident("y"), value: lit(2) },
311 { key: ident("z"), value: lit(3) } ]));
312 assertExpr("({x:1, 'y':2, z:3})", objExpr([{ key: ident("x"), value: lit(1) },
313 { key: lit("y"), value: lit(2) },
314 { key: ident("z"), value: lit(3) } ]));
315 assertExpr("({'x':1, 'y':2, z:3})", objExpr([{ key: lit("x"), value: lit(1) },
316 { key: lit("y"), value: lit(2) },
317 { key: ident("z"), value: lit(3) } ]));
318 assertExpr("({'x':1, 'y':2, 3:3})", objExpr([{ key: lit("x"), value: lit(1) },
319 { key: lit("y"), value: lit(2) },
320 { key: lit(3), value: lit(3) } ]));
324 assertStmt("throw 42", throwStmt(lit(42)));
325 assertStmt("for (;;) break", forStmt(null, null, null, breakStmt(null)));
326 assertStmt("for (x; y; z) break", forStmt(ident("x"), ident("y"), ident("z"), breakStmt(null)));
327 assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z")));
328 assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z")));
329 assertStmt("for (x; ; z) break", forStmt(ident("x"), null, ident("z"), breakStmt(null)));
330 assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z")));
331 assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z")));
332 assertStmt("for (x; y; ) break", forStmt(ident("x"), ident("y"), null, breakStmt(null)));
333 assertStmt("for (var x; y; ) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), null, breakStmt(null)));
334 assertStmt("for (var x = 42; y; ) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), null, breakStmt(null)));
335 assertStmt("for (var x in y) break", forInStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), breakStmt(null)));
336 assertStmt("for (x in y) break", forInStmt(ident("x"), ident("y"), breakStmt(null)));
337 assertStmt("{ }", blockStmt([]));
338 assertStmt("{ throw 1; throw 2; throw 3; }", blockStmt([ throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]));
339 assertStmt(";", emptyStmt);
340 assertStmt("if (foo) throw 42;", ifStmt(ident("foo"), throwStmt(lit(42)), null));
341 assertStmt("if (foo) throw 42; else true;", ifStmt(ident("foo"), throwStmt(lit(42)), exprStmt(lit(true))));
342 assertStmt("if (foo) { throw 1; throw 2; throw 3; }",
344 blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]),
346 assertStmt("if (foo) { throw 1; throw 2; throw 3; } else true;",
348 blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]),
349 exprStmt(lit(true))));
350 assertStmt("foo: for(;;) break foo;", labStmt(ident("foo"), forStmt(null, null, null, breakStmt(ident("foo")))));
351 assertStmt("foo: for(;;) continue foo;", labStmt(ident("foo"), forStmt(null, null, null, continueStmt(ident("foo")))));
352 assertStmt("with (obj) { }", withStmt(ident("obj"), blockStmt([])));
353 assertStmt("with (obj) { obj; }", withStmt(ident("obj"), blockStmt([exprStmt(ident("obj"))])));
354 assertStmt("while (foo) { }", whileStmt(ident("foo"), blockStmt([])));
355 assertStmt("while (foo) { foo; }", whileStmt(ident("foo"), blockStmt([exprStmt(ident("foo"))])));
356 assertStmt("do { } while (foo);", doStmt(blockStmt([]), ident("foo")));
357 assertStmt("do { foo; } while (foo)", doStmt(blockStmt([exprStmt(ident("foo"))]), ident("foo")));
358 assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; }",
359 switchStmt(ident("foo"),
360 [ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]),
361 caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]),
362 defaultClause([ exprStmt(lit(3)) ]) ]));
363 assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; case 42: 42; }",
364 switchStmt(ident("foo"),
365 [ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]),
366 caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]),
367 defaultClause([ exprStmt(lit(3)) ]),
368 caseClause(lit(42), [ exprStmt(lit(42)) ]) ]));
369 assertStmt("try { } catch (e) { }",
370 tryStmt(blockStmt([]),
371 catchClause(ident("e"), null, blockStmt([])),
373 assertStmt("try { } catch (e) { } finally { }",
374 tryStmt(blockStmt([]),
375 catchClause(ident("e"), null, blockStmt([])),
377 assertStmt("try { } finally { }",
378 tryStmt(blockStmt([]),
381 assertStmt("try { } catch (e if foo) { } catch (e if bar) { } finally { }",
382 tryStmt(blockStmt([]),
383 [ catchClause(ident("e"), ident("foo"), blockStmt([])),
384 catchClause(ident("e"), ident("bar"), blockStmt([])) ],
386 assertStmt("try { } catch (e if foo) { } catch (e if bar) { } catch (e) { } finally { }",
387 tryStmt(blockStmt([]),
388 [ catchClause(ident("e"), ident("foo"), blockStmt([])),
389 catchClause(ident("e"), ident("bar"), blockStmt([])),
390 catchClause(ident("e"), null, blockStmt([])) ],
393 // redeclarations (TOK_NAME nodes with lexdef)
395 assertStmt("function f() { function g() { } function g() { } }",
396 funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])),
397 funDecl(ident("g"), [], blockStmt([]))])));
399 assertStmt("function f() { function g() { } function g() { return 42 } }",
400 funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])),
401 funDecl(ident("g"), [], blockStmt([returnStmt(lit(42))]))])));
403 assertStmt("function f() { var x = 42; var x = 43; }",
404 funDecl(ident("f"), [], blockStmt([varDecl([{ id: ident("x"), init: lit(42) }]),
405 varDecl([{ id: ident("x"), init: lit(43) }])])));
408 assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
409 init: ident("foo") }]));
412 assertGlobalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
413 init: ident("foo") }]));
414 // function-global let is var
415 assertLocalDecl("let {x:y} = foo;", varDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
416 init: ident("foo") }]));
417 // block-local let is let
418 assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
419 init: ident("foo") }]));
421 assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([{ key: ident("x"), value: ident("y") }]),
422 init: ident("foo") }]));
425 // various combinations of identifiers and destructuring patterns:
426 function makePatternCombinations(id, destr)
430 [ id(1), id(2), id(3) ],
431 [ id(1), id(2), id(3), id(4) ],
432 [ id(1), id(2), id(3), id(4), id(5) ],
435 [ destr(1), destr(2) ],
436 [ destr(1), destr(2), destr(3) ],
437 [ destr(1), destr(2), destr(3), destr(4) ],
438 [ destr(1), destr(2), destr(3), destr(4), destr(5) ],
442 [ destr(1), id(2), id(3) ],
443 [ destr(1), id(2), id(3), id(4) ],
444 [ destr(1), id(2), id(3), id(4), id(5) ],
445 [ destr(1), id(2), id(3), id(4), destr(5) ],
446 [ destr(1), id(2), id(3), destr(4) ],
447 [ destr(1), id(2), id(3), destr(4), id(5) ],
448 [ destr(1), id(2), id(3), destr(4), destr(5) ],
450 [ destr(1), id(2), destr(3) ],
451 [ destr(1), id(2), destr(3), id(4) ],
452 [ destr(1), id(2), destr(3), id(4), id(5) ],
453 [ destr(1), id(2), destr(3), id(4), destr(5) ],
454 [ destr(1), id(2), destr(3), destr(4) ],
455 [ destr(1), id(2), destr(3), destr(4), id(5) ],
456 [ destr(1), id(2), destr(3), destr(4), destr(5) ],
460 [ id(1), destr(2), id(3) ],
461 [ id(1), destr(2), id(3), id(4) ],
462 [ id(1), destr(2), id(3), id(4), id(5) ],
463 [ id(1), destr(2), id(3), id(4), destr(5) ],
464 [ id(1), destr(2), id(3), destr(4) ],
465 [ id(1), destr(2), id(3), destr(4), id(5) ],
466 [ id(1), destr(2), id(3), destr(4), destr(5) ],
468 [ id(1), destr(2), destr(3) ],
469 [ id(1), destr(2), destr(3), id(4) ],
470 [ id(1), destr(2), destr(3), id(4), id(5) ],
471 [ id(1), destr(2), destr(3), id(4), destr(5) ],
472 [ id(1), destr(2), destr(3), destr(4) ],
473 [ id(1), destr(2), destr(3), destr(4), id(5) ],
474 [ id(1), destr(2), destr(3), destr(4), destr(5) ]
477 // destructuring function parameters
479 function testParamPatternCombinations(makePattSrc, makePattPatt) {
480 var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
481 var pattPatts = makePatternCombinations(function(n) (ident("x" + n)), makePattPatt);
483 for (var i = 0; i < pattSrcs.length; i++) {
484 function makeSrc(body) ("(function(" + pattSrcs[i].join(",") + ") " + body + ")")
485 function makePatt(body) (funExpr(null, pattPatts[i], body))
487 // no upvars, block body
488 assertExpr(makeSrc("{ }", makePatt(blockStmt([]))));
489 // upvars, block body
490 assertExpr(makeSrc("{ return [x1,x2,x3,x4,x5]; }"),
491 makePatt(blockStmt([returnStmt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))])));
492 // no upvars, expression body
493 assertExpr(makeSrc("(0)"), makePatt(lit(0)));
494 // upvars, expression body
495 assertExpr(makeSrc("[x1,x2,x3,x4,x5]"),
496 makePatt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")])));
500 testParamPatternCombinations(function(n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "}"),
501 function(n) (objPatt([{ key: ident("a" + n), value: ident("x" + n) },
502 { key: ident("b" + n), value: ident("y" + n) },
503 { key: ident("c" + n), value: ident("z" + n) }])));
505 testParamPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "]"),
506 function(n) (arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)])));
509 // destructuring variable declarations
511 function testVarPatternCombinations(makePattSrc, makePattPatt) {
512 var pattSrcs = makePatternCombinations(function(n) ("x" + n), makePattSrc);
513 var pattPatts = makePatternCombinations(function(n) ({ id: ident("x" + n), init: null }), makePattPatt);
515 for (var i = 0; i < pattSrcs.length; i++) {
516 // variable declarations in blocks
517 assertDecl("var " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
519 assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
520 assertLocalDecl("let " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i]));
521 assertBlockDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i]));
523 assertDecl("const " + pattSrcs[i].join(",") + ";", constDecl(pattPatts[i]));
525 // variable declarations in for-loop heads
526 assertStmt("for (var " + pattSrcs[i].join(",") + "; foo; bar);",
527 forStmt(varDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
528 assertStmt("for (let " + pattSrcs[i].join(",") + "; foo; bar);",
529 forStmt(letDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
530 assertStmt("for (const " + pattSrcs[i].join(",") + "; foo; bar);",
531 forStmt(constDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt));
535 testVarPatternCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
536 function (n) ({ id: objPatt([{ key: ident("a" + n), value: ident("x" + n) },
537 { key: ident("b" + n), value: ident("y" + n) },
538 { key: ident("c" + n), value: ident("z" + n) }]),
541 testVarPatternCombinations(function(n) ("[x" + n + "," + "y" + n + "," + "z" + n + "] = 0"),
542 function(n) ({ id: arrPatt([ident("x" + n), ident("y" + n), ident("z" + n)]),
545 // destructuring assignment
547 function testAssignmentCombinations(makePattSrc, makePattPatt) {
548 var pattSrcs = makePatternCombinations(function(n) ("x" + n + " = 0"), makePattSrc);
549 var pattPatts = makePatternCombinations(function(n) (aExpr("=", ident("x" + n), lit(0))), makePattPatt);
551 for (var i = 0; i < pattSrcs.length; i++) {
552 var src = pattSrcs[i].join(",");
553 var patt = pattPatts[i].length === 1 ? pattPatts[i][0] : seqExpr(pattPatts[i]);
555 // assignment expression statement
556 assertExpr("(" + src + ")", patt);
558 // for-loop head assignment
559 assertStmt("for (" + src + "; foo; bar);",
560 forStmt(patt, ident("foo"), ident("bar"), emptyStmt));
564 testAssignmentCombinations(function (n) ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"),
565 function (n) (aExpr("=",
566 objPatt([{ key: ident("a" + n), value: ident("x" + n) },
567 { key: ident("b" + n), value: ident("y" + n) },
568 { key: ident("c" + n), value: ident("z" + n) }]),
572 // destructuring in for-in and for-each-in loop heads
574 var axbycz = objPatt([{ key: ident("a"), value: ident("x") },
575 { key: ident("b"), value: ident("y") },
576 { key: ident("c"), value: ident("z") }]);
577 var xyz = arrPatt([ident("x"), ident("y"), ident("z")]);
579 assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
580 assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
581 assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt));
582 assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
583 assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
584 assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt));
585 assertStmt("for each (var {a:x,b:y,c:z} in foo);", forEachInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
586 assertStmt("for each (let {a:x,b:y,c:z} in foo);", forEachInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt));
587 assertStmt("for each ({a:x,b:y,c:z} in foo);", forEachInStmt(axbycz, ident("foo"), emptyStmt));
588 assertStmt("for each (var [x,y,z] in foo);", forEachInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
589 assertStmt("for each (let [x,y,z] in foo);", forEachInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt));
590 assertStmt("for each ([x,y,z] in foo);", forEachInStmt(xyz, ident("foo"), emptyStmt));
591 assertError("for (const x in foo);", SyntaxError);
592 assertError("for (const {a:x,b:y,c:z} in foo);", SyntaxError);
593 assertError("for (const [x,y,z] in foo);", SyntaxError);
594 assertError("for each (const x in foo);", SyntaxError);
595 assertError("for each (const {a:x,b:y,c:z} in foo);", SyntaxError);
596 assertError("for each (const [x,y,z] in foo);", SyntaxError);
598 // destructuring in for-in and for-each-in loop heads with initializers
600 assertStmt("for (var {a:x,b:y,c:z} = 22 in foo);", forInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
601 assertStmt("for (var [x,y,z] = 22 in foo);", forInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
602 assertStmt("for each (var {a:x,b:y,c:z} = 22 in foo);", forEachInStmt(varDecl([{ id: axbycz, init: lit(22) }]), ident("foo"), emptyStmt));
603 assertStmt("for each (var [x,y,z] = 22 in foo);", forEachInStmt(varDecl([{ id: xyz, init: lit(22) }]), ident("foo"), emptyStmt));
604 assertError("for (x = 22 in foo);", SyntaxError);
605 assertError("for ({a:x,b:y,c:z} = 22 in foo);", SyntaxError);
606 assertError("for ([x,y,z] = 22 in foo);", SyntaxError);
607 assertError("for (const x = 22 in foo);", SyntaxError);
608 assertError("for (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError);
609 assertError("for (const [x,y,z] = 22 in foo);", SyntaxError);
610 assertError("for each (const x = 22 in foo);", SyntaxError);
611 assertError("for each (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError);
612 assertError("for each (const [x,y,z] = 22 in foo);", SyntaxError);
614 // expression closures
616 assertDecl("function inc(x) (x + 1)", funDecl(ident("inc"), [ident("x")], binExpr("+", ident("x"), lit(1))));
617 assertExpr("(function(x) (x+1))", funExpr(null, [ident("x")], binExpr("+"), ident("x"), lit(1)));
621 assertDecl("function gen(x) { yield }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
622 assertExpr("(function(x) { yield })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(null))])));
623 assertDecl("function gen(x) { yield 42 }", genFunDecl(ident("gen"), [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
624 assertExpr("(function(x) { yield 42 })", genFunExpr(null, [ident("x")], blockStmt([exprStmt(yieldExpr(lit(42)))])));
626 // getters and setters
628 assertExpr("({ get x() { return 42 } })",
629 objExpr([ { key: ident("x"),
630 value: funExpr(null, [], blockStmt([returnStmt(lit(42))])),
632 assertExpr("({ set x(v) { return 42 } })",
633 objExpr([ { key: ident("x"),
634 value: funExpr(null, [ident("v")], blockStmt([returnStmt(lit(42))])),
639 assertExpr("[ x for (x in foo)]",
640 compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null));
641 assertExpr("[ [x,y] for (x in foo) for (y in bar)]",
642 compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null));
643 assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz)]",
644 compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
645 [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
648 assertExpr("[ x for (x in foo) if (p)]",
649 compExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p")));
650 assertExpr("[ [x,y] for (x in foo) for (y in bar) if (p)]",
651 compExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p")));
652 assertExpr("[ [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) ]",
653 compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
654 [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
657 assertExpr("[ x for each (x in foo)]",
658 compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null));
659 assertExpr("[ [x,y] for each (x in foo) for each (y in bar)]",
660 compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null));
661 assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz)]",
662 compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
663 [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
666 assertExpr("[ x for each (x in foo) if (p)]",
667 compExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p")));
668 assertExpr("[ [x,y] for each (x in foo) for each (y in bar) if (p)]",
669 compExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p")));
670 assertExpr("[ [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) ]",
671 compExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
672 [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
675 // generator expressions
677 assertExpr("( x for (x in foo))",
678 genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], null));
679 assertExpr("( [x,y] for (x in foo) for (y in bar))",
680 genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], null));
681 assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz))",
682 genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
683 [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
686 assertExpr("( x for (x in foo) if (p))",
687 genExpr(ident("x"), [compBlock(ident("x"), ident("foo"))], ident("p")));
688 assertExpr("( [x,y] for (x in foo) for (y in bar) if (p))",
689 genExpr(arrExpr([ident("x"), ident("y")]), [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar"))], ident("p")));
690 assertExpr("( [x,y,z] for (x in foo) for (y in bar) for (z in baz) if (p) )",
691 genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
692 [compBlock(ident("x"), ident("foo")), compBlock(ident("y"), ident("bar")), compBlock(ident("z"), ident("baz"))],
695 assertExpr("( x for each (x in foo))",
696 genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], null));
697 assertExpr("( [x,y] for each (x in foo) for each (y in bar))",
698 genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], null));
699 assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz))",
700 genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
701 [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
704 assertExpr("( x for each (x in foo) if (p))",
705 genExpr(ident("x"), [compEachBlock(ident("x"), ident("foo"))], ident("p")));
706 assertExpr("( [x,y] for each (x in foo) for each (y in bar) if (p))",
707 genExpr(arrExpr([ident("x"), ident("y")]), [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar"))], ident("p")));
708 assertExpr("( [x,y,z] for each (x in foo) for each (y in bar) for each (z in baz) if (p) )",
709 genExpr(arrExpr([ident("x"), ident("y"), ident("z")]),
710 [compEachBlock(ident("x"), ident("foo")), compEachBlock(ident("y"), ident("bar")), compEachBlock(ident("z"), ident("baz"))],
713 // NOTE: it would be good to test generator expressions both with and without upvars, just like functions above.
718 assertExpr("#1={me:#1#}", graphExpr(1, objExpr([{ key: ident("me"), value: idxExpr(1) }])));
722 assertExpr("(let (x=1) x)", letExpr([{ id: ident("x"), init: lit(1) }], ident("x")));
723 assertExpr("(let (x=1,y=2) y)", letExpr([{ id: ident("x"), init: lit(1) },
724 { id: ident("y"), init: lit(2) }],
726 assertExpr("(let (x=1,y=2,z=3) z)", letExpr([{ id: ident("x"), init: lit(1) },
727 { id: ident("y"), init: lit(2) },
728 { id: ident("z"), init: lit(3) }],
730 assertExpr("(let (x) x)", letExpr([{ id: ident("x"), init: null }], ident("x")));
731 assertExpr("(let (x,y) y)", letExpr([{ id: ident("x"), init: null },
732 { id: ident("y"), init: null }],
734 assertExpr("(let (x,y,z) z)", letExpr([{ id: ident("x"), init: null },
735 { id: ident("y"), init: null },
736 { id: ident("z"), init: null }],
738 assertExpr("(let (x = 1, y = x) y)", letExpr([{ id: ident("x"), init: lit(1) },
739 { id: ident("y"), init: ident("x") }],
741 assertError("(let (x = 1, x = 2) x)", TypeError);
745 assertStmt("let (x=1) { }", letStmt([{ id: ident("x"), init: lit(1) }], blockStmt([])));
746 assertStmt("let (x=1,y=2) { }", letStmt([{ id: ident("x"), init: lit(1) },
747 { id: ident("y"), init: lit(2) }],
749 assertStmt("let (x=1,y=2,z=3) { }", letStmt([{ id: ident("x"), init: lit(1) },
750 { id: ident("y"), init: lit(2) },
751 { id: ident("z"), init: lit(3) }],
753 assertStmt("let (x) { }", letStmt([{ id: ident("x"), init: null }], blockStmt([])));
754 assertStmt("let (x,y) { }", letStmt([{ id: ident("x"), init: null },
755 { id: ident("y"), init: null }],
757 assertStmt("let (x,y,z) { }", letStmt([{ id: ident("x"), init: null },
758 { id: ident("y"), init: null },
759 { id: ident("z"), init: null }],
761 assertStmt("let (x = 1, y = x) { }", letStmt([{ id: ident("x"), init: lit(1) },
762 { id: ident("y"), init: ident("x") }],
764 assertError("let (x = 1, x = 2) { }", TypeError);
769 assertExpr("x..tagName", binExpr("..", ident("x"), lit("tagName")));
770 assertExpr("x.*", memExpr(ident("x"), xmlAnyName));
771 assertExpr("x[*]", memExpr(ident("x"), xmlAnyName));
772 assertExpr("x::y", xmlQualId(ident("x"), ident("y"), false));
773 assertExpr("x::[foo]", xmlQualId(ident("x"), ident("foo"), true));
774 assertExpr("x::[foo()]", xmlQualId(ident("x"), callExpr(ident("foo"), []), true));
775 assertExpr("*::*", xmlQualId(xmlAnyName, ident("*"), false));
776 assertExpr("*::[foo]", xmlQualId(xmlAnyName, ident("foo"), true));
777 assertExpr("*::[foo()]", xmlQualId(xmlAnyName, callExpr(ident("foo"), []), true));
778 assertExpr("function::x", xmlFuncQualId(ident("x"), false));
779 assertExpr("function::[foo]", xmlFuncQualId(ident("foo"), true));
780 assertExpr("@foo", xmlAttrSel(ident("foo")));
781 assertExpr("x.(p)", xmlFilter(ident("x"), ident("p")));
782 assertExpr("<{foo}/>", xmlPointTag([xmlEscape(ident("foo"))]));
783 assertExpr("<{foo}></{foo}>", xmlElt([xmlStartTag([xmlEscape(ident("foo"))]),
784 xmlEndTag([xmlEscape(ident("foo"))])]));
785 assertExpr("<{foo} {attr}='attr'/>", xmlPointTag([xmlEscape(ident("foo")),
786 xmlEscape(ident("attr")),
788 assertExpr("<{foo}>text</{foo}>", xmlElt([xmlStartTag([xmlEscape(ident("foo"))]),
790 xmlEndTag([xmlEscape(ident("foo"))])]));
791 assertExpr("<?xml?>", xmlPI("xml", ""));
792 assertExpr("<?xml version='1.0'?>", xmlPI("xml", "version='1.0'"));
793 assertDecl("default xml namespace = 'js';", xmlDefNS(lit("js")));
794 assertDecl("default xml namespace = foo;", xmlDefNS(ident("foo")));
796 // The parser turns these into TOK_UNARY nodes with pn_op == JSOP_SETXMLNAME.
798 assertExpr("x::y = foo", aExpr("=", xmlQualId(ident("x"), ident("y"), false), ident("foo")));
799 assertExpr("function::x = foo", aExpr("=", xmlFuncQualId(ident("x"), false), ident("foo")));
800 assertExpr("@x = foo", aExpr("=", xmlAttrSel(ident("x")), ident("foo")));
801 assertExpr("x::* = foo", aExpr("=", xmlQualId(ident("x"), ident("*"), false), ident("foo")));
802 assertExpr("*::* = foo", aExpr("=", xmlQualId(xmlAnyName, ident("*"), false), ident("foo")));
803 assertExpr("x.* = foo", aExpr("=", memExpr(ident("x"), xmlAnyName), ident("foo")));
804 assertExpr("x[*] = foo", aExpr("=", memExpr(ident("x"), xmlAnyName), ident("foo")));
806 assertExpr("x::y += foo", aExpr("+=", xmlQualId(ident("x"), ident("y"), false), ident("foo")));
807 assertExpr("function::x += foo", aExpr("+=", xmlFuncQualId(ident("x"), false), ident("foo")));
808 assertExpr("@x += foo", aExpr("+=", xmlAttrSel(ident("x")), ident("foo")));
809 assertExpr("x::* += foo", aExpr("+=", xmlQualId(ident("x"), ident("*"), false), ident("foo")));
810 assertExpr("*::* += foo", aExpr("+=", xmlQualId(xmlAnyName, ident("*"), false), ident("foo")));
811 assertExpr("x.* += foo", aExpr("+=", memExpr(ident("x"), xmlAnyName), ident("foo")));
812 assertExpr("x[*] += foo", aExpr("+=", memExpr(ident("x"), xmlAnyName), ident("foo")));
814 assertExpr("x::y++", updExpr("++", xmlQualId(ident("x"), ident("y"), false), false));
815 assertExpr("function::x++", updExpr("++", xmlFuncQualId(ident("x"), false), false));
816 assertExpr("@x++", updExpr("++", xmlAttrSel(ident("x")), false));
817 assertExpr("x::*++", updExpr("++", xmlQualId(ident("x"), ident("*"), false), false));
818 assertExpr("*::*++", updExpr("++", xmlQualId(xmlAnyName, ident("*"), false), false));
819 assertExpr("x.*++", updExpr("++", memExpr(ident("x"), xmlAnyName), false));
820 assertExpr("x[*]++", updExpr("++", memExpr(ident("x"), xmlAnyName), false));
822 assertExpr("++x::y", updExpr("++", xmlQualId(ident("x"), ident("y"), false), true));
823 assertExpr("++function::x", updExpr("++", xmlFuncQualId(ident("x"), false), true));
824 assertExpr("++@x", updExpr("++", xmlAttrSel(ident("x")), true));
825 assertExpr("++x::*", updExpr("++", xmlQualId(ident("x"), ident("*"), false), true));
826 assertExpr("++*::*", updExpr("++", xmlQualId(xmlAnyName, ident("*"), false), true));
827 assertExpr("++x.*", updExpr("++", memExpr(ident("x"), xmlAnyName), true));
828 assertExpr("++x[*]", updExpr("++", memExpr(ident("x"), xmlAnyName), true));
831 // The parser turns these into TOK_UNARY nodes with pn_op == JSOP_BINDXMLNAME.
833 function singletonObjPatt(name, val) objPatt([{ key: ident(name), value: val }])
835 assertExpr("({a:x::y}) = foo", aExpr("=", singletonObjPatt("a", xmlQualId(ident("x"), ident("y"), false)), ident("foo")));
836 assertExpr("({a:function::x}) = foo", aExpr("=", singletonObjPatt("a", xmlFuncQualId(ident("x"), false)), ident("foo")));
837 assertExpr("({a:@x}) = foo", aExpr("=", singletonObjPatt("a", xmlAttrSel(ident("x"))), ident("foo")));
838 assertExpr("({a:x::*}) = foo", aExpr("=", singletonObjPatt("a", xmlQualId(ident("x"), ident("*"), false)), ident("foo")));
839 assertExpr("({a:*::*}) = foo", aExpr("=", singletonObjPatt("a", xmlQualId(xmlAnyName, ident("*"), false)), ident("foo")));
840 assertExpr("({a:x.*}) = foo", aExpr("=", singletonObjPatt("a", memExpr(ident("x"), xmlAnyName)), ident("foo")));
841 assertExpr("({a:x[*]}) = foo", aExpr("=", singletonObjPatt("a", memExpr(ident("x"), xmlAnyName)), ident("foo")));
843 function emptyForInPatt(val, rhs) forInStmt(val, rhs, emptyStmt)
845 assertStmt("for (x::y in foo);", emptyForInPatt(xmlQualId(ident("x"), ident("y"), false), ident("foo")));
846 assertStmt("for (function::x in foo);", emptyForInPatt(xmlFuncQualId(ident("x"), false), ident("foo")));
847 assertStmt("for (@x in foo);", emptyForInPatt(xmlAttrSel(ident("x")), ident("foo")));
848 assertStmt("for (x::* in foo);", emptyForInPatt(xmlQualId(ident("x"), ident("*"), false), ident("foo")));
849 assertStmt("for (*::* in foo);", emptyForInPatt(xmlQualId(xmlAnyName, ident("*"), false), ident("foo")));
850 assertStmt("for (x.* in foo);", emptyForInPatt(memExpr(ident("x"), xmlAnyName), ident("foo")));
851 assertStmt("for (x[*] in foo);", emptyForInPatt(memExpr(ident("x"), xmlAnyName), ident("foo")));
854 // I'm not quite sure why, but putting XML in the callee of a call expression is
855 // the only way I've found to be able to preserve TOK_XMLNAME, TOK_XMLSPACE,
856 // TOK_XMLCDATA, and TOK_XMLCOMMENT parse nodes.
858 assertExpr("(<x> </x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]),
860 xmlEndTag([xmlName("x")])]),
862 assertExpr("(<x> </x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]),
864 xmlEndTag([xmlName("x")])]),
866 assertExpr("(<x><![CDATA[hello, world]]></x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]),
867 xmlCdata("hello, world"),
868 xmlEndTag([xmlName("x")])]),
870 assertExpr("(<x><!-- hello, world --></x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]),
871 xmlComment(" hello, world "),
872 xmlEndTag([xmlName("x")])]),
876 // Source location information
879 var withoutFileOrLine = Reflect.parse("42");
880 var withFile = Reflect.parse("42", {source:"foo.js"});
881 var withFileAndLine = Reflect.parse("42", {source:"foo.js", line:111});
883 Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withoutFileOrLine.loc);
884 Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withFile.loc);
885 Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 111, column: 2 } }).match(withFileAndLine.loc);
887 var withoutFileOrLine2 = Reflect.parse("foo +\nbar");
888 var withFile2 = Reflect.parse("foo +\nbar", {source:"foo.js"});
889 var withFileAndLine2 = Reflect.parse("foo +\nbar", {source:"foo.js", line:111});
891 Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withoutFileOrLine2.loc);
892 Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withFile2.loc);
893 Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 112, column: 3 } }).match(withFileAndLine2.loc);
895 var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", {source:"quad.js"});
896 var fourAC = nested.body[0].expression.left.right.arguments[0].right;
898 Pattern({ source: "quad.js", start: { line: 1, column: 20 }, end: { line: 1, column: 29 } }).match(fourAC.loc);
901 // No source location
903 assertEq(Reflect.parse("42", {loc:false}).loc, null);
904 program([exprStmt(lit(42))]).assert(Reflect.parse("42", {loc:false}));
909 Pattern("program").match(Reflect.parse("42", {builder:{program:function()"program"}}));
911 assertGlobalStmt("throw 42", 1, { throwStatement: function() 1 });
912 assertGlobalStmt("for (;;);", 2, { forStatement: function() 2 });
913 assertGlobalStmt("for (x in y);", 3, { forInStatement: function() 3 });
914 assertGlobalStmt("{ }", 4, { blockStatement: function() 4 });
915 assertGlobalStmt("foo: { }", 5, { labeledStatement: function() 5 });
916 assertGlobalStmt("with (o) { }", 6, { withStatement: function() 6 });
917 assertGlobalStmt("while (x) { }", 7, { whileStatement: function() 7 });
918 assertGlobalStmt("do { } while(false);", 8, { doWhileStatement: function() 8 });
919 assertGlobalStmt("switch (x) { }", 9, { switchStatement: function() 9 });
920 assertGlobalStmt("try { } catch(e) { }", 10, { tryStatement: function() 10 });
921 assertGlobalStmt(";", 11, { emptyStatement: function() 11 });
922 assertGlobalStmt("debugger;", 12, { debuggerStatement: function() 12 });
923 assertGlobalStmt("42;", 13, { expressionStatement: function() 13 });
924 assertGlobalStmt("for (;;) break", forStmt(null, null, null, 14), { breakStatement: function() 14 });
925 assertGlobalStmt("for (;;) continue", forStmt(null, null, null, 15), { continueStatement: function() 15 });
927 assertBlockDecl("var x", "var", { variableDeclaration: function(kind) kind });
928 assertBlockDecl("let x", "let", { variableDeclaration: function(kind) kind });
929 assertBlockDecl("const x", "const", { variableDeclaration: function(kind) kind });
930 assertBlockDecl("function f() { }", "function", { functionDeclaration: function() "function" });
932 assertGlobalExpr("(x,y,z)", 1, { sequenceExpression: function() 1 });
933 assertGlobalExpr("(x ? y : z)", 2, { conditionalExpression: function() 2 });
934 assertGlobalExpr("x + y", 3, { binaryExpression: function() 3 });
935 assertGlobalExpr("delete x", 4, { unaryExpression: function() 4 });
936 assertGlobalExpr("x = y", 5, { assignmentExpression: function() 5 });
937 assertGlobalExpr("x || y", 6, { logicalExpression: function() 6 });
938 assertGlobalExpr("x++", 7, { updateExpression: function() 7 });
939 assertGlobalExpr("new x", 8, { newExpression: function() 8 });
940 assertGlobalExpr("x()", 9, { callExpression: function() 9 });
941 assertGlobalExpr("x.y", 10, { memberExpression: function() 10 });
942 assertGlobalExpr("(function() { })", 11, { functionExpression: function() 11 });
943 assertGlobalExpr("[1,2,3]", 12, { arrayExpression: function() 12 });
944 assertGlobalExpr("({ x: y })", 13, { objectExpression: function() 13 });
945 assertGlobalExpr("this", 14, { thisExpression: function() 14 });
946 assertGlobalExpr("#1={ }", 15, { graphExpression: function() 15 });
947 assertGlobalExpr("#1={ self: #1# }", graphExpr(1, objExpr([{ key: ident("self"), value: 16 }])), { graphIndexExpression: function() 16 });
948 assertGlobalExpr("[x for (x in y)]", 17, { comprehensionExpression: function() 17 });
949 assertGlobalExpr("(x for (x in y))", 18, { generatorExpression: function() 18 });
950 assertGlobalExpr("(function() { yield 42 })", genFunExpr(null, [], blockStmt([exprStmt(19)])), { yieldExpression: function() 19 });
951 assertGlobalExpr("(let (x) x)", 20, { letExpression: function() 20 });
953 assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: function() 1 });
954 assertGlobalStmt("try { } catch (e) { }", tryStmt(blockStmt([]), 2, null), { catchClause: function() 2 });
955 assertGlobalStmt("try { } catch (e if e instanceof A) { } catch (e if e instanceof B) { }",
956 tryStmt(blockStmt([]), [2, 2], null),
957 { catchClause: function() 2 });
958 assertGlobalExpr("[x for (y in z) for (x in y)]", compExpr(ident("x"), [3, 3], null), { comprehensionBlock: function() 3 });
960 assertGlobalExpr("({ x: y } = z)", aExpr("=", 1, ident("z")), { objectPattern: function() 1 });
961 assertGlobalExpr("({ x: y } = z)", aExpr("=", objPatt([2]), ident("z")), { propertyPattern: function() 2 });
962 assertGlobalExpr("[ x ] = y", aExpr("=", 3, ident("y")), { arrayPattern: function() 3 });
964 assertGlobalExpr("({a:x::y}) = foo", aExpr("=", singletonObjPatt("a", 1), ident("foo")), { xmlQualifiedIdentifier: function() 1 });
965 assertGlobalExpr("({a:function::x}) = foo", aExpr("=", singletonObjPatt("a", 2), ident("foo")), { xmlFunctionQualifiedIdentifier: function() 2 });
966 assertGlobalExpr("({a:@x}) = foo", aExpr("=", singletonObjPatt("a", 3), ident("foo")), { xmlAttributeSelector: function() 3 });
967 assertGlobalExpr("({a:x.*}) = foo", aExpr("=", singletonObjPatt("a", memExpr(ident("x"), 4)), ident("foo")), { xmlAnyName: function() 4 });
969 assertGlobalExpr("(<x> </x>)()", callExpr(xmlElt([5, xmlText(" "), xmlEndTag([xmlName("x")])]), []), { xmlStartTag: function() 5 });
970 assertGlobalExpr("(<x> </x>)()", callExpr(xmlElt([xmlStartTag([6]), xmlText(" "), xmlEndTag([6])]), []), { xmlName: function() 6 });
971 assertGlobalExpr("(<x> </x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]), 7, xmlEndTag([xmlName("x")])]), []), { xmlText: function() 7 });
972 assertGlobalExpr("(<x> </x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]), xmlText(" "), 8]), []), { xmlEndTag: function() 8 });
973 assertGlobalExpr("(<x><![CDATA[hello, world]]></x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]), 9, xmlEndTag([xmlName("x")])]), []), { xmlCdata: function() 9 });
974 assertGlobalExpr("(<x><!-- hello, world --></x>)()", callExpr(xmlElt([xmlStartTag([xmlName("x")]), 10, xmlEndTag([xmlName("x")])]), []), { xmlComment: function() 10 });
977 // Ensure that exceptions thrown by builder methods propagate.
980 Reflect.parse("42", { builder: { program: function() { throw "expected" } } });
981 } catch (e if e === "expected") {
985 throw new Error("builder exception not propagated");
988 // A simple proof-of-concept that the builder API can be used to generate other
989 // formats, such as JsonMLAst:
991 // http://code.google.com/p/es-lab/wiki/JsonMLASTFormat
993 // It's incomplete (e.g., it doesn't convert source-location information and
994 // doesn't use all the direct-eval rules), but I think it proves the point.
996 var JsonMLAst = (function() {
998 throw new SyntaxError("node type not supported");
1001 function isDirectEval(expr) {
1002 // an approximation to the actual rules. you get the idea
1003 return (expr[0] === "IdExpr" && expr[1].name === "eval");
1006 function functionNode(type) {
1007 return function(id, args, body, isGenerator, isExpression) {
1009 body = ["ReturnStmt", {}, body];
1014 // Patch up the argument node types: s/IdExpr/IdPatt/g
1015 for (var i = 0; i < args.length; i++) {
1016 args[i][0] = "IdPatt";
1019 args.unshift("ParamDecl", {});
1021 return [type, {}, id, args, body];
1026 program: function(stmts) {
1027 stmts.unshift("Program", {});
1030 identifier: function(name) {
1031 return ["IdExpr", { name: name }];
1033 literal: function(val) {
1034 return ["LiteralExpr", { value: val }];
1036 expressionStatement: function(expr) expr,
1037 conditionalExpression: function(test, cons, alt) {
1038 return ["ConditionalExpr", {}, test, cons, alt];
1040 unaryExpression: function(op, expr) {
1041 return ["UnaryExpr", {op: op}, expr];
1043 binaryExpression: function(op, left, right) {
1044 return ["BinaryExpr", {op: op}, left, right];
1046 property: function(kind, key, val) {
1047 return [kind === "init"
1052 {name: key[1].name}, val];
1054 functionDeclaration: functionNode("FunctionDecl"),
1055 variableDeclaration: function(kind, elts) {
1056 if (kind === "let" || kind === "const")
1057 throw new SyntaxError("let and const not supported");
1058 elts.unshift("VarDecl", {});
1061 variableDeclarator: function(id, init) {
1065 return ["InitPatt", {}, id, init];
1067 sequenceExpression: function(exprs) {
1068 var length = exprs.length;
1069 var result = ["BinaryExpr", {op:","}, exprs[exprs.length - 2], exprs[exprs.length - 1]];
1070 for (var i = exprs.length - 3; i >= 0; i--) {
1071 result = ["BinaryExpr", {op:","}, exprs[i], result];
1075 assignmentExpression: function(op, lhs, expr) {
1076 return ["AssignExpr", {op: op}, lhs, expr];
1078 logicalExpression: function(op, left, right) {
1079 return [op === "&&" ? "LogicalAndExpr" : "LogicalOrExpr", {}, left, right];
1081 updateExpression: function(expr, op, isPrefix) {
1082 return ["CountExpr", {isPrefix:isPrefix, op:op}, expr];
1084 newExpression: function(callee, args) {
1085 args.unshift("NewExpr", {}, callee);
1088 callExpression: function(callee, args) {
1089 args.unshift(isDirectEval(callee) ? "EvalExpr" : "CallExpr", {}, callee);
1092 memberExpression: function(isComputed, expr, member) {
1093 return ["MemberExpr", {}, expr, isComputed ? member : ["LiteralExpr", {type: "string", value: member[1].name}]];
1095 functionExpression: functionNode("FunctionExpr"),
1096 arrayExpression: function(elts) {
1097 for (var i = 0; i < elts.length; i++) {
1099 elts[i] = ["Empty"];
1101 elts.unshift("ArrayExpr", {});
1104 objectExpression: function(props) {
1105 props.unshift("ObjectExpr", {});
1108 thisExpression: function() {
1109 return ["ThisExpr", {}];
1112 graphExpression: reject,
1113 graphIndexExpression: reject,
1114 comprehensionExpression: reject,
1115 generatorExpression: reject,
1116 yieldExpression: reject,
1117 letExpression: reject,
1119 emptyStatement: function() ["EmptyStmt", {}],
1120 blockStatement: function(stmts) {
1121 stmts.unshift("BlockStmt", {});
1124 labeledStatement: function(lab, stmt) {
1125 return ["LabelledStmt", {label: lab}, stmt];
1127 ifStatement: function(test, cons, alt) {
1128 return ["IfStmt", {}, test, cons, alt || ["EmptyStmt", {}]];
1130 switchStatement: function(test, clauses, isLexical) {
1131 clauses.unshift("SwitchStmt", {}, test);
1134 whileStatement: function(expr, stmt) {
1135 return ["WhileStmt", {}, expr, stmt];
1137 doWhileStatement: function(stmt, expr) {
1138 return ["DoWhileStmt", {}, stmt, expr];
1140 forStatement: function(init, test, update, body) {
1141 return ["ForStmt", {}, init || ["Empty"], test || ["Empty"], update || ["Empty"], body];
1143 forInStatement: function(lhs, rhs, body) {
1144 return ["ForInStmt", {}, lhs, rhs, body];
1146 breakStatement: function(lab) {
1147 return lab ? ["BreakStmt", {}, lab] : ["BreakStmt", {}];
1149 continueStatement: function(lab) {
1150 return lab ? ["ContinueStmt", {}, lab] : ["ContinueStmt", {}];
1152 withStatement: function(expr, stmt) {
1153 return ["WithStmt", {}, expr, stmt];
1155 returnStatement: function(expr) {
1156 return expr ? ["ReturnStmt", {}, expr] : ["ReturnStmt", {}];
1158 tryStatement: function(body, catches, fin) {
1159 if (catches.length > 1)
1160 throw new SyntaxError("multiple catch clauses not supported");
1161 var node = ["TryStmt", body, catches[0] || ["Empty"]];
1166 throwStatement: function(expr) {
1167 return ["ThrowStmt", {}, expr];
1169 debuggerStatement: function() ["DebuggerStmt", {}],
1170 letStatement: reject,
1171 switchCase: function(expr, stmts) {
1173 stmts.unshift("SwitchCase", {}, expr);
1175 stmts.unshift("DefaultCase", {});
1178 catchClause: function(param, guard, body) {
1180 throw new SyntaxError("catch guards not supported");
1181 param[0] = "IdPatt";
1182 return ["CatchClause", {}, param, body];
1184 comprehensionBlock: reject,
1186 arrayPattern: reject,
1187 objectPattern: reject,
1188 propertyPattern: reject,
1191 xmlAttributeSelector: reject,
1193 xmlFilterExpression: reject,
1194 xmlDefaultDeclaration: reject,
1195 xmlQualifiedIdentifier: reject,
1196 xmlFunctionQualifiedIdentifier: reject,
1200 xmlStartTag: reject,
1202 xmlPointTag: reject,
1204 xmlAttribute: reject,
1207 xmlProcessingInstruction: reject
1211 Pattern(["Program", {},
1212 ["BinaryExpr", {op: "+"},
1213 ["LiteralExpr", {value: 2}],
1214 ["BinaryExpr", {op: "*"},
1215 ["UnaryExpr", {op: "-"}, ["IdExpr", {name: "x"}]],
1216 ["IdExpr", {name: "y"}]]]]).match(Reflect.parse("2 + (-x * y)", {loc: false, builder: JsonMLAst}));
1218 reportCompare(true, true);