2015-12-16 21:15:23 +03:00
( 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 = 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 ) {
// A recursive descent parser operates by defining functions for all
// syntactic elements, and recursively calling those, each function
// advancing the input stream and returning an AST node. Precedence
// of constructs (for example, the fact that `!x[1]` means `!(x[1])`
// instead of `(!x)[1]` is handled by the fact that the parser
// function that parses unary prefix operators is called first, and
// in turn calls the function that parses `[]` subscripts — that
// way, it'll receive the node for `x[1]` already parsed, and wraps
// *that* in the unary operator node.
//
// Acorn uses an [operator precedence parser][opp] to handle binary
// operator precedence, because it is much more compact than using
// the technique outlined above, which uses different, nesting
// functions to specify precedence, for all of the ten binary
// precedence levels that JavaScript defines.
//
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
"use strict" ;
var _tokentype = _dereq _ ( "./tokentype" ) ;
var _state = _dereq _ ( "./state" ) ;
var pp = _state . Parser . prototype ;
// Check if property name clashes with already added.
// Object/class getters and setters are not allowed to clash —
// either with each other or with an init property — and in
// strict mode, init properties are also not allowed to be repeated.
pp . checkPropClash = function ( prop , propHash ) {
if ( this . options . ecmaVersion >= 6 && ( prop . computed || prop . method || prop . shorthand ) ) return ;
var key = prop . key ; var name = undefined ;
switch ( key . type ) {
case "Identifier" :
name = key . name ; break ;
case "Literal" :
name = String ( key . value ) ; break ;
default :
return ;
}
var kind = prop . kind ;
if ( this . options . ecmaVersion >= 6 ) {
if ( name === "__proto__" && kind === "init" ) {
if ( propHash . proto ) this . raise ( key . start , "Redefinition of __proto__ property" ) ;
propHash . proto = true ;
}
return ;
}
name = "$" + name ;
var other = propHash [ name ] ;
if ( other ) {
var isGetSet = kind !== "init" ;
if ( ( this . strict || isGetSet ) && other [ kind ] || ! ( isGetSet ^ other . init ) ) this . raise ( key . start , "Redefinition of property" ) ;
} else {
other = propHash [ name ] = {
init : false ,
get : false ,
set : false
} ;
}
other [ kind ] = true ;
} ;
// ### Expression parsing
// These nest, from the most general expression type at the top to
// 'atomic', nondivisible expression types at the bottom. Most of
// the functions will simply let the function(s) below them parse,
// and, *if* the syntactic construct they handle is present, wrap
// the AST node that the inner parser gave them in another node.
// Parse a full expression. The optional arguments are used to
// forbid the `in` operator (in for loops initalization expressions)
// and provide reference for storing '=' operator inside shorthand
// property assignment in contexts where both object expression
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).
pp . parseExpression = function ( noIn , refDestructuringErrors ) {
var startPos = this . start ,
startLoc = this . startLoc ;
var expr = this . parseMaybeAssign ( noIn , refDestructuringErrors ) ;
if ( this . type === _tokentype . types . comma ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . expressions = [ expr ] ;
while ( this . eat ( _tokentype . types . comma ) ) node . expressions . push ( this . parseMaybeAssign ( noIn , refDestructuringErrors ) ) ;
return this . finishNode ( node , "SequenceExpression" ) ;
}
return expr ;
} ;
// Parse an assignment expression. This includes applications of
// operators like `+=`.
pp . parseMaybeAssign = function ( noIn , refDestructuringErrors , afterLeftParse ) {
if ( this . type == _tokentype . types . _yield && this . inGenerator ) return this . parseYield ( ) ;
var validateDestructuring = false ;
if ( ! refDestructuringErrors ) {
refDestructuringErrors = { shorthandAssign : 0 , trailingComma : 0 } ;
validateDestructuring = true ;
}
var startPos = this . start ,
startLoc = this . startLoc ;
if ( this . type == _tokentype . types . parenL || this . type == _tokentype . types . name ) this . potentialArrowAt = this . start ;
var left = this . parseMaybeConditional ( noIn , refDestructuringErrors ) ;
if ( afterLeftParse ) left = afterLeftParse . call ( this , left , startPos , startLoc ) ;
if ( this . type . isAssign ) {
if ( validateDestructuring ) this . checkPatternErrors ( refDestructuringErrors , true ) ;
var node = this . startNodeAt ( startPos , startLoc ) ;
node . operator = this . value ;
node . left = this . type === _tokentype . types . eq ? this . toAssignable ( left ) : left ;
refDestructuringErrors . shorthandAssign = 0 ; // reset because shorthand default was used correctly
this . checkLVal ( left ) ;
this . next ( ) ;
node . right = this . parseMaybeAssign ( noIn ) ;
return this . finishNode ( node , "AssignmentExpression" ) ;
} else {
if ( validateDestructuring ) this . checkExpressionErrors ( refDestructuringErrors , true ) ;
}
return left ;
} ;
// Parse a ternary conditional (`?:`) operator.
pp . parseMaybeConditional = function ( noIn , refDestructuringErrors ) {
var startPos = this . start ,
startLoc = this . startLoc ;
var expr = this . parseExprOps ( noIn , refDestructuringErrors ) ;
if ( this . checkExpressionErrors ( refDestructuringErrors ) ) return expr ;
if ( this . eat ( _tokentype . types . question ) ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . test = expr ;
node . consequent = this . parseMaybeAssign ( ) ;
this . expect ( _tokentype . types . colon ) ;
node . alternate = this . parseMaybeAssign ( noIn ) ;
return this . finishNode ( node , "ConditionalExpression" ) ;
}
return expr ;
} ;
// Start the precedence parser.
pp . parseExprOps = function ( noIn , refDestructuringErrors ) {
var startPos = this . start ,
startLoc = this . startLoc ;
var expr = this . parseMaybeUnary ( refDestructuringErrors ) ;
if ( this . checkExpressionErrors ( refDestructuringErrors ) ) return expr ;
return this . parseExprOp ( expr , startPos , startLoc , - 1 , noIn ) ;
} ;
// Parse binary operators with the operator precedence parsing
// algorithm. `left` is the left-hand side of the operator.
// `minPrec` provides context that allows the function to stop and
// defer further parser to one of its callers when it encounters an
// operator that has a lower precedence than the set it is parsing.
pp . parseExprOp = function ( left , leftStartPos , leftStartLoc , minPrec , noIn ) {
var prec = this . type . binop ;
if ( prec != null && ( ! noIn || this . type !== _tokentype . types . _in ) ) {
if ( prec > minPrec ) {
var node = this . startNodeAt ( leftStartPos , leftStartLoc ) ;
node . left = left ;
node . operator = this . value ;
var op = this . type ;
this . next ( ) ;
var startPos = this . start ,
startLoc = this . startLoc ;
node . right = this . parseExprOp ( this . parseMaybeUnary ( ) , startPos , startLoc , prec , noIn ) ;
this . finishNode ( node , op === _tokentype . types . logicalOR || op === _tokentype . types . logicalAND ? "LogicalExpression" : "BinaryExpression" ) ;
return this . parseExprOp ( node , leftStartPos , leftStartLoc , minPrec , noIn ) ;
}
}
return left ;
} ;
// Parse unary operators, both prefix and postfix.
pp . parseMaybeUnary = function ( refDestructuringErrors ) {
if ( this . type . prefix ) {
var node = this . startNode ( ) ,
update = this . type === _tokentype . types . incDec ;
node . operator = this . value ;
node . prefix = true ;
this . next ( ) ;
node . argument = this . parseMaybeUnary ( ) ;
this . checkExpressionErrors ( refDestructuringErrors , true ) ;
if ( update ) this . checkLVal ( node . argument ) ; else if ( this . strict && node . operator === "delete" && node . argument . type === "Identifier" ) this . raise ( node . start , "Deleting local variable in strict mode" ) ;
return this . finishNode ( node , update ? "UpdateExpression" : "UnaryExpression" ) ;
}
var startPos = this . start ,
startLoc = this . startLoc ;
var expr = this . parseExprSubscripts ( refDestructuringErrors ) ;
if ( this . checkExpressionErrors ( refDestructuringErrors ) ) return expr ;
while ( this . type . postfix && ! this . canInsertSemicolon ( ) ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . operator = this . value ;
node . prefix = false ;
node . argument = expr ;
this . checkLVal ( expr ) ;
this . next ( ) ;
expr = this . finishNode ( node , "UpdateExpression" ) ;
}
return expr ;
} ;
// Parse call, dot, and `[]`-subscript expressions.
pp . parseExprSubscripts = function ( refDestructuringErrors ) {
var startPos = this . start ,
startLoc = this . startLoc ;
var expr = this . parseExprAtom ( refDestructuringErrors ) ;
var skipArrowSubscripts = expr . type === "ArrowFunctionExpression" && this . input . slice ( this . lastTokStart , this . lastTokEnd ) !== ")" ;
if ( this . checkExpressionErrors ( refDestructuringErrors ) || skipArrowSubscripts ) return expr ;
return this . parseSubscripts ( expr , startPos , startLoc ) ;
} ;
pp . parseSubscripts = function ( base , startPos , startLoc , noCalls ) {
for ( ; ; ) {
if ( this . eat ( _tokentype . types . dot ) ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . object = base ;
node . property = this . parseIdent ( true ) ;
node . computed = false ;
base = this . finishNode ( node , "MemberExpression" ) ;
} else if ( this . eat ( _tokentype . types . bracketL ) ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . object = base ;
node . property = this . parseExpression ( ) ;
node . computed = true ;
this . expect ( _tokentype . types . bracketR ) ;
base = this . finishNode ( node , "MemberExpression" ) ;
} else if ( ! noCalls && this . eat ( _tokentype . types . parenL ) ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . callee = base ;
node . arguments = this . parseExprList ( _tokentype . types . parenR , false ) ;
base = this . finishNode ( node , "CallExpression" ) ;
} else if ( this . type === _tokentype . types . backQuote ) {
var node = this . startNodeAt ( startPos , startLoc ) ;
node . tag = base ;
node . quasi = this . parseTemplate ( ) ;
base = this . finishNode ( node , "TaggedTemplateExpression" ) ;
} else {
return base ;
}
}
} ;
// Parse an atomic expression — either a single token that is an
// expression, an expression started by a keyword like `function` or
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
pp . parseExprAtom = function ( refDestructuringErrors ) {
var node = undefined ,
canBeArrow = this . potentialArrowAt == this . start ;
switch ( this . type ) {
case _tokentype . types . _super :
if ( ! this . inFunction ) this . raise ( this . start , "'super' outside of function or class" ) ;
case _tokentype . types . _this :
var type = this . type === _tokentype . types . _this ? "ThisExpression" : "Super" ;
node = this . startNode ( ) ;
this . next ( ) ;
return this . finishNode ( node , type ) ;
case _tokentype . types . _yield :
if ( this . inGenerator ) this . unexpected ( ) ;
case _tokentype . types . name :
var startPos = this . start ,
startLoc = this . startLoc ;
var id = this . parseIdent ( this . type !== _tokentype . types . name ) ;
if ( canBeArrow && ! this . canInsertSemicolon ( ) && this . eat ( _tokentype . types . arrow ) ) return this . parseArrowExpression ( this . startNodeAt ( startPos , startLoc ) , [ id ] ) ;
return id ;
case _tokentype . types . regexp :
var value = this . value ;
node = this . parseLiteral ( value . value ) ;
node . regex = { pattern : value . pattern , flags : value . flags } ;
return node ;
case _tokentype . types . num : case _tokentype . types . string :
return this . parseLiteral ( this . value ) ;
case _tokentype . types . _null : case _tokentype . types . _true : case _tokentype . types . _false :
node = this . startNode ( ) ;
node . value = this . type === _tokentype . types . _null ? null : this . type === _tokentype . types . _true ;
node . raw = this . type . keyword ;
this . next ( ) ;
return this . finishNode ( node , "Literal" ) ;
case _tokentype . types . parenL :
return this . parseParenAndDistinguishExpression ( canBeArrow ) ;
case _tokentype . types . bracketL :
node = this . startNode ( ) ;
this . next ( ) ;
// check whether this is array comprehension or regular array
if ( this . options . ecmaVersion >= 7 && this . type === _tokentype . types . _for ) {
return this . parseComprehension ( node , false ) ;
}
node . elements = this . parseExprList ( _tokentype . types . bracketR , true , true , refDestructuringErrors ) ;
return this . finishNode ( node , "ArrayExpression" ) ;
case _tokentype . types . braceL :
return this . parseObj ( false , refDestructuringErrors ) ;
case _tokentype . types . _function :
node = this . startNode ( ) ;
this . next ( ) ;
return this . parseFunction ( node , false ) ;
case _tokentype . types . _class :
return this . parseClass ( this . startNode ( ) , false ) ;
case _tokentype . types . _new :
return this . parseNew ( ) ;
case _tokentype . types . backQuote :
return this . parseTemplate ( ) ;
default :
this . unexpected ( ) ;
}
} ;
pp . parseLiteral = function ( value ) {
var node = this . startNode ( ) ;
node . value = value ;
node . raw = this . input . slice ( this . start , this . end ) ;
this . next ( ) ;
return this . finishNode ( node , "Literal" ) ;
} ;
pp . parseParenExpression = function ( ) {
this . expect ( _tokentype . types . parenL ) ;
var val = this . parseExpression ( ) ;
this . expect ( _tokentype . types . parenR ) ;
return val ;
} ;
pp . parseParenAndDistinguishExpression = function ( canBeArrow ) {
var startPos = this . start ,
startLoc = this . startLoc ,
val = undefined ;
if ( this . options . ecmaVersion >= 6 ) {
this . next ( ) ;
if ( this . options . ecmaVersion >= 7 && this . type === _tokentype . types . _for ) {
return this . parseComprehension ( this . startNodeAt ( startPos , startLoc ) , true ) ;
}
var innerStartPos = this . start ,
innerStartLoc = this . startLoc ;
var exprList = [ ] ,
first = true ;
var refDestructuringErrors = { shorthandAssign : 0 , trailingComma : 0 } ,
spreadStart = undefined ,
innerParenStart = undefined ;
while ( this . type !== _tokentype . types . parenR ) {
first ? first = false : this . expect ( _tokentype . types . comma ) ;
if ( this . type === _tokentype . types . ellipsis ) {
spreadStart = this . start ;
exprList . push ( this . parseParenItem ( this . parseRest ( ) ) ) ;
break ;
} else {
if ( this . type === _tokentype . types . parenL && ! innerParenStart ) {
innerParenStart = this . start ;
}
exprList . push ( this . parseMaybeAssign ( false , refDestructuringErrors , this . parseParenItem ) ) ;
}
}
var innerEndPos = this . start ,
innerEndLoc = this . startLoc ;
this . expect ( _tokentype . types . parenR ) ;
if ( canBeArrow && ! this . canInsertSemicolon ( ) && this . eat ( _tokentype . types . arrow ) ) {
this . checkPatternErrors ( refDestructuringErrors , true ) ;
if ( innerParenStart ) this . unexpected ( innerParenStart ) ;
return this . parseParenArrowList ( startPos , startLoc , exprList ) ;
}
if ( ! exprList . length ) this . unexpected ( this . lastTokStart ) ;
if ( spreadStart ) this . unexpected ( spreadStart ) ;
this . checkExpressionErrors ( refDestructuringErrors , true ) ;
if ( exprList . length > 1 ) {
val = this . startNodeAt ( innerStartPos , innerStartLoc ) ;
val . expressions = exprList ;
this . finishNodeAt ( val , "SequenceExpression" , innerEndPos , innerEndLoc ) ;
} else {
val = exprList [ 0 ] ;
}
} else {
val = this . parseParenExpression ( ) ;
}
if ( this . options . preserveParens ) {
var par = this . startNodeAt ( startPos , startLoc ) ;
par . expression = val ;
return this . finishNode ( par , "ParenthesizedExpression" ) ;
} else {
return val ;
}
} ;
pp . parseParenItem = function ( item ) {
return item ;
} ;
pp . parseParenArrowList = function ( startPos , startLoc , exprList ) {
return this . parseArrowExpression ( this . startNodeAt ( startPos , startLoc ) , exprList ) ;
} ;
// New's precedence is slightly tricky. It must allow its argument
// to be a `[]` or dot subscript expression, but not a call — at
// least, not without wrapping it in parentheses. Thus, it uses the
var empty = [ ] ;
pp . parseNew = function ( ) {
var node = this . startNode ( ) ;
var meta = this . parseIdent ( true ) ;
if ( this . options . ecmaVersion >= 6 && this . eat ( _tokentype . types . dot ) ) {
node . meta = meta ;
node . property = this . parseIdent ( true ) ;
if ( node . property . name !== "target" ) this . raise ( node . property . start , "The only valid meta property for new is new.target" ) ;
if ( ! this . inFunction ) this . raise ( node . start , "new.target can only be used in functions" ) ;
return this . finishNode ( node , "MetaProperty" ) ;
}
var startPos = this . start ,
startLoc = this . startLoc ;
node . callee = this . parseSubscripts ( this . parseExprAtom ( ) , startPos , startLoc , true ) ;
if ( this . eat ( _tokentype . types . parenL ) ) node . arguments = this . parseExprList ( _tokentype . types . parenR , false ) ; else node . arguments = empty ;
return this . finishNode ( node , "NewExpression" ) ;
} ;
// Parse template expression.
pp . parseTemplateElement = function ( ) {
var elem = this . startNode ( ) ;
elem . value = {
raw : this . input . slice ( this . start , this . end ) . replace ( /\r\n?/g , '\n' ) ,
cooked : this . value
} ;
this . next ( ) ;
elem . tail = this . type === _tokentype . types . backQuote ;
return this . finishNode ( elem , "TemplateElement" ) ;
} ;
pp . parseTemplate = function ( ) {
var node = this . startNode ( ) ;
this . next ( ) ;
node . expressions = [ ] ;
var curElt = this . parseTemplateElement ( ) ;
node . quasis = [ curElt ] ;
while ( ! curElt . tail ) {
this . expect ( _tokentype . types . dollarBraceL ) ;
node . expressions . push ( this . parseExpression ( ) ) ;
this . expect ( _tokentype . types . braceR ) ;
node . quasis . push ( curElt = this . parseTemplateElement ( ) ) ;
}
this . next ( ) ;
return this . finishNode ( node , "TemplateLiteral" ) ;
} ;
// Parse an object literal or binding pattern.
pp . parseObj = function ( isPattern , refDestructuringErrors ) {
var node = this . startNode ( ) ,
first = true ,
propHash = { } ;
node . properties = [ ] ;
this . next ( ) ;
while ( ! this . eat ( _tokentype . types . braceR ) ) {
if ( ! first ) {
this . expect ( _tokentype . types . comma ) ;
if ( this . afterTrailingComma ( _tokentype . types . braceR ) ) break ;
} else first = false ;
var prop = this . startNode ( ) ,
isGenerator = undefined ,
startPos = undefined ,
startLoc = undefined ;
if ( this . options . ecmaVersion >= 6 ) {
prop . method = false ;
prop . shorthand = false ;
if ( isPattern || refDestructuringErrors ) {
startPos = this . start ;
startLoc = this . startLoc ;
}
if ( ! isPattern ) isGenerator = this . eat ( _tokentype . types . star ) ;
}
this . parsePropertyName ( prop ) ;
this . parsePropertyValue ( prop , isPattern , isGenerator , startPos , startLoc , refDestructuringErrors ) ;
this . checkPropClash ( prop , propHash ) ;
node . properties . push ( this . finishNode ( prop , "Property" ) ) ;
}
return this . finishNode ( node , isPattern ? "ObjectPattern" : "ObjectExpression" ) ;
} ;
pp . parsePropertyValue = function ( prop , isPattern , isGenerator , startPos , startLoc , refDestructuringErrors ) {
if ( this . eat ( _tokentype . types . colon ) ) {
prop . value = isPattern ? this . parseMaybeDefault ( this . start , this . startLoc ) : this . parseMaybeAssign ( false , refDestructuringErrors ) ;
prop . kind = "init" ;
} else if ( this . options . ecmaVersion >= 6 && this . type === _tokentype . types . parenL ) {
if ( isPattern ) this . unexpected ( ) ;
prop . kind = "init" ;
prop . method = true ;
prop . value = this . parseMethod ( isGenerator ) ;
} else if ( this . options . ecmaVersion >= 5 && ! prop . computed && prop . key . type === "Identifier" && ( prop . key . name === "get" || prop . key . name === "set" ) && ( this . type != _tokentype . types . comma && this . type != _tokentype . types . braceR ) ) {
if ( isGenerator || isPattern ) this . unexpected ( ) ;
prop . kind = prop . key . name ;
this . parsePropertyName ( prop ) ;
prop . value = this . parseMethod ( false ) ;
var paramCount = prop . kind === "get" ? 0 : 1 ;
if ( prop . value . params . length !== paramCount ) {
var start = prop . value . start ;
if ( prop . kind === "get" ) this . raise ( start , "getter should have no params" ) ; else this . raise ( start , "setter should have exactly one param" ) ;
}
} else if ( this . options . ecmaVersion >= 6 && ! prop . computed && prop . key . type === "Identifier" ) {
prop . kind = "init" ;
if ( isPattern ) {
if ( this . keywords . test ( prop . key . name ) || ( this . strict ? this . reservedWordsStrictBind : this . reservedWords ) . test ( prop . key . name ) ) this . raise ( prop . key . start , "Binding " + prop . key . name ) ;
prop . value = this . parseMaybeDefault ( startPos , startLoc , prop . key ) ;
} else if ( this . type === _tokentype . types . eq && refDestructuringErrors ) {
if ( ! refDestructuringErrors . shorthandAssign ) refDestructuringErrors . shorthandAssign = this . start ;
prop . value = this . parseMaybeDefault ( startPos , startLoc , prop . key ) ;
} else {
prop . value = prop . key ;
}
prop . shorthand = true ;
} else this . unexpected ( ) ;
} ;
pp . parsePropertyName = function ( prop ) {
if ( this . options . ecmaVersion >= 6 ) {
if ( this . eat ( _tokentype . types . bracketL ) ) {
prop . computed = true ;
prop . key = this . parseMaybeAssign ( ) ;
this . expect ( _tokentype . types . bracketR ) ;
return prop . key ;
} else {
prop . computed = false ;
}
}
return prop . key = this . type === _tokentype . types . num || this . type === _tokentype . types . string ? this . parseExprAtom ( ) : this . parseIdent ( true ) ;
} ;
// Initialize empty function node.
pp . initFunction = function ( node ) {
node . id = null ;
if ( this . options . ecmaVersion >= 6 ) {
node . generator = false ;
node . expression = false ;
}
} ;
// Parse object or class method.
pp . parseMethod = function ( isGenerator ) {
var node = this . startNode ( ) ;
this . initFunction ( node ) ;
this . expect ( _tokentype . types . parenL ) ;
node . params = this . parseBindingList ( _tokentype . types . parenR , false , false ) ;
if ( this . options . ecmaVersion >= 6 ) node . generator = isGenerator ;
this . parseFunctionBody ( node , false ) ;
return this . finishNode ( node , "FunctionExpression" ) ;
} ;
// Parse arrow function expression with given parameters.
pp . parseArrowExpression = function ( node , params ) {
this . initFunction ( node ) ;
node . params = this . toAssignableList ( params , true ) ;
this . parseFunctionBody ( node , true ) ;
return this . finishNode ( node , "ArrowFunctionExpression" ) ;
} ;
// Parse function body and check parameters.
pp . parseFunctionBody = function ( node , isArrowFunction ) {
var isExpression = isArrowFunction && this . type !== _tokentype . types . braceL ;
if ( isExpression ) {
node . body = this . parseMaybeAssign ( ) ;
node . expression = true ;
} else {
// Start a new scope with regard to labels and the `inFunction`
// flag (restore them to their old value afterwards).
var oldInFunc = this . inFunction ,
oldInGen = this . inGenerator ,
oldLabels = this . labels ;
this . inFunction = true ; this . inGenerator = node . generator ; this . labels = [ ] ;
node . body = this . parseBlock ( true ) ;
node . expression = false ;
this . inFunction = oldInFunc ; this . inGenerator = oldInGen ; this . labels = oldLabels ;
}
// If this is a strict mode function, verify that argument names
// are not repeated, and it does not try to bind the words `eval`
// or `arguments`.
if ( this . strict || ! isExpression && node . body . body . length && this . isUseStrict ( node . body . body [ 0 ] ) ) {
var oldStrict = this . strict ;
this . strict = true ;
if ( node . id ) this . checkLVal ( node . id , true ) ;
this . checkParams ( node ) ;
this . strict = oldStrict ;
} else if ( isArrowFunction ) {
this . checkParams ( node ) ;
}
} ;
// Checks function params for various disallowed patterns such as using "eval"
// or "arguments" and duplicate parameters.
pp . checkParams = function ( node ) {
var nameHash = { } ;
for ( var i = 0 ; i < node . params . length ; i ++ ) {
this . checkLVal ( node . params [ i ] , true , nameHash ) ;
}
} ;
// Parses a comma-separated list of expressions, and returns them as
// an array. `close` is the token type that ends the list, and
// `allowEmpty` can be turned on to allow subsequent commas with
// nothing in between them to be parsed as `null` (which is needed
// for array literals).
pp . parseExprList = function ( close , allowTrailingComma , allowEmpty , refDestructuringErrors ) {
var elts = [ ] ,
first = true ;
while ( ! this . eat ( close ) ) {
if ( ! first ) {
this . expect ( _tokentype . types . comma ) ;
if ( this . type === close && refDestructuringErrors && ! refDestructuringErrors . trailingComma ) {
refDestructuringErrors . trailingComma = this . lastTokStart ;
}
if ( allowTrailingComma && this . afterTrailingComma ( close ) ) break ;
} else first = false ;
var elt = undefined ;
if ( allowEmpty && this . type === _tokentype . types . comma ) elt = null ; else if ( this . type === _tokentype . types . ellipsis ) elt = this . parseSpread ( refDestructuringErrors ) ; else elt = this . parseMaybeAssign ( false , refDestructuringErrors ) ;
elts . push ( elt ) ;
}
return elts ;
} ;
// Parse the next token as an identifier. If `liberal` is true (used
// when parsing properties), it will also convert keywords into
// identifiers.
pp . parseIdent = function ( liberal ) {
var node = this . startNode ( ) ;
if ( liberal && this . options . allowReserved == "never" ) liberal = false ;
if ( this . type === _tokentype . types . name ) {
2018-02-01 22:45:22 +03:00
if ( ! liberal && ( this . strict ? this . reservedWordsStrict : this . reservedWords ) . test ( this . value ) && ( this . options . ecmaVersion >= 6 || ! this . input . slice ( this . start , this . end ) . includes ( "\\" ) ) ) this . raise ( this . start , "The keyword '" + this . value + "' is reserved" ) ;
2015-12-16 21:15:23 +03:00
node . name = this . value ;
} else if ( liberal && this . type . keyword ) {
node . name = this . type . keyword ;
} else {
this . unexpected ( ) ;
}
this . next ( ) ;
return this . finishNode ( node , "Identifier" ) ;
} ;
// Parses yield expression inside generator.
pp . parseYield = function ( ) {
var node = this . startNode ( ) ;
this . next ( ) ;
if ( this . type == _tokentype . types . semi || this . canInsertSemicolon ( ) || this . type != _tokentype . types . star && ! this . type . startsExpr ) {
node . delegate = false ;
node . argument = null ;
} else {
node . delegate = this . eat ( _tokentype . types . star ) ;
node . argument = this . parseMaybeAssign ( ) ;
}
return this . finishNode ( node , "YieldExpression" ) ;
} ;
// Parses array and generator comprehensions.
pp . parseComprehension = function ( node , isGenerator ) {
node . blocks = [ ] ;
while ( this . type === _tokentype . types . _for ) {
var block = this . startNode ( ) ;
this . next ( ) ;
this . expect ( _tokentype . types . parenL ) ;
block . left = this . parseBindingAtom ( ) ;
this . checkLVal ( block . left , true ) ;
this . expectContextual ( "of" ) ;
block . right = this . parseExpression ( ) ;
this . expect ( _tokentype . types . parenR ) ;
node . blocks . push ( this . finishNode ( block , "ComprehensionBlock" ) ) ;
}
node . filter = this . eat ( _tokentype . types . _if ) ? this . parseParenExpression ( ) : null ;
node . body = this . parseExpression ( ) ;
this . expect ( isGenerator ? _tokentype . types . parenR : _tokentype . types . bracketR ) ;
node . generator = isGenerator ;
return this . finishNode ( node , "ComprehensionExpression" ) ;
} ;
} , { "./state" : 10 , "./tokentype" : 14 } ] , 2 : [ function ( _dereq _ , module , exports ) {
// 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
// predicate containing a big ugly `switch` statement is faster than
// a regular expression, and on Chrome the two are about on par.
// This function uses `eval` (non-lexical) to produce such a
// predicate from a space-separated string of words.
//
// It starts by sorting the words by length.
// Reserved word lists for various dialects of the language
"use strict" ;
exports . _ _esModule = true ;
exports . isIdentifierStart = isIdentifierStart ;
exports . isIdentifierChar = isIdentifierChar ;
var reservedWords = {
3 : "abstract boolean byte char class double enum export extends final float goto implements import int interface long native package private protected public short static super synchronized throws transient volatile" ,
5 : "class enum extends super const export import" ,
6 : "enum" ,
strict : "implements interface let package private protected public static yield" ,
strictBind : "eval arguments"
} ;
exports . reservedWords = reservedWords ;
// And the keywords
var ecma5AndLessKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this" ;
var keywords = {
5 : ecma5AndLessKeywords ,
6 : ecma5AndLessKeywords + " let const class extends export import yield super"
} ;
exports . keywords = keywords ;
// ## Character categories
// Big ugly regular expressions that match characters in the
// whitespace, identifier, and identifier-start categories. These
// are only applied when a character is found to actually have a
// code point above 128.
// Generated by `bin/generate-identifier-regex.js`.
var nonASCIIidentifierStartChars = "ªµºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬˮͰ-ʹͶͷͺ-ͽͿΆΈ-ΊΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙա-ևא-תװ-ײؠ-يٮٯٱ-ۓەۥۦۮۯۺ-ۼۿܐܒ-ܯݍ-ޥޱߊ-ߪߴߵߺࠀ-ࠕࠚࠤࠨࡀ-ࡘࢠ-ࢲऄ-हऽॐक़-ॡॱ-ঀঅ-ঌএঐও-নপ-রলশ-হঽৎড়ঢ়য়-ৡৰৱਅ-ਊਏਐਓ-ਨਪ-ਰਲਲ਼ਵਸ਼ਸਹਖ਼-ੜਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલળવ-હઽૐૠૡଅ-ଌଏଐଓ-ନପ-ରଲଳଵ-ହଽଡ଼ଢ଼ୟ-ୡୱஃஅ-ஊஎ-ஐஒ-கஙசஜஞடணதந-பம-ஹௐఅ-ఌఎ-ఐఒ-నప-హఽౘౙౠౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽೞೠೡೱೲഅ-ഌഎ-ഐഒ-ഺഽൎൠൡൺ-ൿඅ-ඖක-නඳ-රලව-ෆก-ะาำเ-ๆກຂຄງຈຊຍດ-ທນ-ຟມ-ຣລວສຫອ-ະາຳຽເ-ໄໆໜ-ໟༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿၐ-ၕၚ-ၝၡၥၦၮ-ၰၵ-ႁႎႠ-ჅჇჍა-ჺჼ-ቈቊ-ቍቐ-ቖቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏼᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛮ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗៜᠠ-ᡷᢀ-ᢨᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᧁ-ᧇᨀ-ᨖᨠ-ᩔᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙὛὝὟ-ώᾀ-ᾴᾶ-ᾼιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱⁿₐ-ₜℂℇℊ-ℓℕ℘-ℝℤΩℨK-ℹℼ-ℿⅅ-ⅉⅎⅠ-ↈⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲⳳⴀ-ⴥⴧⴭⴰ-ⵧⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞ々-〇〡-〩〱-〵〸-〼ぁ-ゖ゛-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿌ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪꘫꙀ-ꙮꙿ-ꚝꚠ-ꛯꜗ-ꜟꜢ-ꞈꞋ-ꞎꞐ-ꞭꞰꞱꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺꩾ-ꪯꪱꪵꪶꪹ-ꪽꫀꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭟꭤꭥꯀ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִײַ-ﬨשׁ-זּטּ-לּמּנּסּףּפּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Z a -zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ" ;
var nonASCIIidentifierChars = "·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-٩ٰۖ-ۜ۟-۪ۤۧۨ-ۭ۰-۹ܑܰ-݊ަ-ް߀-߉߫-߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛ࣤ-ःऺ-़ा-ॏ॑-ॗॢॣ०-९ঁ-ঃ়া-ৄেৈো-্ৗৢৣ০-৯ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑ੦-ੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣ૦-૯ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣ୦-୯ஂா-ூெ-ைொ-்ௗ௦-௯ఀ-ఃా-ౄె-ైొ-్ౕౖౢౣ౦-౯ಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣ೦-೯ഁ-ഃാ-ൄെ-ൈൊ-്ൗൢൣ൦-൯ංඃ්ා-ුූෘ-ෟ෦-෯ෲෳัิ-ฺ็-๎๐-๙ັິ-ູົຼ່-ໍ໐-໙༘༙༠-༩༹༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှ၀-၉ၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏ-ႝ፝-፟፩-፱ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝០-៩᠋-᠍᠐-᠙ᢩᤠ-ᤫᤰ-᤻᥆-᥏ᦰ-ᧀᧈᧉ᧐-᧚ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼-᪉᪐-᪙᪰-᪽ᬀ-ᬄ᬴-᭄᭐-᭙᭫-᭳ᮀ-ᮂᮡ-ᮭ᮰-᮹᯦-᯳ᰤ-᰷᱀-᱉᱐-᱙᳐-᳔᳒-᳨᳭ᳲ-᳴᳸᳹᷀-᷵᷼-᷿‿⁀⁔⃐-⃥⃜⃡-⃰⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꘠-꘩꙯ꙴ-꙽ꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-꣄꣐-꣙꣠-꣱꤀-꤉ꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀꧐-꧙ꧥ꧰-꧹ꨩ-ꨶꩃꩌꩍ꩐-꩙ꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭꯰-꯹ﬞ︀-️︠-︭︳︴﹍-﹏ 0 -9 _ " ;
var nonASCIIidentifierStart = new RegExp ( "[" + nonASCIIidentifierStartChars + "]" ) ;
var nonASCIIidentifier = new RegExp ( "[" + nonASCIIidentifierStartChars + nonASCIIidentifierChars + "]" ) ;
nonASCIIidentifierStartChars = nonASCIIidentifierChars = null ;
// These are a run-length and offset encoded representation of the
// >0xffff code points that are a valid part of identifiers. The
// offset starts at 0x10000, and each pair of numbers represents an
// offset to the next range, and then a size of the range. They were
// generated by tools/generate-identifier-regex.js
var astralIdentifierStartCodes = [ 0 , 11 , 2 , 25 , 2 , 18 , 2 , 1 , 2 , 14 , 3 , 13 , 35 , 122 , 70 , 52 , 268 , 28 , 4 , 48 , 48 , 31 , 17 , 26 , 6 , 37 , 11 , 29 , 3 , 35 , 5 , 7 , 2 , 4 , 43 , 157 , 99 , 39 , 9 , 51 , 157 , 310 , 10 , 21 , 11 , 7 , 153 , 5 , 3 , 0 , 2 , 43 , 2 , 1 , 4 , 0 , 3 , 22 , 11 , 22 , 10 , 30 , 98 , 21 , 11 , 25 , 71 , 55 , 7 , 1 , 65 , 0 , 16 , 3 , 2 , 2 , 2 , 26 , 45 , 28 , 4 , 28 , 36 , 7 , 2 , 27 , 28 , 53 , 11 , 21 , 11 , 18 , 14 , 17 , 111 , 72 , 955 , 52 , 76 , 44 , 33 , 24 , 27 , 35 , 42 , 34 , 4 , 0 , 13 , 47 , 15 , 3 , 22 , 0 , 38 , 17 , 2 , 24 , 133 , 46 , 39 , 7 , 3 , 1 , 3 , 21 , 2 , 6 , 2 , 1 , 2 , 4 , 4 , 0 , 32 , 4 , 287 , 47 , 21 , 1 , 2 , 0 , 185 , 46 , 82 , 47 , 21 , 0 , 60 , 42 , 502 , 63 , 32 , 0 , 449 , 56 , 1288 , 920 , 104 , 110 , 2962 , 1070 , 13266 , 568 , 8 , 30 , 114 , 29 , 19 , 47 , 17 , 3 , 32 , 20 , 6 , 18 , 881 , 68 , 12 , 0 , 67 , 12 , 16481 , 1 , 3071 , 106 , 6 , 12 , 4 , 8 , 8 , 9 , 5991 , 84 , 2 , 70 , 2 , 1 , 3 , 0 , 3 , 1 , 3 , 3 , 2 , 11 , 2 , 0 , 2 , 6 , 2 , 64 , 2 , 3 , 3 , 7 , 2 , 6 , 2 , 27 , 2 , 3 , 2 , 4 , 2 , 0 , 4 , 6 , 2 , 339 , 3 , 24 , 2 , 24 , 2 , 30 , 2 , 24 , 2 , 30 , 2 , 24 , 2 , 30 , 2 , 24 , 2 , 30 , 2 , 24 , 2 , 7 , 4149 , 196 , 1340 , 3 , 2 , 26 , 2 , 1 , 2 , 0 , 3 , 0 , 2 , 9 , 2 , 3 , 2 , 0 , 2 , 0 , 7 , 0 , 5 , 0 , 2 , 0 , 2 , 0 , 2 , 2 , 2 , 1 , 2 , 0 , 3 , 0 , 2 , 0 , 2 , 0 , 2 , 0 , 2 , 0 , 2 , 1 , 2 , 0 , 3 , 3 , 2 , 6 , 2 , 3 , 2 , 3 , 2 , 0 , 2 , 9 , 2 , 16 , 6 , 2 , 2 , 4 , 2 , 16 , 4421 , 42710 , 42 , 4148 , 12 , 221 , 16355 , 541 ] ;
var astralIdentifierCodes = [ 509 , 0 , 227 , 0 , 150 , 4 , 294 , 9 , 1368 , 2 , 2 , 1 , 6 , 3 , 41 , 2 , 5 , 0 , 166 , 1 , 1306 , 2 , 54 , 14 , 32 , 9 , 16 , 3 , 46 , 10 , 54 , 9 , 7 , 2 , 37 , 13 , 2 , 9 , 52 , 0 , 13 , 2 , 49 , 13 , 16 , 9 , 83 , 11 , 168 , 11 , 6 , 9 , 8 , 2 , 57 , 0 , 2 , 6 , 3 , 1 , 3 , 2 , 10 , 0 , 11 , 1 , 3 , 6 , 4 , 4 , 316 , 19 , 13 , 9 , 214 , 6 , 3 , 8 , 112 , 16 , 16 , 9 , 82 , 12 , 9 , 9 , 535 , 9 , 20855 , 9 , 135 , 4 , 60 , 6 , 26 , 9 , 1016 , 45 , 17 , 3 , 19723 , 1 , 5319 , 4 , 4 , 5 , 9 , 7 , 3 , 6 , 31 , 3 , 149 , 2 , 1418 , 49 , 4305 , 6 , 792618 , 239 ] ;
// This has a complexity linear to the value of the code. The
// assumption is that looking up astral identifier characters is
// rare.
function isInAstralSet ( code , set ) {
var pos = 0x10000 ;
for ( var i = 0 ; i < set . length ; i += 2 ) {
pos += set [ i ] ;
if ( pos > code ) return false ;
pos += set [ i + 1 ] ;
if ( pos >= code ) return true ;
}
}
// Test whether a given character code starts an identifier.
function isIdentifierStart ( code , astral ) {
if ( code < 65 ) return code === 36 ;
if ( code < 91 ) return true ;
if ( code < 97 ) return code === 95 ;
if ( code < 123 ) return true ;
if ( code <= 0xffff ) return code >= 0xaa && nonASCIIidentifierStart . test ( String . fromCharCode ( code ) ) ;
if ( astral === false ) return false ;
return isInAstralSet ( code , astralIdentifierStartCodes ) ;
}
// Test whether a given character is part of an identifier.
function isIdentifierChar ( code , astral ) {
if ( code < 48 ) return code === 36 ;
if ( code < 58 ) return true ;
if ( code < 65 ) return false ;
if ( code < 91 ) return true ;
if ( code < 97 ) return code === 95 ;
if ( code < 123 ) return true ;
if ( code <= 0xffff ) return code >= 0xaa && nonASCIIidentifier . test ( String . fromCharCode ( code ) ) ;
if ( astral === false ) return false ;
return isInAstralSet ( code , astralIdentifierStartCodes ) || isInAstralSet ( code , astralIdentifierCodes ) ;
}
} , { } ] , 3 : [ function ( _dereq _ , module , exports ) {
2015-01-06 23:24:00 +03:00
// Acorn is a tiny, fast JavaScript parser written in JavaScript.
//
2015-12-16 21:15:23 +03:00
// Acorn was written by Marijn Haverbeke, Ingvar Stepanyan, and
// various contributors and released under an MIT license.
2015-01-06 23:24:00 +03:00
//
// Git repositories for Acorn are available at
//
// http://marijnhaverbeke.nl/git/acorn
2015-12-16 21:15:23 +03:00
// https://github.com/ternjs/acorn.git
2015-01-06 23:24:00 +03:00
//
// Please use the [github bug tracker][ghbt] to report issues.
//
2015-12-16 21:15:23 +03:00
// [ghbt]: https://github.com/ternjs/acorn/issues
2015-01-06 23:24:00 +03:00
//
// 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
2015-12-16 21:15:23 +03:00
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . _ _esModule = true ;
exports . parse = parse ;
exports . parseExpressionAt = parseExpressionAt ;
exports . tokenizer = tokenizer ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _state = _dereq _ ( "./state" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_dereq _ ( "./parseutil" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_dereq _ ( "./statement" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_dereq _ ( "./lval" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_dereq _ ( "./expression" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_dereq _ ( "./location" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . Parser = _state . Parser ;
exports . plugins = _state . plugins ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _options = _dereq _ ( "./options" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . defaultOptions = _options . defaultOptions ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _locutil = _dereq _ ( "./locutil" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . Position = _locutil . Position ;
exports . SourceLocation = _locutil . SourceLocation ;
exports . getLineInfo = _locutil . getLineInfo ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _node = _dereq _ ( "./node" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . Node = _node . Node ;
var _tokentype = _dereq _ ( "./tokentype" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . TokenType = _tokentype . TokenType ;
exports . tokTypes = _tokentype . types ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _tokencontext = _dereq _ ( "./tokencontext" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . TokContext = _tokencontext . TokContext ;
exports . tokContexts = _tokencontext . types ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _identifier = _dereq _ ( "./identifier" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . isIdentifierChar = _identifier . isIdentifierChar ;
exports . isIdentifierStart = _identifier . isIdentifierStart ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _tokenize = _dereq _ ( "./tokenize" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . Token = _tokenize . Token ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _whitespace = _dereq _ ( "./whitespace" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . isNewLine = _whitespace . isNewLine ;
exports . lineBreak = _whitespace . lineBreak ;
exports . lineBreakG = _whitespace . lineBreakG ;
var version = "2.6.4" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . version = version ;
// The main exported interface (under `self.acorn` when in the
// browser) is a `parse` function that takes a code string and
// returns an abstract syntax tree as specified by [Mozilla parser
// API][api].
//
// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function parse ( input , options ) {
return new _state . Parser ( options , input ) . parse ( ) ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// This function tries to parse a single expression at a given
// offset in a string. Useful for parsing mixed-language formats
// that embed JavaScript expressions.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function parseExpressionAt ( input , pos , options ) {
var p = new _state . Parser ( options , input , pos ) ;
p . nextToken ( ) ;
return p . parseExpression ( ) ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Acorn is organized as a tokenizer and a recursive-descent parser.
// The `tokenizer` export provides an interface to the tokenizer.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function tokenizer ( input , options ) {
return new _state . Parser ( options , input ) ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./expression" : 1 , "./identifier" : 2 , "./location" : 4 , "./locutil" : 5 , "./lval" : 6 , "./node" : 7 , "./options" : 8 , "./parseutil" : 9 , "./state" : 10 , "./statement" : 11 , "./tokencontext" : 12 , "./tokenize" : 13 , "./tokentype" : 14 , "./whitespace" : 16 } ] , 4 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _state = _dereq _ ( "./state" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _locutil = _dereq _ ( "./locutil" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var pp = _state . Parser . prototype ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// This function is used to raise exceptions on parse errors. It
// takes an offset integer (into the current `input`) to indicate
// the location of the error, attaches the position to the end
// of the error message, and then raises a `SyntaxError` with that
// message.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . raise = function ( pos , message ) {
var loc = _locutil . getLineInfo ( this . input , pos ) ;
message += " (" + loc . line + ":" + loc . column + ")" ;
var err = new SyntaxError ( message ) ;
err . pos = pos ; err . loc = loc ; err . raisedAt = this . pos ;
throw err ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . curPosition = function ( ) {
if ( this . options . locations ) {
return new _locutil . Position ( this . curLine , this . pos - this . lineStart ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./locutil" : 5 , "./state" : 10 } ] , 5 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . _ _esModule = true ;
exports . getLineInfo = getLineInfo ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _whitespace = _dereq _ ( "./whitespace" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// These are used when `options.locations` is on, for the
// `startLoc` and `endLoc` properties.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var Position = ( function ( ) {
function Position ( line , col ) {
_classCallCheck ( this , Position ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
this . line = line ;
this . column = col ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
Position . prototype . offset = function offset ( n ) {
return new Position ( this . line , this . column + n ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
return Position ;
} ) ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . Position = Position ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var SourceLocation = function SourceLocation ( p , start , end ) {
_classCallCheck ( this , SourceLocation ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
this . start = start ;
this . end = end ;
if ( p . sourceFile !== null ) this . source = p . sourceFile ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// 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.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . SourceLocation = SourceLocation ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function getLineInfo ( input , offset ) {
for ( var line = 1 , cur = 0 ; ; ) {
_whitespace . lineBreakG . lastIndex = cur ;
var match = _whitespace . lineBreakG . exec ( input ) ;
if ( match && match . index < offset ) {
++ line ;
cur = match . index + match [ 0 ] . length ;
2015-01-06 23:24:00 +03:00
} else {
2015-12-16 21:15:23 +03:00
return new Position ( line , offset - cur ) ;
2015-01-06 23:24:00 +03:00
}
}
2015-12-16 21:15:23 +03:00
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./whitespace" : 16 } ] , 6 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _tokentype = _dereq _ ( "./tokentype" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _state = _dereq _ ( "./state" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _util = _dereq _ ( "./util" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var pp = _state . Parser . prototype ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Convert existing expression atom to assignable pattern
// if possible.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . toAssignable = function ( node , isBinding ) {
if ( this . options . ecmaVersion >= 6 && node ) {
switch ( node . type ) {
case "Identifier" :
case "ObjectPattern" :
case "ArrayPattern" :
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "ObjectExpression" :
node . type = "ObjectPattern" ;
for ( var i = 0 ; i < node . properties . length ; i ++ ) {
var prop = node . properties [ i ] ;
if ( prop . kind !== "init" ) this . raise ( prop . key . start , "Object pattern can't contain getter or setter" ) ;
this . toAssignable ( prop . value , isBinding ) ;
}
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "ArrayExpression" :
node . type = "ArrayPattern" ;
this . toAssignableList ( node . elements , isBinding ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "AssignmentExpression" :
if ( node . operator === "=" ) {
node . type = "AssignmentPattern" ;
delete node . operator ;
// falls through to AssignmentPattern
} else {
this . raise ( node . left . end , "Only '=' operator can be used for specifying default value." ) ;
break ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "AssignmentPattern" :
if ( node . right . type === "YieldExpression" ) this . raise ( node . right . start , "Yield expression cannot be a default value" ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "ParenthesizedExpression" :
node . expression = this . toAssignable ( node . expression , isBinding ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "MemberExpression" :
if ( ! isBinding ) break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
default :
this . raise ( node . start , "Assigning to rvalue" ) ;
}
}
return node ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Convert list of expression atoms to binding list.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . toAssignableList = function ( exprList , isBinding ) {
var end = exprList . length ;
if ( end ) {
var last = exprList [ end - 1 ] ;
if ( last && last . type == "RestElement" ) {
-- end ;
} else if ( last && last . type == "SpreadElement" ) {
last . type = "RestElement" ;
var arg = last . argument ;
this . toAssignable ( arg , isBinding ) ;
if ( arg . type !== "Identifier" && arg . type !== "MemberExpression" && arg . type !== "ArrayPattern" ) this . unexpected ( arg . start ) ;
-- end ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
if ( isBinding && last . type === "RestElement" && last . argument . type !== "Identifier" ) this . unexpected ( last . argument . start ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
for ( var i = 0 ; i < end ; i ++ ) {
var elt = exprList [ i ] ;
if ( elt ) this . toAssignable ( elt , isBinding ) ;
}
return exprList ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Parses spread element.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . parseSpread = function ( refDestructuringErrors ) {
var node = this . startNode ( ) ;
this . next ( ) ;
node . argument = this . parseMaybeAssign ( refDestructuringErrors ) ;
return this . finishNode ( node , "SpreadElement" ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . parseRest = function ( allowNonIdent ) {
var node = this . startNode ( ) ;
this . next ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// RestElement inside of a function parameter must be an identifier
if ( allowNonIdent ) node . argument = this . type === _tokentype . types . name ? this . parseIdent ( ) : this . unexpected ( ) ; else node . argument = this . type === _tokentype . types . name || this . type === _tokentype . types . bracketL ? this . parseBindingAtom ( ) : this . unexpected ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
return this . finishNode ( node , "RestElement" ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Parses lvalue (assignable) atom.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . parseBindingAtom = function ( ) {
if ( this . options . ecmaVersion < 6 ) return this . parseIdent ( ) ;
switch ( this . type ) {
case _tokentype . types . name :
return this . parseIdent ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case _tokentype . types . bracketL :
var node = this . startNode ( ) ;
this . next ( ) ;
node . elements = this . parseBindingList ( _tokentype . types . bracketR , true , true ) ;
return this . finishNode ( node , "ArrayPattern" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case _tokentype . types . braceL :
return this . parseObj ( true ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
default :
this . unexpected ( ) ;
}
} ;
pp . parseBindingList = function ( close , allowEmpty , allowTrailingComma , allowNonIdent ) {
var elts = [ ] ,
first = true ;
while ( ! this . eat ( close ) ) {
if ( first ) first = false ; else this . expect ( _tokentype . types . comma ) ;
if ( allowEmpty && this . type === _tokentype . types . comma ) {
elts . push ( null ) ;
} else if ( allowTrailingComma && this . afterTrailingComma ( close ) ) {
break ;
} else if ( this . type === _tokentype . types . ellipsis ) {
var rest = this . parseRest ( allowNonIdent ) ;
this . parseBindingListItem ( rest ) ;
elts . push ( rest ) ;
this . expect ( close ) ;
break ;
} else {
var elem = this . parseMaybeDefault ( this . start , this . startLoc ) ;
this . parseBindingListItem ( elem ) ;
elts . push ( elem ) ;
}
}
return elts ;
} ;
pp . parseBindingListItem = function ( param ) {
return param ;
} ;
// Parses assignment pattern around given atom if possible.
pp . parseMaybeDefault = function ( startPos , startLoc , left ) {
left = left || this . parseBindingAtom ( ) ;
if ( this . options . ecmaVersion < 6 || ! this . eat ( _tokentype . types . eq ) ) return left ;
var node = this . startNodeAt ( startPos , startLoc ) ;
node . left = left ;
node . right = this . parseMaybeAssign ( ) ;
return this . finishNode ( node , "AssignmentPattern" ) ;
} ;
// Verify that a node is an lval — something that can be assigned
// to.
pp . checkLVal = function ( expr , isBinding , checkClashes ) {
switch ( expr . type ) {
case "Identifier" :
if ( this . strict && this . reservedWordsStrictBind . test ( expr . name ) ) this . raise ( expr . start , ( isBinding ? "Binding " : "Assigning to " ) + expr . name + " in strict mode" ) ;
if ( checkClashes ) {
if ( _util . has ( checkClashes , expr . name ) ) this . raise ( expr . start , "Argument name clash" ) ;
checkClashes [ expr . name ] = true ;
}
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "MemberExpression" :
if ( isBinding ) this . raise ( expr . start , ( isBinding ? "Binding" : "Assigning to" ) + " member expression" ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "ObjectPattern" :
for ( var i = 0 ; i < expr . properties . length ; i ++ ) {
this . checkLVal ( expr . properties [ i ] . value , isBinding , checkClashes ) ;
} break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "ArrayPattern" :
for ( var i = 0 ; i < expr . elements . length ; i ++ ) {
var elem = expr . elements [ i ] ;
if ( elem ) this . checkLVal ( elem , isBinding , checkClashes ) ;
}
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "AssignmentPattern" :
this . checkLVal ( expr . left , isBinding , checkClashes ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "RestElement" :
this . checkLVal ( expr . argument , isBinding , checkClashes ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case "ParenthesizedExpression" :
this . checkLVal ( expr . expression , isBinding , checkClashes ) ;
break ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
default :
this . raise ( expr . start , ( isBinding ? "Binding" : "Assigning to" ) + " rvalue" ) ;
}
} ;
} , { "./state" : 10 , "./tokentype" : 14 , "./util" : 15 } ] , 7 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
exports . _ _esModule = true ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
var _state = _dereq _ ( "./state" ) ;
var _locutil = _dereq _ ( "./locutil" ) ;
var Node = function Node ( parser , pos , loc ) {
_classCallCheck ( this , Node ) ;
this . type = "" ;
this . start = pos ;
this . end = 0 ;
if ( parser . options . locations ) this . loc = new _locutil . 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.
;
exports . Node = Node ;
var pp = _state . Parser . prototype ;
pp . startNode = function ( ) {
return new Node ( this , this . start , this . startLoc ) ;
} ;
pp . startNodeAt = function ( pos , loc ) {
return new Node ( this , pos , loc ) ;
} ;
// Finish an AST node, adding `type` and `end` properties.
function finishNodeAt ( 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 ;
}
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 ) {
return finishNodeAt . call ( this , node , type , pos , loc ) ;
} ;
} , { "./locutil" : 5 , "./state" : 10 } ] , 8 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
exports . _ _esModule = true ;
exports . getOptions = getOptions ;
var _util = _dereq _ ( "./util" ) ;
var _locutil = _dereq _ ( "./locutil" ) ;
// A second optional argument can be given to further configure
// the parser process. These options are recognized:
var defaultOptions = {
// `ecmaVersion` indicates the ECMAScript version to parse. Must
// be either 3, or 5, or 6. This influences support for strict
// mode, the set of reserved words, support for getters and
// setters and other features.
ecmaVersion : 5 ,
// Source type ("script" or "module") for different semantics
sourceType : "script" ,
// `onInsertedSemicolon` can be a callback that will be called
// when a semicolon is automatically inserted. It will be passed
// th position of the comma as an offset, and if `locations` is
// enabled, it is given the location as a `{line, column}` object
// as second argument.
onInsertedSemicolon : null ,
// `onTrailingComma` is similar to `onInsertedSemicolon`, but for
// trailing commas.
onTrailingComma : null ,
// By default, reserved words are only enforced if ecmaVersion >= 5.
// Set `allowReserved` to a boolean value to explicitly turn this on
// an off. When this option has the value "never", reserved words
// and keywords can also not be used as property names.
allowReserved : null ,
// When enabled, a return at the top level is not considered an
// error.
allowReturnOutsideFunction : false ,
// When enabled, import/export statements are not constrained to
// appearing at the top of the program.
allowImportExportEverywhere : false ,
// When enabled, hashbang directive in the beginning of file
// is allowed and treated as a line comment.
allowHashBang : false ,
// When `locations` is on, `loc` properties holding objects with
// `start` and `end` properties in `{line, column}` form (with
// line being 1-based and column 0-based) will be attached to the
// nodes.
locations : false ,
// A function can be passed as `onToken` option, which will
// cause Acorn to call that function with object in the same
// format as tokens returned from `tokenizer().getToken()`. Note
// that you are not allowed to call the parser from the
// callback—that will corrupt its internal state.
onToken : null ,
// 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. Note that you are not allowed to call the
// parser from the callback—that will corrupt its internal state.
onComment : null ,
// Nodes have their start and end characters offsets recorded in
// `start` and `end` properties (directly on the node, rather than
// the `loc` object, which holds line/column data. To also add a
// [semi-standardized][range] `range` property holding a `[start,
// end]` array with the same numbers, set the `ranges` option to
// `true`.
2015-01-06 23:24:00 +03:00
//
2015-12-16 21:15:23 +03:00
// [range]: https://bugzilla.mozilla.org/show_bug.cgi?id=745678
ranges : false ,
// It is possible to parse multiple files into a single AST by
// passing the tree produced by parsing the first file as
// `program` option in subsequent parses. This will add the
// toplevel forms of the parsed file to the `Program` (top) node
// of an existing parse tree.
program : null ,
// When `locations` is on, you can pass this to record the source
// file in every node's `loc` object.
sourceFile : null ,
// This value, if given, is stored in every node, whether
// `locations` is on or off.
directSourceFile : null ,
// When enabled, parenthesized expressions are represented by
// (non-standard) ParenthesizedExpression nodes
preserveParens : false ,
plugins : { }
} ;
exports . defaultOptions = defaultOptions ;
// Interpret and default an options object
function getOptions ( opts ) {
var options = { } ;
for ( var opt in defaultOptions ) {
options [ opt ] = opts && _util . has ( opts , opt ) ? opts [ opt ] : defaultOptions [ opt ] ;
} if ( options . allowReserved == null ) options . allowReserved = options . ecmaVersion < 5 ;
if ( _util . isArray ( options . onToken ) ) {
( function ( ) {
var tokens = options . onToken ;
options . onToken = function ( token ) {
return tokens . push ( token ) ;
} ;
} ) ( ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
if ( _util . isArray ( options . onComment ) ) options . onComment = pushComment ( options , options . onComment ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
return options ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function pushComment ( options , array ) {
return function ( block , text , start , end , startLoc , endLoc ) {
var comment = {
type : block ? 'Block' : 'Line' ,
value : text ,
start : start ,
end : end
} ;
if ( options . locations ) comment . loc = new _locutil . SourceLocation ( this , startLoc , endLoc ) ;
if ( options . ranges ) comment . range = [ start , end ] ;
array . push ( comment ) ;
} ;
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./locutil" : 5 , "./util" : 15 } ] , 9 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _tokentype = _dereq _ ( "./tokentype" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _state = _dereq _ ( "./state" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _whitespace = _dereq _ ( "./whitespace" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var pp = _state . Parser . prototype ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// ## Parser utilities
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Test whether a statement node is the string literal `"use strict"`.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . isUseStrict = function ( stmt ) {
return this . options . ecmaVersion >= 5 && stmt . type === "ExpressionStatement" && stmt . expression . type === "Literal" && stmt . expression . raw . slice ( 1 , - 1 ) === "use strict" ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Predicate that tests whether the next token is of the given
// type, and if yes, consumes it as a side effect.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . eat = function ( type ) {
if ( this . type === type ) {
this . next ( ) ;
return true ;
} else {
return false ;
}
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Tests whether parsed token is a contextual keyword.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . isContextual = function ( name ) {
return this . type === _tokentype . types . name && this . value === name ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Consumes contextual keyword if possible.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . eatContextual = function ( name ) {
return this . value === name && this . eat ( _tokentype . types . name ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Asserts that following token is given contextual keyword.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . expectContextual = function ( name ) {
if ( ! this . eatContextual ( name ) ) this . unexpected ( ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Test whether a semicolon can be inserted at the current position.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . canInsertSemicolon = function ( ) {
return this . type === _tokentype . types . eof || this . type === _tokentype . types . braceR || _whitespace . lineBreak . test ( this . input . slice ( this . lastTokEnd , this . start ) ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . insertSemicolon = function ( ) {
if ( this . canInsertSemicolon ( ) ) {
if ( this . options . onInsertedSemicolon ) this . options . onInsertedSemicolon ( this . lastTokEnd , this . lastTokEndLoc ) ;
return true ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . semicolon = function ( ) {
if ( ! this . eat ( _tokentype . types . semi ) && ! this . insertSemicolon ( ) ) this . unexpected ( ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . afterTrailingComma = function ( tokType ) {
if ( this . type == tokType ) {
if ( this . options . onTrailingComma ) this . options . onTrailingComma ( this . lastTokStart , this . lastTokStartLoc ) ;
this . next ( ) ;
return true ;
}
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . expect = function ( type ) {
this . eat ( type ) || this . unexpected ( ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Raise an unexpected token error.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . unexpected = function ( pos ) {
this . raise ( pos != null ? pos : this . start , "Unexpected token" ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . checkPatternErrors = function ( refDestructuringErrors , andThrow ) {
var pos = refDestructuringErrors && refDestructuringErrors . trailingComma ;
if ( ! andThrow ) return ! ! pos ;
if ( pos ) this . raise ( pos , "Trailing comma is not permitted in destructuring patterns" ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . checkExpressionErrors = function ( refDestructuringErrors , andThrow ) {
var pos = refDestructuringErrors && refDestructuringErrors . shorthandAssign ;
if ( ! andThrow ) return ! ! pos ;
if ( pos ) this . raise ( pos , "Shorthand property assignments are valid only in destructuring patterns" ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./state" : 10 , "./tokentype" : 14 , "./whitespace" : 16 } ] , 10 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . _ _esModule = true ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _identifier = _dereq _ ( "./identifier" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _tokentype = _dereq _ ( "./tokentype" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _whitespace = _dereq _ ( "./whitespace" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _options = _dereq _ ( "./options" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Registered plugins
var plugins = { } ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . plugins = plugins ;
function keywordRegexp ( words ) {
return new RegExp ( "^(" + words . replace ( / /g , "|" ) + ")$" ) ;
}
var Parser = ( function ( ) {
function Parser ( options , input , startPos ) {
_classCallCheck ( this , Parser ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
this . options = options = _options . getOptions ( options ) ;
this . sourceFile = options . sourceFile ;
this . keywords = keywordRegexp ( _identifier . keywords [ options . ecmaVersion >= 6 ? 6 : 5 ] ) ;
var reserved = options . allowReserved ? "" : _identifier . reservedWords [ options . ecmaVersion ] + ( options . sourceType == "module" ? " await" : "" ) ;
this . reservedWords = keywordRegexp ( reserved ) ;
var reservedStrict = ( reserved ? reserved + " " : "" ) + _identifier . reservedWords . strict ;
this . reservedWordsStrict = keywordRegexp ( reservedStrict ) ;
this . reservedWordsStrictBind = keywordRegexp ( reservedStrict + " " + _identifier . reservedWords . strictBind ) ;
this . input = String ( input ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Used to signal to callers of `readWord1` whether the word
// contained any escape sequences. This is needed because words with
// escape sequences must not be interpreted as keywords.
this . containsEsc = false ;
// Load plugins
this . loadPlugins ( options . plugins ) ;
// Set up token state
// 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 ( _whitespace . lineBreak ) . length ;
2015-01-06 23:24:00 +03:00
} else {
2015-12-16 21:15:23 +03:00
this . pos = this . lineStart = 0 ;
this . curLine = 1 ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
// Properties of the current token:
// Its type
this . type = _tokentype . types . 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 ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Position information for the previous token
this . lastTokEndLoc = this . lastTokStartLoc = null ;
this . lastTokStart = this . lastTokEnd = this . pos ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// 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 ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Figure out if it's a module code.
this . strict = this . inModule = options . sourceType === "module" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Used to signify the start of a potential arrow function
this . potentialArrowAt = - 1 ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Flags to track whether we are in a function, a generator.
this . inFunction = this . inGenerator = false ;
// Labels in scope.
this . labels = [ ] ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// If enabled, skip leading hashbang line.
if ( this . pos === 0 && options . allowHashBang && this . input . slice ( 0 , 2 ) === '#!' ) this . skipLineComment ( 2 ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
// DEPRECATED Kept for backwards compatibility until 3.0 in case a plugin uses them
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
Parser . prototype . isKeyword = function isKeyword ( word ) {
return this . keywords . test ( word ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
Parser . prototype . isReservedWord = function isReservedWord ( word ) {
return this . reservedWords . test ( word ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
Parser . prototype . extend = function extend ( name , f ) {
this [ name ] = f ( this [ name ] ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
Parser . prototype . loadPlugins = function loadPlugins ( pluginConfigs ) {
for ( var _name in pluginConfigs ) {
var plugin = plugins [ _name ] ;
if ( ! plugin ) throw new Error ( "Plugin '" + _name + "' not found" ) ;
plugin ( this , pluginConfigs [ _name ] ) ;
}
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
Parser . prototype . parse = function parse ( ) {
var node = this . options . program || this . startNode ( ) ;
this . nextToken ( ) ;
return this . parseTopLevel ( node ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
return Parser ;
} ) ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . Parser = Parser ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./identifier" : 2 , "./options" : 8 , "./tokentype" : 14 , "./whitespace" : 16 } ] , 11 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _tokentype = _dereq _ ( "./tokentype" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _state = _dereq _ ( "./state" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var _whitespace = _dereq _ ( "./whitespace" ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var pp = _state . Parser . prototype ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// ### Statement parsing
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Parse a program. Initializes the parser, reads any number of
// statements, and wraps them in a Program node. Optionally takes a
// `program` argument. If present, the statements will be appended
// to its body instead of creating a new node.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . parseTopLevel = function ( node ) {
var first = true ;
if ( ! node . body ) node . body = [ ] ;
while ( this . type !== _tokentype . types . eof ) {
var stmt = this . parseStatement ( true , true ) ;
node . body . push ( stmt ) ;
if ( first ) {
if ( this . isUseStrict ( stmt ) ) this . setStrict ( true ) ;
first = false ;
2015-01-06 23:24:00 +03:00
}
}
2015-12-16 21:15:23 +03:00
this . next ( ) ;
if ( this . options . ecmaVersion >= 6 ) {
node . sourceType = this . options . sourceType ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
return this . finishNode ( node , "Program" ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
var loopLabel = { kind : "loop" } ,
switchLabel = { kind : "switch" } ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Parse a single statement.
//
// If expecting a statement and finding a slash operator, parse a
// regular expression literal. This is to handle cases like
// `if (foo) /blah/.exec(foo)`, where looking at the previous token
// does not help.
pp . parseStatement = function ( declaration , topLevel ) {
var starttype = this . type ,
node = this . startNode ( ) ;
// Most types of statements are recognized by the keyword they
// start with. Many are trivial to parse, some require a bit of
// complexity.
switch ( starttype ) {
case _tokentype . types . _break : case _tokentype . types . _continue :
return this . parseBreakContinueStatement ( node , starttype . keyword ) ;
case _tokentype . types . _debugger :
return this . parseDebuggerStatement ( node ) ;
case _tokentype . types . _do :
return this . parseDoStatement ( node ) ;
case _tokentype . types . _for :
return this . parseForStatement ( node ) ;
case _tokentype . types . _function :
if ( ! declaration && this . options . ecmaVersion >= 6 ) this . unexpected ( ) ;
return this . parseFunctionStatement ( node ) ;
case _tokentype . types . _class :
if ( ! declaration ) this . unexpected ( ) ;
return this . parseClass ( node , true ) ;
case _tokentype . types . _if :
return this . parseIfStatement ( node ) ;
case _tokentype . types . _return :
return this . parseReturnStatement ( node ) ;
case _tokentype . types . _switch :
return this . parseSwitchStatement ( node ) ;
case _tokentype . types . _throw :
return this . parseThrowStatement ( node ) ;
case _tokentype . types . _try :
return this . parseTryStatement ( node ) ;
case _tokentype . types . _let : case _tokentype . types . _const :
if ( ! declaration ) this . unexpected ( ) ; // NOTE: falls through to _var
case _tokentype . types . _var :
return this . parseVarStatement ( node , starttype ) ;
case _tokentype . types . _while :
return this . parseWhileStatement ( node ) ;
case _tokentype . types . _with :
return this . parseWithStatement ( node ) ;
case _tokentype . types . braceL :
return this . parseBlock ( ) ;
case _tokentype . types . semi :
return this . parseEmptyStatement ( node ) ;
case _tokentype . types . _export :
case _tokentype . types . _import :
if ( ! this . options . allowImportExportEverywhere ) {
if ( ! topLevel ) this . raise ( this . start , "'import' and 'export' may only appear at the top level" ) ;
if ( ! this . inModule ) this . raise ( this . start , "'import' and 'export' may appear only with 'sourceType: module'" ) ;
}
return starttype === _tokentype . types . _import ? this . parseImport ( node ) : this . parseExport ( node ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// If the statement does not start with a statement keyword or a
// brace, it's an ExpressionStatement or LabeledStatement. We
// simply start parsing an expression, and afterwards, if the
// next token is a colon and the expression was a simple
// Identifier node, we switch to interpreting it as a label.
default :
var maybeName = this . value ,
expr = this . parseExpression ( ) ;
if ( starttype === _tokentype . types . name && expr . type === "Identifier" && this . eat ( _tokentype . types . colon ) ) return this . parseLabeledStatement ( node , maybeName , expr ) ; else return this . parseExpressionStatement ( node , expr ) ;
}
} ;
pp . parseBreakContinueStatement = function ( node , keyword ) {
var isBreak = keyword == "break" ;
this . next ( ) ;
if ( this . eat ( _tokentype . types . semi ) || this . insertSemicolon ( ) ) node . label = null ; else if ( this . type !== _tokentype . types . name ) this . unexpected ( ) ; else {
node . label = this . parseIdent ( ) ;
this . semicolon ( ) ;
}
// Verify that there is an actual destination to break or
// continue to.
for ( var i = 0 ; i < this . labels . length ; ++ i ) {
var lab = this . labels [ i ] ;
if ( node . label == null || lab . name === node . label . name ) {
if ( lab . kind != null && ( isBreak || lab . kind === "loop" ) ) break ;
if ( node . label && isBreak ) break ;
}
}
if ( i === this . labels . length ) this . raise ( node . start , "Unsyntactic " + keyword ) ;
return this . finishNode ( node , isBreak ? "BreakStatement" : "ContinueStatement" ) ;
} ;
pp . parseDebuggerStatement = function ( node ) {
this . next ( ) ;
this . semicolon ( ) ;
return this . finishNode ( node , "DebuggerStatement" ) ;
} ;
pp . parseDoStatement = function ( node ) {
this . next ( ) ;
this . labels . push ( loopLabel ) ;
node . body = this . parseStatement ( false ) ;
this . labels . pop ( ) ;
this . expect ( _tokentype . types . _while ) ;
node . test = this . parseParenExpression ( ) ;
if ( this . options . ecmaVersion >= 6 ) this . eat ( _tokentype . types . semi ) ; else this . semicolon ( ) ;
return this . finishNode ( node , "DoWhileStatement" ) ;
} ;
// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
// loop is non-trivial. Basically, we have to parse the init `var`
// statement or expression, disallowing the `in` operator (see
// the second parameter to `parseExpression`), and then check
// whether the next token is `in` or `of`. When there is no init
// part (semicolon immediately after the opening parenthesis), it
// is a regular `for` loop.
pp . parseForStatement = function ( node ) {
this . next ( ) ;
this . labels . push ( loopLabel ) ;
this . expect ( _tokentype . types . parenL ) ;
if ( this . type === _tokentype . types . semi ) return this . parseFor ( node , null ) ;
if ( this . type === _tokentype . types . _var || this . type === _tokentype . types . _let || this . type === _tokentype . types . _const ) {
var _init = this . startNode ( ) ,
varKind = this . type ;
this . next ( ) ;
this . parseVar ( _init , true , varKind ) ;
this . finishNode ( _init , "VariableDeclaration" ) ;
if ( ( this . type === _tokentype . types . _in || this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) && _init . declarations . length === 1 && ! ( varKind !== _tokentype . types . _var && _init . declarations [ 0 ] . init ) ) return this . parseForIn ( node , _init ) ;
return this . parseFor ( node , _init ) ;
}
var refDestructuringErrors = { shorthandAssign : 0 , trailingComma : 0 } ;
var init = this . parseExpression ( true , refDestructuringErrors ) ;
if ( this . type === _tokentype . types . _in || this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) {
this . checkPatternErrors ( refDestructuringErrors , true ) ;
this . toAssignable ( init ) ;
this . checkLVal ( init ) ;
return this . parseForIn ( node , init ) ;
} else {
this . checkExpressionErrors ( refDestructuringErrors , true ) ;
}
return this . parseFor ( node , init ) ;
} ;
pp . parseFunctionStatement = function ( node ) {
this . next ( ) ;
return this . parseFunction ( node , true ) ;
} ;
pp . parseIfStatement = function ( node ) {
this . next ( ) ;
node . test = this . parseParenExpression ( ) ;
node . consequent = this . parseStatement ( false ) ;
node . alternate = this . eat ( _tokentype . types . _else ) ? this . parseStatement ( false ) : null ;
return this . finishNode ( node , "IfStatement" ) ;
} ;
pp . parseReturnStatement = function ( node ) {
if ( ! this . inFunction && ! this . options . allowReturnOutsideFunction ) this . raise ( this . start , "'return' outside of function" ) ;
this . next ( ) ;
// In `return` (and `break`/`continue`), the keywords with
// optional arguments, we eagerly look for a semicolon or the
// possibility to insert one.
if ( this . eat ( _tokentype . types . semi ) || this . insertSemicolon ( ) ) node . argument = null ; else {
node . argument = this . parseExpression ( ) ; this . semicolon ( ) ;
}
return this . finishNode ( node , "ReturnStatement" ) ;
} ;
pp . parseSwitchStatement = function ( node ) {
this . next ( ) ;
node . discriminant = this . parseParenExpression ( ) ;
node . cases = [ ] ;
this . expect ( _tokentype . types . braceL ) ;
this . labels . push ( switchLabel ) ;
// Statements under must be grouped (by label) in SwitchCase
// nodes. `cur` is used to keep the node that we are currently
// adding statements to.
for ( var cur , sawDefault = false ; this . type != _tokentype . types . braceR ; ) {
if ( this . type === _tokentype . types . _case || this . type === _tokentype . types . _default ) {
var isCase = this . type === _tokentype . types . _case ;
if ( cur ) this . finishNode ( cur , "SwitchCase" ) ;
node . cases . push ( cur = this . startNode ( ) ) ;
cur . consequent = [ ] ;
this . next ( ) ;
if ( isCase ) {
cur . test = this . parseExpression ( ) ;
} else {
if ( sawDefault ) this . raise ( this . lastTokStart , "Multiple default clauses" ) ;
sawDefault = true ;
cur . test = null ;
}
this . expect ( _tokentype . types . colon ) ;
} else {
if ( ! cur ) this . unexpected ( ) ;
cur . consequent . push ( this . parseStatement ( true ) ) ;
}
}
if ( cur ) this . finishNode ( cur , "SwitchCase" ) ;
this . next ( ) ; // Closing brace
this . labels . pop ( ) ;
return this . finishNode ( node , "SwitchStatement" ) ;
} ;
pp . parseThrowStatement = function ( node ) {
this . next ( ) ;
if ( _whitespace . lineBreak . test ( this . input . slice ( this . lastTokEnd , this . start ) ) ) this . raise ( this . lastTokEnd , "Illegal newline after throw" ) ;
node . argument = this . parseExpression ( ) ;
this . semicolon ( ) ;
return this . finishNode ( node , "ThrowStatement" ) ;
} ;
// Reused empty array added for node fields that are always empty.
var empty = [ ] ;
pp . parseTryStatement = function ( node ) {
this . next ( ) ;
node . block = this . parseBlock ( ) ;
node . handler = null ;
if ( this . type === _tokentype . types . _catch ) {
var clause = this . startNode ( ) ;
this . next ( ) ;
this . expect ( _tokentype . types . parenL ) ;
clause . param = this . parseBindingAtom ( ) ;
this . checkLVal ( clause . param , true ) ;
this . expect ( _tokentype . types . parenR ) ;
clause . body = this . parseBlock ( ) ;
node . handler = this . finishNode ( clause , "CatchClause" ) ;
}
node . finalizer = this . eat ( _tokentype . types . _finally ) ? this . parseBlock ( ) : null ;
if ( ! node . handler && ! node . finalizer ) this . raise ( node . start , "Missing catch or finally clause" ) ;
return this . finishNode ( node , "TryStatement" ) ;
} ;
pp . parseVarStatement = function ( node , kind ) {
this . next ( ) ;
this . parseVar ( node , false , kind ) ;
this . semicolon ( ) ;
return this . finishNode ( node , "VariableDeclaration" ) ;
} ;
pp . parseWhileStatement = function ( node ) {
this . next ( ) ;
node . test = this . parseParenExpression ( ) ;
this . labels . push ( loopLabel ) ;
node . body = this . parseStatement ( false ) ;
this . labels . pop ( ) ;
return this . finishNode ( node , "WhileStatement" ) ;
} ;
pp . parseWithStatement = function ( node ) {
if ( this . strict ) this . raise ( this . start , "'with' in strict mode" ) ;
this . next ( ) ;
node . object = this . parseParenExpression ( ) ;
node . body = this . parseStatement ( false ) ;
return this . finishNode ( node , "WithStatement" ) ;
} ;
pp . parseEmptyStatement = function ( node ) {
this . next ( ) ;
return this . finishNode ( node , "EmptyStatement" ) ;
} ;
pp . parseLabeledStatement = function ( node , maybeName , expr ) {
for ( var i = 0 ; i < this . labels . length ; ++ i ) {
if ( this . labels [ i ] . name === maybeName ) this . raise ( expr . start , "Label '" + maybeName + "' is already declared" ) ;
} var kind = this . type . isLoop ? "loop" : this . type === _tokentype . types . _switch ? "switch" : null ;
for ( var i = this . labels . length - 1 ; i >= 0 ; i -- ) {
var label = this . labels [ i ] ;
if ( label . statementStart == node . start ) {
label . statementStart = this . start ;
label . kind = kind ;
} else break ;
}
this . labels . push ( { name : maybeName , kind : kind , statementStart : this . start } ) ;
node . body = this . parseStatement ( true ) ;
this . labels . pop ( ) ;
node . label = expr ;
return this . finishNode ( node , "LabeledStatement" ) ;
} ;
pp . parseExpressionStatement = function ( node , expr ) {
node . expression = expr ;
this . semicolon ( ) ;
return this . finishNode ( node , "ExpressionStatement" ) ;
} ;
// Parse a semicolon-enclosed block of statements, handling `"use
// strict"` declarations when `allowStrict` is true (used for
// function bodies).
pp . parseBlock = function ( allowStrict ) {
var node = this . startNode ( ) ,
first = true ,
oldStrict = undefined ;
node . body = [ ] ;
this . expect ( _tokentype . types . braceL ) ;
while ( ! this . eat ( _tokentype . types . braceR ) ) {
var stmt = this . parseStatement ( true ) ;
node . body . push ( stmt ) ;
if ( first && allowStrict && this . isUseStrict ( stmt ) ) {
oldStrict = this . strict ;
this . setStrict ( this . strict = true ) ;
}
first = false ;
}
if ( oldStrict === false ) this . setStrict ( false ) ;
return this . finishNode ( node , "BlockStatement" ) ;
} ;
// Parse a regular `for` loop. The disambiguation code in
// `parseStatement` will already have parsed the init statement or
// expression.
pp . parseFor = function ( node , init ) {
node . init = init ;
this . expect ( _tokentype . types . semi ) ;
node . test = this . type === _tokentype . types . semi ? null : this . parseExpression ( ) ;
this . expect ( _tokentype . types . semi ) ;
node . update = this . type === _tokentype . types . parenR ? null : this . parseExpression ( ) ;
this . expect ( _tokentype . types . parenR ) ;
node . body = this . parseStatement ( false ) ;
this . labels . pop ( ) ;
return this . finishNode ( node , "ForStatement" ) ;
} ;
// Parse a `for`/`in` and `for`/`of` loop, which are almost
// same from parser's perspective.
pp . parseForIn = function ( node , init ) {
var type = this . type === _tokentype . types . _in ? "ForInStatement" : "ForOfStatement" ;
this . next ( ) ;
node . left = init ;
node . right = this . parseExpression ( ) ;
this . expect ( _tokentype . types . parenR ) ;
node . body = this . parseStatement ( false ) ;
this . labels . pop ( ) ;
return this . finishNode ( node , type ) ;
} ;
// Parse a list of variable declarations.
pp . parseVar = function ( node , isFor , kind ) {
node . declarations = [ ] ;
node . kind = kind . keyword ;
for ( ; ; ) {
var decl = this . startNode ( ) ;
this . parseVarId ( decl ) ;
if ( this . eat ( _tokentype . types . eq ) ) {
decl . init = this . parseMaybeAssign ( isFor ) ;
} else if ( kind === _tokentype . types . _const && ! ( this . type === _tokentype . types . _in || this . options . ecmaVersion >= 6 && this . isContextual ( "of" ) ) ) {
this . unexpected ( ) ;
} else if ( decl . id . type != "Identifier" && ! ( isFor && ( this . type === _tokentype . types . _in || this . isContextual ( "of" ) ) ) ) {
this . raise ( this . lastTokEnd , "Complex binding patterns require an initialization value" ) ;
2015-01-06 23:24:00 +03:00
} else {
2015-12-16 21:15:23 +03:00
decl . init = null ;
}
node . declarations . push ( this . finishNode ( decl , "VariableDeclarator" ) ) ;
if ( ! this . eat ( _tokentype . types . comma ) ) break ;
}
return node ;
} ;
pp . parseVarId = function ( decl ) {
decl . id = this . parseBindingAtom ( ) ;
this . checkLVal ( decl . id , true ) ;
} ;
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
pp . parseFunction = function ( node , isStatement , allowExpressionBody ) {
this . initFunction ( node ) ;
if ( this . options . ecmaVersion >= 6 ) node . generator = this . eat ( _tokentype . types . star ) ;
if ( isStatement || this . type === _tokentype . types . name ) node . id = this . parseIdent ( ) ;
this . parseFunctionParams ( node ) ;
this . parseFunctionBody ( node , allowExpressionBody ) ;
return this . finishNode ( node , isStatement ? "FunctionDeclaration" : "FunctionExpression" ) ;
} ;
pp . parseFunctionParams = function ( node ) {
this . expect ( _tokentype . types . parenL ) ;
node . params = this . parseBindingList ( _tokentype . types . parenR , false , false , true ) ;
} ;
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
pp . parseClass = function ( node , isStatement ) {
this . next ( ) ;
this . parseClassId ( node , isStatement ) ;
this . parseClassSuper ( node ) ;
var classBody = this . startNode ( ) ;
var hadConstructor = false ;
classBody . body = [ ] ;
this . expect ( _tokentype . types . braceL ) ;
while ( ! this . eat ( _tokentype . types . braceR ) ) {
if ( this . eat ( _tokentype . types . semi ) ) continue ;
var method = this . startNode ( ) ;
var isGenerator = this . eat ( _tokentype . types . star ) ;
var isMaybeStatic = this . type === _tokentype . types . name && this . value === "static" ;
this . parsePropertyName ( method ) ;
method [ "static" ] = isMaybeStatic && this . type !== _tokentype . types . parenL ;
if ( method [ "static" ] ) {
if ( isGenerator ) this . unexpected ( ) ;
isGenerator = this . eat ( _tokentype . types . star ) ;
this . parsePropertyName ( method ) ;
}
method . kind = "method" ;
var isGetSet = false ;
if ( ! method . computed ) {
var key = method . key ;
if ( ! isGenerator && key . type === "Identifier" && this . type !== _tokentype . types . parenL && ( key . name === "get" || key . name === "set" ) ) {
isGetSet = true ;
method . kind = key . name ;
key = this . parsePropertyName ( method ) ;
}
if ( ! method [ "static" ] && ( key . type === "Identifier" && key . name === "constructor" || key . type === "Literal" && key . value === "constructor" ) ) {
if ( hadConstructor ) this . raise ( key . start , "Duplicate constructor in the same class" ) ;
if ( isGetSet ) this . raise ( key . start , "Constructor can't have get/set modifier" ) ;
if ( isGenerator ) this . raise ( key . start , "Constructor can't be a generator" ) ;
method . kind = "constructor" ;
hadConstructor = true ;
}
}
this . parseClassMethod ( classBody , method , isGenerator ) ;
if ( isGetSet ) {
var paramCount = method . kind === "get" ? 0 : 1 ;
if ( method . value . params . length !== paramCount ) {
var start = method . value . start ;
if ( method . kind === "get" ) this . raise ( start , "getter should have no params" ) ; else this . raise ( start , "setter should have exactly one param" ) ;
}
2015-01-06 23:24:00 +03:00
}
}
2015-12-16 21:15:23 +03:00
node . body = this . finishNode ( classBody , "ClassBody" ) ;
return this . finishNode ( node , isStatement ? "ClassDeclaration" : "ClassExpression" ) ;
} ;
pp . parseClassMethod = function ( classBody , method , isGenerator ) {
method . value = this . parseMethod ( isGenerator ) ;
classBody . body . push ( this . finishNode ( method , "MethodDefinition" ) ) ;
} ;
pp . parseClassId = function ( node , isStatement ) {
node . id = this . type === _tokentype . types . name ? this . parseIdent ( ) : isStatement ? this . unexpected ( ) : null ;
} ;
pp . parseClassSuper = function ( node ) {
node . superClass = this . eat ( _tokentype . types . _extends ) ? this . parseExprSubscripts ( ) : null ;
} ;
// Parses module export declaration.
pp . parseExport = function ( node ) {
this . next ( ) ;
// export * from '...'
if ( this . eat ( _tokentype . types . star ) ) {
this . expectContextual ( "from" ) ;
node . source = this . type === _tokentype . types . string ? this . parseExprAtom ( ) : this . unexpected ( ) ;
this . semicolon ( ) ;
return this . finishNode ( node , "ExportAllDeclaration" ) ;
}
if ( this . eat ( _tokentype . types . _default ) ) {
// export default ...
var expr = this . parseMaybeAssign ( ) ;
var needsSemi = true ;
if ( expr . type == "FunctionExpression" || expr . type == "ClassExpression" ) {
needsSemi = false ;
if ( expr . id ) {
expr . type = expr . type == "FunctionExpression" ? "FunctionDeclaration" : "ClassDeclaration" ;
}
}
node . declaration = expr ;
if ( needsSemi ) this . semicolon ( ) ;
return this . finishNode ( node , "ExportDefaultDeclaration" ) ;
}
// export var|const|let|function|class ...
if ( this . shouldParseExportStatement ( ) ) {
node . declaration = this . parseStatement ( true ) ;
node . specifiers = [ ] ;
node . source = null ;
} else {
// export { x, y as z } [from '...']
node . declaration = null ;
node . specifiers = this . parseExportSpecifiers ( ) ;
if ( this . eatContextual ( "from" ) ) {
node . source = this . type === _tokentype . types . string ? this . parseExprAtom ( ) : this . unexpected ( ) ;
} else {
// check for keywords used as local names
for ( var i = 0 ; i < node . specifiers . length ; i ++ ) {
if ( this . keywords . test ( node . specifiers [ i ] . local . name ) || this . reservedWords . test ( node . specifiers [ i ] . local . name ) ) {
this . unexpected ( node . specifiers [ i ] . local . start ) ;
}
}
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
node . source = null ;
}
this . semicolon ( ) ;
}
return this . finishNode ( node , "ExportNamedDeclaration" ) ;
} ;
pp . shouldParseExportStatement = function ( ) {
return this . type . keyword ;
} ;
// Parses a comma-separated list of module exports.
pp . parseExportSpecifiers = function ( ) {
var nodes = [ ] ,
first = true ;
// export { x, y as z } [from '...']
this . expect ( _tokentype . types . braceL ) ;
while ( ! this . eat ( _tokentype . types . braceR ) ) {
if ( ! first ) {
this . expect ( _tokentype . types . comma ) ;
if ( this . afterTrailingComma ( _tokentype . types . braceR ) ) break ;
} else first = false ;
var node = this . startNode ( ) ;
node . local = this . parseIdent ( this . type === _tokentype . types . _default ) ;
node . exported = this . eatContextual ( "as" ) ? this . parseIdent ( true ) : node . local ;
nodes . push ( this . finishNode ( node , "ExportSpecifier" ) ) ;
}
return nodes ;
} ;
// Parses import declaration.
pp . parseImport = function ( node ) {
this . next ( ) ;
// import '...'
if ( this . type === _tokentype . types . string ) {
node . specifiers = empty ;
node . source = this . parseExprAtom ( ) ;
} else {
node . specifiers = this . parseImportSpecifiers ( ) ;
this . expectContextual ( "from" ) ;
node . source = this . type === _tokentype . types . string ? this . parseExprAtom ( ) : this . unexpected ( ) ;
}
this . semicolon ( ) ;
return this . finishNode ( node , "ImportDeclaration" ) ;
} ;
// Parses a comma-separated list of module imports.
pp . parseImportSpecifiers = function ( ) {
var nodes = [ ] ,
first = true ;
if ( this . type === _tokentype . types . name ) {
// import defaultObj, { x, y as z } from '...'
var node = this . startNode ( ) ;
node . local = this . parseIdent ( ) ;
this . checkLVal ( node . local , true ) ;
nodes . push ( this . finishNode ( node , "ImportDefaultSpecifier" ) ) ;
if ( ! this . eat ( _tokentype . types . comma ) ) return nodes ;
}
if ( this . type === _tokentype . types . star ) {
var node = this . startNode ( ) ;
this . next ( ) ;
this . expectContextual ( "as" ) ;
node . local = this . parseIdent ( ) ;
this . checkLVal ( node . local , true ) ;
nodes . push ( this . finishNode ( node , "ImportNamespaceSpecifier" ) ) ;
return nodes ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
this . expect ( _tokentype . types . braceL ) ;
while ( ! this . eat ( _tokentype . types . braceR ) ) {
if ( ! first ) {
this . expect ( _tokentype . types . comma ) ;
if ( this . afterTrailingComma ( _tokentype . types . braceR ) ) break ;
} else first = false ;
var node = this . startNode ( ) ;
node . imported = this . parseIdent ( true ) ;
node . local = this . eatContextual ( "as" ) ? this . parseIdent ( ) : node . imported ;
this . checkLVal ( node . local , true ) ;
nodes . push ( this . finishNode ( node , "ImportSpecifier" ) ) ;
}
return nodes ;
} ;
} , { "./state" : 10 , "./tokentype" : 14 , "./whitespace" : 16 } ] , 12 : [ function ( _dereq _ , module , exports ) {
// The algorithm used to determine whether a regexp can appear at a
// given point in the program is loosely based on sweet.js' approach.
// See https://github.com/mozilla/sweet.js/wiki/design
"use strict" ;
exports . _ _esModule = true ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
var _state = _dereq _ ( "./state" ) ;
var _tokentype = _dereq _ ( "./tokentype" ) ;
var _whitespace = _dereq _ ( "./whitespace" ) ;
var TokContext = function TokContext ( token , isExpr , preserveSpace , override ) {
_classCallCheck ( this , TokContext ) ;
this . token = token ;
this . isExpr = ! ! isExpr ;
this . preserveSpace = ! ! preserveSpace ;
this . override = override ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . TokContext = TokContext ;
var types = {
b _stat : new TokContext ( "{" , false ) ,
b _expr : new TokContext ( "{" , true ) ,
b _tmpl : new TokContext ( "${" , true ) ,
p _stat : new TokContext ( "(" , false ) ,
p _expr : new TokContext ( "(" , true ) ,
q _tmpl : new TokContext ( "`" , true , true , function ( p ) {
return p . readTmplToken ( ) ;
} ) ,
f _expr : new TokContext ( "function" , true )
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
exports . types = types ;
var pp = _state . Parser . prototype ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . initialContext = function ( ) {
return [ types . b _stat ] ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . braceIsBlock = function ( prevType ) {
if ( prevType === _tokentype . types . colon ) {
var _parent = this . curContext ( ) ;
if ( _parent === types . b _stat || _parent === types . b _expr ) return ! _parent . isExpr ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
if ( prevType === _tokentype . types . _return ) return _whitespace . lineBreak . test ( this . input . slice ( this . lastTokEnd , this . start ) ) ;
if ( prevType === _tokentype . types . _else || prevType === _tokentype . types . semi || prevType === _tokentype . types . eof || prevType === _tokentype . types . parenR ) return true ;
if ( prevType == _tokentype . types . braceL ) return this . curContext ( ) === types . b _stat ;
return ! this . exprAllowed ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . updateContext = function ( prevType ) {
var update = undefined ,
type = this . type ;
if ( type . keyword && prevType == _tokentype . types . dot ) this . exprAllowed = false ; else if ( update = type . updateContext ) update . call ( this , prevType ) ; else this . exprAllowed = type . beforeExpr ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Token-specific context update code
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_tokentype . types . parenR . updateContext = _tokentype . types . braceR . updateContext = function ( ) {
if ( this . context . length == 1 ) {
this . exprAllowed = true ;
return ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
var out = this . context . pop ( ) ;
if ( out === types . b _stat && this . curContext ( ) === types . f _expr ) {
this . context . pop ( ) ;
this . exprAllowed = false ;
} else if ( out === types . b _tmpl ) {
this . exprAllowed = true ;
} else {
this . exprAllowed = ! out . isExpr ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_tokentype . types . braceL . updateContext = function ( prevType ) {
this . context . push ( this . braceIsBlock ( prevType ) ? types . b _stat : types . b _expr ) ;
this . exprAllowed = true ;
} ;
_tokentype . types . dollarBraceL . updateContext = function ( ) {
this . context . push ( types . b _tmpl ) ;
this . exprAllowed = true ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_tokentype . types . parenL . updateContext = function ( prevType ) {
var statementParens = prevType === _tokentype . types . _if || prevType === _tokentype . types . _for || prevType === _tokentype . types . _with || prevType === _tokentype . types . _while ;
this . context . push ( statementParens ? types . p _stat : types . p _expr ) ;
this . exprAllowed = true ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_tokentype . types . incDec . updateContext = function ( ) {
// tokExprAllowed stays unchanged
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_tokentype . types . _function . updateContext = function ( ) {
if ( this . curContext ( ) !== types . b _stat ) this . context . push ( types . f _expr ) ;
this . exprAllowed = false ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
_tokentype . types . backQuote . updateContext = function ( ) {
if ( this . curContext ( ) === types . q _tmpl ) this . context . pop ( ) ; else this . context . push ( types . q _tmpl ) ;
this . exprAllowed = false ;
} ;
} , { "./state" : 10 , "./tokentype" : 14 , "./whitespace" : 16 } ] , 13 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
exports . _ _esModule = true ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
var _identifier = _dereq _ ( "./identifier" ) ;
var _tokentype = _dereq _ ( "./tokentype" ) ;
var _state = _dereq _ ( "./state" ) ;
var _locutil = _dereq _ ( "./locutil" ) ;
var _whitespace = _dereq _ ( "./whitespace" ) ;
// Object type used to represent tokens. Note that normally, tokens
// simply exist as properties on the parser object. This is only
// used for the onToken callback and the external tokenizer.
var Token = function Token ( p ) {
_classCallCheck ( this , Token ) ;
this . type = p . type ;
this . value = p . value ;
this . start = p . start ;
this . end = p . end ;
if ( p . options . locations ) this . loc = new _locutil . SourceLocation ( p , p . startLoc , p . endLoc ) ;
if ( p . options . ranges ) this . range = [ p . start , p . end ] ;
}
// ## Tokenizer
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
;
exports . Token = Token ;
var pp = _state . Parser . prototype ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Are we running under Rhino?
var isRhino = typeof Packages == "object" && Object . prototype . toString . call ( Packages ) == "[object JavaPackage]" ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Move to the next token
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . next = function ( ) {
if ( this . options . onToken ) this . options . onToken ( new Token ( this ) ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
this . lastTokEnd = this . end ;
this . lastTokStart = this . start ;
this . lastTokEndLoc = this . endLoc ;
this . lastTokStartLoc = this . startLoc ;
this . nextToken ( ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . getToken = function ( ) {
this . next ( ) ;
return new Token ( this ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// If we're in an ES6 environment, make parsers iterable
if ( typeof Symbol !== "undefined" ) pp [ Symbol . iterator ] = function ( ) {
var self = this ;
return { next : function next ( ) {
var token = self . getToken ( ) ;
return {
done : token . type === _tokentype . types . eof ,
value : token
} ;
} } ;
} ;
// Toggle strict mode. Re-reads the next number or string to please
// pedantic tests (`"use strict"; 010;` should fail).
pp . setStrict = function ( strict ) {
this . strict = strict ;
if ( this . type !== _tokentype . types . num && this . type !== _tokentype . types . string ) return ;
this . pos = this . start ;
if ( this . options . locations ) {
while ( this . pos < this . lineStart ) {
this . lineStart = this . input . lastIndexOf ( "\n" , this . lineStart - 2 ) + 1 ;
-- this . curLine ;
}
}
this . nextToken ( ) ;
} ;
pp . curContext = function ( ) {
return this . context [ this . context . length - 1 ] ;
} ;
// Read a single token, updating the parser object's token-related
// properties.
pp . nextToken = function ( ) {
var curContext = this . curContext ( ) ;
if ( ! curContext || ! curContext . preserveSpace ) this . skipSpace ( ) ;
this . start = this . pos ;
if ( this . options . locations ) this . startLoc = this . curPosition ( ) ;
if ( this . pos >= this . input . length ) return this . finishToken ( _tokentype . types . eof ) ;
if ( curContext . override ) return curContext . override ( this ) ; else this . readToken ( this . fullCharCodeAtPos ( ) ) ;
} ;
pp . readToken = function ( code ) {
// Identifier or keyword. '\uXXXX' sequences are allowed in
// identifiers, so '\' also dispatches to that.
if ( _identifier . isIdentifierStart ( code , this . options . ecmaVersion >= 6 ) || code === 92 /* '\' */ ) return this . readWord ( ) ;
return this . getTokenFromCode ( code ) ;
} ;
pp . fullCharCodeAtPos = function ( ) {
var code = this . input . charCodeAt ( this . pos ) ;
if ( code <= 0xd7ff || code >= 0xe000 ) return code ;
var next = this . input . charCodeAt ( this . pos + 1 ) ;
return ( code << 10 ) + next - 0x35fdc00 ;
} ;
pp . skipBlockComment = function ( ) {
var startLoc = this . options . onComment && this . curPosition ( ) ;
var start = this . pos ,
end = this . input . indexOf ( "*/" , this . pos += 2 ) ;
if ( end === - 1 ) this . raise ( this . pos - 2 , "Unterminated comment" ) ;
this . pos = end + 2 ;
if ( this . options . locations ) {
_whitespace . lineBreakG . lastIndex = start ;
var match = undefined ;
while ( ( match = _whitespace . lineBreakG . exec ( this . input ) ) && match . index < this . pos ) {
++ this . curLine ;
this . lineStart = match . index + match [ 0 ] . length ;
}
}
if ( this . options . onComment ) this . options . onComment ( true , this . input . slice ( start + 2 , end ) , start , this . pos , startLoc , this . curPosition ( ) ) ;
} ;
pp . skipLineComment = function ( startSkip ) {
var start = this . pos ;
var startLoc = this . options . onComment && this . curPosition ( ) ;
var ch = this . input . charCodeAt ( this . pos += startSkip ) ;
while ( this . pos < this . input . length && ch !== 10 && ch !== 13 && ch !== 8232 && ch !== 8233 ) {
++ this . pos ;
ch = this . input . charCodeAt ( this . pos ) ;
}
if ( this . options . onComment ) this . options . onComment ( false , this . input . slice ( start + startSkip , this . pos ) , start , this . pos , startLoc , this . curPosition ( ) ) ;
} ;
// Called at the start of the parse and after every token. Skips
// whitespace and comments, and.
pp . skipSpace = function ( ) {
loop : while ( this . pos < this . input . length ) {
var ch = this . input . charCodeAt ( this . pos ) ;
switch ( ch ) {
case 32 : case 160 :
// ' '
++ this . pos ;
2015-01-06 23:24:00 +03:00
break ;
2015-12-16 21:15:23 +03:00
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 ;
2015-01-06 23:24:00 +03:00
}
break ;
2015-12-16 21:15:23 +03:00
case 47 :
// '/'
switch ( this . input . charCodeAt ( this . pos + 1 ) ) {
case 42 :
// '*'
this . skipBlockComment ( ) ;
break ;
case 47 :
this . skipLineComment ( 2 ) ;
break ;
default :
break loop ;
}
2015-01-06 23:24:00 +03:00
break ;
default :
2015-12-16 21:15:23 +03:00
if ( ch > 8 && ch < 14 || ch >= 5760 && _whitespace . nonASCIIwhitespace . test ( String . fromCharCode ( ch ) ) ) {
++ this . pos ;
} else {
break loop ;
2015-01-06 23:24:00 +03:00
}
}
}
2015-12-16 21:15:23 +03:00
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Called at the end of every token. Sets `end`, `val`, and
// maintains `context` and `exprAllowed`, and skips the space after
// the token, so that the next one's `start` will point at the
// right position.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . finishToken = function ( type , val ) {
this . end = this . pos ;
if ( this . options . locations ) this . endLoc = this . curPosition ( ) ;
var prevType = this . type ;
this . type = type ;
this . value = val ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
this . updateContext ( prevType ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// ### Token reading
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// This is the function that is called to fetch the next token. It
// is somewhat obscure, because it works in character codes rather
// than characters, and because operator parsing has been inlined
// into it.
//
// All in the name of speed.
//
pp . readToken _dot = function ( ) {
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next >= 48 && next <= 57 ) return this . readNumber ( true ) ;
var next2 = this . input . charCodeAt ( this . pos + 2 ) ;
if ( this . options . ecmaVersion >= 6 && next === 46 && next2 === 46 ) {
// 46 = dot '.'
this . pos += 3 ;
return this . finishToken ( _tokentype . types . ellipsis ) ;
} else {
++ this . pos ;
return this . finishToken ( _tokentype . types . dot ) ;
}
} ;
pp . readToken _slash = function ( ) {
// '/'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( this . exprAllowed ) {
++ this . pos ; return this . readRegexp ( ) ;
}
if ( next === 61 ) return this . finishOp ( _tokentype . types . assign , 2 ) ;
return this . finishOp ( _tokentype . types . slash , 1 ) ;
} ;
pp . readToken _mult _modulo = function ( code ) {
// '%*'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next === 61 ) return this . finishOp ( _tokentype . types . assign , 2 ) ;
return this . finishOp ( code === 42 ? _tokentype . types . star : _tokentype . types . modulo , 1 ) ;
} ;
pp . readToken _pipe _amp = function ( code ) {
// '|&'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next === code ) return this . finishOp ( code === 124 ? _tokentype . types . logicalOR : _tokentype . types . logicalAND , 2 ) ;
if ( next === 61 ) return this . finishOp ( _tokentype . types . assign , 2 ) ;
return this . finishOp ( code === 124 ? _tokentype . types . bitwiseOR : _tokentype . types . bitwiseAND , 1 ) ;
} ;
pp . readToken _caret = function ( ) {
// '^'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next === 61 ) return this . finishOp ( _tokentype . types . assign , 2 ) ;
return this . finishOp ( _tokentype . types . bitwiseXOR , 1 ) ;
} ;
pp . readToken _plus _min = function ( code ) {
// '+-'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next === code ) {
if ( next == 45 && this . input . charCodeAt ( this . pos + 2 ) == 62 && _whitespace . lineBreak . test ( this . input . slice ( this . lastTokEnd , this . pos ) ) ) {
// A `-->` line comment
this . skipLineComment ( 3 ) ;
this . skipSpace ( ) ;
return this . nextToken ( ) ;
}
return this . finishOp ( _tokentype . types . incDec , 2 ) ;
}
if ( next === 61 ) return this . finishOp ( _tokentype . types . assign , 2 ) ;
return this . finishOp ( _tokentype . types . plusMin , 1 ) ;
} ;
pp . readToken _lt _gt = function ( code ) {
// '<>'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
var size = 1 ;
if ( next === code ) {
size = code === 62 && this . input . charCodeAt ( this . pos + 2 ) === 62 ? 3 : 2 ;
if ( this . input . charCodeAt ( this . pos + size ) === 61 ) return this . finishOp ( _tokentype . types . assign , size + 1 ) ;
return this . finishOp ( _tokentype . types . bitShift , size ) ;
}
if ( next == 33 && code == 60 && this . input . charCodeAt ( this . pos + 2 ) == 45 && this . input . charCodeAt ( this . pos + 3 ) == 45 ) {
if ( this . inModule ) this . unexpected ( ) ;
// `<!--`, an XML-style comment that should be interpreted as a line comment
this . skipLineComment ( 4 ) ;
this . skipSpace ( ) ;
return this . nextToken ( ) ;
}
if ( next === 61 ) size = this . input . charCodeAt ( this . pos + 2 ) === 61 ? 3 : 2 ;
return this . finishOp ( _tokentype . types . relational , size ) ;
} ;
pp . readToken _eq _excl = function ( code ) {
// '=!'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next === 61 ) return this . finishOp ( _tokentype . types . equality , this . input . charCodeAt ( this . pos + 2 ) === 61 ? 3 : 2 ) ;
if ( code === 61 && next === 62 && this . options . ecmaVersion >= 6 ) {
// '=>'
this . pos += 2 ;
return this . finishToken ( _tokentype . types . arrow ) ;
}
return this . finishOp ( code === 61 ? _tokentype . types . eq : _tokentype . types . prefix , 1 ) ;
} ;
pp . getTokenFromCode = function ( code ) {
switch ( code ) {
// The interpretation of a dot depends on whether it is followed
// by a digit or another two dots.
case 46 :
// '.'
return this . readToken _dot ( ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Punctuation tokens.
case 40 :
++ this . pos ; return this . finishToken ( _tokentype . types . parenL ) ;
case 41 :
++ this . pos ; return this . finishToken ( _tokentype . types . parenR ) ;
case 59 :
++ this . pos ; return this . finishToken ( _tokentype . types . semi ) ;
case 44 :
++ this . pos ; return this . finishToken ( _tokentype . types . comma ) ;
case 91 :
++ this . pos ; return this . finishToken ( _tokentype . types . bracketL ) ;
case 93 :
++ this . pos ; return this . finishToken ( _tokentype . types . bracketR ) ;
case 123 :
++ this . pos ; return this . finishToken ( _tokentype . types . braceL ) ;
case 125 :
++ this . pos ; return this . finishToken ( _tokentype . types . braceR ) ;
case 58 :
++ this . pos ; return this . finishToken ( _tokentype . types . colon ) ;
case 63 :
++ this . pos ; return this . finishToken ( _tokentype . types . question ) ;
case 96 :
// '`'
if ( this . options . ecmaVersion < 6 ) break ;
++ this . pos ;
return this . finishToken ( _tokentype . types . backQuote ) ;
case 48 :
// '0'
var next = this . input . charCodeAt ( this . pos + 1 ) ;
if ( next === 120 || next === 88 ) return this . readRadixNumber ( 16 ) ; // '0x', '0X' - hex number
if ( this . options . ecmaVersion >= 6 ) {
if ( next === 111 || next === 79 ) return this . readRadixNumber ( 8 ) ; // '0o', '0O' - octal number
if ( next === 98 || next === 66 ) return this . readRadixNumber ( 2 ) ; // '0b', '0B' - binary number
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
// Anything else beginning with a digit is an integer, octal
// number, or float.
case 49 : case 50 : case 51 : case 52 : case 53 : case 54 : case 55 : case 56 : case 57 :
// 1-9
return this . readNumber ( false ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Quotes produce strings.
case 34 : case 39 :
// '"', "'"
return this . readString ( code ) ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Operators are parsed inline in tiny state machines. '=' (61) is
// often referred to. `finishOp` simply skips the amount of
// characters it is given as second argument, and returns a token
// of the type given by its first argument.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
case 47 :
// '/'
return this . readToken _slash ( ) ;
case 37 : case 42 :
// '%*'
return this . readToken _mult _modulo ( code ) ;
case 124 : case 38 :
// '|&'
return this . readToken _pipe _amp ( code ) ;
case 94 :
// '^'
return this . readToken _caret ( ) ;
case 43 : case 45 :
// '+-'
return this . readToken _plus _min ( code ) ;
case 60 : case 62 :
// '<>'
return this . readToken _lt _gt ( code ) ;
case 61 : case 33 :
// '=!'
return this . readToken _eq _excl ( code ) ;
case 126 :
// '~'
return this . finishOp ( _tokentype . types . prefix , 1 ) ;
}
this . raise ( this . pos , "Unexpected character '" + codePointToString ( code ) + "'" ) ;
} ;
pp . finishOp = function ( type , size ) {
var str = this . input . slice ( this . pos , this . pos + size ) ;
this . pos += size ;
return this . finishToken ( type , str ) ;
} ;
// Parse a regular expression. Some context-awareness is necessary,
// since a '/' inside a '[]' set does not end the expression.
function tryCreateRegexp ( src , flags , throwErrorAt , parser ) {
try {
return new RegExp ( src , flags ) ;
} catch ( e ) {
if ( throwErrorAt !== undefined ) {
if ( e instanceof SyntaxError ) parser . raise ( throwErrorAt , "Error parsing regular expression: " + e . message ) ;
throw e ;
}
}
}
var regexpUnicodeSupport = ! ! tryCreateRegexp ( "" , "u" ) ;
pp . readRegexp = function ( ) {
var _this = this ;
var escaped = undefined ,
inClass = undefined ,
start = this . pos ;
for ( ; ; ) {
if ( this . pos >= this . input . length ) this . raise ( start , "Unterminated regular expression" ) ;
var ch = this . input . charAt ( this . pos ) ;
if ( _whitespace . lineBreak . test ( ch ) ) this . raise ( start , "Unterminated regular expression" ) ;
if ( ! escaped ) {
if ( ch === "[" ) inClass = true ; else if ( ch === "]" && inClass ) inClass = false ; else if ( ch === "/" && ! inClass ) break ;
escaped = ch === "\\" ;
} else escaped = false ;
++ this . pos ;
}
var content = this . input . slice ( start , this . pos ) ;
++ this . pos ;
// Need to use `readWord1` because '\uXXXX' sequences are allowed
// here (don't ask).
var mods = this . readWord1 ( ) ;
var tmp = content ;
if ( mods ) {
var validFlags = /^[gmsiy]*$/ ;
if ( this . options . ecmaVersion >= 6 ) validFlags = /^[gmsiyu]*$/ ;
if ( ! validFlags . test ( mods ) ) this . raise ( start , "Invalid regular expression flag" ) ;
2018-02-01 22:45:22 +03:00
if ( mods . includes ( 'u' ) && ! regexpUnicodeSupport ) {
2015-12-16 21:15:23 +03:00
// Replace each astral symbol and every Unicode escape sequence that
// possibly represents an astral symbol or a paired surrogate with a
// single ASCII symbol to avoid throwing on regular expressions that
// are only valid in combination with the `/u` flag.
// Note: replacing with the ASCII symbol `x` might cause false
// negatives in unlikely scenarios. For example, `[\u{61}-b]` is a
// perfectly valid pattern that is equivalent to `[a-b]`, but it would
// be replaced by `[x-b]` which throws an error.
tmp = tmp . replace ( /\\u\{([0-9a-fA-F]+)\}/g , function ( _match , code , offset ) {
code = Number ( "0x" + code ) ;
if ( code > 0x10FFFF ) _this . raise ( start + offset + 3 , "Code point out of bounds" ) ;
return "x" ;
} ) ;
tmp = tmp . replace ( /\\u([a-fA-F0-9]{4})|[\uD800-\uDBFF][\uDC00-\uDFFF]/g , "x" ) ;
}
}
// Detect invalid regular expressions.
var value = null ;
// Rhino's regular expression parser is flaky and throws uncatchable exceptions,
// so don't do detection if we are running under Rhino
if ( ! isRhino ) {
tryCreateRegexp ( tmp , undefined , start , this ) ;
// Get a regular expression object for this pattern-flag pair, or `null` in
// case the current environment doesn't support the flags it uses.
value = tryCreateRegexp ( content , mods ) ;
}
return this . finishToken ( _tokentype . types . regexp , { pattern : content , flags : mods , value : value } ) ;
} ;
// Read an integer in the given radix. Return null if zero digits
// were read, the integer value otherwise. When `len` is given, this
// will return `null` unless the integer has exactly `len` digits.
pp . readInt = function ( radix , len ) {
var start = this . pos ,
total = 0 ;
for ( var i = 0 , e = len == null ? Infinity : len ; i < e ; ++ i ) {
var code = this . input . charCodeAt ( this . pos ) ,
val = undefined ;
if ( code >= 97 ) val = code - 97 + 10 ; // a
else if ( code >= 65 ) val = code - 65 + 10 ; // A
else if ( code >= 48 && code <= 57 ) val = code - 48 ; // 0-9
else val = Infinity ;
if ( val >= radix ) break ;
++ this . pos ;
total = total * radix + val ;
}
if ( this . pos === start || len != null && this . pos - start !== len ) return null ;
return total ;
} ;
pp . readRadixNumber = function ( radix ) {
this . pos += 2 ; // 0x
var val = this . readInt ( radix ) ;
if ( val == null ) this . raise ( this . start + 2 , "Expected number in radix " + radix ) ;
if ( _identifier . isIdentifierStart ( this . fullCharCodeAtPos ( ) ) ) this . raise ( this . pos , "Identifier directly after number" ) ;
return this . finishToken ( _tokentype . types . num , val ) ;
} ;
// Read an integer, octal integer, or floating-point number.
pp . readNumber = function ( startsWithDot ) {
var start = this . pos ,
isFloat = false ,
octal = this . input . charCodeAt ( this . pos ) === 48 ;
if ( ! startsWithDot && this . readInt ( 10 ) === null ) this . raise ( start , "Invalid number" ) ;
var next = this . input . charCodeAt ( this . pos ) ;
if ( next === 46 ) {
// '.'
++ this . pos ;
this . readInt ( 10 ) ;
isFloat = true ;
next = this . input . charCodeAt ( this . pos ) ;
}
if ( next === 69 || next === 101 ) {
// 'eE'
next = this . input . charCodeAt ( ++ this . pos ) ;
if ( next === 43 || next === 45 ) ++ this . pos ; // '+-'
if ( this . readInt ( 10 ) === null ) this . raise ( start , "Invalid number" ) ;
isFloat = true ;
}
if ( _identifier . isIdentifierStart ( this . fullCharCodeAtPos ( ) ) ) this . raise ( this . pos , "Identifier directly after number" ) ;
var str = this . input . slice ( start , this . pos ) ,
val = undefined ;
if ( isFloat ) val = parseFloat ( str ) ; else if ( ! octal || str . length === 1 ) val = parseInt ( str , 10 ) ; else if ( /[89]/ . test ( str ) || this . strict ) this . raise ( start , "Invalid number" ) ; else val = parseInt ( str , 8 ) ;
return this . finishToken ( _tokentype . types . num , val ) ;
} ;
// Read a string value, interpreting backslash-escapes.
pp . readCodePoint = function ( ) {
var ch = this . input . charCodeAt ( this . pos ) ,
code = undefined ;
if ( ch === 123 ) {
if ( this . options . ecmaVersion < 6 ) this . unexpected ( ) ;
var codePos = ++ this . pos ;
code = this . readHexChar ( this . input . indexOf ( '}' , this . pos ) - this . pos ) ;
++ this . pos ;
if ( code > 0x10FFFF ) this . raise ( codePos , "Code point out of bounds" ) ;
} else {
code = this . readHexChar ( 4 ) ;
}
return code ;
} ;
function codePointToString ( code ) {
// UTF-16 Decoding
if ( code <= 0xFFFF ) return String . fromCharCode ( code ) ;
code -= 0x10000 ;
return String . fromCharCode ( ( code >> 10 ) + 0xD800 , ( code & 1023 ) + 0xDC00 ) ;
}
pp . readString = function ( quote ) {
var out = "" ,
chunkStart = ++ this . pos ;
for ( ; ; ) {
if ( this . pos >= this . input . length ) this . raise ( this . start , "Unterminated string constant" ) ;
var ch = this . input . charCodeAt ( this . pos ) ;
if ( ch === quote ) break ;
if ( ch === 92 ) {
// '\'
out += this . input . slice ( chunkStart , this . pos ) ;
out += this . readEscapedChar ( false ) ;
chunkStart = this . pos ;
} else {
if ( _whitespace . isNewLine ( ch ) ) this . raise ( this . start , "Unterminated string constant" ) ;
++ this . pos ;
}
}
out += this . input . slice ( chunkStart , this . pos ++ ) ;
return this . finishToken ( _tokentype . types . string , out ) ;
} ;
// Reads template string tokens.
pp . readTmplToken = function ( ) {
var out = "" ,
chunkStart = this . pos ;
for ( ; ; ) {
if ( this . pos >= this . input . length ) this . raise ( this . start , "Unterminated template" ) ;
var ch = this . input . charCodeAt ( this . pos ) ;
if ( ch === 96 || ch === 36 && this . input . charCodeAt ( this . pos + 1 ) === 123 ) {
// '`', '${'
if ( this . pos === this . start && this . type === _tokentype . types . template ) {
if ( ch === 36 ) {
this . pos += 2 ;
return this . finishToken ( _tokentype . types . dollarBraceL ) ;
2015-01-06 23:24:00 +03:00
} else {
2015-12-16 21:15:23 +03:00
++ this . pos ;
return this . finishToken ( _tokentype . types . backQuote ) ;
2015-01-06 23:24:00 +03:00
}
}
2015-12-16 21:15:23 +03:00
out += this . input . slice ( chunkStart , this . pos ) ;
return this . finishToken ( _tokentype . types . template , out ) ;
}
if ( ch === 92 ) {
// '\'
out += this . input . slice ( chunkStart , this . pos ) ;
out += this . readEscapedChar ( true ) ;
chunkStart = this . pos ;
} else if ( _whitespace . isNewLine ( ch ) ) {
out += this . input . slice ( chunkStart , this . pos ) ;
++ this . pos ;
switch ( ch ) {
case 13 :
if ( this . input . charCodeAt ( this . pos ) === 10 ) ++ this . pos ;
case 10 :
out += "\n" ;
break ;
default :
out += String . fromCharCode ( ch ) ;
break ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
if ( this . options . locations ) {
++ this . curLine ;
this . lineStart = this . pos ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
chunkStart = this . pos ;
2015-01-06 23:24:00 +03:00
} else {
2015-12-16 21:15:23 +03:00
++ this . pos ;
}
}
} ;
// Used to read escaped characters
pp . readEscapedChar = function ( inTemplate ) {
var ch = this . input . charCodeAt ( ++ this . pos ) ;
++ this . pos ;
switch ( ch ) {
case 110 :
return "\n" ; // 'n' -> '\n'
case 114 :
return "\r" ; // 'r' -> '\r'
case 120 :
return String . fromCharCode ( this . readHexChar ( 2 ) ) ; // 'x'
case 117 :
return codePointToString ( this . readCodePoint ( ) ) ; // 'u'
case 116 :
return "\t" ; // 't' -> '\t'
case 98 :
return "\b" ; // 'b' -> '\b'
case 118 :
return "\u000b" ; // 'v' -> '\u000b'
case 102 :
return "\f" ; // 'f' -> '\f'
case 13 :
if ( this . input . charCodeAt ( this . pos ) === 10 ) ++ this . pos ; // '\r\n'
case 10 :
// ' \n'
if ( this . options . locations ) {
this . lineStart = this . pos ; ++ this . curLine ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
return "" ;
default :
if ( ch >= 48 && ch <= 55 ) {
var octalStr = this . input . substr ( this . pos - 1 , 3 ) . match ( /^[0-7]+/ ) [ 0 ] ;
var octal = parseInt ( octalStr , 8 ) ;
if ( octal > 255 ) {
octalStr = octalStr . slice ( 0 , - 1 ) ;
octal = parseInt ( octalStr , 8 ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
if ( octal > 0 && ( this . strict || inTemplate ) ) {
this . raise ( this . pos - 2 , "Octal literal in strict mode" ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
this . pos += octalStr . length - 1 ;
return String . fromCharCode ( octal ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
return String . fromCharCode ( ch ) ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Used to read character escape sequences ('\x', '\u', '\U').
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . readHexChar = function ( len ) {
var codePos = this . pos ;
var n = this . readInt ( 16 , len ) ;
if ( n === null ) this . raise ( codePos , "Bad character escape sequence" ) ;
return n ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Read an identifier, and return it as a string. Sets `this.containsEsc`
// to whether the word contained a '\u' escape.
//
// Incrementally adds only escaped chars, adding other chunks as-is
// as a micro-optimization.
pp . readWord1 = function ( ) {
this . containsEsc = false ;
var word = "" ,
first = true ,
chunkStart = this . pos ;
var astral = this . options . ecmaVersion >= 6 ;
while ( this . pos < this . input . length ) {
var ch = this . fullCharCodeAtPos ( ) ;
if ( _identifier . isIdentifierChar ( ch , astral ) ) {
this . pos += ch <= 0xffff ? 1 : 2 ;
} else if ( ch === 92 ) {
// "\"
this . containsEsc = true ;
word += this . input . slice ( chunkStart , this . pos ) ;
var escStart = this . pos ;
if ( this . input . charCodeAt ( ++ this . pos ) != 117 ) // "u"
this . raise ( this . pos , "Expecting Unicode escape sequence \\uXXXX" ) ;
++ this . pos ;
var esc = this . readCodePoint ( ) ;
if ( ! ( first ? _identifier . isIdentifierStart : _identifier . isIdentifierChar ) ( esc , astral ) ) this . raise ( escStart , "Invalid Unicode escape" ) ;
word += codePointToString ( esc ) ;
chunkStart = this . pos ;
2015-01-06 23:24:00 +03:00
} else {
2015-12-16 21:15:23 +03:00
break ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
first = false ;
2015-01-06 23:24:00 +03:00
}
2015-12-16 21:15:23 +03:00
return word + this . input . slice ( chunkStart , this . pos ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Read an identifier or keyword token. Will check for reserved
// words when necessary.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
pp . readWord = function ( ) {
var word = this . readWord1 ( ) ;
var type = _tokentype . types . name ;
if ( ( this . options . ecmaVersion >= 6 || ! this . containsEsc ) && this . keywords . test ( word ) ) type = _tokentype . keywords [ word ] ;
return this . finishToken ( type , word ) ;
} ;
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
} , { "./identifier" : 2 , "./locutil" : 5 , "./state" : 10 , "./tokentype" : 14 , "./whitespace" : 16 } ] , 14 : [ function ( _dereq _ , module , exports ) {
// ## Token types
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// The assignment of fine-grained, information-carrying type objects
// allows the tokenizer to store the information it has about a
// token in a way that is very cheap for the parser to look up.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// All token type variables start with an underscore, to make them
// easy to recognize.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// The `beforeExpr` property is used to disambiguate between regular
// expressions and divisions. It is set on all token types that can
// be followed by an expression (thus, a slash after them would be a
// regular expression).
//
// The `startsExpr` property is used to check if the token ends a
// `yield` expression. It is set on all token types that either can
// directly start an expression (like a quotation mark) or can
// continue an expression (like the body of a string).
//
// `isLoop` marks a keyword as starting a loop, which is important
// to know when parsing a label, in order to allow or disallow
// continue jumps to that label.
"use strict" ;
exports . _ _esModule = true ;
function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
var TokenType = function TokenType ( label ) {
var conf = arguments . length <= 1 || arguments [ 1 ] === undefined ? { } : arguments [ 1 ] ;
_classCallCheck ( this , TokenType ) ;
this . label = label ;
this . keyword = conf . keyword ;
this . beforeExpr = ! ! conf . beforeExpr ;
this . startsExpr = ! ! conf . startsExpr ;
this . isLoop = ! ! conf . isLoop ;
this . isAssign = ! ! conf . isAssign ;
this . prefix = ! ! conf . prefix ;
this . postfix = ! ! conf . postfix ;
this . binop = conf . binop || null ;
this . updateContext = null ;
} ;
exports . TokenType = TokenType ;
function binop ( name , prec ) {
return new TokenType ( name , { beforeExpr : true , binop : prec } ) ;
}
var beforeExpr = { beforeExpr : true } ,
startsExpr = { startsExpr : true } ;
var types = {
num : new TokenType ( "num" , startsExpr ) ,
regexp : new TokenType ( "regexp" , startsExpr ) ,
string : new TokenType ( "string" , startsExpr ) ,
name : new TokenType ( "name" , startsExpr ) ,
eof : new TokenType ( "eof" ) ,
// Punctuation token types.
bracketL : new TokenType ( "[" , { beforeExpr : true , startsExpr : true } ) ,
bracketR : new TokenType ( "]" ) ,
braceL : new TokenType ( "{" , { beforeExpr : true , startsExpr : true } ) ,
braceR : new TokenType ( "}" ) ,
parenL : new TokenType ( "(" , { beforeExpr : true , startsExpr : true } ) ,
parenR : new TokenType ( ")" ) ,
comma : new TokenType ( "," , beforeExpr ) ,
semi : new TokenType ( ";" , beforeExpr ) ,
colon : new TokenType ( ":" , beforeExpr ) ,
dot : new TokenType ( "." ) ,
question : new TokenType ( "?" , beforeExpr ) ,
arrow : new TokenType ( "=>" , beforeExpr ) ,
template : new TokenType ( "template" ) ,
ellipsis : new TokenType ( "..." , beforeExpr ) ,
backQuote : new TokenType ( "`" , startsExpr ) ,
dollarBraceL : new TokenType ( "${" , { beforeExpr : true , startsExpr : true } ) ,
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
// Operators. These carry several kinds of properties to help the
// parser use them properly (the presence of these properties is
// what categorizes them as operators).
//
// `binop`, when present, specifies that this operator is a binary
// operator, and will refer to its precedence.
//
// `prefix` and `postfix` mark the operator as a prefix or postfix
// unary operator.
//
// `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as
// binary operators with a very low precedence, that should result
// in AssignmentExpression nodes.
2015-01-06 23:24:00 +03:00
2015-12-16 21:15:23 +03:00
eq : new TokenType ( "=" , { beforeExpr : true , isAssign : true } ) ,
assign : new TokenType ( "_=" , { beforeExpr : true , isAssign : true } ) ,
incDec : new TokenType ( "++/--" , { prefix : true , postfix : true , startsExpr : true } ) ,
prefix : new TokenType ( "prefix" , { beforeExpr : true , prefix : true , startsExpr : true } ) ,
logicalOR : binop ( "||" , 1 ) ,
logicalAND : binop ( "&&" , 2 ) ,
bitwiseOR : binop ( "|" , 3 ) ,
bitwiseXOR : binop ( "^" , 4 ) ,
bitwiseAND : binop ( "&" , 5 ) ,
equality : binop ( "==/!=" , 6 ) ,
relational : binop ( "</>" , 7 ) ,
bitShift : binop ( "<</>>" , 8 ) ,
plusMin : new TokenType ( "+/-" , { beforeExpr : true , binop : 9 , prefix : true , startsExpr : true } ) ,
modulo : binop ( "%" , 10 ) ,
star : binop ( "*" , 10 ) ,
slash : binop ( "/" , 10 )
} ;
exports . types = types ;
// Map keyword names to token types.
var keywords = { } ;
exports . keywords = keywords ;
// Succinct definitions of keyword token types
function kw ( name ) {
var options = arguments . length <= 1 || arguments [ 1 ] === undefined ? { } : arguments [ 1 ] ;
options . keyword = name ;
keywords [ name ] = types [ "_" + name ] = new TokenType ( name , options ) ;
}
kw ( "break" ) ;
kw ( "case" , beforeExpr ) ;
kw ( "catch" ) ;
kw ( "continue" ) ;
kw ( "debugger" ) ;
kw ( "default" , beforeExpr ) ;
kw ( "do" , { isLoop : true , beforeExpr : true } ) ;
kw ( "else" , beforeExpr ) ;
kw ( "finally" ) ;
kw ( "for" , { isLoop : true } ) ;
kw ( "function" , startsExpr ) ;
kw ( "if" ) ;
kw ( "return" , beforeExpr ) ;
kw ( "switch" ) ;
kw ( "throw" , beforeExpr ) ;
kw ( "try" ) ;
kw ( "var" ) ;
kw ( "let" ) ;
kw ( "const" ) ;
kw ( "while" , { isLoop : true } ) ;
kw ( "with" ) ;
kw ( "new" , { beforeExpr : true , startsExpr : true } ) ;
kw ( "this" , startsExpr ) ;
kw ( "super" , startsExpr ) ;
kw ( "class" ) ;
kw ( "extends" , beforeExpr ) ;
kw ( "export" ) ;
kw ( "import" ) ;
kw ( "yield" , { beforeExpr : true , startsExpr : true } ) ;
kw ( "null" , startsExpr ) ;
kw ( "true" , startsExpr ) ;
kw ( "false" , startsExpr ) ;
kw ( "in" , { beforeExpr : true , binop : 7 } ) ;
kw ( "instanceof" , { beforeExpr : true , binop : 7 } ) ;
kw ( "typeof" , { beforeExpr : true , prefix : true , startsExpr : true } ) ;
kw ( "void" , { beforeExpr : true , prefix : true , startsExpr : true } ) ;
kw ( "delete" , { beforeExpr : true , prefix : true , startsExpr : true } ) ;
} , { } ] , 15 : [ function ( _dereq _ , module , exports ) {
"use strict" ;
exports . _ _esModule = true ;
exports . isArray = isArray ;
exports . has = has ;
function isArray ( obj ) {
return Object . prototype . toString . call ( obj ) === "[object Array]" ;
}
// Checks if an object has a property.
function has ( obj , propName ) {
return Object . prototype . hasOwnProperty . call ( obj , propName ) ;
}
} , { } ] , 16 : [ function ( _dereq _ , module , exports ) {
// Matches a whole line break (where CRLF is considered a single
// line break). Used to count lines.
"use strict" ;
exports . _ _esModule = true ;
exports . isNewLine = isNewLine ;
var lineBreak = /\r\n?|\n|\u2028|\u2029/ ;
exports . lineBreak = lineBreak ;
var lineBreakG = new RegExp ( lineBreak . source , "g" ) ;
exports . lineBreakG = lineBreakG ;
function isNewLine ( code ) {
return code === 10 || code === 13 || code === 0x2028 || code == 0x2029 ;
}
var nonASCIIwhitespace = /[\u1680\u180e\u2000-\u200a\u202f\u205f\u3000\ufeff]/ ;
exports . nonASCIIwhitespace = nonASCIIwhitespace ;
} , { } ] } , { } , [ 3 ] ) ( 3 )
} ) ;