diff options
Diffstat (limited to 'js/src/tests/non262/reflect-parse')
32 files changed, 2517 insertions, 0 deletions
diff --git a/js/src/tests/non262/reflect-parse/Match.js b/js/src/tests/non262/reflect-parse/Match.js new file mode 100644 index 0000000000..2a14d8a315 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/Match.js @@ -0,0 +1,242 @@ +// |reftest| skip + +// A little pattern-matching library. +var Match = + +(function() { + + function Pattern(template) { + // act like a constructor even as a function + if (!(this instanceof Pattern)) + return new Pattern(template); + + this.template = template; + } + + Pattern.prototype = { + match: function(act) { + return match(act, this.template); + }, + + matches: function(act) { + try { + return this.match(act); + } + catch (e) { + if (!(e instanceof MatchError)) + throw e; + return false; + } + }, + + assert: function(act, message) { + try { + return this.match(act); + } + catch (e) { + if (!(e instanceof MatchError)) + throw e; + throw new Error((message || "failed match") + ": " + e.message); + } + }, + + toString: () => "[object Pattern]" + }; + + Pattern.ANY = new Pattern; + Pattern.ANY.template = Pattern.ANY; + + Pattern.NUMBER = new Pattern; + Pattern.NUMBER.match = function (act) { + if (typeof act !== 'number') { + throw new MatchError("Expected number, got: " + quote(act)); + } + } + + Pattern.NATURAL = new Pattern + Pattern.NATURAL.match = function (act) { + if (typeof act !== 'number' || act !== Math.floor(act) || act < 0) { + throw new MatchError("Expected natural number, got: " + quote(act)); + } + } + + class ObjectWithExactly extends Pattern { + constructor(template) { + super(template); + } + + match(actual) { + return matchObjectWithExactly(actual, this.template) + } + } + + Pattern.OBJECT_WITH_EXACTLY = function (template) { + return new ObjectWithExactly(template); + } + + var quote = JSON.stringify; + + class MatchError extends Error { + toString() { + return "match error: " + this.message; + } + }; + + Pattern.MatchError = MatchError; + + function isAtom(x) { + return (typeof x === "number") || + (typeof x === "string") || + (typeof x === "boolean") || + (x === null) || + (x === undefined) || + (typeof x === "object" && x instanceof RegExp) || + (typeof x === "bigint"); + } + + function isObject(x) { + return (x !== null) && (typeof x === "object"); + } + + function isFunction(x) { + return typeof x === "function"; + } + + function isArrayLike(x) { + return isObject(x) && ("length" in x); + } + + function matchAtom(act, exp) { + if ((typeof exp) === "number" && isNaN(exp)) { + if ((typeof act) !== "number" || !isNaN(act)) + throw new MatchError("expected NaN, got: " + quote(act)); + return true; + } + + if (exp === null) { + if (act !== null) + throw new MatchError("expected null, got: " + quote(act)); + return true; + } + + if (exp instanceof RegExp) { + if (!(act instanceof RegExp) || exp.source !== act.source) + throw new MatchError("expected " + quote(exp) + ", got: " + quote(act)); + return true; + } + + switch (typeof exp) { + case "string": + case "undefined": + if (act !== exp) + throw new MatchError("expected " + quote(exp) + ", got " + quote(act)); + return true; + case "boolean": + case "number": + case "bigint": + if (exp !== act) + throw new MatchError("expected " + exp + ", got " + quote(act)); + return true; + } + + throw new Error("bad pattern: " + JSON.stringify(exp)); + } + + // Match an object having at least the expected properties. + function matchObjectWithAtLeast(act, exp) { + if (!isObject(act)) + throw new MatchError("expected object, got " + quote(act)); + + for (var key in exp) { + if (!(key in act)) + throw new MatchError("expected property " + quote(key) + " not found in " + quote(act)); + try { + match(act[key], exp[key]); + } catch (inner) { + if (!(inner instanceof MatchError)) { + throw inner; + } + inner.message = `matching property "${String(key)}":\n${inner.message}`; + throw inner; + } + } + + return true; + } + + // Match an object having all the expected properties and no more. + function matchObjectWithExactly(act, exp) { + matchObjectWithAtLeast(act, exp); + + for (var key in act) { + if (!(key in exp)) { + throw new MatchError("unexpected property " + quote(key)); + } + } + + return true; + } + + function matchFunction(act, exp) { + if (!isFunction(act)) + throw new MatchError("expected function, got " + quote(act)); + + if (act !== exp) + throw new MatchError("expected function: " + exp + + "\nbut got different function: " + act); + } + + function matchArray(act, exp) { + if (!isObject(act) || !("length" in act)) + throw new MatchError("expected array-like object, got " + quote(act)); + + var length = exp.length; + if (act.length !== exp.length) + throw new MatchError("expected array-like object of length " + length + ", got " + quote(act)); + + for (var i = 0; i < length; i++) { + if (i in exp) { + if (!(i in act)) + throw new MatchError("expected array property " + i + " not found in " + quote(act)); + try { + match(act[i], exp[i]); + } catch (inner) { + if (!(inner instanceof MatchError)) { + throw inner; + } + inner.message = `matching array element [${i}]:\n${inner.message}`; + throw inner; + } + } + } + + return true; + } + + function match(act, exp) { + if (exp === Pattern.ANY) + return true; + + if (exp instanceof Pattern) + return exp.match(act); + + if (isAtom(exp)) + return matchAtom(act, exp); + + if (isArrayLike(exp)) + return matchArray(act, exp); + + if (isFunction(exp)) + return matchFunction(act, exp); + + if (isObject(exp)) + return matchObjectWithAtLeast(act, exp); + + throw new Error("bad pattern: " + JSON.stringify(exp)); + } + + return { Pattern: Pattern, + MatchError: MatchError }; + +})(); + diff --git a/js/src/tests/non262/reflect-parse/PatternAsserts.js b/js/src/tests/non262/reflect-parse/PatternAsserts.js new file mode 100644 index 0000000000..1be20d2812 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/PatternAsserts.js @@ -0,0 +1,95 @@ +// |reftest| skip + +loadRelativeToScript('PatternBuilders.js'); + +function localSrc(src) { + return "(function(){ " + src + " })"; +} +function localPatt(patt) { + return program([exprStmt(funExpr(null, [], blockStmt([patt])))]); +} +function blockSrc(src) { + return "(function(){ { " + src + " } })"; +} +function blockPatt(patt) { + return program([exprStmt(funExpr(null, [], blockStmt([blockStmt([patt])])))]); +} + +function assertBlockStmt(src, patt) { + blockPatt(patt).assert(Reflect.parse(blockSrc(src))); +} + +function assertBlockExpr(src, patt) { + assertBlockStmt(src, exprStmt(patt)); +} + +function assertBlockDecl(src, patt, builder) { + blockPatt(patt).assert(Reflect.parse(blockSrc(src), {builder: builder})); +} + +function assertLocalStmt(src, patt) { + localPatt(patt).assert(Reflect.parse(localSrc(src))); +} + +function assertLocalExpr(src, patt) { + assertLocalStmt(src, exprStmt(patt)); +} + +function assertLocalDecl(src, patt) { + localPatt(patt).assert(Reflect.parse(localSrc(src))); +} + +function assertGlobalStmt(src, patt, builder) { + program([patt]).assert(Reflect.parse(src, {builder: builder})); +} + +function assertStringExpr(src, patt) { + program([exprStmt(patt)]).assert(Reflect.parse(src)); +} + +function assertGlobalExpr(src, patt, builder) { + program([exprStmt(patt)]).assert(Reflect.parse(src, {builder: builder})); + //assertStmt(src, exprStmt(patt)); +} + +function assertGlobalDecl(src, patt) { + program([patt]).assert(Reflect.parse(src)); +} + +function assertProg(src, patt) { + program(patt).assert(Reflect.parse(src)); +} + +function assertStmt(src, patt) { + assertLocalStmt(src, patt); + assertGlobalStmt(src, patt); + assertBlockStmt(src, patt); +} + +function assertInFunctionExpr(src, patt) { + assertLocalExpr(src, patt); + assertBlockExpr(src, patt); +} + +function assertExpr(src, patt) { + assertLocalExpr(src, patt); + assertGlobalExpr(src, patt); + assertBlockExpr(src, patt); +} + +function assertDecl(src, patt) { + assertLocalDecl(src, patt); + assertGlobalDecl(src, patt); + assertBlockDecl(src, patt); +} + +function assertError(src, errorType) { + try { + Reflect.parse(src); + } catch (expected) { + if (!(expected instanceof errorType)) + throw expected; + return; + } + throw new Error("expected " + errorType.name + " for " + JSON.stringify(src)); +} diff --git a/js/src/tests/non262/reflect-parse/PatternBuilders.js b/js/src/tests/non262/reflect-parse/PatternBuilders.js new file mode 100644 index 0000000000..e1ad9c046f --- /dev/null +++ b/js/src/tests/non262/reflect-parse/PatternBuilders.js @@ -0,0 +1,287 @@ +// |reftest| skip + +loadRelativeToScript('Match.js'); + +var { Pattern, MatchError } = Match; + +function program(elts) { + return Pattern({ type: "Program", body: elts }); +} +function exprStmt(expr) { + return Pattern({ type: "ExpressionStatement", expression: expr }); +} +function throwStmt(expr) { + return Pattern({ type: "ThrowStatement", argument: expr }); +} +function returnStmt(expr) { + return Pattern({ type: "ReturnStatement", argument: expr }); +} +function yieldExpr(expr) { + return Pattern({ type: "YieldExpression", argument: expr }); +} +function lit(val) { + return Pattern({ type: "Literal", value: val }); +} +function comp(name) { + return Pattern({ type: "ComputedName", name: name }); +} +function spread(val) { + return Pattern({ type: "SpreadExpression", expression: val}); +} +function optExpr(val) { + return Pattern({ type: "OptionalExpression", expression: val}); +} +function delOptExpr(val) { + return Pattern({ type: "DeleteOptionalExpression", expression: val}); +} +var thisExpr = Pattern({ type: "ThisExpression" }); +function funDecl(id, params, body, defaults=[], rest=null) { + return Pattern({ type: "FunctionDeclaration", + id: id, + params: params, + defaults: defaults, + body: body, + rest: rest, + generator: false }); +} +function genFunDecl(style, id, params, body) { + return Pattern({ type: "FunctionDeclaration", + id: id, + params: params, + defaults: [], + body: body, + generator: true, + style: style }); +} +function asyncFunDecl(id, params, body) { + return Pattern({ type: "FunctionDeclaration", + id: id, + params: params, + defaults: [], + body: body, + generator: false, + async: true }); +} +function varDecl(decls) { + return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" }); +} +function letDecl(decls) { + return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "let" }); +} +function constDecl(decls) { + return Pattern({ type: "VariableDeclaration", declarations: decls, kind: "const" }); +} +function ident(name) { + return Pattern({ type: "Identifier", name: name }); +} +function dotExpr(obj, id) { + return Pattern({ type: "MemberExpression", computed: false, object: obj, property: id }); +} +function memExpr(obj, id) { + return Pattern({ type: "MemberExpression", computed: true, object: obj, property: id }); +} +function optDotExpr(obj, id) { + return Pattern({ type: "OptionalMemberExpression", computed: false, object: obj, property: id }); +} +function optMemExpr(obj, id) { + return Pattern({ type: "OptionalMemberExpression", computed: true, object: obj, property: id }); +} +function forStmt(init, test, update, body) { + return Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body }); +} +function forOfStmt(lhs, rhs, body) { + return Pattern({ type: "ForOfStatement", left: lhs, right: rhs, body: body }); +} +function forInStmt(lhs, rhs, body) { + return Pattern({ type: "ForInStatement", left: lhs, right: rhs, body: body }); +} +function breakStmt(lab) { + return Pattern({ type: "BreakStatement", label: lab }); +} +function continueStmt(lab) { + return Pattern({ type: "ContinueStatement", label: lab }); +} +function blockStmt(body) { + return Pattern({ type: "BlockStatement", body: body }); +} +function literal(val) { + return Pattern({ type: "Literal", value: val }); +} +var emptyStmt = Pattern({ type: "EmptyStatement" }); +function ifStmt(test, cons, alt) { + return Pattern({ type: "IfStatement", test: test, alternate: alt, consequent: cons }); +} +function labStmt(lab, stmt) { + return Pattern({ type: "LabeledStatement", label: lab, body: stmt }); +} +function withStmt(obj, stmt) { + return Pattern({ type: "WithStatement", object: obj, body: stmt }); +} +function whileStmt(test, stmt) { + return Pattern({ type: "WhileStatement", test: test, body: stmt }); +} +function doStmt(stmt, test) { + return Pattern({ type: "DoWhileStatement", test: test, body: stmt }); +} +function switchStmt(disc, cases) { + return Pattern({ type: "SwitchStatement", discriminant: disc, cases: cases }); +} +function caseClause(test, stmts) { + return Pattern({ type: "SwitchCase", test: test, consequent: stmts }); +} +function defaultClause(stmts) { + return Pattern({ type: "SwitchCase", test: null, consequent: stmts }); +} +function catchClause(id, body) { + return Pattern({ type: "CatchClause", param: id, body: body }); +} +function tryStmt(body, handler, fin) { + return Pattern({ type: "TryStatement", block: body, handler: handler, finalizer: fin }); +} + +function superProp(id) { + return dotExpr(Pattern({ type: "Super" }), id); +} +function superElem(id) { + return memExpr(Pattern({ type: "Super" }), id); +} + +function classStmt(id, heritage, body) { + return Pattern({ type: "ClassStatement", + id: id, + superClass: heritage, + body: body}); +} +function classExpr(id, heritage, body) { + return Pattern({ type: "ClassExpression", + id: id, + superClass: heritage, + body: body}); +} +function classMethod(id, body, kind, static) { + return Pattern({ type: "ClassMethod", + name: id, + body: body, + kind: kind, + static: static }); +} +function classField(id, init) { + return Pattern({ type: "ClassField", + name: id, + init: init }); +} + +function funExpr(id, args, body, gen) { + return Pattern({ type: "FunctionExpression", + id: id, + params: args, + body: body, + generator: false }); +} +function genFunExpr(style, id, args, body) { + return Pattern({ type: "FunctionExpression", + id: id, + params: args, + body: body, + generator: true, + style: style }); +} +function asyncFunExpr(id, args, body) { + return Pattern({ type: "FunctionExpression", + id: id, + params: args, + body: body, + generator: false, + async: true }); +} +function arrowExpr(args, body) { + return Pattern({ type: "ArrowFunctionExpression", + params: args, + body: body }); +} +function asyncArrowExpr(isExpression, args, body) { + return Pattern({ type: "ArrowFunctionExpression", + params: args, + body: body, + generator: false, + async: true, + expression: isExpression }); +} + +function metaProperty(meta, property) { + return Pattern({ type: "MetaProperty", + meta: meta, + property: property }); +} +function newTarget() { + return metaProperty(ident("new"), ident("target")); +} + +function unExpr(op, arg) { + return Pattern({ type: "UnaryExpression", operator: op, argument: arg }); +} +function binExpr(op, left, right) { + return Pattern({ type: "BinaryExpression", operator: op, left: left, right: right }); +} +function aExpr(op, left, right) { + return Pattern({ type: "AssignmentExpression", operator: op, left: left, right: right }); +} +function updExpr(op, arg, prefix) { + return Pattern({ type: "UpdateExpression", operator: op, argument: arg, prefix: prefix }); +} +function logExpr(op, left, right) { + return Pattern({ type: "LogicalExpression", operator: op, left: left, right: right }); +} + +function condExpr(test, cons, alt) { + return Pattern({ type: "ConditionalExpression", test: test, consequent: cons, alternate: alt }); +} +function seqExpr(exprs) { + return Pattern({ type: "SequenceExpression", expressions: exprs }); +} +function newExpr(callee, args) { + return Pattern({ type: "NewExpression", callee: callee, arguments: args }); +} +function callExpr(callee, args) { + return Pattern({ type: "CallExpression", callee: callee, arguments: args }); +} +function optCallExpr(callee, args) { + return Pattern({ type: "OptionalCallExpression", callee: callee, arguments: args }); +} +function superCallExpr(args) { + return callExpr({ type: "Super" }, args); +} +function arrExpr(elts) { + return Pattern({ type: "ArrayExpression", elements: elts }); +} +function objExpr(elts) { + return Pattern({ type: "ObjectExpression", properties: elts }); +} +function computedName(elts) { + return Pattern({ type: "ComputedName", name: elts }); +} +function templateLit(elts) { + return Pattern({ type: "TemplateLiteral", elements: elts }); +} +function taggedTemplate(tagPart, templatePart) { + return Pattern({ type: "TaggedTemplate", callee: tagPart, arguments : templatePart }); +} +function template(raw, cooked, ...args) { + return Pattern([{ type: "CallSiteObject", raw: raw, cooked: cooked}, ...args]); +} + +function arrPatt(elts) { + return Pattern({ type: "ArrayPattern", elements: elts }); +} +function objPatt(elts) { + return Pattern({ type: "ObjectPattern", properties: elts }); +} + +function assignElem(target, defaultExpr = null, targetIdent = typeof target == 'string' ? ident(target) : target) { + return defaultExpr ? aExpr('=', targetIdent, defaultExpr) : targetIdent; +} +function assignProp(property, target, defaultExpr = null, shorthand = !target, targetProp = target || ident(property)) { + return Pattern({ + type: "Property", key: ident(property), shorthand, + value: defaultExpr ? aExpr('=', targetProp, defaultExpr) : targetProp }); +} diff --git a/js/src/tests/non262/reflect-parse/alternateBuilder.js b/js/src/tests/non262/reflect-parse/alternateBuilder.js new file mode 100644 index 0000000000..4d869a7f7e --- /dev/null +++ b/js/src/tests/non262/reflect-parse/alternateBuilder.js @@ -0,0 +1,215 @@ +// |reftest| skip-if(!xulRuntime.shell) +// A simple proof-of-concept that the builder API can be used to generate other +// formats, such as JsonMLAst: +// +// http://code.google.com/p/es-lab/wiki/JsonMLASTFormat +// +// It's incomplete (e.g., it doesn't convert source-location information and +// doesn't use all the direct-eval rules), but I think it proves the point. + +function test() { + +var JsonMLAst = (function() { +function reject() { + throw new SyntaxError("node type not supported"); +} + +function isDirectEval(expr) { + // an approximation to the actual rules. you get the idea + return (expr[0] === "IdExpr" && expr[1].name === "eval"); +} + +function functionNode(type) { + return function(id, args, body, isGenerator, isExpression) { + if (isExpression) + body = ["ReturnStmt", {}, body]; + + if (!id) + id = ["Empty"]; + + // Patch up the argument node types: s/IdExpr/IdPatt/g + for (var i = 0; i < args.length; i++) { + args[i][0] = "IdPatt"; + } + + args.unshift("ParamDecl", {}); + + return [type, {}, id, args, body]; + } +} + +return { + program: function(stmts) { + stmts.unshift("Program", {}); + return stmts; + }, + identifier: function(name) { + return ["IdExpr", { name: name }]; + }, + literal: function(val) { + return ["LiteralExpr", { value: val }]; + }, + expressionStatement: expr => expr, + conditionalExpression: function(test, cons, alt) { + return ["ConditionalExpr", {}, test, cons, alt]; + }, + unaryExpression: function(op, expr) { + return ["UnaryExpr", {op: op}, expr]; + }, + binaryExpression: function(op, left, right) { + return ["BinaryExpr", {op: op}, left, right]; + }, + property: function(kind, key, val) { + return [kind === "init" + ? "DataProp" + : kind === "get" + ? "GetterProp" + : "SetterProp", + {name: key[1].name}, val]; + }, + functionDeclaration: functionNode("FunctionDecl"), + variableDeclaration: function(kind, elts) { + if (kind === "let" || kind === "const") + throw new SyntaxError("let and const not supported"); + elts.unshift("VarDecl", {}); + return elts; + }, + variableDeclarator: function(id, init) { + id[0] = "IdPatt"; + if (!init) + return id; + return ["InitPatt", {}, id, init]; + }, + sequenceExpression: function(exprs) { + var length = exprs.length; + var result = ["BinaryExpr", {op:","}, exprs[exprs.length - 2], exprs[exprs.length - 1]]; + for (var i = exprs.length - 3; i >= 0; i--) { + result = ["BinaryExpr", {op:","}, exprs[i], result]; + } + return result; + }, + assignmentExpression: function(op, lhs, expr) { + return ["AssignExpr", {op: op}, lhs, expr]; + }, + logicalExpression: function(op, left, right) { + return [op === "&&" ? "LogicalAndExpr" : "LogicalOrExpr", {}, left, right]; + }, + updateExpression: function(expr, op, isPrefix) { + return ["CountExpr", {isPrefix:isPrefix, op:op}, expr]; + }, + newExpression: function(callee, args) { + args.unshift("NewExpr", {}, callee); + return args; + }, + callExpression: function(callee, args) { + args.unshift(isDirectEval(callee) ? "EvalExpr" : "CallExpr", {}, callee); + return args; + }, + memberExpression: function(isComputed, expr, member) { + return ["MemberExpr", {}, expr, isComputed ? member : ["LiteralExpr", {type: "string", value: member[1].name}]]; + }, + functionExpression: functionNode("FunctionExpr"), + arrayExpression: function(elts) { + for (var i = 0; i < elts.length; i++) { + if (!elts[i]) + elts[i] = ["Empty"]; + } + elts.unshift("ArrayExpr", {}); + return elts; + }, + objectExpression: function(props) { + props.unshift("ObjectExpr", {}); + return props; + }, + thisExpression: function() { + return ["ThisExpr", {}]; + }, + templateLiteral: function(elts) { + for (var i = 0; i < elts.length; i++) { + if (!elts[i]) + elts[i] = ["Empty"]; + } + elts.unshift("TemplateLit", {}); + return elts; + }, + + yieldExpression: reject, + + emptyStatement: () => ["EmptyStmt", {}], + blockStatement: function(stmts) { + stmts.unshift("BlockStmt", {}); + return stmts; + }, + labeledStatement: function(lab, stmt) { + return ["LabelledStmt", {label: lab}, stmt]; + }, + ifStatement: function(test, cons, alt) { + return ["IfStmt", {}, test, cons, alt || ["EmptyStmt", {}]]; + }, + switchStatement: function(test, clauses, isLexical) { + clauses.unshift("SwitchStmt", {}, test); + return clauses; + }, + whileStatement: function(expr, stmt) { + return ["WhileStmt", {}, expr, stmt]; + }, + doWhileStatement: function(stmt, expr) { + return ["DoWhileStmt", {}, stmt, expr]; + }, + forStatement: function(init, test, update, body) { + return ["ForStmt", {}, init || ["Empty"], test || ["Empty"], update || ["Empty"], body]; + }, + forInStatement: function(lhs, rhs, body) { + return ["ForInStmt", {}, lhs, rhs, body]; + }, + breakStatement: function(lab) { + return lab ? ["BreakStmt", {}, lab] : ["BreakStmt", {}]; + }, + continueStatement: function(lab) { + return lab ? ["ContinueStmt", {}, lab] : ["ContinueStmt", {}]; + }, + withStatement: function(expr, stmt) { + return ["WithStmt", {}, expr, stmt]; + }, + returnStatement: function(expr) { + return expr ? ["ReturnStmt", {}, expr] : ["ReturnStmt", {}]; + }, + tryStatement: function(body, handler, fin) { + var node = ["TryStmt", body, handler]; + if (fin) + node.push(fin); + return node; + }, + throwStatement: function(expr) { + return ["ThrowStmt", {}, expr]; + }, + debuggerStatement: () => ["DebuggerStmt", {}], + letStatement: reject, + switchCase: function(expr, stmts) { + if (expr) + stmts.unshift("SwitchCase", {}, expr); + else + stmts.unshift("DefaultCase", {}); + return stmts; + }, + catchClause: function(param, body) { + param[0] = "IdPatt"; + return ["CatchClause", {}, param, body]; + }, + + arrayPattern: reject, + objectPattern: reject, + propertyPattern: reject, +}; +})(); + +Pattern(["Program", {}, + ["BinaryExpr", {op: "+"}, + ["LiteralExpr", {value: 2}], + ["BinaryExpr", {op: "*"}, + ["UnaryExpr", {op: "-"}, ["IdExpr", {name: "x"}]], + ["IdExpr", {name: "y"}]]]]).match(Reflect.parse("2 + (-x * y)", {loc: false, builder: JsonMLAst})); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/async.js b/js/src/tests/non262/reflect-parse/async.js new file mode 100644 index 0000000000..355f0356c5 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/async.js @@ -0,0 +1,25 @@ +// |reftest| skip-if(!xulRuntime.shell) + +// async function declaration. +assertDecl("async function foo() {}", asyncFunDecl(ident("foo"), [], blockStmt([]))); + +// async function expression. +assertExpr("(async function() {})", asyncFunExpr(null, [], blockStmt([]))); +assertExpr("(async function foo() {})", asyncFunExpr(ident("foo"), [], blockStmt([]))); + +// async arrow. +assertExpr("async a => 1", asyncArrowExpr(true, [ident("a")], literal(1))); +assertExpr("async a => { 1 }", asyncArrowExpr(false, [ident("a")], blockStmt([exprStmt(literal(1))]))); +assertExpr("async a => { return 1 }", asyncArrowExpr(false, [ident("a")], blockStmt([returnStmt(literal(1))]))); + +// async method. +assertExpr("({ async foo() {} })", objExpr([{ key: ident("foo"), value: asyncFunExpr(ident("foo"), [], blockStmt([]))}])); + +assertStmt("class C { async foo() {} }", classStmt(ident("C"), null, [classMethod(ident("foo"), asyncFunExpr(ident("foo"), [], blockStmt([])), "method", false)])); +assertStmt("class C { static async foo() {} }", classStmt(ident("C"), null, [classMethod(ident("foo"), asyncFunExpr(ident("foo"), [], blockStmt([])), "method", true)])); + +// await expression. +assertDecl("async function foo() { await bar }", asyncFunDecl(ident("foo"), [], blockStmt([exprStmt(unExpr("await", ident("bar")))]))); + +if (typeof reportCompare === 'function') + reportCompare(true, true); diff --git a/js/src/tests/non262/reflect-parse/basicBuilder.js b/js/src/tests/non262/reflect-parse/basicBuilder.js new file mode 100644 index 0000000000..c724e2f7f5 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/basicBuilder.js @@ -0,0 +1,54 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { +// Builder tests + +Pattern("program").match(Reflect.parse("42", {builder:{program:() => "program"}})); + +assertGlobalStmt("throw 42", 1, { throwStatement: () => 1 }); +assertGlobalStmt("for (;;);", 2, { forStatement: () => 2 }); +assertGlobalStmt("for (x in y);", 3, { forInStatement: () => 3 }); +assertGlobalStmt("{ }", 4, { blockStatement: () => 4 }); +assertGlobalStmt("foo: { }", 5, { labeledStatement: () => 5 }); +assertGlobalStmt("with (o) { }", 6, { withStatement: () => 6 }); +assertGlobalStmt("while (x) { }", 7, { whileStatement: () => 7 }); +assertGlobalStmt("do { } while(false);", 8, { doWhileStatement: () => 8 }); +assertGlobalStmt("switch (x) { }", 9, { switchStatement: () => 9 }); +assertGlobalStmt("try { } catch(e) { }", 10, { tryStatement: () => 10 }); +assertGlobalStmt(";", 11, { emptyStatement: () => 11 }); +assertGlobalStmt("debugger;", 12, { debuggerStatement: () => 12 }); +assertGlobalStmt("42;", 13, { expressionStatement: () => 13 }); +assertGlobalStmt("for (;;) break", forStmt(null, null, null, 14), { breakStatement: () => 14 }); +assertGlobalStmt("for (;;) continue", forStmt(null, null, null, 15), { continueStatement: () => 15 }); + +assertBlockDecl("var x", "var", { variableDeclaration: kind => kind }); +assertBlockDecl("let x", "let", { variableDeclaration: kind => kind }); +assertBlockDecl("const x = undefined", "const", { variableDeclaration: kind => kind }); +assertBlockDecl("function f() { }", "function", { functionDeclaration: () => "function" }); + +assertGlobalExpr("(x,y,z)", 1, { sequenceExpression: () => 1 }); +assertGlobalExpr("(x ? y : z)", 2, { conditionalExpression: () => 2 }); +assertGlobalExpr("x + y", 3, { binaryExpression: () => 3 }); +assertGlobalExpr("delete x", 4, { unaryExpression: () => 4 }); +assertGlobalExpr("x = y", 5, { assignmentExpression: () => 5 }); +assertGlobalExpr("x || y", 6, { logicalExpression: () => 6 }); +assertGlobalExpr("x++", 7, { updateExpression: () => 7 }); +assertGlobalExpr("new x", 8, { newExpression: () => 8 }); +assertGlobalExpr("x()", 9, { callExpression: () => 9 }); +assertGlobalExpr("x.y", 10, { memberExpression: () => 10 }); +assertGlobalExpr("(function() { })", 11, { functionExpression: () => 11 }); +assertGlobalExpr("[1,2,3]", 12, { arrayExpression: () => 12 }); +assertGlobalExpr("({ x: y })", 13, { objectExpression: () => 13 }); +assertGlobalExpr("this", 14, { thisExpression: () => 14 }); +assertGlobalExpr("(function*() { yield 42 })", genFunExpr("es6", null, [], blockStmt([exprStmt(19)])), { yieldExpression: () => 19 }); + +assertGlobalStmt("switch (x) { case y: }", switchStmt(ident("x"), [1]), { switchCase: () => 1 }); +assertGlobalStmt("try { } catch (e) { }", 2, { tryStatement: (b, h, f) => h, catchClause: () => 2 }); +assertGlobalStmt("try { } catch (e) { }", tryStmt(blockStmt([]), 2, null), { catchClause: () => 2 }); + +assertGlobalExpr("({ x: y } = z)", aExpr("=", 1, ident("z")), { objectPattern: () => 1 }); +assertGlobalExpr("({ x: y } = z)", aExpr("=", objPatt([2]), ident("z")), { propertyPattern: () => 2 }); +assertGlobalExpr("[ x ] = y", aExpr("=", 3, ident("y")), { arrayPattern: () => 3 }); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/browser.js b/js/src/tests/non262/reflect-parse/browser.js new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/browser.js diff --git a/js/src/tests/non262/reflect-parse/builderExceptions.js b/js/src/tests/non262/reflect-parse/builderExceptions.js new file mode 100644 index 0000000000..d22ab473fe --- /dev/null +++ b/js/src/tests/non262/reflect-parse/builderExceptions.js @@ -0,0 +1,15 @@ +// |reftest| skip-if(!xulRuntime.shell) +// Ensure that exceptions thrown by builder methods propagate. +var thrown = false; +try { + Reflect.parse("42", { builder: { program: function() { throw "expected" } } }); +} catch (e) { + if (e !== "expected") + throw e; + thrown = true; +} +if (!thrown) + throw new Error("builder exception not propagated"); + +if (typeof reportCompare === 'function') + reportCompare(true, true); diff --git a/js/src/tests/non262/reflect-parse/class-fields.js b/js/src/tests/non262/reflect-parse/class-fields.js new file mode 100644 index 0000000000..aa6d09dbcf --- /dev/null +++ b/js/src/tests/non262/reflect-parse/class-fields.js @@ -0,0 +1,26 @@ +// |reftest| skip-if(!xulRuntime.shell||(function(){try{eval('c=class{x;}');return(false);}catch{return(true);}})()) +// Classes +function testClassFields() { + function constructor_(name) { + let body = blockStmt([]); + let method = funExpr(ident(name), [], body); + return classMethod(ident("constructor"), method, "method", false); + } + + let genConstructor = constructor_("C"); + + // TODO: Should genConstructor be present? + assertExpr("(class C { x = 2; })", classExpr(ident("C"), null, [classField(ident("x"), lit(2)), genConstructor])); + assertExpr("(class C { x = x; })", classExpr(ident("C"), null, [classField(ident("x"), ident("x")), genConstructor])) + assertExpr("(class C { x; })", classExpr(ident("C"), null, [classField(ident("x"), null), genConstructor])) + assertExpr("(class C { x; y = 2; })", classExpr(ident("C"), null, [classField(ident("x"), null), classField(ident("y"), lit(2)), genConstructor])) + assertExpr("(class C { x = 2; constructor(){} })", classExpr(ident("C"), null, [classField(ident("x"), lit(2)), genConstructor])) + + if (getRealmConfiguration().privateFields) { + assertExpr("(class C { #x = 2; })", classExpr(ident("C"), null, [classField(ident("#x"), lit(2)), genConstructor])); + assertExpr("(class C { #x; })", classExpr(ident("C"), null, [classField(ident("#x"), null), genConstructor])) + assertExpr("(class C { #x; #y = 2; })", classExpr(ident("C"), null, [classField(ident("#x"), null), classField(ident("#y"), lit(2)), genConstructor])) + } +} + +runtest(testClassFields); diff --git a/js/src/tests/non262/reflect-parse/classes.js b/js/src/tests/non262/reflect-parse/classes.js new file mode 100644 index 0000000000..609c0d1e10 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/classes.js @@ -0,0 +1,552 @@ +// |reftest| slow skip-if(!xulRuntime.shell) +// Classes +function testClasses() { + function methodFun(id, kind, generator, args, body = []) { + assertEq(generator && kind === "method", generator); + assertEq(typeof id === 'string' || id === null, true); + let methodName; + switch (kind) { + case "method": + methodName = typeof id === 'string' ? ident(id) : null; + break; + case "get": + case "set": + methodName = ident(`${kind} ${typeof id === 'string' ? id : ""}`); + break; + default: + methodName = null; + break; + } + return generator + ? genFunExpr("es6", methodName, args.map(ident), blockStmt(body)) + : funExpr(methodName, args.map(ident), blockStmt(body)); + } + + function simpleMethod(id, kind, generator, args=[], isStatic=false) { + return classMethod(ident(id), + methodFun(id, kind, generator, args), + kind, isStatic); + } + function ctorWithName(id, body = []) { + return classMethod(ident("constructor"), + methodFun(id, "method", false, [], body), + "method", false); + } + function emptyCPNMethod(id, isStatic) { + return classMethod(computedName(lit(id)), + funExpr(null, [], blockStmt([])), + "method", isStatic); + } + + function assertClassExpr(str, methods, heritage=null, name=null) { + let template = classExpr(name, heritage, methods); + assertExpr("(" + str + ")", template); + } + + // FunctionExpression of constructor has class name as its id. + // FIXME: Implement ES6 function "name" property semantics (bug 883377). + let ctorPlaceholder = {}; + function assertClass(str, methods, heritage=null, constructorBody=[]) { + let namelessStr = str.replace("NAME", ""); + let namedStr = str.replace("NAME", "Foo"); + let namedCtor = ctorWithName("Foo", constructorBody); + let namelessCtor = ctorWithName(null, constructorBody); + let namelessMethods = methods.map(x => x == ctorPlaceholder ? namelessCtor : x); + let namedMethods = methods.map(x => x == ctorPlaceholder ? namedCtor : x); + assertClassExpr(namelessStr, namelessMethods, heritage); + assertClassExpr(namedStr, namedMethods, heritage, ident("Foo")); + + let template = classStmt(ident("Foo"), heritage, namedMethods); + assertStmt(namedStr, template); + } + function assertNamedClassError(str, error) { + assertError(str, error); + assertError("(" + str + ")", error); + } + function assertClassError(str, error) { + assertNamedClassError(str, error); + assertError("(" + str.replace("NAME", "") + ")", error); + } + + /* Trivial classes */ + // Unnamed class statements are forbidden, but unnamed class expressions are + // just fine. + assertError("class { constructor() { } }", SyntaxError); + assertClass("class NAME { constructor() { } }", [ctorPlaceholder]); + + // A class name must actually be a name + assertNamedClassError("class x.y { constructor() {} }", SyntaxError); + assertNamedClassError("class [] { constructor() {} }", SyntaxError); + assertNamedClassError("class {x} { constructor() {} }", SyntaxError); + assertNamedClassError("class for { constructor() {} }", SyntaxError); + + // Allow methods and accessors + assertClass("class NAME { constructor() { } method() { } }", + [ctorPlaceholder, simpleMethod("method", "method", false)]); + + assertClass("class NAME { constructor() { } get method() { } }", + [ctorPlaceholder, simpleMethod("method", "get", false)]); + + assertClass("class NAME { constructor() { } set method(x) { } }", + [ctorPlaceholder, simpleMethod("method", "set", false, ["x"])]); + + /* Static */ + assertClass(`class NAME { + constructor() { }; + static method() { }; + static *methodGen() { }; + static get getter() { }; + static set setter(x) { } + }`, + [ctorPlaceholder, + simpleMethod("method", "method", false, [], true), + simpleMethod("methodGen", "method", true, [], true), + simpleMethod("getter", "get", false, [], true), + simpleMethod("setter", "set", false, ["x"], true)]); + + // It's not an error to have a method named static, static, or not. + assertClass("class NAME { constructor() { } static() { } }", + [ctorPlaceholder, simpleMethod("static", "method", false)]); + assertClass("class NAME { static static() { }; constructor() { } }", + [simpleMethod("static", "method", false, [], true), ctorPlaceholder]); + assertClass("class NAME { static get static() { }; constructor() { } }", + [simpleMethod("static", "get", false, [], true), ctorPlaceholder]); + assertClass("class NAME { constructor() { }; static set static(x) { } }", + [ctorPlaceholder, simpleMethod("static", "set", false, ["x"], true)]); + + // You do, however, have to put static in the right spot + assertClassError("class NAME { constructor() { }; get static foo() { } }", SyntaxError); + + // Spec disallows "prototype" as a static member in a class, since that + // one's important to make the desugaring work + assertClassError("class NAME { constructor() { } static prototype() { } }", SyntaxError); + assertClassError("class NAME { constructor() { } static *prototype() { } }", SyntaxError); + assertClassError("class NAME { static get prototype() { }; constructor() { } }", SyntaxError); + assertClassError("class NAME { static set prototype(x) { }; constructor() { } }", SyntaxError); + + // You are, however, allowed to have a CPN called prototype as a static + assertClass("class NAME { constructor() { }; static [\"prototype\"]() { } }", + [ctorPlaceholder, emptyCPNMethod("prototype", true)]); + + /* Constructor */ + // Allow default constructors + assertClass("class NAME { }", []); + assertClass("class NAME extends null { }", [], lit(null)); + + // Derived class constructor must have curly brackets + assertClassError("class NAME extends null { constructor() 1 }", SyntaxError); + + // It is an error to have two methods named constructor, but not other + // names, regardless if one is an accessor or a generator or static. + assertClassError("class NAME { constructor() { } constructor(a) { } }", SyntaxError); + let methods = [["method() { }", simpleMethod("method", "method", false)], + ["*method() { }", simpleMethod("method", "method", true)], + ["get method() { }", simpleMethod("method", "get", false)], + ["set method(x) { }", simpleMethod("method", "set", false, ["x"])], + ["static method() { }", simpleMethod("method", "method", false, [], true)], + ["static *method() { }", simpleMethod("method", "method", true, [], true)], + ["static get method() { }", simpleMethod("method", "get", false, [], true)], + ["static set method(x) { }", simpleMethod("method", "set", false, ["x"], true)]]; + let i,j; + for (i=0; i < methods.length; i++) { + for (j=0; j < methods.length; j++) { + let str = "class NAME { constructor() { } " + + methods[i][0] + " " + methods[j][0] + + " }"; + assertClass(str, [ctorPlaceholder, methods[i][1], methods[j][1]]); + } + } + + // It is, however, not an error to have a constructor, and a method with a + // computed property name 'constructor' + assertClass("class NAME { constructor () { } [\"constructor\"] () { } }", + [ctorPlaceholder, emptyCPNMethod("constructor", false)]); + + // It is an error to have a generator or accessor named constructor + assertClassError("class NAME { *constructor() { } }", SyntaxError); + assertClassError("class NAME { get constructor() { } }", SyntaxError); + assertClassError("class NAME { set constructor() { } }", SyntaxError); + + /* Semicolons */ + // Allow Semicolons in Class Definitions + assertClass("class NAME { constructor() { }; }", [ctorPlaceholder]); + + // Allow more than one semicolon, even in otherwise trivial classses + assertClass("class NAME { ;;; constructor() { } }", [ctorPlaceholder]); + + // Semicolons are optional, even if the methods share a line + assertClass("class NAME { method() { } constructor() { } }", + [simpleMethod("method", "method", false), ctorPlaceholder]); + + /* Generators */ + // No yield as a class name inside a generator + assertError(`function *foo() { + class yield { + constructor() { } + } + }`, SyntaxError); + assertError(`function *foo() { + (class yield { + constructor() { } + }) + }`, SyntaxError); + + // No legacy generators for methods. + assertClassError(`class NAME { + constructor() { yield 2; } + }`, SyntaxError); + assertClassError(`class NAME { + method() { yield 2; } + }`, SyntaxError); + assertClassError(`class NAME { + get method() { yield 2; } + }`, SyntaxError); + assertClassError(`class NAME { + set method() { yield 2; } + }`, SyntaxError); + + // Methods may be generators, but not accessors + assertClassError("class NAME { constructor() { } *get foo() { } }", SyntaxError); + assertClassError("class NAME { constructor() { } *set foo() { } }", SyntaxError); + + assertClass("class NAME { *method() { } constructor() { } }", + [simpleMethod("method", "method", true), ctorPlaceholder]); + + /* Strictness */ + // yield is a strict-mode keyword, and class definitions are always strict. + assertClassError("class NAME { constructor() { var yield; } }", SyntaxError); + + // Beware of the strictness of computed property names. Here use bareword + // deletion (a deprecated action) to check. + assertClassError("class NAME { constructor() { } [delete bar]() { }}", SyntaxError); + + /* Bindings */ + // Class statements bind lexically, so they should collide with other + // in-block lexical bindings, but class expressions don't. + let FooCtor = ctorWithName("Foo"); + assertError("{ let Foo; class Foo { constructor() { } } }", SyntaxError); + assertStmt("{ let Foo; (class Foo { constructor() { } }) }", + blockStmt([letDecl([{id: ident("Foo"), init: null}]), + exprStmt(classExpr(ident("Foo"), null, [FooCtor]))])); + assertError("{ const Foo = 0; class Foo { constructor() { } } }", SyntaxError); + assertStmt("{ const Foo = 0; (class Foo { constructor() { } }) }", + blockStmt([constDecl([{id: ident("Foo"), init: lit(0)}]), + exprStmt(classExpr(ident("Foo"), null, [FooCtor]))])); + assertError("{ class Foo { constructor() { } } class Foo { constructor() { } } }", SyntaxError); + assertStmt(`{ + (class Foo { + constructor() { } + }, + class Foo { + constructor() { } + }); + }`, + blockStmt([exprStmt(seqExpr([classExpr(ident("Foo"), null, [FooCtor]), + classExpr(ident("Foo"), null, [FooCtor])]))])); + assertStmt(`{ + var x = class Foo { constructor() { } }; + class Foo { constructor() { } } + }`, + blockStmt([varDecl([{ id: ident("x"), + init: classExpr(ident("Foo"), null, [FooCtor]) + }]), + classStmt(ident("Foo"), null, [FooCtor])])); + + + // Can't make a lexical binding without a block. + assertError("if (1) class Foo { constructor() { } }", SyntaxError); + + /* Heritage Expressions */ + // It's illegal to have things that look like "multiple inheritance": + // non-parenthesized comma expressions. + assertClassError("class NAME extends null, undefined { constructor() { } }", SyntaxError); + + // Again check for strict-mode in heritage expressions + assertClassError("class NAME extends (delete x) { constructor() { } }", SyntaxError); + + // You must specify an inheritance if you say "extends" + assertClassError("class NAME extends { constructor() { } }", SyntaxError); + + // "extends" is still a valid name for a method + assertClass("class NAME { constructor() { }; extends() { } }", + [ctorPlaceholder, simpleMethod("extends", "method", false)]); + + // Immediate expression + assertClass("class NAME extends null { constructor() { } }", + [ctorPlaceholder], lit(null)); + + // Sequence expresson + assertClass("class NAME extends (undefined, undefined) { constructor() { } }", + [ctorPlaceholder], seqExpr([ident("undefined"), ident("undefined")])); + + // Function expression + let emptyFunction = funExpr(null, [], blockStmt([])); + assertClass("class NAME extends function(){ } { constructor() { } }", + [ctorPlaceholder], emptyFunction); + + // New expression + assertClass("class NAME extends new function(){ }() { constructor() { } }", + [ctorPlaceholder], newExpr(emptyFunction, [])); + + // Call expression + assertClass("class NAME extends function(){ }() { constructor() { } }", + [ctorPlaceholder], callExpr(emptyFunction, [])); + + // Dot expression + assertClass("class NAME extends {}.foo { constructor() { } }", + [ctorPlaceholder], dotExpr(objExpr([]), ident("foo"))); + + // Member expression + assertClass("class NAME extends {}[foo] { constructor() { } }", + [ctorPlaceholder], memExpr(objExpr([]), ident("foo"))); + + if (getRealmConfiguration().privateMethods) { + // #constructor is an invalid private method name. + assertClassError("class NAME { #constructor() { } }", SyntaxError); + + const method = ["#method() { }", simpleMethod("#method", "method", false)]; + const generator = ["*#method() { }", simpleMethod("#method", "method", true)]; + const getter = ["get #method() { }", simpleMethod("#method", "get", false)]; + const setter = ["set #method(x) { }", simpleMethod("#method", "set", false, ["x"])]; + for (const [source, parsed] of [method, generator, getter, setter]) { + assertClass(`class NAME { constructor() { } ${source} }`, [ctorPlaceholder, parsed]); + } + + // Private getters and setters of the same name are allowed. + assertClass(`class NAME { constructor() { } ${getter[0]} ${setter[0]} }`, + [ctorPlaceholder, getter[1], setter[1]]); + assertClass(`class NAME { constructor() { } ${setter[0]} ${getter[0]} }`, + [ctorPlaceholder, setter[1], getter[1]]); + + // Private method names can't be used multiple times, other than for a getter/setter pair. + for (const [source1, _] of [method, generator, getter, setter]) { + for (const [source2, _] of [method, generator]) { + assertClassError(`class NAME { constructor() { } ${source1} ${source2} }`, SyntaxError); + } + } + + assertClassError(`class NAME { constructor() { } ${setter[0]} ${setter[0]} }`, SyntaxError); + assertClassError(`class NAME { constructor() { } ${getter[0]} ${getter[0]} }`, SyntaxError); + } + + /* SuperProperty */ + // NOTE: Some of these tests involve object literals, as SuperProperty is a + // valid production in any method definition, including in objectl + // litterals. These tests still fall here, as |super| is not implemented in + // any form without classes. + + function assertValidSuperProps(assertion, makeStr, makeExpr, type, generator, args, static, + extending) + { + let superProperty = superProp(ident("prop")); + let superMember = superElem(lit("prop")); + + let situations = [ + ["super.prop", superProperty], + ["super['prop']", superMember], + ["super.prop()", callExpr(superProperty, [])], + ["super['prop']()", callExpr(superMember, [])], + ["new super.prop()", newExpr(superProperty, [])], + ["new super['prop']()", newExpr(superMember, [])], + ["delete super.prop", unExpr("delete", superProperty)], + ["delete super['prop']", unExpr("delete", superMember)], + ["++super.prop", updExpr("++", superProperty, true)], + ["super['prop']--", updExpr("--", superMember, false)], + ["super.prop = 4", aExpr("=", superProperty, lit(4))], + ["super['prop'] = 4", aExpr("=", superMember, lit(4))], + ["super.prop += 4", aExpr("+=", superProperty, lit(4))], + ["super['prop'] += 4", aExpr("+=", superMember, lit(4))], + ["super.prop -= 4", aExpr("-=", superProperty, lit(4))], + ["super['prop'] -= 4", aExpr("-=", superMember, lit(4))], + ["super.prop *= 4", aExpr("*=", superProperty, lit(4))], + ["super['prop'] *= 4", aExpr("*=", superMember, lit(4))], + ["super.prop /= 4", aExpr("/=", superProperty, lit(4))], + ["super['prop'] /= 4", aExpr("/=", superMember, lit(4))], + ["super.prop %= 4", aExpr("%=", superProperty, lit(4))], + ["super['prop'] %= 4", aExpr("%=", superMember, lit(4))], + ["super.prop <<= 4", aExpr("<<=", superProperty, lit(4))], + ["super['prop'] <<= 4", aExpr("<<=", superMember, lit(4))], + ["super.prop >>= 4", aExpr(">>=", superProperty, lit(4))], + ["super['prop'] >>= 4", aExpr(">>=", superMember, lit(4))], + ["super.prop >>>= 4", aExpr(">>>=", superProperty, lit(4))], + ["super['prop'] >>>= 4", aExpr(">>>=", superMember, lit(4))], + ["super.prop |= 4", aExpr("|=", superProperty, lit(4))], + ["super['prop'] |= 4", aExpr("|=", superMember, lit(4))], + ["super.prop ^= 4", aExpr("^=", superProperty, lit(4))], + ["super['prop'] ^= 4", aExpr("^=", superMember, lit(4))], + ["super.prop &= 4", aExpr("&=", superProperty, lit(4))], + ["super['prop'] &= 4", aExpr("&=", superMember, lit(4))], + + // We can also use super from inside arrow functions in method + // definitions + ["()=>super.prop", arrowExpr([], superProperty)], + ["()=>super['prop']", arrowExpr([], superMember)]]; + + for (let situation of situations) { + let sitStr = situation[0]; + let sitExpr = situation[1]; + + let fun = methodFun("method", type, generator, args, [exprStmt(sitExpr)]); + let str = makeStr(sitStr, type, generator, args, static, extending); + assertion(str, makeExpr(fun, type, static), extending); + } + } + + function assertValidSuperPropTypes(assertion, makeStr, makeExpr, static, extending) { + for (let type of ["method", "get", "set"]) { + if (type === "method") { + // methods can also be generators + assertValidSuperProps(assertion, makeStr, makeExpr, type, true, [], static, extending); + assertValidSuperProps(assertion, makeStr, makeExpr, type, false, [], static, extending); + continue; + } + + // Setters require 1 argument, and getters require 0 + assertValidSuperProps(assertion, makeStr, makeExpr, type, false, + type === "set" ? ["x"] : [], static, extending); + } + } + + function makeSuperPropMethodStr(propStr, type, generator, args) { + return `${type === "method" ? "" : type} ${generator ? "*" : ""} method(${args.join(",")}) + { + ${propStr}; + }`; + } + + function makeClassSuperPropStr(propStr, type, generator, args, static, extending) { + return `class NAME ${extending ? "extends null" : ""} { + constructor() { }; + ${static ? "static" : ""} ${makeSuperPropMethodStr(propStr, type, generator, args)} + }`; + } + function makeClassSuperPropExpr(fun, type, static) { + // We are going right into assertClass, so we don't have to build the + // entire statement. + return [ctorPlaceholder, + classMethod(ident("method"), fun, type, static)]; + } + function doClassSuperPropAssert(str, expr, extending) { + assertClass(str, expr, extending ? lit(null) : null); + } + function assertValidClassSuperPropExtends(extending) { + // super.prop and super[prop] are valid, regardless of whether the + // method is static or not + assertValidSuperPropTypes(doClassSuperPropAssert, makeClassSuperPropStr, makeClassSuperPropExpr, + false, extending); + assertValidSuperPropTypes(doClassSuperPropAssert, makeClassSuperPropStr, makeClassSuperPropExpr, + true, extending); + } + function assertValidClassSuperProps() { + // super.prop and super[prop] are valid, regardless of class heritage + assertValidClassSuperPropExtends(false); + assertValidClassSuperPropExtends(true); + } + + function makeOLSuperPropStr(propStr, type, generator, args) { + let str = `({ ${makeSuperPropMethodStr(propStr, type, generator, args)} })`; + return str; + } + function makeOLSuperPropExpr(fun) { + return objExpr([{ type: "Property", key: ident("method"), value: fun}]); + } + function assertValidOLSuperProps() { + assertValidSuperPropTypes(assertExpr, makeOLSuperPropStr, makeOLSuperPropExpr); + } + + + // Check all valid uses of SuperProperty + assertValidClassSuperProps(); + assertValidOLSuperProps(); + + // SuperProperty is forbidden outside of method definitions. + assertError("function foo () { super.prop; }", SyntaxError); + assertError("(function () { super.prop; }", SyntaxError); + assertError("(()=>super.prop)", SyntaxError); + assertError("function *foo() { super.prop; }", SyntaxError); + assertError("super.prop", SyntaxError); + assertError("function foo () { super['prop']; }", SyntaxError); + assertError("(function () { super['prop']; }", SyntaxError); + assertError("(()=>super['prop'])", SyntaxError); + assertError("function *foo() { super['prop']; }", SyntaxError); + assertError("super['prop']", SyntaxError); + + // Or inside functions inside method definitions... + assertClassError("class NAME { constructor() { function nested() { super.prop; }}}", SyntaxError); + + // Bare super is forbidden + assertError("super", SyntaxError); + + // Even where super is otherwise allowed + assertError("{ foo() { super } }", SyntaxError); + assertClassError("class NAME { constructor() { super; } }", SyntaxError); + + /* SuperCall */ + + // SuperCall is invalid outside derived class constructors. + assertError("super()", SyntaxError); + assertError("(function() { super(); })", SyntaxError); + + + // Even in class constructors + assertClassError("class NAME { constructor() { super(); } }", SyntaxError); + + function superConstructor(args) { + return classMethod(ident("constructor"), + methodFun("NAME", "method", false, + [], [exprStmt(superCallExpr(args))]), + "method", false); + } + + function superCallBody(args) { + return [exprStmt(superCallExpr(args))]; + } + + // SuperCall works with various argument configurations. + assertClass("class NAME extends null { constructor() { super() } }", + [ctorPlaceholder], lit(null), superCallBody([])); + assertClass("class NAME extends null { constructor() { super(1) } }", + [ctorPlaceholder], lit(null), superCallBody([lit(1)])); + assertClass("class NAME extends null { constructor() { super(1, a) } }", + [ctorPlaceholder], lit(null), superCallBody([lit(1), ident("a")])); + assertClass("class NAME extends null { constructor() { super(...[]) } }", + [ctorPlaceholder], lit(null), superCallBody([spread(arrExpr([]))])); + + /* EOF */ + // Clipped classes should throw a syntax error + assertClassError("class NAME {", SyntaxError); + assertClassError("class NAME {;", SyntaxError); + assertClassError("class NAME { constructor", SyntaxError); + assertClassError("class NAME { constructor(", SyntaxError); + assertClassError("class NAME { constructor()", SyntaxError); + assertClassError("class NAME { constructor()", SyntaxError); + assertClassError("class NAME { constructor() {", SyntaxError); + assertClassError("class NAME { constructor() { }", SyntaxError); + assertClassError("class NAME { static", SyntaxError); + assertClassError("class NAME { static y", SyntaxError); + assertClassError("class NAME { static *", SyntaxError); + assertClassError("class NAME { static *y", SyntaxError); + assertClassError("class NAME { static get", SyntaxError); + assertClassError("class NAME { static get y", SyntaxError); + assertClassError("class NAME { static ;", SyntaxError); + assertClassError("class NAME extends", SyntaxError); + assertClassError("class NAME { constructor() { super", SyntaxError); + assertClassError("class NAME { constructor() { super.", SyntaxError); + assertClassError("class NAME { constructor() { super.x", SyntaxError); + assertClassError("class NAME { constructor() { super.m(", SyntaxError); + assertClassError("class NAME { constructor() { super[", SyntaxError); + assertClassError("class NAME { constructor() { super(", SyntaxError); + + // Can not omit curly brackets + assertClassError("class NAME { constructor() ({}) }", SyntaxError); + assertClassError("class NAME { constructor() void 0 }", SyntaxError); + assertClassError("class NAME { constructor() 1 }", SyntaxError); + assertClassError("class NAME { constructor() false }", SyntaxError); + assertClassError("class NAME { constructor() {} a() ({}) }", SyntaxError); + assertClassError("class NAME { constructor() {} a() void 0 }", SyntaxError); + assertClassError("class NAME { constructor() {} a() 1 }", SyntaxError); + assertClassError("class NAME { constructor() {} a() false }", SyntaxError); + +} + +runtest(testClasses); diff --git a/js/src/tests/non262/reflect-parse/computedPropNames.js b/js/src/tests/non262/reflect-parse/computedPropNames.js new file mode 100644 index 0000000000..d96e73152b --- /dev/null +++ b/js/src/tests/non262/reflect-parse/computedPropNames.js @@ -0,0 +1,45 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// Bug 924688: computed property names +assertExpr('a= {[field1]: "a", [field2=1]: "b"}', + aExpr("=", ident("a"), + objExpr([{ key: computedName(ident("field1")), value: lit("a")}, + { key: computedName(aExpr("=", ident("field2"), lit(1))), + value: lit("b")}]))); + +assertExpr('a= {["field1"]: "a", field2 : "b"}', + aExpr("=", ident("a"), + objExpr([{ key: computedName(lit("field1")), value: lit("a") }, + { key: ident("field2"), value: lit("b") }]))); + +assertExpr('a= {[1]: 1, 2 : 2}', + aExpr("=", ident("a"), + objExpr([{ key: computedName(lit(1)), value: lit(1) }, + { key: lit(2), value: lit(2) }]))); + +// Bug 924688: computed property names - location information +var node = Reflect.parse("a = {[field1]: 5}"); +Pattern({ body: [ { expression: { right: { properties: [ {key: { loc: + { start: { line: 1, column: 5 }, end: { line: 1, column: 13 }}}}]}}}]}).match(node); + +// Bug 1048384 - Getter/setter syntax with computed names +assertExpr("b = { get [meth]() { } }", aExpr("=", ident("b"), + objExpr([{ key: computedName(ident("meth")), value: funExpr(null, [], blockStmt([])), + method: false, kind: "get"}]))); +assertExpr("b = { set [meth](a) { } }", aExpr("=", ident("b"), + objExpr([{ key: computedName(ident("meth")), value: funExpr(null, [ident("a")], + blockStmt([])), method: false, kind: "set"}]))); + +// Bug 1220702 - If it's not written as a method, `.method` should be false. +assertExpr("({[x]: function () {}})", + objExpr([{ + key: computedName(ident("x")), + value: funExpr(null, [], blockStmt([])), + method: false, + kind: "init" + }])); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/declarations.js b/js/src/tests/non262/reflect-parse/declarations.js new file mode 100644 index 0000000000..4962f4cee9 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/declarations.js @@ -0,0 +1,97 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// Bug 632056: constant-folding +program([exprStmt(ident("f")), + ifStmt(lit(1), + blockStmt([funDecl(ident("f"), [], blockStmt([]))]), + null)]).assert(Reflect.parse("f; if (1) function f(){}")); +// declarations + +assertDecl("var x = 1, y = 2, z = 3", + varDecl([{ id: ident("x"), init: lit(1) }, + { id: ident("y"), init: lit(2) }, + { id: ident("z"), init: lit(3) }])); +assertDecl("var x, y, z", + varDecl([{ id: ident("x"), init: null }, + { id: ident("y"), init: null }, + { id: ident("z"), init: null }])); +assertDecl("function foo() { }", + funDecl(ident("foo"), [], blockStmt([]))); +assertDecl("function foo() { return 42 }", + funDecl(ident("foo"), [], blockStmt([returnStmt(lit(42))]))); + +assertDecl("function foo(...rest) { }", + funDecl(ident("foo"), [], blockStmt([]), [], ident("rest"))); + +assertDecl("function foo(a=4) { }", funDecl(ident("foo"), [ident("a")], blockStmt([]), [lit(4)])); +assertDecl("function foo(a, b=4) { }", funDecl(ident("foo"), [ident("a"), ident("b")], blockStmt([]), [null, lit(4)])); +assertDecl("function foo(a, b=4, ...rest) { }", + funDecl(ident("foo"), [ident("a"), ident("b")], blockStmt([]), [null, lit(4), null], ident("rest"))); +assertDecl("function foo(a=(function () {})) { function a() {} }", + funDecl(ident("foo"), [ident("a")], blockStmt([funDecl(ident("a"), [], blockStmt([]))]), + [funExpr(null, [], blockStmt([]))])); + +// Bug 1018628: default paremeter for destructuring +assertDecl("function f(a=1, [x,y]=[2,3]) { }", + funDecl(ident("f"), + [ident("a"), arrPatt([ident("x"), ident("y")])], + blockStmt([]), + [lit(1), arrExpr([lit(2), lit(3)])])); + +// Bug 591437: rebound args have their defs turned into uses +assertDecl("function f(a) { function a() { } }", + funDecl(ident("f"), [ident("a")], blockStmt([funDecl(ident("a"), [], blockStmt([]))]))); +assertDecl("function f(a,b,c) { function b() { } }", + funDecl(ident("f"), [ident("a"),ident("b"),ident("c")], blockStmt([funDecl(ident("b"), [], blockStmt([]))]))); +assertDecl("function f(a,[x,y]) { function a() { } }", + funDecl(ident("f"), + [ident("a"), arrPatt([assignElem("x"), assignElem("y")])], + blockStmt([funDecl(ident("a"), [], blockStmt([]))]))); + +// Bug 591450: this test currently crashes because of a bug in jsparse +// assertDecl("function f(a,[x,y],b,[w,z],c) { function b() { } }", +// funDecl(ident("f"), +// [ident("a"), arrPatt([ident("x"), ident("y")]), ident("b"), arrPatt([ident("w"), ident("z")]), ident("c")], +// blockStmt([funDecl(ident("b"), [], blockStmt([]))]))); + +// redeclarations (TOK_NAME nodes with lexdef) + +assertStmt("function f() { function g() { } function g() { } }", + funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])), + funDecl(ident("g"), [], blockStmt([]))]))); + +// Fails due to parser quirks (bug 638577) +//assertStmt("function f() { function g() { } function g() { return 42 } }", +// funDecl(ident("f"), [], blockStmt([funDecl(ident("g"), [], blockStmt([])), +// funDecl(ident("g"), [], blockStmt([returnStmt(lit(42))]))]))); + +assertStmt("function f() { var x = 42; var x = 43; }", + funDecl(ident("f"), [], blockStmt([varDecl([{ id: ident("x"), init: lit(42) }]), + varDecl([{ id: ident("x"), init: lit(43) }])]))); + + +assertDecl("var {x:y} = foo;", varDecl([{ id: objPatt([assignProp("x", ident("y"))]), + init: ident("foo") }])); +assertDecl("var {x} = foo;", varDecl([{ id: objPatt([assignProp("x")]), + init: ident("foo") }])); + +// Bug 632030: redeclarations between var and funargs, var and function +assertStmt("function g(x) { var x }", + funDecl(ident("g"), [ident("x")], blockStmt([varDecl([{ id: ident("x"), init: null }])]))); +assertProg("f.p = 1; var f; f.p; function f(){}", + [exprStmt(aExpr("=", dotExpr(ident("f"), ident("p")), lit(1))), + varDecl([{ id: ident("f"), init: null }]), + exprStmt(dotExpr(ident("f"), ident("p"))), + funDecl(ident("f"), [], blockStmt([]))]); +} + +assertBlockStmt("{ function f(x) {} }", + blockStmt([funDecl(ident("f"), [ident("x")], blockStmt([]))])); + +// Annex B semantics should not change parse tree. +assertBlockStmt("{ let f; { function f(x) {} } }", + blockStmt([letDecl([{ id: ident("f"), init: null }]), + blockStmt([funDecl(ident("f"), [ident("x")], blockStmt([]))])])); + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/destructuring-array-holes-reflect-as-null.js b/js/src/tests/non262/reflect-parse/destructuring-array-holes-reflect-as-null.js new file mode 100644 index 0000000000..8005ecc5cd --- /dev/null +++ b/js/src/tests/non262/reflect-parse/destructuring-array-holes-reflect-as-null.js @@ -0,0 +1,9 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// Bug 632027: array holes should reflect as null +assertExpr("[,]=[,]", aExpr("=", arrPatt([null]), arrExpr([null]))); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/destructuring-assignment.js b/js/src/tests/non262/reflect-parse/destructuring-assignment.js new file mode 100644 index 0000000000..cba4197ee9 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/destructuring-assignment.js @@ -0,0 +1,32 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// destructuring assignment + +function testAssignmentCombinations(makePattSrc, makePattPatt) { + var pattSrcs = makePatternCombinations(n => ("x" + n + " = 0"), makePattSrc); + var pattPatts = makePatternCombinations(n => (aExpr("=", ident("x" + n), lit(0))), makePattPatt); + + for (var i = 0; i < pattSrcs.length; i++) { + var src = pattSrcs[i].join(","); + var patt = pattPatts[i].length === 1 ? pattPatts[i][0] : seqExpr(pattPatts[i]); + + // assignment expression statement + assertExpr("(" + src + ")", patt); + + // for-loop head assignment + assertStmt("for (" + src + "; foo; bar);", + forStmt(patt, ident("foo"), ident("bar"), emptyStmt)); + } +} + +testAssignmentCombinations(n => ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"), + n => (aExpr("=", + objPatt([assignProp("a" + n, ident("x" + n)), + assignProp("b" + n, ident("y" + n)), + assignProp("c" + n, ident("z" + n))]), + lit(0)))); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/destructuring-function-parameters.js b/js/src/tests/non262/reflect-parse/destructuring-function-parameters.js new file mode 100644 index 0000000000..6b3a777379 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/destructuring-function-parameters.js @@ -0,0 +1,45 @@ +// |reftest| slow skip-if(!xulRuntime.shell) +function test() { + +function testParamPatternCombinations(makePattSrc, makePattPatt) { + var pattSrcs = makePatternCombinations(n => ("x" + n), makePattSrc); + var pattPatts = makePatternCombinations(n => (ident("x" + n)), makePattPatt); + + for (var i = 0; i < pattSrcs.length; i++) { + function makeSrc(body) { + return "(function(" + pattSrcs[i].join(",") + ") " + body + ")"; + } + function makePatt(body) { + return funExpr(null, pattPatts[i], body); + } + + // no upvars, block body + assertExpr(makeSrc("{ }"), makePatt(blockStmt([]))); + // upvars, block body + assertExpr(makeSrc("{ return [x1,x2,x3,x4,x5]; }"), + makePatt(blockStmt([returnStmt(arrExpr([ident("x1"), ident("x2"), ident("x3"), ident("x4"), ident("x5")]))]))); + } +} + +testParamPatternCombinations(n => ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "}"), + n => (objPatt([assignProp("a" + n, ident("x" + n)), + assignProp("b" + n, ident("y" + n)), + assignProp("c" + n, ident("z" + n))]))); + +testParamPatternCombinations(n => ("{a" + n + ":x" + n + " = 10," + "b" + n + ":y" + n + " = 10," + "c" + n + ":z" + n + " = 10}"), + n => (objPatt([assignProp("a" + n, ident("x" + n), lit(10)), + assignProp("b" + n, ident("y" + n), lit(10)), + assignProp("c" + n, ident("z" + n), lit(10))]))); + +testParamPatternCombinations(n => ("[x" + n + "," + "y" + n + "," + "z" + n + "]"), + n => (arrPatt([assignElem("x" + n), assignElem("y" + n), assignElem("z" + n)]))); + +testParamPatternCombinations(n => ("[a" + n + ", ..." + "b" + n + "]"), + n => (arrPatt([assignElem("a" + n), spread(ident("b" + n))]))); + +testParamPatternCombinations(n => ("[a" + n + ", " + "b" + n + " = 10]"), + n => (arrPatt([assignElem("a" + n), assignElem("b" + n, lit(10))]))); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/destructuring-variable-declarations.js b/js/src/tests/non262/reflect-parse/destructuring-variable-declarations.js new file mode 100644 index 0000000000..6a455668af --- /dev/null +++ b/js/src/tests/non262/reflect-parse/destructuring-variable-declarations.js @@ -0,0 +1,58 @@ +// |reftest| slow skip-if(!xulRuntime.shell) +function test() { + +function testVarPatternCombinations(makePattSrc, makePattPatt) { + var pattSrcs = makePatternCombinations(n => ("x" + n), makePattSrc); + var pattPatts = makePatternCombinations(n => ({ id: ident("x" + n), init: null }), makePattPatt); + // It's illegal to have uninitialized const declarations, so we need a + // separate set of patterns and sources. + var constSrcs = makePatternCombinations(n => ("x" + n + " = undefined"), makePattSrc); + var constPatts = makePatternCombinations(n => ({ id: ident("x" + n), init: ident("undefined") }), makePattPatt); + + for (var i = 0; i < pattSrcs.length; i++) { + // variable declarations in blocks + assertDecl("var " + pattSrcs[i].join(",") + ";", varDecl(pattPatts[i])); + + assertGlobalDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); + assertLocalDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); + assertBlockDecl("let " + pattSrcs[i].join(",") + ";", letDecl(pattPatts[i])); + + assertDecl("const " + constSrcs[i].join(",") + ";", constDecl(constPatts[i])); + + // variable declarations in for-loop heads + assertStmt("for (var " + pattSrcs[i].join(",") + "; foo; bar);", + forStmt(varDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt)); + assertStmt("for (let " + pattSrcs[i].join(",") + "; foo; bar);", + forStmt(letDecl(pattPatts[i]), ident("foo"), ident("bar"), emptyStmt)); + assertStmt("for (const " + constSrcs[i].join(",") + "; foo; bar);", + forStmt(constDecl(constPatts[i]), ident("foo"), ident("bar"), emptyStmt)); + } +} + +testVarPatternCombinations(n => ("{a" + n + ":x" + n + "," + "b" + n + ":y" + n + "," + "c" + n + ":z" + n + "} = 0"), + n => ({ id: objPatt([assignProp("a" + n, ident("x" + n)), + assignProp("b" + n, ident("y" + n)), + assignProp("c" + n, ident("z" + n))]), + init: lit(0) })); + +testVarPatternCombinations(n => ("{a" + n + ":x" + n + " = 10," + "b" + n + ":y" + n + " = 10," + "c" + n + ":z" + n + " = 10} = 0"), + n => ({ id: objPatt([assignProp("a" + n, ident("x" + n), lit(10)), + assignProp("b" + n, ident("y" + n), lit(10)), + assignProp("c" + n, ident("z" + n), lit(10))]), + init: lit(0) })); + +testVarPatternCombinations(n => ("[x" + n + "," + "y" + n + "," + "z" + n + "] = 0"), + n => ({ id: arrPatt([assignElem("x" + n), assignElem("y" + n), assignElem("z" + n)]), + init: lit(0) })); + +testVarPatternCombinations(n => ("[a" + n + ", ..." + "b" + n + "] = 0"), + n => ({ id: arrPatt([assignElem("a" + n), spread(ident("b" + n))]), + init: lit(0) })); + +testVarPatternCombinations(n => ("[a" + n + ", " + "b" + n + " = 10] = 0"), + n => ({ id: arrPatt([assignElem("a" + n), assignElem("b" + n, lit(10))]), + init: lit(0) })); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/destructuring__proto__.js b/js/src/tests/non262/reflect-parse/destructuring__proto__.js new file mode 100644 index 0000000000..3238904086 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/destructuring__proto__.js @@ -0,0 +1,16 @@ +// |reftest| skip-if(!xulRuntime.shell) +// |reftest| skip-if(!xulRuntime.shell) +// bug 963641 + +Reflect.parse("({ __proto__: null });"); +Reflect.parse("var { __proto__: x } = obj;"); +Reflect.parse("var [{ __proto__: y }] = obj;"); +Reflect.parse("[{ __proto__: y }] = arr;"); +Reflect.parse("({ __proto__: y } = obj);"); + +if (typeof reportCompare === "function") + reportCompare(true, true); + + + +print("Tests complete"); diff --git a/js/src/tests/non262/reflect-parse/expression-short-circuit-compound-assignment.js b/js/src/tests/non262/reflect-parse/expression-short-circuit-compound-assignment.js new file mode 100644 index 0000000000..538b9f31c2 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/expression-short-circuit-compound-assignment.js @@ -0,0 +1,11 @@ +// |reftest| skip-if(!xulRuntime.shell||release_or_beta) + +function test() { + +assertExpr("(x ??= y)", aExpr("??=", ident("x"), ident("y"))); +assertExpr("(x ||= y)", aExpr("||=", ident("x"), ident("y"))); +assertExpr("(x &&= y)", aExpr("&&=", ident("x"), ident("y"))); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/expression.js b/js/src/tests/non262/reflect-parse/expression.js new file mode 100644 index 0000000000..c91525aa98 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/expression.js @@ -0,0 +1,193 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// primary expressions +assertExpr("true", lit(true)); +assertExpr("false", lit(false)); +assertExpr("42", lit(42)); +assertExpr("(/asdf/)", lit(/asdf/)); +assertExpr("this", thisExpr); +assertExpr("foo", ident("foo")); +if ("BigInt" in this) { + assertExpr("1234n", lit(BigInt(1234))); +} + +// member expressions +assertExpr("foo.bar", dotExpr(ident("foo"), ident("bar"))); +assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar"))); +assertExpr("foo['bar']", memExpr(ident("foo"), lit("bar"))); +assertExpr("foo[42]", memExpr(ident("foo"), lit(42))); + +// optional member expressions +assertExpr("foo?.bar", optExpr(optDotExpr(ident("foo"), ident("bar")))); +assertExpr("foo?.bar.baz", optExpr(dotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo.bar?.baz", optExpr(optDotExpr(dotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo?.bar?.baz", optExpr(optDotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo?.[bar].baz", optExpr(dotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo.bar?.[baz]", optExpr(optMemExpr(dotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo[bar]?.[baz]", optExpr(optMemExpr(memExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo?.[bar][baz]", optExpr(memExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("foo?.['bar']?.['baz']", optExpr(optMemExpr(optMemExpr(ident("foo"), lit("bar")), lit("baz")))); +assertExpr("foo?.[bar]?.baz", optExpr(optDotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz")))); + +// delete optional expressions +assertExpr("\ndelete [] ?. [1]", delOptExpr(optMemExpr(arrExpr([]), lit(1)))); +assertExpr("delete foo?.bar", delOptExpr(optDotExpr(ident("foo"), ident("bar")))); +assertExpr("delete foo?.bar.baz", delOptExpr(dotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo.bar?.baz", delOptExpr(optDotExpr(dotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo?.bar?.baz", delOptExpr(optDotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo?.[bar].baz", delOptExpr(dotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo.bar?.[baz]", delOptExpr(optMemExpr(dotExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo[bar]?.[baz]", delOptExpr(optMemExpr(memExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo?.[bar][baz]", delOptExpr(memExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz")))); +assertExpr("delete foo?.['bar']?.['baz']", delOptExpr(optMemExpr(optMemExpr(ident("foo"), lit("bar")), lit("baz")))); +assertExpr("delete foo?.[bar]?.baz", delOptExpr(optDotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz")))); + +// function expressions +assertExpr("(function(){})", funExpr(null, [], blockStmt([]))); +assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([]))); +assertExpr("(function f(x,y,z) {})", funExpr(ident("f"), [ident("x"),ident("y"),ident("z")], blockStmt([]))); +assertExpr("a => a", arrowExpr([ident("a")], ident("a"))); +assertExpr("(a) => a", arrowExpr([ident("a")], ident("a"))); +assertExpr("a => b => a", arrowExpr([ident("a")], arrowExpr([ident("b")], ident("a")))); +assertExpr("a => {}", arrowExpr([ident("a")], blockStmt([]))); +assertExpr("a => ({})", arrowExpr([ident("a")], objExpr([]))); +assertExpr("(a, b, c) => {}", arrowExpr([ident("a"), ident("b"), ident("c")], blockStmt([]))); +assertExpr("([a, b]) => {}", arrowExpr([arrPatt([assignElem("a"), assignElem("b")])], blockStmt([]))); + +// Unary expressions +assertExpr("(++x)", updExpr("++", ident("x"), true)); +assertExpr("(x++)", updExpr("++", ident("x"), false)); +assertExpr("(+x)", unExpr("+", ident("x"))); +assertExpr("(-x)", unExpr("-", ident("x"))); +assertExpr("(!x)", unExpr("!", ident("x"))); +assertExpr("(~x)", unExpr("~", ident("x"))); +assertExpr("(delete x)", unExpr("delete", ident("x"))); +assertExpr("(typeof x)", unExpr("typeof", ident("x"))); +assertExpr("(void x)", unExpr("void", ident("x"))); + +// Bug 632026: constant-folding +assertExpr("typeof(0?0:a)", unExpr("typeof", condExpr(lit(0), lit(0), ident("a")))); + +// Binary exporessions +assertExpr("(x == y)", binExpr("==", ident("x"), ident("y"))); +assertExpr("(x != y)", binExpr("!=", ident("x"), ident("y"))); +assertExpr("(x === y)", binExpr("===", ident("x"), ident("y"))); +assertExpr("(x !== y)", binExpr("!==", ident("x"), ident("y"))); +assertExpr("(x < y)", binExpr("<", ident("x"), ident("y"))); +assertExpr("(x <= y)", binExpr("<=", ident("x"), ident("y"))); +assertExpr("(x > y)", binExpr(">", ident("x"), ident("y"))); +assertExpr("(x >= y)", binExpr(">=", ident("x"), ident("y"))); +assertExpr("(x << y)", binExpr("<<", ident("x"), ident("y"))); +assertExpr("(x >> y)", binExpr(">>", ident("x"), ident("y"))); +assertExpr("(x >>> y)", binExpr(">>>", ident("x"), ident("y"))); +assertExpr("(x + y)", binExpr("+", ident("x"), ident("y"))); +assertExpr("(w + x + y + z)", binExpr("+", binExpr("+", binExpr("+", ident("w"), ident("x")), ident("y")), ident("z"))); +assertExpr("(x - y)", binExpr("-", ident("x"), ident("y"))); +assertExpr("(w - x - y - z)", binExpr("-", binExpr("-", binExpr("-", ident("w"), ident("x")), ident("y")), ident("z"))); +assertExpr("(x * y)", binExpr("*", ident("x"), ident("y"))); +assertExpr("(x / y)", binExpr("/", ident("x"), ident("y"))); +assertExpr("(x % y)", binExpr("%", ident("x"), ident("y"))); +assertExpr("(x | y)", binExpr("|", ident("x"), ident("y"))); +assertExpr("(x ^ y)", binExpr("^", ident("x"), ident("y"))); +assertExpr("(x & y)", binExpr("&", ident("x"), ident("y"))); +assertExpr("(x in y)", binExpr("in", ident("x"), ident("y"))); +assertExpr("(x instanceof y)", binExpr("instanceof", ident("x"), ident("y"))); + +// Bug 571617: eliminate constant-folding +assertExpr("2 + 3", binExpr("+", lit(2), lit(3))); + +// Assignment expressions +assertExpr("(x = y)", aExpr("=", ident("x"), ident("y"))); +assertExpr("(x += y)", aExpr("+=", ident("x"), ident("y"))); +assertExpr("(x -= y)", aExpr("-=", ident("x"), ident("y"))); +assertExpr("(x *= y)", aExpr("*=", ident("x"), ident("y"))); +assertExpr("(x /= y)", aExpr("/=", ident("x"), ident("y"))); +assertExpr("(x %= y)", aExpr("%=", ident("x"), ident("y"))); +assertExpr("(x <<= y)", aExpr("<<=", ident("x"), ident("y"))); +assertExpr("(x >>= y)", aExpr(">>=", ident("x"), ident("y"))); +assertExpr("(x >>>= y)", aExpr(">>>=", ident("x"), ident("y"))); +assertExpr("(x |= y)", aExpr("|=", ident("x"), ident("y"))); +assertExpr("(x ^= y)", aExpr("^=", ident("x"), ident("y"))); +assertExpr("(x &= y)", aExpr("&=", ident("x"), ident("y"))); + +// Conditional expressions +assertExpr("(x || y)", logExpr("||", ident("x"), ident("y"))); +assertExpr("(x && y)", logExpr("&&", ident("x"), ident("y"))); +assertExpr("(x ?? y)", logExpr("??", ident("x"), ident("y"))); +assertExpr("(w || x || y || z)", logExpr("||", logExpr("||", logExpr("||", ident("w"), ident("x")), ident("y")), ident("z"))) +assertExpr("(x ? y : z)", condExpr(ident("x"), ident("y"), ident("z"))); + +// Sequence expressions +assertExpr("(x,y)", seqExpr([ident("x"),ident("y")])) +assertExpr("(x,y,z)", seqExpr([ident("x"),ident("y"),ident("z")])) +assertExpr("(a,b,c,d,e,f,g)", seqExpr([ident("a"),ident("b"),ident("c"),ident("d"),ident("e"),ident("f"),ident("g")])); + +// Call expressions +assertExpr("(new Object)", newExpr(ident("Object"), [])); +assertExpr("(new Object())", newExpr(ident("Object"), [])); +assertExpr("(new Object(42))", newExpr(ident("Object"), [lit(42)])); +assertExpr("(new Object(1,2,3))", newExpr(ident("Object"), [lit(1),lit(2),lit(3)])); +assertExpr("(String())", callExpr(ident("String"), [])); +assertExpr("(String(42))", callExpr(ident("String"), [lit(42)])); +assertExpr("(String(1,2,3))", callExpr(ident("String"), [lit(1),lit(2),lit(3)])); + +// Optional Call expressions +assertExpr("(String?.())", optExpr(optCallExpr(ident("String"), []))); +assertExpr("(String?.(42))", optExpr(optCallExpr(ident("String"), [lit(42)]))); +assertExpr("(String?.(1,2,3))", optExpr(optCallExpr(ident("String"), [lit(1),lit(2),lit(3)]))); +assertExpr("(String?.foo?.())", optExpr(optCallExpr(optDotExpr(ident("String"), ident("foo")), []))); +assertExpr("(String.foo?.())", optExpr(optCallExpr(dotExpr(ident("String"), ident("foo")), []))); +assertExpr("(String?.foo)()", callExpr(optExpr(optDotExpr(ident("String"), ident("foo"))), [])); +assertExpr("(String?.foo)?.()", optExpr(optCallExpr(optExpr(optDotExpr(ident("String"), ident("foo"))), []))); + +// Array expressions +assertExpr("[]", arrExpr([])); +assertExpr("[1]", arrExpr([lit(1)])); +assertExpr("[1,2]", arrExpr([lit(1),lit(2)])); +assertExpr("[1,2,3]", arrExpr([lit(1),lit(2),lit(3)])); +assertExpr("[1,,2,3]", arrExpr([lit(1),null,lit(2),lit(3)])); +assertExpr("[1,,,2,3]", arrExpr([lit(1),null,null,lit(2),lit(3)])); +assertExpr("[1,,,2,,3]", arrExpr([lit(1),null,null,lit(2),null,lit(3)])); +assertExpr("[1,,,2,,,3]", arrExpr([lit(1),null,null,lit(2),null,null,lit(3)])); +assertExpr("[,1,2,3]", arrExpr([null,lit(1),lit(2),lit(3)])); +assertExpr("[,,1,2,3]", arrExpr([null,null,lit(1),lit(2),lit(3)])); +assertExpr("[,,,1,2,3]", arrExpr([null,null,null,lit(1),lit(2),lit(3)])); +assertExpr("[,,,1,2,3,]", arrExpr([null,null,null,lit(1),lit(2),lit(3)])); +assertExpr("[,,,1,2,3,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null])); +assertExpr("[,,,1,2,3,,,]", arrExpr([null,null,null,lit(1),lit(2),lit(3),null,null])); +assertExpr("[,,,,,]", arrExpr([null,null,null,null,null])); +assertExpr("[1, ...a, 2]", arrExpr([lit(1), spread(ident("a")), lit(2)])); +assertExpr("[,, ...a,, ...b, 42]", arrExpr([null,null, spread(ident("a")),, spread(ident("b")), lit(42)])); +assertExpr("[1,(2,3)]", arrExpr([lit(1),seqExpr([lit(2),lit(3)])])); +assertExpr("[,(2,3)]", arrExpr([null,seqExpr([lit(2),lit(3)])])); + +// Object expressions +assertExpr("({})", objExpr([])); +assertExpr("({x:1})", objExpr([{ key: ident("x"), value: lit(1) }])); +assertExpr("({x:x, y})", objExpr([{ key: ident("x"), value: ident("x"), shorthand: false }, + { key: ident("y"), value: ident("y"), shorthand: true }])); +assertExpr("({x:1, y:2})", objExpr([{ key: ident("x"), value: lit(1) }, + { key: ident("y"), value: lit(2) } ])); +assertExpr("({x:1, y:2, z:3})", objExpr([{ key: ident("x"), value: lit(1) }, + { key: ident("y"), value: lit(2) }, + { key: ident("z"), value: lit(3) } ])); +assertExpr("({x:1, 'y':2, z:3})", objExpr([{ key: ident("x"), value: lit(1) }, + { key: lit("y"), value: lit(2) }, + { key: ident("z"), value: lit(3) } ])); +assertExpr("({'x':1, 'y':2, z:3})", objExpr([{ key: lit("x"), value: lit(1) }, + { key: lit("y"), value: lit(2) }, + { key: ident("z"), value: lit(3) } ])); +assertExpr("({'x':1, 'y':2, 3:3})", objExpr([{ key: lit("x"), value: lit(1) }, + { key: lit("y"), value: lit(2) }, + { key: lit(3), value: lit(3) } ])); +assertExpr("({__proto__:x})", objExpr([{ type: "PrototypeMutation", value: ident("x") }])); +assertExpr("({'__proto__':x})", objExpr([{ type: "PrototypeMutation", value: ident("x") }])); +assertExpr("({['__proto__']:x})", objExpr([{ type: "Property", key: comp(lit("__proto__")), value: ident("x") }])); +assertExpr("({['__proto__']:q, __proto__() {}, __proto__: null })", + objExpr([{ type: "Property", key: comp(lit("__proto__")), value: ident("q") }, + { type: "Property", key: ident("__proto__"), method: true }, + { type: "PrototypeMutation", value: lit(null) }])); +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/for-loop-destructuring.js b/js/src/tests/non262/reflect-parse/for-loop-destructuring.js new file mode 100644 index 0000000000..06a745334e --- /dev/null +++ b/js/src/tests/non262/reflect-parse/for-loop-destructuring.js @@ -0,0 +1,47 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// destructuring in for-in and for-of loop heads + +var axbycz = objPatt([assignProp("a", ident("x")), + assignProp("b", ident("y")), + assignProp("c", ident("z"))]); +var xyz = arrPatt([assignElem("x"), assignElem("y"), assignElem("z")]); + +assertStmt("for (var {a:x,b:y,c:z} in foo);", forInStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (let {a:x,b:y,c:z} in foo);", forInStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for ({a:x,b:y,c:z} in foo);", forInStmt(axbycz, ident("foo"), emptyStmt)); +assertStmt("for (var [x,y,z] in foo);", forInStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (let [x,y,z] in foo);", forInStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for ([x,y,z] in foo);", forInStmt(xyz, ident("foo"), emptyStmt)); +assertStmt("for (var {a:x,b:y,c:z} of foo);", forOfStmt(varDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (let {a:x,b:y,c:z} of foo);", forOfStmt(letDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for ({a:x,b:y,c:z} of foo);", forOfStmt(axbycz, ident("foo"), emptyStmt)); +assertStmt("for (var [x,y,z] of foo);", forOfStmt(varDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (let [x,y,z] of foo);", forOfStmt(letDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for ([x,y,z] of foo);", forOfStmt(xyz, ident("foo"), emptyStmt)); + +assertStmt("for (const x in foo);", + forInStmt(constDecl([{ id: ident("x"), init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (const {a:x,b:y,c:z} in foo);", + forInStmt(constDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (const [x,y,z] in foo);", + forInStmt(constDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); + +assertStmt("for (const x of foo);", + forOfStmt(constDecl([{id: ident("x"), init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (const {a:x,b:y,c:z} of foo);", + forOfStmt(constDecl([{ id: axbycz, init: null }]), ident("foo"), emptyStmt)); +assertStmt("for (const [x,y,z] of foo);", + forOfStmt(constDecl([{ id: xyz, init: null }]), ident("foo"), emptyStmt)); + +assertError("for (x = 22 in foo);", SyntaxError);- +assertError("for ({a:x,b:y,c:z} = 22 in foo);", SyntaxError); +assertError("for ([x,y,z] = 22 in foo);", SyntaxError); +assertError("for (const x = 22 in foo);", SyntaxError); +assertError("for (const {a:x,b:y,c:z} = 22 in foo);", SyntaxError); +assertError("for (const [x,y,z] = 22 in foo);", SyntaxError); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/generators.js b/js/src/tests/non262/reflect-parse/generators.js new file mode 100644 index 0000000000..14bac5b527 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/generators.js @@ -0,0 +1,12 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// generators + +assertDecl("function* gen() {}", genFunDecl("es6", ident("gen"), [], blockStmt([]))); +assertExpr("(function*() {})", genFunExpr("es6", null, [], blockStmt([]))); +assertExpr("(function* gen() {})", genFunExpr("es6", ident("gen"), [], blockStmt([]))); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/lexicals.js b/js/src/tests/non262/reflect-parse/lexicals.js new file mode 100644 index 0000000000..c42c43c32f --- /dev/null +++ b/js/src/tests/non262/reflect-parse/lexicals.js @@ -0,0 +1,19 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// global let is var +assertGlobalDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]), + init: ident("foo") }])); +// function-global let is let +assertLocalDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]), + init: ident("foo") }])); +// block-local let is let +assertBlockDecl("let {x:y} = foo;", letDecl([{ id: objPatt([assignProp("x", ident("y"))]), + init: ident("foo") }])); + +assertDecl("const {x:y} = foo;", constDecl([{ id: objPatt([assignProp("x", ident("y"))]), + init: ident("foo") }])); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/location.js b/js/src/tests/non262/reflect-parse/location.js new file mode 100644 index 0000000000..7e7a26a9e6 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/location.js @@ -0,0 +1,33 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// Source location information +var withoutFileOrLine = Reflect.parse("42"); +var withFile = Reflect.parse("42", {source:"foo.js"}); +var withFileAndLine = Reflect.parse("42", {source:"foo.js", line:111}); + +Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withoutFileOrLine.loc); +Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 1, column: 2 } }).match(withFile.loc); +Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 111, column: 2 } }).match(withFileAndLine.loc); + +var withoutFileOrLine2 = Reflect.parse("foo +\nbar"); +var withFile2 = Reflect.parse("foo +\nbar", {source:"foo.js"}); +var withFileAndLine2 = Reflect.parse("foo +\nbar", {source:"foo.js", line:111}); + +Pattern({ source: null, start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withoutFileOrLine2.loc); +Pattern({ source: "foo.js", start: { line: 1, column: 0 }, end: { line: 2, column: 3 } }).match(withFile2.loc); +Pattern({ source: "foo.js", start: { line: 111, column: 0 }, end: { line: 112, column: 3 } }).match(withFileAndLine2.loc); + +var nested = Reflect.parse("(-b + sqrt(sqr(b) - 4 * a * c)) / (2 * a)", {source:"quad.js"}); +var fourAC = nested.body[0].expression.left.right.arguments[0].right; + +Pattern({ source: "quad.js", start: { line: 1, column: 20 }, end: { line: 1, column: 29 } }).match(fourAC.loc); + +// No source location + +assertEq("loc" in Reflect.parse("42", {loc:false}), false); +program([exprStmt(lit(42))]).assert(Reflect.parse("42", {loc:false})); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/methodDefn.js b/js/src/tests/non262/reflect-parse/methodDefn.js new file mode 100644 index 0000000000..cad9b44435 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/methodDefn.js @@ -0,0 +1,51 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// Bug 924672: Method definitions +assertExpr("b = { a() { } }", aExpr("=", ident("b"), + objExpr([{ key: ident("a"), value: funExpr(ident("a"), [], blockStmt([])), method: + true}]))); + +assertExpr("b = { *a() { } }", aExpr("=", ident("b"), + objExpr([{ key: ident("a"), value: genFunExpr("es6", ident("a"), [], blockStmt([])), method: + true}]))); + +// Method definitions without braces +assertError("({ a() void 0 })", SyntaxError); +assertError("({ a() 1 })", SyntaxError); +assertError("({ a() false })", SyntaxError); + +// getters and setters + +assertExpr("({ get x() { return 42 } })", + objExpr([ { key: ident("x"), + value: funExpr(ident("get x"), [], blockStmt([returnStmt(lit(42))])), + kind: "get" } ])); +assertExpr("({ set x(v) { return 42 } })", + objExpr([ { key: ident("x"), + value: funExpr(ident("set x"), [ident("v")], blockStmt([returnStmt(lit(42))])), + kind: "set" } ])); + +// Bug 1073809 - Getter/setter syntax with generators +assertExpr("({*get() { }})", objExpr([{ type: "Property", key: ident("get"), method: true, + value: genFunExpr("es6", ident("get"), [], blockStmt([]))}])); +assertExpr("({*set() { }})", objExpr([{ type: "Property", key: ident("set"), method: true, + value: genFunExpr("es6", ident("set"), [], blockStmt([]))}])); +assertError("({*get foo() { }})", SyntaxError); +assertError("({*set foo() { }})", SyntaxError); + +assertError("({ *get 1() {} })", SyntaxError); +assertError("({ *get \"\"() {} })", SyntaxError); +assertError("({ *get foo() {} })", SyntaxError); +assertError("({ *get []() {} })", SyntaxError); +assertError("({ *get [1]() {} })", SyntaxError); + +assertError("({ *set 1() {} })", SyntaxError); +assertError("({ *set \"\"() {} })", SyntaxError); +assertError("({ *set foo() {} })", SyntaxError); +assertError("({ *set []() {} })", SyntaxError); +assertError("({ *set [1]() {} })", SyntaxError); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/newTarget.js b/js/src/tests/non262/reflect-parse/newTarget.js new file mode 100644 index 0000000000..3db2c2726d --- /dev/null +++ b/js/src/tests/non262/reflect-parse/newTarget.js @@ -0,0 +1,42 @@ +// |reftest| skip-if(!xulRuntime.shell) +function testNewTarget() { + + // new.target is currently valid inside any non-arrow, non-generator function + assertInFunctionExpr("new.target", newTarget()); + + // even with gratuitous whitespace. + assertInFunctionExpr(`new. + target`, newTarget()); + + // invalid in top-level scripts + assertError("new.target", SyntaxError); + + // valid in arrow functions inside functions + assertInFunctionExpr("()=>new.target", arrowExpr([], newTarget())); + assertError("(() => new.target))", SyntaxError); + + // valid in generators, too! + assertStmt("function *foo() { new.target; }", genFunDecl("es6", ident("foo"), [], + blockStmt([exprStmt(newTarget())]))); + + // new.target is a member expression. You should be able to call, invoke, or + // access properties of it. + assertInFunctionExpr("new.target.foo", dotExpr(newTarget(), ident("foo"))); + assertInFunctionExpr("new.target[\"foo\"]", memExpr(newTarget(), literal("foo"))); + + assertInFunctionExpr("new.target()", callExpr(newTarget(), [])); + assertInFunctionExpr("new new.target()", newExpr(newTarget(), [])); + + // assignment to newTarget is an error + assertError("new.target = 4", SyntaxError); + + // only new.target is a valid production, no shorn names or other names + assertError("new.", SyntaxError); + assertError("new.foo", SyntaxError); + assertError("new.targe", SyntaxError); + + // obj.new.target is still a member expression + assertExpr("obj.new.target", dotExpr(dotExpr(ident("obj"), ident("new")), ident("target"))); +} + +runtest(testNewTarget); diff --git a/js/src/tests/non262/reflect-parse/object-rest.js b/js/src/tests/non262/reflect-parse/object-rest.js new file mode 100644 index 0000000000..1c35034aa1 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/object-rest.js @@ -0,0 +1,41 @@ +// |reftest| skip-if(!xulRuntime.shell) + +function property(key, value = key, shorthand = key === value) { + return { key, value, shorthand }; +} + +function assertDestrAssign(src, pattern) { + assertExpr(`(${src} = 0)`, aExpr("=", pattern, lit(0))); +} + +function assertDestrBinding(src, pattern) { + assertDecl(`var ${src} = 0`, varDecl([{id: pattern, init: lit(0)}])); +} + +function test() { + // Target expression must be a simple assignment target in object assignment patterns. + assertDestrAssign("{...x}", objPatt([spread(ident("x"))])); + assertDestrAssign("{...(x)}", objPatt([spread(ident("x"))])); + assertDestrAssign("{...obj.p}", objPatt([spread(dotExpr(ident("obj"), ident("p")))])); + assertDestrAssign("{...(obj.p)}", objPatt([spread(dotExpr(ident("obj"), ident("p")))])); + + // Object binding patterns only allow binding identifiers. + assertDestrBinding("{...x}", objPatt([spread(ident("x"))])); + + // The rest-property can be preceded by other properties. + for (var assertDestr of [assertDestrAssign, assertDestrBinding]) { + assertDestr("{a, ...x}", objPatt([property(ident("a")), spread(ident("x"))])); + assertDestr("{a: b, ...x}", objPatt([property(ident("a"), ident("b")), spread(ident("x"))])); + assertDestr("{[a]: b, ...x}", objPatt([property(comp(ident("a")), ident("b")), spread(ident("x"))])); + } + + // Tests when __proto__ is used in the object pattern. + for (var assertDestr of [assertDestrAssign, assertDestrBinding]) { + assertDestr("{...__proto__}", objPatt([spread(ident("__proto__"))])); + assertDestr("{__proto__, ...x}", objPatt([property(ident("__proto__")), spread(ident("x"))])); + } + assertDestrAssign("{__proto__: a, ...x}", objPatt([property(lit("__proto__"), ident("a")), spread(ident("x"))])); + assertDestrBinding("{__proto__: a, ...x}", objPatt([property(ident("__proto__"), ident("a")), spread(ident("x"))])); +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/object-spread.js b/js/src/tests/non262/reflect-parse/object-spread.js new file mode 100644 index 0000000000..a4b269c409 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/object-spread.js @@ -0,0 +1,29 @@ +// |reftest| skip-if(!xulRuntime.shell) + +function property(key, value = key, shorthand = key === value) { + return { key, value, shorthand }; +} + +function test() { + // Any expression can be spreaded. + assertExpr("({...x})", objExpr([spread(ident("x"))])); + assertExpr("({...f()})", objExpr([spread(callExpr(ident("f"), []))])); + assertExpr("({...123})", objExpr([spread(lit(123))])); + + // Multiple spread expression are allowed. + assertExpr("({...x, ...obj.p})", objExpr([spread(ident("x")), spread(dotExpr(ident("obj"), ident("p")))])); + + // Spread expression can appear anywhere in an object literal. + assertExpr("({p, ...x})", objExpr([property(ident("p")), spread(ident("x"))])); + assertExpr("({p: a, ...x})", objExpr([property(ident("p"), ident("a")), spread(ident("x"))])); + assertExpr("({...x, p: a})", objExpr([spread(ident("x")), property(ident("p"), ident("a"))])); + + // Trailing comma after spread expression is allowed. + assertExpr("({...x,})", objExpr([spread(ident("x"))])); + + // __proto__ is not special in spread expressions. + assertExpr("({...__proto__})", objExpr([spread(ident("__proto__"))])); + assertExpr("({...__proto__, ...__proto__})", objExpr([spread(ident("__proto__")), spread(ident("__proto__"))])); +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/proxyArgs.js b/js/src/tests/non262/reflect-parse/proxyArgs.js new file mode 100644 index 0000000000..c615642c72 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/proxyArgs.js @@ -0,0 +1,22 @@ +// |reftest| skip-if(!xulRuntime.shell) +// |reftest| skip-if(!xulRuntime.shell) +// bug 905774 + +// Proxy options +var opts = new Proxy({loc: false}, {}); +assertEq("loc" in Reflect.parse("0;", opts), false); +opts.loc = true; +assertEq(Reflect.parse("0;", opts).loc !== null, true); +delete opts.loc; +assertEq(Reflect.parse("0;", opts).loc !== null, true); // default is true + +// Proxy builder +var builder = { + program: function (body) { return body.join(); }, + expressionStatement: function (expr) { return expr + ";" }, + literal: function (val) { return "" + val; } +}; +opts = {builder: new Proxy(builder, {})}; +assertEq(Reflect.parse("0xff;", opts), "255;"); + +reportCompare(0, 0, 'ok'); diff --git a/js/src/tests/non262/reflect-parse/shell.js b/js/src/tests/non262/reflect-parse/shell.js new file mode 100644 index 0000000000..665e3fe59d --- /dev/null +++ b/js/src/tests/non262/reflect-parse/shell.js @@ -0,0 +1,66 @@ +loadRelativeToScript('PatternAsserts.js'); + +// various combinations of identifiers and destructuring patterns: +function makePatternCombinations(id, destr) +{ + return [ + [ id(1) ], + [ id(1), id(2) ], + [ id(1), id(2), id(3) ], + [ id(1), id(2), id(3), id(4) ], + [ id(1), id(2), id(3), id(4), id(5) ], + + [ destr(1) ], + [ destr(1), destr(2) ], + [ destr(1), destr(2), destr(3) ], + [ destr(1), destr(2), destr(3), destr(4) ], + [ destr(1), destr(2), destr(3), destr(4), destr(5) ], + + [ destr(1), id(2) ], + + [ destr(1), id(2), id(3) ], + [ destr(1), id(2), id(3), id(4) ], + [ destr(1), id(2), id(3), id(4), id(5) ], + [ destr(1), id(2), id(3), id(4), destr(5) ], + [ destr(1), id(2), id(3), destr(4) ], + [ destr(1), id(2), id(3), destr(4), id(5) ], + [ destr(1), id(2), id(3), destr(4), destr(5) ], + + [ destr(1), id(2), destr(3) ], + [ destr(1), id(2), destr(3), id(4) ], + [ destr(1), id(2), destr(3), id(4), id(5) ], + [ destr(1), id(2), destr(3), id(4), destr(5) ], + [ destr(1), id(2), destr(3), destr(4) ], + [ destr(1), id(2), destr(3), destr(4), id(5) ], + [ destr(1), id(2), destr(3), destr(4), destr(5) ], + + [ id(1), destr(2) ], + + [ id(1), destr(2), id(3) ], + [ id(1), destr(2), id(3), id(4) ], + [ id(1), destr(2), id(3), id(4), id(5) ], + [ id(1), destr(2), id(3), id(4), destr(5) ], + [ id(1), destr(2), id(3), destr(4) ], + [ id(1), destr(2), id(3), destr(4), id(5) ], + [ id(1), destr(2), id(3), destr(4), destr(5) ], + + [ id(1), destr(2), destr(3) ], + [ id(1), destr(2), destr(3), id(4) ], + [ id(1), destr(2), destr(3), id(4), id(5) ], + [ id(1), destr(2), destr(3), id(4), destr(5) ], + [ id(1), destr(2), destr(3), destr(4) ], + [ id(1), destr(2), destr(3), destr(4), id(5) ], + [ id(1), destr(2), destr(3), destr(4), destr(5) ] + ]; +} + +function runtest(main) { + try { + main(); + if (typeof reportCompare === 'function') + reportCompare(true, true); + } catch (exc) { + print(exc.stack); + throw exc; + } +} diff --git a/js/src/tests/non262/reflect-parse/stackOverflow.js b/js/src/tests/non262/reflect-parse/stackOverflow.js new file mode 100644 index 0000000000..5fadbde4d8 --- /dev/null +++ b/js/src/tests/non262/reflect-parse/stackOverflow.js @@ -0,0 +1,8 @@ +// |reftest| skip-if(!xulRuntime.shell) +// Bug 632024: no crashing on stack overflow +try { + Reflect.parse(Array(3000).join("x + y - ") + "z") +} catch (e) { } + +if (typeof reportCompare === 'function') + reportCompare(true, true); diff --git a/js/src/tests/non262/reflect-parse/statements.js b/js/src/tests/non262/reflect-parse/statements.js new file mode 100644 index 0000000000..36a8b3ecea --- /dev/null +++ b/js/src/tests/non262/reflect-parse/statements.js @@ -0,0 +1,88 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// statements + +assertStmt("throw 42", throwStmt(lit(42))); +assertStmt("for (;;) break", forStmt(null, null, null, breakStmt(null))); +assertStmt("for (x; y; z) break", forStmt(ident("x"), ident("y"), ident("z"), breakStmt(null))); +assertStmt("for (var x; y; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), ident("z"), breakStmt(null))); +assertStmt("for (var x = 42; y; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), ident("z"), breakStmt(null))); +assertStmt("for (x; ; z) break", forStmt(ident("x"), null, ident("z"), breakStmt(null))); +assertStmt("for (var x; ; z) break", forStmt(varDecl([{ id: ident("x"), init: null }]), null, ident("z"), breakStmt(null))); +assertStmt("for (var x = 42; ; z) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), null, ident("z"), breakStmt(null))); +assertStmt("for (x; y; ) break", forStmt(ident("x"), ident("y"), null, breakStmt(null))); +assertStmt("for (var x; y; ) break", forStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), null, breakStmt(null))); +assertStmt("for (var x = 42; y; ) break", forStmt(varDecl([{ id: ident("x"), init: lit(42) }]), ident("y"), null, breakStmt(null))); +assertStmt("for (var x in y) break", forInStmt(varDecl([{ id: ident("x"), init: null }]), ident("y"), breakStmt(null))); +assertStmt("for (x in y) break", forInStmt(ident("x"), ident("y"), breakStmt(null))); +assertStmt("{ }", blockStmt([])); +assertStmt("{ throw 1; throw 2; throw 3; }", blockStmt([ throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))])); +assertStmt(";", emptyStmt); +assertStmt("if (foo) throw 42;", ifStmt(ident("foo"), throwStmt(lit(42)), null)); +assertStmt("if (foo) throw 42; else true;", ifStmt(ident("foo"), throwStmt(lit(42)), exprStmt(lit(true)))); +assertStmt("if (foo) { throw 1; throw 2; throw 3; }", + ifStmt(ident("foo"), + blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]), + null)); +assertStmt("if (foo) { throw 1; throw 2; throw 3; } else true;", + ifStmt(ident("foo"), + blockStmt([throwStmt(lit(1)), throwStmt(lit(2)), throwStmt(lit(3))]), + exprStmt(lit(true)))); + + +assertStmt("foo: for(;;) break foo;", labStmt(ident("foo"), forStmt(null, null, null, breakStmt(ident("foo"))))); +assertStmt("foo: for(;;) continue foo;", labStmt(ident("foo"), forStmt(null, null, null, continueStmt(ident("foo"))))); +assertStmt("with (obj) { }", withStmt(ident("obj"), blockStmt([]))); +assertStmt("with (obj) { obj; }", withStmt(ident("obj"), blockStmt([exprStmt(ident("obj"))]))); +assertStmt("while (foo) { }", whileStmt(ident("foo"), blockStmt([]))); +assertStmt("while (foo) { foo; }", whileStmt(ident("foo"), blockStmt([exprStmt(ident("foo"))]))); +assertStmt("do { } while (foo);", doStmt(blockStmt([]), ident("foo"))); +assertStmt("do { foo; } while (foo)", doStmt(blockStmt([exprStmt(ident("foo"))]), ident("foo"))); +assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; }", + switchStmt(ident("foo"), + [ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]), + caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]), + defaultClause([ exprStmt(lit(3)) ]) ])); +assertStmt("switch (foo) { case 1: 1; break; case 2: 2; break; default: 3; case 42: 42; }", + switchStmt(ident("foo"), + [ caseClause(lit(1), [ exprStmt(lit(1)), breakStmt(null) ]), + caseClause(lit(2), [ exprStmt(lit(2)), breakStmt(null) ]), + defaultClause([ exprStmt(lit(3)) ]), + caseClause(lit(42), [ exprStmt(lit(42)) ]) ])); +assertStmt("try { } catch (e) { }", + tryStmt(blockStmt([]), + catchClause(ident("e"), blockStmt([])), + null)); +assertStmt("try { } catch (e) { } finally { }", + tryStmt(blockStmt([]), + catchClause(ident("e"), blockStmt([])), + blockStmt([]))); +assertStmt("try { } finally { }", + tryStmt(blockStmt([]), + null, + blockStmt([]))); +assertStmt("try { } catch { }", + tryStmt(blockStmt([]), + catchClause(null, blockStmt([])), + null)); +assertStmt("try { } catch { } finally { }", + tryStmt(blockStmt([]), + catchClause(null, blockStmt([])), + blockStmt([]))); + + +// Bug 632028: yield outside of a function should throw +(function() { + var threw = false; + try { + Reflect.parse("yield 0"); + } catch (expected) { + threw = true; + } + assertEq(threw, true); +})(); + +} + +runtest(test); diff --git a/js/src/tests/non262/reflect-parse/templateStrings.js b/js/src/tests/non262/reflect-parse/templateStrings.js new file mode 100644 index 0000000000..fb12afd00f --- /dev/null +++ b/js/src/tests/non262/reflect-parse/templateStrings.js @@ -0,0 +1,42 @@ +// |reftest| skip-if(!xulRuntime.shell) +function test() { + +// template strings +assertStringExpr("`hey there`", literal("hey there")); +assertStringExpr("`hey\nthere`", literal("hey\nthere")); +assertExpr("`hey${\"there\"}`", templateLit([lit("hey"), lit("there"), lit("")])); +assertExpr("`hey${\"there\"}mine`", templateLit([lit("hey"), lit("there"), lit("mine")])); +assertExpr("`hey${a == 5}mine`", templateLit([lit("hey"), binExpr("==", ident("a"), lit(5)), lit("mine")])); +assertExpr("func`hey\\x`", taggedTemplate(ident("func"), template(["hey\\x"], [void 0]))); +assertExpr("func`hey${4}\\x`", taggedTemplate(ident("func"), template(["hey","\\x"], ["hey",void 0], lit(4)))); +assertExpr("`hey${`there${\"how\"}`}mine`", templateLit([lit("hey"), + templateLit([lit("there"), lit("how"), lit("")]), lit("mine")])); +assertExpr("func`hey`", taggedTemplate(ident("func"), template(["hey"], ["hey"]))); +assertExpr("func`hey${\"4\"}there`", taggedTemplate(ident("func"), + template(["hey", "there"], ["hey", "there"], lit("4")))); +assertExpr("func`hey${\"4\"}there${5}`", taggedTemplate(ident("func"), + template(["hey", "there", ""], ["hey", "there", ""], + lit("4"), lit(5)))); +assertExpr("func`hey\r\n`", taggedTemplate(ident("func"), template(["hey\n"], ["hey\n"]))); +assertExpr("func`hey${4}``${5}there``mine`", + taggedTemplate(taggedTemplate(taggedTemplate( + ident("func"), template(["hey", ""], ["hey", ""], lit(4))), + template(["", "there"], ["", "there"], lit(5))), + template(["mine"], ["mine"]))); + +// multi-line template string - line numbers +var node = Reflect.parse("`\n\n ${2}\n\n\n`"); +Pattern({loc:{start:{line:1, column:0}, end:{line:6, column:1}, source:null}, type:"Program", +body:[{loc:{start:{line:1, column:0}, end:{line:6, column:1}, source:null}, +type:"ExpressionStatement", expression:{loc:{start:{line:1, column:0}, end:{line:6, column:1}, +source:null}, type:"TemplateLiteral", elements:[{loc:{start:{line:1, column:0}, end:{line:3, +column:5}, source:null}, type:"Literal", value:"\n\n "}, {loc:{start:{line:3, column:5}, +end:{line:3, column:6}, source:null}, type:"Literal", value:2}, {loc:{start:{line:3, column:6}, +end:{line:6, column:1}, source:null}, type:"Literal", value:"\n\n\n"}]}}]}).match(node); + + +assertStringExpr("\"hey there\"", literal("hey there")); + +} + +runtest(test); |