Merge branch 'upstream' into jsx
Conflicts: acorn.js test/run.js
This commit is contained in:
commit
42d21f5064
7
.editorconfig
Normal file
7
.editorconfig
Normal file
@ -0,0 +1,7 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
120
acorn.js
120
acorn.js
@ -43,8 +43,9 @@
|
||||
input = String(inpt); inputLen = input.length;
|
||||
setOptions(opts);
|
||||
initTokenState();
|
||||
var startPos = options.locations ? [tokPos, new Position] : tokPos;
|
||||
initParserState();
|
||||
return parseTopLevel(options.program);
|
||||
return parseTopLevel(options.program || startNodeAt(startPos));
|
||||
};
|
||||
|
||||
// A second optional argument can be given to further configure
|
||||
@ -135,9 +136,9 @@
|
||||
};
|
||||
|
||||
function setOptions(opts) {
|
||||
options = opts || {};
|
||||
for (var opt in defaultOptions) if (!has(options, opt))
|
||||
options[opt] = defaultOptions[opt];
|
||||
options = {};
|
||||
for (var opt in defaultOptions)
|
||||
options[opt] = opts && has(opts, opt) ? opts[opt] : defaultOptions[opt];
|
||||
sourceFile = options.sourceFile || null;
|
||||
if (isArray(options.onToken)) {
|
||||
var tokens = options.onToken;
|
||||
@ -214,6 +215,7 @@
|
||||
input = String(inpt); inputLen = input.length;
|
||||
setOptions(opts);
|
||||
initTokenState();
|
||||
skipSpace();
|
||||
|
||||
function getToken(forceRegexp) {
|
||||
lastEnd = tokEnd;
|
||||
@ -234,6 +236,10 @@
|
||||
tokRegexpAllowed = reAllowed;
|
||||
skipSpace();
|
||||
};
|
||||
getToken.noRegexp = function() {
|
||||
tokRegexpAllowed = false;
|
||||
};
|
||||
getToken.options = options;
|
||||
return getToken;
|
||||
};
|
||||
|
||||
@ -308,6 +314,7 @@
|
||||
if (options.locations) lastEndLoc = new Position;
|
||||
inFunction = inGenerator = strict = false;
|
||||
labels = [];
|
||||
skipSpace();
|
||||
readToken();
|
||||
}
|
||||
|
||||
@ -406,8 +413,9 @@
|
||||
var _bracketL = {type: "[", beforeExpr: true}, _bracketR = {type: "]"}, _braceL = {type: "{", beforeExpr: true};
|
||||
var _braceR = {type: "}"}, _parenL = {type: "(", beforeExpr: true}, _parenR = {type: ")"};
|
||||
var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true};
|
||||
var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _ellipsis = {type: "..."}, _question = {type: "?", beforeExpr: true};
|
||||
var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _question = {type: "?", beforeExpr: true};
|
||||
var _arrow = {type: "=>", beforeExpr: true}, _bquote = {type: "`"}, _dollarBraceL = {type: "${", beforeExpr: true};
|
||||
var _ellipsis = {type: "...", prefix: true, beforeExpr: true};
|
||||
var _ltSlash = {type: "</"};
|
||||
|
||||
// Operators. These carry several kinds of properties to help the
|
||||
@ -453,8 +461,8 @@
|
||||
parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon,
|
||||
dot: _dot, ellipsis: _ellipsis, question: _question, slash: _slash, eq: _eq,
|
||||
name: _name, eof: _eof, num: _num, regexp: _regexp, string: _string,
|
||||
arrow: _arrow, bquote: _bquote, dollarBraceL: _dollarBraceL,
|
||||
xjsName: _xjsName, xjsText: _xjsText};
|
||||
arrow: _arrow, bquote: _bquote, dollarBraceL: _dollarBraceL, star: _star,
|
||||
assign: _assign, xjsName: _xjsName, xjsText: _xjsText};
|
||||
for (var kw in keywordTypes) exports.tokTypes["_" + kw] = keywordTypes[kw];
|
||||
|
||||
// This is a trick taken from Esprima. It turns out that, on
|
||||
@ -600,7 +608,6 @@
|
||||
tokRegexpAllowed = true;
|
||||
metParenL = 0;
|
||||
inTemplate = inXJSChild = inXJSTag = false;
|
||||
skipSpace();
|
||||
}
|
||||
|
||||
// Called at the end of every token. Sets `tokEnd`, `tokVal`, and
|
||||
@ -937,6 +944,10 @@
|
||||
finishToken(type, str, shouldSkipSpace);
|
||||
}
|
||||
|
||||
var regexpUnicodeSupport = false;
|
||||
try { new RegExp("\uffff", "u"); regexpUnicodeSupport = true; }
|
||||
catch(e) {}
|
||||
|
||||
// Parse a regular expression. Some context-awareness is necessary,
|
||||
// since a '/' inside a '[]' set does not end the expression.
|
||||
|
||||
@ -959,14 +970,36 @@
|
||||
// Need to use `readWord1` because '\uXXXX' sequences are allowed
|
||||
// here (don't ask).
|
||||
var mods = readWord1();
|
||||
if (mods && !/^[gmsiy]*$/.test(mods)) raise(start, "Invalid regular expression flag");
|
||||
var tmp = content;
|
||||
if (mods) {
|
||||
var validFlags = /^[gmsiy]*$/;
|
||||
if (options.ecmaVersion >= 6) validFlags = /^[gmsiyu]*$/;
|
||||
if (!validFlags.test(mods)) raise(start, "Invalid regular expression flag");
|
||||
if (mods.indexOf('u') >= 0 && !regexpUnicodeSupport) {
|
||||
// Replace each astral symbol and every Unicode code point
|
||||
// escape sequence that represents such a symbol with a single
|
||||
// ASCII symbol to avoid throwing on regular expressions that
|
||||
// are only valid in combination with the `/u` flag.
|
||||
tmp = tmp
|
||||
.replace(/\\u\{([0-9a-fA-F]{5,6})\}/g, "x")
|
||||
.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g, "x");
|
||||
}
|
||||
}
|
||||
// Detect invalid regular expressions.
|
||||
try {
|
||||
var value = new RegExp(content, mods);
|
||||
new RegExp(tmp);
|
||||
} catch (e) {
|
||||
if (e instanceof SyntaxError) raise(start, "Error parsing regular expression: " + e.message);
|
||||
raise(e);
|
||||
}
|
||||
return finishToken(_regexp, value);
|
||||
// Get a regular expression object for this pattern-flag pair, or `null` in
|
||||
// case the current environment doesn't support the flags it uses.
|
||||
try {
|
||||
var value = new RegExp(content, mods);
|
||||
} catch (err) {
|
||||
value = null;
|
||||
}
|
||||
return finishToken(_regexp, {pattern: content, flags: mods, value: value});
|
||||
}
|
||||
|
||||
// Read an integer in the given radix. Return null if zero digits
|
||||
@ -1764,7 +1797,7 @@
|
||||
// strict mode, init properties are also not allowed to be repeated.
|
||||
|
||||
function checkPropClash(prop, propHash) {
|
||||
if (prop.computed) return;
|
||||
if (options.ecmaVersion >= 6) return;
|
||||
var key = prop.key, name;
|
||||
switch (key.type) {
|
||||
case "Identifier": name = key.name; break;
|
||||
@ -1834,15 +1867,19 @@
|
||||
// `program` argument. If present, the statements will be appended
|
||||
// to its body instead of creating a new node.
|
||||
|
||||
function parseTopLevel(program) {
|
||||
var node = program || startNode(), first = true;
|
||||
if (!program) node.body = [];
|
||||
function parseTopLevel(node) {
|
||||
var first = true;
|
||||
if (!node.body) node.body = [];
|
||||
while (tokType !== _eof) {
|
||||
var stmt = parseStatement();
|
||||
node.body.push(stmt);
|
||||
if (first && isUseStrict(stmt)) setStrict(true);
|
||||
first = false;
|
||||
}
|
||||
|
||||
lastStart = tokStart;
|
||||
lastEnd = tokEnd;
|
||||
lastEndLoc = tokEndLoc;
|
||||
return finishNode(node, "Program");
|
||||
}
|
||||
|
||||
@ -2279,9 +2316,14 @@
|
||||
|
||||
function parseMaybeUnary() {
|
||||
if (tokType.prefix) {
|
||||
var node = startNode(), update = tokType.isUpdate;
|
||||
var node = startNode(), update = tokType.isUpdate, nodeType;
|
||||
if (tokType === _ellipsis) {
|
||||
nodeType = "SpreadElement";
|
||||
} else {
|
||||
nodeType = update ? "UpdateExpression" : "UnaryExpression";
|
||||
node.operator = tokVal;
|
||||
node.prefix = true;
|
||||
}
|
||||
tokRegexpAllowed = true;
|
||||
next();
|
||||
node.argument = parseMaybeUnary();
|
||||
@ -2289,7 +2331,7 @@
|
||||
else if (strict && node.operator === "delete" &&
|
||||
node.argument.type === "Identifier")
|
||||
raise(node.start, "Deleting local variable in strict mode");
|
||||
return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
|
||||
return finishNode(node, nodeType);
|
||||
}
|
||||
var start = storeCurrentPos();
|
||||
var expr = parseExprSubscripts();
|
||||
@ -2362,7 +2404,15 @@
|
||||
}
|
||||
return id;
|
||||
|
||||
case _num: case _string: case _regexp: case _xjsText:
|
||||
case _regexp:
|
||||
var node = startNode();
|
||||
node.regex = {pattern: tokVal.pattern, flags: tokVal.flags};
|
||||
node.value = tokVal.value;
|
||||
node.raw = input.slice(tokStart, tokEnd);
|
||||
next();
|
||||
return finishNode(node, "Literal");
|
||||
|
||||
case _num: case _string: case _xjsText:
|
||||
var node = startNode();
|
||||
node.value = tokVal;
|
||||
node.raw = input.slice(tokStart, tokEnd);
|
||||
@ -2378,10 +2428,10 @@
|
||||
|
||||
case _parenL:
|
||||
var start = storeCurrentPos();
|
||||
var tokStartLoc1 = tokStartLoc, tokStart1 = tokStart, val, exprList;
|
||||
var val, exprList;
|
||||
next();
|
||||
// check whether this is generator comprehension or regular expression
|
||||
if (options.ecmaVersion >= 6 && tokType === _for) {
|
||||
if (options.ecmaVersion >= 7 && tokType === _for) {
|
||||
val = parseComprehension(startNodeAt(start), true);
|
||||
} else {
|
||||
var oldParenL = ++metParenL;
|
||||
@ -2418,7 +2468,7 @@
|
||||
var node = startNode();
|
||||
next();
|
||||
// check whether this is array comprehension or regular array
|
||||
if (options.ecmaVersion >= 6 && tokType === _for) {
|
||||
if (options.ecmaVersion >= 7 && tokType === _for) {
|
||||
return parseComprehension(node, false);
|
||||
}
|
||||
node.elements = parseExprList(_bracketR, true, true);
|
||||
@ -2438,9 +2488,6 @@
|
||||
case _new:
|
||||
return parseNew();
|
||||
|
||||
case _ellipsis:
|
||||
return parseSpread();
|
||||
|
||||
case _bquote:
|
||||
return parseTemplate();
|
||||
|
||||
@ -2466,15 +2513,6 @@
|
||||
return finishNode(node, "NewExpression");
|
||||
}
|
||||
|
||||
// Parse spread element '...expr'
|
||||
|
||||
function parseSpread() {
|
||||
var node = startNode();
|
||||
next();
|
||||
node.argument = parseExpression(true);
|
||||
return finishNode(node, "SpreadElement");
|
||||
}
|
||||
|
||||
// Parse template expression.
|
||||
|
||||
function parseTemplate() {
|
||||
@ -2715,7 +2753,7 @@
|
||||
next();
|
||||
node.id = tokType === _name ? parseIdent() : isStatement ? unexpected() : null;
|
||||
node.superClass = eat(_extends) ? parseExpression() : null;
|
||||
var classBody = startNode(), methodHash = {}, staticMethodHash = {};
|
||||
var classBody = startNode();
|
||||
classBody.body = [];
|
||||
expect(_braceL);
|
||||
while (!eat(_braceR)) {
|
||||
@ -2728,7 +2766,7 @@
|
||||
}
|
||||
var isGenerator = eat(_star);
|
||||
parsePropertyName(method);
|
||||
if (tokType === _name && !method.computed && method.key.type === "Identifier" &&
|
||||
if (tokType !== _parenL && !method.computed && method.key.type === "Identifier" &&
|
||||
(method.key.name === "get" || method.key.name === "set")) {
|
||||
if (isGenerator) unexpected();
|
||||
method.kind = method.key.name;
|
||||
@ -2737,7 +2775,6 @@
|
||||
method.kind = "";
|
||||
}
|
||||
method.value = parseMethod(isGenerator);
|
||||
checkPropClash(method, method['static'] ? staticMethodHash : methodHash);
|
||||
classBody.body.push(finishNode(method, "MethodDefinition"));
|
||||
eat(_semi);
|
||||
}
|
||||
@ -2809,8 +2846,8 @@
|
||||
node.source = null;
|
||||
semicolon();
|
||||
} else {
|
||||
// export * from '...'
|
||||
// export { x, y as z } [from '...']
|
||||
// export * from '...';
|
||||
// export { x, y as z } [from '...'];
|
||||
var isBatch = tokType === _star;
|
||||
node.declaration = null;
|
||||
node['default'] = false;
|
||||
@ -2822,6 +2859,7 @@
|
||||
if (isBatch) unexpected();
|
||||
node.source = null;
|
||||
}
|
||||
semicolon();
|
||||
}
|
||||
return finishNode(node, "ExportDeclaration");
|
||||
}
|
||||
@ -2845,7 +2883,7 @@
|
||||
} else first = false;
|
||||
|
||||
var node = startNode();
|
||||
node.id = parseIdent();
|
||||
node.id = parseIdent(tokType === _default);
|
||||
if (tokType === _name && tokVal === "as") {
|
||||
next();
|
||||
node.name = parseIdent(true);
|
||||
@ -2876,6 +2914,7 @@
|
||||
// (it doesn't support mixed default + named yet)
|
||||
node.kind = node.specifiers[0]['default'] ? "default" : "named";
|
||||
}
|
||||
semicolon();
|
||||
return finishNode(node, "ImportDeclaration");
|
||||
}
|
||||
|
||||
@ -3134,7 +3173,8 @@
|
||||
inXJSTag = false;
|
||||
|
||||
next();
|
||||
var node = parseSpread();
|
||||
if (tokType !== _ellipsis) unexpected();
|
||||
var node = parseMaybeUnary();
|
||||
|
||||
inXJSTag = origInXJSTag;
|
||||
|
||||
|
||||
450
acorn_loose.js
450
acorn_loose.js
@ -40,14 +40,14 @@
|
||||
|
||||
var options, input, fetchToken, context;
|
||||
|
||||
acorn.defaultOptions.tabSize = 4;
|
||||
|
||||
exports.parse_dammit = function(inpt, opts) {
|
||||
if (!opts) opts = {};
|
||||
input = String(inpt);
|
||||
if (/^#!.*/.test(input)) input = "//" + input.slice(2);
|
||||
|
||||
options = opts;
|
||||
if (!opts.tabSize) opts.tabSize = 4;
|
||||
fetchToken = acorn.tokenize(input, opts);
|
||||
options = fetchToken.options;
|
||||
sourceFile = options.sourceFile || null;
|
||||
context = [];
|
||||
nextLineStart = 0;
|
||||
@ -59,15 +59,14 @@
|
||||
var lastEnd, token = {start: 0, end: 0}, ahead = [];
|
||||
var curLineStart, nextLineStart, curIndent, lastEndLoc, sourceFile;
|
||||
|
||||
function next() {
|
||||
function next(forceRegexp) {
|
||||
lastEnd = token.end;
|
||||
if (options.locations)
|
||||
lastEndLoc = token.endLoc;
|
||||
if (forceRegexp)
|
||||
ahead.length = 0;
|
||||
|
||||
if (ahead.length)
|
||||
token = ahead.shift();
|
||||
else
|
||||
token = readToken();
|
||||
token = ahead.shift() || readToken(forceRegexp);
|
||||
|
||||
if (token.start >= nextLineStart) {
|
||||
while (token.start >= nextLineStart) {
|
||||
@ -78,10 +77,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
function readToken() {
|
||||
function readToken(forceRegexp) {
|
||||
for (;;) {
|
||||
try {
|
||||
return fetchToken();
|
||||
var tok = fetchToken(forceRegexp);
|
||||
if (tok.type === tt.dot && input.substr(tok.end, 1) === '.') {
|
||||
tok = fetchToken();
|
||||
tok.start--;
|
||||
tok.type = tt.ellipsis;
|
||||
}
|
||||
return tok;
|
||||
} catch(e) {
|
||||
if (!(e instanceof SyntaxError)) throw e;
|
||||
|
||||
@ -256,6 +261,8 @@
|
||||
if (token.type === type) {
|
||||
next();
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -263,7 +270,7 @@
|
||||
return (token.type === tt.eof || token.type === tt.braceR || newline.test(input.slice(lastEnd, token.start)));
|
||||
}
|
||||
function semicolon() {
|
||||
eat(tt.semi);
|
||||
return eat(tt.semi);
|
||||
}
|
||||
|
||||
function expect(type) {
|
||||
@ -279,26 +286,45 @@
|
||||
}
|
||||
|
||||
function checkLVal(expr) {
|
||||
if (expr.type === "Identifier" || expr.type === "MemberExpression") return expr;
|
||||
return dummyIdent();
|
||||
if (!expr) return expr;
|
||||
switch (expr.type) {
|
||||
case "Identifier":
|
||||
case "MemberExpression":
|
||||
case "ObjectPattern":
|
||||
case "ArrayPattern":
|
||||
case "SpreadElement":
|
||||
return expr;
|
||||
|
||||
default:
|
||||
return dummyIdent();
|
||||
}
|
||||
}
|
||||
|
||||
function parseTopLevel() {
|
||||
var node = startNode();
|
||||
var node = startNodeAt(options.locations ? [0, acorn.getLineInfo(input, 0)] : 0);
|
||||
node.body = [];
|
||||
while (token.type !== tt.eof) node.body.push(parseStatement());
|
||||
lastEnd = token.end;
|
||||
lastEndLoc = token.endLoc;
|
||||
return finishNode(node, "Program");
|
||||
}
|
||||
|
||||
function parseStatement() {
|
||||
if (token.type === tt.slash || token.type === tt.assign && token.value === "/=")
|
||||
next(true);
|
||||
|
||||
var starttype = token.type, node = startNode();
|
||||
|
||||
switch (starttype) {
|
||||
case tt._break: case tt._continue:
|
||||
next();
|
||||
var isBreak = starttype === tt._break;
|
||||
node.label = token.type === tt.name ? parseIdent() : null;
|
||||
semicolon();
|
||||
if (semicolon() || canInsertSemicolon()) {
|
||||
node.label = null;
|
||||
} else {
|
||||
node.label = token.type === tt.name ? parseIdent() : null;
|
||||
semicolon();
|
||||
}
|
||||
return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
|
||||
|
||||
case tt._debugger:
|
||||
@ -318,16 +344,17 @@
|
||||
pushCx();
|
||||
expect(tt.parenL);
|
||||
if (token.type === tt.semi) return parseFor(node, null);
|
||||
if (token.type === tt._var) {
|
||||
var init = startNode();
|
||||
next();
|
||||
parseVar(init, true);
|
||||
if (init.declarations.length === 1 && eat(tt._in))
|
||||
if (token.type === tt._var || token.type === tt._let) {
|
||||
var init = parseVar(true);
|
||||
if (init.declarations.length === 1 && (token.type === tt._in || token.type === tt.name && token.value === "of")) {
|
||||
return parseForIn(node, init);
|
||||
}
|
||||
return parseFor(node, init);
|
||||
}
|
||||
var init = parseExpression(false, true);
|
||||
if (eat(tt._in)) {return parseForIn(node, checkLVal(init));}
|
||||
if (token.type === tt._in || token.type === tt.name && token.value === "of") {
|
||||
return parseForIn(node, checkLVal(init));
|
||||
}
|
||||
return parseFor(node, init);
|
||||
|
||||
case tt._function:
|
||||
@ -404,9 +431,9 @@
|
||||
return finishNode(node, "TryStatement");
|
||||
|
||||
case tt._var:
|
||||
next();
|
||||
node = parseVar(node);
|
||||
return node;
|
||||
case tt._let:
|
||||
case tt._const:
|
||||
return parseVar();
|
||||
|
||||
case tt._while:
|
||||
next();
|
||||
@ -427,6 +454,15 @@
|
||||
next();
|
||||
return finishNode(node, "EmptyStatement");
|
||||
|
||||
case tt._class:
|
||||
return parseObj(true, true);
|
||||
|
||||
case tt._import:
|
||||
return parseImport();
|
||||
|
||||
case tt._export:
|
||||
return parseExport();
|
||||
|
||||
default:
|
||||
var expr = parseExpression();
|
||||
if (isDummy(expr)) {
|
||||
@ -470,24 +506,27 @@
|
||||
}
|
||||
|
||||
function parseForIn(node, init) {
|
||||
var type = token.type === tt._in ? "ForInStatement" : "ForOfStatement";
|
||||
next();
|
||||
node.left = init;
|
||||
node.right = parseExpression();
|
||||
popCx();
|
||||
expect(tt.parenR);
|
||||
node.body = parseStatement();
|
||||
return finishNode(node, "ForInStatement");
|
||||
return finishNode(node, type);
|
||||
}
|
||||
|
||||
function parseVar(node, noIn) {
|
||||
function parseVar(noIn) {
|
||||
var node = startNode();
|
||||
node.kind = token.type.keyword;
|
||||
next();
|
||||
node.declarations = [];
|
||||
node.kind = "var";
|
||||
while (token.type === tt.name) {
|
||||
do {
|
||||
var decl = startNode();
|
||||
decl.id = parseIdent();
|
||||
decl.id = options.ecmaVersion >= 6 ? toAssignable(parseExprAtom()) : parseIdent();
|
||||
decl.init = eat(tt.eq) ? parseExpression(true, noIn) : null;
|
||||
node.declarations.push(finishNode(decl, "VariableDeclarator"));
|
||||
if (!eat(tt.comma)) break;
|
||||
}
|
||||
} while (eat(tt.comma));
|
||||
if (!node.declarations.length) {
|
||||
var decl = startNode();
|
||||
decl.id = dummyIdent();
|
||||
@ -524,7 +563,7 @@
|
||||
if (token.type.isAssign) {
|
||||
var node = startNodeAt(start);
|
||||
node.operator = token.value;
|
||||
node.left = checkLVal(left);
|
||||
node.left = token.type === tt.eq ? toAssignable(left) : checkLVal(left);
|
||||
next();
|
||||
node.right = parseMaybeAssign(noIn);
|
||||
return finishNode(node, "AssignmentExpression");
|
||||
@ -575,13 +614,20 @@
|
||||
|
||||
function parseMaybeUnary(noIn) {
|
||||
if (token.type.prefix) {
|
||||
var node = startNode(), update = token.type.isUpdate;
|
||||
var node = startNode(), update = token.type.isUpdate, nodeType;
|
||||
if (token.type === tt.ellipsis) {
|
||||
nodeType = "SpreadElement";
|
||||
} else {
|
||||
nodeType = update ? "UpdateExpression" : "UnaryExpression";
|
||||
node.operator = token.value;
|
||||
node.prefix = true;
|
||||
}
|
||||
node.operator = token.value;
|
||||
node.prefix = true;
|
||||
next();
|
||||
node.argument = parseMaybeUnary(noIn);
|
||||
if (update) node.argument = checkLVal(node.argument);
|
||||
return finishNode(node, update ? "UpdateExpression" : "UnaryExpression");
|
||||
return finishNode(node, nodeType);
|
||||
}
|
||||
var start = storeCurrentPos();
|
||||
var expr = parseExprSubscripts();
|
||||
@ -647,9 +693,22 @@
|
||||
var node = startNode();
|
||||
next();
|
||||
return finishNode(node, "ThisExpression");
|
||||
|
||||
case tt.name:
|
||||
return parseIdent();
|
||||
case tt.num: case tt.string: case tt.regexp:
|
||||
var start = storeCurrentPos();
|
||||
var id = parseIdent();
|
||||
return eat(tt.arrow) ? parseArrowExpression(startNodeAt(start), [id]) : id;
|
||||
|
||||
case tt.regexp:
|
||||
var node = startNode();
|
||||
var val = token.value;
|
||||
node.regex = {pattern: val.pattern, flags: val.flags};
|
||||
node.value = val.value;
|
||||
node.raw = input.slice(token.start, token.end);
|
||||
next();
|
||||
return finishNode(node, "Literal");
|
||||
|
||||
case tt.num: case tt.string:
|
||||
var node = startNode();
|
||||
node.value = token.value;
|
||||
node.raw = input.slice(token.start, token.end);
|
||||
@ -664,20 +723,32 @@
|
||||
return finishNode(node, "Literal");
|
||||
|
||||
case tt.parenL:
|
||||
var start = storeCurrentPos();
|
||||
next();
|
||||
var val = parseExpression();
|
||||
expect(tt.parenR);
|
||||
if (eat(tt.arrow)) {
|
||||
return parseArrowExpression(startNodeAt(start), val.expressions || (isDummy(val) ? [] : [val]));
|
||||
}
|
||||
if (options.preserveParens) {
|
||||
var par = startNodeAt(start);
|
||||
par.expression = val;
|
||||
val = finishNode(par, "ParenthesizedExpression");
|
||||
}
|
||||
return val;
|
||||
|
||||
case tt.bracketL:
|
||||
var node = startNode();
|
||||
pushCx();
|
||||
node.elements = parseExprList(tt.bracketR);
|
||||
node.elements = parseExprList(tt.bracketR, true);
|
||||
return finishNode(node, "ArrayExpression");
|
||||
|
||||
case tt.braceL:
|
||||
return parseObj();
|
||||
|
||||
case tt._class:
|
||||
return parseObj(true);
|
||||
|
||||
case tt._function:
|
||||
var node = startNode();
|
||||
next();
|
||||
@ -686,6 +757,18 @@
|
||||
case tt._new:
|
||||
return parseNew();
|
||||
|
||||
case tt._yield:
|
||||
var node = startNode();
|
||||
next();
|
||||
if (semicolon() || canInsertSemicolon()) {
|
||||
node.delegate = false;
|
||||
node.argument = null;
|
||||
} else {
|
||||
node.delegate = eat(tt.star);
|
||||
node.argument = parseExpression(true);
|
||||
}
|
||||
return finishNode(node, "YieldExpression");
|
||||
|
||||
default:
|
||||
return dummyIdent();
|
||||
}
|
||||
@ -705,41 +788,92 @@
|
||||
return finishNode(node, "NewExpression");
|
||||
}
|
||||
|
||||
function parseObj() {
|
||||
function parseObj(isClass, isStatement) {
|
||||
var node = startNode();
|
||||
node.properties = [];
|
||||
if (isClass) {
|
||||
next();
|
||||
if (token.type === tt.name) node.id = parseIdent();
|
||||
else if (isStatement) node.id = dummyIdent();
|
||||
node.superClass = eat(tt._extends) ? parseExpression() : null;
|
||||
node.body = startNode();
|
||||
node.body.body = [];
|
||||
} else {
|
||||
node.properties = [];
|
||||
}
|
||||
pushCx();
|
||||
var indent = curIndent + 1, line = curLineStart;
|
||||
next();
|
||||
eat(tt.braceL);
|
||||
if (curIndent + 1 < indent) { indent = curIndent; line = curLineStart; }
|
||||
while (!closes(tt.braceR, indent, line)) {
|
||||
var name = parsePropertyName();
|
||||
if (!name) { if (isDummy(parseExpression(true))) next(); eat(tt.comma); continue; }
|
||||
var prop = startNode();
|
||||
prop.key = name;
|
||||
if (eat(tt.colon)) {
|
||||
prop.value = parseExpression(true);
|
||||
var prop = startNode(), isGenerator;
|
||||
if (options.ecmaVersion >= 6) {
|
||||
if (isClass) {
|
||||
if (prop['static'] = (token.type === tt.name && token.value === "static")) next();
|
||||
} else {
|
||||
prop.method = false;
|
||||
prop.shorthand = false;
|
||||
}
|
||||
isGenerator = eat(tt.star);
|
||||
}
|
||||
parsePropertyName(prop);
|
||||
if (isDummy(prop.key)) { if (isDummy(parseExpression(true))) next(); eat(tt.comma); continue; }
|
||||
if (!isClass && eat(tt.colon)) {
|
||||
prop.kind = "init";
|
||||
prop.value = parseExpression(true);
|
||||
} else if (options.ecmaVersion >= 6 && (token.type === tt.parenL || token.type === tt.braceL)) {
|
||||
if (isClass) {
|
||||
prop.kind = "";
|
||||
} else {
|
||||
prop.kind = "init";
|
||||
prop.method = true;
|
||||
}
|
||||
prop.value = parseMethod(isGenerator);
|
||||
} else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" &&
|
||||
(prop.key.name === "get" || prop.key.name === "set")) {
|
||||
prop.kind = prop.key.name;
|
||||
prop.key = parsePropertyName() || dummyIdent();
|
||||
prop.value = parseFunction(startNode(), false);
|
||||
parsePropertyName(prop);
|
||||
prop.value = parseMethod(false);
|
||||
} else if (isClass) {
|
||||
prop.kind = "";
|
||||
prop.value = parseMethod(isGenerator);
|
||||
} else {
|
||||
prop.value = dummyIdent();
|
||||
prop.kind = "init";
|
||||
prop.value = options.ecmaVersion >= 6 ? prop.key : dummyIdent();
|
||||
prop.shorthand = true;
|
||||
}
|
||||
|
||||
node.properties.push(finishNode(prop, "Property"));
|
||||
eat(tt.comma);
|
||||
if (isClass) {
|
||||
node.body.body.push(finishNode(prop, "MethodDefinition"));
|
||||
semicolon();
|
||||
} else {
|
||||
node.properties.push(finishNode(prop, "Property"));
|
||||
eat(tt.comma);
|
||||
}
|
||||
}
|
||||
popCx();
|
||||
eat(tt.braceR);
|
||||
return finishNode(node, "ObjectExpression");
|
||||
if (isClass) {
|
||||
semicolon();
|
||||
finishNode(node.body, "ClassBody");
|
||||
return finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
|
||||
} else {
|
||||
return finishNode(node, "ObjectExpression");
|
||||
}
|
||||
}
|
||||
|
||||
function parsePropertyName() {
|
||||
if (token.type === tt.num || token.type === tt.string) return parseExprAtom();
|
||||
if (token.type === tt.name || token.type.keyword) return parseIdent();
|
||||
function parsePropertyName(prop) {
|
||||
if (options.ecmaVersion >= 6) {
|
||||
if (eat(tt.bracketL)) {
|
||||
prop.computed = true;
|
||||
prop.key = parseExpression();
|
||||
expect(tt.bracketR);
|
||||
return;
|
||||
} else {
|
||||
prop.computed = false;
|
||||
}
|
||||
}
|
||||
var key = (token.type === tt.num || token.type === tt.string) ? parseExprAtom() : parseIdent();
|
||||
prop.key = key || dummyIdent();
|
||||
}
|
||||
|
||||
function parsePropertyAccessor() {
|
||||
@ -749,32 +883,212 @@
|
||||
function parseIdent() {
|
||||
var node = startNode();
|
||||
node.name = token.type === tt.name ? token.value : token.type.keyword;
|
||||
fetchToken.noRegexp();
|
||||
next();
|
||||
return finishNode(node, "Identifier");
|
||||
}
|
||||
|
||||
function initFunction(node) {
|
||||
node.id = null;
|
||||
node.params = [];
|
||||
if (options.ecmaVersion >= 6) {
|
||||
node.defaults = [];
|
||||
node.rest = null;
|
||||
node.generator = false;
|
||||
node.expression = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert existing expression atom to assignable pattern
|
||||
// if possible.
|
||||
|
||||
function toAssignable(node) {
|
||||
if (options.ecmaVersion >= 6 && node) {
|
||||
switch (node.type) {
|
||||
case "ObjectExpression":
|
||||
node.type = "ObjectPattern";
|
||||
var props = node.properties;
|
||||
for (var i = 0; i < props.length; i++) {
|
||||
props[i].value = toAssignable(props[i].value);
|
||||
}
|
||||
break;
|
||||
|
||||
case "ArrayExpression":
|
||||
node.type = "ArrayPattern";
|
||||
var elms = node.elements;
|
||||
for (var i = 0; i < elms.length; i++) {
|
||||
elms[i] = toAssignable(elms[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case "SpreadElement":
|
||||
node.argument = toAssignable(node.argument);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return checkLVal(node);
|
||||
}
|
||||
|
||||
function parseFunctionParams(node, params) {
|
||||
var defaults = [], hasDefaults = false;
|
||||
|
||||
if (!params) {
|
||||
pushCx();
|
||||
params = parseExprList(tt.parenR);
|
||||
}
|
||||
for (var i = 0; i < params.length; i++) {
|
||||
var param = params[i], defValue = null;
|
||||
if (param.type === "AssignmentExpression") {
|
||||
defValue = param.right;
|
||||
param = param.left;
|
||||
}
|
||||
param = toAssignable(param);
|
||||
if (param.type === "SpreadElement") {
|
||||
param = param.argument;
|
||||
if (i === params.length - 1) {
|
||||
node.rest = param;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
node.params.push(param);
|
||||
defaults.push(defValue);
|
||||
if (defValue) hasDefaults = true;
|
||||
}
|
||||
|
||||
if (hasDefaults) node.defaults = defaults;
|
||||
}
|
||||
|
||||
function parseFunction(node, isStatement) {
|
||||
initFunction(node);
|
||||
if (options.ecmaVersion >= 6) {
|
||||
node.generator = eat(tt.star);
|
||||
}
|
||||
if (token.type === tt.name) node.id = parseIdent();
|
||||
else if (isStatement) node.id = dummyIdent();
|
||||
else node.id = null;
|
||||
node.params = [];
|
||||
pushCx();
|
||||
expect(tt.parenL);
|
||||
while (token.type == tt.name) {
|
||||
node.params.push(parseIdent());
|
||||
eat(tt.comma);
|
||||
}
|
||||
popCx();
|
||||
eat(tt.parenR);
|
||||
parseFunctionParams(node);
|
||||
node.body = parseBlock();
|
||||
return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
|
||||
}
|
||||
|
||||
function parseExprList(close) {
|
||||
function parseMethod(isGenerator) {
|
||||
var node = startNode();
|
||||
initFunction(node);
|
||||
parseFunctionParams(node);
|
||||
node.generator = isGenerator || false;
|
||||
node.expression = options.ecmaVersion >= 6 && token.type !== tt.braceL;
|
||||
node.body = node.expression ? parseExpression(true) : parseBlock();
|
||||
return finishNode(node, "FunctionExpression");
|
||||
}
|
||||
|
||||
function parseArrowExpression(node, params) {
|
||||
initFunction(node);
|
||||
parseFunctionParams(node, params);
|
||||
node.expression = token.type !== tt.braceL;
|
||||
node.body = node.expression ? parseExpression(true) : parseBlock();
|
||||
return finishNode(node, "ArrowFunctionExpression");
|
||||
}
|
||||
|
||||
function parseExport() {
|
||||
var node = startNode();
|
||||
next();
|
||||
node['default'] = eat(tt._default);
|
||||
node.specifiers = node.source = null;
|
||||
if (node['default']) {
|
||||
node.declaration = parseExpression();
|
||||
semicolon();
|
||||
} else if (token.type.keyword) {
|
||||
node.declaration = parseStatement();
|
||||
} else {
|
||||
node.declaration = null;
|
||||
parseSpecifierList(node, "Export");
|
||||
}
|
||||
semicolon();
|
||||
return finishNode(node, "ExportDeclaration");
|
||||
}
|
||||
|
||||
function parseImport() {
|
||||
var node = startNode();
|
||||
next();
|
||||
if (token.type === tt.string) {
|
||||
node.specifiers = [];
|
||||
node.source = parseExprAtom();
|
||||
node.kind = '';
|
||||
} else {
|
||||
if (token.type === tt.name && token.value !== "from") {
|
||||
var elt = startNode();
|
||||
elt.id = parseIdent();
|
||||
elt.name = null;
|
||||
elt['default'] = true;
|
||||
finishNode(elt, "ImportSpecifier");
|
||||
eat(tt.comma);
|
||||
}
|
||||
parseSpecifierList(node, "Import");
|
||||
var specs = node.specifiers;
|
||||
for (var i = 0; i < specs.length; i++) specs[i]['default'] = false;
|
||||
if (elt) node.specifiers.unshift(elt);
|
||||
}
|
||||
semicolon();
|
||||
return finishNode(node, "ImportDeclaration");
|
||||
}
|
||||
|
||||
function parseSpecifierList(node, prefix) {
|
||||
var elts = node.specifiers = [];
|
||||
if (token.type === tt.star) {
|
||||
var elt = startNode();
|
||||
next();
|
||||
if (token.type === tt.name && token.value === "as") {
|
||||
next();
|
||||
elt.name = parseIdent();
|
||||
}
|
||||
elts.push(finishNode(elt, prefix + "BatchSpecifier"));
|
||||
} else {
|
||||
var indent = curIndent, line = curLineStart, continuedLine = nextLineStart;
|
||||
pushCx();
|
||||
eat(tt.braceL);
|
||||
if (curLineStart > continuedLine) continuedLine = curLineStart;
|
||||
while (!closes(tt.braceR, indent + (curLineStart <= continuedLine ? 1 : 0), line)) {
|
||||
var elt = startNode();
|
||||
if (token.type === tt.star) {
|
||||
next();
|
||||
if (token.type === tt.name && token.value === "as") {
|
||||
next();
|
||||
elt.name = parseIdent();
|
||||
}
|
||||
finishNode(elt, prefix + "BatchSpecifier");
|
||||
} else {
|
||||
if (token.type === tt.name && token.value === "from") break;
|
||||
elt.id = parseIdent();
|
||||
if (token.type === tt.name && token.value === "as") {
|
||||
next();
|
||||
elt.name = parseIdent();
|
||||
} else {
|
||||
elt.name = null;
|
||||
}
|
||||
finishNode(elt, prefix + "Specifier");
|
||||
}
|
||||
elts.push(elt);
|
||||
eat(tt.comma);
|
||||
}
|
||||
eat(tt.braceR);
|
||||
popCx();
|
||||
}
|
||||
if (token.type === tt.name && token.value === "from") {
|
||||
next();
|
||||
node.source = parseExprAtom();
|
||||
} else {
|
||||
node.source = null;
|
||||
}
|
||||
}
|
||||
|
||||
function parseExprList(close, allowEmpty) {
|
||||
var indent = curIndent, line = curLineStart, elts = [], continuedLine = nextLineStart;
|
||||
next(); // Opening bracket
|
||||
if (curLineStart > continuedLine) continuedLine = curLineStart;
|
||||
while (!closes(close, indent + (curLineStart <= continuedLine ? 1 : 0), line)) {
|
||||
if (eat(tt.comma)) {
|
||||
elts.push(allowEmpty ? null : dummyIdent());
|
||||
continue;
|
||||
}
|
||||
var elt = parseExpression(true);
|
||||
if (isDummy(elt)) {
|
||||
if (closes(close, indent, line)) break;
|
||||
@ -782,7 +1096,7 @@
|
||||
} else {
|
||||
elts.push(elt);
|
||||
}
|
||||
while (eat(tt.comma)) {}
|
||||
eat(tt.comma);
|
||||
}
|
||||
popCx();
|
||||
eat(close);
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
(function(exports) {
|
||||
var tests = [];
|
||||
var acorn = typeof require == "undefined" ? window.acorn : require("../acorn.js");
|
||||
|
||||
exports.test = function(code, ast, options, comments) {
|
||||
tests.push({code: code, ast: ast, options: options, comments: comments});
|
||||
exports.test = function(code, ast, options) {
|
||||
tests.push({code: code, ast: ast, options: options});
|
||||
};
|
||||
exports.testFail = function(code, message, options) {
|
||||
tests.push({code: code, error: message, options: options});
|
||||
@ -12,30 +11,29 @@
|
||||
tests.push({code: code, assert: assert, options: options});
|
||||
};
|
||||
|
||||
exports.runTests = function(callback) {
|
||||
var comments;
|
||||
|
||||
function onComment(block, text, start, end, startLoc, endLoc) {
|
||||
comments.push({
|
||||
block: block,
|
||||
text: text,
|
||||
start: start,
|
||||
end: end,
|
||||
startLoc: { line: startLoc.line, column: startLoc.column },
|
||||
endLoc: { line: endLoc.line, column: endLoc.column }
|
||||
});
|
||||
}
|
||||
|
||||
var opts = {locations: true, onComment: onComment};
|
||||
exports.runTests = function(config, callback) {
|
||||
var parse = config.parse;
|
||||
|
||||
for (var i = 0; i < tests.length; ++i) {
|
||||
var test = tests[i];
|
||||
if (config.filter && !config.filter(test)) continue;
|
||||
try {
|
||||
comments = [];
|
||||
if (test.options && !test.options.onComment) test.options.onComment = onComment;
|
||||
var ast = acorn.parse(test.code, test.options || opts);
|
||||
if (test.error) callback("fail", test.code,
|
||||
"Expected error message: " + test.error + "\nBut parsing succeeded.");
|
||||
var testOpts = test.options || {locations: true};
|
||||
var expected = {};
|
||||
if (expected.onComment = testOpts.onComment) {
|
||||
testOpts.onComment = []
|
||||
}
|
||||
if (expected.onToken = testOpts.onToken) {
|
||||
testOpts.onToken = [];
|
||||
}
|
||||
var ast = parse(test.code, testOpts);
|
||||
if (test.error) {
|
||||
if (config.loose) {
|
||||
callback("ok", test.code);
|
||||
} else {
|
||||
callback("fail", test.code, "Expected error message: " + test.error + "\nBut parsing succeeded.");
|
||||
}
|
||||
}
|
||||
else if (test.assert) {
|
||||
var error = test.assert(ast);
|
||||
if (error) callback("fail", test.code,
|
||||
@ -43,12 +41,21 @@
|
||||
else callback("ok", test.code);
|
||||
} else {
|
||||
var mis = misMatch(test.ast, ast);
|
||||
if (!mis && test.comments) mis = misMatch(test.comments, comments);
|
||||
for (var name in expected) {
|
||||
if (mis) break;
|
||||
if (expected[name]) {
|
||||
mis = misMatch(expected[name], testOpts[name]);
|
||||
testOpts[name] = expected[name];
|
||||
}
|
||||
}
|
||||
if (mis) callback("fail", test.code, mis);
|
||||
else callback("ok", test.code);
|
||||
}
|
||||
} catch(e) {
|
||||
if (test.error && e instanceof SyntaxError) {
|
||||
if (!(e instanceof SyntaxError)) {
|
||||
throw e;
|
||||
}
|
||||
if (test.error) {
|
||||
if (e.message == test.error) callback("ok", test.code);
|
||||
else callback("fail", test.code,
|
||||
"Expected error message: " + test.error + "\nGot error message: " + e.message);
|
||||
|
||||
@ -3,24 +3,13 @@
|
||||
<meta charset="utf-8">
|
||||
<title>Acorn test suite</title>
|
||||
<script src="../acorn.js"></script>
|
||||
<script src="../acorn_loose.js"></script>
|
||||
<script src="driver.js"></script>
|
||||
<script src="tests-jsx.js" charset="utf-8"></script>
|
||||
<script src="tests.js" charset="utf-8"></script>
|
||||
<script src="tests-harmony.js" charset="utf-8"></script>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
var testsRun = 0, failed = 0;
|
||||
function report(state, code, message) {
|
||||
if (state != "ok") {++failed; console.log(code, message);}
|
||||
++testsRun;
|
||||
}
|
||||
window.onload = function(){
|
||||
var t0 = +new Date;
|
||||
runTests(report);
|
||||
var out = testsRun + " tests run in " + (+new Date - t0) + "ms\n";
|
||||
if (failed) out += failed + " failures.\n";
|
||||
else out += "All passed.\n";
|
||||
document.body.appendChild(document.createElement("pre")).appendChild(document.createTextNode(out));
|
||||
};
|
||||
</script>
|
||||
<body>
|
||||
<ul id="log"></ul>
|
||||
<script src="run.js"></script>
|
||||
</body>
|
||||
|
||||
118
test/run.js
118
test/run.js
@ -1,23 +1,111 @@
|
||||
var driver = require("./driver.js");
|
||||
require("./tests.js");
|
||||
require("./tests-harmony.js");
|
||||
require("./tests-jsx.js");
|
||||
(function() {
|
||||
var driver;
|
||||
|
||||
if (typeof require !== "undefined") {
|
||||
driver = require("./driver.js");
|
||||
require("./tests.js");
|
||||
require("./tests-harmony.js");
|
||||
require("./tests-jsx.js");
|
||||
} else {
|
||||
driver = window;
|
||||
}
|
||||
|
||||
var htmlLog = typeof document === "object" && document.getElementById('log');
|
||||
var htmlGroup = htmlLog;
|
||||
|
||||
function group(name) {
|
||||
if (htmlGroup) {
|
||||
var parentGroup = htmlGroup;
|
||||
htmlGroup = document.createElement("ul");
|
||||
var item = document.createElement("li");
|
||||
item.textContent = name;
|
||||
item.appendChild(htmlGroup);
|
||||
parentGroup.appendChild(item);
|
||||
}
|
||||
if (typeof console === "object" && console.group) {
|
||||
console.group(name);
|
||||
}
|
||||
}
|
||||
|
||||
function groupEnd() {
|
||||
if (htmlGroup) {
|
||||
htmlGroup = htmlGroup.parentElement.parentElement;
|
||||
}
|
||||
if (typeof console === "object" && console.groupEnd) {
|
||||
console.groupEnd(name);
|
||||
}
|
||||
}
|
||||
|
||||
function log(title, message) {
|
||||
if (htmlGroup) {
|
||||
var elem = document.createElement("li");
|
||||
elem.innerHTML = "<b>" + title + "</b> " + message;
|
||||
htmlGroup.appendChild(elem);
|
||||
}
|
||||
if (typeof console === "object") console.log(title, message);
|
||||
}
|
||||
|
||||
var stats, modes = {
|
||||
Normal: {
|
||||
config: {
|
||||
parse: (typeof require === "undefined" ? window.acorn : require("../acorn.js")).parse
|
||||
}
|
||||
},
|
||||
Loose: {
|
||||
config: {
|
||||
parse: (typeof require === "undefined" ? window.acorn : require("../acorn_loose")).parse_dammit,
|
||||
loose: true,
|
||||
filter: function (test) {
|
||||
if (/`/.test(test.code)) return false; // FIXME remove this when the loose parse supports template strings
|
||||
var opts = test.options || {};
|
||||
if (opts.loose === false) return false;
|
||||
return (opts.ecmaVersion || 5) <= 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var testsRun = 0, failed = 0;
|
||||
function report(state, code, message) {
|
||||
if (state != "ok") {++failed; console.log(code, message);}
|
||||
++testsRun;
|
||||
if (state != "ok") {++stats.failed; log(code, message);}
|
||||
++stats.testsRun;
|
||||
}
|
||||
|
||||
var t0 = +new Date;
|
||||
driver.runTests(report);
|
||||
console.log(testsRun + " tests run in " + (+new Date - t0) + "ms");
|
||||
group("Errors");
|
||||
|
||||
if (failed) {
|
||||
console.log(failed + " failures.");
|
||||
for (var name in modes) {
|
||||
group(name);
|
||||
var mode = modes[name];
|
||||
stats = mode.stats = {testsRun: 0, failed: 0};
|
||||
var t0 = +new Date;
|
||||
driver.runTests(mode.config, report);
|
||||
mode.stats.duration = +new Date - t0;
|
||||
groupEnd();
|
||||
}
|
||||
|
||||
groupEnd();
|
||||
|
||||
function outputStats(name, stats) {
|
||||
log(name + ":", stats.testsRun + " tests run in " + stats.duration + "ms; " +
|
||||
(stats.failed ? stats.failed + " failures." : "all passed."));
|
||||
}
|
||||
|
||||
var total = {testsRun: 0, failed: 0, duration: 0};
|
||||
|
||||
group("Stats");
|
||||
|
||||
for (var name in modes) {
|
||||
var stats = modes[name].stats;
|
||||
outputStats(name + " parser", stats);
|
||||
for (var key in stats) total[key] += stats[key];
|
||||
}
|
||||
|
||||
outputStats("Total", total);
|
||||
|
||||
groupEnd();
|
||||
|
||||
if (total.failed && typeof process === "object") {
|
||||
process.stdout.write("", function() {
|
||||
process.exit(1);
|
||||
});
|
||||
} else {
|
||||
console.log("All passed.");
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
444
test/tests.js
444
test/tests.js
@ -43,8 +43,8 @@ test("this\n", {
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 4
|
||||
line: 2,
|
||||
column: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -86,8 +86,8 @@ test("null\n", {
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 4
|
||||
line: 2,
|
||||
column: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -125,16 +125,70 @@ test("\n 42\n\n", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
column: 4
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
column: 6
|
||||
line: 4,
|
||||
column: 0
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test("/foobar/", {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
type: "Literal",
|
||||
value: /foobar/,
|
||||
regex: {
|
||||
pattern: "foobar",
|
||||
flags: ""
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
test("/[a-z]/g", {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "ExpressionStatement",
|
||||
expression: {
|
||||
type: "Literal",
|
||||
value: /[a-z]/,
|
||||
regex: {
|
||||
pattern: "[a-z]",
|
||||
flags: "g"
|
||||
},
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 8
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
test("(1 + 2 ) * 3", {
|
||||
type: "Program",
|
||||
body: [
|
||||
@ -4862,7 +4916,7 @@ test("/* block comment */ 42", {
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 20
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
@ -4909,7 +4963,7 @@ test("42 /*The*/ /*Answer*/", {
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 2
|
||||
column: 21
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -4952,7 +5006,7 @@ test("42 /*the*/ /*answer*/", {
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 2
|
||||
column: 21
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -4990,8 +5044,8 @@ test("/* multiline\ncomment\nshould\nbe\nignored */ 42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 5,
|
||||
column: 11
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 5,
|
||||
@ -5033,8 +5087,8 @@ test("/*a\r\nb*/ 42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
column: 4
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
@ -5076,8 +5130,8 @@ test("/*a\rb*/ 42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
column: 4
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
@ -5119,8 +5173,8 @@ test("/*a\nb*/ 42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
column: 4
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
@ -5162,8 +5216,8 @@ test("/*a\nc*/ 42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
column: 4
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 2,
|
||||
@ -5205,7 +5259,7 @@ test("// line comment\n42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
@ -5253,7 +5307,7 @@ test("42 // line comment", {
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
column: 2
|
||||
column: 18
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -5291,7 +5345,7 @@ test("// Hello, world!\n42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
@ -5306,7 +5360,7 @@ test("// Hello, world!\n", {
|
||||
body: [],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
@ -5321,7 +5375,7 @@ test("// Hallo, world!\n", {
|
||||
body: [],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
@ -5364,7 +5418,7 @@ test("//\n42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 2,
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
@ -5380,7 +5434,7 @@ test("//", {
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 2
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
@ -5395,7 +5449,7 @@ test("// ", {
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 3
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
@ -5438,7 +5492,7 @@ test("/**/42", {
|
||||
loc: {
|
||||
start: {
|
||||
line: 1,
|
||||
column: 4
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
line: 1,
|
||||
@ -5480,7 +5534,7 @@ test("// Hello, world!\n\n// Another hello\n42", {
|
||||
],
|
||||
loc: {
|
||||
start: {
|
||||
line: 4,
|
||||
line: 1,
|
||||
column: 0
|
||||
},
|
||||
end: {
|
||||
@ -28612,191 +28666,171 @@ testFail("for(x of a);", "Unexpected token (1:6)");
|
||||
testFail("for(var x of a);", "Unexpected token (1:10)");
|
||||
|
||||
// Assertion Tests
|
||||
(function() {
|
||||
var actualComments = [],
|
||||
expectedComments = [
|
||||
" Bear class",
|
||||
" Whatever",
|
||||
[" 1",
|
||||
" 2",
|
||||
" 3"
|
||||
].join('\n'),
|
||||
"stuff"
|
||||
];
|
||||
testAssert(
|
||||
function TestComments() {
|
||||
// Bear class
|
||||
function Bear(x,y,z) {
|
||||
this.position = [x||0,y||0,z||0]
|
||||
}
|
||||
|
||||
Bear.prototype.roar = function(message) {
|
||||
return 'RAWWW: ' + message; // Whatever
|
||||
};
|
||||
|
||||
function Cat() {
|
||||
/* 1
|
||||
2
|
||||
3*/
|
||||
}
|
||||
|
||||
Cat.prototype.roar = function(message) {
|
||||
return 'MEOOWW: ' + /*stuff*/ message;
|
||||
};
|
||||
}.toString().replace(/\r\n/g, '\n'),
|
||||
function assert(ast) {
|
||||
if (actualComments.length !== expectedComments.length) {
|
||||
return JSON.stringify(actualComments) + " !== " + JSON.stringify(expectedComments);
|
||||
} else {
|
||||
for (var i=0, n=actualComments.length; i < n; i++) {
|
||||
if (actualComments[i] !== expectedComments[i])
|
||||
return JSON.stringify(actualComments[i]) + ' !== ' + JSON.stringify(expectedComments[i]);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
onComment: function(isMultiline, text) {
|
||||
actualComments.push(text);
|
||||
}
|
||||
test(function TestComments() {
|
||||
// Bear class
|
||||
function Bear(x,y,z) {
|
||||
this.position = [x||0,y||0,z||0]
|
||||
}
|
||||
);
|
||||
})();
|
||||
|
||||
Bear.prototype.roar = function(message) {
|
||||
return 'RAWWW: ' + message; // Whatever
|
||||
};
|
||||
|
||||
function Cat() {
|
||||
/* 1
|
||||
2
|
||||
3*/
|
||||
}
|
||||
|
||||
Cat.prototype.roar = function(message) {
|
||||
return 'MEOOWW: ' + /*stuff*/ message;
|
||||
};
|
||||
}.toString().replace(/\r\n/g, '\n'), {}, {
|
||||
onComment: [
|
||||
{type: "Line", value: " Bear class"},
|
||||
{type: "Line", value: " Whatever"},
|
||||
{type: "Block", value: [
|
||||
" 1",
|
||||
" 2",
|
||||
" 3"
|
||||
].join('\n')},
|
||||
{type: "Block", value: "stuff"}
|
||||
]
|
||||
});
|
||||
|
||||
test("<!--\n;", {
|
||||
type: "Program",
|
||||
body: [
|
||||
{
|
||||
type: "EmptyStatement"
|
||||
body: [{
|
||||
type: "EmptyStatement"
|
||||
}]
|
||||
});
|
||||
|
||||
test("\nfunction plop() {\n'use strict';\n/* Comment */\n}", {}, {
|
||||
locations: true,
|
||||
onComment: [{
|
||||
type: "Block",
|
||||
value: " Comment ",
|
||||
loc: {
|
||||
start: { line: 4, column: 0 },
|
||||
end: { line: 4, column: 13 }
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
}]
|
||||
});
|
||||
|
||||
(function() {
|
||||
test("\nfunction plop() {\n'use strict';\n/* Comment */\n}", {}, {locations: true},
|
||||
[{
|
||||
block: true,
|
||||
text: " Comment ",
|
||||
startLoc: { line: 4, column: 0 },
|
||||
endLoc: { line: 4, column: 13 }
|
||||
}]);
|
||||
test("// line comment", {}, {
|
||||
locations: true,
|
||||
onComment: [{
|
||||
type: "Line",
|
||||
value: " line comment",
|
||||
loc: {
|
||||
start: { line: 1, column: 0 },
|
||||
end: { line: 1, column: 15 }
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
test("// line comment", {}, {locations: true},
|
||||
[{
|
||||
block: false,
|
||||
text: " line comment",
|
||||
startLoc: { line: 1, column: 0 },
|
||||
endLoc: { line: 1, column: 15 }
|
||||
}]);
|
||||
test("<!-- HTML comment", {}, {
|
||||
locations: true,
|
||||
onComment: [{
|
||||
type: "Line",
|
||||
value: " HTML comment",
|
||||
loc: {
|
||||
start: { line: 1, column: 0 },
|
||||
end: { line: 1, column: 17 }
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
test("<!-- HTML comment", {}, {locations: true},
|
||||
[{
|
||||
block: false,
|
||||
text: " HTML comment",
|
||||
startLoc: { line: 1, column: 0 },
|
||||
endLoc: { line: 1, column: 17 }
|
||||
}]);
|
||||
test(";\n--> HTML comment", {}, {
|
||||
locations: true,
|
||||
onComment: [{
|
||||
type: "Line",
|
||||
value: " HTML comment",
|
||||
loc: {
|
||||
start: { line: 2, column: 0 },
|
||||
end: { line: 2, column: 16 }
|
||||
}
|
||||
}]
|
||||
});
|
||||
|
||||
test(";\n--> HTML comment", {}, {locations: true},
|
||||
[{
|
||||
block: false,
|
||||
text: " HTML comment",
|
||||
startLoc: { line: 2, column: 0 },
|
||||
endLoc: { line: 2, column: 16 }
|
||||
}]);
|
||||
})();
|
||||
var tokTypes = acorn.tokTypes;
|
||||
|
||||
(function() {
|
||||
var tokTypes = acorn.tokTypes;
|
||||
|
||||
var actualTokens = [],
|
||||
expectedTokens = [
|
||||
{
|
||||
type: tokTypes._var,
|
||||
value: "var",
|
||||
loc: {
|
||||
start: {line: 1, column: 0},
|
||||
end: {line: 1, column: 3}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.name,
|
||||
value: "x",
|
||||
loc: {
|
||||
start: {line: 1, column: 4},
|
||||
end: {line: 1, column: 5}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.eq,
|
||||
value: "=",
|
||||
loc: {
|
||||
start: {line: 1, column: 6},
|
||||
end: {line: 1, column: 7}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.parenL,
|
||||
value: undefined,
|
||||
loc: {
|
||||
start: {line: 1, column: 8},
|
||||
end: {line: 1, column: 9}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.num,
|
||||
value: 1,
|
||||
loc: {
|
||||
start: {line: 1, column: 9},
|
||||
end: {line: 1, column: 10}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: {binop: 9, prefix: true, beforeExpr: true},
|
||||
value: "+",
|
||||
loc: {
|
||||
start: {line: 1, column: 11},
|
||||
end: {line: 1, column: 12}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.num,
|
||||
value: 2,
|
||||
loc: {
|
||||
start: {line: 1, column: 13},
|
||||
end: {line: 1, column: 14}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.parenR,
|
||||
value: undefined,
|
||||
loc: {
|
||||
start: {line: 1, column: 14},
|
||||
end: {line: 1, column: 15}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.eof,
|
||||
value: undefined,
|
||||
loc: {
|
||||
start: {line: 1, column: 15},
|
||||
end: {line: 1, column: 15}
|
||||
}
|
||||
}
|
||||
];
|
||||
testAssert('var x = (1 + 2)', function assert(ast) {
|
||||
if (actualTokens.length !== expectedTokens.length) {
|
||||
return "Bad token stream length: expected " + expectedTokens.length + ", got " + actualTokens.length;
|
||||
} else {
|
||||
for (var i=0, n=actualTokens.length; i < n; i++) {
|
||||
var mis = misMatch(expectedTokens[i], actualTokens[i]);
|
||||
if (mis) return mis;
|
||||
test('var x = (1 + 2)', {}, {
|
||||
locations: true,
|
||||
onToken: [
|
||||
{
|
||||
type: tokTypes._var,
|
||||
value: "var",
|
||||
loc: {
|
||||
start: {line: 1, column: 0},
|
||||
end: {line: 1, column: 3}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.name,
|
||||
value: "x",
|
||||
loc: {
|
||||
start: {line: 1, column: 4},
|
||||
end: {line: 1, column: 5}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.eq,
|
||||
value: "=",
|
||||
loc: {
|
||||
start: {line: 1, column: 6},
|
||||
end: {line: 1, column: 7}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.parenL,
|
||||
value: undefined,
|
||||
loc: {
|
||||
start: {line: 1, column: 8},
|
||||
end: {line: 1, column: 9}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.num,
|
||||
value: 1,
|
||||
loc: {
|
||||
start: {line: 1, column: 9},
|
||||
end: {line: 1, column: 10}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: {binop: 9, prefix: true, beforeExpr: true},
|
||||
value: "+",
|
||||
loc: {
|
||||
start: {line: 1, column: 11},
|
||||
end: {line: 1, column: 12}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.num,
|
||||
value: 2,
|
||||
loc: {
|
||||
start: {line: 1, column: 13},
|
||||
end: {line: 1, column: 14}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.parenR,
|
||||
value: undefined,
|
||||
loc: {
|
||||
start: {line: 1, column: 14},
|
||||
end: {line: 1, column: 15}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: tokTypes.eof,
|
||||
value: undefined,
|
||||
loc: {
|
||||
start: {line: 1, column: 15},
|
||||
end: {line: 1, column: 15}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
locations: true,
|
||||
onToken: actualTokens
|
||||
});
|
||||
})();
|
||||
]
|
||||
});
|
||||
|
||||
test("function f(f) { 'use strict'; }", {});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user