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 ;
}
2016-04-07 10:15:28 +00:00
if ( methods ) for ( i in methods ) if ( HOP ( methods , 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 ;
} ;
2015-09-24 14:57:47 +00:00
exports [ "AST_" + type ] = ctor ;
2012-05-27 11:09:01 +00:00
return ctor ;
} ;
2015-11-12 10:18:25 +00:00
var AST _Token = DEFNODE ( "Token" , "type value line col pos endline endcol endpos nlb comments_before file raw" , {
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 ) {
2015-01-11 20:07:19 +00:00
if ( node . body instanceof AST _Node ) {
2012-09-21 11:19:05 +00:00
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
2015-04-13 00:25:46 +00:00
var AST _ForOf = DEFNODE ( "ForOf" , null , {
$documentation : "A `for ... of` statement" ,
} , AST _ForIn ) ;
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
2016-10-19 13:34:26 +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)" ,
2016-04-18 13:51:32 +00:00
} ,
get _defun _scope : function ( ) {
var self = this ;
2016-10-19 13:34:26 +00:00
while ( self . is _block _scope ( ) && self . parent _scope ) {
2016-04-18 13:51:32 +00:00
self = self . parent _scope ;
}
return self ;
2016-04-17 11:37:01 +00:00
}
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
}
} ) ) ;
}
2015-09-24 14:55:37 +00:00
var wrapped _tl = "(function(exports, global){ '$ORIG'; '$EXPORTS'; global['" + name + "'] = exports; }({}, (function(){return this}())))" ;
2012-10-08 09:55:18 +00:00
wrapped _tl = parse ( wrapped _tl ) ;
wrapped _tl = wrapped _tl . transform ( new TreeTransformer ( function before ( node ) {
2015-09-24 14:55:37 +00:00
if ( node instanceof AST _Directive ) {
switch ( node . value ) {
2012-10-08 09:55:18 +00:00
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 ) ;
2016-06-10 23:40:45 +00:00
var AST _Expansion = DEFNODE ( "Expansion" , "expression" , {
2015-08-14 01:19:53 +00:00
$documentation : "An expandible argument, such as ...rest, a splat, such as [1,2,...all], or an expansion in a variable declaration, such as var [first, ...rest] = list" ,
2015-04-13 00:26:26 +00:00
$propdoc : {
2016-06-10 23:40:45 +00:00
expression : "AST_Symbol the thing to be expanded"
2015-04-13 00:26:26 +00:00
} ,
_walk : function ( visitor ) {
var self = this ;
return visitor . _visit ( this , function ( ) {
2016-06-10 23:40:45 +00:00
self . expression . walk ( visitor ) ;
2015-04-13 00:26:26 +00:00
} ) ;
}
} ) ;
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 : {
2015-04-13 00:26:26 +00:00
expressions : "[AST_Expression|AST_Destructuring|AST_Expansion*] array of expressions or argument names or destructurings."
2015-01-15 03:03:38 +00:00
} ,
as _params : function ( croak ) {
// We don't want anything which doesn't belong in a destructuring
var root = this ;
2015-11-22 18:02:35 +00:00
return this . expressions . map ( function to _fun _args ( ex , _ , _ _ , default _seen _above ) {
2015-01-15 03:03:38 +00:00
if ( ex instanceof AST _Object ) {
return new AST _Destructuring ( {
start : ex . start ,
end : ex . end ,
is _array : false ,
2015-11-22 18:02:35 +00:00
default : default _seen _above ,
2015-01-15 03:03:38 +00:00
names : ex . properties . map ( to _fun _args )
} ) ;
2016-10-18 14:18:34 +00:00
} else if ( ex instanceof AST _ObjectKeyVal ) {
2016-09-06 23:00:07 +00:00
if ( ex . key instanceof AST _SymbolRef ) {
ex . key = to _fun _args ( ex . key , 0 , [ ex . key ] , ex . default ) ;
}
ex . value = to _fun _args ( ex . value , 0 , [ ex . key ] , ex . default ) ;
return ex ;
} else if ( ex instanceof AST _Hole ) {
return ex ;
2015-08-03 23:14:18 +00:00
} else if ( ex instanceof AST _Destructuring ) {
if ( ex . names . length == 0 )
croak ( "Invalid destructuring function parameter" , ex . start . line , ex . start . col ) ;
ex . names = ex . names . map ( to _fun _args ) ;
return ex ;
2015-01-15 03:03:38 +00:00
} else if ( ex instanceof AST _SymbolRef ) {
return new AST _SymbolFunarg ( {
name : ex . name ,
2015-11-22 18:02:35 +00:00
default : default _seen _above ,
2015-01-15 03:03:38 +00:00
start : ex . start ,
end : ex . end
} ) ;
2015-04-13 00:26:26 +00:00
} else if ( ex instanceof AST _Expansion ) {
return ex ;
2015-01-15 03:03:38 +00:00
} else if ( ex instanceof AST _Array ) {
return new AST _Destructuring ( {
start : ex . start ,
end : ex . end ,
is _array : true ,
2015-11-22 18:02:35 +00:00
default : default _seen _above ,
2015-01-15 03:03:38 +00:00
names : ex . elements . map ( to _fun _args )
} ) ;
2015-11-22 18:02:35 +00:00
} else if ( ex instanceof AST _Assign ) {
return to _fun _args ( ex . left , undefined , undefined , ex . right ) ;
2015-01-15 03:03:38 +00:00
} else {
croak ( "Invalid function parameter" , ex . start . line , ex . start . col ) ;
}
} ) ;
} ,
as _expr : function ( croak ) {
return AST _Seq . from _array ( this . expressions ) ;
}
} ) ;
2016-02-04 21:19:48 +00:00
var AST _Lambda = DEFNODE ( "Lambda" , "name argnames uses_arguments is_generator" , {
2012-08-19 19:46:00 +00:00
$documentation : "Base class for functions" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
2016-07-29 01:18:21 +00:00
is _generator : "[boolean] is generatorFn or not" ,
name : "[AST_SymbolDeclaration?] the name of this function" ,
2015-04-13 00:26:26 +00:00
argnames : "[AST_SymbolFunarg|AST_Destructuring|AST_Expansion*] array of function arguments, destructurings, or expanding arguments" ,
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 = [ ] ;
2015-08-13 01:58:08 +00:00
for ( var i = 0 ; i < this . argnames . length ; i ++ ) {
if ( this . argnames [ i ] instanceof AST _Destructuring ) {
out = out . concat ( this . argnames [ i ] . all _symbols ( ) ) ;
} else {
out . push ( this . argnames [ i ] ) ;
2015-04-13 00:26:26 +00:00
}
2015-08-13 01:58:08 +00:00
}
2015-01-15 03:03:38 +00:00
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 ]----- */
2015-11-22 18:02:35 +00:00
var AST _Destructuring = DEFNODE ( "Destructuring" , "names is_array default" , {
2015-01-15 03:03:38 +00:00
$documentation : "A destructuring of several names. Used in destructuring assignment and with destructuring function argument names" ,
2016-09-06 23:00:07 +00:00
$propdoc : {
"names" : "[AST_Destructuring|AST_Expansion|AST_Hole|AST_ObjectKeyVal|AST_Symbol] Array of properties or elements" ,
"is_array" : "[Boolean] Whether the destructuring represents an object or array" ,
"default" : "[AST_Node?] Default assign value"
} ,
2015-01-15 03:03:38 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . names . forEach ( function ( name ) {
name . _walk ( visitor ) ;
} ) ;
} ) ;
2015-08-13 01:58:08 +00:00
} ,
all _symbols : function ( ) {
var out = [ ] ;
this . walk ( new TreeWalker ( function ( node ) {
if ( node instanceof AST _Symbol ) {
out . push ( node ) ;
}
if ( node instanceof AST _Expansion ) {
2016-06-10 23:40:45 +00:00
out . push ( node . expression ) ;
2015-08-13 01:58:08 +00:00
}
} ) ) ;
return out ;
2015-01-15 03:03:38 +00:00
}
} ) ;
2015-09-05 21:48:17 +00:00
var AST _PrefixedTemplateString = DEFNODE ( "PrefixedTemplateString" , "template_string prefix" , {
$documentation : "A templatestring with a prefix, such as String.raw`foobarbaz`" ,
$propdoc : {
template _string : "[AST_TemplateString] The template string" ,
prefix : "[AST_SymbolRef|AST_PropAccess] The prefix, which can be a symbol such as `foo` or a dotted expression such as `String.raw`."
} ,
_walk : function ( visitor ) {
this . prefix . _walk ( visitor ) ;
this . template _string . _walk ( visitor ) ;
}
} )
2015-09-05 21:32:57 +00:00
var AST _TemplateString = DEFNODE ( "TemplateString" , "segments" , {
$documentation : "A template string literal" ,
$propdoc : {
2016-06-22 17:24:03 +00:00
segments : "[AST_TemplateSegment|AST_Expression]* One or more segments, starting with AST_TemplateSegment. AST_Expression may follow AST_TemplateSegment, but each AST_Expression must be followed by AST_TemplateSegment."
2015-09-05 21:32:57 +00:00
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . segments . forEach ( function ( seg , i ) {
if ( i % 2 !== 0 ) {
seg . _walk ( visitor ) ;
}
} ) ;
} ) ;
}
} ) ;
2016-06-22 17:24:03 +00:00
var AST _TemplateSegment = DEFNODE ( "TemplateSegment" , "value raw" , {
$documentation : "A segment of a template string literal" ,
$propdoc : {
value : "Content of the segment" ,
raw : "Raw content of the segment"
}
} ) ;
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 ) ;
2015-09-06 20:33:17 +00:00
var AST _Let = DEFNODE ( "Let" , null , {
$documentation : "A `let` statement"
} , AST _Definitions ) ;
2012-05-27 11:09:01 +00:00
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 ) ;
2016-02-26 21:12:19 +00:00
var AST _NameImport = DEFNODE ( "NameImport" , "foreign_name name" , {
$documentation : "The part of the import statement that imports names from a module." ,
$propdoc : {
foreign _name : "[AST_SymbolImportForeign] The name being imported (as specified in the module)" ,
name : "[AST_SymbolImport] The name as it becomes available to this module."
2016-02-27 12:01:16 +00:00
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
this . foreign _name . _walk ( visitor ) ;
this . name . _walk ( visitor ) ;
} ) ;
2016-02-26 21:12:19 +00:00
}
} )
var AST _Import = DEFNODE ( "Import" , "imported_name imported_names module_name" , {
2016-01-29 20:47:49 +00:00
$documentation : "An `import` statement" ,
$propdoc : {
2016-02-21 17:06:09 +00:00
imported _name : "[AST_SymbolImport] The name of the variable holding the module's default export." ,
2016-02-26 21:12:19 +00:00
imported _names : "[AST_NameImport*] The names of non-default imported variables" ,
2016-01-29 20:47:49 +00:00
module _name : "[AST_String] String literal describing where this module came from" ,
2016-02-21 17:06:09 +00:00
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
if ( this . imported _name ) {
this . imported _name . _walk ( visitor ) ;
}
2016-02-27 12:01:16 +00:00
if ( this . imported _names ) {
this . imported _names . forEach ( function ( name _import ) {
name _import . _walk ( visitor ) ;
} ) ;
}
2016-02-21 17:06:09 +00:00
this . module _name . _walk ( visitor ) ;
} ) ;
2016-01-29 20:47:49 +00:00
}
} ) ;
2016-02-27 12:24:18 +00:00
var AST _Export = DEFNODE ( "Export" , "exported_definition exported_value is_default" , {
$documentation : "An `export` statement" ,
$propdoc : {
exported _definition : "[AST_Defun|AST_Definitions|AST_DefClass?] An exported definition" ,
exported _value : "[AST_Node?] An exported value" ,
is _default : "[Boolean] Whether this is the default exported value of this module"
} ,
2016-02-27 12:40:57 +00:00
_walk : function ( visitor ) {
visitor . _visit ( this , function ( ) {
if ( this . exported _definition ) {
this . exported _definition . _walk ( visitor ) ;
}
if ( this . exported _value ) {
this . exported _value . _walk ( visitor ) ;
}
} ) ;
}
2016-02-27 12:24:18 +00:00
} , AST _Statement ) ;
2012-05-27 11:09:01 +00:00
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 : {
2015-08-13 23:20:21 +00:00
name : "[AST_SymbolVar|AST_SymbolConst|AST_Destructuring] name of the variable" ,
2012-10-09 13:25:45 +00:00
value : "[AST_Node?] initializer, or null of there's no initializer"
} ,
2015-08-13 23:20:21 +00:00
is _destructuring : function ( ) {
return this . name instanceof AST _Destructuring ;
} ,
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 ;
}
} ,
2016-04-12 11:15:14 +00:00
len : function ( ) {
if ( this . cdr instanceof AST _Seq ) {
return this . cdr . len ( ) + 1 ;
} else {
return 2 ;
}
} ,
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 : {
2016-07-29 01:18:21 +00:00
key : "[string|AST_Node] the property name converted to a string for ObjectKeyVal. For setters, getters and computed property this is an arbitrary AST_Node" ,
2016-08-20 20:32:29 +00:00
value : "[AST_Node] property value. For setters and getters this is an AST_Function." ,
default : "[AST_Expression] The default for this parameter, only used when nested inside a binding pattern"
2012-10-09 13:25:45 +00:00
} ,
2012-08-21 08:38:49 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
2016-07-29 01:18:21 +00:00
if ( this . key instanceof AST _Node )
this . key . _walk ( visitor ) ;
2012-08-21 08:38:49 +00:00
this . value . _walk ( visitor ) ;
} ) ;
}
} ) ;
2012-05-27 11:09:01 +00:00
2016-09-06 23:00:07 +00:00
var AST _ObjectKeyVal = DEFNODE ( "ObjectKeyVal" , "quote default" , {
2012-09-03 09:05:10 +00:00
$documentation : "A key: value object property" ,
2015-01-27 20:26:27 +00:00
$propdoc : {
2016-03-12 15:53:57 +00:00
quote : "[string] the original quote character" ,
2016-09-06 23:00:07 +00:00
default : "[AST_Expression] The default parameter value, only used when nested inside a binding pattern"
2015-01-27 20:26:27 +00:00
}
2012-05-27 11:09:01 +00:00
} , AST _ObjectProperty ) ;
2015-09-07 21:46:07 +00:00
2016-07-29 01:18:21 +00:00
var AST _ObjectSetter = DEFNODE ( "ObjectSetter" , "quote static" , {
2015-10-27 00:51:47 +00:00
$propdoc : {
2016-07-29 01:18:21 +00:00
quote : "[string|undefined] the original quote character, if any" ,
2015-10-27 00:51:47 +00:00
static : "[boolean] whether this is a static setter (classes only)"
} ,
2012-09-03 09:05:10 +00:00
$documentation : "An object setter property" ,
2012-05-27 11:09:01 +00:00
} , AST _ObjectProperty ) ;
2016-07-29 01:18:21 +00:00
var AST _ObjectGetter = DEFNODE ( "ObjectGetter" , "quote static" , {
2015-10-27 00:51:47 +00:00
$propdoc : {
2016-07-29 01:18:21 +00:00
quote : "[string|undefined] the original quote character, if any" ,
2015-10-27 00:51:47 +00:00
static : "[boolean] whether this is a static getter (classes only)"
} ,
2012-09-03 09:05:10 +00:00
$documentation : "An object getter property" ,
2012-05-27 11:09:01 +00:00
} , AST _ObjectProperty ) ;
2016-07-29 01:18:21 +00:00
var AST _ConciseMethod = DEFNODE ( "ConciseMethod" , "quote static is_generator" , {
$propdoc : {
quote : "[string|undefined] the original quote character, if any" ,
static : "[boolean] whether this method is static (classes only)" ,
is _generator : "[boolean] is generatorFn or not" ,
} ,
$documentation : "An ES6 concise method inside an object or class"
} , AST _ObjectProperty ) ;
2015-11-20 19:34:10 +00:00
var AST _Class = DEFNODE ( "Class" , "name extends properties" , {
2015-10-27 00:40:46 +00:00
$propdoc : {
2015-11-21 09:17:32 +00:00
name : "[AST_SymbolClass|AST_SymbolDefClass?] optional class name." ,
2015-10-27 00:40:46 +00:00
extends : "[AST_Node]? optional parent class" ,
2015-11-20 19:34:10 +00:00
properties : "[AST_ObjectProperty*] array of properties"
2015-10-27 00:40:46 +00:00
} ,
$documentation : "An ES6 class" ,
2015-11-20 19:34:10 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
if ( this . name ) {
this . name . _walk ( visitor ) ;
}
if ( this . extends ) {
this . extends . _walk ( visitor ) ;
}
this . properties . forEach ( function ( prop ) {
prop . _walk ( visitor ) ;
} ) ;
} ) ;
} ,
} , AST _Scope ) ;
2015-10-27 00:40:46 +00:00
2015-11-21 09:17:32 +00:00
var AST _DefClass = DEFNODE ( "DefClass" , null , {
$documentation : "A class definition" ,
} , AST _Class ) ;
var AST _ClassExpression = DEFNODE ( "ClassExpression" , null , {
$documentation : "A class expression."
} , AST _Class ) ;
2016-09-06 23:00:07 +00:00
var AST _Symbol = DEFNODE ( "Symbol" , "scope name thedef default" , {
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)" ,
2016-09-06 23:00:07 +00:00
thedef : "[SymbolDef/S] the definition of this symbol" ,
default : "[AST_Expression] The default parameter value, only used when nested inside a binding pattern"
2012-10-09 13:25:45 +00:00
} ,
2012-09-03 09:05:10 +00:00
$documentation : "Base class for all symbols" ,
2016-09-06 23:00:07 +00:00
_walk : function ( visitor ) {
return visitor . _visit ( this , function ( ) {
if ( this . default ) this . default . _walk ( visitor ) ;
} ) ;
}
2012-05-27 14:25:31 +00:00
} ) ;
2015-11-21 14:48:23 +00:00
var AST _NewTarget = DEFNODE ( "NewTarget" , null , {
$documentation : "A reference to new.target"
} ) ;
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 ) ;
2016-09-06 23:00:07 +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 : {
2016-09-06 23:00:07 +00:00
init : "[AST_Node*/S] array of initializers for this declaration."
2015-11-22 19:00:54 +00:00
} ,
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 ) ;
2016-02-28 14:06:51 +00:00
var AST _SymbolBlockDeclaration = DEFNODE ( "SymbolBlockDeclaration" , null , {
$documentation : "Base class for block-scoped declaration symbols"
} , AST _SymbolDeclaration ) ;
2012-10-02 09:22:39 +00:00
var AST _SymbolConst = DEFNODE ( "SymbolConst" , null , {
$documentation : "A constant declaration"
2016-02-28 14:06:51 +00:00
} , AST _SymbolBlockDeclaration ) ;
var AST _SymbolLet = DEFNODE ( "SymbolLet" , null , {
$documentation : "A block-scoped `let` declaration"
} , AST _SymbolBlockDeclaration ) ;
2012-05-27 14:25:31 +00:00
2015-11-22 19:00:54 +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 ) ;
2015-10-26 22:14:55 +00:00
var AST _SymbolMethod = DEFNODE ( "SymbolMethod" , null , {
$documentation : "Symbol in an object defining a method" ,
} , AST _Symbol ) ;
2012-08-19 12:57:50 +00:00
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 ) ;
2015-11-21 09:17:32 +00:00
var AST _SymbolDefClass = DEFNODE ( "SymbolDefClass" , null , {
$documentation : "Symbol naming a class's name in a class declaration. Lexically scoped to its containing scope, and accessible within the class."
2016-02-28 14:06:51 +00:00
} , AST _SymbolBlockDeclaration ) ;
2015-11-21 09:17:32 +00:00
var AST _SymbolClass = DEFNODE ( "SymbolClass" , null , {
2015-10-27 00:40:46 +00:00
$documentation : "Symbol naming a class's name. Lexically scoped to the class."
} , AST _SymbolDeclaration ) ;
2012-08-19 12:57:50 +00:00
var AST _SymbolCatch = DEFNODE ( "SymbolCatch" , null , {
2012-09-03 09:05:10 +00:00
$documentation : "Symbol naming the exception in catch" ,
2016-02-28 14:06:51 +00:00
} , AST _SymbolBlockDeclaration ) ;
2012-05-27 11:09:01 +00:00
2016-02-21 17:06:09 +00:00
var AST _SymbolImport = DEFNODE ( "SymbolImport" , null , {
$documentation : "Symbol refering to an imported name" ,
2016-02-28 14:06:51 +00:00
} , AST _SymbolBlockDeclaration ) ;
2016-02-21 17:06:09 +00:00
2016-02-26 21:12:19 +00:00
var AST _SymbolImportForeign = DEFNODE ( "SymbolImportForeign" , null , {
$documentation : "A symbol imported from a module, but it is defined in the other module, and its real name is irrelevant for this module's purposes" ,
} , AST _Symbol ) ;
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 ) ;
2015-08-07 01:44:53 +00:00
var AST _Super = DEFNODE ( "Super" , null , {
$documentation : "The `super` symbol" ,
} , 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
2015-10-07 17:10:53 +00:00
var AST _Number = DEFNODE ( "Number" , "value literal" , {
2012-09-03 09:05:10 +00:00
$documentation : "A number literal" ,
2012-10-09 13:25:45 +00:00
$propdoc : {
2015-10-07 17:10:53 +00:00
value : "[number] the numeric value" ,
literal : "[string] numeric value as string (optional)"
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
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
2016-05-26 15:00:37 +00:00
/* -----[ Yield ]----- */
var AST _Yield = DEFNODE ( "Yield" , "expression is_star" , {
$documentation : "A `yield` statement" ,
$propdoc : {
expression : "[AST_Node?] the value returned or thrown by this statement; could be null (representing undefined) but only when is_star is set to false" ,
is _star : "[Boolean] Whether this is a yield or yield* statement"
} ,
_walk : function ( visitor ) {
return visitor . _visit ( this , this . expression && function ( ) {
this . expression . _walk ( visitor ) ;
} ) ;
}
} ) ;
2012-08-19 12:57:50 +00:00
/* -----[ TreeWalker ]----- */
function TreeWalker ( callback ) {
this . visit = callback ;
this . stack = [ ] ;
2015-11-11 20:15:25 +00:00
this . directives = Object . create ( null ) ;
2012-08-19 12:57:50 +00:00
} ;
TreeWalker . prototype = {
_visit : function ( node , descend ) {
2015-11-11 20:15:25 +00:00
this . 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 ) ;
}
2015-11-11 20:15:25 +00:00
this . pop ( node ) ;
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 ) {
2015-11-11 20:15:25 +00:00
if ( node instanceof AST _Lambda ) {
this . directives = Object . create ( this . directives ) ;
} else if ( node instanceof AST _Directive ) {
this . directives [ node . value ] = this . directives [ node . value ] ? "up" : true ;
2016-09-11 13:06:10 +00:00
} else if ( node instanceof AST _Class ) {
this . directives = Object . create ( this . directives ) ;
this . directives [ "use strict" ] = this . directives [ "use strict" ] ? "up" : true ;
2015-11-11 20:15:25 +00:00
}
2012-09-26 09:16:16 +00:00
this . stack . push ( node ) ;
} ,
2015-11-11 20:15:25 +00:00
pop : function ( node ) {
this . stack . pop ( ) ;
2016-09-11 13:06:10 +00:00
if ( node instanceof AST _Lambda || node instanceof AST _Class ) {
2015-11-11 20:15:25 +00:00
this . directives = Object . getPrototypeOf ( this . directives ) ;
}
2012-09-26 09:16:16 +00:00
} ,
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 ) {
2015-11-11 20:15:25 +00:00
var dir = this . directives [ type ] ;
if ( dir ) return dir ;
var node = this . stack [ this . stack . length - 1 ] ;
2015-12-26 16:55:38 +00:00
if ( node instanceof AST _Scope && node . body ) {
2015-11-11 20:15:25 +00:00
for ( var i = 0 ; i < node . body . length ; ++ i ) {
var st = node . body [ i ] ;
if ( ! ( st instanceof AST _Directive ) ) break ;
if ( st . value == type ) return true ;
}
}
2013-06-07 09:51:23 +00:00
} ,
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
} ;