Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(288)

Side by Side Diff: node_modules/vulcanize/node_modules/uglify-js/lib/ast.js

Issue 800513006: Added vulcanize under third_party/npm_modules (Closed) Base URL: https://chromium.googlesource.com/infra/third_party/npm_modules.git@master
Patch Set: Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 /***********************************************************************
2
3 A JavaScript tokenizer / parser / beautifier / compressor.
4 https://github.com/mishoo/UglifyJS2
5
6 -------------------------------- (C) ---------------------------------
7
8 Author: Mihai Bazon
9 <mihai.bazon@gmail.com>
10 http://mihai.bazon.net/blog
11
12 Distributed under the BSD license:
13
14 Copyright 2012 (c) Mihai Bazon <mihai.bazon@gmail.com>
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 * Redistributions of source code must retain the above
21 copyright notice, this list of conditions and the following
22 disclaimer.
23
24 * Redistributions in binary form must reproduce the above
25 copyright notice, this list of conditions and the following
26 disclaimer in the documentation and/or other materials
27 provided with the distribution.
28
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “AS IS” AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
33 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
34 OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
36 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
38 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
39 THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 SUCH DAMAGE.
41
42 ***********************************************************************/
43
44 "use strict";
45
46 function DEFNODE(type, props, methods, base) {
47 if (arguments.length < 4) base = AST_Node;
48 if (!props) props = [];
49 else props = props.split(/\s+/);
50 var self_props = props;
51 if (base && base.PROPS)
52 props = props.concat(base.PROPS);
53 var code = "return function AST_" + type + "(props){ if (props) { ";
54 for (var i = props.length; --i >= 0;) {
55 code += "this." + props[i] + " = props." + props[i] + ";";
56 }
57 var proto = base && new base;
58 if (proto && proto.initialize || (methods && methods.initialize))
59 code += "this.initialize();";
60 code += "}}";
61 var ctor = new Function(code)();
62 if (proto) {
63 ctor.prototype = proto;
64 ctor.BASE = base;
65 }
66 if (base) base.SUBCLASSES.push(ctor);
67 ctor.prototype.CTOR = ctor;
68 ctor.PROPS = props || null;
69 ctor.SELF_PROPS = self_props;
70 ctor.SUBCLASSES = [];
71 if (type) {
72 ctor.prototype.TYPE = ctor.TYPE = type;
73 }
74 if (methods) for (i in methods) if (methods.hasOwnProperty(i)) {
75 if (/^\$/.test(i)) {
76 ctor[i.substr(1)] = methods[i];
77 } else {
78 ctor.prototype[i] = methods[i];
79 }
80 }
81 ctor.DEFMETHOD = function(name, method) {
82 this.prototype[name] = method;
83 };
84 return ctor;
85 };
86
87 var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_be fore file", {
88 }, null);
89
90 var AST_Node = DEFNODE("Node", "start end", {
91 clone: function() {
92 return new this.CTOR(this);
93 },
94 $documentation: "Base class of all AST nodes",
95 $propdoc: {
96 start: "[AST_Token] The first token of this node",
97 end: "[AST_Token] The last token of this node"
98 },
99 _walk: function(visitor) {
100 return visitor._visit(this);
101 },
102 walk: function(visitor) {
103 return this._walk(visitor); // not sure the indirection will be any help
104 }
105 }, null);
106
107 AST_Node.warn_function = null;
108 AST_Node.warn = function(txt, props) {
109 if (AST_Node.warn_function)
110 AST_Node.warn_function(string_template(txt, props));
111 };
112
113 /* -----[ statements ]----- */
114
115 var AST_Statement = DEFNODE("Statement", null, {
116 $documentation: "Base class of all statements",
117 });
118
119 var AST_Debugger = DEFNODE("Debugger", null, {
120 $documentation: "Represents a debugger statement",
121 }, AST_Statement);
122
123 var AST_Directive = DEFNODE("Directive", "value scope", {
124 $documentation: "Represents a directive, like \"use strict\";",
125 $propdoc: {
126 value: "[string] The value of this directive as a plain string (it's not an AST_String!)",
127 scope: "[AST_Scope/S] The scope that this directive affects"
128 },
129 }, AST_Statement);
130
131 var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
132 $documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
133 $propdoc: {
134 body: "[AST_Node] an expression node (should not be instanceof AST_State ment)"
135 },
136 _walk: function(visitor) {
137 return visitor._visit(this, function(){
138 this.body._walk(visitor);
139 });
140 }
141 }, AST_Statement);
142
143 function walk_body(node, visitor) {
144 if (node.body instanceof AST_Statement) {
145 node.body._walk(visitor);
146 }
147 else node.body.forEach(function(stat){
148 stat._walk(visitor);
149 });
150 };
151
152 var AST_Block = DEFNODE("Block", "body", {
153 $documentation: "A body of statements (usually bracketed)",
154 $propdoc: {
155 body: "[AST_Statement*] an array of statements"
156 },
157 _walk: function(visitor) {
158 return visitor._visit(this, function(){
159 walk_body(this, visitor);
160 });
161 }
162 }, AST_Statement);
163
164 var AST_BlockStatement = DEFNODE("BlockStatement", null, {
165 $documentation: "A block statement",
166 }, AST_Block);
167
168 var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
169 $documentation: "The empty statement (empty block or simply a semicolon)",
170 _walk: function(visitor) {
171 return visitor._visit(this);
172 }
173 }, AST_Statement);
174
175 var AST_StatementWithBody = DEFNODE("StatementWithBody", "body", {
176 $documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`",
177 $propdoc: {
178 body: "[AST_Statement] the body; this should always be present, even if it's an AST_EmptyStatement"
179 },
180 _walk: function(visitor) {
181 return visitor._visit(this, function(){
182 this.body._walk(visitor);
183 });
184 }
185 }, AST_Statement);
186
187 var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
188 $documentation: "Statement with a label",
189 $propdoc: {
190 label: "[AST_Label] a label definition"
191 },
192 _walk: function(visitor) {
193 return visitor._visit(this, function(){
194 this.label._walk(visitor);
195 this.body._walk(visitor);
196 });
197 }
198 }, AST_StatementWithBody);
199
200 var AST_IterationStatement = DEFNODE("IterationStatement", null, {
201 $documentation: "Internal class. All loops inherit from it."
202 }, AST_StatementWithBody);
203
204 var AST_DWLoop = DEFNODE("DWLoop", "condition", {
205 $documentation: "Base class for do/while statements",
206 $propdoc: {
207 condition: "[AST_Node] the loop condition. Should not be instanceof AST _Statement"
208 },
209 _walk: function(visitor) {
210 return visitor._visit(this, function(){
211 this.condition._walk(visitor);
212 this.body._walk(visitor);
213 });
214 }
215 }, AST_IterationStatement);
216
217 var AST_Do = DEFNODE("Do", null, {
218 $documentation: "A `do` statement",
219 }, AST_DWLoop);
220
221 var AST_While = DEFNODE("While", null, {
222 $documentation: "A `while` statement",
223 }, AST_DWLoop);
224
225 var AST_For = DEFNODE("For", "init condition step", {
226 $documentation: "A `for` statement",
227 $propdoc: {
228 init: "[AST_Node?] the `for` initialization code, or null if empty",
229 condition: "[AST_Node?] the `for` termination clause, or null if empty",
230 step: "[AST_Node?] the `for` update clause, or null if empty"
231 },
232 _walk: function(visitor) {
233 return visitor._visit(this, function(){
234 if (this.init) this.init._walk(visitor);
235 if (this.condition) this.condition._walk(visitor);
236 if (this.step) this.step._walk(visitor);
237 this.body._walk(visitor);
238 });
239 }
240 }, AST_IterationStatement);
241
242 var AST_ForIn = DEFNODE("ForIn", "init name object", {
243 $documentation: "A `for ... in` statement",
244 $propdoc: {
245 init: "[AST_Node] the `for/in` initialization code",
246 name: "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
247 object: "[AST_Node] the object that we're looping through"
248 },
249 _walk: function(visitor) {
250 return visitor._visit(this, function(){
251 this.init._walk(visitor);
252 this.object._walk(visitor);
253 this.body._walk(visitor);
254 });
255 }
256 }, AST_IterationStatement);
257
258 var AST_With = DEFNODE("With", "expression", {
259 $documentation: "A `with` statement",
260 $propdoc: {
261 expression: "[AST_Node] the `with` expression"
262 },
263 _walk: function(visitor) {
264 return visitor._visit(this, function(){
265 this.expression._walk(visitor);
266 this.body._walk(visitor);
267 });
268 }
269 }, AST_StatementWithBody);
270
271 /* -----[ scope and functions ]----- */
272
273 var AST_Scope = DEFNODE("Scope", "directives variables functions uses_with uses_ eval parent_scope enclosed cname", {
274 $documentation: "Base class for all statements introducing a lexical scope",
275 $propdoc: {
276 directives: "[string*/S] an array of directives declared in this scope",
277 variables: "[Object/S] a map of name -> SymbolDef for all variables/func tions defined in this scope",
278 functions: "[Object/S] like `variables`, but only lists function declara tions",
279 uses_with: "[boolean/S] tells whether this scope uses the `with` stateme nt",
280 uses_eval: "[boolean/S] tells whether this scope contains a direct call to the global `eval`",
281 parent_scope: "[AST_Scope?/S] link to the parent scope",
282 enclosed: "[SymbolDef*/S] a list of all symbol definitions that are acce ssed from this scope or any subscopes",
283 cname: "[integer/S] current index for mangling variables (used internall y by the mangler)",
284 },
285 }, AST_Block);
286
287 var AST_Toplevel = DEFNODE("Toplevel", "globals", {
288 $documentation: "The toplevel scope",
289 $propdoc: {
290 globals: "[Object/S] a map of name -> SymbolDef for all undeclared names ",
291 },
292 wrap_enclose: function(arg_parameter_pairs) {
293 var self = this;
294 var args = [];
295 var parameters = [];
296
297 arg_parameter_pairs.forEach(function(pair) {
298 var splitAt = pair.lastIndexOf(":");
299
300 args.push(pair.substr(0, splitAt));
301 parameters.push(pair.substr(splitAt + 1));
302 });
303
304 var wrapped_tl = "(function(" + parameters.join(",") + "){ '$ORIG'; })(" + args.join(",") + ")";
305 wrapped_tl = parse(wrapped_tl);
306 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(no de){
307 if (node instanceof AST_Directive && node.value == "$ORIG") {
308 return MAP.splice(self.body);
309 }
310 }));
311 return wrapped_tl;
312 },
313 wrap_commonjs: function(name, export_all) {
314 var self = this;
315 var to_export = [];
316 if (export_all) {
317 self.figure_out_scope();
318 self.walk(new TreeWalker(function(node){
319 if (node instanceof AST_SymbolDeclaration && node.definition().g lobal) {
320 if (!find_if(function(n){ return n.name == node.name }, to_e xport))
321 to_export.push(node);
322 }
323 }));
324 }
325 var wrapped_tl = "(function(exports, global){ global['" + name + "'] = e xports; '$ORIG'; '$EXPORTS'; }({}, (function(){return this}())))";
326 wrapped_tl = parse(wrapped_tl);
327 wrapped_tl = wrapped_tl.transform(new TreeTransformer(function before(no de){
328 if (node instanceof AST_SimpleStatement) {
329 node = node.body;
330 if (node instanceof AST_String) switch (node.getValue()) {
331 case "$ORIG":
332 return MAP.splice(self.body);
333 case "$EXPORTS":
334 var body = [];
335 to_export.forEach(function(sym){
336 body.push(new AST_SimpleStatement({
337 body: new AST_Assign({
338 left: new AST_Sub({
339 expression: new AST_SymbolRef({ name: "expor ts" }),
340 property: new AST_String({ value: sym.name } ),
341 }),
342 operator: "=",
343 right: new AST_SymbolRef(sym),
344 }),
345 }));
346 });
347 return MAP.splice(body);
348 }
349 }
350 }));
351 return wrapped_tl;
352 }
353 }, AST_Scope);
354
355 var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
356 $documentation: "Base class for functions",
357 $propdoc: {
358 name: "[AST_SymbolDeclaration?] the name of this function",
359 argnames: "[AST_SymbolFunarg*] array of function arguments",
360 uses_arguments: "[boolean/S] tells whether this function accesses the ar guments array"
361 },
362 _walk: function(visitor) {
363 return visitor._visit(this, function(){
364 if (this.name) this.name._walk(visitor);
365 this.argnames.forEach(function(arg){
366 arg._walk(visitor);
367 });
368 walk_body(this, visitor);
369 });
370 }
371 }, AST_Scope);
372
373 var AST_Accessor = DEFNODE("Accessor", null, {
374 $documentation: "A setter/getter function. The `name` property is always nu ll."
375 }, AST_Lambda);
376
377 var AST_Function = DEFNODE("Function", null, {
378 $documentation: "A function expression"
379 }, AST_Lambda);
380
381 var AST_Defun = DEFNODE("Defun", null, {
382 $documentation: "A function definition"
383 }, AST_Lambda);
384
385 /* -----[ JUMPS ]----- */
386
387 var AST_Jump = DEFNODE("Jump", null, {
388 $documentation: "Base class for “jumps” (for now that's `return`, `throw`, ` break` and `continue`)"
389 }, AST_Statement);
390
391 var AST_Exit = DEFNODE("Exit", "value", {
392 $documentation: "Base class for “exits” (`return` and `throw`)",
393 $propdoc: {
394 value: "[AST_Node?] the value returned or thrown by this statement; coul d be null for AST_Return"
395 },
396 _walk: function(visitor) {
397 return visitor._visit(this, this.value && function(){
398 this.value._walk(visitor);
399 });
400 }
401 }, AST_Jump);
402
403 var AST_Return = DEFNODE("Return", null, {
404 $documentation: "A `return` statement"
405 }, AST_Exit);
406
407 var AST_Throw = DEFNODE("Throw", null, {
408 $documentation: "A `throw` statement"
409 }, AST_Exit);
410
411 var AST_LoopControl = DEFNODE("LoopControl", "label", {
412 $documentation: "Base class for loop control statements (`break` and `contin ue`)",
413 $propdoc: {
414 label: "[AST_LabelRef?] the label, or null if none",
415 },
416 _walk: function(visitor) {
417 return visitor._visit(this, this.label && function(){
418 this.label._walk(visitor);
419 });
420 }
421 }, AST_Jump);
422
423 var AST_Break = DEFNODE("Break", null, {
424 $documentation: "A `break` statement"
425 }, AST_LoopControl);
426
427 var AST_Continue = DEFNODE("Continue", null, {
428 $documentation: "A `continue` statement"
429 }, AST_LoopControl);
430
431 /* -----[ IF ]----- */
432
433 var AST_If = DEFNODE("If", "condition alternative", {
434 $documentation: "A `if` statement",
435 $propdoc: {
436 condition: "[AST_Node] the `if` condition",
437 alternative: "[AST_Statement?] the `else` part, or null if not present"
438 },
439 _walk: function(visitor) {
440 return visitor._visit(this, function(){
441 this.condition._walk(visitor);
442 this.body._walk(visitor);
443 if (this.alternative) this.alternative._walk(visitor);
444 });
445 }
446 }, AST_StatementWithBody);
447
448 /* -----[ SWITCH ]----- */
449
450 var AST_Switch = DEFNODE("Switch", "expression", {
451 $documentation: "A `switch` statement",
452 $propdoc: {
453 expression: "[AST_Node] the `switch` “discriminant”"
454 },
455 _walk: function(visitor) {
456 return visitor._visit(this, function(){
457 this.expression._walk(visitor);
458 walk_body(this, visitor);
459 });
460 }
461 }, AST_Block);
462
463 var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
464 $documentation: "Base class for `switch` branches",
465 }, AST_Block);
466
467 var AST_Default = DEFNODE("Default", null, {
468 $documentation: "A `default` switch branch",
469 }, AST_SwitchBranch);
470
471 var AST_Case = DEFNODE("Case", "expression", {
472 $documentation: "A `case` switch branch",
473 $propdoc: {
474 expression: "[AST_Node] the `case` expression"
475 },
476 _walk: function(visitor) {
477 return visitor._visit(this, function(){
478 this.expression._walk(visitor);
479 walk_body(this, visitor);
480 });
481 }
482 }, AST_SwitchBranch);
483
484 /* -----[ EXCEPTIONS ]----- */
485
486 var AST_Try = DEFNODE("Try", "bcatch bfinally", {
487 $documentation: "A `try` statement",
488 $propdoc: {
489 bcatch: "[AST_Catch?] the catch block, or null if not present",
490 bfinally: "[AST_Finally?] the finally block, or null if not present"
491 },
492 _walk: function(visitor) {
493 return visitor._visit(this, function(){
494 walk_body(this, visitor);
495 if (this.bcatch) this.bcatch._walk(visitor);
496 if (this.bfinally) this.bfinally._walk(visitor);
497 });
498 }
499 }, AST_Block);
500
501 var AST_Catch = DEFNODE("Catch", "argname", {
502 $documentation: "A `catch` node; only makes sense as part of a `try` stateme nt",
503 $propdoc: {
504 argname: "[AST_SymbolCatch] symbol for the exception"
505 },
506 _walk: function(visitor) {
507 return visitor._visit(this, function(){
508 this.argname._walk(visitor);
509 walk_body(this, visitor);
510 });
511 }
512 }, AST_Block);
513
514 var AST_Finally = DEFNODE("Finally", null, {
515 $documentation: "A `finally` node; only makes sense as part of a `try` state ment"
516 }, AST_Block);
517
518 /* -----[ VAR/CONST ]----- */
519
520 var AST_Definitions = DEFNODE("Definitions", "definitions", {
521 $documentation: "Base class for `var` or `const` nodes (variable declaration s/initializations)",
522 $propdoc: {
523 definitions: "[AST_VarDef*] array of variable definitions"
524 },
525 _walk: function(visitor) {
526 return visitor._visit(this, function(){
527 this.definitions.forEach(function(def){
528 def._walk(visitor);
529 });
530 });
531 }
532 }, AST_Statement);
533
534 var AST_Var = DEFNODE("Var", null, {
535 $documentation: "A `var` statement"
536 }, AST_Definitions);
537
538 var AST_Const = DEFNODE("Const", null, {
539 $documentation: "A `const` statement"
540 }, AST_Definitions);
541
542 var AST_VarDef = DEFNODE("VarDef", "name value", {
543 $documentation: "A variable declaration; only appears in a AST_Definitions n ode",
544 $propdoc: {
545 name: "[AST_SymbolVar|AST_SymbolConst] name of the variable",
546 value: "[AST_Node?] initializer, or null of there's no initializer"
547 },
548 _walk: function(visitor) {
549 return visitor._visit(this, function(){
550 this.name._walk(visitor);
551 if (this.value) this.value._walk(visitor);
552 });
553 }
554 });
555
556 /* -----[ OTHER ]----- */
557
558 var AST_Call = DEFNODE("Call", "expression args", {
559 $documentation: "A function call expression",
560 $propdoc: {
561 expression: "[AST_Node] expression to invoke as function",
562 args: "[AST_Node*] array of arguments"
563 },
564 _walk: function(visitor) {
565 return visitor._visit(this, function(){
566 this.expression._walk(visitor);
567 this.args.forEach(function(arg){
568 arg._walk(visitor);
569 });
570 });
571 }
572 });
573
574 var AST_New = DEFNODE("New", null, {
575 $documentation: "An object instantiation. Derives from a function call sinc e it has exactly the same properties"
576 }, AST_Call);
577
578 var AST_Seq = DEFNODE("Seq", "car cdr", {
579 $documentation: "A sequence expression (two comma-separated expressions)",
580 $propdoc: {
581 car: "[AST_Node] first element in sequence",
582 cdr: "[AST_Node] second element in sequence"
583 },
584 $cons: function(x, y) {
585 var seq = new AST_Seq(x);
586 seq.car = x;
587 seq.cdr = y;
588 return seq;
589 },
590 $from_array: function(array) {
591 if (array.length == 0) return null;
592 if (array.length == 1) return array[0].clone();
593 var list = null;
594 for (var i = array.length; --i >= 0;) {
595 list = AST_Seq.cons(array[i], list);
596 }
597 var p = list;
598 while (p) {
599 if (p.cdr && !p.cdr.cdr) {
600 p.cdr = p.cdr.car;
601 break;
602 }
603 p = p.cdr;
604 }
605 return list;
606 },
607 to_array: function() {
608 var p = this, a = [];
609 while (p) {
610 a.push(p.car);
611 if (p.cdr && !(p.cdr instanceof AST_Seq)) {
612 a.push(p.cdr);
613 break;
614 }
615 p = p.cdr;
616 }
617 return a;
618 },
619 add: function(node) {
620 var p = this;
621 while (p) {
622 if (!(p.cdr instanceof AST_Seq)) {
623 var cell = AST_Seq.cons(p.cdr, node);
624 return p.cdr = cell;
625 }
626 p = p.cdr;
627 }
628 },
629 _walk: function(visitor) {
630 return visitor._visit(this, function(){
631 this.car._walk(visitor);
632 if (this.cdr) this.cdr._walk(visitor);
633 });
634 }
635 });
636
637 var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
638 $documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`",
639 $propdoc: {
640 expression: "[AST_Node] the “container” expression",
641 property: "[AST_Node|string] the property to access. For AST_Dot this i s always a plain string, while for AST_Sub it's an arbitrary AST_Node"
642 }
643 });
644
645 var AST_Dot = DEFNODE("Dot", null, {
646 $documentation: "A dotted property access expression",
647 _walk: function(visitor) {
648 return visitor._visit(this, function(){
649 this.expression._walk(visitor);
650 });
651 }
652 }, AST_PropAccess);
653
654 var AST_Sub = DEFNODE("Sub", null, {
655 $documentation: "Index-style property access, i.e. `a[\"foo\"]`",
656 _walk: function(visitor) {
657 return visitor._visit(this, function(){
658 this.expression._walk(visitor);
659 this.property._walk(visitor);
660 });
661 }
662 }, AST_PropAccess);
663
664 var AST_Unary = DEFNODE("Unary", "operator expression", {
665 $documentation: "Base class for unary expressions",
666 $propdoc: {
667 operator: "[string] the operator",
668 expression: "[AST_Node] expression that this unary operator applies to"
669 },
670 _walk: function(visitor) {
671 return visitor._visit(this, function(){
672 this.expression._walk(visitor);
673 });
674 }
675 });
676
677 var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
678 $documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
679 }, AST_Unary);
680
681 var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
682 $documentation: "Unary postfix expression, i.e. `i++`"
683 }, AST_Unary);
684
685 var AST_Binary = DEFNODE("Binary", "left operator right", {
686 $documentation: "Binary expression, i.e. `a + b`",
687 $propdoc: {
688 left: "[AST_Node] left-hand side expression",
689 operator: "[string] the operator",
690 right: "[AST_Node] right-hand side expression"
691 },
692 _walk: function(visitor) {
693 return visitor._visit(this, function(){
694 this.left._walk(visitor);
695 this.right._walk(visitor);
696 });
697 }
698 });
699
700 var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
701 $documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
702 $propdoc: {
703 condition: "[AST_Node]",
704 consequent: "[AST_Node]",
705 alternative: "[AST_Node]"
706 },
707 _walk: function(visitor) {
708 return visitor._visit(this, function(){
709 this.condition._walk(visitor);
710 this.consequent._walk(visitor);
711 this.alternative._walk(visitor);
712 });
713 }
714 });
715
716 var AST_Assign = DEFNODE("Assign", null, {
717 $documentation: "An assignment expression — `a = b + 5`",
718 }, AST_Binary);
719
720 /* -----[ LITERALS ]----- */
721
722 var AST_Array = DEFNODE("Array", "elements", {
723 $documentation: "An array literal",
724 $propdoc: {
725 elements: "[AST_Node*] array of elements"
726 },
727 _walk: function(visitor) {
728 return visitor._visit(this, function(){
729 this.elements.forEach(function(el){
730 el._walk(visitor);
731 });
732 });
733 }
734 });
735
736 var AST_Object = DEFNODE("Object", "properties", {
737 $documentation: "An object literal",
738 $propdoc: {
739 properties: "[AST_ObjectProperty*] array of properties"
740 },
741 _walk: function(visitor) {
742 return visitor._visit(this, function(){
743 this.properties.forEach(function(prop){
744 prop._walk(visitor);
745 });
746 });
747 }
748 });
749
750 var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
751 $documentation: "Base class for literal object properties",
752 $propdoc: {
753 key: "[string] the property name converted to a string for ObjectKeyVal. For setters and getters this is an arbitrary AST_Node.",
754 value: "[AST_Node] property value. For setters and getters this is an A ST_Function."
755 },
756 _walk: function(visitor) {
757 return visitor._visit(this, function(){
758 this.value._walk(visitor);
759 });
760 }
761 });
762
763 var AST_ObjectKeyVal = DEFNODE("ObjectKeyVal", null, {
764 $documentation: "A key: value object property",
765 }, AST_ObjectProperty);
766
767 var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
768 $documentation: "An object setter property",
769 }, AST_ObjectProperty);
770
771 var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
772 $documentation: "An object getter property",
773 }, AST_ObjectProperty);
774
775 var AST_Symbol = DEFNODE("Symbol", "scope name thedef", {
776 $propdoc: {
777 name: "[string] name of this symbol",
778 scope: "[AST_Scope/S] the current scope (not necessarily the definition scope)",
779 thedef: "[SymbolDef/S] the definition of this symbol"
780 },
781 $documentation: "Base class for all symbols",
782 });
783
784 var AST_SymbolAccessor = DEFNODE("SymbolAccessor", null, {
785 $documentation: "The name of a property accessor (setter/getter function)"
786 }, AST_Symbol);
787
788 var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "init", {
789 $documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
790 $propdoc: {
791 init: "[AST_Node*/S] array of initializers for this declaration."
792 }
793 }, AST_Symbol);
794
795 var AST_SymbolVar = DEFNODE("SymbolVar", null, {
796 $documentation: "Symbol defining a variable",
797 }, AST_SymbolDeclaration);
798
799 var AST_SymbolConst = DEFNODE("SymbolConst", null, {
800 $documentation: "A constant declaration"
801 }, AST_SymbolDeclaration);
802
803 var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
804 $documentation: "Symbol naming a function argument",
805 }, AST_SymbolVar);
806
807 var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
808 $documentation: "Symbol defining a function",
809 }, AST_SymbolDeclaration);
810
811 var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
812 $documentation: "Symbol naming a function expression",
813 }, AST_SymbolDeclaration);
814
815 var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
816 $documentation: "Symbol naming the exception in catch",
817 }, AST_SymbolDeclaration);
818
819 var AST_Label = DEFNODE("Label", "references", {
820 $documentation: "Symbol naming a label (declaration)",
821 $propdoc: {
822 references: "[AST_LoopControl*] a list of nodes referring to this label"
823 },
824 initialize: function() {
825 this.references = [];
826 this.thedef = this;
827 }
828 }, AST_Symbol);
829
830 var AST_SymbolRef = DEFNODE("SymbolRef", null, {
831 $documentation: "Reference to some symbol (not definition/declaration)",
832 }, AST_Symbol);
833
834 var AST_LabelRef = DEFNODE("LabelRef", null, {
835 $documentation: "Reference to a label symbol",
836 }, AST_Symbol);
837
838 var AST_This = DEFNODE("This", null, {
839 $documentation: "The `this` symbol",
840 }, AST_Symbol);
841
842 var AST_Constant = DEFNODE("Constant", null, {
843 $documentation: "Base class for all constants",
844 getValue: function() {
845 return this.value;
846 }
847 });
848
849 var AST_String = DEFNODE("String", "value", {
850 $documentation: "A string literal",
851 $propdoc: {
852 value: "[string] the contents of this string"
853 }
854 }, AST_Constant);
855
856 var AST_Number = DEFNODE("Number", "value", {
857 $documentation: "A number literal",
858 $propdoc: {
859 value: "[number] the numeric value"
860 }
861 }, AST_Constant);
862
863 var AST_RegExp = DEFNODE("RegExp", "value", {
864 $documentation: "A regexp literal",
865 $propdoc: {
866 value: "[RegExp] the actual regexp"
867 }
868 }, AST_Constant);
869
870 var AST_Atom = DEFNODE("Atom", null, {
871 $documentation: "Base class for atoms",
872 }, AST_Constant);
873
874 var AST_Null = DEFNODE("Null", null, {
875 $documentation: "The `null` atom",
876 value: null
877 }, AST_Atom);
878
879 var AST_NaN = DEFNODE("NaN", null, {
880 $documentation: "The impossible value",
881 value: 0/0
882 }, AST_Atom);
883
884 var AST_Undefined = DEFNODE("Undefined", null, {
885 $documentation: "The `undefined` value",
886 value: (function(){}())
887 }, AST_Atom);
888
889 var AST_Hole = DEFNODE("Hole", null, {
890 $documentation: "A hole in an array",
891 value: (function(){}())
892 }, AST_Atom);
893
894 var AST_Infinity = DEFNODE("Infinity", null, {
895 $documentation: "The `Infinity` value",
896 value: 1/0
897 }, AST_Atom);
898
899 var AST_Boolean = DEFNODE("Boolean", null, {
900 $documentation: "Base class for booleans",
901 }, AST_Atom);
902
903 var AST_False = DEFNODE("False", null, {
904 $documentation: "The `false` atom",
905 value: false
906 }, AST_Boolean);
907
908 var AST_True = DEFNODE("True", null, {
909 $documentation: "The `true` atom",
910 value: true
911 }, AST_Boolean);
912
913 /* -----[ TreeWalker ]----- */
914
915 function TreeWalker(callback) {
916 this.visit = callback;
917 this.stack = [];
918 };
919 TreeWalker.prototype = {
920 _visit: function(node, descend) {
921 this.stack.push(node);
922 var ret = this.visit(node, descend ? function(){
923 descend.call(node);
924 } : noop);
925 if (!ret && descend) {
926 descend.call(node);
927 }
928 this.stack.pop();
929 return ret;
930 },
931 parent: function(n) {
932 return this.stack[this.stack.length - 2 - (n || 0)];
933 },
934 push: function (node) {
935 this.stack.push(node);
936 },
937 pop: function() {
938 return this.stack.pop();
939 },
940 self: function() {
941 return this.stack[this.stack.length - 1];
942 },
943 find_parent: function(type) {
944 var stack = this.stack;
945 for (var i = stack.length; --i >= 0;) {
946 var x = stack[i];
947 if (x instanceof type) return x;
948 }
949 },
950 has_directive: function(type) {
951 return this.find_parent(AST_Scope).has_directive(type);
952 },
953 in_boolean_context: function() {
954 var stack = this.stack;
955 var i = stack.length, self = stack[--i];
956 while (i > 0) {
957 var p = stack[--i];
958 if ((p instanceof AST_If && p.condition === self) ||
959 (p instanceof AST_Conditional && p.condition === self) ||
960 (p instanceof AST_DWLoop && p.condition === self) ||
961 (p instanceof AST_For && p.condition === self) ||
962 (p instanceof AST_UnaryPrefix && p.operator == "!" && p.express ion === self))
963 {
964 return true;
965 }
966 if (!(p instanceof AST_Binary && (p.operator == "&&" || p.operator = = "||")))
967 return false;
968 self = p;
969 }
970 },
971 loopcontrol_target: function(label) {
972 var stack = this.stack;
973 if (label) for (var i = stack.length; --i >= 0;) {
974 var x = stack[i];
975 if (x instanceof AST_LabeledStatement && x.label.name == label.name) {
976 return x.body;
977 }
978 } else for (var i = stack.length; --i >= 0;) {
979 var x = stack[i];
980 if (x instanceof AST_Switch || x instanceof AST_IterationStatement)
981 return x;
982 }
983 }
984 };
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698