acorn
Advanced tools
Comparing version 2.0.4 to 2.1.0
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.acorn || (g.acorn = {})).loose = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
var _interopRequireWildcard = function (obj) { return obj && obj.__esModule ? obj : { "default": obj }; }; | ||
exports.parse_dammit = parse_dammit; | ||
exports.__esModule = true; | ||
// Acorn: Loose parser | ||
// | ||
// This module provides an alternative parser (`parse_dammit`) that | ||
// exposes that same interface as `parse`, but will try to parse | ||
// anything as JavaScript, repairing syntax error the best it can. | ||
// There are circumstances in which it will raise an error and give | ||
// up, but they are very rare. The resulting AST will be a mostly | ||
// valid JavaScript AST (as per the [Mozilla parser API][api], except | ||
// that: | ||
// | ||
// - Return outside functions is allowed | ||
// | ||
// - Label consistency (no conflicts, break only to existing labels) | ||
// is not enforced. | ||
// | ||
// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever | ||
// the parser got too confused to return anything meaningful. | ||
// | ||
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API | ||
// | ||
// The expected use for this is to *first* try `acorn.parse`, and only | ||
// if that fails switch to `parse_dammit`. The loose parser might | ||
// parse badly indented code incorrectly, so **don't** use it as | ||
// your default parser. | ||
// | ||
// Quite a lot of acorn.js is duplicated here. The alternative was to | ||
// add a *lot* of extra cruft to that file, making it less readable | ||
// and slower. Copying and editing the code allowed me to make | ||
// invasive changes and simplifications without creating a complicated | ||
// tangle. | ||
var acorn = _interopRequireWildcard(_dereq_("..")); | ||
var _state = _dereq_("./state"); | ||
var LooseParser = _state.LooseParser; | ||
_dereq_("./tokenize"); | ||
_dereq_("./parseutil"); | ||
_dereq_("./statement"); | ||
_dereq_("./expression"); | ||
exports.LooseParser = _state.LooseParser; | ||
acorn.defaultOptions.tabSize = 4; | ||
function parse_dammit(input, options) { | ||
var p = new LooseParser(input, options); | ||
p.next(); | ||
return p.parseTopLevel(); | ||
} | ||
acorn.parse_dammit = parse_dammit; | ||
acorn.LooseParser = LooseParser; | ||
},{"..":2,"./expression":3,"./parseutil":4,"./state":5,"./statement":6,"./tokenize":7}],2:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
module.exports = typeof acorn != "undefined" ? acorn : _dereq_("./acorn"); | ||
},{}],3:[function(_dereq_,module,exports){ | ||
},{}],2:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
var LooseParser = _dereq_("./state").LooseParser; | ||
var _state = _dereq_("./state"); | ||
var isDummy = _dereq_("./parseutil").isDummy; | ||
var _parseutil = _dereq_("./parseutil"); | ||
var tt = _dereq_("..").tokTypes; | ||
var _ = _dereq_(".."); | ||
var lp = LooseParser.prototype; | ||
var lp = _state.LooseParser.prototype; | ||
@@ -110,6 +45,6 @@ lp.checkLVal = function (expr, binding) { | ||
var expr = this.parseMaybeAssign(noIn); | ||
if (this.tok.type === tt.comma) { | ||
if (this.tok.type === _.tokTypes.comma) { | ||
var node = this.startNodeAt(start); | ||
node.expressions = [expr]; | ||
while (this.eat(tt.comma)) node.expressions.push(this.parseMaybeAssign(noIn)); | ||
while (this.eat(_.tokTypes.comma)) node.expressions.push(this.parseMaybeAssign(noIn)); | ||
return this.finishNode(node, "SequenceExpression"); | ||
@@ -122,6 +57,6 @@ } | ||
this.pushCx(); | ||
this.expect(tt.parenL); | ||
this.expect(_.tokTypes.parenL); | ||
var val = this.parseExpression(); | ||
this.popCx(); | ||
this.expect(tt.parenR); | ||
this.expect(_.tokTypes.parenR); | ||
return val; | ||
@@ -136,3 +71,3 @@ }; | ||
node.operator = this.tok.value; | ||
node.left = this.tok.type === tt.eq ? this.toAssignable(left) : this.checkLVal(left); | ||
node.left = this.tok.type === _.tokTypes.eq ? this.toAssignable(left) : this.checkLVal(left); | ||
this.next(); | ||
@@ -148,7 +83,7 @@ node.right = this.parseMaybeAssign(noIn); | ||
var expr = this.parseExprOps(noIn); | ||
if (this.eat(tt.question)) { | ||
if (this.eat(_.tokTypes.question)) { | ||
var node = this.startNodeAt(start); | ||
node.test = expr; | ||
node.consequent = this.parseMaybeAssign(); | ||
node.alternate = this.expect(tt.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent(); | ||
node.alternate = this.expect(_.tokTypes.colon) ? this.parseMaybeAssign(noIn) : this.dummyIdent(); | ||
return this.finishNode(node, "ConditionalExpression"); | ||
@@ -169,3 +104,3 @@ } | ||
var prec = this.tok.type.binop; | ||
if (prec != null && (!noIn || this.tok.type !== tt._in)) { | ||
if (prec != null && (!noIn || this.tok.type !== _.tokTypes._in)) { | ||
if (prec > minPrec) { | ||
@@ -192,3 +127,3 @@ var node = this.startNodeAt(start); | ||
var node = this.startNode(), | ||
update = this.tok.type === tt.incDec; | ||
update = this.tok.type === _.tokTypes.incDec; | ||
node.operator = this.tok.value; | ||
@@ -200,3 +135,3 @@ node.prefix = true; | ||
return this.finishNode(node, update ? "UpdateExpression" : "UnaryExpression"); | ||
} else if (this.tok.type === tt.ellipsis) { | ||
} else if (this.tok.type === _.tokTypes.ellipsis) { | ||
var node = this.startNode(); | ||
@@ -228,6 +163,6 @@ this.next(); | ||
if (this.curLineStart != line && this.curIndent <= startIndent && this.tokenStartsLine()) { | ||
if (this.tok.type == tt.dot && this.curIndent == startIndent) --startIndent;else return base; | ||
if (this.tok.type == _.tokTypes.dot && this.curIndent == startIndent) --startIndent;else return base; | ||
} | ||
if (this.eat(tt.dot)) { | ||
if (this.eat(_.tokTypes.dot)) { | ||
var node = this.startNodeAt(start); | ||
@@ -238,3 +173,3 @@ node.object = base; | ||
base = this.finishNode(node, "MemberExpression"); | ||
} else if (this.tok.type == tt.bracketL) { | ||
} else if (this.tok.type == _.tokTypes.bracketL) { | ||
this.pushCx(); | ||
@@ -247,10 +182,10 @@ this.next(); | ||
this.popCx(); | ||
this.expect(tt.bracketR); | ||
this.expect(_.tokTypes.bracketR); | ||
base = this.finishNode(node, "MemberExpression"); | ||
} else if (!noCalls && this.tok.type == tt.parenL) { | ||
} else if (!noCalls && this.tok.type == _.tokTypes.parenL) { | ||
var node = this.startNodeAt(start); | ||
node.callee = base; | ||
node.arguments = this.parseExprList(tt.parenR); | ||
node.arguments = this.parseExprList(_.tokTypes.parenR); | ||
base = this.finishNode(node, "CallExpression"); | ||
} else if (this.tok.type == tt.backQuote) { | ||
} else if (this.tok.type == _.tokTypes.backQuote) { | ||
var node = this.startNodeAt(start); | ||
@@ -269,5 +204,5 @@ node.tag = base; | ||
switch (this.tok.type) { | ||
case tt._this: | ||
case tt._super: | ||
var type = this.tok.type === tt._this ? "ThisExpression" : "Super"; | ||
case _.tokTypes._this: | ||
case _.tokTypes._super: | ||
var type = this.tok.type === _.tokTypes._this ? "ThisExpression" : "Super"; | ||
node = this.startNode(); | ||
@@ -277,8 +212,8 @@ this.next(); | ||
case tt.name: | ||
case _.tokTypes.name: | ||
var start = this.storeCurrentPos(); | ||
var id = this.parseIdent(); | ||
return this.eat(tt.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id]) : id; | ||
return this.eat(_.tokTypes.arrow) ? this.parseArrowExpression(this.startNodeAt(start), [id]) : id; | ||
case tt.regexp: | ||
case _.tokTypes.regexp: | ||
node = this.startNode(); | ||
@@ -292,3 +227,3 @@ var val = this.tok.value; | ||
case tt.num:case tt.string: | ||
case _.tokTypes.num:case _.tokTypes.string: | ||
node = this.startNode(); | ||
@@ -300,5 +235,5 @@ node.value = this.tok.value; | ||
case tt._null:case tt._true:case tt._false: | ||
case _.tokTypes._null:case _.tokTypes._true:case _.tokTypes._false: | ||
node = this.startNode(); | ||
node.value = this.tok.type === tt._null ? null : this.tok.type === tt._true; | ||
node.value = this.tok.type === _.tokTypes._null ? null : this.tok.type === _.tokTypes._true; | ||
node.raw = this.tok.type.keyword; | ||
@@ -308,9 +243,9 @@ this.next(); | ||
case tt.parenL: | ||
case _.tokTypes.parenL: | ||
var parenStart = this.storeCurrentPos(); | ||
this.next(); | ||
var inner = this.parseExpression(); | ||
this.expect(tt.parenR); | ||
if (this.eat(tt.arrow)) { | ||
return this.parseArrowExpression(this.startNodeAt(parenStart), inner.expressions || (isDummy(inner) ? [] : [inner])); | ||
this.expect(_.tokTypes.parenR); | ||
if (this.eat(_.tokTypes.arrow)) { | ||
return this.parseArrowExpression(this.startNodeAt(parenStart), inner.expressions || (_parseutil.isDummy(inner) ? [] : [inner])); | ||
} | ||
@@ -324,14 +259,14 @@ if (this.options.preserveParens) { | ||
case tt.bracketL: | ||
case _.tokTypes.bracketL: | ||
node = this.startNode(); | ||
node.elements = this.parseExprList(tt.bracketR, true); | ||
node.elements = this.parseExprList(_.tokTypes.bracketR, true); | ||
return this.finishNode(node, "ArrayExpression"); | ||
case tt.braceL: | ||
case _.tokTypes.braceL: | ||
return this.parseObj(); | ||
case tt._class: | ||
case _.tokTypes._class: | ||
return this.parseClass(); | ||
case tt._function: | ||
case _.tokTypes._function: | ||
node = this.startNode(); | ||
@@ -341,13 +276,13 @@ this.next(); | ||
case tt._new: | ||
case _.tokTypes._new: | ||
return this.parseNew(); | ||
case tt._yield: | ||
case _.tokTypes._yield: | ||
node = this.startNode(); | ||
this.next(); | ||
if (this.semicolon() || this.canInsertSemicolon() || this.tok.type != tt.star && !this.tok.type.startsExpr) { | ||
if (this.semicolon() || this.canInsertSemicolon() || this.tok.type != _.tokTypes.star && !this.tok.type.startsExpr) { | ||
node.delegate = false; | ||
node.argument = null; | ||
} else { | ||
node.delegate = this.eat(tt.star); | ||
node.delegate = this.eat(_.tokTypes.star); | ||
node.argument = this.parseMaybeAssign(); | ||
@@ -357,3 +292,3 @@ } | ||
case tt.backQuote: | ||
case _.tokTypes.backQuote: | ||
return this.parseTemplate(); | ||
@@ -371,3 +306,3 @@ | ||
var meta = this.parseIdent(true); | ||
if (this.options.ecmaVersion >= 6 && this.eat(tt.dot)) { | ||
if (this.options.ecmaVersion >= 6 && this.eat(_.tokTypes.dot)) { | ||
node.meta = meta; | ||
@@ -379,4 +314,4 @@ node.property = this.parseIdent(true); | ||
node.callee = this.parseSubscripts(this.parseExprAtom(), start, true, startIndent, line); | ||
if (this.tok.type == tt.parenL) { | ||
node.arguments = this.parseExprList(tt.parenR); | ||
if (this.tok.type == _.tokTypes.parenL) { | ||
node.arguments = this.parseExprList(_.tokTypes.parenR); | ||
} else { | ||
@@ -395,3 +330,3 @@ node.arguments = []; | ||
this.next(); | ||
elem.tail = this.tok.type === tt.backQuote; | ||
elem.tail = this.tok.type === _.tokTypes.backQuote; | ||
return this.finishNode(elem, "TemplateElement"); | ||
@@ -409,3 +344,3 @@ }; | ||
node.expressions.push(this.parseExpression()); | ||
if (this.expect(tt.braceR)) { | ||
if (this.expect(_.tokTypes.braceR)) { | ||
curElt = this.parseTemplateElement(); | ||
@@ -419,3 +354,3 @@ } else { | ||
} | ||
this.expect(tt.backQuote); | ||
this.expect(_.tokTypes.backQuote); | ||
return this.finishNode(node, "TemplateLiteral"); | ||
@@ -430,7 +365,7 @@ }; | ||
line = this.curLineStart; | ||
this.eat(tt.braceL); | ||
this.eat(_.tokTypes.braceL); | ||
if (this.curIndent + 1 < indent) { | ||
indent = this.curIndent;line = this.curLineStart; | ||
} | ||
while (!this.closes(tt.braceR, indent, line)) { | ||
while (!this.closes(_.tokTypes.braceR, indent, line)) { | ||
var prop = this.startNode(), | ||
@@ -443,16 +378,16 @@ isGenerator = undefined, | ||
prop.shorthand = false; | ||
isGenerator = this.eat(tt.star); | ||
isGenerator = this.eat(_.tokTypes.star); | ||
} | ||
this.parsePropertyName(prop); | ||
if (isDummy(prop.key)) { | ||
if (isDummy(this.parseMaybeAssign())) this.next();this.eat(tt.comma);continue; | ||
if (_parseutil.isDummy(prop.key)) { | ||
if (_parseutil.isDummy(this.parseMaybeAssign())) this.next();this.eat(_.tokTypes.comma);continue; | ||
} | ||
if (this.eat(tt.colon)) { | ||
if (this.eat(_.tokTypes.colon)) { | ||
prop.kind = "init"; | ||
prop.value = this.parseMaybeAssign(); | ||
} else if (this.options.ecmaVersion >= 6 && (this.tok.type === tt.parenL || this.tok.type === tt.braceL)) { | ||
} else if (this.options.ecmaVersion >= 6 && (this.tok.type === _.tokTypes.parenL || this.tok.type === _.tokTypes.braceL)) { | ||
prop.kind = "init"; | ||
prop.method = true; | ||
prop.value = this.parseMethod(isGenerator); | ||
} else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && (this.tok.type != tt.comma && this.tok.type != tt.braceR)) { | ||
} else if (this.options.ecmaVersion >= 5 && prop.key.type === "Identifier" && !prop.computed && (prop.key.name === "get" || prop.key.name === "set") && (this.tok.type != _.tokTypes.comma && this.tok.type != _.tokTypes.braceR)) { | ||
prop.kind = prop.key.name; | ||
@@ -464,3 +399,3 @@ this.parsePropertyName(prop); | ||
if (this.options.ecmaVersion >= 6) { | ||
if (this.eat(tt.eq)) { | ||
if (this.eat(_.tokTypes.eq)) { | ||
var assign = this.startNodeAt(start); | ||
@@ -480,6 +415,6 @@ assign.operator = "="; | ||
node.properties.push(this.finishNode(prop, "Property")); | ||
this.eat(tt.comma); | ||
this.eat(_.tokTypes.comma); | ||
} | ||
this.popCx(); | ||
if (!this.eat(tt.braceR)) { | ||
if (!this.eat(_.tokTypes.braceR)) { | ||
// If there is no closing brace, make the node span to the start | ||
@@ -495,6 +430,6 @@ // of the next token (this is useful for Tern) | ||
if (this.options.ecmaVersion >= 6) { | ||
if (this.eat(tt.bracketL)) { | ||
if (this.eat(_.tokTypes.bracketL)) { | ||
prop.computed = true; | ||
prop.key = this.parseExpression(); | ||
this.expect(tt.bracketR); | ||
this.expect(_.tokTypes.bracketR); | ||
return; | ||
@@ -505,3 +440,3 @@ } else { | ||
} | ||
var key = this.tok.type === tt.num || this.tok.type === tt.string ? this.parseExprAtom() : this.parseIdent(); | ||
var key = this.tok.type === _.tokTypes.num || this.tok.type === _.tokTypes.string ? this.parseExprAtom() : this.parseIdent(); | ||
prop.key = key || this.dummyIdent(); | ||
@@ -511,7 +446,7 @@ }; | ||
lp.parsePropertyAccessor = function () { | ||
if (this.tok.type === tt.name || this.tok.type.keyword) return this.parseIdent(); | ||
if (this.tok.type === _.tokTypes.name || this.tok.type.keyword) return this.parseIdent(); | ||
}; | ||
lp.parseIdent = function () { | ||
var name = this.tok.type === tt.name ? this.tok.value : this.tok.type.keyword; | ||
var name = this.tok.type === _.tokTypes.name ? this.tok.value : this.tok.type.keyword; | ||
if (!name) return this.dummyIdent(); | ||
@@ -572,3 +507,3 @@ var node = this.startNode(); | ||
lp.parseFunctionParams = function (params) { | ||
params = this.parseExprList(tt.parenR); | ||
params = this.parseExprList(_.tokTypes.parenR); | ||
return this.toAssignableList(params, true); | ||
@@ -582,3 +517,3 @@ }; | ||
node.generator = isGenerator || false; | ||
node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== tt.braceL; | ||
node.expression = this.options.ecmaVersion >= 6 && this.tok.type !== _.tokTypes.braceL; | ||
node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock(); | ||
@@ -591,3 +526,3 @@ return this.finishNode(node, "FunctionExpression"); | ||
node.params = this.toAssignableList(params, true); | ||
node.expression = this.tok.type !== tt.braceL; | ||
node.expression = this.tok.type !== _.tokTypes.braceL; | ||
node.body = node.expression ? this.parseMaybeAssign() : this.parseBlock(); | ||
@@ -604,3 +539,3 @@ return this.finishNode(node, "ArrowFunctionExpression"); | ||
while (!this.closes(close, indent + 1, line)) { | ||
if (this.eat(tt.comma)) { | ||
if (this.eat(_.tokTypes.comma)) { | ||
elts.push(allowEmpty ? null : this.dummyIdent()); | ||
@@ -610,3 +545,3 @@ continue; | ||
var elt = this.parseMaybeAssign(); | ||
if (isDummy(elt)) { | ||
if (_parseutil.isDummy(elt)) { | ||
if (this.closes(close, indent, line)) break; | ||
@@ -617,3 +552,3 @@ this.next(); | ||
} | ||
this.eat(tt.comma); | ||
this.eat(_.tokTypes.comma); | ||
} | ||
@@ -630,61 +565,72 @@ this.popCx(); | ||
},{"..":2,"./parseutil":4,"./state":5}],4:[function(_dereq_,module,exports){ | ||
},{"..":1,"./parseutil":4,"./state":5}],3:[function(_dereq_,module,exports){ | ||
// Acorn: Loose parser | ||
// | ||
// This module provides an alternative parser (`parse_dammit`) that | ||
// exposes that same interface as `parse`, but will try to parse | ||
// anything as JavaScript, repairing syntax error the best it can. | ||
// There are circumstances in which it will raise an error and give | ||
// up, but they are very rare. The resulting AST will be a mostly | ||
// valid JavaScript AST (as per the [Mozilla parser API][api], except | ||
// that: | ||
// | ||
// - Return outside functions is allowed | ||
// | ||
// - Label consistency (no conflicts, break only to existing labels) | ||
// is not enforced. | ||
// | ||
// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever | ||
// the parser got too confused to return anything meaningful. | ||
// | ||
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API | ||
// | ||
// The expected use for this is to *first* try `acorn.parse`, and only | ||
// if that fails switch to `parse_dammit`. The loose parser might | ||
// parse badly indented code incorrectly, so **don't** use it as | ||
// your default parser. | ||
// | ||
// Quite a lot of acorn.js is duplicated here. The alternative was to | ||
// add a *lot* of extra cruft to that file, making it less readable | ||
// and slower. Copying and editing the code allowed me to make | ||
// invasive changes and simplifications without creating a complicated | ||
// tangle. | ||
"use strict"; | ||
exports.isDummy = isDummy; | ||
exports.__esModule = true; | ||
exports.parse_dammit = parse_dammit; | ||
var LooseParser = _dereq_("./state").LooseParser; | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj["default"] = obj; return newObj; } } | ||
var _ = _dereq_(".."); | ||
var Node = _.Node; | ||
var SourceLocation = _.SourceLocation; | ||
var lineBreak = _.lineBreak; | ||
var isNewLine = _.isNewLine; | ||
var tt = _.tokTypes; | ||
var acorn = _interopRequireWildcard(_); | ||
var lp = LooseParser.prototype; | ||
var _state = _dereq_("./state"); | ||
lp.startNode = function () { | ||
var node = new Node(); | ||
node.start = this.tok.start; | ||
if (this.options.locations) node.loc = new SourceLocation(this.toks, this.tok.loc.start); | ||
if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile; | ||
if (this.options.ranges) node.range = [this.tok.start, 0]; | ||
return node; | ||
}; | ||
_dereq_("./tokenize"); | ||
lp.storeCurrentPos = function () { | ||
return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start; | ||
}; | ||
_dereq_("./statement"); | ||
lp.startNodeAt = function (pos) { | ||
var node = new Node(); | ||
if (this.options.locations) { | ||
node.start = pos[0]; | ||
node.loc = new SourceLocation(this.toks, pos[1]); | ||
pos = pos[0]; | ||
} else { | ||
node.start = pos; | ||
} | ||
if (this.options.directSourceFile) node.sourceFile = this.options.directSourceFile; | ||
if (this.options.ranges) node.range = [pos, 0]; | ||
return node; | ||
}; | ||
_dereq_("./expression"); | ||
lp.finishNode = function (node, type) { | ||
node.type = type; | ||
node.end = this.last.end; | ||
if (this.options.locations) node.loc.end = this.last.loc.end; | ||
if (this.options.ranges) node.range[1] = this.last.end; | ||
return node; | ||
}; | ||
exports.LooseParser = _state.LooseParser; | ||
lp.dummyIdent = function () { | ||
var dummy = this.startNode(); | ||
dummy.name = "✖"; | ||
return this.finishNode(dummy, "Identifier"); | ||
}; | ||
acorn.defaultOptions.tabSize = 4; | ||
function parse_dammit(input, options) { | ||
var p = new _state.LooseParser(input, options); | ||
p.next(); | ||
return p.parseTopLevel(); | ||
} | ||
acorn.parse_dammit = parse_dammit; | ||
acorn.LooseParser = _state.LooseParser; | ||
},{"..":1,"./expression":2,"./state":5,"./statement":6,"./tokenize":7}],4:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports.isDummy = isDummy; | ||
function isDummy(node) { | ||
@@ -694,116 +640,149 @@ return node.name == "✖"; | ||
lp.eat = function (type) { | ||
if (this.tok.type === type) { | ||
this.next(); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
},{}],5:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
lp.isContextual = function (name) { | ||
return this.tok.type === tt.name && this.tok.value === name; | ||
}; | ||
exports.__esModule = true; | ||
lp.eatContextual = function (name) { | ||
return this.tok.value === name && this.eat(tt.name); | ||
}; | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
lp.canInsertSemicolon = function () { | ||
return this.tok.type === tt.eof || this.tok.type === tt.braceR || lineBreak.test(this.input.slice(this.last.end, this.tok.start)); | ||
}; | ||
var _ = _dereq_(".."); | ||
lp.semicolon = function () { | ||
return this.eat(tt.semi); | ||
}; | ||
var LooseParser = (function () { | ||
function LooseParser(input, options) { | ||
_classCallCheck(this, LooseParser); | ||
lp.expect = function (type) { | ||
if (this.eat(type)) return true; | ||
for (var i = 1; i <= 2; i++) { | ||
if (this.lookAhead(i).type == type) { | ||
for (var j = 0; j < i; j++) { | ||
this.next(); | ||
}return true; | ||
this.toks = _.tokenizer(input, options); | ||
this.options = this.toks.options; | ||
this.input = this.toks.input; | ||
this.tok = this.last = { type: _.tokTypes.eof, start: 0, end: 0 }; | ||
if (this.options.locations) { | ||
var here = this.toks.curPosition(); | ||
this.tok.loc = new _.SourceLocation(this.toks, here, here); | ||
} | ||
this.ahead = []; // Tokens ahead | ||
this.context = []; // Indentation contexted | ||
this.curIndent = 0; | ||
this.curLineStart = 0; | ||
this.nextLineStart = this.lineEnd(this.curLineStart) + 1; | ||
} | ||
}; | ||
lp.pushCx = function () { | ||
this.context.push(this.curIndent); | ||
}; | ||
lp.popCx = function () { | ||
this.curIndent = this.context.pop(); | ||
}; | ||
LooseParser.prototype.startNode = function startNode() { | ||
return new _.Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null); | ||
}; | ||
lp.lineEnd = function (pos) { | ||
while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos; | ||
return pos; | ||
}; | ||
LooseParser.prototype.storeCurrentPos = function storeCurrentPos() { | ||
return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start; | ||
}; | ||
lp.indentationAfter = function (pos) { | ||
for (var count = 0;; ++pos) { | ||
var ch = this.input.charCodeAt(pos); | ||
if (ch === 32) ++count;else if (ch === 9) count += this.options.tabSize;else return count; | ||
} | ||
}; | ||
LooseParser.prototype.startNodeAt = function startNodeAt(pos) { | ||
if (this.options.locations) { | ||
return new _.Node(this.toks, pos[0], pos[1]); | ||
} else { | ||
return new _.Node(this.toks, pos); | ||
} | ||
}; | ||
lp.closes = function (closeTok, indent, line, blockHeuristic) { | ||
if (this.tok.type === closeTok || this.tok.type === tt.eof) return true; | ||
return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && (!blockHeuristic || this.nextLineStart >= this.input.length || this.indentationAfter(this.nextLineStart) < indent); | ||
}; | ||
LooseParser.prototype.finishNode = function finishNode(node, type) { | ||
node.type = type; | ||
node.end = this.last.end; | ||
if (this.options.locations) node.loc.end = this.last.loc.end; | ||
if (this.options.ranges) node.range[1] = this.last.end; | ||
return node; | ||
}; | ||
lp.tokenStartsLine = function () { | ||
for (var p = this.tok.start - 1; p >= this.curLineStart; --p) { | ||
var ch = this.input.charCodeAt(p); | ||
if (ch !== 9 && ch !== 32) return false; | ||
} | ||
return true; | ||
}; | ||
LooseParser.prototype.dummyIdent = function dummyIdent() { | ||
var dummy = this.startNode(); | ||
dummy.name = "✖"; | ||
return this.finishNode(dummy, "Identifier"); | ||
}; | ||
},{"..":2,"./state":5}],5:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
LooseParser.prototype.eat = function eat(type) { | ||
if (this.tok.type === type) { | ||
this.next(); | ||
return true; | ||
} else { | ||
return false; | ||
} | ||
}; | ||
exports.LooseParser = LooseParser; | ||
exports.__esModule = true; | ||
LooseParser.prototype.isContextual = function isContextual(name) { | ||
return this.tok.type === _.tokTypes.name && this.tok.value === name; | ||
}; | ||
var _ = _dereq_(".."); | ||
LooseParser.prototype.eatContextual = function eatContextual(name) { | ||
return this.tok.value === name && this.eat(_.tokTypes.name); | ||
}; | ||
var tokenizer = _.tokenizer; | ||
var SourceLocation = _.SourceLocation; | ||
var tt = _.tokTypes; | ||
LooseParser.prototype.canInsertSemicolon = function canInsertSemicolon() { | ||
return this.tok.type === _.tokTypes.eof || this.tok.type === _.tokTypes.braceR || _.lineBreak.test(this.input.slice(this.last.end, this.tok.start)); | ||
}; | ||
function LooseParser(input, options) { | ||
this.toks = tokenizer(input, options); | ||
this.options = this.toks.options; | ||
this.input = this.toks.input; | ||
this.tok = this.last = { type: tt.eof, start: 0, end: 0 }; | ||
if (this.options.locations) { | ||
var here = this.toks.curPosition(); | ||
this.tok.loc = new SourceLocation(this.toks, here, here); | ||
} | ||
this.ahead = []; // Tokens ahead | ||
this.context = []; // Indentation contexted | ||
this.curIndent = 0; | ||
this.curLineStart = 0; | ||
this.nextLineStart = this.lineEnd(this.curLineStart) + 1; | ||
} | ||
LooseParser.prototype.semicolon = function semicolon() { | ||
return this.eat(_.tokTypes.semi); | ||
}; | ||
},{"..":2}],6:[function(_dereq_,module,exports){ | ||
LooseParser.prototype.expect = function expect(type) { | ||
if (this.eat(type)) return true; | ||
for (var i = 1; i <= 2; i++) { | ||
if (this.lookAhead(i).type == type) { | ||
for (var j = 0; j < i; j++) { | ||
this.next(); | ||
}return true; | ||
} | ||
} | ||
}; | ||
LooseParser.prototype.pushCx = function pushCx() { | ||
this.context.push(this.curIndent); | ||
}; | ||
LooseParser.prototype.popCx = function popCx() { | ||
this.curIndent = this.context.pop(); | ||
}; | ||
LooseParser.prototype.lineEnd = function lineEnd(pos) { | ||
while (pos < this.input.length && !_.isNewLine(this.input.charCodeAt(pos))) ++pos; | ||
return pos; | ||
}; | ||
LooseParser.prototype.indentationAfter = function indentationAfter(pos) { | ||
for (var count = 0;; ++pos) { | ||
var ch = this.input.charCodeAt(pos); | ||
if (ch === 32) ++count;else if (ch === 9) count += this.options.tabSize;else return count; | ||
} | ||
}; | ||
LooseParser.prototype.closes = function closes(closeTok, indent, line, blockHeuristic) { | ||
if (this.tok.type === closeTok || this.tok.type === _.tokTypes.eof) return true; | ||
return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && (!blockHeuristic || this.nextLineStart >= this.input.length || this.indentationAfter(this.nextLineStart) < indent); | ||
}; | ||
LooseParser.prototype.tokenStartsLine = function tokenStartsLine() { | ||
for (var p = this.tok.start - 1; p >= this.curLineStart; --p) { | ||
var ch = this.input.charCodeAt(p); | ||
if (ch !== 9 && ch !== 32) return false; | ||
} | ||
return true; | ||
}; | ||
return LooseParser; | ||
})(); | ||
exports.LooseParser = LooseParser; | ||
},{"..":1}],6:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
var LooseParser = _dereq_("./state").LooseParser; | ||
var _state = _dereq_("./state"); | ||
var isDummy = _dereq_("./parseutil").isDummy; | ||
var _parseutil = _dereq_("./parseutil"); | ||
var _ = _dereq_(".."); | ||
var getLineInfo = _.getLineInfo; | ||
var tt = _.tokTypes; | ||
var lp = _state.LooseParser.prototype; | ||
var lp = LooseParser.prototype; | ||
lp.parseTopLevel = function () { | ||
var node = this.startNodeAt(this.options.locations ? [0, getLineInfo(this.input, 0)] : 0); | ||
var node = this.startNodeAt(this.options.locations ? [0, _.getLineInfo(this.input, 0)] : 0); | ||
node.body = []; | ||
while (this.tok.type !== tt.eof) node.body.push(this.parseStatement()); | ||
while (this.tok.type !== _.tokTypes.eof) node.body.push(this.parseStatement()); | ||
this.last = this.tok; | ||
@@ -821,9 +800,9 @@ if (this.options.ecmaVersion >= 6) { | ||
switch (starttype) { | ||
case tt._break:case tt._continue: | ||
case _.tokTypes._break:case _.tokTypes._continue: | ||
this.next(); | ||
var isBreak = starttype === tt._break; | ||
var isBreak = starttype === _.tokTypes._break; | ||
if (this.semicolon() || this.canInsertSemicolon()) { | ||
node.label = null; | ||
} else { | ||
node.label = this.tok.type === tt.name ? this.parseIdent() : null; | ||
node.label = this.tok.type === _.tokTypes.name ? this.parseIdent() : null; | ||
this.semicolon(); | ||
@@ -833,3 +812,3 @@ } | ||
case tt._debugger: | ||
case _.tokTypes._debugger: | ||
this.next(); | ||
@@ -839,17 +818,17 @@ this.semicolon(); | ||
case tt._do: | ||
case _.tokTypes._do: | ||
this.next(); | ||
node.body = this.parseStatement(); | ||
node.test = this.eat(tt._while) ? this.parseParenExpression() : this.dummyIdent(); | ||
node.test = this.eat(_.tokTypes._while) ? this.parseParenExpression() : this.dummyIdent(); | ||
this.semicolon(); | ||
return this.finishNode(node, "DoWhileStatement"); | ||
case tt._for: | ||
case _.tokTypes._for: | ||
this.next(); | ||
this.pushCx(); | ||
this.expect(tt.parenL); | ||
if (this.tok.type === tt.semi) return this.parseFor(node, null); | ||
if (this.tok.type === tt._var || this.tok.type === tt._let || this.tok.type === tt._const) { | ||
this.expect(_.tokTypes.parenL); | ||
if (this.tok.type === _.tokTypes.semi) return this.parseFor(node, null); | ||
if (this.tok.type === _.tokTypes._var || this.tok.type === _.tokTypes._let || this.tok.type === _.tokTypes._const) { | ||
var _init = this.parseVar(true); | ||
if (_init.declarations.length === 1 && (this.tok.type === tt._in || this.isContextual("of"))) { | ||
if (_init.declarations.length === 1 && (this.tok.type === _.tokTypes._in || this.isContextual("of"))) { | ||
return this.parseForIn(node, _init); | ||
@@ -860,19 +839,19 @@ } | ||
var init = this.parseExpression(true); | ||
if (this.tok.type === tt._in || this.isContextual("of")) return this.parseForIn(node, this.toAssignable(init)); | ||
if (this.tok.type === _.tokTypes._in || this.isContextual("of")) return this.parseForIn(node, this.toAssignable(init)); | ||
return this.parseFor(node, init); | ||
case tt._function: | ||
case _.tokTypes._function: | ||
this.next(); | ||
return this.parseFunction(node, true); | ||
case tt._if: | ||
case _.tokTypes._if: | ||
this.next(); | ||
node.test = this.parseParenExpression(); | ||
node.consequent = this.parseStatement(); | ||
node.alternate = this.eat(tt._else) ? this.parseStatement() : null; | ||
node.alternate = this.eat(_.tokTypes._else) ? this.parseStatement() : null; | ||
return this.finishNode(node, "IfStatement"); | ||
case tt._return: | ||
case _.tokTypes._return: | ||
this.next(); | ||
if (this.eat(tt.semi) || this.canInsertSemicolon()) node.argument = null;else { | ||
if (this.eat(_.tokTypes.semi) || this.canInsertSemicolon()) node.argument = null;else { | ||
node.argument = this.parseExpression();this.semicolon(); | ||
@@ -882,3 +861,3 @@ } | ||
case tt._switch: | ||
case _.tokTypes._switch: | ||
var blockIndent = this.curIndent, | ||
@@ -890,8 +869,8 @@ line = this.curLineStart; | ||
this.pushCx(); | ||
this.expect(tt.braceL); | ||
this.expect(_.tokTypes.braceL); | ||
var cur = undefined; | ||
while (!this.closes(tt.braceR, blockIndent, line, true)) { | ||
if (this.tok.type === tt._case || this.tok.type === tt._default) { | ||
var isCase = this.tok.type === tt._case; | ||
while (!this.closes(_.tokTypes.braceR, blockIndent, line, true)) { | ||
if (this.tok.type === _.tokTypes._case || this.tok.type === _.tokTypes._default) { | ||
var isCase = this.tok.type === _.tokTypes._case; | ||
if (cur) this.finishNode(cur, "SwitchCase"); | ||
@@ -902,3 +881,3 @@ node.cases.push(cur = this.startNode()); | ||
if (isCase) cur.test = this.parseExpression();else cur.test = null; | ||
this.expect(tt.colon); | ||
this.expect(_.tokTypes.colon); | ||
} else { | ||
@@ -915,6 +894,6 @@ if (!cur) { | ||
this.popCx(); | ||
this.eat(tt.braceR); | ||
this.eat(_.tokTypes.braceR); | ||
return this.finishNode(node, "SwitchStatement"); | ||
case tt._throw: | ||
case _.tokTypes._throw: | ||
this.next(); | ||
@@ -925,12 +904,12 @@ node.argument = this.parseExpression(); | ||
case tt._try: | ||
case _.tokTypes._try: | ||
this.next(); | ||
node.block = this.parseBlock(); | ||
node.handler = null; | ||
if (this.tok.type === tt._catch) { | ||
if (this.tok.type === _.tokTypes._catch) { | ||
var clause = this.startNode(); | ||
this.next(); | ||
this.expect(tt.parenL); | ||
this.expect(_.tokTypes.parenL); | ||
clause.param = this.toAssignable(this.parseExprAtom(), true); | ||
this.expect(tt.parenR); | ||
this.expect(_.tokTypes.parenR); | ||
clause.guard = null; | ||
@@ -940,12 +919,12 @@ clause.body = this.parseBlock(); | ||
} | ||
node.finalizer = this.eat(tt._finally) ? this.parseBlock() : null; | ||
node.finalizer = this.eat(_.tokTypes._finally) ? this.parseBlock() : null; | ||
if (!node.handler && !node.finalizer) return node.block; | ||
return this.finishNode(node, "TryStatement"); | ||
case tt._var: | ||
case tt._let: | ||
case tt._const: | ||
case _.tokTypes._var: | ||
case _.tokTypes._let: | ||
case _.tokTypes._const: | ||
return this.parseVar(); | ||
case tt._while: | ||
case _.tokTypes._while: | ||
this.next(); | ||
@@ -956,3 +935,3 @@ node.test = this.parseParenExpression(); | ||
case tt._with: | ||
case _.tokTypes._with: | ||
this.next(); | ||
@@ -963,16 +942,16 @@ node.object = this.parseParenExpression(); | ||
case tt.braceL: | ||
case _.tokTypes.braceL: | ||
return this.parseBlock(); | ||
case tt.semi: | ||
case _.tokTypes.semi: | ||
this.next(); | ||
return this.finishNode(node, "EmptyStatement"); | ||
case tt._class: | ||
case _.tokTypes._class: | ||
return this.parseClass(true); | ||
case tt._import: | ||
case _.tokTypes._import: | ||
return this.parseImport(); | ||
case tt._export: | ||
case _.tokTypes._export: | ||
return this.parseExport(); | ||
@@ -982,7 +961,7 @@ | ||
var expr = this.parseExpression(); | ||
if (isDummy(expr)) { | ||
if (_parseutil.isDummy(expr)) { | ||
this.next(); | ||
if (this.tok.type === tt.eof) return this.finishNode(node, "EmptyStatement"); | ||
if (this.tok.type === _.tokTypes.eof) return this.finishNode(node, "EmptyStatement"); | ||
return this.parseStatement(); | ||
} else if (starttype === tt.name && expr.type === "Identifier" && this.eat(tt.colon)) { | ||
} else if (starttype === _.tokTypes.name && expr.type === "Identifier" && this.eat(_.tokTypes.colon)) { | ||
node.body = this.parseStatement(); | ||
@@ -1002,9 +981,9 @@ node.label = expr; | ||
this.pushCx(); | ||
this.expect(tt.braceL); | ||
this.expect(_.tokTypes.braceL); | ||
var blockIndent = this.curIndent, | ||
line = this.curLineStart; | ||
node.body = []; | ||
while (!this.closes(tt.braceR, blockIndent, line, true)) node.body.push(this.parseStatement()); | ||
while (!this.closes(_.tokTypes.braceR, blockIndent, line, true)) node.body.push(this.parseStatement()); | ||
this.popCx(); | ||
this.eat(tt.braceR); | ||
this.eat(_.tokTypes.braceR); | ||
return this.finishNode(node, "BlockStatement"); | ||
@@ -1016,6 +995,6 @@ }; | ||
node.test = node.update = null; | ||
if (this.eat(tt.semi) && this.tok.type !== tt.semi) node.test = this.parseExpression(); | ||
if (this.eat(tt.semi) && this.tok.type !== tt.parenR) node.update = this.parseExpression(); | ||
if (this.eat(_.tokTypes.semi) && this.tok.type !== _.tokTypes.semi) node.test = this.parseExpression(); | ||
if (this.eat(_.tokTypes.semi) && this.tok.type !== _.tokTypes.parenR) node.update = this.parseExpression(); | ||
this.popCx(); | ||
this.expect(tt.parenR); | ||
this.expect(_.tokTypes.parenR); | ||
node.body = this.parseStatement(); | ||
@@ -1026,3 +1005,3 @@ return this.finishNode(node, "ForStatement"); | ||
lp.parseForIn = function (node, init) { | ||
var type = this.tok.type === tt._in ? "ForInStatement" : "ForOfStatement"; | ||
var type = this.tok.type === _.tokTypes._in ? "ForInStatement" : "ForOfStatement"; | ||
this.next(); | ||
@@ -1032,3 +1011,3 @@ node.left = init; | ||
this.popCx(); | ||
this.expect(tt.parenR); | ||
this.expect(_.tokTypes.parenR); | ||
node.body = this.parseStatement(); | ||
@@ -1046,5 +1025,5 @@ return this.finishNode(node, type); | ||
decl.id = this.options.ecmaVersion >= 6 ? this.toAssignable(this.parseExprAtom(), true) : this.parseIdent(); | ||
decl.init = this.eat(tt.eq) ? this.parseMaybeAssign(noIn) : null; | ||
decl.init = this.eat(_.tokTypes.eq) ? this.parseMaybeAssign(noIn) : null; | ||
node.declarations.push(this.finishNode(decl, "VariableDeclarator")); | ||
} while (this.eat(tt.comma)); | ||
} while (this.eat(_.tokTypes.comma)); | ||
if (!node.declarations.length) { | ||
@@ -1062,4 +1041,4 @@ var decl = this.startNode(); | ||
this.next(); | ||
if (this.tok.type === tt.name) node.id = this.parseIdent();else if (isStatement) node.id = this.dummyIdent();else node.id = null; | ||
node.superClass = this.eat(tt._extends) ? this.parseExpression() : null; | ||
if (this.tok.type === _.tokTypes.name) node.id = this.parseIdent();else if (isStatement) node.id = this.dummyIdent();else node.id = null; | ||
node.superClass = this.eat(_.tokTypes._extends) ? this.parseExpression() : null; | ||
node.body = this.startNode(); | ||
@@ -1070,7 +1049,7 @@ node.body.body = []; | ||
line = this.curLineStart; | ||
this.eat(tt.braceL); | ||
this.eat(_.tokTypes.braceL); | ||
if (this.curIndent + 1 < indent) { | ||
indent = this.curIndent;line = this.curLineStart; | ||
} | ||
while (!this.closes(tt.braceR, indent, line)) { | ||
while (!this.closes(_.tokTypes.braceR, indent, line)) { | ||
if (this.semicolon()) continue; | ||
@@ -1081,11 +1060,11 @@ var method = this.startNode(), | ||
method["static"] = false; | ||
isGenerator = this.eat(tt.star); | ||
isGenerator = this.eat(_.tokTypes.star); | ||
} | ||
this.parsePropertyName(method); | ||
if (isDummy(method.key)) { | ||
if (isDummy(this.parseMaybeAssign())) this.next();this.eat(tt.comma);continue; | ||
if (_parseutil.isDummy(method.key)) { | ||
if (_parseutil.isDummy(this.parseMaybeAssign())) this.next();this.eat(_.tokTypes.comma);continue; | ||
} | ||
if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && (this.tok.type != tt.parenL && this.tok.type != tt.braceL)) { | ||
if (method.key.type === "Identifier" && !method.computed && method.key.name === "static" && (this.tok.type != _.tokTypes.parenL && this.tok.type != _.tokTypes.braceL)) { | ||
method["static"] = true; | ||
isGenerator = this.eat(tt.star); | ||
isGenerator = this.eat(_.tokTypes.star); | ||
this.parsePropertyName(method); | ||
@@ -1095,3 +1074,3 @@ } else { | ||
} | ||
if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" && !method.computed && (method.key.name === "get" || method.key.name === "set") && this.tok.type !== tt.parenL && this.tok.type !== tt.braceL) { | ||
if (this.options.ecmaVersion >= 5 && method.key.type === "Identifier" && !method.computed && (method.key.name === "get" || method.key.name === "set") && this.tok.type !== _.tokTypes.parenL && this.tok.type !== _.tokTypes.braceL) { | ||
method.kind = method.key.name; | ||
@@ -1111,3 +1090,3 @@ this.parsePropertyName(method); | ||
this.popCx(); | ||
if (!this.eat(tt.braceR)) { | ||
if (!this.eat(_.tokTypes.braceR)) { | ||
// If there is no closing brace, make the node span to the start | ||
@@ -1126,5 +1105,5 @@ // of the next token (this is useful for Tern) | ||
if (this.options.ecmaVersion >= 6) { | ||
node.generator = this.eat(tt.star); | ||
node.generator = this.eat(_.tokTypes.star); | ||
} | ||
if (this.tok.type === tt.name) node.id = this.parseIdent();else if (isStatement) node.id = this.dummyIdent(); | ||
if (this.tok.type === _.tokTypes.name) node.id = this.parseIdent();else if (isStatement) node.id = this.dummyIdent(); | ||
node.params = this.parseFunctionParams(); | ||
@@ -1138,7 +1117,7 @@ node.body = this.parseBlock(); | ||
this.next(); | ||
if (this.eat(tt.star)) { | ||
if (this.eat(_.tokTypes.star)) { | ||
node.source = this.eatContextual("from") ? this.parseExprAtom() : null; | ||
return this.finishNode(node, "ExportAllDeclaration"); | ||
} | ||
if (this.eat(tt._default)) { | ||
if (this.eat(_.tokTypes._default)) { | ||
var expr = this.parseMaybeAssign(); | ||
@@ -1173,3 +1152,3 @@ if (expr.id) { | ||
this.next(); | ||
if (this.tok.type === tt.string) { | ||
if (this.tok.type === _.tokTypes.string) { | ||
node.specifiers = []; | ||
@@ -1180,7 +1159,7 @@ node.source = this.parseExprAtom(); | ||
var elt = undefined; | ||
if (this.tok.type === tt.name && this.tok.value !== "from") { | ||
if (this.tok.type === _.tokTypes.name && this.tok.value !== "from") { | ||
elt = this.startNode(); | ||
elt.local = this.parseIdent(); | ||
this.finishNode(elt, "ImportDefaultSpecifier"); | ||
this.eat(tt.comma); | ||
this.eat(_.tokTypes.comma); | ||
} | ||
@@ -1197,3 +1176,3 @@ node.specifiers = this.parseImportSpecifierList(); | ||
var elts = []; | ||
if (this.tok.type === tt.star) { | ||
if (this.tok.type === _.tokTypes.star) { | ||
var elt = this.startNode(); | ||
@@ -1208,7 +1187,7 @@ this.next(); | ||
this.pushCx(); | ||
this.eat(tt.braceL); | ||
this.eat(_.tokTypes.braceL); | ||
if (this.curLineStart > continuedLine) continuedLine = this.curLineStart; | ||
while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { | ||
while (!this.closes(_.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { | ||
var elt = this.startNode(); | ||
if (this.eat(tt.star)) { | ||
if (this.eat(_.tokTypes.star)) { | ||
if (this.eatContextual("as")) elt.local = this.parseIdent(); | ||
@@ -1219,2 +1198,3 @@ this.finishNode(elt, "ImportNamespaceSpecifier"); | ||
elt.imported = this.parseIdent(); | ||
if (_parseutil.isDummy(elt.imported)) break; | ||
elt.local = this.eatContextual("as") ? this.parseIdent() : elt.imported; | ||
@@ -1224,5 +1204,5 @@ this.finishNode(elt, "ImportSpecifier"); | ||
elts.push(elt); | ||
this.eat(tt.comma); | ||
this.eat(_.tokTypes.comma); | ||
} | ||
this.eat(tt.braceR); | ||
this.eat(_.tokTypes.braceR); | ||
this.popCx(); | ||
@@ -1239,14 +1219,15 @@ } | ||
this.pushCx(); | ||
this.eat(tt.braceL); | ||
this.eat(_.tokTypes.braceL); | ||
if (this.curLineStart > continuedLine) continuedLine = this.curLineStart; | ||
while (!this.closes(tt.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { | ||
while (!this.closes(_.tokTypes.braceR, indent + (this.curLineStart <= continuedLine ? 1 : 0), line)) { | ||
if (this.isContextual("from")) break; | ||
var elt = this.startNode(); | ||
elt.local = this.parseIdent(); | ||
if (_parseutil.isDummy(elt.local)) break; | ||
elt.exported = this.eatContextual("as") ? this.parseIdent() : elt.local; | ||
this.finishNode(elt, "ExportSpecifier"); | ||
elts.push(elt); | ||
this.eat(tt.comma); | ||
this.eat(_.tokTypes.comma); | ||
} | ||
this.eat(tt.braceR); | ||
this.eat(_.tokTypes.braceR); | ||
this.popCx(); | ||
@@ -1256,3 +1237,3 @@ return elts; | ||
},{"..":2,"./parseutil":4,"./state":5}],7:[function(_dereq_,module,exports){ | ||
},{"..":1,"./parseutil":4,"./state":5}],7:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
@@ -1262,15 +1243,8 @@ | ||
var tt = _.tokTypes; | ||
var Token = _.Token; | ||
var isNewLine = _.isNewLine; | ||
var SourceLocation = _.SourceLocation; | ||
var getLineInfo = _.getLineInfo; | ||
var lineBreakG = _.lineBreakG; | ||
var _state = _dereq_("./state"); | ||
var LooseParser = _dereq_("./state").LooseParser; | ||
var lp = _state.LooseParser.prototype; | ||
var lp = LooseParser.prototype; | ||
function isSpace(ch) { | ||
return ch < 14 && ch > 8 || ch === 32 || ch === 160 || isNewLine(ch); | ||
return ch < 14 && ch > 8 || ch === 32 || ch === 160 || _.isNewLine(ch); | ||
} | ||
@@ -1295,7 +1269,7 @@ | ||
this.toks.next(); | ||
if (this.toks.type === tt.dot && this.input.substr(this.toks.end, 1) === "." && this.options.ecmaVersion >= 6) { | ||
if (this.toks.type === _.tokTypes.dot && this.input.substr(this.toks.end, 1) === "." && this.options.ecmaVersion >= 6) { | ||
this.toks.end++; | ||
this.toks.type = tt.ellipsis; | ||
this.toks.type = _.tokTypes.ellipsis; | ||
} | ||
return new Token(this.toks); | ||
return new _.Token(this.toks); | ||
} catch (e) { | ||
@@ -1311,3 +1285,3 @@ if (!(e instanceof SyntaxError)) throw e; | ||
if (/string/.test(msg)) { | ||
replace = { start: e.pos, end: pos, type: tt.string, value: this.input.slice(e.pos + 1, pos) }; | ||
replace = { start: e.pos, end: pos, type: _.tokTypes.string, value: this.input.slice(e.pos + 1, pos) }; | ||
} else if (/regular expr/i.test(msg)) { | ||
@@ -1318,6 +1292,6 @@ var re = this.input.slice(e.pos, pos); | ||
} catch (e) {} | ||
replace = { start: e.pos, end: pos, type: tt.regexp, value: re }; | ||
replace = { start: e.pos, end: pos, type: _.tokTypes.regexp, value: re }; | ||
} else if (/template/.test(msg)) { | ||
replace = { start: e.pos, end: pos, | ||
type: tt.template, | ||
type: _.tokTypes.template, | ||
value: this.input.slice(e.pos, pos) }; | ||
@@ -1332,3 +1306,3 @@ } else { | ||
var ch = this.input.charCodeAt(pos++); | ||
if (ch === 34 || ch === 39 || isNewLine(ch)) break; | ||
if (ch === 34 || ch === 39 || _.isNewLine(ch)) break; | ||
} | ||
@@ -1344,5 +1318,5 @@ } else if (/unexpected character/i.test(msg)) { | ||
this.resetTo(pos); | ||
if (replace === true) replace = { start: pos, end: pos, type: tt.name, value: "✖" }; | ||
if (replace === true) replace = { start: pos, end: pos, type: _.tokTypes.name, value: "✖" }; | ||
if (replace) { | ||
if (this.options.locations) replace.loc = new SourceLocation(this.toks, getLineInfo(this.input, replace.start), getLineInfo(this.input, replace.end)); | ||
if (this.options.locations) replace.loc = new _.SourceLocation(this.toks, _.getLineInfo(this.input, replace.start), _.getLineInfo(this.input, replace.end)); | ||
return replace; | ||
@@ -1361,5 +1335,5 @@ } | ||
this.toks.curLine = 1; | ||
this.toks.lineStart = lineBreakG.lastIndex = 0; | ||
this.toks.lineStart = _.lineBreakG.lastIndex = 0; | ||
var match = undefined; | ||
while ((match = lineBreakG.exec(this.input)) && match.index < pos) { | ||
while ((match = _.lineBreakG.exec(this.input)) && match.index < pos) { | ||
++this.toks.curLine; | ||
@@ -1376,3 +1350,3 @@ this.toks.lineStart = match.index + match[0].length; | ||
},{"..":2,"./state":5}]},{},[1])(1) | ||
},{"..":1,"./state":5}]},{},[3])(3) | ||
}); |
102
dist/walk.js
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}(g.acorn || (g.acorn = {})).walk = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){ | ||
"use strict"; | ||
var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; | ||
// AST walker module for Mozilla Parser API compatible trees | ||
@@ -24,35 +20,16 @@ | ||
"use strict"; | ||
exports.__esModule = true; | ||
exports.simple = simple; | ||
// An ancestor walk builds up an array of ancestor nodes (including | ||
// the current node) and passes them to the callback as the state parameter. | ||
exports.ancestor = ancestor; | ||
// A recursive walk is one where your functions override the default | ||
// walkers. They can modify and replace the state parameter that's | ||
// threaded through the walk, and can opt how and whether to walk | ||
// their child nodes (by calling their third argument on these | ||
// nodes). | ||
exports.recursive = recursive; | ||
// Find a node with a given start, end, and type (all are optional, | ||
// null can be used as wildcard). Returns a {node, state} object, or | ||
// undefined when it doesn't find a matching node. | ||
exports.findNodeAt = findNodeAt; | ||
// Find the innermost node of a given type that contains the given | ||
// position. Interface similar to findNodeAt. | ||
exports.findNodeAround = findNodeAround; | ||
// Find the outermost matching node after a given position. | ||
exports.findNodeAfter = findNodeAfter; | ||
// Find the outermost matching node before a given position. | ||
exports.findNodeBefore = findNodeBefore; | ||
// Used to create a custom walker. Will fill in all missing node | ||
// type properties with the defaults. | ||
exports.make = make; | ||
exports.__esModule = true; | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function simple(node, visitors, base, state, override) { | ||
@@ -67,2 +44,5 @@ if (!base) base = exports.base;(function c(node, st, override) { | ||
// An ancestor walk builds up an array of ancestor nodes (including | ||
// the current node) and passes them to the callback as the state parameter. | ||
function ancestor(node, visitors, base, state) { | ||
@@ -82,2 +62,8 @@ if (!base) base = exports.base; | ||
// A recursive walk is one where your functions override the default | ||
// walkers. They can modify and replace the state parameter that's | ||
// threaded through the walk, and can opt how and whether to walk | ||
// their child nodes (by calling their third argument on these | ||
// nodes). | ||
function recursive(node, state, funcs, base, override) { | ||
@@ -90,13 +76,7 @@ var visitor = funcs ? exports.make(funcs, base) : base;(function c(node, st, override) { | ||
function makeTest(test) { | ||
if (typeof test == "string") { | ||
return function (type) { | ||
return type == test; | ||
}; | ||
} else if (!test) { | ||
return function () { | ||
return true; | ||
}; | ||
} else { | ||
return test; | ||
} | ||
if (typeof test == "string") return function (type) { | ||
return type == test; | ||
};else if (!test) return function () { | ||
return true; | ||
};else return test; | ||
} | ||
@@ -110,2 +90,6 @@ | ||
// Find a node with a given start, end, and type (all are optional, | ||
// null can be used as wildcard). Returns a {node, state} object, or | ||
// undefined when it doesn't find a matching node. | ||
function findNodeAt(node, start, end, test, base, state) { | ||
@@ -121,8 +105,10 @@ test = makeTest(test); | ||
} catch (e) { | ||
if (e instanceof Found) { | ||
return e; | ||
}throw e; | ||
if (e instanceof Found) return e; | ||
throw e; | ||
} | ||
} | ||
// Find the innermost node of a given type that contains the given | ||
// position. Interface similar to findNodeAt. | ||
function findNodeAround(node, pos, test, base, state) { | ||
@@ -134,14 +120,14 @@ test = makeTest(test); | ||
var type = override || node.type; | ||
if (node.start > pos || node.end < pos) { | ||
return; | ||
}base[type](node, st, c); | ||
if (node.start > pos || node.end < pos) return; | ||
base[type](node, st, c); | ||
if (test(type, node)) throw new Found(node, st); | ||
})(node, state); | ||
} catch (e) { | ||
if (e instanceof Found) { | ||
return e; | ||
}throw e; | ||
if (e instanceof Found) return e; | ||
throw e; | ||
} | ||
} | ||
// Find the outermost matching node after a given position. | ||
function findNodeAfter(node, pos, test, base, state) { | ||
@@ -152,5 +138,4 @@ test = makeTest(test); | ||
;(function c(node, st, override) { | ||
if (node.end < pos) { | ||
return; | ||
}var type = override || node.type; | ||
if (node.end < pos) return; | ||
var type = override || node.type; | ||
if (node.start >= pos && test(type, node)) throw new Found(node, st); | ||
@@ -160,8 +145,9 @@ base[type](node, st, c); | ||
} catch (e) { | ||
if (e instanceof Found) { | ||
return e; | ||
}throw e; | ||
if (e instanceof Found) return e; | ||
throw e; | ||
} | ||
} | ||
// Find the outermost matching node before a given position. | ||
function findNodeBefore(node, pos, test, base, state) { | ||
@@ -171,5 +157,4 @@ test = makeTest(test); | ||
var max = undefined;(function c(node, st, override) { | ||
if (node.start > pos) { | ||
return; | ||
}var type = override || node.type; | ||
if (node.start > pos) return; | ||
var type = override || node.type; | ||
if (node.end <= pos && (!max || max.node.end < node.end) && test(type, node)) max = new Found(node, st); | ||
@@ -181,2 +166,5 @@ base[type](node, st, c); | ||
// Used to create a custom walker. Will fill in all missing node | ||
// type properties with the defaults. | ||
function make(funcs, base) { | ||
@@ -183,0 +171,0 @@ if (!base) base = exports.base; |
@@ -6,3 +6,3 @@ { | ||
"main": "dist/acorn.js", | ||
"version": "2.0.4", | ||
"version": "2.1.0", | ||
"engines": { | ||
@@ -29,4 +29,4 @@ "node": ">=0.4.0" | ||
"scripts": { | ||
"test": "node test/run.js", | ||
"prepublish": "node bin/build-acorn.js && node bin/without_eval > dist/acorn_csp.js" | ||
"prepublish": "node bin/build-acorn.js && node bin/without_eval > dist/acorn_csp.js", | ||
"test": "node test/run.js" | ||
}, | ||
@@ -37,4 +37,5 @@ "bin": { | ||
"devDependencies": { | ||
"babelify": "^5.0.4", | ||
"browserify": "^9.0.3", | ||
"babel-core": "^5.6.15", | ||
"babelify": "^6.1.2", | ||
"browserify": "^10.2.4", | ||
"browserify-derequire": "^0.9.4", | ||
@@ -41,0 +42,0 @@ "unicode-7.0.0": "~0.1.5" |
@@ -232,3 +232,3 @@ # Acorn | ||
This file implements an error-tolerant parser. It exposes a single | ||
function. | ||
function. The loose parser is accessible in node.js via `require("acorn/dist/acorn_loose")`. | ||
@@ -335,3 +335,3 @@ **parse_dammit**`(input, options)` takes the same arguments and | ||
require("babelify/node_modules/babel-core/register") | ||
require("babel-core/register") | ||
@@ -338,0 +338,0 @@ That will allow you to directly `require` the ES6 modules. |
@@ -623,10 +623,10 @@ // A recursive descent parser operates by defining functions for all | ||
if (allowEmpty && this.type === tt.comma) { | ||
elts.push(null) | ||
} else { | ||
if (this.type === tt.ellipsis) | ||
elts.push(this.parseSpread(refShorthandDefaultPos)) | ||
else | ||
elts.push(this.parseMaybeAssign(false, refShorthandDefaultPos)) | ||
} | ||
let elt | ||
if (allowEmpty && this.type === tt.comma) | ||
elt = null | ||
else if (this.type === tt.ellipsis) | ||
elt = this.parseSpread(refShorthandDefaultPos) | ||
else | ||
elt = this.parseMaybeAssign(false, refShorthandDefaultPos) | ||
elts.push(elt) | ||
} | ||
@@ -633,0 +633,0 @@ return elts |
@@ -28,7 +28,7 @@ // Acorn is a tiny, fast JavaScript parser written in JavaScript. | ||
import "./expression" | ||
import "./location" | ||
export {Parser, plugins} from "./state" | ||
export {defaultOptions} from "./options" | ||
export {SourceLocation} from "./location" | ||
export {getLineInfo} from "./location" | ||
export {Position, SourceLocation, getLineInfo} from "./locutil" | ||
export {Node} from "./node" | ||
@@ -41,3 +41,3 @@ export {TokenType, types as tokTypes} from "./tokentype" | ||
export const version = "2.0.4" | ||
export const version = "2.1.0" | ||
@@ -52,6 +52,3 @@ // The main exported interface (under `self.acorn` when in the | ||
export function parse(input, options) { | ||
let p = parser(options, input) | ||
let startPos = p.pos, startLoc = p.options.locations && p.curPosition() | ||
p.nextToken() | ||
return p.parseTopLevel(p.options.program || p.startNodeAt(startPos, startLoc)) | ||
return new Parser(options, input).parse() | ||
} | ||
@@ -64,3 +61,3 @@ | ||
export function parseExpressionAt(input, pos, options) { | ||
let p = parser(options, input, pos) | ||
let p = new Parser(options, input, pos) | ||
p.nextToken() | ||
@@ -74,7 +71,3 @@ return p.parseExpression() | ||
export function tokenizer(input, options) { | ||
return parser(options, input) | ||
return new Parser(options, input) | ||
} | ||
function parser(options, input) { | ||
return new Parser(getOptions(options), String(input)) | ||
} |
import {Parser} from "./state" | ||
import {lineBreakG} from "./whitespace" | ||
import {Position, getLineInfo} from "./locutil" | ||
// These are used when `options.locations` is on, for the | ||
// `startLoc` and `endLoc` properties. | ||
export class Position { | ||
constructor(line, col) { | ||
this.line = line | ||
this.column = col | ||
} | ||
offset(n) { | ||
return new Position(this.line, this.column + n) | ||
} | ||
} | ||
export class SourceLocation { | ||
constructor(p, start, end) { | ||
this.start = start | ||
this.end = end | ||
if (p.sourceFile !== null) this.source = p.sourceFile | ||
} | ||
} | ||
// The `getLineInfo` function is mostly useful when the | ||
// `locations` option is off (for performance reasons) and you | ||
// want to find the line/column position for a given character | ||
// offset. `input` should be the code string that the offset refers | ||
// into. | ||
export function getLineInfo(input, offset) { | ||
for (let line = 1, cur = 0;;) { | ||
lineBreakG.lastIndex = cur | ||
let match = lineBreakG.exec(input) | ||
if (match && match.index < offset) { | ||
++line | ||
cur = match.index + match[0].length | ||
} else { | ||
return new Position(line, offset - cur) | ||
} | ||
} | ||
} | ||
const pp = Parser.prototype | ||
@@ -62,3 +21,5 @@ | ||
pp.curPosition = function() { | ||
return new Position(this.curLine, this.pos - this.lineStart) | ||
if (this.options.locations) { | ||
return new Position(this.curLine, this.pos - this.lineStart) | ||
} | ||
} |
@@ -35,3 +35,2 @@ // Acorn: Loose parser | ||
import "./tokenize" | ||
import "./parseutil" | ||
import "./statement" | ||
@@ -38,0 +37,0 @@ import "./expression" |
@@ -1,126 +0,1 @@ | ||
import {LooseParser} from "./state" | ||
import {Node, SourceLocation, lineBreak, isNewLine, tokTypes as tt} from ".." | ||
const lp = LooseParser.prototype | ||
lp.startNode = function() { | ||
let node = new Node | ||
node.start = this.tok.start | ||
if (this.options.locations) | ||
node.loc = new SourceLocation(this.toks, this.tok.loc.start) | ||
if (this.options.directSourceFile) | ||
node.sourceFile = this.options.directSourceFile | ||
if (this.options.ranges) | ||
node.range = [this.tok.start, 0] | ||
return node | ||
} | ||
lp.storeCurrentPos = function() { | ||
return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start | ||
} | ||
lp.startNodeAt = function(pos) { | ||
let node = new Node | ||
if (this.options.locations) { | ||
node.start = pos[0] | ||
node.loc = new SourceLocation(this.toks, pos[1]) | ||
pos = pos[0] | ||
} else { | ||
node.start = pos | ||
} | ||
if (this.options.directSourceFile) | ||
node.sourceFile = this.options.directSourceFile | ||
if (this.options.ranges) | ||
node.range = [pos, 0] | ||
return node | ||
} | ||
lp.finishNode = function(node, type) { | ||
node.type = type | ||
node.end = this.last.end | ||
if (this.options.locations) | ||
node.loc.end = this.last.loc.end | ||
if (this.options.ranges) | ||
node.range[1] = this.last.end | ||
return node | ||
} | ||
lp.dummyIdent = function() { | ||
let dummy = this.startNode() | ||
dummy.name = "✖" | ||
return this.finishNode(dummy, "Identifier") | ||
} | ||
export function isDummy(node) { return node.name == "✖" } | ||
lp.eat = function(type) { | ||
if (this.tok.type === type) { | ||
this.next() | ||
return true | ||
} else { | ||
return false | ||
} | ||
} | ||
lp.isContextual = function(name) { | ||
return this.tok.type === tt.name && this.tok.value === name | ||
} | ||
lp.eatContextual = function(name) { | ||
return this.tok.value === name && this.eat(tt.name) | ||
} | ||
lp.canInsertSemicolon = function() { | ||
return this.tok.type === tt.eof || this.tok.type === tt.braceR || | ||
lineBreak.test(this.input.slice(this.last.end, this.tok.start)) | ||
} | ||
lp.semicolon = function() { | ||
return this.eat(tt.semi) | ||
} | ||
lp.expect = function(type) { | ||
if (this.eat(type)) return true | ||
for (let i = 1; i <= 2; i++) { | ||
if (this.lookAhead(i).type == type) { | ||
for (let j = 0; j < i; j++) this.next() | ||
return true | ||
} | ||
} | ||
} | ||
lp.pushCx = function() { | ||
this.context.push(this.curIndent) | ||
} | ||
lp.popCx = function() { | ||
this.curIndent = this.context.pop() | ||
} | ||
lp.lineEnd = function(pos) { | ||
while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos | ||
return pos | ||
} | ||
lp.indentationAfter = function(pos) { | ||
for (let count = 0;; ++pos) { | ||
let ch = this.input.charCodeAt(pos) | ||
if (ch === 32) ++count | ||
else if (ch === 9) count += this.options.tabSize | ||
else return count | ||
} | ||
} | ||
lp.closes = function(closeTok, indent, line, blockHeuristic) { | ||
if (this.tok.type === closeTok || this.tok.type === tt.eof) return true | ||
return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && | ||
(!blockHeuristic || this.nextLineStart >= this.input.length || | ||
this.indentationAfter(this.nextLineStart) < indent) | ||
} | ||
lp.tokenStartsLine = function() { | ||
for (let p = this.tok.start - 1; p >= this.curLineStart; --p) { | ||
let ch = this.input.charCodeAt(p) | ||
if (ch !== 9 && ch !== 32) return false | ||
} | ||
return true | ||
} | ||
export function isDummy(node) { return node.name == "✖" } |
@@ -1,17 +0,124 @@ | ||
import {tokenizer, SourceLocation, tokTypes as tt} from ".." | ||
import {tokenizer, SourceLocation, tokTypes as tt, Node, lineBreak, isNewLine} from ".." | ||
export function LooseParser(input, options) { | ||
this.toks = tokenizer(input, options) | ||
this.options = this.toks.options | ||
this.input = this.toks.input | ||
this.tok = this.last = {type: tt.eof, start: 0, end: 0} | ||
if (this.options.locations) { | ||
let here = this.toks.curPosition() | ||
this.tok.loc = new SourceLocation(this.toks, here, here) | ||
export class LooseParser{ | ||
constructor(input, options) { | ||
this.toks = tokenizer(input, options) | ||
this.options = this.toks.options | ||
this.input = this.toks.input | ||
this.tok = this.last = {type: tt.eof, start: 0, end: 0} | ||
if (this.options.locations) { | ||
let here = this.toks.curPosition() | ||
this.tok.loc = new SourceLocation(this.toks, here, here) | ||
} | ||
this.ahead = []; // Tokens ahead | ||
this.context = []; // Indentation contexted | ||
this.curIndent = 0 | ||
this.curLineStart = 0 | ||
this.nextLineStart = this.lineEnd(this.curLineStart) + 1 | ||
} | ||
this.ahead = []; // Tokens ahead | ||
this.context = []; // Indentation contexted | ||
this.curIndent = 0 | ||
this.curLineStart = 0 | ||
this.nextLineStart = this.lineEnd(this.curLineStart) + 1 | ||
startNode() { | ||
return new Node(this.toks, this.tok.start, this.options.locations ? this.tok.loc.start : null) | ||
} | ||
storeCurrentPos() { | ||
return this.options.locations ? [this.tok.start, this.tok.loc.start] : this.tok.start | ||
} | ||
startNodeAt(pos) { | ||
if (this.options.locations) { | ||
return new Node(this.toks, pos[0], pos[1]) | ||
} else { | ||
return new Node(this.toks, pos) | ||
} | ||
} | ||
finishNode(node, type) { | ||
node.type = type | ||
node.end = this.last.end | ||
if (this.options.locations) | ||
node.loc.end = this.last.loc.end | ||
if (this.options.ranges) | ||
node.range[1] = this.last.end | ||
return node | ||
} | ||
dummyIdent() { | ||
let dummy = this.startNode() | ||
dummy.name = "✖" | ||
return this.finishNode(dummy, "Identifier") | ||
} | ||
eat(type) { | ||
if (this.tok.type === type) { | ||
this.next() | ||
return true | ||
} else { | ||
return false | ||
} | ||
} | ||
isContextual(name) { | ||
return this.tok.type === tt.name && this.tok.value === name | ||
} | ||
eatContextual(name) { | ||
return this.tok.value === name && this.eat(tt.name) | ||
} | ||
canInsertSemicolon() { | ||
return this.tok.type === tt.eof || this.tok.type === tt.braceR || | ||
lineBreak.test(this.input.slice(this.last.end, this.tok.start)) | ||
} | ||
semicolon() { | ||
return this.eat(tt.semi) | ||
} | ||
expect(type) { | ||
if (this.eat(type)) return true | ||
for (let i = 1; i <= 2; i++) { | ||
if (this.lookAhead(i).type == type) { | ||
for (let j = 0; j < i; j++) this.next() | ||
return true | ||
} | ||
} | ||
} | ||
pushCx() { | ||
this.context.push(this.curIndent) | ||
} | ||
popCx() { | ||
this.curIndent = this.context.pop() | ||
} | ||
lineEnd(pos) { | ||
while (pos < this.input.length && !isNewLine(this.input.charCodeAt(pos))) ++pos | ||
return pos | ||
} | ||
indentationAfter(pos) { | ||
for (let count = 0;; ++pos) { | ||
let ch = this.input.charCodeAt(pos) | ||
if (ch === 32) ++count | ||
else if (ch === 9) count += this.options.tabSize | ||
else return count | ||
} | ||
} | ||
closes(closeTok, indent, line, blockHeuristic) { | ||
if (this.tok.type === closeTok || this.tok.type === tt.eof) return true | ||
return line != this.curLineStart && this.curIndent < indent && this.tokenStartsLine() && | ||
(!blockHeuristic || this.nextLineStart >= this.input.length || | ||
this.indentationAfter(this.nextLineStart) < indent) | ||
} | ||
tokenStartsLine() { | ||
for (let p = this.tok.start - 1; p >= this.curLineStart; --p) { | ||
let ch = this.input.charCodeAt(p) | ||
if (ch !== 9 && ch !== 32) return false | ||
} | ||
return true | ||
} | ||
} |
@@ -389,2 +389,3 @@ import {LooseParser} from "./state" | ||
elt.imported = this.parseIdent() | ||
if (isDummy(elt.imported)) break | ||
elt.local = this.eatContextual("as") ? this.parseIdent() : elt.imported | ||
@@ -412,2 +413,3 @@ this.finishNode(elt, "ImportSpecifier") | ||
elt.local = this.parseIdent() | ||
if (isDummy(elt.local)) break | ||
elt.exported = this.eatContextual("as") ? this.parseIdent() : elt.local | ||
@@ -414,0 +416,0 @@ this.finishNode(elt, "ExportSpecifier") |
import {Parser} from "./state" | ||
import {SourceLocation} from "./location" | ||
import {SourceLocation} from "./locutil" | ||
export class Node { | ||
constructor(parser, pos, loc) { | ||
this.type = "" | ||
this.start = pos | ||
this.end = 0 | ||
if (parser.options.locations) | ||
this.loc = new SourceLocation(parser, loc) | ||
if (parser.options.directSourceFile) | ||
this.sourceFile = parser.options.directSourceFile | ||
if (parser.options.ranges) | ||
this.range = [pos, 0] | ||
} | ||
} | ||
// Start an AST node, attaching a start offset. | ||
@@ -8,26 +22,8 @@ | ||
export class Node {} | ||
pp.startNode = function() { | ||
let node = new Node | ||
node.start = this.start | ||
if (this.options.locations) | ||
node.loc = new SourceLocation(this, this.startLoc) | ||
if (this.options.directSourceFile) | ||
node.sourceFile = this.options.directSourceFile | ||
if (this.options.ranges) | ||
node.range = [this.start, 0] | ||
return node | ||
return new Node(this, this.start, this.startLoc) | ||
} | ||
pp.startNodeAt = function(pos, loc) { | ||
let node = new Node | ||
node.start = pos | ||
if (this.options.locations) | ||
node.loc = new SourceLocation(this, loc) | ||
if (this.options.directSourceFile) | ||
node.sourceFile = this.options.directSourceFile | ||
if (this.options.ranges) | ||
node.range = [pos, 0] | ||
return node | ||
return new Node(this, pos, loc) | ||
} | ||
@@ -37,22 +33,20 @@ | ||
pp.finishNode = function(node, type) { | ||
function finishNodeAt(node, type, pos, loc) { | ||
node.type = type | ||
node.end = this.lastTokEnd | ||
node.end = pos | ||
if (this.options.locations) | ||
node.loc.end = this.lastTokEndLoc | ||
node.loc.end = loc | ||
if (this.options.ranges) | ||
node.range[1] = this.lastTokEnd | ||
node.range[1] = pos | ||
return node | ||
} | ||
pp.finishNode = function(node, type) { | ||
return finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc) | ||
} | ||
// Finish node at given position | ||
pp.finishNodeAt = function(node, type, pos, loc) { | ||
node.type = type | ||
node.end = pos | ||
if (this.options.locations) | ||
node.loc.end = loc | ||
if (this.options.ranges) | ||
node.range[1] = pos | ||
return node | ||
return finishNodeAt.call(this, node, type, pos, loc) | ||
} |
import {has, isArray} from "./util" | ||
import {SourceLocation} from "./location" | ||
import {SourceLocation} from "./locutil" | ||
@@ -4,0 +4,0 @@ // A second optional argument can be given to further configure |
@@ -13,3 +13,4 @@ import {types as tt} from "./tokentype" | ||
return this.options.ecmaVersion >= 5 && stmt.type === "ExpressionStatement" && | ||
stmt.expression.type === "Literal" && stmt.expression.value === "use strict" | ||
stmt.expression.type === "Literal" && | ||
stmt.expression.raw.slice(1, -1) === "use strict" | ||
} | ||
@@ -16,0 +17,0 @@ |
124
src/state.js
import {reservedWords, keywords} from "./identifier" | ||
import {types as tt} from "./tokentype" | ||
import {lineBreak} from "./whitespace" | ||
import {getOptions} from "./options" | ||
export function Parser(options, input, startPos) { | ||
this.options = options | ||
this.sourceFile = this.options.sourceFile || null | ||
this.isKeyword = keywords[this.options.ecmaVersion >= 6 ? 6 : 5] | ||
this.isReservedWord = reservedWords[this.options.ecmaVersion] | ||
this.input = input | ||
// Registered plugins | ||
export const plugins = {} | ||
// Load plugins | ||
this.loadPlugins(this.options.plugins) | ||
export class Parser { | ||
constructor(options, input, startPos) { | ||
this.options = getOptions(options) | ||
this.sourceFile = this.options.sourceFile | ||
this.isKeyword = keywords[this.options.ecmaVersion >= 6 ? 6 : 5] | ||
this.isReservedWord = reservedWords[this.options.ecmaVersion] | ||
this.input = String(input) | ||
// Set up token state | ||
// Load plugins | ||
this.loadPlugins(this.options.plugins) | ||
// The current position of the tokenizer in the input. | ||
if (startPos) { | ||
this.pos = startPos | ||
this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos)) | ||
this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length | ||
} else { | ||
this.pos = this.lineStart = 0 | ||
this.curLine = 1 | ||
} | ||
// Set up token state | ||
// Properties of the current token: | ||
// Its type | ||
this.type = tt.eof | ||
// For tokens that include more information than their type, the value | ||
this.value = null | ||
// Its start and end offset | ||
this.start = this.end = this.pos | ||
// And, if locations are used, the {line, column} object | ||
// corresponding to those offsets | ||
this.startLoc = this.endLoc = null | ||
// The current position of the tokenizer in the input. | ||
if (startPos) { | ||
this.pos = startPos | ||
this.lineStart = Math.max(0, this.input.lastIndexOf("\n", startPos)) | ||
this.curLine = this.input.slice(0, this.lineStart).split(lineBreak).length | ||
} else { | ||
this.pos = this.lineStart = 0 | ||
this.curLine = 1 | ||
} | ||
// Position information for the previous token | ||
this.lastTokEndLoc = this.lastTokStartLoc = null | ||
this.lastTokStart = this.lastTokEnd = this.pos | ||
// Properties of the current token: | ||
// Its type | ||
this.type = tt.eof | ||
// For tokens that include more information than their type, the value | ||
this.value = null | ||
// Its start and end offset | ||
this.start = this.end = this.pos | ||
// And, if locations are used, the {line, column} object | ||
// corresponding to those offsets | ||
this.startLoc = this.endLoc = this.curPosition() | ||
// The context stack is used to superficially track syntactic | ||
// context to predict whether a regular expression is allowed in a | ||
// given position. | ||
this.context = this.initialContext() | ||
this.exprAllowed = true | ||
// Position information for the previous token | ||
this.lastTokEndLoc = this.lastTokStartLoc = null | ||
this.lastTokStart = this.lastTokEnd = this.pos | ||
// Figure out if it's a module code. | ||
this.strict = this.inModule = this.options.sourceType === "module" | ||
// The context stack is used to superficially track syntactic | ||
// context to predict whether a regular expression is allowed in a | ||
// given position. | ||
this.context = this.initialContext() | ||
this.exprAllowed = true | ||
// Used to signify the start of a potential arrow function | ||
this.potentialArrowAt = -1 | ||
// Figure out if it's a module code. | ||
this.strict = this.inModule = this.options.sourceType === "module" | ||
// Flags to track whether we are in a function, a generator. | ||
this.inFunction = this.inGenerator = false | ||
// Labels in scope. | ||
this.labels = [] | ||
// Used to signify the start of a potential arrow function | ||
this.potentialArrowAt = -1 | ||
// If enabled, skip leading hashbang line. | ||
if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === '#!') | ||
this.skipLineComment(2) | ||
} | ||
// Flags to track whether we are in a function, a generator. | ||
this.inFunction = this.inGenerator = false | ||
// Labels in scope. | ||
this.labels = [] | ||
Parser.prototype.extend = function(name, f) { | ||
this[name] = f(this[name]) | ||
} | ||
// If enabled, skip leading hashbang line. | ||
if (this.pos === 0 && this.options.allowHashBang && this.input.slice(0, 2) === '#!') | ||
this.skipLineComment(2) | ||
} | ||
// Registered plugins | ||
extend(name, f) { | ||
this[name] = f(this[name]) | ||
} | ||
export const plugins = {} | ||
loadPlugins(pluginConfigs) { | ||
for (let name in pluginConfigs) { | ||
let plugin = plugins[name] | ||
if (!plugin) throw new Error("Plugin '" + name + "' not found") | ||
plugin(this, pluginConfigs[name]) | ||
} | ||
} | ||
Parser.prototype.loadPlugins = function(plugins) { | ||
for (let name in plugins) { | ||
let plugin = exports.plugins[name] | ||
if (!plugin) throw new Error("Plugin '" + name + "' not found") | ||
plugin(this, plugins[name]) | ||
parse() { | ||
let node = this.options.program || this.startNode() | ||
this.nextToken() | ||
return this.parseTopLevel(node) | ||
} | ||
} |
@@ -20,4 +20,6 @@ import {types as tt} from "./tokentype" | ||
node.body.push(stmt) | ||
if (first && this.isUseStrict(stmt)) this.setStrict(true) | ||
first = false | ||
if (first) { | ||
if (this.isUseStrict(stmt)) this.setStrict(true) | ||
first = false | ||
} | ||
} | ||
@@ -208,3 +210,3 @@ this.next() | ||
for (var cur, sawDefault; this.type != tt.braceR;) { | ||
for (var cur, sawDefault = false; this.type != tt.braceR;) { | ||
if (this.type === tt._case || this.type === tt._default) { | ||
@@ -211,0 +213,0 @@ let isCase = this.type === tt._case |
@@ -12,4 +12,4 @@ // The algorithm used to determine whether a regexp can appear at a | ||
this.token = token | ||
this.isExpr = isExpr | ||
this.preserveSpace = preserveSpace | ||
this.isExpr = !!isExpr | ||
this.preserveSpace = !!preserveSpace | ||
this.override = override | ||
@@ -36,8 +36,10 @@ } | ||
pp.braceIsBlock = function(prevType) { | ||
let parent | ||
if (prevType === tt.colon && (parent = this.curContext()).token == "{") | ||
return !parent.isExpr | ||
if (prevType === tt.colon) { | ||
let parent = this.curContext() | ||
if (parent === types.b_stat || parent === types.b_expr) | ||
return !parent.isExpr | ||
} | ||
if (prevType === tt._return) | ||
return lineBreak.test(this.input.slice(this.lastTokEnd, this.start)) | ||
if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof) | ||
if (prevType === tt._else || prevType === tt.semi || prevType === tt.eof || prevType === tt.parenR) | ||
return true | ||
@@ -44,0 +46,0 @@ if (prevType == tt.braceL) |
import {isIdentifierStart, isIdentifierChar} from "./identifier" | ||
import {types as tt, keywords as keywordTypes} from "./tokentype" | ||
import {Parser} from "./state" | ||
import {SourceLocation} from "./location" | ||
import {SourceLocation} from "./locutil" | ||
import {lineBreak, lineBreakG, isNewLine, nonASCIIwhitespace} from "./whitespace" | ||
@@ -114,3 +114,3 @@ | ||
pp.skipBlockComment = function() { | ||
let startLoc = this.options.onComment && this.options.locations && this.curPosition() | ||
let startLoc = this.options.onComment && this.curPosition() | ||
let start = this.pos, end = this.input.indexOf("*/", this.pos += 2) | ||
@@ -129,3 +129,3 @@ if (end === -1) this.raise(this.pos - 2, "Unterminated comment") | ||
this.options.onComment(true, this.input.slice(start + 2, end), start, this.pos, | ||
startLoc, this.options.locations && this.curPosition()) | ||
startLoc, this.curPosition()) | ||
} | ||
@@ -135,3 +135,3 @@ | ||
let start = this.pos | ||
let startLoc = this.options.onComment && this.options.locations && this.curPosition() | ||
let startLoc = this.options.onComment && this.curPosition() | ||
let ch = this.input.charCodeAt(this.pos+=startSkip) | ||
@@ -144,3 +144,3 @@ while (this.pos < this.input.length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233) { | ||
this.options.onComment(false, this.input.slice(start + startSkip, this.pos), start, this.pos, | ||
startLoc, this.options.locations && this.curPosition()) | ||
startLoc, this.curPosition()) | ||
} | ||
@@ -152,37 +152,37 @@ | ||
pp.skipSpace = function() { | ||
while (this.pos < this.input.length) { | ||
loop: while (this.pos < this.input.length) { | ||
let ch = this.input.charCodeAt(this.pos) | ||
if (ch === 32) { // ' ' | ||
++this.pos | ||
} else if (ch === 13) { | ||
++this.pos | ||
let next = this.input.charCodeAt(this.pos) | ||
if (next === 10) { | ||
switch (ch) { | ||
case 32: case 160: // ' ' | ||
++this.pos | ||
} | ||
if (this.options.locations) { | ||
++this.curLine | ||
this.lineStart = this.pos | ||
} | ||
} else if (ch === 10 || ch === 8232 || ch === 8233) { | ||
++this.pos | ||
if (this.options.locations) { | ||
++this.curLine | ||
this.lineStart = this.pos | ||
} | ||
} else if (ch > 8 && ch < 14) { | ||
++this.pos | ||
} else if (ch === 47) { // '/' | ||
let next = this.input.charCodeAt(this.pos + 1) | ||
if (next === 42) { // '*' | ||
this.skipBlockComment() | ||
} else if (next === 47) { // '/' | ||
this.skipLineComment(2) | ||
} else break | ||
} else if (ch === 160) { // '\xa0' | ||
++this.pos | ||
} else if (ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { | ||
++this.pos | ||
} else { | ||
break | ||
break | ||
case 13: | ||
if (this.input.charCodeAt(this.pos + 1) === 10) { | ||
++this.pos | ||
} | ||
case 10: case 8232: case 8233: | ||
++this.pos | ||
if (this.options.locations) { | ||
++this.curLine | ||
this.lineStart = this.pos | ||
} | ||
break | ||
case 47: // '/' | ||
switch (this.input.charCodeAt(this.pos + 1)) { | ||
case 42: // '*' | ||
this.skipBlockComment() | ||
break | ||
case 47: | ||
this.skipLineComment(2) | ||
break | ||
default: | ||
break loop | ||
} | ||
break | ||
default: | ||
if (ch > 8 && ch < 14 || ch >= 5760 && nonASCIIwhitespace.test(String.fromCharCode(ch))) { | ||
++this.pos | ||
} else { | ||
break loop | ||
} | ||
} | ||
@@ -381,9 +381,18 @@ } | ||
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. | ||
function tryCreateRegexp(src, flags, throwErrorAt) { | ||
try { | ||
return new RegExp(src, flags); | ||
} catch (e) { | ||
if (throwErrorAt !== undefined) { | ||
if (e instanceof SyntaxError) this.raise(throwErrorAt, "Error parsing regular expression: " + e.message) | ||
this.raise(e) | ||
} | ||
} | ||
} | ||
var regexpUnicodeSupport = !!tryCreateRegexp("\uffff", "u"); | ||
pp.readRegexp = function() { | ||
@@ -435,13 +444,6 @@ let escaped, inClass, start = this.pos | ||
if (!isRhino) { | ||
try { | ||
new RegExp(tmp) | ||
} catch (e) { | ||
if (e instanceof SyntaxError) this.raise(start, "Error parsing regular expression: " + e.message) | ||
this.raise(e) | ||
} | ||
tryCreateRegexp(tmp, undefined, start); | ||
// 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 { | ||
value = new RegExp(content, mods) | ||
} catch (err) {} | ||
value = tryCreateRegexp(content, mods) | ||
} | ||
@@ -485,8 +487,9 @@ return this.finishToken(tt.regexp, {pattern: content, flags: mods, value: value}) | ||
if (!startsWithDot && this.readInt(10) === null) this.raise(start, "Invalid number") | ||
if (this.input.charCodeAt(this.pos) === 46) { | ||
let next = this.input.charCodeAt(this.pos) | ||
if (next === 46) { // '.' | ||
++this.pos | ||
this.readInt(10) | ||
isFloat = true | ||
next = this.input.charCodeAt(this.pos) | ||
} | ||
let next = this.input.charCodeAt(this.pos) | ||
if (next === 69 || next === 101) { // 'eE' | ||
@@ -528,4 +531,4 @@ next = this.input.charCodeAt(++this.pos) | ||
if (code <= 0xFFFF) return String.fromCharCode(code) | ||
return String.fromCharCode(((code - 0x10000) >> 10) + 0xD800, | ||
((code - 0x10000) & 1023) + 0xDC00) | ||
code -= 0x10000 | ||
return String.fromCharCode((code >> 10) + 0xD800, (code & 1023) + 0xDC00) | ||
} | ||
@@ -532,0 +535,0 @@ |
@@ -111,3 +111,3 @@ // ## Token types | ||
kw("debugger") | ||
kw("default") | ||
kw("default", beforeExpr) | ||
kw("do", {isLoop: true}) | ||
@@ -114,0 +114,0 @@ kw("else", beforeExpr) |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
482151
5
11369