2012-08-22 18:28:59 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
A JavaScript tokenizer / parser / beautifier / compressor .
https : //github.com/mishoo/UglifyJS2
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- ( C ) -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
Author : Mihai Bazon
< mihai . bazon @ gmail . com >
http : //mihai.bazon.net/blog
Distributed under the BSD license :
2012-08-27 08:01:27 +00:00
Copyright 2012 ( c ) Mihai Bazon < mihai . bazon @ gmail . com >
2012-08-22 18:28:59 +00:00
Redistribution and use in source and binary forms , with or without
modification , are permitted provided that the following conditions
are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the following
disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the following
disclaimer in the documentation and / or other materials
provided with the distribution .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “ AS IS ” AND ANY
EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL , SPECIAL , EXEMPLARY ,
OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT LIMITED TO ,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE , DATA , OR
PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR
TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF
THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * /
2012-10-02 09:45:31 +00:00
"use strict" ;
2012-05-27 11:09:01 +00:00
function DEFNODE ( type , props , methods , base ) {
if ( arguments . length < 4 ) base = AST _Node ;
if ( ! props ) props = [ ] ;
else props = props . split ( /\s+/ ) ;
2012-08-22 12:21:58 +00:00
var self _props = props ;
2012-05-27 11:09:01 +00:00
if ( base && base . PROPS )
props = props . concat ( base . PROPS ) ;
var code = "return function AST_" + type + "(props){ if (props) { " ;
for ( var i = props . length ; -- i >= 0 ; ) {
code += "this." + props [ i ] + " = props." + props [ i ] + ";" ;
}
2012-08-19 12:57:50 +00:00
var proto = base && new base ;
if ( proto && proto . initialize || ( methods && methods . initialize ) )
2012-08-17 12:59:42 +00:00
code += "this.initialize();" ;
2012-10-12 08:07:35 +00:00
code += "}}" ;
2012-05-27 11:09:01 +00:00
var ctor = new Function ( code ) ( ) ;
2012-08-19 12:57:50 +00:00
if ( proto ) {
ctor . prototype = proto ;
ctor . BASE = base ;
2012-05-27 11:09:01 +00:00
}
2012-10-09 10:21:21 +00:00
if ( base ) base . SUBCLASSES . push ( ctor ) ;
2012-05-27 11:09:01 +00:00
ctor . prototype . CTOR = ctor ;
ctor . PROPS = props || null ;
2012-08-22 12:21:58 +00:00
ctor . SELF _PROPS = self _props ;
2012-10-09 10:21:21 +00:00
ctor . SUBCLASSES = [ ] ;
2012-05-27 11:09:01 +00:00
if ( type ) {
ctor . prototype . TYPE = ctor . TYPE = type ;
}
2012-10-11 08:07:42 +00:00
if ( methods ) for ( i in methods ) if ( methods . hasOwnProperty ( i ) ) {
2012-09-14 12:36:38 +00:00
if ( /^\$/ . test ( i ) ) {
ctor [ i . substr ( 1 ) ] = methods [ i ] ;
} else {
ctor . prototype [ i ] = methods [ i ] ;
}
2012-05-27 11:09:01 +00:00
}
2012-08-16 15:11:04 +00:00
ctor . DEFMETHOD = function ( name , method ) {
this . prototype [ name ] = method ;
} ;
2012-05-27 11:09:01 +00:00
return ctor ;
} ;
2014-08-08 11:15:43 +00:00
var AST _Token = DEFNODE ( "Token" , "type value line col pos endline endcol endpos nlb comments_before file" , {
2012-05-27 11:09:01 +00:00
} , null ) ;
2012-10-12 08:07:35 +00:00
var AST _Node = DEFNODE ( "Node" , "start end" , {
2012-08-21 12:45:05 +00:00
clone : function ( ) {
return new this . CTOR ( this ) ;
} ,
2012-08-19 19:46:00 +00:00
$documentation : "Base class of all AST nodes" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
start : "[AST_Token] The first token of this node" ,
end : "[AST_Token] The last token of this node"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this ) ;
} ,
walk : function ( visitor ) {
return this . _walk ( visitor ) ; // not sure the indirection will be any help
2012-08-17 12:59:42 +00:00
}
2012-05-27 11:09:01 +00:00
} , null ) ;
2012-08-21 12:45:05 +00:00
AST _Node . warn _function = null ;
2012-08-20 14:19:30 +00:00
AST _Node . warn = function ( txt , props ) {
2012-08-21 12:45:05 +00:00
if ( AST _Node . warn _function )
AST _Node . warn _function ( string _template ( txt , props ) ) ;
2012-08-20 14:19:30 +00:00
} ;
2012-09-07 15:55:13 +00:00
/* -----[ statements ]----- */
2012-08-16 15:11:04 +00:00
2012-10-03 12:41:11 +00:00
var AST _Statement = DEFNODE ( "Statement" , null , {
$documentation : "Base class of all statements" ,
2012-05-27 11:09:01 +00:00
} ) ;
2012-10-03 12:41:11 +00:00
var AST _Debugger = DEFNODE ( "Debugger" , null , {
$documentation : "Represents a debugger statement" ,
} , AST _Statement ) ;
2015-01-27 20:26:27 +00:00
var AST _Directive = DEFNODE ( "Directive" , "value scope quote" , {
2012-10-03 12:41:11 +00:00
$documentation : "Represents a directive, like \"use strict\";" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
value : "[string] The value of this directive as a plain string (it's not an AST_String!)" ,
2015-01-27 20:26:27 +00:00
scope : "[AST_Scope/S] The scope that this directive affects" ,
quote : "[string] the original quote character"
2012-10-09 13:25:45 +00:00
} ,
2012-10-03 12:41:11 +00:00
} , AST _Statement ) ;
var AST _SimpleStatement = DEFNODE ( "SimpleStatement" , "body" , {
2012-10-09 10:52:32 +00:00
$documentation : "A statement consisting of an expression, i.e. a = 1 + 2" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
body : "[AST_Node] an expression node (should not be instanceof AST_Statement)"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . body . _walk ( visitor ) ;
} ) ;
}
2012-08-15 10:32:37 +00:00
} , AST _Statement ) ;
2012-05-27 11:09:01 +00:00
2012-09-05 08:31:02 +00:00
function walk _body ( node , visitor ) {
2012-09-21 11:19:05 +00:00
if ( node . body instanceof AST _Statement ) {
node . body . _walk ( visitor ) ;
}
else node . body . forEach ( function ( stat ) {
2012-09-05 08:31:02 +00:00
stat . _walk ( visitor ) ;
2012-09-07 15:55:13 +00:00
} ) ;
2012-09-05 08:31:02 +00:00
} ;
2012-10-03 12:41:11 +00:00
var AST _Block = DEFNODE ( "Block" , "body" , {
2012-10-09 10:52:32 +00:00
$documentation : "A body of statements (usually bracketed)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
body : "[AST_Statement*] an array of statements"
} ,
2012-09-05 08:31:02 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
walk _body ( this , visitor ) ;
} ) ;
}
} , AST _Statement ) ;
2012-10-09 10:52:32 +00:00
var AST _BlockStatement = DEFNODE ( "BlockStatement" , null , {
$documentation : "A block statement" ,
} , AST _Block ) ;
2012-08-15 10:32:37 +00:00
var AST _EmptyStatement = DEFNODE ( "EmptyStatement" , null , {
2012-10-09 10:52:32 +00:00
$documentation : "The empty statement (empty block or simply a semicolon)" ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this ) ;
}
2012-08-15 10:32:37 +00:00
} , AST _Statement ) ;
2012-05-27 11:09:01 +00:00
2012-10-03 12:41:11 +00:00
var AST _StatementWithBody = DEFNODE ( "StatementWithBody" , "body" , {
2012-10-09 10:52:32 +00:00
$documentation : "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
body : "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
} ,
2012-10-03 12:41:11 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . body . _walk ( visitor ) ;
} ) ;
}
2012-08-28 12:29:58 +00:00
} , AST _Statement ) ;
2012-09-03 09:05:10 +00:00
var AST _LabeledStatement = DEFNODE ( "LabeledStatement" , "label" , {
$documentation : "Statement with a label" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
label : "[AST_Label] a label definition"
} ,
2012-09-03 09:05:10 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . label . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
} , AST _StatementWithBody ) ;
2013-09-02 16:38:00 +00:00
var AST _IterationStatement = DEFNODE ( "IterationStatement" , null , {
2013-09-02 16:36:16 +00:00
$documentation : "Internal class. All loops inherit from it."
} , AST _StatementWithBody ) ;
2012-08-17 12:59:42 +00:00
var AST _DWLoop = DEFNODE ( "DWLoop" , "condition" , {
2012-10-09 10:52:32 +00:00
$documentation : "Base class for do/while statements" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
condition : "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
2012-08-19 12:57:50 +00:00
}
2013-09-02 16:36:16 +00:00
} , AST _IterationStatement ) ;
2012-05-27 11:09:01 +00:00
2012-08-17 12:59:42 +00:00
var AST _Do = DEFNODE ( "Do" , null , {
2012-10-09 13:25:45 +00:00
$documentation : "A `do` statement" ,
2015-01-06 10:27:23 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . body . _walk ( visitor ) ;
this . condition . _walk ( visitor ) ;
} ) ;
}
2012-08-17 12:59:42 +00:00
} , AST _DWLoop ) ;
var AST _While = DEFNODE ( "While" , null , {
2012-10-09 13:25:45 +00:00
$documentation : "A `while` statement" ,
2015-01-06 10:27:23 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . condition . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
2012-08-17 12:59:42 +00:00
} , AST _DWLoop ) ;
2012-05-27 11:09:01 +00:00
var AST _For = DEFNODE ( "For" , "init condition step" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `for` statement" ,
2012-10-09 13:25:45 +00:00
$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"
} ,
2012-08-19 12:57:50 +00:00
_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 ) ;
2012-08-20 14:19:30 +00:00
this . body . _walk ( visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2013-09-02 16:36:16 +00:00
} , AST _IterationStatement ) ;
2012-05-27 11:09:01 +00:00
var AST _ForIn = DEFNODE ( "ForIn" , "init name object" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `for ... in` statement" ,
2012-10-09 13:25:45 +00:00
$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"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
2012-08-21 12:45:05 +00:00
this . init . _walk ( visitor ) ;
this . object . _walk ( visitor ) ;
2012-08-20 14:19:30 +00:00
this . body . _walk ( visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2013-09-02 16:36:16 +00:00
} , AST _IterationStatement ) ;
2012-05-27 11:09:01 +00:00
2012-08-15 10:32:37 +00:00
var AST _With = DEFNODE ( "With" , "expression" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `with` statement" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
expression : "[AST_Node] the `with` expression"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
this . body . _walk ( visitor ) ;
} ) ;
}
2012-08-28 12:29:58 +00:00
} , AST _StatementWithBody ) ;
2012-05-27 11:09:01 +00:00
2012-08-19 12:57:50 +00:00
/* -----[ scope and functions ]----- */
2012-05-27 11:09:01 +00:00
2012-09-18 10:21:09 +00:00
var AST _Scope = DEFNODE ( "Scope" , "directives variables functions uses_with uses_eval parent_scope enclosed cname" , {
2012-09-05 08:31:02 +00:00
$documentation : "Base class for all statements introducing a lexical scope" ,
2012-10-09 13:25:45 +00:00
$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)" ,
} ,
2012-09-05 08:31:02 +00:00
} , AST _Block ) ;
2012-05-27 11:09:01 +00:00
2012-09-21 11:19:05 +00:00
var AST _Toplevel = DEFNODE ( "Toplevel" , "globals" , {
2012-10-08 09:55:18 +00:00
$documentation : "The toplevel scope" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
globals : "[Object/S] a map of name -> SymbolDef for all undeclared names" ,
} ,
2013-03-01 05:21:14 +00:00
wrap _enclose : function ( arg _parameter _pairs ) {
var self = this ;
var args = [ ] ;
var parameters = [ ] ;
arg _parameter _pairs . forEach ( function ( pair ) {
2014-03-23 01:02:21 +00:00
var splitAt = pair . lastIndexOf ( ":" ) ;
2013-03-01 05:21:14 +00:00
2014-03-23 01:02:21 +00:00
args . push ( pair . substr ( 0 , splitAt ) ) ;
parameters . push ( pair . substr ( splitAt + 1 ) ) ;
2013-03-01 05:21:14 +00:00
} ) ;
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 ;
} ,
2012-10-08 09:55:18 +00:00
wrap _commonjs : function ( name , export _all ) {
var self = this ;
2012-11-24 08:02:08 +00:00
var to _export = [ ] ;
2012-10-08 09:55:18 +00:00
if ( export _all ) {
self . figure _out _scope ( ) ;
self . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _SymbolDeclaration && node . definition ( ) . global ) {
2012-10-10 08:28:05 +00:00
if ( ! find _if ( function ( n ) { return n . name == node . name } , to _export ) )
to _export . push ( node ) ;
2012-10-08 09:55:18 +00:00
}
} ) ) ;
}
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" :
2012-10-10 08:28:05 +00:00
return MAP . splice ( self . body ) ;
2012-10-08 09:55:18 +00:00
case "$EXPORTS" :
var body = [ ] ;
2012-10-10 08:28:05 +00:00
to _export . forEach ( function ( sym ) {
2012-10-08 09:55:18 +00:00
body . push ( new AST _SimpleStatement ( {
body : new AST _Assign ( {
left : new AST _Sub ( {
expression : new AST _SymbolRef ( { name : "exports" } ) ,
2012-10-10 08:28:05 +00:00
property : new AST _String ( { value : sym . name } ) ,
2012-10-08 09:55:18 +00:00
} ) ,
operator : "=" ,
2012-10-10 08:28:05 +00:00
right : new AST _SymbolRef ( sym ) ,
2012-10-08 09:55:18 +00:00
} ) ,
} ) ) ;
} ) ;
2012-10-10 08:28:05 +00:00
return MAP . splice ( body ) ;
2012-10-08 09:55:18 +00:00
}
}
} ) ) ;
return wrapped _tl ;
}
2012-05-27 11:09:01 +00:00
} , AST _Scope ) ;
2015-01-15 03:03:38 +00:00
var AST _ArrowParametersOrSeq = DEFNODE ( "ArrowParametersOrSeq" , "expressions" , {
$documentation : "A set of arrow function parameters or a sequence expression. This is used because when the parser sees a \"(\" it could be the start of a seq, or the start of a parameter list of an arrow function." ,
$propdoc : {
expressions : "[AST_Expression|AST_Destructuring*] array of expressions or argument names or destructurings."
} ,
as _params : function ( croak ) {
// We don't want anything which doesn't belong in a destructuring
var root = this ;
return this . expressions . map ( function to _fun _args ( ex ) {
if ( ex instanceof AST _Object ) {
if ( ex . properties . length == 0 )
croak ( "Invalid destructuring function parameter" , ex . start . line , ex . start . col ) ;
return new AST _Destructuring ( {
start : ex . start ,
end : ex . end ,
is _array : false ,
names : ex . properties . map ( to _fun _args )
} ) ;
} else if ( ex instanceof AST _ObjectSymbol ) {
return new AST _SymbolFunarg ( {
name : ex . symbol . name ,
start : ex . start ,
end : ex . end
} ) ;
} else if ( ex instanceof AST _SymbolRef ) {
return new AST _SymbolFunarg ( {
name : ex . name ,
start : ex . start ,
end : ex . end
} ) ;
} else if ( ex instanceof AST _Array ) {
if ( ex . elements . length === 0 )
croak ( "Invalid destructuring function parameter" , ex . start . line , ex . start . col ) ;
return new AST _Destructuring ( {
start : ex . start ,
end : ex . end ,
is _array : true ,
names : ex . elements . map ( to _fun _args )
} ) ;
} else {
croak ( "Invalid function parameter" , ex . start . line , ex . start . col ) ;
}
} ) ;
} ,
as _expr : function ( croak ) {
return AST _Seq . from _array ( this . expressions ) ;
}
} ) ;
2012-08-21 17:06:57 +00:00
var AST _Lambda = DEFNODE ( "Lambda" , "name argnames uses_arguments" , {
2012-08-19 19:46:00 +00:00
$documentation : "Base class for functions" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
name : "[AST_SymbolDeclaration?] the name of this function" ,
2015-01-15 03:03:38 +00:00
argnames : "[AST_SymbolFunarg|AST_Destructuring*] array of function arguments or destructurings" ,
2012-10-09 13:25:45 +00:00
uses _arguments : "[boolean/S] tells whether this function accesses the arguments array"
} ,
2015-01-15 03:03:38 +00:00
args _as _names : function ( ) {
var out = [ ] ;
this . walk ( new TreeWalker ( function ( parm ) {
var that = this ;
if ( parm instanceof AST _SymbolFunarg ) {
out . push ( parm ) ;
}
} ) ) ;
return out ;
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
if ( this . name ) this . name . _walk ( visitor ) ;
this . argnames . forEach ( function ( arg ) {
arg . _walk ( visitor ) ;
} ) ;
2012-09-05 08:31:02 +00:00
walk _body ( this , visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2012-05-27 11:09:01 +00:00
} , AST _Scope ) ;
2012-05-27 14:25:31 +00:00
2012-11-07 10:43:27 +00:00
var AST _Accessor = DEFNODE ( "Accessor" , null , {
2013-10-30 09:50:22 +00:00
$documentation : "A setter/getter function. The `name` property is always null."
2012-11-07 10:43:27 +00:00
} , AST _Lambda ) ;
2012-05-27 11:09:01 +00:00
var AST _Function = DEFNODE ( "Function" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A function expression"
2012-05-27 11:09:01 +00:00
} , AST _Lambda ) ;
2012-05-27 14:25:31 +00:00
2015-01-15 03:03:38 +00:00
var AST _Arrow = DEFNODE ( "Arrow" , null , {
$documentation : "An ES6 Arrow function ((a) => b)"
} , AST _Lambda ) ;
2012-05-27 11:09:01 +00:00
var AST _Defun = DEFNODE ( "Defun" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A function definition"
2012-08-19 12:57:50 +00:00
} , AST _Lambda ) ;
2012-05-27 11:09:01 +00:00
2015-01-15 03:03:38 +00:00
/* -----[ DESTRUCTURING ]----- */
var AST _Destructuring = DEFNODE ( "Destructuring" , "names is_array" , {
$documentation : "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names" ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . names . forEach ( function ( name ) {
name . _walk ( visitor ) ;
} ) ;
} ) ;
}
} ) ;
2012-05-27 11:09:01 +00:00
/* -----[ JUMPS ]----- */
2012-05-27 14:25:31 +00:00
var AST _Jump = DEFNODE ( "Jump" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "Base class for “jumps” (for now that's `return`, `throw`, `break` and `continue`)"
2012-09-03 09:39:02 +00:00
} , AST _Statement ) ;
2012-05-27 11:09:01 +00:00
2012-05-27 14:25:31 +00:00
var AST _Exit = DEFNODE ( "Exit" , "value" , {
2012-08-19 19:46:00 +00:00
$documentation : "Base class for “exits” (`return` and `throw`)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
value : "[AST_Node?] the value returned or thrown by this statement; could be null for AST_Return"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , this . value && function ( ) {
this . value . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} , AST _Jump ) ;
2012-05-27 14:25:31 +00:00
var AST _Return = DEFNODE ( "Return" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `return` statement"
2012-05-27 14:25:31 +00:00
} , AST _Exit ) ;
2012-05-27 11:09:01 +00:00
var AST _Throw = DEFNODE ( "Throw" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `throw` statement"
2012-05-27 14:25:31 +00:00
} , AST _Exit ) ;
2012-10-09 13:25:45 +00:00
var AST _LoopControl = DEFNODE ( "LoopControl" , "label" , {
2012-08-19 19:46:00 +00:00
$documentation : "Base class for loop control statements (`break` and `continue`)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
label : "[AST_LabelRef?] the label, or null if none" ,
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , this . label && function ( ) {
this . label . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} , AST _Jump ) ;
2012-05-27 14:25:31 +00:00
var AST _Break = DEFNODE ( "Break" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `break` statement"
2012-05-27 14:25:31 +00:00
} , AST _LoopControl ) ;
var AST _Continue = DEFNODE ( "Continue" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `continue` statement"
2012-05-27 14:25:31 +00:00
} , AST _LoopControl ) ;
2012-05-27 11:09:01 +00:00
/* -----[ IF ]----- */
2012-09-03 09:11:44 +00:00
var AST _If = DEFNODE ( "If" , "condition alternative" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `if` statement" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
condition : "[AST_Node] the `if` condition" ,
alternative : "[AST_Statement?] the `else` part, or null if not present"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . condition . _walk ( visitor ) ;
2012-09-03 09:11:44 +00:00
this . body . _walk ( visitor ) ;
2012-08-19 12:57:50 +00:00
if ( this . alternative ) this . alternative . _walk ( visitor ) ;
} ) ;
}
2012-09-03 09:11:44 +00:00
} , AST _StatementWithBody ) ;
2012-05-27 11:09:01 +00:00
/* -----[ SWITCH ]----- */
2012-10-09 13:25:45 +00:00
var AST _Switch = DEFNODE ( "Switch" , "expression" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `switch` statement" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
expression : "[AST_Node] the `switch` “discriminant”"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
2012-10-03 12:52:01 +00:00
walk _body ( this , visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2012-10-09 13:25:45 +00:00
} , AST _Block ) ;
2012-05-27 11:09:01 +00:00
2012-08-19 12:57:50 +00:00
var AST _SwitchBranch = DEFNODE ( "SwitchBranch" , null , {
2012-09-03 08:05:59 +00:00
$documentation : "Base class for `switch` branches" ,
2012-09-05 08:31:02 +00:00
} , AST _Block ) ;
2012-05-27 11:09:01 +00:00
var AST _Default = DEFNODE ( "Default" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `default` switch branch" ,
2012-05-27 11:09:01 +00:00
} , AST _SwitchBranch ) ;
var AST _Case = DEFNODE ( "Case" , "expression" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `case` switch branch" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
expression : "[AST_Node] the `case` expression"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
2012-09-05 08:31:02 +00:00
walk _body ( this , visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2012-05-27 11:09:01 +00:00
} , AST _SwitchBranch ) ;
/* -----[ EXCEPTIONS ]----- */
2012-09-05 08:31:02 +00:00
var AST _Try = DEFNODE ( "Try" , "bcatch bfinally" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `try` statement" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
bcatch : "[AST_Catch?] the catch block, or null if not present" ,
bfinally : "[AST_Finally?] the finally block, or null if not present"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
2012-09-05 08:31:02 +00:00
walk _body ( this , visitor ) ;
2012-08-19 12:57:50 +00:00
if ( this . bcatch ) this . bcatch . _walk ( visitor ) ;
if ( this . bfinally ) this . bfinally . _walk ( visitor ) ;
} ) ;
}
2012-09-05 08:31:02 +00:00
} , AST _Block ) ;
2012-05-27 11:09:01 +00:00
2012-09-05 08:31:02 +00:00
var AST _Catch = DEFNODE ( "Catch" , "argname" , {
2012-08-19 19:46:00 +00:00
$documentation : "A `catch` node; only makes sense as part of a `try` statement" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
argname : "[AST_SymbolCatch] symbol for the exception"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . argname . _walk ( visitor ) ;
2012-09-05 08:31:02 +00:00
walk _body ( this , visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2013-12-05 11:30:29 +00:00
} , AST _Block ) ;
2012-05-27 11:09:01 +00:00
2012-09-05 08:31:02 +00:00
var AST _Finally = DEFNODE ( "Finally" , null , {
$documentation : "A `finally` node; only makes sense as part of a `try` statement"
} , AST _Block ) ;
2012-05-27 11:09:01 +00:00
/* -----[ VAR/CONST ]----- */
2012-08-17 12:59:42 +00:00
var AST _Definitions = DEFNODE ( "Definitions" , "definitions" , {
2012-08-19 19:46:00 +00:00
$documentation : "Base class for `var` or `const` nodes (variable declarations/initializations)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
definitions : "[AST_VarDef*] array of variable definitions"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . definitions . forEach ( function ( def ) {
def . _walk ( visitor ) ;
} ) ;
} ) ;
}
2012-09-03 09:39:02 +00:00
} , AST _Statement ) ;
2012-05-27 11:09:01 +00:00
var AST _Var = DEFNODE ( "Var" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `var` statement"
2012-05-27 11:09:01 +00:00
} , AST _Definitions ) ;
var AST _Const = DEFNODE ( "Const" , null , {
2012-08-19 19:46:00 +00:00
$documentation : "A `const` statement"
2012-05-27 11:09:01 +00:00
} , AST _Definitions ) ;
var AST _VarDef = DEFNODE ( "VarDef" , "name value" , {
2012-08-19 19:46:00 +00:00
$documentation : "A variable declaration; only appears in a AST_Definitions node" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
name : "[AST_SymbolVar|AST_SymbolConst] name of the variable" ,
value : "[AST_Node?] initializer, or null of there's no initializer"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . name . _walk ( visitor ) ;
if ( this . value ) this . value . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
/* -----[ OTHER ]----- */
var AST _Call = DEFNODE ( "Call" , "expression args" , {
2012-08-19 19:46:00 +00:00
$documentation : "A function call expression" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
expression : "[AST_Node] expression to invoke as function" ,
args : "[AST_Node*] array of arguments"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
this . args . forEach ( function ( arg ) {
arg . _walk ( visitor ) ;
} ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
var AST _New = DEFNODE ( "New" , null , {
2012-10-09 10:52:32 +00:00
$documentation : "An object instantiation. Derives from a function call since it has exactly the same properties"
2012-05-27 11:09:01 +00:00
} , AST _Call ) ;
2012-09-14 12:36:38 +00:00
var AST _Seq = DEFNODE ( "Seq" , "car cdr" , {
2012-08-19 19:46:00 +00:00
$documentation : "A sequence expression (two comma-separated expressions)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
car : "[AST_Node] first element in sequence" ,
cdr : "[AST_Node] second element in sequence"
} ,
2012-09-14 12:36:38 +00:00
$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 ;
} ,
2012-10-22 08:49:58 +00:00
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 ;
} ,
2012-09-14 12:36:38 +00:00
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 ;
}
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
2012-09-14 12:36:38 +00:00
this . car . _walk ( visitor ) ;
if ( this . cdr ) this . cdr . _walk ( visitor ) ;
2012-08-19 12:57:50 +00:00
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
var AST _PropAccess = DEFNODE ( "PropAccess" , "expression property" , {
2012-10-09 13:25:45 +00:00
$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"
}
2012-05-27 11:09:01 +00:00
} ) ;
var AST _Dot = DEFNODE ( "Dot" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "A dotted property access expression" ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} , AST _PropAccess ) ;
var AST _Sub = DEFNODE ( "Sub" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Index-style property access, i.e. `a[\"foo\"]`" ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
this . property . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} , AST _PropAccess ) ;
var AST _Unary = DEFNODE ( "Unary" , "operator expression" , {
2012-09-03 09:05:10 +00:00
$documentation : "Base class for unary expressions" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
operator : "[string] the operator" ,
expression : "[AST_Node] expression that this unary operator applies to"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . expression . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
var AST _UnaryPrefix = DEFNODE ( "UnaryPrefix" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Unary prefix expression, i.e. `typeof i` or `++i`"
2012-05-27 11:09:01 +00:00
} , AST _Unary ) ;
var AST _UnaryPostfix = DEFNODE ( "UnaryPostfix" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Unary postfix expression, i.e. `i++`"
2012-05-27 11:09:01 +00:00
} , AST _Unary ) ;
var AST _Binary = DEFNODE ( "Binary" , "left operator right" , {
2012-09-03 09:05:10 +00:00
$documentation : "Binary expression, i.e. `a + b`" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
left : "[AST_Node] left-hand side expression" ,
operator : "[string] the operator" ,
right : "[AST_Node] right-hand side expression"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . left . _walk ( visitor ) ;
this . right . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
var AST _Conditional = DEFNODE ( "Conditional" , "condition consequent alternative" , {
2012-09-03 09:05:10 +00:00
$documentation : "Conditional expression using the ternary operator, i.e. `a ? b : c`" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
condition : "[AST_Node]" ,
consequent : "[AST_Node]" ,
alternative : "[AST_Node]"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . condition . _walk ( visitor ) ;
this . consequent . _walk ( visitor ) ;
this . alternative . _walk ( visitor ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
2012-10-09 13:25:45 +00:00
var AST _Assign = DEFNODE ( "Assign" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "An assignment expression — `a = b + 5`" ,
2012-05-27 14:25:31 +00:00
} , AST _Binary ) ;
2012-05-27 11:09:01 +00:00
/* -----[ LITERALS ]----- */
var AST _Array = DEFNODE ( "Array" , "elements" , {
2012-09-03 09:05:10 +00:00
$documentation : "An array literal" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
elements : "[AST_Node*] array of elements"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . elements . forEach ( function ( el ) {
el . _walk ( visitor ) ;
} ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
var AST _Object = DEFNODE ( "Object" , "properties" , {
2012-09-03 09:05:10 +00:00
$documentation : "An object literal" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
properties : "[AST_ObjectProperty*] array of properties"
} ,
2012-08-19 12:57:50 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . properties . forEach ( function ( prop ) {
prop . _walk ( visitor ) ;
} ) ;
} ) ;
}
2012-05-27 11:09:01 +00:00
} ) ;
2012-08-21 08:38:49 +00:00
var AST _ObjectProperty = DEFNODE ( "ObjectProperty" , "key value" , {
2012-09-03 09:05:10 +00:00
$documentation : "Base class for literal object properties" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
2013-10-30 09:50:22 +00:00
key : "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node." ,
2012-10-09 13:25:45 +00:00
value : "[AST_Node] property value. For setters and getters this is an AST_Function."
} ,
2012-08-21 08:38:49 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . value . _walk ( visitor ) ;
} ) ;
}
} ) ;
2012-05-27 11:09:01 +00:00
2015-01-27 20:26:27 +00:00
var AST _ObjectKeyVal = DEFNODE ( "ObjectKeyVal" , "quote" , {
2012-09-03 09:05:10 +00:00
$documentation : "A key: value object property" ,
2015-01-27 20:26:27 +00:00
$propdoc : {
quote : "[string] the original quote character"
}
2012-05-27 11:09:01 +00:00
} , AST _ObjectProperty ) ;
2015-01-15 03:03:38 +00:00
var AST _ObjectSymbol = DEFNODE ( "ObjectSymbol" , "symbol" , {
$propdoc : {
symbol : "[AST_SymbolRef] what symbol it is"
} ,
$documentation : "A symbol in an object" ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . symbol . _walk ( visitor ) ;
} ) ;
}
} , AST _ObjectProperty ) ;
2012-08-19 12:57:50 +00:00
var AST _ObjectSetter = DEFNODE ( "ObjectSetter" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "An object setter property" ,
2012-05-27 11:09:01 +00:00
} , AST _ObjectProperty ) ;
2012-08-19 12:57:50 +00:00
var AST _ObjectGetter = DEFNODE ( "ObjectGetter" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "An object getter property" ,
2012-05-27 11:09:01 +00:00
} , AST _ObjectProperty ) ;
2012-09-11 12:42:28 +00:00
var AST _Symbol = DEFNODE ( "Symbol" , "scope name thedef" , {
2012-10-09 13:25:45 +00:00
$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"
} ,
2012-09-03 09:05:10 +00:00
$documentation : "Base class for all symbols" ,
2012-05-27 14:25:31 +00:00
} ) ;
2012-11-07 10:43:27 +00:00
var AST _SymbolAccessor = DEFNODE ( "SymbolAccessor" , null , {
$documentation : "The name of a property accessor (setter/getter function)"
} , AST _Symbol ) ;
2012-09-23 09:47:34 +00:00
var AST _SymbolDeclaration = DEFNODE ( "SymbolDeclaration" , "init" , {
2012-09-03 09:05:10 +00:00
$documentation : "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
init : "[AST_Node*/S] array of initializers for this declaration."
}
2012-05-27 14:25:31 +00:00
} , AST _Symbol ) ;
2012-08-19 12:57:50 +00:00
var AST _SymbolVar = DEFNODE ( "SymbolVar" , null , {
2012-10-02 09:22:39 +00:00
$documentation : "Symbol defining a variable" ,
} , AST _SymbolDeclaration ) ;
var AST _SymbolConst = DEFNODE ( "SymbolConst" , null , {
$documentation : "A constant declaration"
2012-08-19 12:57:50 +00:00
} , AST _SymbolDeclaration ) ;
2012-05-27 14:25:31 +00:00
2012-08-19 12:57:50 +00:00
var AST _SymbolFunarg = DEFNODE ( "SymbolFunarg" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Symbol naming a function argument" ,
2012-08-19 12:57:50 +00:00
} , AST _SymbolVar ) ;
var AST _SymbolDefun = DEFNODE ( "SymbolDefun" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Symbol defining a function" ,
2012-08-19 12:57:50 +00:00
} , AST _SymbolDeclaration ) ;
var AST _SymbolLambda = DEFNODE ( "SymbolLambda" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Symbol naming a function expression" ,
2012-08-19 12:57:50 +00:00
} , AST _SymbolDeclaration ) ;
var AST _SymbolCatch = DEFNODE ( "SymbolCatch" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Symbol naming the exception in catch" ,
2012-08-19 12:57:50 +00:00
} , AST _SymbolDeclaration ) ;
2012-05-27 11:09:01 +00:00
2012-10-09 13:25:45 +00:00
var AST _Label = DEFNODE ( "Label" , "references" , {
2012-09-03 09:05:10 +00:00
$documentation : "Symbol naming a label (declaration)" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
2013-09-02 16:36:16 +00:00
references : "[AST_LoopControl*] a list of nodes referring to this label"
} ,
initialize : function ( ) {
this . references = [ ] ;
this . thedef = this ;
2012-10-09 13:25:45 +00:00
}
2012-10-10 08:37:51 +00:00
} , AST _Symbol ) ;
2012-08-19 12:57:50 +00:00
2012-09-11 12:42:28 +00:00
var AST _SymbolRef = DEFNODE ( "SymbolRef" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Reference to some symbol (not definition/declaration)" ,
2012-08-19 12:57:50 +00:00
} , AST _Symbol ) ;
2012-05-27 14:25:31 +00:00
2012-08-19 12:57:50 +00:00
var AST _LabelRef = DEFNODE ( "LabelRef" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Reference to a label symbol" ,
2012-11-08 13:39:14 +00:00
} , AST _Symbol ) ;
2012-05-27 14:25:31 +00:00
2012-08-19 12:57:50 +00:00
var AST _This = DEFNODE ( "This" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "The `this` symbol" ,
2012-08-19 12:57:50 +00:00
} , AST _Symbol ) ;
2012-05-27 14:25:31 +00:00
var AST _Constant = DEFNODE ( "Constant" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Base class for all constants" ,
2012-05-27 14:25:31 +00:00
getValue : function ( ) {
return this . value ;
}
2012-05-27 11:09:01 +00:00
} ) ;
2015-01-27 20:26:27 +00:00
var AST _String = DEFNODE ( "String" , "value quote" , {
2012-09-03 09:05:10 +00:00
$documentation : "A string literal" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
2015-01-27 20:26:27 +00:00
value : "[string] the contents of this string" ,
quote : "[string] the original quote character"
2012-10-09 13:25:45 +00:00
}
2012-05-27 14:25:31 +00:00
} , AST _Constant ) ;
2012-05-27 11:09:01 +00:00
var AST _Number = DEFNODE ( "Number" , "value" , {
2012-09-03 09:05:10 +00:00
$documentation : "A number literal" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
value : "[number] the numeric value"
}
2012-05-27 14:25:31 +00:00
} , AST _Constant ) ;
2012-05-27 11:09:01 +00:00
2012-10-09 13:25:45 +00:00
var AST _RegExp = DEFNODE ( "RegExp" , "value" , {
2012-09-03 09:05:10 +00:00
$documentation : "A regexp literal" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
value : "[RegExp] the actual regexp"
2012-05-27 14:25:31 +00:00
}
} , AST _Constant ) ;
2012-05-27 11:09:01 +00:00
var AST _Atom = DEFNODE ( "Atom" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Base class for atoms" ,
2012-05-27 14:25:31 +00:00
} , AST _Constant ) ;
2012-05-27 11:09:01 +00:00
var AST _Null = DEFNODE ( "Null" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "The `null` atom" ,
2012-08-15 10:32:37 +00:00
value : null
2012-05-27 11:09:01 +00:00
} , AST _Atom ) ;
2012-09-18 07:53:46 +00:00
var AST _NaN = DEFNODE ( "NaN" , null , {
$documentation : "The impossible value" ,
value : 0 / 0
} , AST _Atom ) ;
2012-05-27 11:09:01 +00:00
var AST _Undefined = DEFNODE ( "Undefined" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "The `undefined` value" ,
2012-08-15 10:32:37 +00:00
value : ( function ( ) { } ( ) )
2012-05-27 11:09:01 +00:00
} , AST _Atom ) ;
2013-01-16 19:59:19 +00:00
var AST _Hole = DEFNODE ( "Hole" , null , {
$documentation : "A hole in an array" ,
value : ( function ( ) { } ( ) )
} , AST _Atom ) ;
2012-10-09 15:35:53 +00:00
var AST _Infinity = DEFNODE ( "Infinity" , null , {
$documentation : "The `Infinity` value" ,
value : 1 / 0
} , AST _Atom ) ;
2012-09-14 12:36:38 +00:00
var AST _Boolean = DEFNODE ( "Boolean" , null , {
$documentation : "Base class for booleans" ,
} , AST _Atom ) ;
2012-05-27 11:09:01 +00:00
var AST _False = DEFNODE ( "False" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "The `false` atom" ,
2012-08-15 10:32:37 +00:00
value : false
2012-09-14 12:36:38 +00:00
} , AST _Boolean ) ;
2012-05-27 11:09:01 +00:00
var AST _True = DEFNODE ( "True" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "The `true` atom" ,
2012-08-15 10:32:37 +00:00
value : true
2012-09-14 12:36:38 +00:00
} , AST _Boolean ) ;
2012-08-19 12:57:50 +00:00
/* -----[ TreeWalker ]----- */
function TreeWalker ( callback ) {
this . visit = callback ;
this . stack = [ ] ;
} ;
TreeWalker . prototype = {
_visit : function ( node , descend ) {
this . stack . push ( node ) ;
2012-09-28 08:12:47 +00:00
var ret = this . visit ( node , descend ? function ( ) {
2012-08-21 09:37:05 +00:00
descend . call ( node ) ;
2012-09-28 08:12:47 +00:00
} : noop ) ;
2012-08-19 12:57:50 +00:00
if ( ! ret && descend ) {
descend . call ( node ) ;
}
2012-08-22 12:21:58 +00:00
this . stack . pop ( ) ;
2012-08-19 12:57:50 +00:00
return ret ;
2012-08-22 12:21:58 +00:00
} ,
parent : function ( n ) {
return this . stack [ this . stack . length - 2 - ( n || 0 ) ] ;
2012-09-26 09:16:16 +00:00
} ,
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 ;
}
} ,
2013-06-07 09:51:23 +00:00
has _directive : function ( type ) {
return this . find _parent ( AST _Scope ) . has _directive ( type ) ;
} ,
2012-09-26 09:16:16 +00:00
in _boolean _context : function ( ) {
var stack = this . stack ;
2012-10-12 08:07:35 +00:00
var i = stack . length , self = stack [ -- i ] ;
2012-09-26 09:16:16 +00:00
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 ;
2012-10-12 08:07:35 +00:00
self = p ;
2012-09-26 09:16:16 +00:00
}
} ,
2012-10-09 13:25:45 +00:00
loopcontrol _target : function ( label ) {
var stack = this . stack ;
2013-09-06 06:52:56 +00:00
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 ;
2012-10-09 13:25:45 +00:00
}
2013-09-06 06:52:56 +00:00
} else for ( var i = stack . length ; -- i >= 0 ; ) {
var x = stack [ i ] ;
if ( x instanceof AST _Switch || x instanceof AST _IterationStatement )
return x ;
2012-10-09 13:25:45 +00:00
}
}
2012-08-19 12:57:50 +00:00
} ;