mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-01 02:38:43 -05:00
Update Acorn.js to v0.1.01
This commit is contained in:
parent
ac8c9cd114
commit
17b81f5f67
2 changed files with 294 additions and 188 deletions
2
lib/acorn-min.js
vendored
2
lib/acorn-min.js
vendored
File diff suppressed because one or more lines are too long
480
lib/acorn.js
480
lib/acorn.js
|
@ -12,13 +12,20 @@
|
||||||
// Please use the [github bug tracker][ghbt] to report issues.
|
// Please use the [github bug tracker][ghbt] to report issues.
|
||||||
//
|
//
|
||||||
// [ghbt]: https://github.com/marijnh/acorn/issues
|
// [ghbt]: https://github.com/marijnh/acorn/issues
|
||||||
|
//
|
||||||
|
// This file defines the main parser interface. The library also comes
|
||||||
|
// with a [error-tolerant parser][dammit] and an
|
||||||
|
// [abstract syntax tree walker][walk], defined in other files.
|
||||||
|
//
|
||||||
|
// [dammit]: acorn_loose.js
|
||||||
|
// [walk]: util/walk.js
|
||||||
|
|
||||||
(function(exports) {
|
(function(exports) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
exports.version = "0.0.1";
|
exports.version = "0.1.01";
|
||||||
|
|
||||||
// The main exported interface (under `window.acorn` when in the
|
// The main exported interface (under `self.acorn` when in the
|
||||||
// browser) is a `parse` function that takes a code string and
|
// browser) is a `parse` function that takes a code string and
|
||||||
// returns an abstract syntax tree as specified by [Mozilla parser
|
// returns an abstract syntax tree as specified by [Mozilla parser
|
||||||
// API][api], with the caveat that the SpiderMonkey-specific syntax
|
// API][api], with the caveat that the SpiderMonkey-specific syntax
|
||||||
|
@ -30,10 +37,8 @@
|
||||||
|
|
||||||
exports.parse = function(inpt, opts) {
|
exports.parse = function(inpt, opts) {
|
||||||
input = String(inpt); inputLen = input.length;
|
input = String(inpt); inputLen = input.length;
|
||||||
options = opts || {};
|
setOptions(opts);
|
||||||
for (var opt in defaultOptions) if (!options.hasOwnProperty(opt))
|
initTokenState();
|
||||||
options[opt] = defaultOptions[opt];
|
|
||||||
sourceFile = options.sourceFile || null;
|
|
||||||
return parseTopLevel(options.program);
|
return parseTopLevel(options.program);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -55,18 +60,21 @@
|
||||||
// By default, reserved words are not enforced. Enable
|
// By default, reserved words are not enforced. Enable
|
||||||
// `forbidReserved` to enforce them.
|
// `forbidReserved` to enforce them.
|
||||||
forbidReserved: false,
|
forbidReserved: false,
|
||||||
// When `trackComments` is turned on, the parser will attach
|
|
||||||
// `commentsBefore` and `commentsAfter` properties to AST nodes
|
|
||||||
// holding arrays of strings. A single comment may appear in both
|
|
||||||
// a `commentsBefore` and `commentsAfter` array (of the nodes
|
|
||||||
// after and before it), but never twice in the before (or after)
|
|
||||||
// array of different nodes.
|
|
||||||
trackComments: false,
|
|
||||||
// When `locations` is on, `loc` properties holding objects with
|
// When `locations` is on, `loc` properties holding objects with
|
||||||
// `start` and `end` properties in `{line, column}` form (with
|
// `start` and `end` properties in `{line, column}` form (with
|
||||||
// line being 1-based and column 0-based) will be attached to the
|
// line being 1-based and column 0-based) will be attached to the
|
||||||
// nodes.
|
// nodes.
|
||||||
locations: false,
|
locations: false,
|
||||||
|
// A function can be passed as `onComment` option, which will
|
||||||
|
// cause Acorn to call that function with `(block, text, start,
|
||||||
|
// end)` parameters whenever a comment is skipped. `block` is a
|
||||||
|
// boolean indicating whether this is a block (`/* */`) comment,
|
||||||
|
// `text` is the content of the comment, and `start` and `end` are
|
||||||
|
// character offsets that denote the start and end of the comment.
|
||||||
|
// When the `locations` option is on, two more parameters are
|
||||||
|
// passed, the full `{line, column}` locations of the start and
|
||||||
|
// end of the comments.
|
||||||
|
onComment: null,
|
||||||
// Nodes have their start and end characters offsets recorded in
|
// Nodes have their start and end characters offsets recorded in
|
||||||
// `start` and `end` properties (directly on the node, rather than
|
// `start` and `end` properties (directly on the node, rather than
|
||||||
// the `loc` object, which holds line/column data. To also add a
|
// the `loc` object, which holds line/column data. To also add a
|
||||||
|
@ -87,6 +95,13 @@
|
||||||
sourceFile: null
|
sourceFile: null
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function setOptions(opts) {
|
||||||
|
options = opts || {};
|
||||||
|
for (var opt in defaultOptions) if (!options.hasOwnProperty(opt))
|
||||||
|
options[opt] = defaultOptions[opt];
|
||||||
|
sourceFile = options.sourceFile || null;
|
||||||
|
}
|
||||||
|
|
||||||
// The `getLineInfo` function is mostly useful when the
|
// The `getLineInfo` function is mostly useful when the
|
||||||
// `locations` option is off (for performance reasons) and you
|
// `locations` option is off (for performance reasons) and you
|
||||||
// want to find the line/column position for a given character
|
// want to find the line/column position for a given character
|
||||||
|
@ -106,9 +121,44 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
// Acorn is organized as a tokenizer and a recursive-descent parser.
|
// Acorn is organized as a tokenizer and a recursive-descent parser.
|
||||||
// Both use (closure-)global variables to keep their state and
|
// The `tokenize` export provides an interface to the tokenizer.
|
||||||
// communicate. We already saw the `options`, `input`, and
|
// Because the tokenizer is optimized for being efficiently used by
|
||||||
// `inputLen` variables above (set in `parse`).
|
// the Acorn parser itself, this interface is somewhat crude and not
|
||||||
|
// very modular. Performing another parse or call to `tokenize` will
|
||||||
|
// reset the internal state, and invalidate existing tokenizers.
|
||||||
|
|
||||||
|
exports.tokenize = function(inpt, opts) {
|
||||||
|
input = String(inpt); inputLen = input.length;
|
||||||
|
setOptions(opts);
|
||||||
|
initTokenState();
|
||||||
|
|
||||||
|
var t = {};
|
||||||
|
function getToken(forceRegexp) {
|
||||||
|
readToken(forceRegexp);
|
||||||
|
t.start = tokStart; t.end = tokEnd;
|
||||||
|
t.startLoc = tokStartLoc; t.endLoc = tokEndLoc;
|
||||||
|
t.type = tokType; t.value = tokVal;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
getToken.jumpTo = function(pos, reAllowed) {
|
||||||
|
tokPos = pos;
|
||||||
|
if (options.locations) {
|
||||||
|
tokCurLine = tokLineStart = lineBreak.lastIndex = 0;
|
||||||
|
var match;
|
||||||
|
while ((match = lineBreak.exec(input)) && match.index < pos) {
|
||||||
|
++tokCurLine;
|
||||||
|
tokLineStart = match.index + match[0].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var ch = input.charAt(pos - 1);
|
||||||
|
tokRegexpAllowed = reAllowed;
|
||||||
|
skipSpace();
|
||||||
|
};
|
||||||
|
return getToken;
|
||||||
|
};
|
||||||
|
|
||||||
|
// State is kept in (closure-)global variables. We already saw the
|
||||||
|
// `options`, `input`, and `inputLen` variables above.
|
||||||
|
|
||||||
// The current position of the tokenizer in the input.
|
// The current position of the tokenizer in the input.
|
||||||
|
|
||||||
|
@ -133,11 +183,6 @@
|
||||||
|
|
||||||
var tokType, tokVal;
|
var tokType, tokVal;
|
||||||
|
|
||||||
// These are used to hold arrays of comments when
|
|
||||||
// `options.trackComments` is true.
|
|
||||||
|
|
||||||
var tokCommentsBefore, tokCommentsAfter;
|
|
||||||
|
|
||||||
// Interal state for the tokenizer. To distinguish between division
|
// Interal state for the tokenizer. To distinguish between division
|
||||||
// operators and regular expressions, it remembers whether the last
|
// operators and regular expressions, it remembers whether the last
|
||||||
// token was one that is allowed to be followed by an expression.
|
// token was one that is allowed to be followed by an expression.
|
||||||
|
@ -145,13 +190,13 @@
|
||||||
// division operator. See the `parseStatement` function for a
|
// division operator. See the `parseStatement` function for a
|
||||||
// caveat.)
|
// caveat.)
|
||||||
|
|
||||||
var tokRegexpAllowed, tokComments;
|
var tokRegexpAllowed;
|
||||||
|
|
||||||
// When `options.locations` is true, these are used to keep
|
// When `options.locations` is true, these are used to keep
|
||||||
// track of the current line, and know when a new line has been
|
// track of the current line, and know when a new line has been
|
||||||
// entered. See the `curLineLoc` function.
|
// entered.
|
||||||
|
|
||||||
var tokCurLine, tokLineStart, tokLineStartNext;
|
var tokCurLine, tokLineStart;
|
||||||
|
|
||||||
// These store the position of the previous token, which is useful
|
// These store the position of the previous token, which is useful
|
||||||
// when finishing a node and assigning its `end` position.
|
// when finishing a node and assigning its `end` position.
|
||||||
|
@ -166,15 +211,17 @@
|
||||||
var inFunction, labels, strict;
|
var inFunction, labels, strict;
|
||||||
|
|
||||||
// This function is used to raise exceptions on parse errors. It
|
// This function is used to raise exceptions on parse errors. It
|
||||||
// takes either a `{line, column}` object or an offset integer (into
|
// takes an offset integer (into the current `input`) to indicate
|
||||||
// the current `input`) as `pos` argument. It attaches the position
|
// the location of the error, attaches the position to the end
|
||||||
// to the end of the error message, and then raises a `SyntaxError`
|
// of the error message, and then raises a `SyntaxError` with that
|
||||||
// with that message.
|
// message.
|
||||||
|
|
||||||
function raise(pos, message) {
|
function raise(pos, message) {
|
||||||
if (typeof pos == "number") pos = getLineInfo(input, pos);
|
var loc = getLineInfo(input, pos);
|
||||||
message += " (" + pos.line + ":" + pos.column + ")";
|
message += " (" + loc.line + ":" + loc.column + ")";
|
||||||
throw new SyntaxError(message);
|
var err = new SyntaxError(message);
|
||||||
|
err.pos = pos; err.loc = loc; err.raisedAt = tokPos;
|
||||||
|
throw err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ## Token types
|
// ## Token types
|
||||||
|
@ -233,10 +280,10 @@
|
||||||
"function": _function, "if": _if, "return": _return, "switch": _switch,
|
"function": _function, "if": _if, "return": _return, "switch": _switch,
|
||||||
"throw": _throw, "try": _try, "var": _var, "while": _while, "with": _with,
|
"throw": _throw, "try": _try, "var": _var, "while": _while, "with": _with,
|
||||||
"null": _null, "true": _true, "false": _false, "new": _new, "in": _in,
|
"null": _null, "true": _true, "false": _false, "new": _new, "in": _in,
|
||||||
"instanceof": {keyword: "instanceof", binop: 7}, "this": _this,
|
"instanceof": {keyword: "instanceof", binop: 7, beforeExpr: true}, "this": _this,
|
||||||
"typeof": {keyword: "typeof", prefix: true},
|
"typeof": {keyword: "typeof", prefix: true, beforeExpr: true},
|
||||||
"void": {keyword: "void", prefix: true},
|
"void": {keyword: "void", prefix: true, beforeExpr: true},
|
||||||
"delete": {keyword: "delete", prefix: true}};
|
"delete": {keyword: "delete", prefix: true, beforeExpr: true}};
|
||||||
|
|
||||||
// Punctuation token types. Again, the `type` property is purely for debugging.
|
// Punctuation token types. Again, the `type` property is purely for debugging.
|
||||||
|
|
||||||
|
@ -270,6 +317,15 @@
|
||||||
var _bin7 = {binop: 7, beforeExpr: true}, _bin8 = {binop: 8, beforeExpr: true};
|
var _bin7 = {binop: 7, beforeExpr: true}, _bin8 = {binop: 8, beforeExpr: true};
|
||||||
var _bin10 = {binop: 10, beforeExpr: true};
|
var _bin10 = {binop: 10, beforeExpr: true};
|
||||||
|
|
||||||
|
// Provide access to the token types for external users of the
|
||||||
|
// tokenizer.
|
||||||
|
|
||||||
|
exports.tokTypes = {bracketL: _bracketL, bracketR: _bracketR, braceL: _braceL, braceR: _braceR,
|
||||||
|
parenL: _parenL, parenR: _parenR, comma: _comma, semi: _semi, colon: _colon,
|
||||||
|
dot: _dot, question: _question, slash: _slash, eq: _eq, name: _name, eof: _eof,
|
||||||
|
num: _num, regexp: _regexp, string: _string};
|
||||||
|
for (var kw in keywordTypes) exports.tokTypes[kw] = keywordTypes[kw];
|
||||||
|
|
||||||
// This is a trick taken from Esprima. It turns out that, on
|
// This is a trick taken from Esprima. It turns out that, on
|
||||||
// non-Chrome browsers, to check whether a string is in a set, a
|
// non-Chrome browsers, to check whether a string is in a set, a
|
||||||
// predicate containing a big ugly `switch` statement is faster than
|
// predicate containing a big ugly `switch` statement is faster than
|
||||||
|
@ -384,23 +440,12 @@
|
||||||
|
|
||||||
// ## Tokenizer
|
// ## Tokenizer
|
||||||
|
|
||||||
// These are used when `options.locations` is on, in order to track
|
// These are used when `options.locations` is on, for the
|
||||||
// the current line number and start of line offset, in order to set
|
// `tokStartLoc` and `tokEndLoc` properties.
|
||||||
// `tokStartLoc` and `tokEndLoc`.
|
|
||||||
|
|
||||||
function nextLineStart() {
|
function line_loc_t() {
|
||||||
lineBreak.lastIndex = tokLineStart;
|
this.line = tokCurLine;
|
||||||
var match = lineBreak.exec(input);
|
this.column = tokPos - tokLineStart;
|
||||||
return match ? match.index + match[0].length : input.length + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function curLineLoc() {
|
|
||||||
while (tokLineStartNext <= tokPos) {
|
|
||||||
++tokCurLine;
|
|
||||||
tokLineStart = tokLineStartNext;
|
|
||||||
tokLineStartNext = nextLineStart();
|
|
||||||
}
|
|
||||||
return {line: tokCurLine, column: tokPos - tokLineStart};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the token state. Used at the start of a parse.
|
// Reset the token state. Used at the start of a parse.
|
||||||
|
@ -408,64 +453,86 @@
|
||||||
function initTokenState() {
|
function initTokenState() {
|
||||||
tokCurLine = 1;
|
tokCurLine = 1;
|
||||||
tokPos = tokLineStart = 0;
|
tokPos = tokLineStart = 0;
|
||||||
tokLineStartNext = nextLineStart();
|
|
||||||
tokRegexpAllowed = true;
|
tokRegexpAllowed = true;
|
||||||
tokComments = null;
|
|
||||||
skipSpace();
|
skipSpace();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called at the end of every token. Sets `tokEnd`, `tokVal`,
|
// Called at the end of every token. Sets `tokEnd`, `tokVal`, and
|
||||||
// `tokCommentsAfter`, and `tokRegexpAllowed`, and skips the space
|
// `tokRegexpAllowed`, and skips the space after the token, so that
|
||||||
// after the token, so that the next one's `tokStart` will point at
|
// the next one's `tokStart` will point at the right position.
|
||||||
// the right position.
|
|
||||||
|
|
||||||
function finishToken(type, val) {
|
function finishToken(type, val) {
|
||||||
tokEnd = tokPos;
|
tokEnd = tokPos;
|
||||||
if (options.locations) tokEndLoc = curLineLoc();
|
if (options.locations) tokEndLoc = new line_loc_t;
|
||||||
tokType = type;
|
tokType = type;
|
||||||
skipSpace();
|
skipSpace();
|
||||||
tokVal = val;
|
tokVal = val;
|
||||||
tokCommentsAfter = tokComments;
|
|
||||||
tokRegexpAllowed = type.beforeExpr;
|
tokRegexpAllowed = type.beforeExpr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function skipBlockComment() {
|
function skipBlockComment() {
|
||||||
var end = input.indexOf("*/", tokPos += 2);
|
var startLoc = options.onComment && options.locations && new line_loc_t;
|
||||||
|
var start = tokPos, end = input.indexOf("*/", tokPos += 2);
|
||||||
if (end === -1) raise(tokPos - 2, "Unterminated comment");
|
if (end === -1) raise(tokPos - 2, "Unterminated comment");
|
||||||
if (options.trackComments)
|
|
||||||
(tokComments || (tokComments = [])).push(input.slice(tokPos, end));
|
|
||||||
tokPos = end + 2;
|
tokPos = end + 2;
|
||||||
|
if (options.locations) {
|
||||||
|
lineBreak.lastIndex = start;
|
||||||
|
var match;
|
||||||
|
while ((match = lineBreak.exec(input)) && match.index < tokPos) {
|
||||||
|
++tokCurLine;
|
||||||
|
tokLineStart = match.index + match[0].length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (options.onComment)
|
||||||
|
options.onComment(true, input.slice(start + 2, end), start, tokPos,
|
||||||
|
startLoc, options.locations && new line_loc_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
function skipLineComment() {
|
function skipLineComment() {
|
||||||
var start = tokPos;
|
var start = tokPos;
|
||||||
|
var startLoc = options.onComment && options.locations && new line_loc_t;
|
||||||
var ch = input.charCodeAt(tokPos+=2);
|
var ch = input.charCodeAt(tokPos+=2);
|
||||||
while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8329) {
|
while (tokPos < inputLen && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8329) {
|
||||||
++tokPos;
|
++tokPos;
|
||||||
ch = input.charCodeAt(tokPos);
|
ch = input.charCodeAt(tokPos);
|
||||||
}
|
}
|
||||||
if (options.trackComments)
|
if (options.onComment)
|
||||||
(tokComments || (tokComments = [])).push(input.slice(start, tokPos));
|
options.onComment(false, input.slice(start + 2, tokPos), start, tokPos,
|
||||||
|
startLoc, options.locations && new line_loc_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called at the start of the parse and after every token. Skips
|
// Called at the start of the parse and after every token. Skips
|
||||||
// whitespace and comments, and, if `options.trackComments` is on,
|
// whitespace and comments, and.
|
||||||
// will store all skipped comments in `tokComments`.
|
|
||||||
|
|
||||||
function skipSpace() {
|
function skipSpace() {
|
||||||
tokComments = null;
|
|
||||||
while (tokPos < inputLen) {
|
while (tokPos < inputLen) {
|
||||||
var ch = input.charCodeAt(tokPos);
|
var ch = input.charCodeAt(tokPos);
|
||||||
if (ch === 47) { // '/'
|
if (ch === 32) { // ' '
|
||||||
|
++tokPos;
|
||||||
|
} else if(ch === 13) {
|
||||||
|
++tokPos;
|
||||||
|
var next = input.charCodeAt(tokPos);
|
||||||
|
if(next === 10) {
|
||||||
|
++tokPos;
|
||||||
|
}
|
||||||
|
if(options.locations) {
|
||||||
|
++tokCurLine;
|
||||||
|
tokLineStart = tokPos;
|
||||||
|
}
|
||||||
|
} else if (ch === 10) {
|
||||||
|
++tokPos;
|
||||||
|
++tokCurLine;
|
||||||
|
tokLineStart = tokPos;
|
||||||
|
} else if(ch < 14 && ch > 8) {
|
||||||
|
++tokPos;
|
||||||
|
} else if (ch === 47) { // '/'
|
||||||
var next = input.charCodeAt(tokPos+1);
|
var next = input.charCodeAt(tokPos+1);
|
||||||
if (next === 42) { // '*'
|
if (next === 42) { // '*'
|
||||||
skipBlockComment();
|
skipBlockComment();
|
||||||
} else if (next === 47) { // '/'
|
} else if (next === 47) { // '/'
|
||||||
skipLineComment();
|
skipLineComment();
|
||||||
} else break;
|
} else break;
|
||||||
} else if (ch < 14 && ch > 8) {
|
} else if ((ch < 14 && ch > 8) || ch === 32 || ch === 160) { // ' ', '\xa0'
|
||||||
++tokPos;
|
|
||||||
} else if (ch === 32 || ch === 160) { // ' ', '\xa0'
|
|
||||||
++tokPos;
|
++tokPos;
|
||||||
} else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {
|
} else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) {
|
||||||
++tokPos;
|
++tokPos;
|
||||||
|
@ -487,26 +554,71 @@
|
||||||
// The `forceRegexp` parameter is used in the one case where the
|
// The `forceRegexp` parameter is used in the one case where the
|
||||||
// `tokRegexpAllowed` trick does not work. See `parseStatement`.
|
// `tokRegexpAllowed` trick does not work. See `parseStatement`.
|
||||||
|
|
||||||
function readToken(forceRegexp) {
|
function readToken_dot() {
|
||||||
tokStart = tokPos;
|
|
||||||
if (options.locations) tokStartLoc = curLineLoc();
|
|
||||||
tokCommentsBefore = tokComments;
|
|
||||||
if (forceRegexp) return readRegexp();
|
|
||||||
if (tokPos >= inputLen) return finishToken(_eof);
|
|
||||||
|
|
||||||
var code = input.charCodeAt(tokPos);
|
|
||||||
// Identifier or keyword. '\uXXXX' sequences are allowed in
|
|
||||||
// identifiers, so '\' also dispatches to that.
|
|
||||||
if (isIdentifierStart(code) || code === 92 /* '\' */) return readWord();
|
|
||||||
var next = input.charCodeAt(tokPos+1);
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (next >= 48 && next <= 57) return readNumber(true);
|
||||||
|
++tokPos;
|
||||||
|
return finishToken(_dot);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_slash() { // '/'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (tokRegexpAllowed) {++tokPos; return readRegexp();}
|
||||||
|
if (next === 61) return finishOp(_assign, 2);
|
||||||
|
return finishOp(_slash, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_mult_modulo() { // '%*'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (next === 61) return finishOp(_assign, 2);
|
||||||
|
return finishOp(_bin10, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_pipe_amp(code) { // '|&'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (next === code) return finishOp(code === 124 ? _bin1 : _bin2, 2);
|
||||||
|
if (next === 61) return finishOp(_assign, 2);
|
||||||
|
return finishOp(code === 124 ? _bin3 : _bin5, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_caret() { // '^'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (next === 61) return finishOp(_assign, 2);
|
||||||
|
return finishOp(_bin4, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_plus_min(code) { // '+-'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (next === code) return finishOp(_incdec, 2);
|
||||||
|
if (next === 61) return finishOp(_assign, 2);
|
||||||
|
return finishOp(_plusmin, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_lt_gt(code) { // '<>'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
var size = 1;
|
||||||
|
if (next === code) {
|
||||||
|
size = code === 62 && input.charCodeAt(tokPos+2) === 62 ? 3 : 2;
|
||||||
|
if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1);
|
||||||
|
return finishOp(_bin8, size);
|
||||||
|
}
|
||||||
|
if (next === 61)
|
||||||
|
size = input.charCodeAt(tokPos+2) === 61 ? 3 : 2;
|
||||||
|
return finishOp(_bin7, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
function readToken_eq_excl(code) { // '=!'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
|
if (next === 61) return finishOp(_bin6, input.charCodeAt(tokPos+2) === 61 ? 3 : 2);
|
||||||
|
return finishOp(code === 61 ? _eq : _prefix, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTokenFromCode(code) {
|
||||||
switch(code) {
|
switch(code) {
|
||||||
// The interpretation of a dot depends on whether it is followed
|
// The interpretation of a dot depends on whether it is followed
|
||||||
// by a digit.
|
// by a digit.
|
||||||
case 46: // '.'
|
case 46: // '.'
|
||||||
if (next >= 48 && next <= 57) return readNumber(String.fromCharCode(code));
|
return readToken_dot();
|
||||||
++tokPos;
|
|
||||||
return finishToken(_dot);
|
|
||||||
|
|
||||||
// Punctuation tokens.
|
// Punctuation tokens.
|
||||||
case 40: ++tokPos; return finishToken(_parenL);
|
case 40: ++tokPos; return finishToken(_parenL);
|
||||||
|
@ -522,11 +634,12 @@
|
||||||
|
|
||||||
// '0x' is a hexadecimal number.
|
// '0x' is a hexadecimal number.
|
||||||
case 48: // '0'
|
case 48: // '0'
|
||||||
|
var next = input.charCodeAt(tokPos+1);
|
||||||
if (next === 120 || next === 88) return readHexNumber();
|
if (next === 120 || next === 88) return readHexNumber();
|
||||||
// Anything else beginning with a digit is an integer, octal
|
// Anything else beginning with a digit is an integer, octal
|
||||||
// number, or float.
|
// number, or float.
|
||||||
case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: // 1-9
|
case 49: case 50: case 51: case 52: case 53: case 54: case 55: case 56: case 57: // 1-9
|
||||||
return readNumber(String.fromCharCode(code));
|
return readNumber(false);
|
||||||
|
|
||||||
// Quotes produce strings.
|
// Quotes produce strings.
|
||||||
case 34: case 39: // '"', "'"
|
case 34: case 39: // '"', "'"
|
||||||
|
@ -538,52 +651,54 @@
|
||||||
// of the type given by its first argument.
|
// of the type given by its first argument.
|
||||||
|
|
||||||
case 47: // '/'
|
case 47: // '/'
|
||||||
if (tokRegexpAllowed) {++tokPos; return readRegexp();}
|
return readToken_slash(code);
|
||||||
if (next === 61) return finishOp(_assign, 2);
|
|
||||||
return finishOp(_slash, 1);
|
|
||||||
|
|
||||||
case 37: case 42: // '%*'
|
case 37: case 42: // '%*'
|
||||||
if (next === 61) return finishOp(_assign, 2);
|
return readToken_mult_modulo();
|
||||||
return finishOp(_bin10, 1);
|
|
||||||
|
|
||||||
case 124: case 38: // '|&'
|
case 124: case 38: // '|&'
|
||||||
if (next === code) return finishOp(code === 124 ? _bin1 : _bin2, 2);
|
return readToken_pipe_amp(code);
|
||||||
if (next === 61) return finishOp(_assign, 2);
|
|
||||||
return finishOp(code === 124 ? _bin3 : _bin5, 1);
|
|
||||||
|
|
||||||
case 94: // '^'
|
case 94: // '^'
|
||||||
if (next === 61) return finishOp(_assign, 2);
|
return readToken_caret();
|
||||||
return finishOp(_bin4, 1);
|
|
||||||
|
|
||||||
case 43: case 45: // '+-'
|
case 43: case 45: // '+-'
|
||||||
if (next === code) return finishOp(_incdec, 2);
|
return readToken_plus_min(code);
|
||||||
if (next === 61) return finishOp(_assign, 2);
|
|
||||||
return finishOp(_plusmin, 1);
|
|
||||||
|
|
||||||
case 60: case 62: // '<>'
|
case 60: case 62: // '<>'
|
||||||
var size = 1;
|
return readToken_lt_gt(code);
|
||||||
if (next === code) {
|
|
||||||
size = code === 62 && input.charCodeAt(tokPos+2) === 62 ? 3 : 2;
|
|
||||||
if (input.charCodeAt(tokPos + size) === 61) return finishOp(_assign, size + 1);
|
|
||||||
return finishOp(_bin8, size);
|
|
||||||
}
|
|
||||||
if (next === 61)
|
|
||||||
size = input.charCodeAt(tokPos+2) === 61 ? 3 : 2;
|
|
||||||
return finishOp(_bin7, size);
|
|
||||||
|
|
||||||
case 61: case 33: // '=!'
|
case 61: case 33: // '=!'
|
||||||
if (next === 61) return finishOp(_bin6, input.charCodeAt(tokPos+2) === 61 ? 3 : 2);
|
return readToken_eq_excl(code);
|
||||||
return finishOp(code === 61 ? _eq : _prefix, 1);
|
|
||||||
|
|
||||||
case 126: // '~'
|
case 126: // '~'
|
||||||
return finishOp(_prefix, 1);
|
return finishOp(_prefix, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are here, we either found a non-ASCII identifier
|
return false;
|
||||||
// character, or something that's entirely disallowed.
|
}
|
||||||
var ch = String.fromCharCode(code);
|
|
||||||
if (ch === "\\" || nonASCIIidentifierStart.test(ch)) return readWord();
|
function readToken(forceRegexp) {
|
||||||
raise(tokPos, "Unexpected character '" + ch + "'");
|
tokStart = tokPos;
|
||||||
|
if (options.locations) tokStartLoc = new line_loc_t;
|
||||||
|
if (forceRegexp) return readRegexp();
|
||||||
|
if (tokPos >= inputLen) return finishToken(_eof);
|
||||||
|
|
||||||
|
var code = input.charCodeAt(tokPos);
|
||||||
|
// Identifier or keyword. '\uXXXX' sequences are allowed in
|
||||||
|
// identifiers, so '\' also dispatches to that.
|
||||||
|
if (isIdentifierStart(code) || code === 92 /* '\' */) return readWord();
|
||||||
|
|
||||||
|
var tok = getTokenFromCode(code);
|
||||||
|
|
||||||
|
if (tok === false) {
|
||||||
|
// If we are here, we either found a non-ASCII identifier
|
||||||
|
// character, or something that's entirely disallowed.
|
||||||
|
var ch = String.fromCharCode(code);
|
||||||
|
if (ch === "\\" || nonASCIIidentifierStart.test(ch)) return readWord();
|
||||||
|
raise(tokPos, "Unexpected character '" + ch + "'");
|
||||||
|
}
|
||||||
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
function finishOp(type, size) {
|
function finishOp(type, size) {
|
||||||
|
@ -624,7 +739,7 @@
|
||||||
|
|
||||||
function readInt(radix, len) {
|
function readInt(radix, len) {
|
||||||
var start = tokPos, total = 0;
|
var start = tokPos, total = 0;
|
||||||
for (;;) {
|
for (var i = 0, e = len == null ? Infinity : len; i < e; ++i) {
|
||||||
var code = input.charCodeAt(tokPos), val;
|
var code = input.charCodeAt(tokPos), val;
|
||||||
if (code >= 97) val = code - 97 + 10; // a
|
if (code >= 97) val = code - 97 + 10; // a
|
||||||
else if (code >= 65) val = code - 65 + 10; // A
|
else if (code >= 65) val = code - 65 + 10; // A
|
||||||
|
@ -649,18 +764,18 @@
|
||||||
|
|
||||||
// Read an integer, octal integer, or floating-point number.
|
// Read an integer, octal integer, or floating-point number.
|
||||||
|
|
||||||
function readNumber(ch) {
|
function readNumber(startsWithDot) {
|
||||||
var start = tokPos, isFloat = ch === ".";
|
var start = tokPos, isFloat = false, octal = input.charCodeAt(tokPos) === 48;
|
||||||
if (!isFloat && readInt(10) == null) raise(start, "Invalid number");
|
if (!startsWithDot && readInt(10) === null) raise(start, "Invalid number");
|
||||||
if (isFloat || input.charAt(tokPos) === ".") {
|
if (input.charCodeAt(tokPos) === 46) {
|
||||||
var next = input.charAt(++tokPos);
|
++tokPos;
|
||||||
if (next === "-" || next === "+") ++tokPos;
|
readInt(10);
|
||||||
if (readInt(10) === null && ch === ".") raise(start, "Invalid number");
|
|
||||||
isFloat = true;
|
isFloat = true;
|
||||||
}
|
}
|
||||||
if (/e/i.test(input.charAt(tokPos))) {
|
var next = input.charCodeAt(tokPos);
|
||||||
var next = input.charAt(++tokPos);
|
if (next === 69 || next === 101) { // 'eE'
|
||||||
if (next === "-" || next === "+") ++tokPos;
|
next = input.charCodeAt(++tokPos);
|
||||||
|
if (next === 43 || next === 45) ++tokPos; // '+-'
|
||||||
if (readInt(10) === null) raise(start, "Invalid number")
|
if (readInt(10) === null) raise(start, "Invalid number")
|
||||||
isFloat = true;
|
isFloat = true;
|
||||||
}
|
}
|
||||||
|
@ -668,7 +783,7 @@
|
||||||
|
|
||||||
var str = input.slice(start, tokPos), val;
|
var str = input.slice(start, tokPos), val;
|
||||||
if (isFloat) val = parseFloat(str);
|
if (isFloat) val = parseFloat(str);
|
||||||
else if (ch !== "0" || str.length === 1) val = parseInt(str, 10);
|
else if (!octal || str.length === 1) val = parseInt(str, 10);
|
||||||
else if (/[89]/.test(str) || strict) raise(start, "Invalid number");
|
else if (/[89]/.test(str) || strict) raise(start, "Invalid number");
|
||||||
else val = parseInt(str, 8);
|
else val = parseInt(str, 8);
|
||||||
return finishToken(_num, val);
|
return finishToken(_num, val);
|
||||||
|
@ -678,13 +793,13 @@
|
||||||
|
|
||||||
function readString(quote) {
|
function readString(quote) {
|
||||||
tokPos++;
|
tokPos++;
|
||||||
var str = [];
|
var out = "";
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (tokPos >= inputLen) raise(tokStart, "Unterminated string constant");
|
if (tokPos >= inputLen) raise(tokStart, "Unterminated string constant");
|
||||||
var ch = input.charCodeAt(tokPos);
|
var ch = input.charCodeAt(tokPos);
|
||||||
if (ch === quote) {
|
if (ch === quote) {
|
||||||
++tokPos;
|
++tokPos;
|
||||||
return finishToken(_string, String.fromCharCode.apply(null, str));
|
return finishToken(_string, out);
|
||||||
}
|
}
|
||||||
if (ch === 92) { // '\'
|
if (ch === 92) { // '\'
|
||||||
ch = input.charCodeAt(++tokPos);
|
ch = input.charCodeAt(++tokPos);
|
||||||
|
@ -695,28 +810,30 @@
|
||||||
++tokPos;
|
++tokPos;
|
||||||
if (octal) {
|
if (octal) {
|
||||||
if (strict) raise(tokPos - 2, "Octal literal in strict mode");
|
if (strict) raise(tokPos - 2, "Octal literal in strict mode");
|
||||||
str.push(parseInt(octal, 8));
|
out += String.fromCharCode(parseInt(octal, 8));
|
||||||
tokPos += octal.length - 1;
|
tokPos += octal.length - 1;
|
||||||
} else {
|
} else {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 110: str.push(10); break; // 'n' -> '\n'
|
case 110: out += "\n"; break; // 'n' -> '\n'
|
||||||
case 114: str.push(13); break; // 'r' -> '\r'
|
case 114: out += "\r"; break; // 'r' -> '\r'
|
||||||
case 120: str.push(readHexChar(2)); break; // 'x'
|
case 120: out += String.fromCharCode(readHexChar(2)); break; // 'x'
|
||||||
case 117: str.push(readHexChar(4)); break; // 'u'
|
case 117: out += String.fromCharCode(readHexChar(4)); break; // 'u'
|
||||||
case 85: str.push(readHexChar(8)); break; // 'U'
|
case 85: out += String.fromCharCode(readHexChar(8)); break; // 'U'
|
||||||
case 116: str.push(9); break; // 't' -> '\t'
|
case 116: out += "\t"; break; // 't' -> '\t'
|
||||||
case 98: str.push(8); break; // 'b' -> '\b'
|
case 98: out += "\b"; break; // 'b' -> '\b'
|
||||||
case 118: str.push(11); break; // 'v' -> '\u000b'
|
case 118: out += "\v"; break; // 'v' -> '\u000b'
|
||||||
case 102: str.push(12); break; // 'f' -> '\f'
|
case 102: out += "\f"; break; // 'f' -> '\f'
|
||||||
case 48: str.push(0); break; // 0 -> '\0'
|
case 48: out += "\0"; break; // 0 -> '\0'
|
||||||
case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; // '\r\n'
|
case 13: if (input.charCodeAt(tokPos) === 10) ++tokPos; // '\r\n'
|
||||||
case 10: break; // ' \n'
|
case 10: // ' \n'
|
||||||
default: str.push(ch); break;
|
if (options.locations) { tokLineStart = tokPos; ++tokCurLine; }
|
||||||
|
break;
|
||||||
|
default: out += String.fromCharCode(ch); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (ch === 13 || ch === 10 || ch === 8232 || ch === 8329) raise(tokStart, "Unterminated string constant");
|
if (ch === 13 || ch === 10 || ch === 8232 || ch === 8329) raise(tokStart, "Unterminated string constant");
|
||||||
if (ch !== 92) str.push(ch); // '\'
|
out += String.fromCharCode(ch); // '\'
|
||||||
++tokPos;
|
++tokPos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -827,65 +944,51 @@
|
||||||
readToken();
|
readToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start an AST node, attaching a start offset and optionally a
|
// Start an AST node, attaching a start offset.
|
||||||
// `commentsBefore` property to it.
|
|
||||||
|
function node_t() {
|
||||||
|
this.type = null;
|
||||||
|
this.start = tokStart;
|
||||||
|
this.end = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function node_loc_t() {
|
||||||
|
this.start = tokStartLoc;
|
||||||
|
this.end = null;
|
||||||
|
if (sourceFile !== null) this.source = sourceFile;
|
||||||
|
}
|
||||||
|
|
||||||
function startNode() {
|
function startNode() {
|
||||||
var node = {type: null, start: tokStart, end: null};
|
var node = new node_t();
|
||||||
if (options.trackComments && tokCommentsBefore) {
|
|
||||||
node.commentsBefore = tokCommentsBefore;
|
|
||||||
tokCommentsBefore = null;
|
|
||||||
}
|
|
||||||
if (options.locations)
|
if (options.locations)
|
||||||
node.loc = {start: tokStartLoc, end: null, source: sourceFile};
|
node.loc = new node_loc_t();
|
||||||
if (options.ranges)
|
if (options.ranges)
|
||||||
node.range = [tokStart, 0];
|
node.range = [tokStart, 0];
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start a node whose start offset/comments information should be
|
// Start a node whose start offset information should be based on
|
||||||
// based on the start of another node. For example, a binary
|
// the start of another node. For example, a binary operator node is
|
||||||
// operator node is only started after its left-hand side has
|
// only started after its left-hand side has already been parsed.
|
||||||
// already been parsed.
|
|
||||||
|
|
||||||
function startNodeFrom(other) {
|
function startNodeFrom(other) {
|
||||||
var node = {type: null, start: other.start};
|
var node = new node_t();
|
||||||
if (other.commentsBefore) {
|
node.start = other.start;
|
||||||
node.commentsBefore = other.commentsBefore;
|
if (options.locations) {
|
||||||
other.commentsBefore = null;
|
node.loc = new node_loc_t();
|
||||||
|
node.loc.start = other.loc.start;
|
||||||
}
|
}
|
||||||
if (options.locations)
|
|
||||||
node.loc = {start: other.loc.start, end: null, source: other.loc.source};
|
|
||||||
if (options.ranges)
|
if (options.ranges)
|
||||||
node.range = [other.range[0], 0];
|
node.range = [other.range[0], 0];
|
||||||
|
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finish an AST node, adding `type`, `end`, and `commentsAfter`
|
// Finish an AST node, adding `type` and `end` properties.
|
||||||
// properties.
|
|
||||||
//
|
|
||||||
// We keep track of the last node that we finished, in order
|
|
||||||
// 'bubble' `commentsAfter` properties up to the biggest node. I.e.
|
|
||||||
// in '`1 + 1 // foo', the comment should be attached to the binary
|
|
||||||
// operator node, not the second literal node.
|
|
||||||
|
|
||||||
var lastFinishedNode;
|
|
||||||
|
|
||||||
function finishNode(node, type) {
|
function finishNode(node, type) {
|
||||||
node.type = type;
|
node.type = type;
|
||||||
node.end = lastEnd;
|
node.end = lastEnd;
|
||||||
if (options.trackComments) {
|
|
||||||
if (tokCommentsAfter) {
|
|
||||||
node.commentsAfter = tokCommentsAfter;
|
|
||||||
tokCommentsAfter = null;
|
|
||||||
} else if (lastFinishedNode && lastFinishedNode.end === lastEnd &&
|
|
||||||
lastFinishedNode.commentsAfter) {
|
|
||||||
node.commentsAfter = lastFinishedNode.commentsAfter;
|
|
||||||
lastFinishedNode.commentsAfter = null;
|
|
||||||
}
|
|
||||||
lastFinishedNode = node;
|
|
||||||
}
|
|
||||||
if (options.locations)
|
if (options.locations)
|
||||||
node.loc.end = lastEndLoc;
|
node.loc.end = lastEndLoc;
|
||||||
if (options.ranges)
|
if (options.ranges)
|
||||||
|
@ -956,9 +1059,8 @@
|
||||||
// to its body instead of creating a new node.
|
// to its body instead of creating a new node.
|
||||||
|
|
||||||
function parseTopLevel(program) {
|
function parseTopLevel(program) {
|
||||||
initTokenState();
|
|
||||||
lastStart = lastEnd = tokPos;
|
lastStart = lastEnd = tokPos;
|
||||||
if (options.locations) lastEndLoc = curLineLoc();
|
if (options.locations) lastEndLoc = new line_loc_t;
|
||||||
inFunction = strict = null;
|
inFunction = strict = null;
|
||||||
labels = [];
|
labels = [];
|
||||||
readToken();
|
readToken();
|
||||||
|
@ -972,7 +1074,7 @@
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
return finishNode(node, "Program");
|
return finishNode(node, "Program");
|
||||||
};
|
}
|
||||||
|
|
||||||
var loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"};
|
var loopLabel = {kind: "loop"}, switchLabel = {kind: "switch"};
|
||||||
|
|
||||||
|
@ -1018,6 +1120,7 @@
|
||||||
|
|
||||||
case _debugger:
|
case _debugger:
|
||||||
next();
|
next();
|
||||||
|
semicolon();
|
||||||
return finishNode(node, "DebuggerStatement");
|
return finishNode(node, "DebuggerStatement");
|
||||||
|
|
||||||
case _do:
|
case _do:
|
||||||
|
@ -1117,6 +1220,7 @@
|
||||||
if (newline.test(input.slice(lastEnd, tokStart)))
|
if (newline.test(input.slice(lastEnd, tokStart)))
|
||||||
raise(lastEnd, "Illegal newline after throw");
|
raise(lastEnd, "Illegal newline after throw");
|
||||||
node.argument = parseExpression();
|
node.argument = parseExpression();
|
||||||
|
semicolon();
|
||||||
return finishNode(node, "ThrowStatement");
|
return finishNode(node, "ThrowStatement");
|
||||||
|
|
||||||
case _try:
|
case _try:
|
||||||
|
@ -1182,6 +1286,7 @@
|
||||||
var kind = tokType.isLoop ? "loop" : tokType === _switch ? "switch" : null;
|
var kind = tokType.isLoop ? "loop" : tokType === _switch ? "switch" : null;
|
||||||
labels.push({name: maybeName, kind: kind});
|
labels.push({name: maybeName, kind: kind});
|
||||||
node.body = parseStatement();
|
node.body = parseStatement();
|
||||||
|
labels.pop();
|
||||||
node.label = expr;
|
node.label = expr;
|
||||||
return finishNode(node, "LabeledStatement");
|
return finishNode(node, "LabeledStatement");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1429,6 +1534,7 @@
|
||||||
case _null: case _true: case _false:
|
case _null: case _true: case _false:
|
||||||
var node = startNode();
|
var node = startNode();
|
||||||
node.value = tokType.atomValue;
|
node.value = tokType.atomValue;
|
||||||
|
node.raw = tokType.keyword
|
||||||
next();
|
next();
|
||||||
return finishNode(node, "Literal");
|
return finishNode(node, "Literal");
|
||||||
|
|
||||||
|
@ -1476,7 +1582,7 @@
|
||||||
function parseNew() {
|
function parseNew() {
|
||||||
var node = startNode();
|
var node = startNode();
|
||||||
next();
|
next();
|
||||||
node.callee = parseSubscripts(parseExprAtom(false), true);
|
node.callee = parseSubscripts(parseExprAtom(), true);
|
||||||
if (eat(_parenL)) node.arguments = parseExprList(_parenR, false);
|
if (eat(_parenL)) node.arguments = parseExprList(_parenR, false);
|
||||||
else node.arguments = [];
|
else node.arguments = [];
|
||||||
return finishNode(node, "NewExpression");
|
return finishNode(node, "NewExpression");
|
||||||
|
@ -1503,7 +1609,7 @@
|
||||||
isGetSet = sawGetSet = true;
|
isGetSet = sawGetSet = true;
|
||||||
kind = prop.kind = prop.key.name;
|
kind = prop.kind = prop.key.name;
|
||||||
prop.key = parsePropertyName();
|
prop.key = parsePropertyName();
|
||||||
if (!tokType === _parenL) unexpected();
|
if (tokType !== _parenL) unexpected();
|
||||||
prop.value = parseFunction(startNode(), false);
|
prop.value = parseFunction(startNode(), false);
|
||||||
} else unexpected();
|
} else unexpected();
|
||||||
|
|
||||||
|
@ -1601,4 +1707,4 @@
|
||||||
return finishNode(node, "Identifier");
|
return finishNode(node, "Identifier");
|
||||||
}
|
}
|
||||||
|
|
||||||
})(typeof exports === "undefined" ? (window.acorn = {}) : exports);
|
})(typeof exports === "undefined" ? (self.acorn = {}) : exports);
|
Loading…
Reference in a new issue