2014-09-20 11:49:04 -04:00
( function ( exports , global ) {
2024-02-29 09:14:04 -05:00
globalThis [ "UglifyJS" ] = exports ;
2014-09-20 11:49:04 -04:00
"use strict" ;
function array _to _hash ( a ) {
var ret = Object . create ( null ) ;
for ( var i = 0 ; i < a . length ; ++ i ) ret [ a [ i ] ] = true ;
return ret ;
}
function slice ( a , start ) {
return Array . prototype . slice . call ( a , start || 0 ) ;
}
function characters ( str ) {
return str . split ( "" ) ;
}
function member ( name , array ) {
for ( var i = array . length ; -- i >= 0 ; ) if ( array [ i ] == name ) return true ;
return false ;
}
function find _if ( func , array ) {
for ( var i = 0 , n = array . length ; i < n ; ++ i ) {
if ( func ( array [ i ] ) ) return array [ i ] ;
}
}
function repeat _string ( str , i ) {
if ( i <= 0 ) return "" ;
if ( i == 1 ) return str ;
var d = repeat _string ( str , i >> 1 ) ;
d += d ;
if ( i & 1 ) d += str ;
return d ;
}
function DefaultsError ( msg , defs ) {
Error . call ( this , msg ) ;
this . msg = msg ;
this . defs = defs ;
}
DefaultsError . prototype = Object . create ( Error . prototype ) ;
DefaultsError . prototype . constructor = DefaultsError ;
DefaultsError . croak = function ( msg , defs ) {
throw new DefaultsError ( msg , defs ) ;
} ;
function defaults ( args , defs , croak ) {
if ( args === true ) args = { } ;
var ret = args || { } ;
if ( croak ) for ( var i in ret ) if ( ret . hasOwnProperty ( i ) && ! defs . hasOwnProperty ( i ) ) DefaultsError . croak ( "`" + i + "` is not a supported option" , defs ) ;
for ( var i in defs ) if ( defs . hasOwnProperty ( i ) ) {
ret [ i ] = args && args . hasOwnProperty ( i ) ? args [ i ] : defs [ i ] ;
}
return ret ;
}
function merge ( obj , ext ) {
for ( var i in ext ) if ( ext . hasOwnProperty ( i ) ) {
obj [ i ] = ext [ i ] ;
}
return obj ;
}
function noop ( ) { }
var MAP = function ( ) {
function MAP ( a , f , backwards ) {
var ret = [ ] , top = [ ] , i ;
function doit ( ) {
var val = f ( a [ i ] , i ) ;
var is _last = val instanceof Last ;
if ( is _last ) val = val . v ;
if ( val instanceof AtTop ) {
val = val . v ;
if ( val instanceof Splice ) {
top . push . apply ( top , backwards ? val . v . slice ( ) . reverse ( ) : val . v ) ;
} else {
top . push ( val ) ;
}
} else if ( val !== skip ) {
if ( val instanceof Splice ) {
ret . push . apply ( ret , backwards ? val . v . slice ( ) . reverse ( ) : val . v ) ;
} else {
ret . push ( val ) ;
}
}
return is _last ;
}
if ( a instanceof Array ) {
if ( backwards ) {
for ( i = a . length ; -- i >= 0 ; ) if ( doit ( ) ) break ;
ret . reverse ( ) ;
top . reverse ( ) ;
} else {
for ( i = 0 ; i < a . length ; ++ i ) if ( doit ( ) ) break ;
}
} else {
for ( i in a ) if ( a . hasOwnProperty ( i ) ) if ( doit ( ) ) break ;
}
return top . concat ( ret ) ;
}
MAP . at _top = function ( val ) {
return new AtTop ( val ) ;
} ;
MAP . splice = function ( val ) {
return new Splice ( val ) ;
} ;
MAP . last = function ( val ) {
return new Last ( val ) ;
} ;
var skip = MAP . skip = { } ;
function AtTop ( val ) {
this . v = val ;
}
function Splice ( val ) {
this . v = val ;
}
function Last ( val ) {
this . v = val ;
}
return MAP ;
} ( ) ;
function push _uniq ( array , el ) {
if ( array . indexOf ( el ) < 0 ) array . push ( el ) ;
}
function string _template ( text , props ) {
return text . replace ( /\{(.+?)\}/g , function ( str , p ) {
return props [ p ] ;
} ) ;
}
function remove ( array , el ) {
for ( var i = array . length ; -- i >= 0 ; ) {
if ( array [ i ] === el ) array . splice ( i , 1 ) ;
}
}
function mergeSort ( array , cmp ) {
if ( array . length < 2 ) return array . slice ( ) ;
function merge ( a , b ) {
var r = [ ] , ai = 0 , bi = 0 , i = 0 ;
while ( ai < a . length && bi < b . length ) {
cmp ( a [ ai ] , b [ bi ] ) <= 0 ? r [ i ++ ] = a [ ai ++ ] : r [ i ++ ] = b [ bi ++ ] ;
}
if ( ai < a . length ) r . push . apply ( r , a . slice ( ai ) ) ;
if ( bi < b . length ) r . push . apply ( r , b . slice ( bi ) ) ;
return r ;
}
function _ms ( a ) {
if ( a . length <= 1 ) return a ;
var m = Math . floor ( a . length / 2 ) , left = a . slice ( 0 , m ) , right = a . slice ( m ) ;
left = _ms ( left ) ;
right = _ms ( right ) ;
return merge ( left , right ) ;
}
return _ms ( array ) ;
}
function set _difference ( a , b ) {
return a . filter ( function ( el ) {
return b . indexOf ( el ) < 0 ;
} ) ;
}
function set _intersection ( a , b ) {
return a . filter ( function ( el ) {
return b . indexOf ( el ) >= 0 ;
} ) ;
}
function makePredicate ( words ) {
if ( ! ( words instanceof Array ) ) words = words . split ( " " ) ;
if ( typeof UglifyJS _NoUnsafeEval !== "undefined" ) {
return function ( str ) {
return words . indexOf ( str ) >= 0 ;
} ;
}
var f = "" , cats = [ ] ;
out : for ( var i = 0 ; i < words . length ; ++ i ) {
for ( var j = 0 ; j < cats . length ; ++ j ) if ( cats [ j ] [ 0 ] . length == words [ i ] . length ) {
cats [ j ] . push ( words [ i ] ) ;
continue out ;
}
cats . push ( [ words [ i ] ] ) ;
}
function compareTo ( arr ) {
if ( arr . length == 1 ) return f += "return str === " + JSON . stringify ( arr [ 0 ] ) + ";" ;
f += "switch(str){" ;
for ( var i = 0 ; i < arr . length ; ++ i ) f += "case " + JSON . stringify ( arr [ i ] ) + ":" ;
f += "return true}return false;" ;
}
if ( cats . length > 3 ) {
cats . sort ( function ( a , b ) {
return b . length - a . length ;
} ) ;
f += "switch(str.length){" ;
for ( var i = 0 ; i < cats . length ; ++ i ) {
var cat = cats [ i ] ;
f += "case " + cat [ 0 ] . length + ":" ;
compareTo ( cat ) ;
}
f += "}" ;
} else {
compareTo ( words ) ;
}
return new Function ( "str" , f ) ;
}
function all ( array , predicate ) {
for ( var i = array . length ; -- i >= 0 ; ) if ( ! predicate ( array [ i ] ) ) return false ;
return true ;
}
function Dictionary ( ) {
this . _values = Object . create ( null ) ;
this . _size = 0 ;
}
Dictionary . prototype = {
set : function ( key , val ) {
if ( ! this . has ( key ) ) ++ this . _size ;
this . _values [ "$" + key ] = val ;
return this ;
} ,
add : function ( key , val ) {
if ( this . has ( key ) ) {
this . get ( key ) . push ( val ) ;
} else {
this . set ( key , [ val ] ) ;
}
return this ;
} ,
get : function ( key ) {
return this . _values [ "$" + key ] ;
} ,
del : function ( key ) {
if ( this . has ( key ) ) {
-- this . _size ;
delete this . _values [ "$" + key ] ;
}
return this ;
} ,
has : function ( key ) {
return "$" + key in this . _values ;
} ,
each : function ( f ) {
for ( var i in this . _values ) f ( this . _values [ i ] , i . substr ( 1 ) ) ;
} ,
size : function ( ) {
return this . _size ;
} ,
map : function ( f ) {
var ret = [ ] ;
for ( var i in this . _values ) ret . push ( f ( this . _values [ i ] , i . substr ( 1 ) ) ) ;
return ret ;
}
} ;
"use strict" ;
function DEFNODE ( type , props , methods , base ) {
if ( arguments . length < 4 ) base = AST _Node ;
if ( ! props ) props = [ ] ; else props = props . split ( /\s+/ ) ;
var self _props = props ;
if ( base && base . PROPS ) props = props . concat ( base . PROPS ) ;
var proto = base && new base ( ) ;
var ctor ;
if ( typeof UglifyJS _NoUnsafeEval === "undefined" ) {
var code = "return function AST_" + type + "(props){ if (props) { " ;
for ( var i = props . length ; -- i >= 0 ; ) {
code += "this." + props [ i ] + " = props." + props [ i ] + ";" ;
}
if ( proto && proto . initialize || methods && methods . initialize ) code += "this.initialize();" ;
code += "}}" ;
ctor = new Function ( code ) ( ) ;
} else {
ctor = function ( values ) {
if ( values ) {
for ( var i = props . length ; -- i >= 0 ; ) this [ props [ i ] ] = values [ props [ i ] ] ;
if ( proto && proto . initialize || methods && methods . initialize ) this . initialize ( ) ;
}
} ;
}
if ( proto ) {
ctor . prototype = proto ;
ctor . BASE = base ;
}
if ( base ) base . SUBCLASSES . push ( ctor ) ;
ctor . prototype . CTOR = ctor ;
ctor . PROPS = props || null ;
ctor . SELF _PROPS = self _props ;
ctor . SUBCLASSES = [ ] ;
if ( type ) {
ctor . prototype . TYPE = ctor . TYPE = type ;
}
if ( methods ) for ( i in methods ) if ( methods . hasOwnProperty ( i ) ) {
if ( /^\$/ . test ( i ) ) {
ctor [ i . substr ( 1 ) ] = methods [ i ] ;
} else {
ctor . prototype [ i ] = methods [ i ] ;
}
}
ctor . DEFMETHOD = function ( name , method ) {
this . prototype [ name ] = method ;
} ;
return ctor ;
}
var AST _Token = DEFNODE ( "Token" , "type value line col pos endpos nlb comments_before file" , { } , null ) ;
var AST _Node = DEFNODE ( "Node" , "start end" , {
clone : function ( ) {
return new this . CTOR ( this ) ;
} ,
$documentation : "Base class of all AST nodes" ,
$propdoc : {
start : "[AST_Token] The first token of this node" ,
end : "[AST_Token] The last token of this node"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this ) ;
} ,
walk : function ( visitor ) {
return this . _walk ( visitor ) ;
}
} , null ) ;
AST _Node . warn _function = null ;
AST _Node . warn = function ( txt , props ) {
if ( AST _Node . warn _function ) AST _Node . warn _function ( string _template ( txt , props ) ) ;
} ;
var AST _Statement = DEFNODE ( "Statement" , null , {
$documentation : "Base class of all statements"
} ) ;
var AST _Debugger = DEFNODE ( "Debugger" , null , {
$documentation : "Represents a debugger statement"
} , AST _Statement ) ;
var AST _Directive = DEFNODE ( "Directive" , "value scope" , {
$documentation : 'Represents a directive, like "use strict";' ,
$propdoc : {
value : "[string] The value of this directive as a plain string (it's not an AST_String!)" ,
scope : "[AST_Scope/S] The scope that this directive affects"
}
} , AST _Statement ) ;
var AST _SimpleStatement = DEFNODE ( "SimpleStatement" , "body" , {
$documentation : "A statement consisting of an expression, i.e. a = 1 + 2" ,
$propdoc : {
body : "[AST_Node] an expression node (should not be instanceof AST_Statement)"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _Statement ) ;
function walk _body ( node , visitor ) {
if ( node . body instanceof AST _Statement ) {
node . body . _walk ( visitor ) ;
} else node . body . forEach ( function ( stat ) {
stat . _walk ( visitor ) ;
} ) ;
}
var AST _Block = DEFNODE ( "Block" , "body" , {
$documentation : "A body of statements (usually bracketed)" ,
$propdoc : {
body : "[AST_Statement*] an array of statements"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
walk _body ( this , visitor ) ;
} ) ;
}
} , AST _Statement ) ;
var AST _BlockStatement = DEFNODE ( "BlockStatement" , null , {
$documentation : "A block statement"
} , AST _Block ) ;
var AST _EmptyStatement = DEFNODE ( "EmptyStatement" , null , {
$documentation : "The empty statement (empty block or simply a semicolon)" ,
_walk : function ( visitor ) {
return visitor . _visit ( this ) ;
}
} , AST _Statement ) ;
var AST _StatementWithBody = DEFNODE ( "StatementWithBody" , "body" , {
$documentation : "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`" ,
$propdoc : {
body : "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _Statement ) ;
var AST _LabeledStatement = DEFNODE ( "LabeledStatement" , "label" , {
$documentation : "Statement with a label" ,
$propdoc : {
label : "[AST_Label] a label definition"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . label . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _StatementWithBody ) ;
var AST _IterationStatement = DEFNODE ( "IterationStatement" , null , {
$documentation : "Internal class. All loops inherit from it."
} , AST _StatementWithBody ) ;
var AST _DWLoop = DEFNODE ( "DWLoop" , "condition" , {
$documentation : "Base class for do/while statements" ,
$propdoc : {
condition : "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . condition . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _IterationStatement ) ;
var AST _Do = DEFNODE ( "Do" , null , {
$documentation : "A `do` statement"
} , AST _DWLoop ) ;
var AST _While = DEFNODE ( "While" , null , {
$documentation : "A `while` statement"
} , AST _DWLoop ) ;
var AST _For = DEFNODE ( "For" , "init condition step" , {
$documentation : "A `for` statement" ,
$propdoc : {
init : "[AST_Node?] the `for` initialization code, or null if empty" ,
condition : "[AST_Node?] the `for` termination clause, or null if empty" ,
step : "[AST_Node?] the `for` update clause, or null if empty"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
if ( this . init ) this . init . _walk ( visitor ) ;
if ( this . condition ) this . condition . _walk ( visitor ) ;
if ( this . step ) this . step . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _IterationStatement ) ;
var AST _ForIn = DEFNODE ( "ForIn" , "init name object" , {
$documentation : "A `for ... in` statement" ,
$propdoc : {
init : "[AST_Node] the `for/in` initialization code" ,
name : "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var" ,
object : "[AST_Node] the object that we're looping through"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . init . _walk ( visitor ) ;
this . object . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _IterationStatement ) ;
var AST _With = DEFNODE ( "With" , "expression" , {
$documentation : "A `with` statement" ,
$propdoc : {
expression : "[AST_Node] the `with` expression"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _StatementWithBody ) ;
var AST _Scope = DEFNODE ( "Scope" , "directives variables functions uses_with uses_eval parent_scope enclosed cname" , {
$documentation : "Base class for all statements introducing a lexical scope" ,
$propdoc : {
directives : "[string*/S] an array of directives declared in this scope" ,
variables : "[Object/S] a map of name -> SymbolDef for all variables/functions defined in this scope" ,
functions : "[Object/S] like `variables`, but only lists function declarations" ,
uses _with : "[boolean/S] tells whether this scope uses the `with` statement" ,
uses _eval : "[boolean/S] tells whether this scope contains a direct call to the global `eval`" ,
parent _scope : "[AST_Scope?/S] link to the parent scope" ,
enclosed : "[SymbolDef*/S] a list of all symbol definitions that are accessed from this scope or any subscopes" ,
cname : "[integer/S] current index for mangling variables (used internally by the mangler)"
}
} , AST _Block ) ;
var AST _Toplevel = DEFNODE ( "Toplevel" , "globals" , {
$documentation : "The toplevel scope" ,
$propdoc : {
globals : "[Object/S] a map of name -> SymbolDef for all undeclared names"
} ,
wrap _enclose : function ( arg _parameter _pairs ) {
var self = this ;
var args = [ ] ;
var parameters = [ ] ;
arg _parameter _pairs . forEach ( function ( pair ) {
var splitAt = pair . lastIndexOf ( ":" ) ;
args . push ( pair . substr ( 0 , splitAt ) ) ;
parameters . push ( pair . substr ( splitAt + 1 ) ) ;
} ) ;
var wrapped _tl = "(function(" + parameters . join ( "," ) + "){ '$ORIG'; })(" + args . join ( "," ) + ")" ;
wrapped _tl = parse ( wrapped _tl ) ;
wrapped _tl = wrapped _tl . transform ( new TreeTransformer ( function before ( node ) {
if ( node instanceof AST _Directive && node . value == "$ORIG" ) {
return MAP . splice ( self . body ) ;
}
} ) ) ;
return wrapped _tl ;
} ,
wrap _commonjs : function ( name , export _all ) {
var self = this ;
var to _export = [ ] ;
if ( export _all ) {
self . figure _out _scope ( ) ;
self . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _SymbolDeclaration && node . definition ( ) . global ) {
if ( ! find _if ( function ( n ) {
return n . name == node . name ;
} , to _export ) ) to _export . push ( node ) ;
}
} ) ) ;
}
var wrapped _tl = "(function(exports, global){ global['" + name + "'] = exports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))" ;
wrapped _tl = parse ( wrapped _tl ) ;
wrapped _tl = wrapped _tl . transform ( new TreeTransformer ( function before ( node ) {
if ( node instanceof AST _SimpleStatement ) {
node = node . body ;
if ( node instanceof AST _String ) switch ( node . getValue ( ) ) {
case "$ORIG" :
return MAP . splice ( self . body ) ;
case "$EXPORTS" :
var body = [ ] ;
to _export . forEach ( function ( sym ) {
body . push ( new AST _SimpleStatement ( {
body : new AST _Assign ( {
left : new AST _Sub ( {
expression : new AST _SymbolRef ( {
name : "exports"
} ) ,
property : new AST _String ( {
value : sym . name
} )
} ) ,
operator : "=" ,
right : new AST _SymbolRef ( sym )
} )
} ) ) ;
} ) ;
return MAP . splice ( body ) ;
}
}
} ) ) ;
return wrapped _tl ;
}
} , AST _Scope ) ;
var AST _Lambda = DEFNODE ( "Lambda" , "name argnames uses_arguments" , {
$documentation : "Base class for functions" ,
$propdoc : {
name : "[AST_SymbolDeclaration?] the name of this function" ,
argnames : "[AST_SymbolFunarg*] array of function arguments" ,
uses _arguments : "[boolean/S] tells whether this function accesses the arguments array"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
if ( this . name ) this . name . _walk ( visitor ) ;
this . argnames . forEach ( function ( arg ) {
arg . _walk ( visitor ) ;
} ) ;
walk _body ( this , visitor ) ;
} ) ;
}
} , AST _Scope ) ;
var AST _Accessor = DEFNODE ( "Accessor" , null , {
$documentation : "A setter/getter function. The `name` property is always null."
} , AST _Lambda ) ;
var AST _Function = DEFNODE ( "Function" , null , {
$documentation : "A function expression"
} , AST _Lambda ) ;
var AST _Defun = DEFNODE ( "Defun" , null , {
$documentation : "A function definition"
} , AST _Lambda ) ;
var AST _Jump = DEFNODE ( "Jump" , null , {
$documentation : "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
} , AST _Statement ) ;
var AST _Exit = DEFNODE ( "Exit" , "value" , {
$documentation : "Base class for “exits” (`return` and `throw`)" ,
$propdoc : {
value : "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , this . value && function ( ) {
this . value . _walk ( visitor ) ;
} ) ;
}
} , AST _Jump ) ;
var AST _Return = DEFNODE ( "Return" , null , {
$documentation : "A `return` statement"
} , AST _Exit ) ;
var AST _Throw = DEFNODE ( "Throw" , null , {
$documentation : "A `throw` statement"
} , AST _Exit ) ;
var AST _LoopControl = DEFNODE ( "LoopControl" , "label" , {
$documentation : "Base class for loop control statements (`break` and `continue`)" ,
$propdoc : {
label : "[AST_LabelRef?] the label, or null if none"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , this . label && function ( ) {
this . label . _walk ( visitor ) ;
} ) ;
}
} , AST _Jump ) ;
var AST _Break = DEFNODE ( "Break" , null , {
$documentation : "A `break` statement"
} , AST _LoopControl ) ;
var AST _Continue = DEFNODE ( "Continue" , null , {
$documentation : "A `continue` statement"
} , AST _LoopControl ) ;
var AST _If = DEFNODE ( "If" , "condition alternative" , {
$documentation : "A `if` statement" ,
$propdoc : {
condition : "[AST_Node] the `if` condition" ,
alternative : "[AST_Statement?] the `else` part, or null if not present"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . condition . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
if ( this . alternative ) this . alternative . _walk ( visitor ) ;
} ) ;
}
} , AST _StatementWithBody ) ;
var AST _Switch = DEFNODE ( "Switch" , "expression" , {
$documentation : "A `switch` statement" ,
$propdoc : {
expression : "[AST_Node] the `switch` “discriminant”"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
walk _body ( this , visitor ) ;
} ) ;
}
} , AST _Block ) ;
var AST _SwitchBranch = DEFNODE ( "SwitchBranch" , null , {
$documentation : "Base class for `switch` branches"
} , AST _Block ) ;
var AST _Default = DEFNODE ( "Default" , null , {
$documentation : "A `default` switch branch"
} , AST _SwitchBranch ) ;
var AST _Case = DEFNODE ( "Case" , "expression" , {
$documentation : "A `case` switch branch" ,
$propdoc : {
expression : "[AST_Node] the `case` expression"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
walk _body ( this , visitor ) ;
} ) ;
}
} , AST _SwitchBranch ) ;
var AST _Try = DEFNODE ( "Try" , "bcatch bfinally" , {
$documentation : "A `try` statement" ,
$propdoc : {
bcatch : "[AST_Catch?] the catch block, or null if not present" ,
bfinally : "[AST_Finally?] the finally block, or null if not present"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
walk _body ( this , visitor ) ;
if ( this . bcatch ) this . bcatch . _walk ( visitor ) ;
if ( this . bfinally ) this . bfinally . _walk ( visitor ) ;
} ) ;
}
} , AST _Block ) ;
var AST _Catch = DEFNODE ( "Catch" , "argname" , {
$documentation : "A `catch` node; only makes sense as part of a `try` statement" ,
$propdoc : {
argname : "[AST_SymbolCatch] symbol for the exception"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . argname . _walk ( visitor ) ;
walk _body ( this , visitor ) ;
} ) ;
}
} , AST _Block ) ;
var AST _Finally = DEFNODE ( "Finally" , null , {
$documentation : "A `finally` node; only makes sense as part of a `try` statement"
} , AST _Block ) ;
var AST _Definitions = DEFNODE ( "Definitions" , "definitions" , {
$documentation : "Base class for `var` or `const` nodes (variable declarations/initializations)" ,
$propdoc : {
definitions : "[AST_VarDef*] array of variable definitions"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . definitions . forEach ( function ( def ) {
def . _walk ( visitor ) ;
} ) ;
} ) ;
}
} , AST _Statement ) ;
var AST _Var = DEFNODE ( "Var" , null , {
$documentation : "A `var` statement"
} , AST _Definitions ) ;
var AST _Const = DEFNODE ( "Const" , null , {
$documentation : "A `const` statement"
} , AST _Definitions ) ;
var AST _VarDef = DEFNODE ( "VarDef" , "name value" , {
$documentation : "A variable declaration; only appears in a AST_Definitions node" ,
$propdoc : {
name : "[AST_SymbolVar|AST_SymbolConst] name of the variable" ,
value : "[AST_Node?] initializer, or null of there's no initializer"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . name . _walk ( visitor ) ;
if ( this . value ) this . value . _walk ( visitor ) ;
} ) ;
}
} ) ;
var AST _Call = DEFNODE ( "Call" , "expression args" , {
$documentation : "A function call expression" ,
$propdoc : {
expression : "[AST_Node] expression to invoke as function" ,
args : "[AST_Node*] array of arguments"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
this . args . forEach ( function ( arg ) {
arg . _walk ( visitor ) ;
} ) ;
} ) ;
}
} ) ;
var AST _New = DEFNODE ( "New" , null , {
$documentation : "An object instantiation. Derives from a function call since it has exactly the same properties"
} , AST _Call ) ;
var AST _Seq = DEFNODE ( "Seq" , "car cdr" , {
$documentation : "A sequence expression (two comma-separated expressions)" ,
$propdoc : {
car : "[AST_Node] first element in sequence" ,
cdr : "[AST_Node] second element in sequence"
} ,
$cons : function ( x , y ) {
var seq = new AST _Seq ( x ) ;
seq . car = x ;
seq . cdr = y ;
return seq ;
} ,
$from _array : function ( array ) {
if ( array . length == 0 ) return null ;
if ( array . length == 1 ) return array [ 0 ] . clone ( ) ;
var list = null ;
for ( var i = array . length ; -- i >= 0 ; ) {
list = AST _Seq . cons ( array [ i ] , list ) ;
}
var p = list ;
while ( p ) {
if ( p . cdr && ! p . cdr . cdr ) {
p . cdr = p . cdr . car ;
break ;
}
p = p . cdr ;
}
return list ;
} ,
to _array : function ( ) {
var p = this , a = [ ] ;
while ( p ) {
a . push ( p . car ) ;
if ( p . cdr && ! ( p . cdr instanceof AST _Seq ) ) {
a . push ( p . cdr ) ;
break ;
}
p = p . cdr ;
}
return a ;
} ,
add : function ( node ) {
var p = this ;
while ( p ) {
if ( ! ( p . cdr instanceof AST _Seq ) ) {
var cell = AST _Seq . cons ( p . cdr , node ) ;
return p . cdr = cell ;
}
p = p . cdr ;
}
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . car . _walk ( visitor ) ;
if ( this . cdr ) this . cdr . _walk ( visitor ) ;
} ) ;
}
} ) ;
var AST _PropAccess = DEFNODE ( "PropAccess" , "expression property" , {
$documentation : 'Base class for property access expressions, i.e. `a.foo` or `a["foo"]`' ,
$propdoc : {
expression : "[AST_Node] the “container” expression" ,
property : "[AST_Node|string] the property to access. For AST_Dot this is always a plain string, while for AST_Sub it's an arbitrary AST_Node"
}
} ) ;
var AST _Dot = DEFNODE ( "Dot" , null , {
$documentation : "A dotted property access expression" ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
} ) ;
}
} , AST _PropAccess ) ;
var AST _Sub = DEFNODE ( "Sub" , null , {
$documentation : 'Index-style property access, i.e. `a["foo"]`' ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
this . property . _walk ( visitor ) ;
} ) ;
}
} , AST _PropAccess ) ;
var AST _Unary = DEFNODE ( "Unary" , "operator expression" , {
$documentation : "Base class for unary expressions" ,
$propdoc : {
operator : "[string] the operator" ,
expression : "[AST_Node] expression that this unary operator applies to"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
} ) ;
}
} ) ;
var AST _UnaryPrefix = DEFNODE ( "UnaryPrefix" , null , {
$documentation : "Unary prefix expression, i.e. `typeof i` or `++i`"
} , AST _Unary ) ;
var AST _UnaryPostfix = DEFNODE ( "UnaryPostfix" , null , {
$documentation : "Unary postfix expression, i.e. `i++`"
} , AST _Unary ) ;
var AST _Binary = DEFNODE ( "Binary" , "left operator right" , {
$documentation : "Binary expression, i.e. `a + b`" ,
$propdoc : {
left : "[AST_Node] left-hand side expression" ,
operator : "[string] the operator" ,
right : "[AST_Node] right-hand side expression"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . left . _walk ( visitor ) ;
this . right . _walk ( visitor ) ;
} ) ;
}
} ) ;
var AST _Conditional = DEFNODE ( "Conditional" , "condition consequent alternative" , {
$documentation : "Conditional expression using the ternary operator, i.e. `a ? b : c`" ,
$propdoc : {
condition : "[AST_Node]" ,
consequent : "[AST_Node]" ,
alternative : "[AST_Node]"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . condition . _walk ( visitor ) ;
this . consequent . _walk ( visitor ) ;
this . alternative . _walk ( visitor ) ;
} ) ;
}
} ) ;
var AST _Assign = DEFNODE ( "Assign" , null , {
$documentation : "An assignment expression — `a = b + 5`"
} , AST _Binary ) ;
var AST _Array = DEFNODE ( "Array" , "elements" , {
$documentation : "An array literal" ,
$propdoc : {
elements : "[AST_Node*] array of elements"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . elements . forEach ( function ( el ) {
el . _walk ( visitor ) ;
} ) ;
} ) ;
}
} ) ;
var AST _Object = DEFNODE ( "Object" , "properties" , {
$documentation : "An object literal" ,
$propdoc : {
properties : "[AST_ObjectProperty*] array of properties"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . properties . forEach ( function ( prop ) {
prop . _walk ( visitor ) ;
} ) ;
} ) ;
}
} ) ;
var AST _ObjectProperty = DEFNODE ( "ObjectProperty" , "key value" , {
$documentation : "Base class for literal object properties" ,
$propdoc : {
key : "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node." ,
value : "[AST_Node] property value. For setters and getters this is an AST_Function."
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . value . _walk ( visitor ) ;
} ) ;
}
} ) ;
var AST _ObjectKeyVal = DEFNODE ( "ObjectKeyVal" , null , {
$documentation : "A key: value object property"
} , AST _ObjectProperty ) ;
var AST _ObjectSetter = DEFNODE ( "ObjectSetter" , null , {
$documentation : "An object setter property"
} , AST _ObjectProperty ) ;
var AST _ObjectGetter = DEFNODE ( "ObjectGetter" , null , {
$documentation : "An object getter property"
} , AST _ObjectProperty ) ;
var AST _Symbol = DEFNODE ( "Symbol" , "scope name thedef" , {
$propdoc : {
name : "[string] name of this symbol" ,
scope : "[AST_Scope/S] the current scope (not necessarily the definition scope)" ,
thedef : "[SymbolDef/S] the definition of this symbol"
} ,
$documentation : "Base class for all symbols"
} ) ;
var AST _SymbolAccessor = DEFNODE ( "SymbolAccessor" , null , {
$documentation : "The name of a property accessor (setter/getter function)"
} , AST _Symbol ) ;
var AST _SymbolDeclaration = DEFNODE ( "SymbolDeclaration" , "init" , {
$documentation : "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)" ,
$propdoc : {
init : "[AST_Node*/S] array of initializers for this declaration."
}
} , AST _Symbol ) ;
var AST _SymbolVar = DEFNODE ( "SymbolVar" , null , {
$documentation : "Symbol defining a variable"
} , AST _SymbolDeclaration ) ;
var AST _SymbolConst = DEFNODE ( "SymbolConst" , null , {
$documentation : "A constant declaration"
} , AST _SymbolDeclaration ) ;
var AST _SymbolFunarg = DEFNODE ( "SymbolFunarg" , null , {
$documentation : "Symbol naming a function argument"
} , AST _SymbolVar ) ;
var AST _SymbolDefun = DEFNODE ( "SymbolDefun" , null , {
$documentation : "Symbol defining a function"
} , AST _SymbolDeclaration ) ;
var AST _SymbolLambda = DEFNODE ( "SymbolLambda" , null , {
$documentation : "Symbol naming a function expression"
} , AST _SymbolDeclaration ) ;
var AST _SymbolCatch = DEFNODE ( "SymbolCatch" , null , {
$documentation : "Symbol naming the exception in catch"
} , AST _SymbolDeclaration ) ;
var AST _Label = DEFNODE ( "Label" , "references" , {
$documentation : "Symbol naming a label (declaration)" ,
$propdoc : {
references : "[AST_LoopControl*] a list of nodes referring to this label"
} ,
initialize : function ( ) {
this . references = [ ] ;
this . thedef = this ;
}
} , AST _Symbol ) ;
var AST _SymbolRef = DEFNODE ( "SymbolRef" , null , {
$documentation : "Reference to some symbol (not definition/declaration)"
} , AST _Symbol ) ;
var AST _LabelRef = DEFNODE ( "LabelRef" , null , {
$documentation : "Reference to a label symbol"
} , AST _Symbol ) ;
var AST _This = DEFNODE ( "This" , null , {
$documentation : "The `this` symbol"
} , AST _Symbol ) ;
var AST _Constant = DEFNODE ( "Constant" , null , {
$documentation : "Base class for all constants" ,
getValue : function ( ) {
return this . value ;
}
} ) ;
var AST _String = DEFNODE ( "String" , "value" , {
$documentation : "A string literal" ,
$propdoc : {
value : "[string] the contents of this string"
}
} , AST _Constant ) ;
var AST _Number = DEFNODE ( "Number" , "value" , {
$documentation : "A number literal" ,
$propdoc : {
value : "[number] the numeric value"
}
} , AST _Constant ) ;
var AST _RegExp = DEFNODE ( "RegExp" , "value" , {
$documentation : "A regexp literal" ,
$propdoc : {
value : "[RegExp] the actual regexp"
}
} , AST _Constant ) ;
var AST _Atom = DEFNODE ( "Atom" , null , {
$documentation : "Base class for atoms"
} , AST _Constant ) ;
var AST _Null = DEFNODE ( "Null" , null , {
$documentation : "The `null` atom" ,
value : null
} , AST _Atom ) ;
var AST _NaN = DEFNODE ( "NaN" , null , {
$documentation : "The impossible value" ,
value : 0 / 0
} , AST _Atom ) ;
var AST _Undefined = DEFNODE ( "Undefined" , null , {
$documentation : "The `undefined` value" ,
value : function ( ) { } ( )
} , AST _Atom ) ;
var AST _Hole = DEFNODE ( "Hole" , null , {
$documentation : "A hole in an array" ,
value : function ( ) { } ( )
} , AST _Atom ) ;
var AST _Infinity = DEFNODE ( "Infinity" , null , {
$documentation : "The `Infinity` value" ,
value : 1 / 0
} , AST _Atom ) ;
var AST _Boolean = DEFNODE ( "Boolean" , null , {
$documentation : "Base class for booleans"
} , AST _Atom ) ;
var AST _False = DEFNODE ( "False" , null , {
$documentation : "The `false` atom" ,
value : false
} , AST _Boolean ) ;
var AST _True = DEFNODE ( "True" , null , {
$documentation : "The `true` atom" ,
value : true
} , AST _Boolean ) ;
function TreeWalker ( callback ) {
this . visit = callback ;
this . stack = [ ] ;
}
TreeWalker . prototype = {
_visit : function ( node , descend ) {
this . stack . push ( node ) ;
var ret = this . visit ( node , descend ? function ( ) {
descend . call ( node ) ;
} : noop ) ;
if ( ! ret && descend ) {
descend . call ( node ) ;
}
this . stack . pop ( ) ;
return ret ;
} ,
parent : function ( n ) {
return this . stack [ this . stack . length - 2 - ( n || 0 ) ] ;
} ,
push : function ( node ) {
this . stack . push ( node ) ;
} ,
pop : function ( ) {
return this . stack . pop ( ) ;
} ,
self : function ( ) {
return this . stack [ this . stack . length - 1 ] ;
} ,
find _parent : function ( type ) {
var stack = this . stack ;
for ( var i = stack . length ; -- i >= 0 ; ) {
var x = stack [ i ] ;
if ( x instanceof type ) return x ;
}
} ,
has _directive : function ( type ) {
return this . find _parent ( AST _Scope ) . has _directive ( type ) ;
} ,
in _boolean _context : function ( ) {
var stack = this . stack ;
var i = stack . length , self = stack [ -- i ] ;
while ( i > 0 ) {
var p = stack [ -- i ] ;
if ( p instanceof AST _If && p . condition === self || p instanceof AST _Conditional && p . condition === self || p instanceof AST _DWLoop && p . condition === self || p instanceof AST _For && p . condition === self || p instanceof AST _UnaryPrefix && p . operator == "!" && p . expression === self ) {
return true ;
}
if ( ! ( p instanceof AST _Binary && ( p . operator == "&&" || p . operator == "||" ) ) ) return false ;
self = p ;
}
} ,
loopcontrol _target : function ( label ) {
var stack = this . stack ;
if ( label ) for ( var i = stack . length ; -- i >= 0 ; ) {
var x = stack [ i ] ;
if ( x instanceof AST _LabeledStatement && x . label . name == label . name ) {
return x . body ;
}
} else for ( var i = stack . length ; -- i >= 0 ; ) {
var x = stack [ i ] ;
if ( x instanceof AST _Switch || x instanceof AST _IterationStatement ) return x ;
}
}
} ;
"use strict" ;
var KEYWORDS = "break case catch const continue debugger default delete do else finally for function if in instanceof new return switch throw try typeof var void while with" ;
var KEYWORDS _ATOM = "false null true" ;
var RESERVED _WORDS = "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 this throws transient volatile yield" + " " + KEYWORDS _ATOM + " " + KEYWORDS ;
var KEYWORDS _BEFORE _EXPRESSION = "return new delete throw else case" ;
KEYWORDS = makePredicate ( KEYWORDS ) ;
RESERVED _WORDS = makePredicate ( RESERVED _WORDS ) ;
KEYWORDS _BEFORE _EXPRESSION = makePredicate ( KEYWORDS _BEFORE _EXPRESSION ) ;
KEYWORDS _ATOM = makePredicate ( KEYWORDS _ATOM ) ;
var OPERATOR _CHARS = makePredicate ( characters ( "+-*&%=<>!?|~^" ) ) ;
var RE _HEX _NUMBER = /^0x[0-9a-f]+$/i ;
var RE _OCT _NUMBER = /^0[0-7]+$/ ;
var RE _DEC _NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i ;
var OPERATORS = makePredicate ( [ "in" , "instanceof" , "typeof" , "new" , "void" , "delete" , "++" , "--" , "+" , "-" , "!" , "~" , "&" , "|" , "^" , "*" , "/" , "%" , ">>" , "<<" , ">>>" , "<" , ">" , "<=" , ">=" , "==" , "===" , "!=" , "!==" , "?" , "=" , "+=" , "-=" , "/=" , "*=" , "%=" , ">>=" , "<<=" , ">>>=" , "|=" , "^=" , "&=" , "&&" , "||" ] ) ;
var WHITESPACE _CHARS = makePredicate ( characters ( " \n\r \f " ) ) ;
var PUNC _BEFORE _EXPRESSION = makePredicate ( characters ( "[{(,.;:" ) ) ;
var PUNC _CHARS = makePredicate ( characters ( "[]{}(),;:" ) ) ;
var REGEXP _MODIFIERS = makePredicate ( characters ( "gmsiy" ) ) ;
var UNICODE = {
letter : new RegExp ( " [ \ \u0041 - \ \u005A \ \u0061 - \ \u007A \ \u00AA \ \u00B5 \ \u00BA \ \u00C0 - \ \u00D6 \ \u00D8 - \ \u00F6 \ \u00F8 - \ \u02C1 \ \u02C6 - \ \u02D1 \ \u02E0 - \ \u02E4 \ \u02EC \ \u02EE \ \u0370 - \ \u0374 \ \u0376 \ \u0377 \ \u037A - \ \u037D \ \u0386 \ \u0388 - \ \u038A \ \u038C \ \u038E - \ \u03A1 \ \u03A3 - \ \u03F5 \ \u03F7 - \ \u0481 \ \u048A - \ \u0523 \ \u0531 - \ \u0556 \ \u0559 \ \u0561 - \ \u0587 \ \u05D0 - \ \u05EA \ \u05F0 - \ \u05F2 \ \u0621 - \ \u064A \ \u066E \ \u066F \ \u0671 - \ \u06D3 \ \u06D5 \ \u06E5 \ \u06E6 \ \u06EE \ \u06EF \ \u06FA - \ \u06FC \ \u06FF \ \u0710 \ \u0712 - \ \u072F \ \u074D - \ \u07A5 \ \u07B1 \ \u07CA - \ \u07EA \ \u07F4 \ \u07F5 \ \u07FA \ \u0904 - \ \u0939 \ \u093D \ \u0950 \ \u0958 - \ \u0961 \ \u0971 \ \u0972 \ \u097B - \ \u097F \ \u0985 - \ \u098C \ \u098F \ \u0990 \ \u0993 - \ \u09A8 \ \u09AA - \ \u09B0 \ \u09B2 \ \u09B6 - \ \u09B9 \ \u09BD \ \u09CE \ \u09DC \ \u09DD \ \u09DF - \ \u09E1 \ \u09F0 \ \u09F1 \ \u0A05 - \ \u0A0A \ \u0A0F \ \u0A10 \ \u0A13 - \ \u0A28 \ \u0A2A - \ \u0A30 \ \u0A32 \ \u0A33 \ \u0A35 \ \u0A36 \ \u0A38 \ \u0A39 \ \u0A59 - \ \u0A5C \ \u0A5E \ \u0A72 - \ \u0A74 \ \u0A85 - \ \u0A8D \ \u0A8F - \ \u0A91 \ \u0A93 - \ \u0AA8 \ \u0AAA - \ \u0AB0 \ \u0AB2 \ \u0AB3 \ \u0AB5 - \ \u0AB9 \ \u0ABD \ \u0AD0 \ \u0AE0 \ \u0AE1 \ \u0B05 - \ \u0B0C \ \u0B0F \ \u0B10 \ \u0B13 - \ \u0B28 \ \u0B2A - \ \u0B30 \ \u0B32 \ \u0B33 \ \u0B35 - \ \u0B39 \ \u0B3D \ \u0B5C \ \u0B5D \ \u0B5F - \ \u0B61 \ \u0B71 \ \u0B83 \ \u0B85 - \ \u0B8A \ \u0B8E - \ \u0B90 \ \u0B92 - \ \u0B95 \ \u0B99 \ \u0B9A \ \u0B9C \ \u0B9E \ \u0B9F \ \u0BA3 \ \u0BA4 \ \u0BA8 - \ \u0BAA \ \u0BAE - \ \u0BB9 \ \u0BD0 \ \u0C05 - \ \u0C0C \ \u0C0E - \ \u0C10 \ \u0C12 - \ \u0C28 \ \u0C2A - \ \u0C33 \ \u0C35 - \ \u0C39 \ \u0C3D \ \u0C58 \ \u0C59 \ \u0C60 \ \u0C61 \ \u0C85 - \ \u0C8C \ \u0C8E - \ \u0C90 \ \u0C92 - \ \u0CA8 \ \u0CAA - \ \u0CB3 \ \u0CB5 - \ \u0CB9 \ \u0CBD \ \u0CDE \ \u0CE0 \ \u0CE1 \ \u0D05 - \ \u0D0C \ \u0D0E - \ \u0D10 \ \u0D12 - \ \u0D28 \ \u0D2A - \ \u0D39 \ \u0D3D \ \u0D60 \ \u0D61 \ \u0D7A - \ \u0D7F \ \u0D85 - \ \u0D96 \ \u0D9A - \ \u0DB1 \ \u0DB3 - \ \u0DBB \ \u0DBD \ \u0DC0 - \ \u0DC6 \ \u0E01 - \ \u0E30 \ \u0E32 \ \u0E33 \ \u0E40 - \ \u0E46 \ \u0E81 \ \u0E82 \ \u0E84 \ \u0E87 \ \u0E88 \ \u0E8A \ \u0E8D \ \u0E94 - \ \u0E97 \ \u0E99 - \ \u0E9F \ \u0EA1 - \ \u0EA3 \ \u0EA5 \ \u0EA7 \ \u0EAA \ \u0EAB \ \u0EAD - \ \u0EB0 \ \u0EB2 \ \u0EB3 \ \u0EBD \ \u0EC0 - \ \u0EC4 \ \u0EC6 \ \u0EDC \ \u0EDD \ \u0F00 \ \u0F40 - \ \u0F47 \ \u0F49 - \ \u0F6C \ \u0F88 - \ \u0F8B \ \u1000 - \ \u102A \ \u103F \ \u1050 - \ \u1055 \ \u105A - \ \u105D \ \u1061 \ \u1065 \ \u1066 \ \u106E - \ \u1070 \ \u1075 - \ \u1081 \ \u108E \ \u10A0 - \ \u10C5 \ \u10D0 - \ \u10FA \ \u10FC \ \u1100 - \ \u1159 \ \u115F - \ \u11A2 \ \u11A8 - \ \u11F9 \ \u1200 - \ \u1248 \ \u124A - \ \u124D \ \u1250 - \ \u1256 \ \u1258 \ \u125A - \ \u125D \ \u1260 - \ \u1288 \ \u128A - \ \u128D \ \u1290 - \ \u12B0 \ \u12B2 - \ \u12B5 \ \u12B8 - \ \u12BE \ \u12C0 \ \u12C2 - \ \u12C5 \ \u12C8 - \ \u12D6 \ \u12D8 - \ \u1310 \ \u1312 - \ \u1315 \ \u1318 - \ \u135A \ \u1380 - \ \u138F \ \u13A0 - \ \u13F4 \ \u1401 - \ \u166C \ \u166F - \ \u1676 \ \u1681 - \ \u169A \ \u16A0 - \ \u16EA \ \u1700 - \ \u170C \ \u170E - \ \u1711 \ \u1720 - \ \u1731 \ \u1740 - \ \u1751 \ \u1760 - \ \u176C \ \u176E - \ \u1770 \ \u1780 - \ \u17B3 \ \u17D7 \ \u17DC \ \u1820 - \ \u1877 \ \u1880 - \ \u18A8 \ \u18AA \ \u1900 - \ \u191C \ \u1950 - \ \u196D \ \u1970 - \ \u1974 \ \u1980 - \ \u19A9 \ \u19C1 - \ \u19C7 \ \u1A00 - \ \u1A16 \ \u1B05 - \ \u1B33 \ \u1B45 - \ \u1B4B \ \u1B83 - \ \u1BA0 \ \u1BAE \ \u1BAF \ \u1C00 - \ \u1C23 \ \u1C4D - \ \u1C4F \ \u1C5A - \ \u1C7D \ \u1D00 - \ \u1DBF \ \u1E00 - \ \u1F15 \ \u1F18 - \ \u1F1D \ \u1F20 - \ \u1F45 \ \u1F48 - \ \u1F4D \ \u1F50 - \ \u1F57 \ \u1F59 \ \u1F5B \ \u1F5D \ \u1F5F - \ \u1F7D \ \u1F80 - \ \u1FB4 \ \u1FB6 - \ \u1FBC \ \u1FBE \ \u1FC2 - \ \u1FC4 \ \u1FC6 - \ \u1FCC \ \u1FD0 - \ \u1FD3 \ \u1FD6 - \ \u1FDB \ \u1FE0 - \ \u1FEC \ \u1FF2 - \ \u1FF4 \ \u1FF6 - \ \u1FFC \ \u2071 \ \u207F \ \u2090 - \ \u2094 \ \u2102 \ \u2107 \ \u210A - \ \u2113 \ \u2115 \ \u2119 - \ \u211D \ \u2124 \ \u2126 \ \u2128 \ \u212A - \ \u212D \ \u212F - \ \u2139 \ \u213C - \ \u213F \ \u2145 - \ \u2149 \ \u214E \ \u2183 \ \u2184 \ \u2C00 - \ \u2C2E \ \u2C30 - \ \u2C5E \ \u2C60 - \ \u2C6F \ \u2C71 - \ \u2C7D \ \u2C80 - \ \u2CE4 \ \u2D00 - \ \u2D25 \ \u2D30 - \ \u2D65 \ \u2D6F \ \u2D80 - \ \u2D96 \ \u2DA0 - \ \u2DA6 \ \u2DA8 - \ \u2DAE \ \u2DB0 - \ \u2DB6 \ \u2DB8 - \ \u2DBE \ \u2DC0 - \ \u2DC6 \ \u2DC8 - \ \u2DCE \ \u2DD0 - \ \u2DD6 \ \u2DD8 - \ \u2DDE \ \u2E2F \ \u3005 \ \u3006 \ \u3031 - \ \u3035 \ \u303B \ \u303C \ \u3041 - \ \u3096 \ \u309D - \ \u309F \ \u30A1 - \ \u30FA \ \u30FC - \ \u30FF \ \u3105 - \ \u312D \ \u3131 - \ \u318E \ \u31A0 - \ \u31B7 \ \u31F0 - \ \u31FF \ \u3400 \ \u4DB5 \ \u4E00 \ \u9FC3 \ \uA000 - \ \uA48C \ \uA500 - \ \uA60C \ \uA610 - \ \uA61F \ \uA62A \ \uA62B \ \uA640 - \ \uA65F \ \uA662 - \ \uA66E \ \uA67F - \ \uA697 \ \uA717 - \ \uA71F \ \uA722 - \ \uA788 \ \uA78B \ \uA78C \ \uA7FB - \ \uA801 \ \uA803 - \ \uA805 \ \uA807 - \ \uA80A \ \uA80C - \ \uA822 \ \uA840 - \ \uA873 \ \uA882 - \ \uA8B3 \ \uA90A - \ \uA925 \ \uA930 - \ \uA946 \ \uAA00 - \ \uAA28 \ \uAA40 - \ \uAA42 \ \uAA44 - \ \uAA4B \ \uAC00 \ \uD7A3 \ \uF900 - \ \uFA2D \ \uFA30 - \ \uFA6A \ \uFA70 - \ \uFAD9 \ \uFB00 - \ \uFB06 \ \ uFB1
non _spacing _mark : new RegExp ( "[\\u0300-\\u036F\\u0483-\\u0487\\u0591-\\u05BD\\u05BF\\u05C1\\u05C2\\u05C4\\u05C5\\u05C7\\u0610-\\u061A\\u064B-\\u065E\\u0670\\u06D6-\\u06DC\\u06DF-\\u06E4\\u06E7\\u06E8\\u06EA-\\u06ED\\u0711\\u0730-\\u074A\\u07A6-\\u07B0\\u07EB-\\u07F3\\u0816-\\u0819\\u081B-\\u0823\\u0825-\\u0827\\u0829-\\u082D\\u0900-\\u0902\\u093C\\u0941-\\u0948\\u094D\\u0951-\\u0955\\u0962\\u0963\\u0981\\u09BC\\u09C1-\\u09C4\\u09CD\\u09E2\\u09E3\\u0A01\\u0A02\\u0A3C\\u0A41\\u0A42\\u0A47\\u0A48\\u0A4B-\\u0A4D\\u0A51\\u0A70\\u0A71\\u0A75\\u0A81\\u0A82\\u0ABC\\u0AC1-\\u0AC5\\u0AC7\\u0AC8\\u0ACD\\u0AE2\\u0AE3\\u0B01\\u0B3C\\u0B3F\\u0B41-\\u0B44\\u0B4D\\u0B56\\u0B62\\u0B63\\u0B82\\u0BC0\\u0BCD\\u0C3E-\\u0C40\\u0C46-\\u0C48\\u0C4A-\\u0C4D\\u0C55\\u0C56\\u0C62\\u0C63\\u0CBC\\u0CBF\\u0CC6\\u0CCC\\u0CCD\\u0CE2\\u0CE3\\u0D41-\\u0D44\\u0D4D\\u0D62\\u0D63\\u0DCA\\u0DD2-\\u0DD4\\u0DD6\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E\\u0EB1\\u0EB4-\\u0EB9\\u0EBB\\u0EBC\\u0EC8-\\u0ECD\\u0F18\\u0F19\\u0F35\\u0F37\\u0F39\\u0F71-\\u0F7E\\u0F80-\\u0F84\\u0F86\\u0F87\\u0F90-\\u0F97\\u0F99-\\u0FBC\\u0FC6\\u102D-\\u1030\\u1032-\\u1037\\u1039\\u103A\\u103D\\u103E\\u1058\\u1059\\u105E-\\u1060\\u1071-\\u1074\\u1082\\u1085\\u1086\\u108D\\u109D\\u135F\\u1712-\\u1714\\u1732-\\u1734\\u1752\\u1753\\u1772\\u1773\\u17B7-\\u17BD\\u17C6\\u17C9-\\u17D3\\u17DD\\u180B-\\u180D\\u18A9\\u1920-\\u1922\\u1927\\u1928\\u1932\\u1939-\\u193B\\u1A17\\u1A18\\u1A56\\u1A58-\\u1A5E\\u1A60\\u1A62\\u1A65-\\u1A6C\\u1A73-\\u1A7C\\u1A7F\\u1B00-\\u1B03\\u1B34\\u1B36-\\u1B3A\\u1B3C\\u1B42\\u1B6B-\\u1B73\\u1B80\\u1B81\\u1BA2-\\u1BA5\\u1BA8\\u1BA9\\u1C2C-\\u1C33\\u1C36\\u1C37\\u1CD0-\\u1CD2\\u1CD4-\\u1CE0\\u1CE2-\\u1CE8\\u1CED\\u1DC0-\\u1DE6\\u1DFD-\\u1DFF\\u20D0-\\u20DC\\u20E1\\u20E5-\\u20F0\\u2CEF-\\u2CF1\\u2DE0-\\u2DFF\\u302A-\\u302F\\u3099\\u309A\\uA66F\\uA67C\\uA67D\\uA6F0\\uA6F1\\uA802\\uA806\\uA80B\\uA825\\uA826\\uA8C4\\uA8E0-\\uA8F1\\uA926-\\uA92D\\uA947-\\uA951\\uA980-\\uA982\\uA9B3\\uA9B6-\\uA9B9\\uA9BC\\uAA29-\\uAA2E\\uAA31\\uAA32\\uAA35\\uAA36\\uAA43\\uAA4C\\uAAB0\\uAAB2-\\uAAB4\\uAAB7\\uAAB8\\uAABE\\uAABF\\uAAC1\\uABE5\\uABE8\\uABED\\uFB1E\\uFE00-\\uFE0F\\uFE20-\\uFE26]" ) ,
space _combining _mark : new RegExp ( "[\\u0903\\u093E-\\u0940\\u0949-\\u094C\\u094E\\u0982\\u0983\\u09BE-\\u09C0\\u09C7\\u09C8\\u09CB\\u09CC\\u09D7\\u0A03\\u0A3E-\\u0A40\\u0A83\\u0ABE-\\u0AC0\\u0AC9\\u0ACB\\u0ACC\\u0B02\\u0B03\\u0B3E\\u0B40\\u0B47\\u0B48\\u0B4B\\u0B4C\\u0B57\\u0BBE\\u0BBF\\u0BC1\\u0BC2\\u0BC6-\\u0BC8\\u0BCA-\\u0BCC\\u0BD7\\u0C01-\\u0C03\\u0C41-\\u0C44\\u0C82\\u0C83\\u0CBE\\u0CC0-\\u0CC4\\u0CC7\\u0CC8\\u0CCA\\u0CCB\\u0CD5\\u0CD6\\u0D02\\u0D03\\u0D3E-\\u0D40\\u0D46-\\u0D48\\u0D4A-\\u0D4C\\u0D57\\u0D82\\u0D83\\u0DCF-\\u0DD1\\u0DD8-\\u0DDF\\u0DF2\\u0DF3\\u0F3E\\u0F3F\\u0F7F\\u102B\\u102C\\u1031\\u1038\\u103B\\u103C\\u1056\\u1057\\u1062-\\u1064\\u1067-\\u106D\\u1083\\u1084\\u1087-\\u108C\\u108F\\u109A-\\u109C\\u17B6\\u17BE-\\u17C5\\u17C7\\u17C8\\u1923-\\u1926\\u1929-\\u192B\\u1930\\u1931\\u1933-\\u1938\\u19B0-\\u19C0\\u19C8\\u19C9\\u1A19-\\u1A1B\\u1A55\\u1A57\\u1A61\\u1A63\\u1A64\\u1A6D-\\u1A72\\u1B04\\u1B35\\u1B3B\\u1B3D-\\u1B41\\u1B43\\u1B44\\u1B82\\u1BA1\\u1BA6\\u1BA7\\u1BAA\\u1C24-\\u1C2B\\u1C34\\u1C35\\u1CE1\\u1CF2\\uA823\\uA824\\uA827\\uA880\\uA881\\uA8B4-\\uA8C3\\uA952\\uA953\\uA983\\uA9B4\\uA9B5\\uA9BA\\uA9BB\\uA9BD-\\uA9C0\\uAA2F\\uAA30\\uAA33\\uAA34\\uAA4D\\uAA7B\\uABE3\\uABE4\\uABE6\\uABE7\\uABE9\\uABEA\\uABEC]" ) ,
connector _punctuation : new RegExp ( "[\\u005F\\u203F\\u2040\\u2054\\uFE33\\uFE34\\uFE4D-\\uFE4F\\uFF3F]" )
} ;
function is _letter ( code ) {
return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 170 && UNICODE . letter . test ( String . fromCharCode ( code ) ) ;
}
function is _digit ( code ) {
return code >= 48 && code <= 57 ;
}
function is _alphanumeric _char ( code ) {
return is _digit ( code ) || is _letter ( code ) ;
}
function is _unicode _combining _mark ( ch ) {
return UNICODE . non _spacing _mark . test ( ch ) || UNICODE . space _combining _mark . test ( ch ) ;
}
function is _unicode _connector _punctuation ( ch ) {
return UNICODE . connector _punctuation . test ( ch ) ;
}
function is _identifier ( name ) {
return ! RESERVED _WORDS ( name ) && /^[a-z_$][a-z0-9_$]*$/i . test ( name ) ;
}
function is _identifier _start ( code ) {
return code == 36 || code == 95 || is _letter ( code ) ;
}
function is _identifier _char ( ch ) {
var code = ch . charCodeAt ( 0 ) ;
return is _identifier _start ( code ) || is _digit ( code ) || code == 8204 || code == 8205 || is _unicode _combining _mark ( ch ) || is _unicode _connector _punctuation ( ch ) ;
}
function is _identifier _string ( str ) {
return /^[a-z_$][a-z0-9_$]*$/i . test ( str ) ;
}
function parse _js _number ( num ) {
if ( RE _HEX _NUMBER . test ( num ) ) {
return parseInt ( num . substr ( 2 ) , 16 ) ;
} else if ( RE _OCT _NUMBER . test ( num ) ) {
return parseInt ( num . substr ( 1 ) , 8 ) ;
} else if ( RE _DEC _NUMBER . test ( num ) ) {
return parseFloat ( num ) ;
}
}
function JS _Parse _Error ( message , line , col , pos ) {
this . message = message ;
this . line = line ;
this . col = col ;
this . pos = pos ;
this . stack = new Error ( ) . stack ;
}
JS _Parse _Error . prototype . toString = function ( ) {
return this . message + " (line: " + this . line + ", col: " + this . col + ", pos: " + this . pos + ")" + "\n\n" + this . stack ;
} ;
function js _error ( message , filename , line , col , pos ) {
throw new JS _Parse _Error ( message , line , col , pos ) ;
}
function is _token ( token , type , val ) {
return token . type == type && ( val == null || token . value == val ) ;
}
var EX _EOF = { } ;
function tokenizer ( $TEXT , filename , html5 _comments ) {
var S = {
text : $TEXT . replace ( /\r\n?|[\n\u2028\u2029]/g , "\n" ) . replace ( /\uFEFF/g , "" ) ,
filename : filename ,
pos : 0 ,
tokpos : 0 ,
line : 1 ,
tokline : 0 ,
col : 0 ,
tokcol : 0 ,
newline _before : false ,
regex _allowed : false ,
comments _before : [ ]
} ;
function peek ( ) {
return S . text . charAt ( S . pos ) ;
}
function next ( signal _eof , in _string ) {
var ch = S . text . charAt ( S . pos ++ ) ;
if ( signal _eof && ! ch ) throw EX _EOF ;
if ( ch == "\n" ) {
S . newline _before = S . newline _before || ! in _string ;
++ S . line ;
S . col = 0 ;
} else {
++ S . col ;
}
return ch ;
}
function forward ( i ) {
while ( i -- > 0 ) next ( ) ;
}
function looking _at ( str ) {
return S . text . substr ( S . pos , str . length ) == str ;
}
function find ( what , signal _eof ) {
var pos = S . text . indexOf ( what , S . pos ) ;
if ( signal _eof && pos == - 1 ) throw EX _EOF ;
return pos ;
}
function start _token ( ) {
S . tokline = S . line ;
S . tokcol = S . col ;
S . tokpos = S . pos ;
}
var prev _was _dot = false ;
function token ( type , value , is _comment ) {
S . regex _allowed = type == "operator" && ! UNARY _POSTFIX ( value ) || type == "keyword" && KEYWORDS _BEFORE _EXPRESSION ( value ) || type == "punc" && PUNC _BEFORE _EXPRESSION ( value ) ;
prev _was _dot = type == "punc" && value == "." ;
var ret = {
type : type ,
value : value ,
line : S . tokline ,
col : S . tokcol ,
pos : S . tokpos ,
endpos : S . pos ,
nlb : S . newline _before ,
file : filename
} ;
if ( ! is _comment ) {
ret . comments _before = S . comments _before ;
S . comments _before = [ ] ;
for ( var i = 0 , len = ret . comments _before . length ; i < len ; i ++ ) {
ret . nlb = ret . nlb || ret . comments _before [ i ] . nlb ;
}
}
S . newline _before = false ;
return new AST _Token ( ret ) ;
}
function skip _whitespace ( ) {
while ( WHITESPACE _CHARS ( peek ( ) ) ) next ( ) ;
}
function read _while ( pred ) {
var ret = "" , ch , i = 0 ;
while ( ( ch = peek ( ) ) && pred ( ch , i ++ ) ) ret += next ( ) ;
return ret ;
}
function parse _error ( err ) {
js _error ( err , filename , S . tokline , S . tokcol , S . tokpos ) ;
}
function read _num ( prefix ) {
var has _e = false , after _e = false , has _x = false , has _dot = prefix == "." ;
var num = read _while ( function ( ch , i ) {
var code = ch . charCodeAt ( 0 ) ;
switch ( code ) {
case 120 :
case 88 :
return has _x ? false : has _x = true ;
case 101 :
case 69 :
return has _x ? true : has _e ? false : has _e = after _e = true ;
case 45 :
return after _e || i == 0 && ! prefix ;
case 43 :
return after _e ;
case after _e = false , 46 :
return ! has _dot && ! has _x && ! has _e ? has _dot = true : false ;
}
return is _alphanumeric _char ( code ) ;
} ) ;
if ( prefix ) num = prefix + num ;
var valid = parse _js _number ( num ) ;
if ( ! isNaN ( valid ) ) {
return token ( "num" , valid ) ;
} else {
parse _error ( "Invalid syntax: " + num ) ;
}
}
function read _escaped _char ( in _string ) {
var ch = next ( true , in _string ) ;
switch ( ch . charCodeAt ( 0 ) ) {
case 110 :
return "\n" ;
case 114 :
return "\r" ;
case 116 :
return " " ;
case 98 :
return "\b" ;
case 118 :
return " " ;
case 102 :
return "\f" ;
case 48 :
return "\x00" ;
case 120 :
return String . fromCharCode ( hex _bytes ( 2 ) ) ;
case 117 :
return String . fromCharCode ( hex _bytes ( 4 ) ) ;
case 10 :
return "" ;
default :
return ch ;
}
}
function hex _bytes ( n ) {
var num = 0 ;
for ( ; n > 0 ; -- n ) {
var digit = parseInt ( next ( true ) , 16 ) ;
if ( isNaN ( digit ) ) parse _error ( "Invalid hex-character pattern in string" ) ;
num = num << 4 | digit ;
}
return num ;
}
var read _string = with _eof _error ( "Unterminated string constant" , function ( ) {
var quote = next ( ) , ret = "" ;
for ( ; ; ) {
var ch = next ( true ) ;
if ( ch == "\\" ) {
var octal _len = 0 , first = null ;
ch = read _while ( function ( ch ) {
if ( ch >= "0" && ch <= "7" ) {
if ( ! first ) {
first = ch ;
return ++ octal _len ;
} else if ( first <= "3" && octal _len <= 2 ) return ++ octal _len ; else if ( first >= "4" && octal _len <= 1 ) return ++ octal _len ;
}
return false ;
} ) ;
if ( octal _len > 0 ) ch = String . fromCharCode ( parseInt ( ch , 8 ) ) ; else ch = read _escaped _char ( true ) ;
} else if ( ch == quote ) break ;
ret += ch ;
}
return token ( "string" , ret ) ;
} ) ;
function skip _line _comment ( type ) {
var regex _allowed = S . regex _allowed ;
var i = find ( "\n" ) , ret ;
if ( i == - 1 ) {
ret = S . text . substr ( S . pos ) ;
S . pos = S . text . length ;
} else {
ret = S . text . substring ( S . pos , i ) ;
S . pos = i ;
}
S . comments _before . push ( token ( type , ret , true ) ) ;
S . regex _allowed = regex _allowed ;
return next _token ( ) ;
}
var skip _multiline _comment = with _eof _error ( "Unterminated multiline comment" , function ( ) {
var regex _allowed = S . regex _allowed ;
var i = find ( "*/" , true ) ;
var text = S . text . substring ( S . pos , i ) ;
var a = text . split ( "\n" ) , n = a . length ;
S . pos = i + 2 ;
S . line += n - 1 ;
if ( n > 1 ) S . col = a [ n - 1 ] . length ; else S . col += a [ n - 1 ] . length ;
S . col += 2 ;
var nlb = S . newline _before = S . newline _before || text . indexOf ( "\n" ) >= 0 ;
S . comments _before . push ( token ( "comment2" , text , true ) ) ;
S . regex _allowed = regex _allowed ;
S . newline _before = nlb ;
return next _token ( ) ;
} ) ;
function read _name ( ) {
var backslash = false , name = "" , ch , escaped = false , hex ;
while ( ( ch = peek ( ) ) != null ) {
if ( ! backslash ) {
if ( ch == "\\" ) escaped = backslash = true , next ( ) ; else if ( is _identifier _char ( ch ) ) name += next ( ) ; else break ;
} else {
if ( ch != "u" ) parse _error ( "Expecting UnicodeEscapeSequence -- uXXXX" ) ;
ch = read _escaped _char ( ) ;
if ( ! is _identifier _char ( ch ) ) parse _error ( "Unicode char: " + ch . charCodeAt ( 0 ) + " is not valid in identifier" ) ;
name += ch ;
backslash = false ;
}
}
if ( KEYWORDS ( name ) && escaped ) {
hex = name . charCodeAt ( 0 ) . toString ( 16 ) . toUpperCase ( ) ;
name = "\\u" + "0000" . substr ( hex . length ) + hex + name . slice ( 1 ) ;
}
return name ;
}
var read _regexp = with _eof _error ( "Unterminated regular expression" , function ( regexp ) {
var prev _backslash = false , ch , in _class = false ;
while ( ch = next ( true ) ) if ( prev _backslash ) {
regexp += "\\" + ch ;
prev _backslash = false ;
} else if ( ch == "[" ) {
in _class = true ;
regexp += ch ;
} else if ( ch == "]" && in _class ) {
in _class = false ;
regexp += ch ;
} else if ( ch == "/" && ! in _class ) {
break ;
} else if ( ch == "\\" ) {
prev _backslash = true ;
} else {
regexp += ch ;
}
var mods = read _name ( ) ;
return token ( "regexp" , new RegExp ( regexp , mods ) ) ;
} ) ;
function read _operator ( prefix ) {
function grow ( op ) {
if ( ! peek ( ) ) return op ;
var bigger = op + peek ( ) ;
if ( OPERATORS ( bigger ) ) {
next ( ) ;
return grow ( bigger ) ;
} else {
return op ;
}
}
return token ( "operator" , grow ( prefix || next ( ) ) ) ;
}
function handle _slash ( ) {
next ( ) ;
switch ( peek ( ) ) {
case "/" :
next ( ) ;
return skip _line _comment ( "comment1" ) ;
case "*" :
next ( ) ;
return skip _multiline _comment ( ) ;
}
return S . regex _allowed ? read _regexp ( "" ) : read _operator ( "/" ) ;
}
function handle _dot ( ) {
next ( ) ;
return is _digit ( peek ( ) . charCodeAt ( 0 ) ) ? read _num ( "." ) : token ( "punc" , "." ) ;
}
function read _word ( ) {
var word = read _name ( ) ;
if ( prev _was _dot ) return token ( "name" , word ) ;
return KEYWORDS _ATOM ( word ) ? token ( "atom" , word ) : ! KEYWORDS ( word ) ? token ( "name" , word ) : OPERATORS ( word ) ? token ( "operator" , word ) : token ( "keyword" , word ) ;
}
function with _eof _error ( eof _error , cont ) {
return function ( x ) {
try {
return cont ( x ) ;
} catch ( ex ) {
if ( ex === EX _EOF ) parse _error ( eof _error ) ; else throw ex ;
}
} ;
}
function next _token ( force _regexp ) {
if ( force _regexp != null ) return read _regexp ( force _regexp ) ;
skip _whitespace ( ) ;
start _token ( ) ;
if ( html5 _comments ) {
if ( looking _at ( "<!--" ) ) {
forward ( 4 ) ;
return skip _line _comment ( "comment3" ) ;
}
if ( looking _at ( "-->" ) && S . newline _before ) {
forward ( 3 ) ;
return skip _line _comment ( "comment4" ) ;
}
}
var ch = peek ( ) ;
if ( ! ch ) return token ( "eof" ) ;
var code = ch . charCodeAt ( 0 ) ;
switch ( code ) {
case 34 :
case 39 :
return read _string ( ) ;
case 46 :
return handle _dot ( ) ;
case 47 :
return handle _slash ( ) ;
}
if ( is _digit ( code ) ) return read _num ( ) ;
if ( PUNC _CHARS ( ch ) ) return token ( "punc" , next ( ) ) ;
if ( OPERATOR _CHARS ( ch ) ) return read _operator ( ) ;
if ( code == 92 || is _identifier _start ( code ) ) return read _word ( ) ;
parse _error ( "Unexpected character '" + ch + "'" ) ;
}
next _token . context = function ( nc ) {
if ( nc ) S = nc ;
return S ;
} ;
return next _token ;
}
var UNARY _PREFIX = makePredicate ( [ "typeof" , "void" , "delete" , "--" , "++" , "!" , "~" , "-" , "+" ] ) ;
var UNARY _POSTFIX = makePredicate ( [ "--" , "++" ] ) ;
var ASSIGNMENT = makePredicate ( [ "=" , "+=" , "-=" , "/=" , "*=" , "%=" , ">>=" , "<<=" , ">>>=" , "|=" , "^=" , "&=" ] ) ;
var PRECEDENCE = function ( a , ret ) {
for ( var i = 0 ; i < a . length ; ++ i ) {
var b = a [ i ] ;
for ( var j = 0 ; j < b . length ; ++ j ) {
ret [ b [ j ] ] = i + 1 ;
}
}
return ret ;
} ( [ [ "||" ] , [ "&&" ] , [ "|" ] , [ "^" ] , [ "&" ] , [ "==" , "===" , "!=" , "!==" ] , [ "<" , ">" , "<=" , ">=" , "in" , "instanceof" ] , [ ">>" , "<<" , ">>>" ] , [ "+" , "-" ] , [ "*" , "/" , "%" ] ] , { } ) ;
var STATEMENTS _WITH _LABELS = array _to _hash ( [ "for" , "do" , "while" , "switch" ] ) ;
var ATOMIC _START _TOKEN = array _to _hash ( [ "atom" , "num" , "string" , "regexp" , "name" ] ) ;
function parse ( $TEXT , options ) {
options = defaults ( options , {
strict : false ,
filename : null ,
toplevel : null ,
expression : false ,
html5 _comments : true
} ) ;
var S = {
input : typeof $TEXT == "string" ? tokenizer ( $TEXT , options . filename , options . html5 _comments ) : $TEXT ,
token : null ,
prev : null ,
peeked : null ,
in _function : 0 ,
in _directives : true ,
in _loop : 0 ,
labels : [ ]
} ;
S . token = next ( ) ;
function is ( type , value ) {
return is _token ( S . token , type , value ) ;
}
function peek ( ) {
return S . peeked || ( S . peeked = S . input ( ) ) ;
}
function next ( ) {
S . prev = S . token ;
if ( S . peeked ) {
S . token = S . peeked ;
S . peeked = null ;
} else {
S . token = S . input ( ) ;
}
S . in _directives = S . in _directives && ( S . token . type == "string" || is ( "punc" , ";" ) ) ;
return S . token ;
}
function prev ( ) {
return S . prev ;
}
function croak ( msg , line , col , pos ) {
var ctx = S . input . context ( ) ;
js _error ( msg , ctx . filename , line != null ? line : ctx . tokline , col != null ? col : ctx . tokcol , pos != null ? pos : ctx . tokpos ) ;
}
function token _error ( token , msg ) {
croak ( msg , token . line , token . col ) ;
}
function unexpected ( token ) {
if ( token == null ) token = S . token ;
token _error ( token , "Unexpected token: " + token . type + " (" + token . value + ")" ) ;
}
function expect _token ( type , val ) {
if ( is ( type , val ) ) {
return next ( ) ;
}
token _error ( S . token , "Unexpected token " + S . token . type + " «" + S . token . value + "»" + ", expected " + type + " «" + val + "»" ) ;
}
function expect ( punc ) {
return expect _token ( "punc" , punc ) ;
}
function can _insert _semicolon ( ) {
return ! options . strict && ( S . token . nlb || is ( "eof" ) || is ( "punc" , "}" ) ) ;
}
function semicolon ( ) {
if ( is ( "punc" , ";" ) ) next ( ) ; else if ( ! can _insert _semicolon ( ) ) unexpected ( ) ;
}
function parenthesised ( ) {
expect ( "(" ) ;
var exp = expression ( true ) ;
expect ( ")" ) ;
return exp ;
}
function embed _tokens ( parser ) {
return function ( ) {
var start = S . token ;
var expr = parser ( ) ;
var end = prev ( ) ;
expr . start = start ;
expr . end = end ;
return expr ;
} ;
}
function handle _regexp ( ) {
if ( is ( "operator" , "/" ) || is ( "operator" , "/=" ) ) {
S . peeked = null ;
S . token = S . input ( S . token . value . substr ( 1 ) ) ;
}
}
var statement = embed _tokens ( function ( ) {
var tmp ;
handle _regexp ( ) ;
switch ( S . token . type ) {
case "string" :
var dir = S . in _directives , stat = simple _statement ( ) ;
if ( dir && stat . body instanceof AST _String && ! is ( "punc" , "," ) ) return new AST _Directive ( {
value : stat . body . value
} ) ;
return stat ;
case "num" :
case "regexp" :
case "operator" :
case "atom" :
return simple _statement ( ) ;
case "name" :
return is _token ( peek ( ) , "punc" , ":" ) ? labeled _statement ( ) : simple _statement ( ) ;
case "punc" :
switch ( S . token . value ) {
case "{" :
return new AST _BlockStatement ( {
start : S . token ,
body : block _ ( ) ,
end : prev ( )
} ) ;
case "[" :
case "(" :
return simple _statement ( ) ;
case ";" :
next ( ) ;
return new AST _EmptyStatement ( ) ;
default :
unexpected ( ) ;
}
case "keyword" :
switch ( tmp = S . token . value , next ( ) , tmp ) {
case "break" :
return break _cont ( AST _Break ) ;
case "continue" :
return break _cont ( AST _Continue ) ;
case "debugger" :
semicolon ( ) ;
return new AST _Debugger ( ) ;
case "do" :
return new AST _Do ( {
body : in _loop ( statement ) ,
condition : ( expect _token ( "keyword" , "while" ) , tmp = parenthesised ( ) , semicolon ( ) ,
tmp )
} ) ;
case "while" :
return new AST _While ( {
condition : parenthesised ( ) ,
body : in _loop ( statement )
} ) ;
case "for" :
return for _ ( ) ;
case "function" :
return function _ ( AST _Defun ) ;
case "if" :
return if _ ( ) ;
case "return" :
if ( S . in _function == 0 ) croak ( "'return' outside of function" ) ;
return new AST _Return ( {
value : is ( "punc" , ";" ) ? ( next ( ) , null ) : can _insert _semicolon ( ) ? null : ( tmp = expression ( true ) ,
semicolon ( ) , tmp )
} ) ;
case "switch" :
return new AST _Switch ( {
expression : parenthesised ( ) ,
body : in _loop ( switch _body _ )
} ) ;
case "throw" :
if ( S . token . nlb ) croak ( "Illegal newline after 'throw'" ) ;
return new AST _Throw ( {
value : ( tmp = expression ( true ) , semicolon ( ) , tmp )
} ) ;
case "try" :
return try _ ( ) ;
case "var" :
return tmp = var _ ( ) , semicolon ( ) , tmp ;
case "const" :
return tmp = const _ ( ) , semicolon ( ) , tmp ;
case "with" :
return new AST _With ( {
expression : parenthesised ( ) ,
body : statement ( )
} ) ;
default :
unexpected ( ) ;
}
}
} ) ;
function labeled _statement ( ) {
var label = as _symbol ( AST _Label ) ;
if ( find _if ( function ( l ) {
return l . name == label . name ;
} , S . labels ) ) {
croak ( "Label " + label . name + " defined twice" ) ;
}
expect ( ":" ) ;
S . labels . push ( label ) ;
var stat = statement ( ) ;
S . labels . pop ( ) ;
if ( ! ( stat instanceof AST _IterationStatement ) ) {
label . references . forEach ( function ( ref ) {
if ( ref instanceof AST _Continue ) {
ref = ref . label . start ;
croak ( "Continue label `" + label . name + "` refers to non-IterationStatement." , ref . line , ref . col , ref . pos ) ;
}
} ) ;
}
return new AST _LabeledStatement ( {
body : stat ,
label : label
} ) ;
}
function simple _statement ( tmp ) {
return new AST _SimpleStatement ( {
body : ( tmp = expression ( true ) , semicolon ( ) , tmp )
} ) ;
}
function break _cont ( type ) {
var label = null , ldef ;
if ( ! can _insert _semicolon ( ) ) {
label = as _symbol ( AST _LabelRef , true ) ;
}
if ( label != null ) {
ldef = find _if ( function ( l ) {
return l . name == label . name ;
} , S . labels ) ;
if ( ! ldef ) croak ( "Undefined label " + label . name ) ;
label . thedef = ldef ;
} else if ( S . in _loop == 0 ) croak ( type . TYPE + " not inside a loop or switch" ) ;
semicolon ( ) ;
var stat = new type ( {
label : label
} ) ;
if ( ldef ) ldef . references . push ( stat ) ;
return stat ;
}
function for _ ( ) {
expect ( "(" ) ;
var init = null ;
if ( ! is ( "punc" , ";" ) ) {
init = is ( "keyword" , "var" ) ? ( next ( ) , var _ ( true ) ) : expression ( true , true ) ;
if ( is ( "operator" , "in" ) ) {
if ( init instanceof AST _Var && init . definitions . length > 1 ) croak ( "Only one variable declaration allowed in for..in loop" ) ;
next ( ) ;
return for _in ( init ) ;
}
}
return regular _for ( init ) ;
}
function regular _for ( init ) {
expect ( ";" ) ;
var test = is ( "punc" , ";" ) ? null : expression ( true ) ;
expect ( ";" ) ;
var step = is ( "punc" , ")" ) ? null : expression ( true ) ;
expect ( ")" ) ;
return new AST _For ( {
init : init ,
condition : test ,
step : step ,
body : in _loop ( statement )
} ) ;
}
function for _in ( init ) {
var lhs = init instanceof AST _Var ? init . definitions [ 0 ] . name : null ;
var obj = expression ( true ) ;
expect ( ")" ) ;
return new AST _ForIn ( {
init : init ,
name : lhs ,
object : obj ,
body : in _loop ( statement )
} ) ;
}
var function _ = function ( ctor ) {
var in _statement = ctor === AST _Defun ;
var name = is ( "name" ) ? as _symbol ( in _statement ? AST _SymbolDefun : AST _SymbolLambda ) : null ;
if ( in _statement && ! name ) unexpected ( ) ;
expect ( "(" ) ;
return new ctor ( {
name : name ,
argnames : function ( first , a ) {
while ( ! is ( "punc" , ")" ) ) {
if ( first ) first = false ; else expect ( "," ) ;
a . push ( as _symbol ( AST _SymbolFunarg ) ) ;
}
next ( ) ;
return a ;
} ( true , [ ] ) ,
body : function ( loop , labels ) {
++ S . in _function ;
S . in _directives = true ;
S . in _loop = 0 ;
S . labels = [ ] ;
var a = block _ ( ) ;
-- S . in _function ;
S . in _loop = loop ;
S . labels = labels ;
return a ;
} ( S . in _loop , S . labels )
} ) ;
} ;
function if _ ( ) {
var cond = parenthesised ( ) , body = statement ( ) , belse = null ;
if ( is ( "keyword" , "else" ) ) {
next ( ) ;
belse = statement ( ) ;
}
return new AST _If ( {
condition : cond ,
body : body ,
alternative : belse
} ) ;
}
function block _ ( ) {
expect ( "{" ) ;
var a = [ ] ;
while ( ! is ( "punc" , "}" ) ) {
if ( is ( "eof" ) ) unexpected ( ) ;
a . push ( statement ( ) ) ;
}
next ( ) ;
return a ;
}
function switch _body _ ( ) {
expect ( "{" ) ;
var a = [ ] , cur = null , branch = null , tmp ;
while ( ! is ( "punc" , "}" ) ) {
if ( is ( "eof" ) ) unexpected ( ) ;
if ( is ( "keyword" , "case" ) ) {
if ( branch ) branch . end = prev ( ) ;
cur = [ ] ;
branch = new AST _Case ( {
start : ( tmp = S . token , next ( ) , tmp ) ,
expression : expression ( true ) ,
body : cur
} ) ;
a . push ( branch ) ;
expect ( ":" ) ;
} else if ( is ( "keyword" , "default" ) ) {
if ( branch ) branch . end = prev ( ) ;
cur = [ ] ;
branch = new AST _Default ( {
start : ( tmp = S . token , next ( ) , expect ( ":" ) , tmp ) ,
body : cur
} ) ;
a . push ( branch ) ;
} else {
if ( ! cur ) unexpected ( ) ;
cur . push ( statement ( ) ) ;
}
}
if ( branch ) branch . end = prev ( ) ;
next ( ) ;
return a ;
}
function try _ ( ) {
var body = block _ ( ) , bcatch = null , bfinally = null ;
if ( is ( "keyword" , "catch" ) ) {
var start = S . token ;
next ( ) ;
expect ( "(" ) ;
var name = as _symbol ( AST _SymbolCatch ) ;
expect ( ")" ) ;
bcatch = new AST _Catch ( {
start : start ,
argname : name ,
body : block _ ( ) ,
end : prev ( )
} ) ;
}
if ( is ( "keyword" , "finally" ) ) {
var start = S . token ;
next ( ) ;
bfinally = new AST _Finally ( {
start : start ,
body : block _ ( ) ,
end : prev ( )
} ) ;
}
if ( ! bcatch && ! bfinally ) croak ( "Missing catch/finally blocks" ) ;
return new AST _Try ( {
body : body ,
bcatch : bcatch ,
bfinally : bfinally
} ) ;
}
function vardefs ( no _in , in _const ) {
var a = [ ] ;
for ( ; ; ) {
a . push ( new AST _VarDef ( {
start : S . token ,
name : as _symbol ( in _const ? AST _SymbolConst : AST _SymbolVar ) ,
value : is ( "operator" , "=" ) ? ( next ( ) , expression ( false , no _in ) ) : null ,
end : prev ( )
} ) ) ;
if ( ! is ( "punc" , "," ) ) break ;
next ( ) ;
}
return a ;
}
var var _ = function ( no _in ) {
return new AST _Var ( {
start : prev ( ) ,
definitions : vardefs ( no _in , false ) ,
end : prev ( )
} ) ;
} ;
var const _ = function ( ) {
return new AST _Const ( {
start : prev ( ) ,
definitions : vardefs ( false , true ) ,
end : prev ( )
} ) ;
} ;
var new _ = function ( ) {
var start = S . token ;
expect _token ( "operator" , "new" ) ;
var newexp = expr _atom ( false ) , args ;
if ( is ( "punc" , "(" ) ) {
next ( ) ;
args = expr _list ( ")" ) ;
} else {
args = [ ] ;
}
return subscripts ( new AST _New ( {
start : start ,
expression : newexp ,
args : args ,
end : prev ( )
} ) , true ) ;
} ;
function as _atom _node ( ) {
var tok = S . token , ret ;
switch ( tok . type ) {
case "name" :
case "keyword" :
ret = _make _symbol ( AST _SymbolRef ) ;
break ;
case "num" :
ret = new AST _Number ( {
start : tok ,
end : tok ,
value : tok . value
} ) ;
break ;
case "string" :
ret = new AST _String ( {
start : tok ,
end : tok ,
value : tok . value
} ) ;
break ;
case "regexp" :
ret = new AST _RegExp ( {
start : tok ,
end : tok ,
value : tok . value
} ) ;
break ;
case "atom" :
switch ( tok . value ) {
case "false" :
ret = new AST _False ( {
start : tok ,
end : tok
} ) ;
break ;
case "true" :
ret = new AST _True ( {
start : tok ,
end : tok
} ) ;
break ;
case "null" :
ret = new AST _Null ( {
start : tok ,
end : tok
} ) ;
break ;
}
break ;
}
next ( ) ;
return ret ;
}
var expr _atom = function ( allow _calls ) {
if ( is ( "operator" , "new" ) ) {
return new _ ( ) ;
}
var start = S . token ;
if ( is ( "punc" ) ) {
switch ( start . value ) {
case "(" :
next ( ) ;
var ex = expression ( true ) ;
ex . start = start ;
ex . end = S . token ;
expect ( ")" ) ;
return subscripts ( ex , allow _calls ) ;
case "[" :
return subscripts ( array _ ( ) , allow _calls ) ;
case "{" :
return subscripts ( object _ ( ) , allow _calls ) ;
}
unexpected ( ) ;
}
if ( is ( "keyword" , "function" ) ) {
next ( ) ;
var func = function _ ( AST _Function ) ;
func . start = start ;
func . end = prev ( ) ;
return subscripts ( func , allow _calls ) ;
}
if ( ATOMIC _START _TOKEN [ S . token . type ] ) {
return subscripts ( as _atom _node ( ) , allow _calls ) ;
}
unexpected ( ) ;
} ;
function expr _list ( closing , allow _trailing _comma , allow _empty ) {
var first = true , a = [ ] ;
while ( ! is ( "punc" , closing ) ) {
if ( first ) first = false ; else expect ( "," ) ;
if ( allow _trailing _comma && is ( "punc" , closing ) ) break ;
if ( is ( "punc" , "," ) && allow _empty ) {
a . push ( new AST _Hole ( {
start : S . token ,
end : S . token
} ) ) ;
} else {
a . push ( expression ( false ) ) ;
}
}
next ( ) ;
return a ;
}
var array _ = embed _tokens ( function ( ) {
expect ( "[" ) ;
return new AST _Array ( {
elements : expr _list ( "]" , ! options . strict , true )
} ) ;
} ) ;
var object _ = embed _tokens ( function ( ) {
expect ( "{" ) ;
var first = true , a = [ ] ;
while ( ! is ( "punc" , "}" ) ) {
if ( first ) first = false ; else expect ( "," ) ;
if ( ! options . strict && is ( "punc" , "}" ) ) break ;
var start = S . token ;
var type = start . type ;
var name = as _property _name ( ) ;
if ( type == "name" && ! is ( "punc" , ":" ) ) {
if ( name == "get" ) {
a . push ( new AST _ObjectGetter ( {
start : start ,
key : as _atom _node ( ) ,
value : function _ ( AST _Accessor ) ,
end : prev ( )
} ) ) ;
continue ;
}
if ( name == "set" ) {
a . push ( new AST _ObjectSetter ( {
start : start ,
key : as _atom _node ( ) ,
value : function _ ( AST _Accessor ) ,
end : prev ( )
} ) ) ;
continue ;
}
}
expect ( ":" ) ;
a . push ( new AST _ObjectKeyVal ( {
start : start ,
key : name ,
value : expression ( false ) ,
end : prev ( )
} ) ) ;
}
next ( ) ;
return new AST _Object ( {
properties : a
} ) ;
} ) ;
function as _property _name ( ) {
var tmp = S . token ;
next ( ) ;
switch ( tmp . type ) {
case "num" :
case "string" :
case "name" :
case "operator" :
case "keyword" :
case "atom" :
return tmp . value ;
default :
unexpected ( ) ;
}
}
function as _name ( ) {
var tmp = S . token ;
next ( ) ;
switch ( tmp . type ) {
case "name" :
case "operator" :
case "keyword" :
case "atom" :
return tmp . value ;
default :
unexpected ( ) ;
}
}
function _make _symbol ( type ) {
var name = S . token . value ;
return new ( name == "this" ? AST _This : type ) ( {
name : String ( name ) ,
start : S . token ,
end : S . token
} ) ;
}
function as _symbol ( type , noerror ) {
if ( ! is ( "name" ) ) {
if ( ! noerror ) croak ( "Name expected" ) ;
return null ;
}
var sym = _make _symbol ( type ) ;
next ( ) ;
return sym ;
}
var subscripts = function ( expr , allow _calls ) {
var start = expr . start ;
if ( is ( "punc" , "." ) ) {
next ( ) ;
return subscripts ( new AST _Dot ( {
start : start ,
expression : expr ,
property : as _name ( ) ,
end : prev ( )
} ) , allow _calls ) ;
}
if ( is ( "punc" , "[" ) ) {
next ( ) ;
var prop = expression ( true ) ;
expect ( "]" ) ;
return subscripts ( new AST _Sub ( {
start : start ,
expression : expr ,
property : prop ,
end : prev ( )
} ) , allow _calls ) ;
}
if ( allow _calls && is ( "punc" , "(" ) ) {
next ( ) ;
return subscripts ( new AST _Call ( {
start : start ,
expression : expr ,
args : expr _list ( ")" ) ,
end : prev ( )
} ) , true ) ;
}
return expr ;
} ;
var maybe _unary = function ( allow _calls ) {
var start = S . token ;
if ( is ( "operator" ) && UNARY _PREFIX ( start . value ) ) {
next ( ) ;
handle _regexp ( ) ;
var ex = make _unary ( AST _UnaryPrefix , start . value , maybe _unary ( allow _calls ) ) ;
ex . start = start ;
ex . end = prev ( ) ;
return ex ;
}
var val = expr _atom ( allow _calls ) ;
while ( is ( "operator" ) && UNARY _POSTFIX ( S . token . value ) && ! S . token . nlb ) {
val = make _unary ( AST _UnaryPostfix , S . token . value , val ) ;
val . start = start ;
val . end = S . token ;
next ( ) ;
}
return val ;
} ;
function make _unary ( ctor , op , expr ) {
if ( ( op == "++" || op == "--" ) && ! is _assignable ( expr ) ) croak ( "Invalid use of " + op + " operator" ) ;
return new ctor ( {
operator : op ,
expression : expr
} ) ;
}
var expr _op = function ( left , min _prec , no _in ) {
var op = is ( "operator" ) ? S . token . value : null ;
if ( op == "in" && no _in ) op = null ;
var prec = op != null ? PRECEDENCE [ op ] : null ;
if ( prec != null && prec > min _prec ) {
next ( ) ;
var right = expr _op ( maybe _unary ( true ) , prec , no _in ) ;
return expr _op ( new AST _Binary ( {
start : left . start ,
left : left ,
operator : op ,
right : right ,
end : right . end
} ) , min _prec , no _in ) ;
}
return left ;
} ;
function expr _ops ( no _in ) {
return expr _op ( maybe _unary ( true ) , 0 , no _in ) ;
}
var maybe _conditional = function ( no _in ) {
var start = S . token ;
var expr = expr _ops ( no _in ) ;
if ( is ( "operator" , "?" ) ) {
next ( ) ;
var yes = expression ( false ) ;
expect ( ":" ) ;
return new AST _Conditional ( {
start : start ,
condition : expr ,
consequent : yes ,
alternative : expression ( false , no _in ) ,
end : prev ( )
} ) ;
}
return expr ;
} ;
function is _assignable ( expr ) {
if ( ! options . strict ) return true ;
if ( expr instanceof AST _This ) return false ;
return expr instanceof AST _PropAccess || expr instanceof AST _Symbol ;
}
var maybe _assign = function ( no _in ) {
var start = S . token ;
var left = maybe _conditional ( no _in ) , val = S . token . value ;
if ( is ( "operator" ) && ASSIGNMENT ( val ) ) {
if ( is _assignable ( left ) ) {
next ( ) ;
return new AST _Assign ( {
start : start ,
left : left ,
operator : val ,
right : maybe _assign ( no _in ) ,
end : prev ( )
} ) ;
}
croak ( "Invalid assignment" ) ;
}
return left ;
} ;
var expression = function ( commas , no _in ) {
var start = S . token ;
var expr = maybe _assign ( no _in ) ;
if ( commas && is ( "punc" , "," ) ) {
next ( ) ;
return new AST _Seq ( {
start : start ,
car : expr ,
cdr : expression ( true , no _in ) ,
end : peek ( )
} ) ;
}
return expr ;
} ;
function in _loop ( cont ) {
++ S . in _loop ;
var ret = cont ( ) ;
-- S . in _loop ;
return ret ;
}
if ( options . expression ) {
return expression ( true ) ;
}
return function ( ) {
var start = S . token ;
var body = [ ] ;
while ( ! is ( "eof" ) ) body . push ( statement ( ) ) ;
var end = prev ( ) ;
var toplevel = options . toplevel ;
if ( toplevel ) {
toplevel . body = toplevel . body . concat ( body ) ;
toplevel . end = end ;
} else {
toplevel = new AST _Toplevel ( {
start : start ,
body : body ,
end : end
} ) ;
}
return toplevel ;
} ( ) ;
}
"use strict" ;
function TreeTransformer ( before , after ) {
TreeWalker . call ( this ) ;
this . before = before ;
this . after = after ;
}
TreeTransformer . prototype = new TreeWalker ( ) ;
( function ( undefined ) {
function _ ( node , descend ) {
node . DEFMETHOD ( "transform" , function ( tw , in _list ) {
var x , y ;
tw . push ( this ) ;
if ( tw . before ) x = tw . before ( this , descend , in _list ) ;
if ( x === undefined ) {
if ( ! tw . after ) {
x = this ;
descend ( x , tw ) ;
} else {
tw . stack [ tw . stack . length - 1 ] = x = this . clone ( ) ;
descend ( x , tw ) ;
y = tw . after ( x , in _list ) ;
if ( y !== undefined ) x = y ;
}
}
tw . pop ( ) ;
return x ;
} ) ;
}
function do _list ( list , tw ) {
return MAP ( list , function ( node ) {
return node . transform ( tw , true ) ;
} ) ;
}
_ ( AST _Node , noop ) ;
_ ( AST _LabeledStatement , function ( self , tw ) {
self . label = self . label . transform ( tw ) ;
self . body = self . body . transform ( tw ) ;
} ) ;
_ ( AST _SimpleStatement , function ( self , tw ) {
self . body = self . body . transform ( tw ) ;
} ) ;
_ ( AST _Block , function ( self , tw ) {
self . body = do _list ( self . body , tw ) ;
} ) ;
_ ( AST _DWLoop , function ( self , tw ) {
self . condition = self . condition . transform ( tw ) ;
self . body = self . body . transform ( tw ) ;
} ) ;
_ ( AST _For , function ( self , tw ) {
if ( self . init ) self . init = self . init . transform ( tw ) ;
if ( self . condition ) self . condition = self . condition . transform ( tw ) ;
if ( self . step ) self . step = self . step . transform ( tw ) ;
self . body = self . body . transform ( tw ) ;
} ) ;
_ ( AST _ForIn , function ( self , tw ) {
self . init = self . init . transform ( tw ) ;
self . object = self . object . transform ( tw ) ;
self . body = self . body . transform ( tw ) ;
} ) ;
_ ( AST _With , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
self . body = self . body . transform ( tw ) ;
} ) ;
_ ( AST _Exit , function ( self , tw ) {
if ( self . value ) self . value = self . value . transform ( tw ) ;
} ) ;
_ ( AST _LoopControl , function ( self , tw ) {
if ( self . label ) self . label = self . label . transform ( tw ) ;
} ) ;
_ ( AST _If , function ( self , tw ) {
self . condition = self . condition . transform ( tw ) ;
self . body = self . body . transform ( tw ) ;
if ( self . alternative ) self . alternative = self . alternative . transform ( tw ) ;
} ) ;
_ ( AST _Switch , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
self . body = do _list ( self . body , tw ) ;
} ) ;
_ ( AST _Case , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
self . body = do _list ( self . body , tw ) ;
} ) ;
_ ( AST _Try , function ( self , tw ) {
self . body = do _list ( self . body , tw ) ;
if ( self . bcatch ) self . bcatch = self . bcatch . transform ( tw ) ;
if ( self . bfinally ) self . bfinally = self . bfinally . transform ( tw ) ;
} ) ;
_ ( AST _Catch , function ( self , tw ) {
self . argname = self . argname . transform ( tw ) ;
self . body = do _list ( self . body , tw ) ;
} ) ;
_ ( AST _Definitions , function ( self , tw ) {
self . definitions = do _list ( self . definitions , tw ) ;
} ) ;
_ ( AST _VarDef , function ( self , tw ) {
self . name = self . name . transform ( tw ) ;
if ( self . value ) self . value = self . value . transform ( tw ) ;
} ) ;
_ ( AST _Lambda , function ( self , tw ) {
if ( self . name ) self . name = self . name . transform ( tw ) ;
self . argnames = do _list ( self . argnames , tw ) ;
self . body = do _list ( self . body , tw ) ;
} ) ;
_ ( AST _Call , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
self . args = do _list ( self . args , tw ) ;
} ) ;
_ ( AST _Seq , function ( self , tw ) {
self . car = self . car . transform ( tw ) ;
self . cdr = self . cdr . transform ( tw ) ;
} ) ;
_ ( AST _Dot , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
} ) ;
_ ( AST _Sub , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
self . property = self . property . transform ( tw ) ;
} ) ;
_ ( AST _Unary , function ( self , tw ) {
self . expression = self . expression . transform ( tw ) ;
} ) ;
_ ( AST _Binary , function ( self , tw ) {
self . left = self . left . transform ( tw ) ;
self . right = self . right . transform ( tw ) ;
} ) ;
_ ( AST _Conditional , function ( self , tw ) {
self . condition = self . condition . transform ( tw ) ;
self . consequent = self . consequent . transform ( tw ) ;
self . alternative = self . alternative . transform ( tw ) ;
} ) ;
_ ( AST _Array , function ( self , tw ) {
self . elements = do _list ( self . elements , tw ) ;
} ) ;
_ ( AST _Object , function ( self , tw ) {
self . properties = do _list ( self . properties , tw ) ;
} ) ;
_ ( AST _ObjectProperty , function ( self , tw ) {
self . value = self . value . transform ( tw ) ;
} ) ;
} ) ( ) ;
"use strict" ;
function SymbolDef ( scope , index , orig ) {
this . name = orig . name ;
this . orig = [ orig ] ;
this . scope = scope ;
this . references = [ ] ;
this . global = false ;
this . mangled _name = null ;
this . undeclared = false ;
this . constant = false ;
this . index = index ;
}
SymbolDef . prototype = {
unmangleable : function ( options ) {
return this . global && ! ( options && options . toplevel ) || this . undeclared || ! ( options && options . eval ) && ( this . scope . uses _eval || this . scope . uses _with ) ;
} ,
mangle : function ( options ) {
if ( ! this . mangled _name && ! this . unmangleable ( options ) ) {
var s = this . scope ;
if ( ! options . screw _ie8 && this . orig [ 0 ] instanceof AST _SymbolLambda ) s = s . parent _scope ;
this . mangled _name = s . next _mangled ( options , this ) ;
}
}
} ;
AST _Toplevel . DEFMETHOD ( "figure_out_scope" , function ( options ) {
options = defaults ( options , {
screw _ie8 : false
} ) ;
var self = this ;
var scope = self . parent _scope = null ;
var defun = null ;
var nesting = 0 ;
var tw = new TreeWalker ( function ( node , descend ) {
if ( options . screw _ie8 && node instanceof AST _Catch ) {
var save _scope = scope ;
scope = new AST _Scope ( node ) ;
scope . init _scope _vars ( nesting ) ;
scope . parent _scope = save _scope ;
descend ( ) ;
scope = save _scope ;
return true ;
}
if ( node instanceof AST _Scope ) {
node . init _scope _vars ( nesting ) ;
var save _scope = node . parent _scope = scope ;
var save _defun = defun ;
defun = scope = node ;
++ nesting ;
descend ( ) ;
-- nesting ;
scope = save _scope ;
defun = save _defun ;
return true ;
}
if ( node instanceof AST _Directive ) {
node . scope = scope ;
push _uniq ( scope . directives , node . value ) ;
return true ;
}
if ( node instanceof AST _With ) {
for ( var s = scope ; s ; s = s . parent _scope ) s . uses _with = true ;
return ;
}
if ( node instanceof AST _Symbol ) {
node . scope = scope ;
}
if ( node instanceof AST _SymbolLambda ) {
defun . def _function ( node ) ;
} else if ( node instanceof AST _SymbolDefun ) {
( node . scope = defun . parent _scope ) . def _function ( node ) ;
} else if ( node instanceof AST _SymbolVar || node instanceof AST _SymbolConst ) {
var def = defun . def _variable ( node ) ;
def . constant = node instanceof AST _SymbolConst ;
def . init = tw . parent ( ) . value ;
} else if ( node instanceof AST _SymbolCatch ) {
( options . screw _ie8 ? scope : defun ) . def _variable ( node ) ;
}
} ) ;
self . walk ( tw ) ;
var func = null ;
var globals = self . globals = new Dictionary ( ) ;
var tw = new TreeWalker ( function ( node , descend ) {
if ( node instanceof AST _Lambda ) {
var prev _func = func ;
func = node ;
descend ( ) ;
func = prev _func ;
return true ;
}
if ( node instanceof AST _SymbolRef ) {
var name = node . name ;
var sym = node . scope . find _variable ( name ) ;
if ( ! sym ) {
var g ;
if ( globals . has ( name ) ) {
g = globals . get ( name ) ;
} else {
g = new SymbolDef ( self , globals . size ( ) , node ) ;
g . undeclared = true ;
g . global = true ;
globals . set ( name , g ) ;
}
node . thedef = g ;
if ( name == "eval" && tw . parent ( ) instanceof AST _Call ) {
for ( var s = node . scope ; s && ! s . uses _eval ; s = s . parent _scope ) s . uses _eval = true ;
}
if ( func && name == "arguments" ) {
func . uses _arguments = true ;
}
} else {
node . thedef = sym ;
}
node . reference ( ) ;
return true ;
}
} ) ;
self . walk ( tw ) ;
} ) ;
AST _Scope . DEFMETHOD ( "init_scope_vars" , function ( nesting ) {
this . directives = [ ] ;
this . variables = new Dictionary ( ) ;
this . functions = new Dictionary ( ) ;
this . uses _with = false ;
this . uses _eval = false ;
this . parent _scope = null ;
this . enclosed = [ ] ;
this . cname = - 1 ;
this . nesting = nesting ;
} ) ;
AST _Scope . DEFMETHOD ( "strict" , function ( ) {
return this . has _directive ( "use strict" ) ;
} ) ;
AST _Lambda . DEFMETHOD ( "init_scope_vars" , function ( ) {
AST _Scope . prototype . init _scope _vars . apply ( this , arguments ) ;
this . uses _arguments = false ;
} ) ;
AST _SymbolRef . DEFMETHOD ( "reference" , function ( ) {
var def = this . definition ( ) ;
def . references . push ( this ) ;
var s = this . scope ;
while ( s ) {
push _uniq ( s . enclosed , def ) ;
if ( s === def . scope ) break ;
s = s . parent _scope ;
}
this . frame = this . scope . nesting - def . scope . nesting ;
} ) ;
AST _Scope . DEFMETHOD ( "find_variable" , function ( name ) {
if ( name instanceof AST _Symbol ) name = name . name ;
return this . variables . get ( name ) || this . parent _scope && this . parent _scope . find _variable ( name ) ;
} ) ;
AST _Scope . DEFMETHOD ( "has_directive" , function ( value ) {
return this . parent _scope && this . parent _scope . has _directive ( value ) || ( this . directives . indexOf ( value ) >= 0 ? this : null ) ;
} ) ;
AST _Scope . DEFMETHOD ( "def_function" , function ( symbol ) {
this . functions . set ( symbol . name , this . def _variable ( symbol ) ) ;
} ) ;
AST _Scope . DEFMETHOD ( "def_variable" , function ( symbol ) {
var def ;
if ( ! this . variables . has ( symbol . name ) ) {
def = new SymbolDef ( this , this . variables . size ( ) , symbol ) ;
this . variables . set ( symbol . name , def ) ;
def . global = ! this . parent _scope ;
} else {
def = this . variables . get ( symbol . name ) ;
def . orig . push ( symbol ) ;
}
return symbol . thedef = def ;
} ) ;
AST _Scope . DEFMETHOD ( "next_mangled" , function ( options ) {
var ext = this . enclosed ;
out : while ( true ) {
var m = base54 ( ++ this . cname ) ;
if ( ! is _identifier ( m ) ) continue ;
if ( options . except . indexOf ( m ) >= 0 ) continue ;
for ( var i = ext . length ; -- i >= 0 ; ) {
var sym = ext [ i ] ;
var name = sym . mangled _name || sym . unmangleable ( options ) && sym . name ;
if ( m == name ) continue out ;
}
return m ;
}
} ) ;
AST _Function . DEFMETHOD ( "next_mangled" , function ( options , def ) {
var tricky _def = def . orig [ 0 ] instanceof AST _SymbolFunarg && this . name && this . name . definition ( ) ;
while ( true ) {
var name = AST _Lambda . prototype . next _mangled . call ( this , options , def ) ;
if ( ! ( tricky _def && tricky _def . mangled _name == name ) ) return name ;
}
} ) ;
AST _Scope . DEFMETHOD ( "references" , function ( sym ) {
if ( sym instanceof AST _Symbol ) sym = sym . definition ( ) ;
return this . enclosed . indexOf ( sym ) < 0 ? null : sym ;
} ) ;
AST _Symbol . DEFMETHOD ( "unmangleable" , function ( options ) {
return this . definition ( ) . unmangleable ( options ) ;
} ) ;
AST _SymbolAccessor . DEFMETHOD ( "unmangleable" , function ( ) {
return true ;
} ) ;
AST _Label . DEFMETHOD ( "unmangleable" , function ( ) {
return false ;
} ) ;
AST _Symbol . DEFMETHOD ( "unreferenced" , function ( ) {
return this . definition ( ) . references . length == 0 && ! ( this . scope . uses _eval || this . scope . uses _with ) ;
} ) ;
AST _Symbol . DEFMETHOD ( "undeclared" , function ( ) {
return this . definition ( ) . undeclared ;
} ) ;
AST _LabelRef . DEFMETHOD ( "undeclared" , function ( ) {
return false ;
} ) ;
AST _Label . DEFMETHOD ( "undeclared" , function ( ) {
return false ;
} ) ;
AST _Symbol . DEFMETHOD ( "definition" , function ( ) {
return this . thedef ;
} ) ;
AST _Symbol . DEFMETHOD ( "global" , function ( ) {
return this . definition ( ) . global ;
} ) ;
AST _Toplevel . DEFMETHOD ( "_default_mangler_options" , function ( options ) {
return defaults ( options , {
except : [ ] ,
eval : false ,
sort : false ,
toplevel : false ,
screw _ie8 : false
} ) ;
} ) ;
AST _Toplevel . DEFMETHOD ( "mangle_names" , function ( options ) {
options = this . _default _mangler _options ( options ) ;
var lname = - 1 ;
var to _mangle = [ ] ;
var tw = new TreeWalker ( function ( node , descend ) {
if ( node instanceof AST _LabeledStatement ) {
var save _nesting = lname ;
descend ( ) ;
lname = save _nesting ;
return true ;
}
if ( node instanceof AST _Scope ) {
var p = tw . parent ( ) , a = [ ] ;
node . variables . each ( function ( symbol ) {
if ( options . except . indexOf ( symbol . name ) < 0 ) {
a . push ( symbol ) ;
}
} ) ;
if ( options . sort ) a . sort ( function ( a , b ) {
return b . references . length - a . references . length ;
} ) ;
to _mangle . push . apply ( to _mangle , a ) ;
return ;
}
if ( node instanceof AST _Label ) {
var name ;
do name = base54 ( ++ lname ) ; while ( ! is _identifier ( name ) ) ;
node . mangled _name = name ;
return true ;
}
if ( options . screw _ie8 && node instanceof AST _SymbolCatch ) {
to _mangle . push ( node . definition ( ) ) ;
return ;
}
} ) ;
this . walk ( tw ) ;
to _mangle . forEach ( function ( def ) {
def . mangle ( options ) ;
} ) ;
} ) ;
AST _Toplevel . DEFMETHOD ( "compute_char_frequency" , function ( options ) {
options = this . _default _mangler _options ( options ) ;
var tw = new TreeWalker ( function ( node ) {
if ( node instanceof AST _Constant ) base54 . consider ( node . print _to _string ( ) ) ; else if ( node instanceof AST _Return ) base54 . consider ( "return" ) ; else if ( node instanceof AST _Throw ) base54 . consider ( "throw" ) ; else if ( node instanceof AST _Continue ) base54 . consider ( "continue" ) ; else if ( node instanceof AST _Break ) base54 . consider ( "break" ) ; else if ( node instanceof AST _Debugger ) base54 . consider ( "debugger" ) ; else if ( node instanceof AST _Directive ) base54 . consider ( node . value ) ; else if ( node instanceof AST _While ) base54 . consider ( "while" ) ; else if ( node instanceof AST _Do ) base54 . consider ( "do while" ) ; else if ( node instanceof AST _If ) {
base54 . consider ( "if" ) ;
if ( node . alternative ) base54 . consider ( "else" ) ;
} else if ( node instanceof AST _Var ) base54 . consider ( "var" ) ; else if ( node instanceof AST _Const ) base54 . consider ( "const" ) ; else if ( node instanceof AST _Lambda ) base54 . consider ( "function" ) ; else if ( node instanceof AST _For ) base54 . consider ( "for" ) ; else if ( node instanceof AST _ForIn ) base54 . consider ( "for in" ) ; else if ( node instanceof AST _Switch ) base54 . consider ( "switch" ) ; else if ( node instanceof AST _Case ) base54 . consider ( "case" ) ; else if ( node instanceof AST _Default ) base54 . consider ( "default" ) ; else if ( node instanceof AST _With ) base54 . consider ( "with" ) ; else if ( node instanceof AST _ObjectSetter ) base54 . consider ( "set" + node . key ) ; else if ( node instanceof AST _ObjectGetter ) base54 . consider ( "get" + node . key ) ; else if ( node instanceof AST _ObjectKeyVal ) base54 . consider ( node . key ) ; else if ( node instanceof AST _New ) base54 . consider ( "new" ) ; else if ( node instanceof AST _This ) base54 . consider ( "this" ) ; else if ( node instanceof AST _Try ) base54 . consider ( "try" ) ; else if ( node instanceof AST _Catch ) base54 . consider ( "catch" ) ; else if ( node instanceof AST _Finally ) base54 . consider ( "finally" ) ; else if ( node instanceof AST _Symbol && node . unmangleable ( options ) ) base54 . consider ( node . name ) ; else if ( node instanceof AST _Unary || node instanceof AST _Binary ) base54 . consider ( node . operator ) ; else if ( node instanceof AST _Dot ) base54 . consider ( node . property ) ;
} ) ;
this . walk ( tw ) ;
base54 . sort ( ) ;
} ) ;
var base54 = function ( ) {
var string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_0123456789" ;
var chars , frequency ;
function reset ( ) {
frequency = Object . create ( null ) ;
chars = string . split ( "" ) . map ( function ( ch ) {
return ch . charCodeAt ( 0 ) ;
} ) ;
chars . forEach ( function ( ch ) {
frequency [ ch ] = 0 ;
} ) ;
}
base54 . consider = function ( str ) {
for ( var i = str . length ; -- i >= 0 ; ) {
var code = str . charCodeAt ( i ) ;
if ( code in frequency ) ++ frequency [ code ] ;
}
} ;
base54 . sort = function ( ) {
chars = mergeSort ( chars , function ( a , b ) {
if ( is _digit ( a ) && ! is _digit ( b ) ) return 1 ;
if ( is _digit ( b ) && ! is _digit ( a ) ) return - 1 ;
return frequency [ b ] - frequency [ a ] ;
} ) ;
} ;
base54 . reset = reset ;
reset ( ) ;
base54 . get = function ( ) {
return chars ;
} ;
base54 . freq = function ( ) {
return frequency ;
} ;
function base54 ( num ) {
var ret = "" , base = 54 ;
do {
ret += String . fromCharCode ( chars [ num % base ] ) ;
num = Math . floor ( num / base ) ;
base = 64 ;
} while ( num > 0 ) ;
return ret ;
}
return base54 ;
} ( ) ;
AST _Toplevel . DEFMETHOD ( "scope_warnings" , function ( options ) {
options = defaults ( options , {
undeclared : false ,
unreferenced : true ,
assign _to _global : true ,
func _arguments : true ,
nested _defuns : true ,
eval : true
} ) ;
var tw = new TreeWalker ( function ( node ) {
if ( options . undeclared && node instanceof AST _SymbolRef && node . undeclared ( ) ) {
AST _Node . warn ( "Undeclared symbol: {name} [{file}:{line},{col}]" , {
name : node . name ,
file : node . start . file ,
line : node . start . line ,
col : node . start . col
} ) ;
}
if ( options . assign _to _global ) {
var sym = null ;
if ( node instanceof AST _Assign && node . left instanceof AST _SymbolRef ) sym = node . left ; else if ( node instanceof AST _ForIn && node . init instanceof AST _SymbolRef ) sym = node . init ;
if ( sym && ( sym . undeclared ( ) || sym . global ( ) && sym . scope !== sym . definition ( ) . scope ) ) {
AST _Node . warn ( "{msg}: {name} [{file}:{line},{col}]" , {
msg : sym . undeclared ( ) ? "Accidental global?" : "Assignment to global" ,
name : sym . name ,
file : sym . start . file ,
line : sym . start . line ,
col : sym . start . col
} ) ;
}
}
if ( options . eval && node instanceof AST _SymbolRef && node . undeclared ( ) && node . name == "eval" ) {
AST _Node . warn ( "Eval is used [{file}:{line},{col}]" , node . start ) ;
}
if ( options . unreferenced && ( node instanceof AST _SymbolDeclaration || node instanceof AST _Label ) && node . unreferenced ( ) ) {
AST _Node . warn ( "{type} {name} is declared but not referenced [{file}:{line},{col}]" , {
type : node instanceof AST _Label ? "Label" : "Symbol" ,
name : node . name ,
file : node . start . file ,
line : node . start . line ,
col : node . start . col
} ) ;
}
if ( options . func _arguments && node instanceof AST _Lambda && node . uses _arguments ) {
AST _Node . warn ( "arguments used in function {name} [{file}:{line},{col}]" , {
name : node . name ? node . name . name : "anonymous" ,
file : node . start . file ,
line : node . start . line ,
col : node . start . col
} ) ;
}
if ( options . nested _defuns && node instanceof AST _Defun && ! ( tw . parent ( ) instanceof AST _Scope ) ) {
AST _Node . warn ( 'Function {name} declared in nested statement "{type}" [{file}:{line},{col}]' , {
name : node . name . name ,
type : tw . parent ( ) . TYPE ,
file : node . start . file ,
line : node . start . line ,
col : node . start . col
} ) ;
}
} ) ;
this . walk ( tw ) ;
} ) ;
"use strict" ;
function OutputStream ( options ) {
options = defaults ( options , {
indent _start : 0 ,
indent _level : 4 ,
quote _keys : false ,
space _colon : true ,
ascii _only : false ,
unescape _regexps : false ,
inline _script : false ,
width : 80 ,
max _line _len : 32e3 ,
beautify : false ,
source _map : null ,
bracketize : false ,
semicolons : true ,
comments : false ,
preserve _line : false ,
screw _ie8 : false ,
preamble : null
} , true ) ;
var indentation = 0 ;
var current _col = 0 ;
var current _line = 1 ;
var current _pos = 0 ;
var OUTPUT = "" ;
function to _ascii ( str , identifier ) {
return str . replace ( /[\u0080-\uffff]/g , function ( ch ) {
var code = ch . charCodeAt ( 0 ) . toString ( 16 ) ;
if ( code . length <= 2 && ! identifier ) {
while ( code . length < 2 ) code = "0" + code ;
return "\\x" + code ;
} else {
while ( code . length < 4 ) code = "0" + code ;
return "\\u" + code ;
}
} ) ;
}
function make _string ( str ) {
var dq = 0 , sq = 0 ;
str = str . replace ( /[\\\b\f\n\r\t\x22\x27\u2028\u2029\0]/g , function ( s ) {
switch ( s ) {
case "\\" :
return "\\\\" ;
case "\b" :
return "\\b" ;
case "\f" :
return "\\f" ;
case "\n" :
return "\\n" ;
case "\r" :
return "\\r" ;
case "\u2028" :
return "\\u2028" ;
case "\u2029" :
return "\\u2029" ;
case '"' :
++ dq ;
return '"' ;
case "'" :
++ sq ;
return "'" ;
case "\x00" :
return "\\x00" ;
}
return s ;
} ) ;
if ( options . ascii _only ) str = to _ascii ( str ) ;
if ( dq > sq ) return "'" + str . replace ( /\x27/g , "\\'" ) + "'" ; else return '"' + str . replace ( /\x22/g , '\\"' ) + '"' ;
}
function encode _string ( str ) {
var ret = make _string ( str ) ;
if ( options . inline _script ) ret = ret . replace ( /<\x2fscript([>\/\t\n\f\r ])/gi , "<\\/script$1" ) ;
return ret ;
}
function make _name ( name ) {
name = name . toString ( ) ;
if ( options . ascii _only ) name = to _ascii ( name , true ) ;
return name ;
}
function make _indent ( back ) {
return repeat _string ( " " , options . indent _start + indentation - back * options . indent _level ) ;
}
var might _need _space = false ;
var might _need _semicolon = false ;
var last = null ;
function last _char ( ) {
return last . charAt ( last . length - 1 ) ;
}
function maybe _newline ( ) {
if ( options . max _line _len && current _col > options . max _line _len ) print ( "\n" ) ;
}
var requireSemicolonChars = makePredicate ( "( [ + * / - , ." ) ;
function print ( str ) {
str = String ( str ) ;
var ch = str . charAt ( 0 ) ;
if ( might _need _semicolon ) {
if ( ( ! ch || ";}" . indexOf ( ch ) < 0 ) && ! /[;]$/ . test ( last ) ) {
if ( options . semicolons || requireSemicolonChars ( ch ) ) {
OUTPUT += ";" ;
current _col ++ ;
current _pos ++ ;
} else {
OUTPUT += "\n" ;
current _pos ++ ;
current _line ++ ;
current _col = 0 ;
}
if ( ! options . beautify ) might _need _space = false ;
}
might _need _semicolon = false ;
maybe _newline ( ) ;
}
if ( ! options . beautify && options . preserve _line && stack [ stack . length - 1 ] ) {
var target _line = stack [ stack . length - 1 ] . start . line ;
while ( current _line < target _line ) {
OUTPUT += "\n" ;
current _pos ++ ;
current _line ++ ;
current _col = 0 ;
might _need _space = false ;
}
}
if ( might _need _space ) {
var prev = last _char ( ) ;
if ( is _identifier _char ( prev ) && ( is _identifier _char ( ch ) || ch == "\\" ) || /^[\+\-\/]$/ . test ( ch ) && ch == prev ) {
OUTPUT += " " ;
current _col ++ ;
current _pos ++ ;
}
might _need _space = false ;
}
var a = str . split ( /\r?\n/ ) , n = a . length - 1 ;
current _line += n ;
if ( n == 0 ) {
current _col += a [ n ] . length ;
} else {
current _col = a [ n ] . length ;
}
current _pos += str . length ;
last = str ;
OUTPUT += str ;
}
var space = options . beautify ? function ( ) {
print ( " " ) ;
} : function ( ) {
might _need _space = true ;
} ;
var indent = options . beautify ? function ( half ) {
if ( options . beautify ) {
print ( make _indent ( half ? . 5 : 0 ) ) ;
}
} : noop ;
var with _indent = options . beautify ? function ( col , cont ) {
if ( col === true ) col = next _indent ( ) ;
var save _indentation = indentation ;
indentation = col ;
var ret = cont ( ) ;
indentation = save _indentation ;
return ret ;
} : function ( col , cont ) {
return cont ( ) ;
} ;
var newline = options . beautify ? function ( ) {
print ( "\n" ) ;
} : noop ;
var semicolon = options . beautify ? function ( ) {
print ( ";" ) ;
} : function ( ) {
might _need _semicolon = true ;
} ;
function force _semicolon ( ) {
might _need _semicolon = false ;
print ( ";" ) ;
}
function next _indent ( ) {
return indentation + options . indent _level ;
}
function with _block ( cont ) {
var ret ;
print ( "{" ) ;
newline ( ) ;
with _indent ( next _indent ( ) , function ( ) {
ret = cont ( ) ;
} ) ;
indent ( ) ;
print ( "}" ) ;
return ret ;
}
function with _parens ( cont ) {
print ( "(" ) ;
var ret = cont ( ) ;
print ( ")" ) ;
return ret ;
}
function with _square ( cont ) {
print ( "[" ) ;
var ret = cont ( ) ;
print ( "]" ) ;
return ret ;
}
function comma ( ) {
print ( "," ) ;
space ( ) ;
}
function colon ( ) {
print ( ":" ) ;
if ( options . space _colon ) space ( ) ;
}
var add _mapping = options . source _map ? function ( token , name ) {
try {
if ( token ) options . source _map . add ( token . file || "?" , current _line , current _col , token . line , token . col , ! name && token . type == "name" ? token . value : name ) ;
} catch ( ex ) {
AST _Node . warn ( "Couldn't figure out mapping for {file}:{line},{col} → {cline},{ccol} [{name}]" , {
file : token . file ,
line : token . line ,
col : token . col ,
cline : current _line ,
ccol : current _col ,
name : name || ""
} ) ;
}
} : noop ;
function get ( ) {
return OUTPUT ;
}
if ( options . preamble ) {
print ( options . preamble . replace ( /\r\n?|[\n\u2028\u2029]|\s*$/g , "\n" ) ) ;
}
var stack = [ ] ;
return {
get : get ,
toString : get ,
indent : indent ,
indentation : function ( ) {
return indentation ;
} ,
current _width : function ( ) {
return current _col - indentation ;
} ,
should _break : function ( ) {
return options . width && this . current _width ( ) >= options . width ;
} ,
newline : newline ,
print : print ,
space : space ,
comma : comma ,
colon : colon ,
last : function ( ) {
return last ;
} ,
semicolon : semicolon ,
force _semicolon : force _semicolon ,
to _ascii : to _ascii ,
print _name : function ( name ) {
print ( make _name ( name ) ) ;
} ,
print _string : function ( str ) {
print ( encode _string ( str ) ) ;
} ,
next _indent : next _indent ,
with _indent : with _indent ,
with _block : with _block ,
with _parens : with _parens ,
with _square : with _square ,
add _mapping : add _mapping ,
option : function ( opt ) {
return options [ opt ] ;
} ,
line : function ( ) {
return current _line ;
} ,
col : function ( ) {
return current _col ;
} ,
pos : function ( ) {
return current _pos ;
} ,
push _node : function ( node ) {
stack . push ( node ) ;
} ,
pop _node : function ( ) {
return stack . pop ( ) ;
} ,
stack : function ( ) {
return stack ;
} ,
parent : function ( n ) {
return stack [ stack . length - 2 - ( n || 0 ) ] ;
}
} ;
}
( function ( ) {
function DEFPRINT ( nodetype , generator ) {
nodetype . DEFMETHOD ( "_codegen" , generator ) ;
}
AST _Node . DEFMETHOD ( "print" , function ( stream , force _parens ) {
var self = this , generator = self . _codegen ;
function doit ( ) {
self . add _comments ( stream ) ;
self . add _source _map ( stream ) ;
generator ( self , stream ) ;
}
stream . push _node ( self ) ;
if ( force _parens || self . needs _parens ( stream ) ) {
stream . with _parens ( doit ) ;
} else {
doit ( ) ;
}
stream . pop _node ( ) ;
} ) ;
AST _Node . DEFMETHOD ( "print_to_string" , function ( options ) {
var s = OutputStream ( options ) ;
this . print ( s ) ;
return s . get ( ) ;
} ) ;
AST _Node . DEFMETHOD ( "add_comments" , function ( output ) {
var c = output . option ( "comments" ) , self = this ;
if ( c ) {
var start = self . start ;
if ( start && ! start . _comments _dumped ) {
start . _comments _dumped = true ;
var comments = start . comments _before || [ ] ;
if ( self instanceof AST _Exit && self . value ) {
self . value . walk ( new TreeWalker ( function ( node ) {
if ( node . start && node . start . comments _before ) {
comments = comments . concat ( node . start . comments _before ) ;
node . start . comments _before = [ ] ;
}
if ( node instanceof AST _Function || node instanceof AST _Array || node instanceof AST _Object ) {
return true ;
}
} ) ) ;
}
if ( c . test ) {
comments = comments . filter ( function ( comment ) {
return c . test ( comment . value ) ;
} ) ;
} else if ( typeof c == "function" ) {
comments = comments . filter ( function ( comment ) {
return c ( self , comment ) ;
} ) ;
}
comments . forEach ( function ( c ) {
if ( /comment[134]/ . test ( c . type ) ) {
output . print ( "//" + c . value + "\n" ) ;
output . indent ( ) ;
} else if ( c . type == "comment2" ) {
output . print ( "/*" + c . value + "*/" ) ;
if ( start . nlb ) {
output . print ( "\n" ) ;
output . indent ( ) ;
} else {
output . space ( ) ;
}
}
} ) ;
}
}
} ) ;
function PARENS ( nodetype , func ) {
if ( Array . isArray ( nodetype ) ) {
nodetype . forEach ( function ( nodetype ) {
PARENS ( nodetype , func ) ;
} ) ;
} else {
nodetype . DEFMETHOD ( "needs_parens" , func ) ;
}
}
PARENS ( AST _Node , function ( ) {
return false ;
} ) ;
PARENS ( AST _Function , function ( output ) {
return first _in _statement ( output ) ;
} ) ;
PARENS ( AST _Object , function ( output ) {
return first _in _statement ( output ) ;
} ) ;
PARENS ( [ AST _Unary , AST _Undefined ] , function ( output ) {
var p = output . parent ( ) ;
return p instanceof AST _PropAccess && p . expression === this ;
} ) ;
PARENS ( AST _Seq , function ( output ) {
var p = output . parent ( ) ;
return p instanceof AST _Call || p instanceof AST _Unary || p instanceof AST _Binary || p instanceof AST _VarDef || p instanceof AST _PropAccess || p instanceof AST _Array || p instanceof AST _ObjectProperty || p instanceof AST _Conditional ;
} ) ;
PARENS ( AST _Binary , function ( output ) {
var p = output . parent ( ) ;
if ( p instanceof AST _Call && p . expression === this ) return true ;
if ( p instanceof AST _Unary ) return true ;
if ( p instanceof AST _PropAccess && p . expression === this ) return true ;
if ( p instanceof AST _Binary ) {
var po = p . operator , pp = PRECEDENCE [ po ] ;
var so = this . operator , sp = PRECEDENCE [ so ] ;
if ( pp > sp || pp == sp && this === p . right ) {
return true ;
}
}
} ) ;
PARENS ( AST _PropAccess , function ( output ) {
var p = output . parent ( ) ;
if ( p instanceof AST _New && p . expression === this ) {
try {
this . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Call ) throw p ;
} ) ) ;
} catch ( ex ) {
if ( ex !== p ) throw ex ;
return true ;
}
}
} ) ;
PARENS ( AST _Call , function ( output ) {
var p = output . parent ( ) , p1 ;
if ( p instanceof AST _New && p . expression === this ) return true ;
return this . expression instanceof AST _Function && p instanceof AST _PropAccess && p . expression === this && ( p1 = output . parent ( 1 ) ) instanceof AST _Assign && p1 . left === p ;
} ) ;
PARENS ( AST _New , function ( output ) {
var p = output . parent ( ) ;
if ( no _constructor _parens ( this , output ) && ( p instanceof AST _PropAccess || p instanceof AST _Call && p . expression === this ) ) return true ;
} ) ;
PARENS ( AST _Number , function ( output ) {
var p = output . parent ( ) ;
if ( this . getValue ( ) < 0 && p instanceof AST _PropAccess && p . expression === this ) return true ;
} ) ;
PARENS ( AST _NaN , function ( output ) {
var p = output . parent ( ) ;
if ( p instanceof AST _PropAccess && p . expression === this ) return true ;
} ) ;
PARENS ( [ AST _Assign , AST _Conditional ] , function ( output ) {
var p = output . parent ( ) ;
if ( p instanceof AST _Unary ) return true ;
if ( p instanceof AST _Binary && ! ( p instanceof AST _Assign ) ) return true ;
if ( p instanceof AST _Call && p . expression === this ) return true ;
if ( p instanceof AST _Conditional && p . condition === this ) return true ;
if ( p instanceof AST _PropAccess && p . expression === this ) return true ;
} ) ;
DEFPRINT ( AST _Directive , function ( self , output ) {
output . print _string ( self . value ) ;
output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _Debugger , function ( self , output ) {
output . print ( "debugger" ) ;
output . semicolon ( ) ;
} ) ;
function display _body ( body , is _toplevel , output ) {
var last = body . length - 1 ;
body . forEach ( function ( stmt , i ) {
if ( ! ( stmt instanceof AST _EmptyStatement ) ) {
output . indent ( ) ;
stmt . print ( output ) ;
if ( ! ( i == last && is _toplevel ) ) {
output . newline ( ) ;
if ( is _toplevel ) output . newline ( ) ;
}
}
} ) ;
}
AST _StatementWithBody . DEFMETHOD ( "_do_print_body" , function ( output ) {
force _statement ( this . body , output ) ;
} ) ;
DEFPRINT ( AST _Statement , function ( self , output ) {
self . body . print ( output ) ;
output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _Toplevel , function ( self , output ) {
display _body ( self . body , true , output ) ;
output . print ( "" ) ;
} ) ;
DEFPRINT ( AST _LabeledStatement , function ( self , output ) {
self . label . print ( output ) ;
output . colon ( ) ;
self . body . print ( output ) ;
} ) ;
DEFPRINT ( AST _SimpleStatement , function ( self , output ) {
self . body . print ( output ) ;
output . semicolon ( ) ;
} ) ;
function print _bracketed ( body , output ) {
if ( body . length > 0 ) output . with _block ( function ( ) {
display _body ( body , false , output ) ;
} ) ; else output . print ( "{}" ) ;
}
DEFPRINT ( AST _BlockStatement , function ( self , output ) {
print _bracketed ( self . body , output ) ;
} ) ;
DEFPRINT ( AST _EmptyStatement , function ( self , output ) {
output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _Do , function ( self , output ) {
output . print ( "do" ) ;
output . space ( ) ;
self . _do _print _body ( output ) ;
output . space ( ) ;
output . print ( "while" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . condition . print ( output ) ;
} ) ;
output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _While , function ( self , output ) {
output . print ( "while" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . condition . print ( output ) ;
} ) ;
output . space ( ) ;
self . _do _print _body ( output ) ;
} ) ;
DEFPRINT ( AST _For , function ( self , output ) {
output . print ( "for" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
if ( self . init && ! ( self . init instanceof AST _EmptyStatement ) ) {
if ( self . init instanceof AST _Definitions ) {
self . init . print ( output ) ;
} else {
parenthesize _for _noin ( self . init , output , true ) ;
}
output . print ( ";" ) ;
output . space ( ) ;
} else {
output . print ( ";" ) ;
}
if ( self . condition ) {
self . condition . print ( output ) ;
output . print ( ";" ) ;
output . space ( ) ;
} else {
output . print ( ";" ) ;
}
if ( self . step ) {
self . step . print ( output ) ;
}
} ) ;
output . space ( ) ;
self . _do _print _body ( output ) ;
} ) ;
DEFPRINT ( AST _ForIn , function ( self , output ) {
output . print ( "for" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . init . print ( output ) ;
output . space ( ) ;
output . print ( "in" ) ;
output . space ( ) ;
self . object . print ( output ) ;
} ) ;
output . space ( ) ;
self . _do _print _body ( output ) ;
} ) ;
DEFPRINT ( AST _With , function ( self , output ) {
output . print ( "with" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . expression . print ( output ) ;
} ) ;
output . space ( ) ;
self . _do _print _body ( output ) ;
} ) ;
AST _Lambda . DEFMETHOD ( "_do_print" , function ( output , nokeyword ) {
var self = this ;
if ( ! nokeyword ) {
output . print ( "function" ) ;
}
if ( self . name ) {
output . space ( ) ;
self . name . print ( output ) ;
}
output . with _parens ( function ( ) {
self . argnames . forEach ( function ( arg , i ) {
if ( i ) output . comma ( ) ;
arg . print ( output ) ;
} ) ;
} ) ;
output . space ( ) ;
print _bracketed ( self . body , output ) ;
} ) ;
DEFPRINT ( AST _Lambda , function ( self , output ) {
self . _do _print ( output ) ;
} ) ;
AST _Exit . DEFMETHOD ( "_do_print" , function ( output , kind ) {
output . print ( kind ) ;
if ( this . value ) {
output . space ( ) ;
this . value . print ( output ) ;
}
output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _Return , function ( self , output ) {
self . _do _print ( output , "return" ) ;
} ) ;
DEFPRINT ( AST _Throw , function ( self , output ) {
self . _do _print ( output , "throw" ) ;
} ) ;
AST _LoopControl . DEFMETHOD ( "_do_print" , function ( output , kind ) {
output . print ( kind ) ;
if ( this . label ) {
output . space ( ) ;
this . label . print ( output ) ;
}
output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _Break , function ( self , output ) {
self . _do _print ( output , "break" ) ;
} ) ;
DEFPRINT ( AST _Continue , function ( self , output ) {
self . _do _print ( output , "continue" ) ;
} ) ;
function make _then ( self , output ) {
if ( output . option ( "bracketize" ) ) {
make _block ( self . body , output ) ;
return ;
}
if ( ! self . body ) return output . force _semicolon ( ) ;
if ( self . body instanceof AST _Do && ! output . option ( "screw_ie8" ) ) {
make _block ( self . body , output ) ;
return ;
}
var b = self . body ;
while ( true ) {
if ( b instanceof AST _If ) {
if ( ! b . alternative ) {
make _block ( self . body , output ) ;
return ;
}
b = b . alternative ;
} else if ( b instanceof AST _StatementWithBody ) {
b = b . body ;
} else break ;
}
force _statement ( self . body , output ) ;
}
DEFPRINT ( AST _If , function ( self , output ) {
output . print ( "if" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . condition . print ( output ) ;
} ) ;
output . space ( ) ;
if ( self . alternative ) {
make _then ( self , output ) ;
output . space ( ) ;
output . print ( "else" ) ;
output . space ( ) ;
force _statement ( self . alternative , output ) ;
} else {
self . _do _print _body ( output ) ;
}
} ) ;
DEFPRINT ( AST _Switch , function ( self , output ) {
output . print ( "switch" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . expression . print ( output ) ;
} ) ;
output . space ( ) ;
if ( self . body . length > 0 ) output . with _block ( function ( ) {
self . body . forEach ( function ( stmt , i ) {
if ( i ) output . newline ( ) ;
output . indent ( true ) ;
stmt . print ( output ) ;
} ) ;
} ) ; else output . print ( "{}" ) ;
} ) ;
AST _SwitchBranch . DEFMETHOD ( "_do_print_body" , function ( output ) {
if ( this . body . length > 0 ) {
output . newline ( ) ;
this . body . forEach ( function ( stmt ) {
output . indent ( ) ;
stmt . print ( output ) ;
output . newline ( ) ;
} ) ;
}
} ) ;
DEFPRINT ( AST _Default , function ( self , output ) {
output . print ( "default:" ) ;
self . _do _print _body ( output ) ;
} ) ;
DEFPRINT ( AST _Case , function ( self , output ) {
output . print ( "case" ) ;
output . space ( ) ;
self . expression . print ( output ) ;
output . print ( ":" ) ;
self . _do _print _body ( output ) ;
} ) ;
DEFPRINT ( AST _Try , function ( self , output ) {
output . print ( "try" ) ;
output . space ( ) ;
print _bracketed ( self . body , output ) ;
if ( self . bcatch ) {
output . space ( ) ;
self . bcatch . print ( output ) ;
}
if ( self . bfinally ) {
output . space ( ) ;
self . bfinally . print ( output ) ;
}
} ) ;
DEFPRINT ( AST _Catch , function ( self , output ) {
output . print ( "catch" ) ;
output . space ( ) ;
output . with _parens ( function ( ) {
self . argname . print ( output ) ;
} ) ;
output . space ( ) ;
print _bracketed ( self . body , output ) ;
} ) ;
DEFPRINT ( AST _Finally , function ( self , output ) {
output . print ( "finally" ) ;
output . space ( ) ;
print _bracketed ( self . body , output ) ;
} ) ;
AST _Definitions . DEFMETHOD ( "_do_print" , function ( output , kind ) {
output . print ( kind ) ;
output . space ( ) ;
this . definitions . forEach ( function ( def , i ) {
if ( i ) output . comma ( ) ;
def . print ( output ) ;
} ) ;
var p = output . parent ( ) ;
var in _for = p instanceof AST _For || p instanceof AST _ForIn ;
var avoid _semicolon = in _for && p . init === this ;
if ( ! avoid _semicolon ) output . semicolon ( ) ;
} ) ;
DEFPRINT ( AST _Var , function ( self , output ) {
self . _do _print ( output , "var" ) ;
} ) ;
DEFPRINT ( AST _Const , function ( self , output ) {
self . _do _print ( output , "const" ) ;
} ) ;
function parenthesize _for _noin ( node , output , noin ) {
if ( ! noin ) node . print ( output ) ; else try {
node . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Binary && node . operator == "in" ) throw output ;
} ) ) ;
node . print ( output ) ;
} catch ( ex ) {
if ( ex !== output ) throw ex ;
node . print ( output , true ) ;
}
}
DEFPRINT ( AST _VarDef , function ( self , output ) {
self . name . print ( output ) ;
if ( self . value ) {
output . space ( ) ;
output . print ( "=" ) ;
output . space ( ) ;
var p = output . parent ( 1 ) ;
var noin = p instanceof AST _For || p instanceof AST _ForIn ;
parenthesize _for _noin ( self . value , output , noin ) ;
}
} ) ;
DEFPRINT ( AST _Call , function ( self , output ) {
self . expression . print ( output ) ;
if ( self instanceof AST _New && no _constructor _parens ( self , output ) ) return ;
output . with _parens ( function ( ) {
self . args . forEach ( function ( expr , i ) {
if ( i ) output . comma ( ) ;
expr . print ( output ) ;
} ) ;
} ) ;
} ) ;
DEFPRINT ( AST _New , function ( self , output ) {
output . print ( "new" ) ;
output . space ( ) ;
AST _Call . prototype . _codegen ( self , output ) ;
} ) ;
AST _Seq . DEFMETHOD ( "_do_print" , function ( output ) {
this . car . print ( output ) ;
if ( this . cdr ) {
output . comma ( ) ;
if ( output . should _break ( ) ) {
output . newline ( ) ;
output . indent ( ) ;
}
this . cdr . print ( output ) ;
}
} ) ;
DEFPRINT ( AST _Seq , function ( self , output ) {
self . _do _print ( output ) ;
} ) ;
DEFPRINT ( AST _Dot , function ( self , output ) {
var expr = self . expression ;
expr . print ( output ) ;
if ( expr instanceof AST _Number && expr . getValue ( ) >= 0 ) {
if ( ! /[xa-f.]/i . test ( output . last ( ) ) ) {
output . print ( "." ) ;
}
}
output . print ( "." ) ;
output . add _mapping ( self . end ) ;
output . print _name ( self . property ) ;
} ) ;
DEFPRINT ( AST _Sub , function ( self , output ) {
self . expression . print ( output ) ;
output . print ( "[" ) ;
self . property . print ( output ) ;
output . print ( "]" ) ;
} ) ;
DEFPRINT ( AST _UnaryPrefix , function ( self , output ) {
var op = self . operator ;
output . print ( op ) ;
if ( /^[a-z]/i . test ( op ) || /[+-]$/ . test ( op ) && self . expression instanceof AST _UnaryPrefix && /^[+-]/ . test ( self . expression . operator ) ) {
output . space ( ) ;
}
self . expression . print ( output ) ;
} ) ;
DEFPRINT ( AST _UnaryPostfix , function ( self , output ) {
self . expression . print ( output ) ;
output . print ( self . operator ) ;
} ) ;
DEFPRINT ( AST _Binary , function ( self , output ) {
self . left . print ( output ) ;
output . space ( ) ;
output . print ( self . operator ) ;
if ( self . operator == "<" && self . right instanceof AST _UnaryPrefix && self . right . operator == "!" && self . right . expression instanceof AST _UnaryPrefix && self . right . expression . operator == "--" ) {
output . print ( " " ) ;
} else {
output . space ( ) ;
}
self . right . print ( output ) ;
} ) ;
DEFPRINT ( AST _Conditional , function ( self , output ) {
self . condition . print ( output ) ;
output . space ( ) ;
output . print ( "?" ) ;
output . space ( ) ;
self . consequent . print ( output ) ;
output . space ( ) ;
output . colon ( ) ;
self . alternative . print ( output ) ;
} ) ;
DEFPRINT ( AST _Array , function ( self , output ) {
output . with _square ( function ( ) {
var a = self . elements , len = a . length ;
if ( len > 0 ) output . space ( ) ;
a . forEach ( function ( exp , i ) {
if ( i ) output . comma ( ) ;
exp . print ( output ) ;
if ( i === len - 1 && exp instanceof AST _Hole ) output . comma ( ) ;
} ) ;
if ( len > 0 ) output . space ( ) ;
} ) ;
} ) ;
DEFPRINT ( AST _Object , function ( self , output ) {
if ( self . properties . length > 0 ) output . with _block ( function ( ) {
self . properties . forEach ( function ( prop , i ) {
if ( i ) {
output . print ( "," ) ;
output . newline ( ) ;
}
output . indent ( ) ;
prop . print ( output ) ;
} ) ;
output . newline ( ) ;
} ) ; else output . print ( "{}" ) ;
} ) ;
DEFPRINT ( AST _ObjectKeyVal , function ( self , output ) {
var key = self . key ;
if ( output . option ( "quote_keys" ) ) {
output . print _string ( key + "" ) ;
} else if ( ( typeof key == "number" || ! output . option ( "beautify" ) && + key + "" == key ) && parseFloat ( key ) >= 0 ) {
output . print ( make _num ( key ) ) ;
} else if ( RESERVED _WORDS ( key ) ? output . option ( "screw_ie8" ) : is _identifier _string ( key ) ) {
output . print _name ( key ) ;
} else {
output . print _string ( key ) ;
}
output . colon ( ) ;
self . value . print ( output ) ;
} ) ;
DEFPRINT ( AST _ObjectSetter , function ( self , output ) {
output . print ( "set" ) ;
output . space ( ) ;
self . key . print ( output ) ;
self . value . _do _print ( output , true ) ;
} ) ;
DEFPRINT ( AST _ObjectGetter , function ( self , output ) {
output . print ( "get" ) ;
output . space ( ) ;
self . key . print ( output ) ;
self . value . _do _print ( output , true ) ;
} ) ;
DEFPRINT ( AST _Symbol , function ( self , output ) {
var def = self . definition ( ) ;
output . print _name ( def ? def . mangled _name || def . name : self . name ) ;
} ) ;
DEFPRINT ( AST _Undefined , function ( self , output ) {
output . print ( "void 0" ) ;
} ) ;
DEFPRINT ( AST _Hole , noop ) ;
DEFPRINT ( AST _Infinity , function ( self , output ) {
output . print ( "1/0" ) ;
} ) ;
DEFPRINT ( AST _NaN , function ( self , output ) {
output . print ( "0/0" ) ;
} ) ;
DEFPRINT ( AST _This , function ( self , output ) {
output . print ( "this" ) ;
} ) ;
DEFPRINT ( AST _Constant , function ( self , output ) {
output . print ( self . getValue ( ) ) ;
} ) ;
DEFPRINT ( AST _String , function ( self , output ) {
output . print _string ( self . getValue ( ) ) ;
} ) ;
DEFPRINT ( AST _Number , function ( self , output ) {
output . print ( make _num ( self . getValue ( ) ) ) ;
} ) ;
function regexp _safe _literal ( code ) {
return [ 92 , 47 , 46 , 43 , 42 , 63 , 40 , 41 , 91 , 93 , 123 , 125 , 36 , 94 , 58 , 124 , 33 , 10 , 13 , 0 , 65279 , 8232 , 8233 ] . indexOf ( code ) < 0 ;
}
DEFPRINT ( AST _RegExp , function ( self , output ) {
var str = self . getValue ( ) . toString ( ) ;
if ( output . option ( "ascii_only" ) ) {
str = output . to _ascii ( str ) ;
} else if ( output . option ( "unescape_regexps" ) ) {
str = str . split ( "\\\\" ) . map ( function ( str ) {
return str . replace ( /\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}/g , function ( s ) {
var code = parseInt ( s . substr ( 2 ) , 16 ) ;
return regexp _safe _literal ( code ) ? String . fromCharCode ( code ) : s ;
} ) ;
} ) . join ( "\\\\" ) ;
}
output . print ( str ) ;
var p = output . parent ( ) ;
if ( p instanceof AST _Binary && /^in/ . test ( p . operator ) && p . left === self ) output . print ( " " ) ;
} ) ;
function force _statement ( stat , output ) {
if ( output . option ( "bracketize" ) ) {
if ( ! stat || stat instanceof AST _EmptyStatement ) output . print ( "{}" ) ; else if ( stat instanceof AST _BlockStatement ) stat . print ( output ) ; else output . with _block ( function ( ) {
output . indent ( ) ;
stat . print ( output ) ;
output . newline ( ) ;
} ) ;
} else {
if ( ! stat || stat instanceof AST _EmptyStatement ) output . force _semicolon ( ) ; else stat . print ( output ) ;
}
}
function first _in _statement ( output ) {
var a = output . stack ( ) , i = a . length , node = a [ -- i ] , p = a [ -- i ] ;
while ( i > 0 ) {
if ( p instanceof AST _Statement && p . body === node ) return true ;
if ( p instanceof AST _Seq && p . car === node || p instanceof AST _Call && p . expression === node && ! ( p instanceof AST _New ) || p instanceof AST _Dot && p . expression === node || p instanceof AST _Sub && p . expression === node || p instanceof AST _Conditional && p . condition === node || p instanceof AST _Binary && p . left === node || p instanceof AST _UnaryPostfix && p . expression === node ) {
node = p ;
p = a [ -- i ] ;
} else {
return false ;
}
}
}
function no _constructor _parens ( self , output ) {
return self . args . length == 0 && ! output . option ( "beautify" ) ;
}
function best _of ( a ) {
var best = a [ 0 ] , len = best . length ;
for ( var i = 1 ; i < a . length ; ++ i ) {
if ( a [ i ] . length < len ) {
best = a [ i ] ;
len = best . length ;
}
}
return best ;
}
function make _num ( num ) {
var str = num . toString ( 10 ) , a = [ str . replace ( /^0\./ , "." ) . replace ( "e+" , "e" ) ] , m ;
if ( Math . floor ( num ) === num ) {
if ( num >= 0 ) {
a . push ( "0x" + num . toString ( 16 ) . toLowerCase ( ) , "0" + num . toString ( 8 ) ) ;
} else {
a . push ( "-0x" + ( - num ) . toString ( 16 ) . toLowerCase ( ) , "-0" + ( - num ) . toString ( 8 ) ) ;
}
if ( m = /^(.*?)(0+)$/ . exec ( num ) ) {
a . push ( m [ 1 ] + "e" + m [ 2 ] . length ) ;
}
} else if ( m = /^0?\.(0+)(.*)$/ . exec ( num ) ) {
a . push ( m [ 2 ] + "e-" + ( m [ 1 ] . length + m [ 2 ] . length ) , str . substr ( str . indexOf ( "." ) ) ) ;
}
return best _of ( a ) ;
}
function make _block ( stmt , output ) {
if ( stmt instanceof AST _BlockStatement ) {
stmt . print ( output ) ;
return ;
}
output . with _block ( function ( ) {
output . indent ( ) ;
stmt . print ( output ) ;
output . newline ( ) ;
} ) ;
}
function DEFMAP ( nodetype , generator ) {
nodetype . DEFMETHOD ( "add_source_map" , function ( stream ) {
generator ( this , stream ) ;
} ) ;
}
DEFMAP ( AST _Node , noop ) ;
function basic _sourcemap _gen ( self , output ) {
output . add _mapping ( self . start ) ;
}
DEFMAP ( AST _Directive , basic _sourcemap _gen ) ;
DEFMAP ( AST _Debugger , basic _sourcemap _gen ) ;
DEFMAP ( AST _Symbol , basic _sourcemap _gen ) ;
DEFMAP ( AST _Jump , basic _sourcemap _gen ) ;
DEFMAP ( AST _StatementWithBody , basic _sourcemap _gen ) ;
DEFMAP ( AST _LabeledStatement , noop ) ;
DEFMAP ( AST _Lambda , basic _sourcemap _gen ) ;
DEFMAP ( AST _Switch , basic _sourcemap _gen ) ;
DEFMAP ( AST _SwitchBranch , basic _sourcemap _gen ) ;
DEFMAP ( AST _BlockStatement , basic _sourcemap _gen ) ;
DEFMAP ( AST _Toplevel , noop ) ;
DEFMAP ( AST _New , basic _sourcemap _gen ) ;
DEFMAP ( AST _Try , basic _sourcemap _gen ) ;
DEFMAP ( AST _Catch , basic _sourcemap _gen ) ;
DEFMAP ( AST _Finally , basic _sourcemap _gen ) ;
DEFMAP ( AST _Definitions , basic _sourcemap _gen ) ;
DEFMAP ( AST _Constant , basic _sourcemap _gen ) ;
DEFMAP ( AST _ObjectProperty , function ( self , output ) {
output . add _mapping ( self . start , self . key ) ;
} ) ;
} ) ( ) ;
"use strict" ;
function Compressor ( options , false _by _default ) {
if ( ! ( this instanceof Compressor ) ) return new Compressor ( options , false _by _default ) ;
TreeTransformer . call ( this , this . before , this . after ) ;
this . options = defaults ( options , {
sequences : ! false _by _default ,
properties : ! false _by _default ,
dead _code : ! false _by _default ,
drop _debugger : ! false _by _default ,
unsafe : false ,
unsafe _comps : false ,
conditionals : ! false _by _default ,
comparisons : ! false _by _default ,
evaluate : ! false _by _default ,
booleans : ! false _by _default ,
loops : ! false _by _default ,
unused : ! false _by _default ,
hoist _funs : ! false _by _default ,
keep _fargs : false ,
hoist _vars : false ,
if _return : ! false _by _default ,
join _vars : ! false _by _default ,
cascade : ! false _by _default ,
side _effects : ! false _by _default ,
pure _getters : false ,
pure _funcs : null ,
negate _iife : ! false _by _default ,
screw _ie8 : false ,
drop _console : false ,
angular : false ,
warnings : true ,
global _defs : { }
} , true ) ;
}
Compressor . prototype = new TreeTransformer ( ) ;
merge ( Compressor . prototype , {
option : function ( key ) {
return this . options [ key ] ;
} ,
warn : function ( ) {
if ( this . options . warnings ) AST _Node . warn . apply ( AST _Node , arguments ) ;
} ,
before : function ( node , descend , in _list ) {
if ( node . _squeezed ) return node ;
var was _scope = false ;
if ( node instanceof AST _Scope ) {
node = node . hoist _declarations ( this ) ;
was _scope = true ;
}
descend ( node , this ) ;
node = node . optimize ( this ) ;
if ( was _scope && node instanceof AST _Scope ) {
node . drop _unused ( this ) ;
descend ( node , this ) ;
}
node . _squeezed = true ;
return node ;
}
} ) ;
( function ( ) {
function OPT ( node , optimizer ) {
node . DEFMETHOD ( "optimize" , function ( compressor ) {
var self = this ;
if ( self . _optimized ) return self ;
var opt = optimizer ( self , compressor ) ;
opt . _optimized = true ;
if ( opt === self ) return opt ;
return opt . transform ( compressor ) ;
} ) ;
}
OPT ( AST _Node , function ( self , compressor ) {
return self ;
} ) ;
AST _Node . DEFMETHOD ( "equivalent_to" , function ( node ) {
return this . print _to _string ( ) == node . print _to _string ( ) ;
} ) ;
function make _node ( ctor , orig , props ) {
if ( ! props ) props = { } ;
if ( orig ) {
if ( ! props . start ) props . start = orig . start ;
if ( ! props . end ) props . end = orig . end ;
}
return new ctor ( props ) ;
}
function make _node _from _constant ( compressor , val , orig ) {
if ( val instanceof AST _Node ) return val . transform ( compressor ) ;
switch ( typeof val ) {
case "string" :
return make _node ( AST _String , orig , {
value : val
} ) . optimize ( compressor ) ;
case "number" :
return make _node ( isNaN ( val ) ? AST _NaN : AST _Number , orig , {
value : val
} ) . optimize ( compressor ) ;
case "boolean" :
return make _node ( val ? AST _True : AST _False , orig ) . optimize ( compressor ) ;
case "undefined" :
return make _node ( AST _Undefined , orig ) . optimize ( compressor ) ;
default :
if ( val === null ) {
return make _node ( AST _Null , orig ) . optimize ( compressor ) ;
}
if ( val instanceof RegExp ) {
return make _node ( AST _RegExp , orig ) . optimize ( compressor ) ;
}
throw new Error ( string _template ( "Can't handle constant of type: {type}" , {
type : typeof val
} ) ) ;
}
}
function as _statement _array ( thing ) {
if ( thing === null ) return [ ] ;
if ( thing instanceof AST _BlockStatement ) return thing . body ;
if ( thing instanceof AST _EmptyStatement ) return [ ] ;
if ( thing instanceof AST _Statement ) return [ thing ] ;
throw new Error ( "Can't convert thing to statement array" ) ;
}
function is _empty ( thing ) {
if ( thing === null ) return true ;
if ( thing instanceof AST _EmptyStatement ) return true ;
if ( thing instanceof AST _BlockStatement ) return thing . body . length == 0 ;
return false ;
}
function loop _body ( x ) {
if ( x instanceof AST _Switch ) return x ;
if ( x instanceof AST _For || x instanceof AST _ForIn || x instanceof AST _DWLoop ) {
return x . body instanceof AST _BlockStatement ? x . body : x ;
}
return x ;
}
function tighten _body ( statements , compressor ) {
var CHANGED ;
do {
CHANGED = false ;
if ( compressor . option ( "angular" ) ) {
statements = process _for _angular ( statements ) ;
}
statements = eliminate _spurious _blocks ( statements ) ;
if ( compressor . option ( "dead_code" ) ) {
statements = eliminate _dead _code ( statements , compressor ) ;
}
if ( compressor . option ( "if_return" ) ) {
statements = handle _if _return ( statements , compressor ) ;
}
if ( compressor . option ( "sequences" ) ) {
statements = sequencesize ( statements , compressor ) ;
}
if ( compressor . option ( "join_vars" ) ) {
statements = join _consecutive _vars ( statements , compressor ) ;
}
} while ( CHANGED ) ;
if ( compressor . option ( "negate_iife" ) ) {
negate _iifes ( statements , compressor ) ;
}
return statements ;
function process _for _angular ( statements ) {
function make _injector ( func , name ) {
return make _node ( AST _SimpleStatement , func , {
body : make _node ( AST _Assign , func , {
operator : "=" ,
left : make _node ( AST _Dot , name , {
expression : make _node ( AST _SymbolRef , name , name ) ,
property : "$inject"
} ) ,
right : make _node ( AST _Array , func , {
elements : func . argnames . map ( function ( sym ) {
return make _node ( AST _String , sym , {
value : sym . name
} ) ;
} )
} )
} )
} ) ;
}
return statements . reduce ( function ( a , stat ) {
a . push ( stat ) ;
var token = stat . start ;
var comments = token . comments _before ;
if ( comments && comments . length > 0 ) {
var last = comments . pop ( ) ;
if ( /@ngInject/ . test ( last . value ) ) {
if ( stat instanceof AST _Defun ) {
a . push ( make _injector ( stat , stat . name ) ) ;
} else if ( stat instanceof AST _Definitions ) {
stat . definitions . forEach ( function ( def ) {
if ( def . value && def . value instanceof AST _Lambda ) {
a . push ( make _injector ( def . value , def . name ) ) ;
}
} ) ;
} else {
compressor . warn ( "Unknown statement marked with @ngInject [{file}:{line},{col}]" , token ) ;
}
}
}
return a ;
} , [ ] ) ;
}
function eliminate _spurious _blocks ( statements ) {
var seen _dirs = [ ] ;
return statements . reduce ( function ( a , stat ) {
if ( stat instanceof AST _BlockStatement ) {
CHANGED = true ;
a . push . apply ( a , eliminate _spurious _blocks ( stat . body ) ) ;
} else if ( stat instanceof AST _EmptyStatement ) {
CHANGED = true ;
} else if ( stat instanceof AST _Directive ) {
if ( seen _dirs . indexOf ( stat . value ) < 0 ) {
a . push ( stat ) ;
seen _dirs . push ( stat . value ) ;
} else {
CHANGED = true ;
}
} else {
a . push ( stat ) ;
}
return a ;
} , [ ] ) ;
}
function handle _if _return ( statements , compressor ) {
var self = compressor . self ( ) ;
var in _lambda = self instanceof AST _Lambda ;
var ret = [ ] ;
loop : for ( var i = statements . length ; -- i >= 0 ; ) {
var stat = statements [ i ] ;
switch ( true ) {
case in _lambda && stat instanceof AST _Return && ! stat . value && ret . length == 0 :
CHANGED = true ;
continue loop ;
case stat instanceof AST _If :
if ( stat . body instanceof AST _Return ) {
if ( ( in _lambda && ret . length == 0 || ret [ 0 ] instanceof AST _Return && ! ret [ 0 ] . value ) && ! stat . body . value && ! stat . alternative ) {
CHANGED = true ;
var cond = make _node ( AST _SimpleStatement , stat . condition , {
body : stat . condition
} ) ;
ret . unshift ( cond ) ;
continue loop ;
}
if ( ret [ 0 ] instanceof AST _Return && stat . body . value && ret [ 0 ] . value && ! stat . alternative ) {
CHANGED = true ;
stat = stat . clone ( ) ;
stat . alternative = ret [ 0 ] ;
ret [ 0 ] = stat . transform ( compressor ) ;
continue loop ;
}
if ( ( ret . length == 0 || ret [ 0 ] instanceof AST _Return ) && stat . body . value && ! stat . alternative && in _lambda ) {
CHANGED = true ;
stat = stat . clone ( ) ;
stat . alternative = ret [ 0 ] || make _node ( AST _Return , stat , {
value : make _node ( AST _Undefined , stat )
} ) ;
ret [ 0 ] = stat . transform ( compressor ) ;
continue loop ;
}
if ( ! stat . body . value && in _lambda ) {
CHANGED = true ;
stat = stat . clone ( ) ;
stat . condition = stat . condition . negate ( compressor ) ;
stat . body = make _node ( AST _BlockStatement , stat , {
body : as _statement _array ( stat . alternative ) . concat ( ret )
} ) ;
stat . alternative = null ;
ret = [ stat . transform ( compressor ) ] ;
continue loop ;
}
if ( ret . length == 1 && in _lambda && ret [ 0 ] instanceof AST _SimpleStatement && ( ! stat . alternative || stat . alternative instanceof AST _SimpleStatement ) ) {
CHANGED = true ;
ret . push ( make _node ( AST _Return , ret [ 0 ] , {
value : make _node ( AST _Undefined , ret [ 0 ] )
} ) . transform ( compressor ) ) ;
ret = as _statement _array ( stat . alternative ) . concat ( ret ) ;
ret . unshift ( stat ) ;
continue loop ;
}
}
var ab = aborts ( stat . body ) ;
var lct = ab instanceof AST _LoopControl ? compressor . loopcontrol _target ( ab . label ) : null ;
if ( ab && ( ab instanceof AST _Return && ! ab . value && in _lambda || ab instanceof AST _Continue && self === loop _body ( lct ) || ab instanceof AST _Break && lct instanceof AST _BlockStatement && self === lct ) ) {
if ( ab . label ) {
remove ( ab . label . thedef . references , ab ) ;
}
CHANGED = true ;
var body = as _statement _array ( stat . body ) . slice ( 0 , - 1 ) ;
stat = stat . clone ( ) ;
stat . condition = stat . condition . negate ( compressor ) ;
stat . body = make _node ( AST _BlockStatement , stat , {
body : as _statement _array ( stat . alternative ) . concat ( ret )
} ) ;
stat . alternative = make _node ( AST _BlockStatement , stat , {
body : body
} ) ;
ret = [ stat . transform ( compressor ) ] ;
continue loop ;
}
var ab = aborts ( stat . alternative ) ;
var lct = ab instanceof AST _LoopControl ? compressor . loopcontrol _target ( ab . label ) : null ;
if ( ab && ( ab instanceof AST _Return && ! ab . value && in _lambda || ab instanceof AST _Continue && self === loop _body ( lct ) || ab instanceof AST _Break && lct instanceof AST _BlockStatement && self === lct ) ) {
if ( ab . label ) {
remove ( ab . label . thedef . references , ab ) ;
}
CHANGED = true ;
stat = stat . clone ( ) ;
stat . body = make _node ( AST _BlockStatement , stat . body , {
body : as _statement _array ( stat . body ) . concat ( ret )
} ) ;
stat . alternative = make _node ( AST _BlockStatement , stat . alternative , {
body : as _statement _array ( stat . alternative ) . slice ( 0 , - 1 )
} ) ;
ret = [ stat . transform ( compressor ) ] ;
continue loop ;
}
ret . unshift ( stat ) ;
break ;
default :
ret . unshift ( stat ) ;
break ;
}
}
return ret ;
}
function eliminate _dead _code ( statements , compressor ) {
var has _quit = false ;
var orig = statements . length ;
var self = compressor . self ( ) ;
statements = statements . reduce ( function ( a , stat ) {
if ( has _quit ) {
extract _declarations _from _unreachable _code ( compressor , stat , a ) ;
} else {
if ( stat instanceof AST _LoopControl ) {
var lct = compressor . loopcontrol _target ( stat . label ) ;
if ( stat instanceof AST _Break && lct instanceof AST _BlockStatement && loop _body ( lct ) === self || stat instanceof AST _Continue && loop _body ( lct ) === self ) {
if ( stat . label ) {
remove ( stat . label . thedef . references , stat ) ;
}
} else {
a . push ( stat ) ;
}
} else {
a . push ( stat ) ;
}
if ( aborts ( stat ) ) has _quit = true ;
}
return a ;
} , [ ] ) ;
CHANGED = statements . length != orig ;
return statements ;
}
function sequencesize ( statements , compressor ) {
if ( statements . length < 2 ) return statements ;
var seq = [ ] , ret = [ ] ;
function push _seq ( ) {
seq = AST _Seq . from _array ( seq ) ;
if ( seq ) ret . push ( make _node ( AST _SimpleStatement , seq , {
body : seq
} ) ) ;
seq = [ ] ;
}
statements . forEach ( function ( stat ) {
if ( stat instanceof AST _SimpleStatement ) seq . push ( stat . body ) ; else push _seq ( ) , ret . push ( stat ) ;
} ) ;
push _seq ( ) ;
ret = sequencesize _2 ( ret , compressor ) ;
CHANGED = ret . length != statements . length ;
return ret ;
}
function sequencesize _2 ( statements , compressor ) {
function cons _seq ( right ) {
ret . pop ( ) ;
var left = prev . body ;
if ( left instanceof AST _Seq ) {
left . add ( right ) ;
} else {
left = AST _Seq . cons ( left , right ) ;
}
return left . transform ( compressor ) ;
}
var ret = [ ] , prev = null ;
statements . forEach ( function ( stat ) {
if ( prev ) {
if ( stat instanceof AST _For ) {
var opera = { } ;
try {
prev . body . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Binary && node . operator == "in" ) throw opera ;
} ) ) ;
if ( stat . init && ! ( stat . init instanceof AST _Definitions ) ) {
stat . init = cons _seq ( stat . init ) ;
} else if ( ! stat . init ) {
stat . init = prev . body ;
ret . pop ( ) ;
}
} catch ( ex ) {
if ( ex !== opera ) throw ex ;
}
} else if ( stat instanceof AST _If ) {
stat . condition = cons _seq ( stat . condition ) ;
} else if ( stat instanceof AST _With ) {
stat . expression = cons _seq ( stat . expression ) ;
} else if ( stat instanceof AST _Exit && stat . value ) {
stat . value = cons _seq ( stat . value ) ;
} else if ( stat instanceof AST _Exit ) {
stat . value = cons _seq ( make _node ( AST _Undefined , stat ) ) ;
} else if ( stat instanceof AST _Switch ) {
stat . expression = cons _seq ( stat . expression ) ;
}
}
ret . push ( stat ) ;
prev = stat instanceof AST _SimpleStatement ? stat : null ;
} ) ;
return ret ;
}
function join _consecutive _vars ( statements , compressor ) {
var prev = null ;
return statements . reduce ( function ( a , stat ) {
if ( stat instanceof AST _Definitions && prev && prev . TYPE == stat . TYPE ) {
prev . definitions = prev . definitions . concat ( stat . definitions ) ;
CHANGED = true ;
} else if ( stat instanceof AST _For && prev instanceof AST _Definitions && ( ! stat . init || stat . init . TYPE == prev . TYPE ) ) {
CHANGED = true ;
a . pop ( ) ;
if ( stat . init ) {
stat . init . definitions = prev . definitions . concat ( stat . init . definitions ) ;
} else {
stat . init = prev ;
}
a . push ( stat ) ;
prev = stat ;
} else {
prev = stat ;
a . push ( stat ) ;
}
return a ;
} , [ ] ) ;
}
function negate _iifes ( statements , compressor ) {
statements . forEach ( function ( stat ) {
if ( stat instanceof AST _SimpleStatement ) {
stat . body = function transform ( thing ) {
return thing . transform ( new TreeTransformer ( function ( node ) {
if ( node instanceof AST _Call && node . expression instanceof AST _Function ) {
return make _node ( AST _UnaryPrefix , node , {
operator : "!" ,
expression : node
} ) ;
} else if ( node instanceof AST _Call ) {
node . expression = transform ( node . expression ) ;
} else if ( node instanceof AST _Seq ) {
node . car = transform ( node . car ) ;
} else if ( node instanceof AST _Conditional ) {
var expr = transform ( node . condition ) ;
if ( expr !== node . condition ) {
node . condition = expr ;
var tmp = node . consequent ;
node . consequent = node . alternative ;
node . alternative = tmp ;
}
}
return node ;
} ) ) ;
} ( stat . body ) ;
}
} ) ;
}
}
function extract _declarations _from _unreachable _code ( compressor , stat , target ) {
compressor . warn ( "Dropping unreachable code [{file}:{line},{col}]" , stat . start ) ;
stat . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Definitions ) {
compressor . warn ( "Declarations in unreachable code! [{file}:{line},{col}]" , node . start ) ;
node . remove _initializers ( ) ;
target . push ( node ) ;
return true ;
}
if ( node instanceof AST _Defun ) {
target . push ( node ) ;
return true ;
}
if ( node instanceof AST _Scope ) {
return true ;
}
} ) ) ;
}
( function ( def ) {
var unary _bool = [ "!" , "delete" ] ;
var binary _bool = [ "in" , "instanceof" , "==" , "!=" , "===" , "!==" , "<" , "<=" , ">=" , ">" ] ;
def ( AST _Node , function ( ) {
return false ;
} ) ;
def ( AST _UnaryPrefix , function ( ) {
return member ( this . operator , unary _bool ) ;
} ) ;
def ( AST _Binary , function ( ) {
return member ( this . operator , binary _bool ) || ( this . operator == "&&" || this . operator == "||" ) && this . left . is _boolean ( ) && this . right . is _boolean ( ) ;
} ) ;
def ( AST _Conditional , function ( ) {
return this . consequent . is _boolean ( ) && this . alternative . is _boolean ( ) ;
} ) ;
def ( AST _Assign , function ( ) {
return this . operator == "=" && this . right . is _boolean ( ) ;
} ) ;
def ( AST _Seq , function ( ) {
return this . cdr . is _boolean ( ) ;
} ) ;
def ( AST _True , function ( ) {
return true ;
} ) ;
def ( AST _False , function ( ) {
return true ;
} ) ;
} ) ( function ( node , func ) {
node . DEFMETHOD ( "is_boolean" , func ) ;
} ) ;
( function ( def ) {
def ( AST _Node , function ( ) {
return false ;
} ) ;
def ( AST _String , function ( ) {
return true ;
} ) ;
def ( AST _UnaryPrefix , function ( ) {
return this . operator == "typeof" ;
} ) ;
def ( AST _Binary , function ( compressor ) {
return this . operator == "+" && ( this . left . is _string ( compressor ) || this . right . is _string ( compressor ) ) ;
} ) ;
def ( AST _Assign , function ( compressor ) {
return ( this . operator == "=" || this . operator == "+=" ) && this . right . is _string ( compressor ) ;
} ) ;
def ( AST _Seq , function ( compressor ) {
return this . cdr . is _string ( compressor ) ;
} ) ;
def ( AST _Conditional , function ( compressor ) {
return this . consequent . is _string ( compressor ) && this . alternative . is _string ( compressor ) ;
} ) ;
def ( AST _Call , function ( compressor ) {
return compressor . option ( "unsafe" ) && this . expression instanceof AST _SymbolRef && this . expression . name == "String" && this . expression . undeclared ( ) ;
} ) ;
} ) ( function ( node , func ) {
node . DEFMETHOD ( "is_string" , func ) ;
} ) ;
function best _of ( ast1 , ast2 ) {
return ast1 . print _to _string ( ) . length > ast2 . print _to _string ( ) . length ? ast2 : ast1 ;
}
( function ( def ) {
AST _Node . DEFMETHOD ( "evaluate" , function ( compressor ) {
if ( ! compressor . option ( "evaluate" ) ) return [ this ] ;
try {
var val = this . _eval ( compressor ) ;
return [ best _of ( make _node _from _constant ( compressor , val , this ) , this ) , val ] ;
} catch ( ex ) {
if ( ex !== def ) throw ex ;
return [ this ] ;
}
} ) ;
def ( AST _Statement , function ( ) {
throw new Error ( string _template ( "Cannot evaluate a statement [{file}:{line},{col}]" , this . start ) ) ;
} ) ;
def ( AST _Function , function ( ) {
throw def ;
} ) ;
function ev ( node , compressor ) {
if ( ! compressor ) throw new Error ( "Compressor must be passed" ) ;
return node . _eval ( compressor ) ;
}
def ( AST _Node , function ( ) {
throw def ;
} ) ;
def ( AST _Constant , function ( ) {
return this . getValue ( ) ;
} ) ;
def ( AST _UnaryPrefix , function ( compressor ) {
var e = this . expression ;
switch ( this . operator ) {
case "!" :
return ! ev ( e , compressor ) ;
case "typeof" :
if ( e instanceof AST _Function ) return typeof function ( ) { } ;
e = ev ( e , compressor ) ;
if ( e instanceof RegExp ) throw def ;
return typeof e ;
case "void" :
return void ev ( e , compressor ) ;
case "~" :
return ~ ev ( e , compressor ) ;
case "-" :
e = ev ( e , compressor ) ;
if ( e === 0 ) throw def ;
return - e ;
case "+" :
return + ev ( e , compressor ) ;
}
throw def ;
} ) ;
def ( AST _Binary , function ( c ) {
var left = this . left , right = this . right ;
switch ( this . operator ) {
case "&&" :
return ev ( left , c ) && ev ( right , c ) ;
case "||" :
return ev ( left , c ) || ev ( right , c ) ;
case "|" :
return ev ( left , c ) | ev ( right , c ) ;
case "&" :
return ev ( left , c ) & ev ( right , c ) ;
case "^" :
return ev ( left , c ) ^ ev ( right , c ) ;
case "+" :
return ev ( left , c ) + ev ( right , c ) ;
case "*" :
return ev ( left , c ) * ev ( right , c ) ;
case "/" :
return ev ( left , c ) / ev ( right , c ) ;
case "%" :
return ev ( left , c ) % ev ( right , c ) ;
case "-" :
return ev ( left , c ) - ev ( right , c ) ;
case "<<" :
return ev ( left , c ) << ev ( right , c ) ;
case ">>" :
return ev ( left , c ) >> ev ( right , c ) ;
case ">>>" :
return ev ( left , c ) >>> ev ( right , c ) ;
case "==" :
return ev ( left , c ) == ev ( right , c ) ;
case "===" :
return ev ( left , c ) === ev ( right , c ) ;
case "!=" :
return ev ( left , c ) != ev ( right , c ) ;
case "!==" :
return ev ( left , c ) !== ev ( right , c ) ;
case "<" :
return ev ( left , c ) < ev ( right , c ) ;
case "<=" :
return ev ( left , c ) <= ev ( right , c ) ;
case ">" :
return ev ( left , c ) > ev ( right , c ) ;
case ">=" :
return ev ( left , c ) >= ev ( right , c ) ;
case "in" :
return ev ( left , c ) in ev ( right , c ) ;
case "instanceof" :
return ev ( left , c ) instanceof ev ( right , c ) ;
}
throw def ;
} ) ;
def ( AST _Conditional , function ( compressor ) {
return ev ( this . condition , compressor ) ? ev ( this . consequent , compressor ) : ev ( this . alternative , compressor ) ;
} ) ;
def ( AST _SymbolRef , function ( compressor ) {
var d = this . definition ( ) ;
if ( d && d . constant && d . init ) return ev ( d . init , compressor ) ;
throw def ;
} ) ;
def ( AST _Dot , function ( compressor ) {
if ( compressor . option ( "unsafe" ) && this . property == "length" ) {
var str = ev ( this . expression , compressor ) ;
if ( typeof str == "string" ) return str . length ;
}
throw def ;
} ) ;
} ) ( function ( node , func ) {
node . DEFMETHOD ( "_eval" , func ) ;
} ) ;
( function ( def ) {
function basic _negation ( exp ) {
return make _node ( AST _UnaryPrefix , exp , {
operator : "!" ,
expression : exp
} ) ;
}
def ( AST _Node , function ( ) {
return basic _negation ( this ) ;
} ) ;
def ( AST _Statement , function ( ) {
throw new Error ( "Cannot negate a statement" ) ;
} ) ;
def ( AST _Function , function ( ) {
return basic _negation ( this ) ;
} ) ;
def ( AST _UnaryPrefix , function ( ) {
if ( this . operator == "!" ) return this . expression ;
return basic _negation ( this ) ;
} ) ;
def ( AST _Seq , function ( compressor ) {
var self = this . clone ( ) ;
self . cdr = self . cdr . negate ( compressor ) ;
return self ;
} ) ;
def ( AST _Conditional , function ( compressor ) {
var self = this . clone ( ) ;
self . consequent = self . consequent . negate ( compressor ) ;
self . alternative = self . alternative . negate ( compressor ) ;
return best _of ( basic _negation ( this ) , self ) ;
} ) ;
def ( AST _Binary , function ( compressor ) {
var self = this . clone ( ) , op = this . operator ;
if ( compressor . option ( "unsafe_comps" ) ) {
switch ( op ) {
case "<=" :
self . operator = ">" ;
return self ;
case "<" :
self . operator = ">=" ;
return self ;
case ">=" :
self . operator = "<" ;
return self ;
case ">" :
self . operator = "<=" ;
return self ;
}
}
switch ( op ) {
case "==" :
self . operator = "!=" ;
return self ;
case "!=" :
self . operator = "==" ;
return self ;
case "===" :
self . operator = "!==" ;
return self ;
case "!==" :
self . operator = "===" ;
return self ;
case "&&" :
self . operator = "||" ;
self . left = self . left . negate ( compressor ) ;
self . right = self . right . negate ( compressor ) ;
return best _of ( basic _negation ( this ) , self ) ;
case "||" :
self . operator = "&&" ;
self . left = self . left . negate ( compressor ) ;
self . right = self . right . negate ( compressor ) ;
return best _of ( basic _negation ( this ) , self ) ;
}
return basic _negation ( this ) ;
} ) ;
} ) ( function ( node , func ) {
node . DEFMETHOD ( "negate" , function ( compressor ) {
return func . call ( this , compressor ) ;
} ) ;
} ) ;
( function ( def ) {
def ( AST _Node , function ( compressor ) {
return true ;
} ) ;
def ( AST _EmptyStatement , function ( compressor ) {
return false ;
} ) ;
def ( AST _Constant , function ( compressor ) {
return false ;
} ) ;
def ( AST _This , function ( compressor ) {
return false ;
} ) ;
def ( AST _Call , function ( compressor ) {
var pure = compressor . option ( "pure_funcs" ) ;
if ( ! pure ) return true ;
return pure . indexOf ( this . expression . print _to _string ( ) ) < 0 ;
} ) ;
def ( AST _Block , function ( compressor ) {
for ( var i = this . body . length ; -- i >= 0 ; ) {
if ( this . body [ i ] . has _side _effects ( compressor ) ) return true ;
}
return false ;
} ) ;
def ( AST _SimpleStatement , function ( compressor ) {
return this . body . has _side _effects ( compressor ) ;
} ) ;
def ( AST _Defun , function ( compressor ) {
return true ;
} ) ;
def ( AST _Function , function ( compressor ) {
return false ;
} ) ;
def ( AST _Binary , function ( compressor ) {
return this . left . has _side _effects ( compressor ) || this . right . has _side _effects ( compressor ) ;
} ) ;
def ( AST _Assign , function ( compressor ) {
return true ;
} ) ;
def ( AST _Conditional , function ( compressor ) {
return this . condition . has _side _effects ( compressor ) || this . consequent . has _side _effects ( compressor ) || this . alternative . has _side _effects ( compressor ) ;
} ) ;
def ( AST _Unary , function ( compressor ) {
return this . operator == "delete" || this . operator == "++" || this . operator == "--" || this . expression . has _side _effects ( compressor ) ;
} ) ;
def ( AST _SymbolRef , function ( compressor ) {
return false ;
} ) ;
def ( AST _Object , function ( compressor ) {
for ( var i = this . properties . length ; -- i >= 0 ; ) if ( this . properties [ i ] . has _side _effects ( compressor ) ) return true ;
return false ;
} ) ;
def ( AST _ObjectProperty , function ( compressor ) {
return this . value . has _side _effects ( compressor ) ;
} ) ;
def ( AST _Array , function ( compressor ) {
for ( var i = this . elements . length ; -- i >= 0 ; ) if ( this . elements [ i ] . has _side _effects ( compressor ) ) return true ;
return false ;
} ) ;
def ( AST _Dot , function ( compressor ) {
if ( ! compressor . option ( "pure_getters" ) ) return true ;
return this . expression . has _side _effects ( compressor ) ;
} ) ;
def ( AST _Sub , function ( compressor ) {
if ( ! compressor . option ( "pure_getters" ) ) return true ;
return this . expression . has _side _effects ( compressor ) || this . property . has _side _effects ( compressor ) ;
} ) ;
def ( AST _PropAccess , function ( compressor ) {
return ! compressor . option ( "pure_getters" ) ;
} ) ;
def ( AST _Seq , function ( compressor ) {
return this . car . has _side _effects ( compressor ) || this . cdr . has _side _effects ( compressor ) ;
} ) ;
} ) ( function ( node , func ) {
node . DEFMETHOD ( "has_side_effects" , func ) ;
} ) ;
function aborts ( thing ) {
return thing && thing . aborts ( ) ;
}
( function ( def ) {
def ( AST _Statement , function ( ) {
return null ;
} ) ;
def ( AST _Jump , function ( ) {
return this ;
} ) ;
function block _aborts ( ) {
var n = this . body . length ;
return n > 0 && aborts ( this . body [ n - 1 ] ) ;
}
def ( AST _BlockStatement , block _aborts ) ;
def ( AST _SwitchBranch , block _aborts ) ;
def ( AST _If , function ( ) {
return this . alternative && aborts ( this . body ) && aborts ( this . alternative ) ;
} ) ;
} ) ( function ( node , func ) {
node . DEFMETHOD ( "aborts" , func ) ;
} ) ;
OPT ( AST _Directive , function ( self , compressor ) {
if ( self . scope . has _directive ( self . value ) !== self . scope ) {
return make _node ( AST _EmptyStatement , self ) ;
}
return self ;
} ) ;
OPT ( AST _Debugger , function ( self , compressor ) {
if ( compressor . option ( "drop_debugger" ) ) return make _node ( AST _EmptyStatement , self ) ;
return self ;
} ) ;
OPT ( AST _LabeledStatement , function ( self , compressor ) {
if ( self . body instanceof AST _Break && compressor . loopcontrol _target ( self . body . label ) === self . body ) {
return make _node ( AST _EmptyStatement , self ) ;
}
return self . label . references . length == 0 ? self . body : self ;
} ) ;
OPT ( AST _Block , function ( self , compressor ) {
self . body = tighten _body ( self . body , compressor ) ;
return self ;
} ) ;
OPT ( AST _BlockStatement , function ( self , compressor ) {
self . body = tighten _body ( self . body , compressor ) ;
switch ( self . body . length ) {
case 1 :
return self . body [ 0 ] ;
case 0 :
return make _node ( AST _EmptyStatement , self ) ;
}
return self ;
} ) ;
AST _Scope . DEFMETHOD ( "drop_unused" , function ( compressor ) {
var self = this ;
if ( compressor . option ( "unused" ) && ! ( self instanceof AST _Toplevel ) && ! self . uses _eval ) {
var in _use = [ ] ;
var initializations = new Dictionary ( ) ;
var scope = this ;
var tw = new TreeWalker ( function ( node , descend ) {
if ( node !== self ) {
if ( node instanceof AST _Defun ) {
initializations . add ( node . name . name , node ) ;
return true ;
}
if ( node instanceof AST _Definitions && scope === self ) {
node . definitions . forEach ( function ( def ) {
if ( def . value ) {
initializations . add ( def . name . name , def . value ) ;
if ( def . value . has _side _effects ( compressor ) ) {
def . value . walk ( tw ) ;
}
}
} ) ;
return true ;
}
if ( node instanceof AST _SymbolRef ) {
push _uniq ( in _use , node . definition ( ) ) ;
return true ;
}
if ( node instanceof AST _Scope ) {
var save _scope = scope ;
scope = node ;
descend ( ) ;
scope = save _scope ;
return true ;
}
}
} ) ;
self . walk ( tw ) ;
for ( var i = 0 ; i < in _use . length ; ++ i ) {
in _use [ i ] . orig . forEach ( function ( decl ) {
var init = initializations . get ( decl . name ) ;
if ( init ) init . forEach ( function ( init ) {
var tw = new TreeWalker ( function ( node ) {
if ( node instanceof AST _SymbolRef ) {
push _uniq ( in _use , node . definition ( ) ) ;
}
} ) ;
init . walk ( tw ) ;
} ) ;
} ) ;
}
var tt = new TreeTransformer ( function before ( node , descend , in _list ) {
if ( node instanceof AST _Lambda && ! ( node instanceof AST _Accessor ) ) {
if ( ! compressor . option ( "keep_fargs" ) ) {
for ( var a = node . argnames , i = a . length ; -- i >= 0 ; ) {
var sym = a [ i ] ;
if ( sym . unreferenced ( ) ) {
a . pop ( ) ;
compressor . warn ( "Dropping unused function argument {name} [{file}:{line},{col}]" , {
name : sym . name ,
file : sym . start . file ,
line : sym . start . line ,
col : sym . start . col
} ) ;
} else break ;
}
}
}
if ( node instanceof AST _Defun && node !== self ) {
if ( ! member ( node . name . definition ( ) , in _use ) ) {
compressor . warn ( "Dropping unused function {name} [{file}:{line},{col}]" , {
name : node . name . name ,
file : node . name . start . file ,
line : node . name . start . line ,
col : node . name . start . col
} ) ;
return make _node ( AST _EmptyStatement , node ) ;
}
return node ;
}
if ( node instanceof AST _Definitions && ! ( tt . parent ( ) instanceof AST _ForIn ) ) {
var def = node . definitions . filter ( function ( def ) {
if ( member ( def . name . definition ( ) , in _use ) ) return true ;
var w = {
name : def . name . name ,
file : def . name . start . file ,
line : def . name . start . line ,
col : def . name . start . col
} ;
if ( def . value && def . value . has _side _effects ( compressor ) ) {
def . _unused _side _effects = true ;
compressor . warn ( "Side effects in initialization of unused variable {name} [{file}:{line},{col}]" , w ) ;
return true ;
}
compressor . warn ( "Dropping unused variable {name} [{file}:{line},{col}]" , w ) ;
return false ;
} ) ;
def = mergeSort ( def , function ( a , b ) {
if ( ! a . value && b . value ) return - 1 ;
if ( ! b . value && a . value ) return 1 ;
return 0 ;
} ) ;
var side _effects = [ ] ;
for ( var i = 0 ; i < def . length ; ) {
var x = def [ i ] ;
if ( x . _unused _side _effects ) {
side _effects . push ( x . value ) ;
def . splice ( i , 1 ) ;
} else {
if ( side _effects . length > 0 ) {
side _effects . push ( x . value ) ;
x . value = AST _Seq . from _array ( side _effects ) ;
side _effects = [ ] ;
}
++ i ;
}
}
if ( side _effects . length > 0 ) {
side _effects = make _node ( AST _BlockStatement , node , {
body : [ make _node ( AST _SimpleStatement , node , {
body : AST _Seq . from _array ( side _effects )
} ) ]
} ) ;
} else {
side _effects = null ;
}
if ( def . length == 0 && ! side _effects ) {
return make _node ( AST _EmptyStatement , node ) ;
}
if ( def . length == 0 ) {
return side _effects ;
}
node . definitions = def ;
if ( side _effects ) {
side _effects . body . unshift ( node ) ;
node = side _effects ;
}
return node ;
}
if ( node instanceof AST _For ) {
descend ( node , this ) ;
if ( node . init instanceof AST _BlockStatement ) {
var body = node . init . body . slice ( 0 , - 1 ) ;
node . init = node . init . body . slice ( - 1 ) [ 0 ] . body ;
body . push ( node ) ;
return in _list ? MAP . splice ( body ) : make _node ( AST _BlockStatement , node , {
body : body
} ) ;
}
}
if ( node instanceof AST _Scope && node !== self ) return node ;
} ) ;
self . transform ( tt ) ;
}
} ) ;
AST _Scope . DEFMETHOD ( "hoist_declarations" , function ( compressor ) {
var hoist _funs = compressor . option ( "hoist_funs" ) ;
var hoist _vars = compressor . option ( "hoist_vars" ) ;
var self = this ;
if ( hoist _funs || hoist _vars ) {
var dirs = [ ] ;
var hoisted = [ ] ;
var vars = new Dictionary ( ) , vars _found = 0 , var _decl = 0 ;
self . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Scope && node !== self ) return true ;
if ( node instanceof AST _Var ) {
++ var _decl ;
return true ;
}
} ) ) ;
hoist _vars = hoist _vars && var _decl > 1 ;
var tt = new TreeTransformer ( function before ( node ) {
if ( node !== self ) {
if ( node instanceof AST _Directive ) {
dirs . push ( node ) ;
return make _node ( AST _EmptyStatement , node ) ;
}
if ( node instanceof AST _Defun && hoist _funs ) {
hoisted . push ( node ) ;
return make _node ( AST _EmptyStatement , node ) ;
}
if ( node instanceof AST _Var && hoist _vars ) {
node . definitions . forEach ( function ( def ) {
vars . set ( def . name . name , def ) ;
++ vars _found ;
} ) ;
var seq = node . to _assignments ( ) ;
var p = tt . parent ( ) ;
if ( p instanceof AST _ForIn && p . init === node ) {
if ( seq == null ) return node . definitions [ 0 ] . name ;
return seq ;
}
if ( p instanceof AST _For && p . init === node ) {
return seq ;
}
if ( ! seq ) return make _node ( AST _EmptyStatement , node ) ;
return make _node ( AST _SimpleStatement , node , {
body : seq
} ) ;
}
if ( node instanceof AST _Scope ) return node ;
}
} ) ;
self = self . transform ( tt ) ;
if ( vars _found > 0 ) {
var defs = [ ] ;
vars . each ( function ( def , name ) {
if ( self instanceof AST _Lambda && find _if ( function ( x ) {
return x . name == def . name . name ;
} , self . argnames ) ) {
vars . del ( name ) ;
} else {
def = def . clone ( ) ;
def . value = null ;
defs . push ( def ) ;
vars . set ( name , def ) ;
}
} ) ;
if ( defs . length > 0 ) {
for ( var i = 0 ; i < self . body . length ; ) {
if ( self . body [ i ] instanceof AST _SimpleStatement ) {
var expr = self . body [ i ] . body , sym , assign ;
if ( expr instanceof AST _Assign && expr . operator == "=" && ( sym = expr . left ) instanceof AST _Symbol && vars . has ( sym . name ) ) {
var def = vars . get ( sym . name ) ;
if ( def . value ) break ;
def . value = expr . right ;
remove ( defs , def ) ;
defs . push ( def ) ;
self . body . splice ( i , 1 ) ;
continue ;
}
if ( expr instanceof AST _Seq && ( assign = expr . car ) instanceof AST _Assign && assign . operator == "=" && ( sym = assign . left ) instanceof AST _Symbol && vars . has ( sym . name ) ) {
var def = vars . get ( sym . name ) ;
if ( def . value ) break ;
def . value = assign . right ;
remove ( defs , def ) ;
defs . push ( def ) ;
self . body [ i ] . body = expr . cdr ;
continue ;
}
}
if ( self . body [ i ] instanceof AST _EmptyStatement ) {
self . body . splice ( i , 1 ) ;
continue ;
}
if ( self . body [ i ] instanceof AST _BlockStatement ) {
var tmp = [ i , 1 ] . concat ( self . body [ i ] . body ) ;
self . body . splice . apply ( self . body , tmp ) ;
continue ;
}
break ;
}
defs = make _node ( AST _Var , self , {
definitions : defs
} ) ;
hoisted . push ( defs ) ;
}
}
self . body = dirs . concat ( hoisted , self . body ) ;
}
return self ;
} ) ;
OPT ( AST _SimpleStatement , function ( self , compressor ) {
if ( compressor . option ( "side_effects" ) ) {
if ( ! self . body . has _side _effects ( compressor ) ) {
compressor . warn ( "Dropping side-effect-free statement [{file}:{line},{col}]" , self . start ) ;
return make _node ( AST _EmptyStatement , self ) ;
}
}
return self ;
} ) ;
OPT ( AST _DWLoop , function ( self , compressor ) {
var cond = self . condition . evaluate ( compressor ) ;
self . condition = cond [ 0 ] ;
if ( ! compressor . option ( "loops" ) ) return self ;
if ( cond . length > 1 ) {
if ( cond [ 1 ] ) {
return make _node ( AST _For , self , {
body : self . body
} ) ;
} else if ( self instanceof AST _While ) {
if ( compressor . option ( "dead_code" ) ) {
var a = [ ] ;
extract _declarations _from _unreachable _code ( compressor , self . body , a ) ;
return make _node ( AST _BlockStatement , self , {
body : a
} ) ;
}
}
}
return self ;
} ) ;
function if _break _in _loop ( self , compressor ) {
function drop _it ( rest ) {
rest = as _statement _array ( rest ) ;
if ( self . body instanceof AST _BlockStatement ) {
self . body = self . body . clone ( ) ;
self . body . body = rest . concat ( self . body . body . slice ( 1 ) ) ;
self . body = self . body . transform ( compressor ) ;
} else {
self . body = make _node ( AST _BlockStatement , self . body , {
body : rest
} ) . transform ( compressor ) ;
}
if _break _in _loop ( self , compressor ) ;
}
var first = self . body instanceof AST _BlockStatement ? self . body . body [ 0 ] : self . body ;
if ( first instanceof AST _If ) {
if ( first . body instanceof AST _Break && compressor . loopcontrol _target ( first . body . label ) === self ) {
if ( self . condition ) {
self . condition = make _node ( AST _Binary , self . condition , {
left : self . condition ,
operator : "&&" ,
right : first . condition . negate ( compressor )
} ) ;
} else {
self . condition = first . condition . negate ( compressor ) ;
}
drop _it ( first . alternative ) ;
} else if ( first . alternative instanceof AST _Break && compressor . loopcontrol _target ( first . alternative . label ) === self ) {
if ( self . condition ) {
self . condition = make _node ( AST _Binary , self . condition , {
left : self . condition ,
operator : "&&" ,
right : first . condition
} ) ;
} else {
self . condition = first . condition ;
}
drop _it ( first . body ) ;
}
}
}
OPT ( AST _While , function ( self , compressor ) {
if ( ! compressor . option ( "loops" ) ) return self ;
self = AST _DWLoop . prototype . optimize . call ( self , compressor ) ;
if ( self instanceof AST _While ) {
if _break _in _loop ( self , compressor ) ;
self = make _node ( AST _For , self , self ) . transform ( compressor ) ;
}
return self ;
} ) ;
OPT ( AST _For , function ( self , compressor ) {
var cond = self . condition ;
if ( cond ) {
cond = cond . evaluate ( compressor ) ;
self . condition = cond [ 0 ] ;
}
if ( ! compressor . option ( "loops" ) ) return self ;
if ( cond ) {
if ( cond . length > 1 && ! cond [ 1 ] ) {
if ( compressor . option ( "dead_code" ) ) {
var a = [ ] ;
if ( self . init instanceof AST _Statement ) {
a . push ( self . init ) ;
} else if ( self . init ) {
a . push ( make _node ( AST _SimpleStatement , self . init , {
body : self . init
} ) ) ;
}
extract _declarations _from _unreachable _code ( compressor , self . body , a ) ;
return make _node ( AST _BlockStatement , self , {
body : a
} ) ;
}
}
}
if _break _in _loop ( self , compressor ) ;
return self ;
} ) ;
OPT ( AST _If , function ( self , compressor ) {
if ( ! compressor . option ( "conditionals" ) ) return self ;
var cond = self . condition . evaluate ( compressor ) ;
self . condition = cond [ 0 ] ;
if ( cond . length > 1 ) {
if ( cond [ 1 ] ) {
compressor . warn ( "Condition always true [{file}:{line},{col}]" , self . condition . start ) ;
if ( compressor . option ( "dead_code" ) ) {
var a = [ ] ;
if ( self . alternative ) {
extract _declarations _from _unreachable _code ( compressor , self . alternative , a ) ;
}
a . push ( self . body ) ;
return make _node ( AST _BlockStatement , self , {
body : a
} ) . transform ( compressor ) ;
}
} else {
compressor . warn ( "Condition always false [{file}:{line},{col}]" , self . condition . start ) ;
if ( compressor . option ( "dead_code" ) ) {
var a = [ ] ;
extract _declarations _from _unreachable _code ( compressor , self . body , a ) ;
if ( self . alternative ) a . push ( self . alternative ) ;
return make _node ( AST _BlockStatement , self , {
body : a
} ) . transform ( compressor ) ;
}
}
}
if ( is _empty ( self . alternative ) ) self . alternative = null ;
var negated = self . condition . negate ( compressor ) ;
var negated _is _best = best _of ( self . condition , negated ) === negated ;
if ( self . alternative && negated _is _best ) {
negated _is _best = false ;
self . condition = negated ;
var tmp = self . body ;
self . body = self . alternative || make _node ( AST _EmptyStatement ) ;
self . alternative = tmp ;
}
if ( is _empty ( self . body ) && is _empty ( self . alternative ) ) {
return make _node ( AST _SimpleStatement , self . condition , {
body : self . condition
} ) . transform ( compressor ) ;
}
if ( self . body instanceof AST _SimpleStatement && self . alternative instanceof AST _SimpleStatement ) {
return make _node ( AST _SimpleStatement , self , {
body : make _node ( AST _Conditional , self , {
condition : self . condition ,
consequent : self . body . body ,
alternative : self . alternative . body
} )
} ) . transform ( compressor ) ;
}
if ( is _empty ( self . alternative ) && self . body instanceof AST _SimpleStatement ) {
if ( negated _is _best ) return make _node ( AST _SimpleStatement , self , {
body : make _node ( AST _Binary , self , {
operator : "||" ,
left : negated ,
right : self . body . body
} )
} ) . transform ( compressor ) ;
return make _node ( AST _SimpleStatement , self , {
body : make _node ( AST _Binary , self , {
operator : "&&" ,
left : self . condition ,
right : self . body . body
} )
} ) . transform ( compressor ) ;
}
if ( self . body instanceof AST _EmptyStatement && self . alternative && self . alternative instanceof AST _SimpleStatement ) {
return make _node ( AST _SimpleStatement , self , {
body : make _node ( AST _Binary , self , {
operator : "||" ,
left : self . condition ,
right : self . alternative . body
} )
} ) . transform ( compressor ) ;
}
if ( self . body instanceof AST _Exit && self . alternative instanceof AST _Exit && self . body . TYPE == self . alternative . TYPE ) {
return make _node ( self . body . CTOR , self , {
value : make _node ( AST _Conditional , self , {
condition : self . condition ,
consequent : self . body . value || make _node ( AST _Undefined , self . body ) . optimize ( compressor ) ,
alternative : self . alternative . value || make _node ( AST _Undefined , self . alternative ) . optimize ( compressor )
} )
} ) . transform ( compressor ) ;
}
if ( self . body instanceof AST _If && ! self . body . alternative && ! self . alternative ) {
self . condition = make _node ( AST _Binary , self . condition , {
operator : "&&" ,
left : self . condition ,
right : self . body . condition
} ) . transform ( compressor ) ;
self . body = self . body . body ;
}
if ( aborts ( self . body ) ) {
if ( self . alternative ) {
var alt = self . alternative ;
self . alternative = null ;
return make _node ( AST _BlockStatement , self , {
body : [ self , alt ]
} ) . transform ( compressor ) ;
}
}
if ( aborts ( self . alternative ) ) {
var body = self . body ;
self . body = self . alternative ;
self . condition = negated _is _best ? negated : self . condition . negate ( compressor ) ;
self . alternative = null ;
return make _node ( AST _BlockStatement , self , {
body : [ self , body ]
} ) . transform ( compressor ) ;
}
return self ;
} ) ;
OPT ( AST _Switch , function ( self , compressor ) {
if ( self . body . length == 0 && compressor . option ( "conditionals" ) ) {
return make _node ( AST _SimpleStatement , self , {
body : self . expression
} ) . transform ( compressor ) ;
}
for ( ; ; ) {
var last _branch = self . body [ self . body . length - 1 ] ;
if ( last _branch ) {
var stat = last _branch . body [ last _branch . body . length - 1 ] ;
if ( stat instanceof AST _Break && loop _body ( compressor . loopcontrol _target ( stat . label ) ) === self ) last _branch . body . pop ( ) ;
if ( last _branch instanceof AST _Default && last _branch . body . length == 0 ) {
self . body . pop ( ) ;
continue ;
}
}
break ;
}
var exp = self . expression . evaluate ( compressor ) ;
out : if ( exp . length == 2 ) try {
self . expression = exp [ 0 ] ;
if ( ! compressor . option ( "dead_code" ) ) break out ;
var value = exp [ 1 ] ;
var in _if = false ;
var in _block = false ;
var started = false ;
var stopped = false ;
var ruined = false ;
var tt = new TreeTransformer ( function ( node , descend , in _list ) {
if ( node instanceof AST _Lambda || node instanceof AST _SimpleStatement ) {
return node ;
} else if ( node instanceof AST _Switch && node === self ) {
node = node . clone ( ) ;
descend ( node , this ) ;
return ruined ? node : make _node ( AST _BlockStatement , node , {
body : node . body . reduce ( function ( a , branch ) {
return a . concat ( branch . body ) ;
} , [ ] )
} ) . transform ( compressor ) ;
} else if ( node instanceof AST _If || node instanceof AST _Try ) {
var save = in _if ;
in _if = ! in _block ;
descend ( node , this ) ;
in _if = save ;
return node ;
} else if ( node instanceof AST _StatementWithBody || node instanceof AST _Switch ) {
var save = in _block ;
in _block = true ;
descend ( node , this ) ;
in _block = save ;
return node ;
} else if ( node instanceof AST _Break && this . loopcontrol _target ( node . label ) === self ) {
if ( in _if ) {
ruined = true ;
return node ;
}
if ( in _block ) return node ;
stopped = true ;
return in _list ? MAP . skip : make _node ( AST _EmptyStatement , node ) ;
} else if ( node instanceof AST _SwitchBranch && this . parent ( ) === self ) {
if ( stopped ) return MAP . skip ;
if ( node instanceof AST _Case ) {
var exp = node . expression . evaluate ( compressor ) ;
if ( exp . length < 2 ) {
throw self ;
}
if ( exp [ 1 ] === value || started ) {
started = true ;
if ( aborts ( node ) ) stopped = true ;
descend ( node , this ) ;
return node ;
}
return MAP . skip ;
}
descend ( node , this ) ;
return node ;
}
} ) ;
tt . stack = compressor . stack . slice ( ) ;
self = self . transform ( tt ) ;
} catch ( ex ) {
if ( ex !== self ) throw ex ;
}
return self ;
} ) ;
OPT ( AST _Case , function ( self , compressor ) {
self . body = tighten _body ( self . body , compressor ) ;
return self ;
} ) ;
OPT ( AST _Try , function ( self , compressor ) {
self . body = tighten _body ( self . body , compressor ) ;
return self ;
} ) ;
AST _Definitions . DEFMETHOD ( "remove_initializers" , function ( ) {
this . definitions . forEach ( function ( def ) {
def . value = null ;
} ) ;
} ) ;
AST _Definitions . DEFMETHOD ( "to_assignments" , function ( ) {
var assignments = this . definitions . reduce ( function ( a , def ) {
if ( def . value ) {
var name = make _node ( AST _SymbolRef , def . name , def . name ) ;
a . push ( make _node ( AST _Assign , def , {
operator : "=" ,
left : name ,
right : def . value
} ) ) ;
}
return a ;
} , [ ] ) ;
if ( assignments . length == 0 ) return null ;
return AST _Seq . from _array ( assignments ) ;
} ) ;
OPT ( AST _Definitions , function ( self , compressor ) {
if ( self . definitions . length == 0 ) return make _node ( AST _EmptyStatement , self ) ;
return self ;
} ) ;
OPT ( AST _Function , function ( self , compressor ) {
self = AST _Lambda . prototype . optimize . call ( self , compressor ) ;
if ( compressor . option ( "unused" ) ) {
if ( self . name && self . name . unreferenced ( ) ) {
self . name = null ;
}
}
return self ;
} ) ;
OPT ( AST _Call , function ( self , compressor ) {
if ( compressor . option ( "unsafe" ) ) {
var exp = self . expression ;
if ( exp instanceof AST _SymbolRef && exp . undeclared ( ) ) {
switch ( exp . name ) {
case "Array" :
if ( self . args . length != 1 ) {
return make _node ( AST _Array , self , {
elements : self . args
} ) . transform ( compressor ) ;
}
break ;
case "Object" :
if ( self . args . length == 0 ) {
return make _node ( AST _Object , self , {
properties : [ ]
} ) ;
}
break ;
case "String" :
if ( self . args . length == 0 ) return make _node ( AST _String , self , {
value : ""
} ) ;
if ( self . args . length <= 1 ) return make _node ( AST _Binary , self , {
left : self . args [ 0 ] ,
operator : "+" ,
right : make _node ( AST _String , self , {
value : ""
} )
} ) . transform ( compressor ) ;
break ;
case "Number" :
if ( self . args . length == 0 ) return make _node ( AST _Number , self , {
value : 0
} ) ;
if ( self . args . length == 1 ) return make _node ( AST _UnaryPrefix , self , {
expression : self . args [ 0 ] ,
operator : "+"
} ) . transform ( compressor ) ;
case "Boolean" :
if ( self . args . length == 0 ) return make _node ( AST _False , self ) ;
if ( self . args . length == 1 ) return make _node ( AST _UnaryPrefix , self , {
expression : make _node ( AST _UnaryPrefix , null , {
expression : self . args [ 0 ] ,
operator : "!"
} ) ,
operator : "!"
} ) . transform ( compressor ) ;
break ;
case "Function" :
if ( all ( self . args , function ( x ) {
return x instanceof AST _String ;
} ) ) {
try {
var code = "(function(" + self . args . slice ( 0 , - 1 ) . map ( function ( arg ) {
return arg . value ;
} ) . join ( "," ) + "){" + self . args [ self . args . length - 1 ] . value + "})()" ;
var ast = parse ( code ) ;
ast . figure _out _scope ( {
screw _ie8 : compressor . option ( "screw_ie8" )
} ) ;
var comp = new Compressor ( compressor . options ) ;
ast = ast . transform ( comp ) ;
ast . figure _out _scope ( {
screw _ie8 : compressor . option ( "screw_ie8" )
} ) ;
ast . mangle _names ( ) ;
var fun ;
try {
ast . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Lambda ) {
fun = node ;
throw ast ;
}
} ) ) ;
} catch ( ex ) {
if ( ex !== ast ) throw ex ;
}
var args = fun . argnames . map ( function ( arg , i ) {
return make _node ( AST _String , self . args [ i ] , {
value : arg . print _to _string ( )
} ) ;
} ) ;
var code = OutputStream ( ) ;
AST _BlockStatement . prototype . _codegen . call ( fun , fun , code ) ;
code = code . toString ( ) . replace ( /^\{|\}$/g , "" ) ;
args . push ( make _node ( AST _String , self . args [ self . args . length - 1 ] , {
value : code
} ) ) ;
self . args = args ;
return self ;
} catch ( ex ) {
if ( ex instanceof JS _Parse _Error ) {
compressor . warn ( "Error parsing code passed to new Function [{file}:{line},{col}]" , self . args [ self . args . length - 1 ] . start ) ;
compressor . warn ( ex . toString ( ) ) ;
} else {
console . log ( ex ) ;
throw ex ;
}
}
}
break ;
}
} else if ( exp instanceof AST _Dot && exp . property == "toString" && self . args . length == 0 ) {
return make _node ( AST _Binary , self , {
left : make _node ( AST _String , self , {
value : ""
} ) ,
operator : "+" ,
right : exp . expression
} ) . transform ( compressor ) ;
} else if ( exp instanceof AST _Dot && exp . expression instanceof AST _Array && exp . property == "join" ) EXIT : {
var separator = self . args . length == 0 ? "," : self . args [ 0 ] . evaluate ( compressor ) [ 1 ] ;
if ( separator == null ) break EXIT ;
var elements = exp . expression . elements . reduce ( function ( a , el ) {
el = el . evaluate ( compressor ) ;
if ( a . length == 0 || el . length == 1 ) {
a . push ( el ) ;
} else {
var last = a [ a . length - 1 ] ;
if ( last . length == 2 ) {
var val = "" + last [ 1 ] + separator + el [ 1 ] ;
a [ a . length - 1 ] = [ make _node _from _constant ( compressor , val , last [ 0 ] ) , val ] ;
} else {
a . push ( el ) ;
}
}
return a ;
} , [ ] ) ;
if ( elements . length == 0 ) return make _node ( AST _String , self , {
value : ""
} ) ;
if ( elements . length == 1 ) return elements [ 0 ] [ 0 ] ;
if ( separator == "" ) {
var first ;
if ( elements [ 0 ] [ 0 ] instanceof AST _String || elements [ 1 ] [ 0 ] instanceof AST _String ) {
first = elements . shift ( ) [ 0 ] ;
} else {
first = make _node ( AST _String , self , {
value : ""
} ) ;
}
return elements . reduce ( function ( prev , el ) {
return make _node ( AST _Binary , el [ 0 ] , {
operator : "+" ,
left : prev ,
right : el [ 0 ]
} ) ;
} , first ) . transform ( compressor ) ;
}
var node = self . clone ( ) ;
node . expression = node . expression . clone ( ) ;
node . expression . expression = node . expression . expression . clone ( ) ;
node . expression . expression . elements = elements . map ( function ( el ) {
return el [ 0 ] ;
} ) ;
return best _of ( self , node ) ;
}
}
if ( compressor . option ( "side_effects" ) ) {
if ( self . expression instanceof AST _Function && self . args . length == 0 && ! AST _Block . prototype . has _side _effects . call ( self . expression , compressor ) ) {
return make _node ( AST _Undefined , self ) . transform ( compressor ) ;
}
}
if ( compressor . option ( "drop_console" ) ) {
if ( self . expression instanceof AST _PropAccess && self . expression . expression instanceof AST _SymbolRef && self . expression . expression . name == "console" && self . expression . expression . undeclared ( ) ) {
return make _node ( AST _Undefined , self ) . transform ( compressor ) ;
}
}
return self . evaluate ( compressor ) [ 0 ] ;
} ) ;
OPT ( AST _New , function ( self , compressor ) {
if ( compressor . option ( "unsafe" ) ) {
var exp = self . expression ;
if ( exp instanceof AST _SymbolRef && exp . undeclared ( ) ) {
switch ( exp . name ) {
case "Object" :
case "RegExp" :
case "Function" :
case "Error" :
case "Array" :
return make _node ( AST _Call , self , self ) . transform ( compressor ) ;
}
}
}
return self ;
} ) ;
OPT ( AST _Seq , function ( self , compressor ) {
if ( ! compressor . option ( "side_effects" ) ) return self ;
if ( ! self . car . has _side _effects ( compressor ) ) {
var p ;
if ( ! ( self . cdr instanceof AST _SymbolRef && self . cdr . name == "eval" && self . cdr . undeclared ( ) && ( p = compressor . parent ( ) ) instanceof AST _Call && p . expression === self ) ) {
return self . cdr ;
}
}
if ( compressor . option ( "cascade" ) ) {
if ( self . car instanceof AST _Assign && ! self . car . left . has _side _effects ( compressor ) ) {
if ( self . car . left . equivalent _to ( self . cdr ) ) {
return self . car ;
}
if ( self . cdr instanceof AST _Call && self . cdr . expression . equivalent _to ( self . car . left ) ) {
self . cdr . expression = self . car ;
return self . cdr ;
}
}
if ( ! self . car . has _side _effects ( compressor ) && ! self . cdr . has _side _effects ( compressor ) && self . car . equivalent _to ( self . cdr ) ) {
return self . car ;
}
}
if ( self . cdr instanceof AST _UnaryPrefix && self . cdr . operator == "void" && ! self . cdr . expression . has _side _effects ( compressor ) ) {
self . cdr . operator = self . car ;
return self . cdr ;
}
if ( self . cdr instanceof AST _Undefined ) {
return make _node ( AST _UnaryPrefix , self , {
operator : "void" ,
expression : self . car
} ) ;
}
return self ;
} ) ;
AST _Unary . DEFMETHOD ( "lift_sequences" , function ( compressor ) {
if ( compressor . option ( "sequences" ) ) {
if ( this . expression instanceof AST _Seq ) {
var seq = this . expression ;
var x = seq . to _array ( ) ;
this . expression = x . pop ( ) ;
x . push ( this ) ;
seq = AST _Seq . from _array ( x ) . transform ( compressor ) ;
return seq ;
}
}
return this ;
} ) ;
OPT ( AST _UnaryPostfix , function ( self , compressor ) {
return self . lift _sequences ( compressor ) ;
} ) ;
OPT ( AST _UnaryPrefix , function ( self , compressor ) {
self = self . lift _sequences ( compressor ) ;
var e = self . expression ;
if ( compressor . option ( "booleans" ) && compressor . in _boolean _context ( ) ) {
switch ( self . operator ) {
case "!" :
if ( e instanceof AST _UnaryPrefix && e . operator == "!" ) {
return e . expression ;
}
break ;
case "typeof" :
compressor . warn ( "Boolean expression always true [{file}:{line},{col}]" , self . start ) ;
return make _node ( AST _True , self ) ;
}
if ( e instanceof AST _Binary && self . operator == "!" ) {
self = best _of ( self , e . negate ( compressor ) ) ;
}
}
return self . evaluate ( compressor ) [ 0 ] ;
} ) ;
function has _side _effects _or _prop _access ( node , compressor ) {
var save _pure _getters = compressor . option ( "pure_getters" ) ;
compressor . options . pure _getters = false ;
var ret = node . has _side _effects ( compressor ) ;
compressor . options . pure _getters = save _pure _getters ;
return ret ;
}
AST _Binary . DEFMETHOD ( "lift_sequences" , function ( compressor ) {
if ( compressor . option ( "sequences" ) ) {
if ( this . left instanceof AST _Seq ) {
var seq = this . left ;
var x = seq . to _array ( ) ;
this . left = x . pop ( ) ;
x . push ( this ) ;
seq = AST _Seq . from _array ( x ) . transform ( compressor ) ;
return seq ;
}
if ( this . right instanceof AST _Seq && this instanceof AST _Assign && ! has _side _effects _or _prop _access ( this . left , compressor ) ) {
var seq = this . right ;
var x = seq . to _array ( ) ;
this . right = x . pop ( ) ;
x . push ( this ) ;
seq = AST _Seq . from _array ( x ) . transform ( compressor ) ;
return seq ;
}
}
return this ;
} ) ;
var commutativeOperators = makePredicate ( "== === != !== * & | ^" ) ;
OPT ( AST _Binary , function ( self , compressor ) {
var reverse = compressor . has _directive ( "use asm" ) ? noop : function ( op , force ) {
if ( force || ! ( self . left . has _side _effects ( compressor ) || self . right . has _side _effects ( compressor ) ) ) {
if ( op ) self . operator = op ;
var tmp = self . left ;
self . left = self . right ;
self . right = tmp ;
}
} ;
if ( commutativeOperators ( self . operator ) ) {
if ( self . right instanceof AST _Constant && ! ( self . left instanceof AST _Constant ) ) {
if ( ! ( self . left instanceof AST _Binary && PRECEDENCE [ self . left . operator ] >= PRECEDENCE [ self . operator ] ) ) {
reverse ( null , true ) ;
}
}
if ( /^[!=]==?$/ . test ( self . operator ) ) {
if ( self . left instanceof AST _SymbolRef && self . right instanceof AST _Conditional ) {
if ( self . right . consequent instanceof AST _SymbolRef && self . right . consequent . definition ( ) === self . left . definition ( ) ) {
if ( /^==/ . test ( self . operator ) ) return self . right . condition ;
if ( /^!=/ . test ( self . operator ) ) return self . right . condition . negate ( compressor ) ;
}
if ( self . right . alternative instanceof AST _SymbolRef && self . right . alternative . definition ( ) === self . left . definition ( ) ) {
if ( /^==/ . test ( self . operator ) ) return self . right . condition . negate ( compressor ) ;
if ( /^!=/ . test ( self . operator ) ) return self . right . condition ;
}
}
if ( self . right instanceof AST _SymbolRef && self . left instanceof AST _Conditional ) {
if ( self . left . consequent instanceof AST _SymbolRef && self . left . consequent . definition ( ) === self . right . definition ( ) ) {
if ( /^==/ . test ( self . operator ) ) return self . left . condition ;
if ( /^!=/ . test ( self . operator ) ) return self . left . condition . negate ( compressor ) ;
}
if ( self . left . alternative instanceof AST _SymbolRef && self . left . alternative . definition ( ) === self . right . definition ( ) ) {
if ( /^==/ . test ( self . operator ) ) return self . left . condition . negate ( compressor ) ;
if ( /^!=/ . test ( self . operator ) ) return self . left . condition ;
}
}
}
}
self = self . lift _sequences ( compressor ) ;
if ( compressor . option ( "comparisons" ) ) switch ( self . operator ) {
case "===" :
case "!==" :
if ( self . left . is _string ( compressor ) && self . right . is _string ( compressor ) || self . left . is _boolean ( ) && self . right . is _boolean ( ) ) {
self . operator = self . operator . substr ( 0 , 2 ) ;
}
case "==" :
case "!=" :
if ( self . left instanceof AST _String && self . left . value == "undefined" && self . right instanceof AST _UnaryPrefix && self . right . operator == "typeof" && compressor . option ( "unsafe" ) ) {
if ( ! ( self . right . expression instanceof AST _SymbolRef ) || ! self . right . expression . undeclared ( ) ) {
self . right = self . right . expression ;
self . left = make _node ( AST _Undefined , self . left ) . optimize ( compressor ) ;
if ( self . operator . length == 2 ) self . operator += "=" ;
}
}
break ;
}
if ( compressor . option ( "booleans" ) && compressor . in _boolean _context ( ) ) switch ( self . operator ) {
case "&&" :
var ll = self . left . evaluate ( compressor ) ;
var rr = self . right . evaluate ( compressor ) ;
if ( ll . length > 1 && ! ll [ 1 ] || rr . length > 1 && ! rr [ 1 ] ) {
compressor . warn ( "Boolean && always false [{file}:{line},{col}]" , self . start ) ;
return make _node ( AST _False , self ) ;
}
if ( ll . length > 1 && ll [ 1 ] ) {
return rr [ 0 ] ;
}
if ( rr . length > 1 && rr [ 1 ] ) {
return ll [ 0 ] ;
}
break ;
case "||" :
var ll = self . left . evaluate ( compressor ) ;
var rr = self . right . evaluate ( compressor ) ;
if ( ll . length > 1 && ll [ 1 ] || rr . length > 1 && rr [ 1 ] ) {
compressor . warn ( "Boolean || always true [{file}:{line},{col}]" , self . start ) ;
return make _node ( AST _True , self ) ;
}
if ( ll . length > 1 && ! ll [ 1 ] ) {
return rr [ 0 ] ;
}
if ( rr . length > 1 && ! rr [ 1 ] ) {
return ll [ 0 ] ;
}
break ;
case "+" :
var ll = self . left . evaluate ( compressor ) ;
var rr = self . right . evaluate ( compressor ) ;
if ( ll . length > 1 && ll [ 0 ] instanceof AST _String && ll [ 1 ] || rr . length > 1 && rr [ 0 ] instanceof AST _String && rr [ 1 ] ) {
compressor . warn ( "+ in boolean context always true [{file}:{line},{col}]" , self . start ) ;
return make _node ( AST _True , self ) ;
}
break ;
}
if ( compressor . option ( "comparisons" ) ) {
if ( ! ( compressor . parent ( ) instanceof AST _Binary ) || compressor . parent ( ) instanceof AST _Assign ) {
var negated = make _node ( AST _UnaryPrefix , self , {
operator : "!" ,
expression : self . negate ( compressor )
} ) ;
self = best _of ( self , negated ) ;
}
switch ( self . operator ) {
case "<" :
reverse ( ">" ) ;
break ;
case "<=" :
reverse ( ">=" ) ;
break ;
}
}
if ( self . operator == "+" && self . right instanceof AST _String && self . right . getValue ( ) === "" && self . left instanceof AST _Binary && self . left . operator == "+" && self . left . is _string ( compressor ) ) {
return self . left ;
}
if ( compressor . option ( "evaluate" ) ) {
if ( self . operator == "+" ) {
if ( self . left instanceof AST _Constant && self . right instanceof AST _Binary && self . right . operator == "+" && self . right . left instanceof AST _Constant && self . right . is _string ( compressor ) ) {
self = make _node ( AST _Binary , self , {
operator : "+" ,
left : make _node ( AST _String , null , {
value : "" + self . left . getValue ( ) + self . right . left . getValue ( ) ,
start : self . left . start ,
end : self . right . left . end
} ) ,
right : self . right . right
} ) ;
}
if ( self . right instanceof AST _Constant && self . left instanceof AST _Binary && self . left . operator == "+" && self . left . right instanceof AST _Constant && self . left . is _string ( compressor ) ) {
self = make _node ( AST _Binary , self , {
operator : "+" ,
left : self . left . left ,
right : make _node ( AST _String , null , {
value : "" + self . left . right . getValue ( ) + self . right . getValue ( ) ,
start : self . left . right . start ,
end : self . right . end
} )
} ) ;
}
if ( self . left instanceof AST _Binary && self . left . operator == "+" && self . left . is _string ( compressor ) && self . left . right instanceof AST _Constant && self . right instanceof AST _Binary && self . right . operator == "+" && self . right . left instanceof AST _Constant && self . right . is _string ( compressor ) ) {
self = make _node ( AST _Binary , self , {
operator : "+" ,
left : make _node ( AST _Binary , self . left , {
operator : "+" ,
left : self . left . left ,
right : make _node ( AST _String , null , {
value : "" + self . left . right . getValue ( ) + self . right . left . getValue ( ) ,
start : self . left . right . start ,
end : self . right . left . end
} )
} ) ,
right : self . right . right
} ) ;
}
}
}
if ( self . right instanceof AST _Binary && self . right . operator == self . operator && ( self . operator == "*" || self . operator == "&&" || self . operator == "||" ) ) {
self . left = make _node ( AST _Binary , self . left , {
operator : self . operator ,
left : self . left ,
right : self . right . left
} ) ;
self . right = self . right . right ;
return self . transform ( compressor ) ;
}
return self . evaluate ( compressor ) [ 0 ] ;
} ) ;
OPT ( AST _SymbolRef , function ( self , compressor ) {
if ( self . undeclared ( ) ) {
var defines = compressor . option ( "global_defs" ) ;
if ( defines && defines . hasOwnProperty ( self . name ) ) {
return make _node _from _constant ( compressor , defines [ self . name ] , self ) ;
}
switch ( self . name ) {
case "undefined" :
return make _node ( AST _Undefined , self ) ;
case "NaN" :
return make _node ( AST _NaN , self ) ;
case "Infinity" :
return make _node ( AST _Infinity , self ) ;
}
}
return self ;
} ) ;
OPT ( AST _Undefined , function ( self , compressor ) {
if ( compressor . option ( "unsafe" ) ) {
var scope = compressor . find _parent ( AST _Scope ) ;
var undef = scope . find _variable ( "undefined" ) ;
if ( undef ) {
var ref = make _node ( AST _SymbolRef , self , {
name : "undefined" ,
scope : scope ,
thedef : undef
} ) ;
ref . reference ( ) ;
return ref ;
}
}
return self ;
} ) ;
var ASSIGN _OPS = [ "+" , "-" , "/" , "*" , "%" , ">>" , "<<" , ">>>" , "|" , "^" , "&" ] ;
OPT ( AST _Assign , function ( self , compressor ) {
self = self . lift _sequences ( compressor ) ;
if ( self . operator == "=" && self . left instanceof AST _SymbolRef && self . right instanceof AST _Binary && self . right . left instanceof AST _SymbolRef && self . right . left . name == self . left . name && member ( self . right . operator , ASSIGN _OPS ) ) {
self . operator = self . right . operator + "=" ;
self . right = self . right . right ;
}
return self ;
} ) ;
OPT ( AST _Conditional , function ( self , compressor ) {
if ( ! compressor . option ( "conditionals" ) ) return self ;
if ( self . condition instanceof AST _Seq ) {
var car = self . condition . car ;
self . condition = self . condition . cdr ;
return AST _Seq . cons ( car , self ) ;
}
var cond = self . condition . evaluate ( compressor ) ;
if ( cond . length > 1 ) {
if ( cond [ 1 ] ) {
compressor . warn ( "Condition always true [{file}:{line},{col}]" , self . start ) ;
return self . consequent ;
} else {
compressor . warn ( "Condition always false [{file}:{line},{col}]" , self . start ) ;
return self . alternative ;
}
}
var negated = cond [ 0 ] . negate ( compressor ) ;
if ( best _of ( cond [ 0 ] , negated ) === negated ) {
self = make _node ( AST _Conditional , self , {
condition : negated ,
consequent : self . alternative ,
alternative : self . consequent
} ) ;
}
var consequent = self . consequent ;
var alternative = self . alternative ;
if ( consequent instanceof AST _Assign && alternative instanceof AST _Assign && consequent . operator == alternative . operator && consequent . left . equivalent _to ( alternative . left ) ) {
return make _node ( AST _Assign , self , {
operator : consequent . operator ,
left : consequent . left ,
right : make _node ( AST _Conditional , self , {
condition : self . condition ,
consequent : consequent . right ,
alternative : alternative . right
} )
} ) ;
}
if ( consequent instanceof AST _Call && alternative . TYPE === consequent . TYPE && consequent . args . length == alternative . args . length && consequent . expression . equivalent _to ( alternative . expression ) ) {
if ( consequent . args . length == 0 ) {
return make _node ( AST _Seq , self , {
car : self . condition ,
cdr : consequent
} ) ;
}
if ( consequent . args . length == 1 ) {
consequent . args [ 0 ] = make _node ( AST _Conditional , self , {
condition : self . condition ,
consequent : consequent . args [ 0 ] ,
alternative : alternative . args [ 0 ]
} ) ;
return consequent ;
}
}
if ( consequent instanceof AST _Conditional && consequent . alternative . equivalent _to ( alternative ) ) {
return make _node ( AST _Conditional , self , {
condition : make _node ( AST _Binary , self , {
left : self . condition ,
operator : "&&" ,
right : consequent . condition
} ) ,
consequent : consequent . consequent ,
alternative : alternative
} ) ;
}
return self ;
} ) ;
OPT ( AST _Boolean , function ( self , compressor ) {
if ( compressor . option ( "booleans" ) ) {
var p = compressor . parent ( ) ;
if ( p instanceof AST _Binary && ( p . operator == "==" || p . operator == "!=" ) ) {
compressor . warn ( "Non-strict equality against boolean: {operator} {value} [{file}:{line},{col}]" , {
operator : p . operator ,
value : self . value ,
file : p . start . file ,
line : p . start . line ,
col : p . start . col
} ) ;
return make _node ( AST _Number , self , {
value : + self . value
} ) ;
}
return make _node ( AST _UnaryPrefix , self , {
operator : "!" ,
expression : make _node ( AST _Number , self , {
value : 1 - self . value
} )
} ) ;
}
return self ;
} ) ;
OPT ( AST _Sub , function ( self , compressor ) {
var prop = self . property ;
if ( prop instanceof AST _String && compressor . option ( "properties" ) ) {
prop = prop . getValue ( ) ;
if ( RESERVED _WORDS ( prop ) ? compressor . option ( "screw_ie8" ) : is _identifier _string ( prop ) ) {
return make _node ( AST _Dot , self , {
expression : self . expression ,
property : prop
} ) . optimize ( compressor ) ;
}
var v = parseFloat ( prop ) ;
if ( ! isNaN ( v ) && v . toString ( ) == prop ) {
self . property = make _node ( AST _Number , self . property , {
value : v
} ) ;
}
}
return self ;
} ) ;
OPT ( AST _Dot , function ( self , compressor ) {
return self . evaluate ( compressor ) [ 0 ] ;
} ) ;
function literals _in _boolean _context ( self , compressor ) {
if ( compressor . option ( "booleans" ) && compressor . in _boolean _context ( ) ) {
return make _node ( AST _True , self ) ;
}
return self ;
}
OPT ( AST _Array , literals _in _boolean _context ) ;
OPT ( AST _Object , literals _in _boolean _context ) ;
OPT ( AST _RegExp , literals _in _boolean _context ) ;
} ) ( ) ;
"use strict" ;
function SourceMap ( options ) {
options = defaults ( options , {
file : null ,
root : null ,
orig : null ,
orig _line _diff : 0 ,
dest _line _diff : 0
} ) ;
var generator = new MOZ _SourceMap . SourceMapGenerator ( {
file : options . file ,
sourceRoot : options . root
} ) ;
var orig _map = options . orig && new MOZ _SourceMap . SourceMapConsumer ( options . orig ) ;
function add ( source , gen _line , gen _col , orig _line , orig _col , name ) {
if ( orig _map ) {
var info = orig _map . originalPositionFor ( {
line : orig _line ,
column : orig _col
} ) ;
if ( info . source === null ) {
return ;
}
source = info . source ;
orig _line = info . line ;
orig _col = info . column ;
name = info . name ;
}
generator . addMapping ( {
generated : {
line : gen _line + options . dest _line _diff ,
column : gen _col
} ,
original : {
line : orig _line + options . orig _line _diff ,
column : orig _col
} ,
source : source ,
name : name
} ) ;
}
return {
add : add ,
get : function ( ) {
return generator ;
} ,
toString : function ( ) {
return generator . toString ( ) ;
}
} ;
}
"use strict" ;
( function ( ) {
var MOZ _TO _ME = {
ExpressionStatement : function ( M ) {
var expr = M . expression ;
if ( expr . type === "Literal" && typeof expr . value === "string" ) {
return new AST _Directive ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
value : expr . value
} ) ;
}
return new AST _SimpleStatement ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
body : from _moz ( expr )
} ) ;
} ,
TryStatement : function ( M ) {
var handlers = M . handlers || [ M . handler ] ;
if ( handlers . length > 1 || M . guardedHandlers && M . guardedHandlers . length ) {
throw new Error ( "Multiple catch clauses are not supported." ) ;
}
return new AST _Try ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
body : from _moz ( M . block ) . body ,
bcatch : from _moz ( handlers [ 0 ] ) ,
bfinally : M . finalizer ? new AST _Finally ( from _moz ( M . finalizer ) ) : null
} ) ;
} ,
Property : function ( M ) {
var key = M . key ;
var name = key . type == "Identifier" ? key . name : key . value ;
var args = {
start : my _start _token ( key ) ,
end : my _end _token ( M . value ) ,
key : name ,
value : from _moz ( M . value )
} ;
switch ( M . kind ) {
case "init" :
return new AST _ObjectKeyVal ( args ) ;
case "set" :
args . value . name = from _moz ( key ) ;
return new AST _ObjectSetter ( args ) ;
case "get" :
args . value . name = from _moz ( key ) ;
return new AST _ObjectGetter ( args ) ;
}
} ,
ObjectExpression : function ( M ) {
return new AST _Object ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
properties : M . properties . map ( function ( prop ) {
prop . type = "Property" ;
return from _moz ( prop ) ;
} )
} ) ;
} ,
SequenceExpression : function ( M ) {
return AST _Seq . from _array ( M . expressions . map ( from _moz ) ) ;
} ,
MemberExpression : function ( M ) {
return new ( M . computed ? AST _Sub : AST _Dot ) ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
property : M . computed ? from _moz ( M . property ) : M . property . name ,
expression : from _moz ( M . object )
} ) ;
} ,
SwitchCase : function ( M ) {
return new ( M . test ? AST _Case : AST _Default ) ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
expression : from _moz ( M . test ) ,
body : M . consequent . map ( from _moz )
} ) ;
} ,
VariableDeclaration : function ( M ) {
return new ( M . kind === "const" ? AST _Const : AST _Var ) ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
definitions : M . declarations . map ( from _moz )
} ) ;
} ,
Literal : function ( M ) {
var val = M . value , args = {
start : my _start _token ( M ) ,
end : my _end _token ( M )
} ;
if ( val === null ) return new AST _Null ( args ) ;
switch ( typeof val ) {
case "string" :
args . value = val ;
return new AST _String ( args ) ;
case "number" :
args . value = val ;
return new AST _Number ( args ) ;
case "boolean" :
return new ( val ? AST _True : AST _False ) ( args ) ;
default :
args . value = val ;
return new AST _RegExp ( args ) ;
}
} ,
Identifier : function ( M ) {
var p = FROM _MOZ _STACK [ FROM _MOZ _STACK . length - 2 ] ;
return new ( p . type == "LabeledStatement" ? AST _Label : p . type == "VariableDeclarator" && p . id === M ? p . kind == "const" ? AST _SymbolConst : AST _SymbolVar : p . type == "FunctionExpression" ? p . id === M ? AST _SymbolLambda : AST _SymbolFunarg : p . type == "FunctionDeclaration" ? p . id === M ? AST _SymbolDefun : AST _SymbolFunarg : p . type == "CatchClause" ? AST _SymbolCatch : p . type == "BreakStatement" || p . type == "ContinueStatement" ? AST _LabelRef : AST _SymbolRef ) ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
name : M . name
} ) ;
}
} ;
MOZ _TO _ME . UpdateExpression = MOZ _TO _ME . UnaryExpression = function To _Moz _Unary ( M ) {
var prefix = "prefix" in M ? M . prefix : M . type == "UnaryExpression" ? true : false ;
return new ( prefix ? AST _UnaryPrefix : AST _UnaryPostfix ) ( {
start : my _start _token ( M ) ,
end : my _end _token ( M ) ,
operator : M . operator ,
expression : from _moz ( M . argument )
} ) ;
} ;
map ( "Program" , AST _Toplevel , "body@body" ) ;
map ( "EmptyStatement" , AST _EmptyStatement ) ;
map ( "BlockStatement" , AST _BlockStatement , "body@body" ) ;
map ( "IfStatement" , AST _If , "test>condition, consequent>body, alternate>alternative" ) ;
map ( "LabeledStatement" , AST _LabeledStatement , "label>label, body>body" ) ;
map ( "BreakStatement" , AST _Break , "label>label" ) ;
map ( "ContinueStatement" , AST _Continue , "label>label" ) ;
map ( "WithStatement" , AST _With , "object>expression, body>body" ) ;
map ( "SwitchStatement" , AST _Switch , "discriminant>expression, cases@body" ) ;
map ( "ReturnStatement" , AST _Return , "argument>value" ) ;
map ( "ThrowStatement" , AST _Throw , "argument>value" ) ;
map ( "WhileStatement" , AST _While , "test>condition, body>body" ) ;
map ( "DoWhileStatement" , AST _Do , "test>condition, body>body" ) ;
map ( "ForStatement" , AST _For , "init>init, test>condition, update>step, body>body" ) ;
map ( "ForInStatement" , AST _ForIn , "left>init, right>object, body>body" ) ;
map ( "DebuggerStatement" , AST _Debugger ) ;
map ( "FunctionDeclaration" , AST _Defun , "id>name, params@argnames, body%body" ) ;
map ( "VariableDeclarator" , AST _VarDef , "id>name, init>value" ) ;
map ( "CatchClause" , AST _Catch , "param>argname, body%body" ) ;
map ( "ThisExpression" , AST _This ) ;
map ( "ArrayExpression" , AST _Array , "elements@elements" ) ;
map ( "FunctionExpression" , AST _Function , "id>name, params@argnames, body%body" ) ;
map ( "BinaryExpression" , AST _Binary , "operator=operator, left>left, right>right" ) ;
map ( "LogicalExpression" , AST _Binary , "operator=operator, left>left, right>right" ) ;
map ( "AssignmentExpression" , AST _Assign , "operator=operator, left>left, right>right" ) ;
map ( "ConditionalExpression" , AST _Conditional , "test>condition, consequent>consequent, alternate>alternative" ) ;
map ( "NewExpression" , AST _New , "callee>expression, arguments@args" ) ;
map ( "CallExpression" , AST _Call , "callee>expression, arguments@args" ) ;
def _to _moz ( AST _Directive , function To _Moz _Directive ( M ) {
return {
type : "ExpressionStatement" ,
expression : {
type : "Literal" ,
value : M . value
}
} ;
} ) ;
def _to _moz ( AST _SimpleStatement , function To _Moz _ExpressionStatement ( M ) {
return {
type : "ExpressionStatement" ,
expression : to _moz ( M . body )
} ;
} ) ;
def _to _moz ( AST _SwitchBranch , function To _Moz _SwitchCase ( M ) {
return {
type : "SwitchCase" ,
test : to _moz ( M . expression ) ,
consequent : M . body . map ( to _moz )
} ;
} ) ;
def _to _moz ( AST _Try , function To _Moz _TryStatement ( M ) {
return {
type : "TryStatement" ,
block : to _moz _block ( M ) ,
handler : to _moz ( M . bcatch ) ,
guardedHandlers : [ ] ,
finalizer : to _moz ( M . bfinally )
} ;
} ) ;
def _to _moz ( AST _Catch , function To _Moz _CatchClause ( M ) {
return {
type : "CatchClause" ,
param : to _moz ( M . argname ) ,
guard : null ,
body : to _moz _block ( M )
} ;
} ) ;
def _to _moz ( AST _Definitions , function To _Moz _VariableDeclaration ( M ) {
return {
type : "VariableDeclaration" ,
kind : M instanceof AST _Const ? "const" : "var" ,
declarations : M . definitions . map ( to _moz )
} ;
} ) ;
def _to _moz ( AST _Seq , function To _Moz _SequenceExpression ( M ) {
return {
type : "SequenceExpression" ,
expressions : M . to _array ( ) . map ( to _moz )
} ;
} ) ;
def _to _moz ( AST _PropAccess , function To _Moz _MemberExpression ( M ) {
var isComputed = M instanceof AST _Sub ;
return {
type : "MemberExpression" ,
object : to _moz ( M . expression ) ,
computed : isComputed ,
property : isComputed ? to _moz ( M . property ) : {
type : "Identifier" ,
name : M . property
}
} ;
} ) ;
def _to _moz ( AST _Unary , function To _Moz _Unary ( M ) {
return {
type : M . operator == "++" || M . operator == "--" ? "UpdateExpression" : "UnaryExpression" ,
operator : M . operator ,
prefix : M instanceof AST _UnaryPrefix ,
argument : to _moz ( M . expression )
} ;
} ) ;
def _to _moz ( AST _Binary , function To _Moz _BinaryExpression ( M ) {
return {
type : M . operator == "&&" || M . operator == "||" ? "LogicalExpression" : "BinaryExpression" ,
left : to _moz ( M . left ) ,
operator : M . operator ,
right : to _moz ( M . right )
} ;
} ) ;
def _to _moz ( AST _Object , function To _Moz _ObjectExpression ( M ) {
return {
type : "ObjectExpression" ,
properties : M . properties . map ( to _moz )
} ;
} ) ;
def _to _moz ( AST _ObjectProperty , function To _Moz _Property ( M ) {
var key = is _identifier ( M . key ) ? {
type : "Identifier" ,
name : M . key
} : {
type : "Literal" ,
value : M . key
} ;
var kind ;
if ( M instanceof AST _ObjectKeyVal ) {
kind = "init" ;
} else if ( M instanceof AST _ObjectGetter ) {
kind = "get" ;
} else if ( M instanceof AST _ObjectSetter ) {
kind = "set" ;
}
return {
type : "Property" ,
kind : kind ,
key : key ,
value : to _moz ( M . value )
} ;
} ) ;
def _to _moz ( AST _Symbol , function To _Moz _Identifier ( M ) {
var def = M . definition ( ) ;
return {
type : "Identifier" ,
name : def ? def . mangled _name || def . name : M . name
} ;
} ) ;
def _to _moz ( AST _Constant , function To _Moz _Literal ( M ) {
var value = M . value ;
if ( typeof value === "number" && ( value < 0 || value === 0 && 1 / value < 0 ) ) {
return {
type : "UnaryExpression" ,
operator : "-" ,
prefix : true ,
argument : {
type : "Literal" ,
value : - value
}
} ;
}
return {
type : "Literal" ,
value : value
} ;
} ) ;
def _to _moz ( AST _Atom , function To _Moz _Atom ( M ) {
return {
type : "Identifier" ,
name : String ( M . value )
} ;
} ) ;
AST _Boolean . DEFMETHOD ( "to_mozilla_ast" , AST _Constant . prototype . to _mozilla _ast ) ;
AST _Null . DEFMETHOD ( "to_mozilla_ast" , AST _Constant . prototype . to _mozilla _ast ) ;
AST _Hole . DEFMETHOD ( "to_mozilla_ast" , function To _Moz _ArrayHole ( ) {
return null ;
} ) ;
AST _Block . DEFMETHOD ( "to_mozilla_ast" , AST _BlockStatement . prototype . to _mozilla _ast ) ;
AST _Lambda . DEFMETHOD ( "to_mozilla_ast" , AST _Function . prototype . to _mozilla _ast ) ;
function my _start _token ( moznode ) {
var loc = moznode . loc ;
var range = moznode . range ;
return new AST _Token ( {
file : loc && loc . source ,
line : loc && loc . start . line ,
col : loc && loc . start . column ,
pos : range ? range [ 0 ] : moznode . start ,
endpos : range ? range [ 0 ] : moznode . start
} ) ;
}
function my _end _token ( moznode ) {
var loc = moznode . loc ;
var range = moznode . range ;
return new AST _Token ( {
file : loc && loc . source ,
line : loc && loc . end . line ,
col : loc && loc . end . column ,
pos : range ? range [ 1 ] : moznode . end ,
endpos : range ? range [ 1 ] : moznode . end
} ) ;
}
function map ( moztype , mytype , propmap ) {
if ( typeof UglifyJS _NoUnsafeEval !== "undefined" ) {
var prop _list = [ ] ;
if ( propmap ) propmap . split ( /\s*,\s*/ ) . forEach ( function ( prop ) {
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i . exec ( prop ) ;
if ( ! m ) throw new Error ( "Can't understand property map: " + prop ) ;
if ( "=@>%" . indexOf ( m [ 2 ] ) < 0 ) {
throw new Error ( "Can't understand operator in propmap: " + prop ) ;
}
prop _list . push ( m ) ;
} ) ;
var moz _to _me = function ( M ) {
var props = {
start : my _start _token ( M ) ,
end : my _end _token ( M )
} ;
for ( var i = 0 ; i < prop _list . length ; i ++ ) {
var m = prop _list [ i ] ;
var moz = m [ 1 ] , how = m [ 2 ] , my = m [ 3 ] ;
var mozProp = M [ moz ] ;
var myProp ;
switch ( how ) {
case "@" :
myProp = mozProp . map ( from _moz ) ;
break ;
case ">" :
myProp = from _moz ( mozProp ) ;
break ;
case "=" :
myProp = mozProp ;
break ;
case "%" :
myProp = from _moz ( mozProp ) . body ;
break ;
}
props [ my ] = myProp ;
}
return new mytype ( props ) ;
} ;
var me _to _moz = function ( M ) {
var props = {
type : moztype
} ;
for ( var i = 0 ; i < prop _list . length ; i ++ ) {
var m = prop _list [ i ] ;
var moz = m [ 1 ] , how = m [ 2 ] , my = m [ 3 ] ;
var myProp = M [ my ] ;
var mozProp ;
switch ( how ) {
case "@" :
mozProp = myProp . map ( to _moz ) ;
break ;
case ">" :
mozProp = to _moz ( myProp ) ;
break ;
case "=" :
mozProp = myProp ;
break ;
case "%" :
mozProp = to _moz _block ( M ) ;
break ;
}
props [ moz ] = mozProp ;
}
return props ;
} ;
MOZ _TO _ME [ moztype ] = moz _to _me ;
def _to _moz ( mytype , me _to _moz ) ;
return ;
}
var moz _to _me = "function From_Moz_" + moztype + "(M){\n" ;
moz _to _me += "return new " + mytype . name + "({\n" + "start: my_start_token(M),\n" + "end: my_end_token(M)" ;
var me _to _moz = "function To_Moz_" + moztype + "(M){\n" ;
me _to _moz += "return {\n" + "type: " + JSON . stringify ( moztype ) ;
if ( propmap ) propmap . split ( /\s*,\s*/ ) . forEach ( function ( prop ) {
var m = /([a-z0-9$_]+)(=|@|>|%)([a-z0-9$_]+)/i . exec ( prop ) ;
if ( ! m ) throw new Error ( "Can't understand property map: " + prop ) ;
var moz = m [ 1 ] , how = m [ 2 ] , my = m [ 3 ] ;
moz _to _me += ",\n" + my + ": " ;
me _to _moz += ",\n" + moz + ": " ;
switch ( how ) {
case "@" :
moz _to _me += "M." + moz + ".map(from_moz)" ;
me _to _moz += "M." + my + ".map(to_moz)" ;
break ;
case ">" :
moz _to _me += "from_moz(M." + moz + ")" ;
me _to _moz += "to_moz(M." + my + ")" ;
break ;
case "=" :
moz _to _me += "M." + moz ;
me _to _moz += "M." + my ;
break ;
case "%" :
moz _to _me += "from_moz(M." + moz + ").body" ;
me _to _moz += "to_moz_block(M)" ;
break ;
default :
throw new Error ( "Can't understand operator in propmap: " + prop ) ;
}
} ) ;
moz _to _me += "\n})\n}" ;
me _to _moz += "\n}\n}" ;
moz _to _me = new Function ( "my_start_token" , "my_end_token" , "from_moz" , "return(" + moz _to _me + ")" ) ( my _start _token , my _end _token , from _moz ) ;
me _to _moz = new Function ( "to_moz" , "to_moz_block" , "return(" + me _to _moz + ")" ) ( to _moz , to _moz _block ) ;
MOZ _TO _ME [ moztype ] = moz _to _me ;
def _to _moz ( mytype , me _to _moz ) ;
}
var FROM _MOZ _STACK = null ;
function from _moz ( node ) {
FROM _MOZ _STACK . push ( node ) ;
var ret = node != null ? MOZ _TO _ME [ node . type ] ( node ) : null ;
FROM _MOZ _STACK . pop ( ) ;
return ret ;
}
AST _Node . from _mozilla _ast = function ( node ) {
var save _stack = FROM _MOZ _STACK ;
FROM _MOZ _STACK = [ ] ;
var ast = from _moz ( node ) ;
FROM _MOZ _STACK = save _stack ;
return ast ;
} ;
function moz _sub _loc ( token ) {
return token . line ? {
line : token . line ,
column : token . col
} : null ;
}
function set _moz _loc ( mynode , moznode ) {
var start = mynode . start ;
var end = mynode . end ;
if ( start . pos != null && end . pos != null ) {
moznode . range = [ start . pos , end . pos ] ;
}
if ( start . line ) {
moznode . loc = {
start : moz _sub _loc ( start ) ,
end : moz _sub _loc ( end )
} ;
if ( start . file ) {
moznode . loc . source = start . file ;
}
}
return moznode ;
}
function def _to _moz ( mytype , handler ) {
mytype . DEFMETHOD ( "to_mozilla_ast" , function ( ) {
return set _moz _loc ( this , handler ( this ) ) ;
} ) ;
}
function to _moz ( node ) {
return node != null ? node . to _mozilla _ast ( ) : null ;
}
function to _moz _block ( node ) {
return {
type : "BlockStatement" ,
body : node . body . map ( to _moz )
} ;
}
} ) ( ) ;
exports [ "array_to_hash" ] = array _to _hash ;
exports [ "slice" ] = slice ;
exports [ "characters" ] = characters ;
exports [ "member" ] = member ;
exports [ "find_if" ] = find _if ;
exports [ "repeat_string" ] = repeat _string ;
exports [ "DefaultsError" ] = DefaultsError ;
exports [ "defaults" ] = defaults ;
exports [ "merge" ] = merge ;
exports [ "noop" ] = noop ;
exports [ "MAP" ] = MAP ;
exports [ "push_uniq" ] = push _uniq ;
exports [ "string_template" ] = string _template ;
exports [ "remove" ] = remove ;
exports [ "mergeSort" ] = mergeSort ;
exports [ "set_difference" ] = set _difference ;
exports [ "set_intersection" ] = set _intersection ;
exports [ "makePredicate" ] = makePredicate ;
exports [ "all" ] = all ;
exports [ "Dictionary" ] = Dictionary ;
exports [ "DEFNODE" ] = DEFNODE ;
exports [ "AST_Token" ] = AST _Token ;
exports [ "AST_Node" ] = AST _Node ;
exports [ "AST_Statement" ] = AST _Statement ;
exports [ "AST_Debugger" ] = AST _Debugger ;
exports [ "AST_Directive" ] = AST _Directive ;
exports [ "AST_SimpleStatement" ] = AST _SimpleStatement ;
exports [ "walk_body" ] = walk _body ;
exports [ "AST_Block" ] = AST _Block ;
exports [ "AST_BlockStatement" ] = AST _BlockStatement ;
exports [ "AST_EmptyStatement" ] = AST _EmptyStatement ;
exports [ "AST_StatementWithBody" ] = AST _StatementWithBody ;
exports [ "AST_LabeledStatement" ] = AST _LabeledStatement ;
exports [ "AST_IterationStatement" ] = AST _IterationStatement ;
exports [ "AST_DWLoop" ] = AST _DWLoop ;
exports [ "AST_Do" ] = AST _Do ;
exports [ "AST_While" ] = AST _While ;
exports [ "AST_For" ] = AST _For ;
exports [ "AST_ForIn" ] = AST _ForIn ;
exports [ "AST_With" ] = AST _With ;
exports [ "AST_Scope" ] = AST _Scope ;
exports [ "AST_Toplevel" ] = AST _Toplevel ;
exports [ "AST_Lambda" ] = AST _Lambda ;
exports [ "AST_Accessor" ] = AST _Accessor ;
exports [ "AST_Function" ] = AST _Function ;
exports [ "AST_Defun" ] = AST _Defun ;
exports [ "AST_Jump" ] = AST _Jump ;
exports [ "AST_Exit" ] = AST _Exit ;
exports [ "AST_Return" ] = AST _Return ;
exports [ "AST_Throw" ] = AST _Throw ;
exports [ "AST_LoopControl" ] = AST _LoopControl ;
exports [ "AST_Break" ] = AST _Break ;
exports [ "AST_Continue" ] = AST _Continue ;
exports [ "AST_If" ] = AST _If ;
exports [ "AST_Switch" ] = AST _Switch ;
exports [ "AST_SwitchBranch" ] = AST _SwitchBranch ;
exports [ "AST_Default" ] = AST _Default ;
exports [ "AST_Case" ] = AST _Case ;
exports [ "AST_Try" ] = AST _Try ;
exports [ "AST_Catch" ] = AST _Catch ;
exports [ "AST_Finally" ] = AST _Finally ;
exports [ "AST_Definitions" ] = AST _Definitions ;
exports [ "AST_Var" ] = AST _Var ;
exports [ "AST_Const" ] = AST _Const ;
exports [ "AST_VarDef" ] = AST _VarDef ;
exports [ "AST_Call" ] = AST _Call ;
exports [ "AST_New" ] = AST _New ;
exports [ "AST_Seq" ] = AST _Seq ;
exports [ "AST_PropAccess" ] = AST _PropAccess ;
exports [ "AST_Dot" ] = AST _Dot ;
exports [ "AST_Sub" ] = AST _Sub ;
exports [ "AST_Unary" ] = AST _Unary ;
exports [ "AST_UnaryPrefix" ] = AST _UnaryPrefix ;
exports [ "AST_UnaryPostfix" ] = AST _UnaryPostfix ;
exports [ "AST_Binary" ] = AST _Binary ;
exports [ "AST_Conditional" ] = AST _Conditional ;
exports [ "AST_Assign" ] = AST _Assign ;
exports [ "AST_Array" ] = AST _Array ;
exports [ "AST_Object" ] = AST _Object ;
exports [ "AST_ObjectProperty" ] = AST _ObjectProperty ;
exports [ "AST_ObjectKeyVal" ] = AST _ObjectKeyVal ;
exports [ "AST_ObjectSetter" ] = AST _ObjectSetter ;
exports [ "AST_ObjectGetter" ] = AST _ObjectGetter ;
exports [ "AST_Symbol" ] = AST _Symbol ;
exports [ "AST_SymbolAccessor" ] = AST _SymbolAccessor ;
exports [ "AST_SymbolDeclaration" ] = AST _SymbolDeclaration ;
exports [ "AST_SymbolVar" ] = AST _SymbolVar ;
exports [ "AST_SymbolConst" ] = AST _SymbolConst ;
exports [ "AST_SymbolFunarg" ] = AST _SymbolFunarg ;
exports [ "AST_SymbolDefun" ] = AST _SymbolDefun ;
exports [ "AST_SymbolLambda" ] = AST _SymbolLambda ;
exports [ "AST_SymbolCatch" ] = AST _SymbolCatch ;
exports [ "AST_Label" ] = AST _Label ;
exports [ "AST_SymbolRef" ] = AST _SymbolRef ;
exports [ "AST_LabelRef" ] = AST _LabelRef ;
exports [ "AST_This" ] = AST _This ;
exports [ "AST_Constant" ] = AST _Constant ;
exports [ "AST_String" ] = AST _String ;
exports [ "AST_Number" ] = AST _Number ;
exports [ "AST_RegExp" ] = AST _RegExp ;
exports [ "AST_Atom" ] = AST _Atom ;
exports [ "AST_Null" ] = AST _Null ;
exports [ "AST_NaN" ] = AST _NaN ;
exports [ "AST_Undefined" ] = AST _Undefined ;
exports [ "AST_Hole" ] = AST _Hole ;
exports [ "AST_Infinity" ] = AST _Infinity ;
exports [ "AST_Boolean" ] = AST _Boolean ;
exports [ "AST_False" ] = AST _False ;
exports [ "AST_True" ] = AST _True ;
exports [ "TreeWalker" ] = TreeWalker ;
exports [ "KEYWORDS" ] = KEYWORDS ;
exports [ "KEYWORDS_ATOM" ] = KEYWORDS _ATOM ;
exports [ "RESERVED_WORDS" ] = RESERVED _WORDS ;
exports [ "KEYWORDS_BEFORE_EXPRESSION" ] = KEYWORDS _BEFORE _EXPRESSION ;
exports [ "OPERATOR_CHARS" ] = OPERATOR _CHARS ;
exports [ "RE_HEX_NUMBER" ] = RE _HEX _NUMBER ;
exports [ "RE_OCT_NUMBER" ] = RE _OCT _NUMBER ;
exports [ "RE_DEC_NUMBER" ] = RE _DEC _NUMBER ;
exports [ "OPERATORS" ] = OPERATORS ;
exports [ "WHITESPACE_CHARS" ] = WHITESPACE _CHARS ;
exports [ "PUNC_BEFORE_EXPRESSION" ] = PUNC _BEFORE _EXPRESSION ;
exports [ "PUNC_CHARS" ] = PUNC _CHARS ;
exports [ "REGEXP_MODIFIERS" ] = REGEXP _MODIFIERS ;
exports [ "UNICODE" ] = UNICODE ;
exports [ "is_letter" ] = is _letter ;
exports [ "is_digit" ] = is _digit ;
exports [ "is_alphanumeric_char" ] = is _alphanumeric _char ;
exports [ "is_unicode_combining_mark" ] = is _unicode _combining _mark ;
exports [ "is_unicode_connector_punctuation" ] = is _unicode _connector _punctuation ;
exports [ "is_identifier" ] = is _identifier ;
exports [ "is_identifier_start" ] = is _identifier _start ;
exports [ "is_identifier_char" ] = is _identifier _char ;
exports [ "is_identifier_string" ] = is _identifier _string ;
exports [ "parse_js_number" ] = parse _js _number ;
exports [ "JS_Parse_Error" ] = JS _Parse _Error ;
exports [ "js_error" ] = js _error ;
exports [ "is_token" ] = is _token ;
exports [ "EX_EOF" ] = EX _EOF ;
exports [ "tokenizer" ] = tokenizer ;
exports [ "UNARY_PREFIX" ] = UNARY _PREFIX ;
exports [ "UNARY_POSTFIX" ] = UNARY _POSTFIX ;
exports [ "ASSIGNMENT" ] = ASSIGNMENT ;
exports [ "PRECEDENCE" ] = PRECEDENCE ;
exports [ "STATEMENTS_WITH_LABELS" ] = STATEMENTS _WITH _LABELS ;
exports [ "ATOMIC_START_TOKEN" ] = ATOMIC _START _TOKEN ;
exports [ "parse" ] = parse ;
exports [ "TreeTransformer" ] = TreeTransformer ;
exports [ "SymbolDef" ] = SymbolDef ;
exports [ "base54" ] = base54 ;
exports [ "OutputStream" ] = OutputStream ;
exports [ "Compressor" ] = Compressor ;
exports [ "SourceMap" ] = SourceMap ;
} ) ( { } , function ( ) {
return this ;
2024-02-29 09:14:04 -05:00
} ( ) ) ;