1/***********************************************************************
2
3  A JavaScript tokenizer / parser / beautifier / compressor.
4  https://github.com/mishoo/UglifyJS
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
46function TreeTransformer(before, after) {
47    TreeWalker.call(this);
48    this.before = before;
49    this.after = after;
50}
51TreeTransformer.prototype = new TreeWalker;
52
53(function(DEF) {
54    function do_list(list, tw) {
55        return List(list, function(node) {
56            return node.transform(tw, true);
57        });
58    }
59
60    DEF(AST_Node, noop);
61    DEF(AST_LabeledStatement, function(self, tw) {
62        self.label = self.label.transform(tw);
63        self.body = self.body.transform(tw);
64    });
65    DEF(AST_SimpleStatement, function(self, tw) {
66        self.body = self.body.transform(tw);
67    });
68    DEF(AST_Block, function(self, tw) {
69        self.body = do_list(self.body, tw);
70    });
71    DEF(AST_Do, function(self, tw) {
72        self.body = self.body.transform(tw);
73        self.condition = self.condition.transform(tw);
74    });
75    DEF(AST_While, function(self, tw) {
76        self.condition = self.condition.transform(tw);
77        self.body = self.body.transform(tw);
78    });
79    DEF(AST_For, function(self, tw) {
80        if (self.init) self.init = self.init.transform(tw);
81        if (self.condition) self.condition = self.condition.transform(tw);
82        if (self.step) self.step = self.step.transform(tw);
83        self.body = self.body.transform(tw);
84    });
85    DEF(AST_ForEnumeration, function(self, tw) {
86        self.init = self.init.transform(tw);
87        self.object = self.object.transform(tw);
88        self.body = self.body.transform(tw);
89    });
90    DEF(AST_With, function(self, tw) {
91        self.expression = self.expression.transform(tw);
92        self.body = self.body.transform(tw);
93    });
94    DEF(AST_Exit, function(self, tw) {
95        if (self.value) self.value = self.value.transform(tw);
96    });
97    DEF(AST_LoopControl, function(self, tw) {
98        if (self.label) self.label = self.label.transform(tw);
99    });
100    DEF(AST_If, function(self, tw) {
101        self.condition = self.condition.transform(tw);
102        self.body = self.body.transform(tw);
103        if (self.alternative) self.alternative = self.alternative.transform(tw);
104    });
105    DEF(AST_Switch, function(self, tw) {
106        self.expression = self.expression.transform(tw);
107        self.body = do_list(self.body, tw);
108    });
109    DEF(AST_Case, function(self, tw) {
110        self.expression = self.expression.transform(tw);
111        self.body = do_list(self.body, tw);
112    });
113    DEF(AST_Try, function(self, tw) {
114        self.body = do_list(self.body, tw);
115        if (self.bcatch) self.bcatch = self.bcatch.transform(tw);
116        if (self.bfinally) self.bfinally = self.bfinally.transform(tw);
117    });
118    DEF(AST_Catch, function(self, tw) {
119        if (self.argname) self.argname = self.argname.transform(tw);
120        self.body = do_list(self.body, tw);
121    });
122    DEF(AST_Definitions, function(self, tw) {
123        self.definitions = do_list(self.definitions, tw);
124    });
125    DEF(AST_VarDef, function(self, tw) {
126        self.name = self.name.transform(tw);
127        if (self.value) self.value = self.value.transform(tw);
128    });
129    DEF(AST_DefaultValue, function(self, tw) {
130        self.name = self.name.transform(tw);
131        self.value = self.value.transform(tw);
132    });
133    DEF(AST_Lambda, function(self, tw) {
134        if (self.name) self.name = self.name.transform(tw);
135        self.argnames = do_list(self.argnames, tw);
136        if (self.rest) self.rest = self.rest.transform(tw);
137        self.body = do_list(self.body, tw);
138    });
139    function transform_arrow(self, tw) {
140        self.argnames = do_list(self.argnames, tw);
141        if (self.rest) self.rest = self.rest.transform(tw);
142        if (self.value) {
143            self.value = self.value.transform(tw);
144        } else {
145            self.body = do_list(self.body, tw);
146        }
147    }
148    DEF(AST_Arrow, transform_arrow);
149    DEF(AST_AsyncArrow, transform_arrow);
150    DEF(AST_Class, function(self, tw) {
151        if (self.name) self.name = self.name.transform(tw);
152        if (self.extends) self.extends = self.extends.transform(tw);
153        self.properties = do_list(self.properties, tw);
154    });
155    DEF(AST_ClassProperty, function(self, tw) {
156        if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
157        if (self.value) self.value = self.value.transform(tw);
158    });
159    DEF(AST_Call, function(self, tw) {
160        self.expression = self.expression.transform(tw);
161        self.args = do_list(self.args, tw);
162    });
163    DEF(AST_Sequence, function(self, tw) {
164        self.expressions = do_list(self.expressions, tw);
165    });
166    DEF(AST_Await, function(self, tw) {
167        self.expression = self.expression.transform(tw);
168    });
169    DEF(AST_Yield, function(self, tw) {
170        if (self.expression) self.expression = self.expression.transform(tw);
171    });
172    DEF(AST_Dot, function(self, tw) {
173        self.expression = self.expression.transform(tw);
174    });
175    DEF(AST_Sub, function(self, tw) {
176        self.expression = self.expression.transform(tw);
177        self.property = self.property.transform(tw);
178    });
179    DEF(AST_Spread, function(self, tw) {
180        self.expression = self.expression.transform(tw);
181    });
182    DEF(AST_Unary, function(self, tw) {
183        self.expression = self.expression.transform(tw);
184    });
185    DEF(AST_Binary, function(self, tw) {
186        self.left = self.left.transform(tw);
187        self.right = self.right.transform(tw);
188    });
189    DEF(AST_Conditional, function(self, tw) {
190        self.condition = self.condition.transform(tw);
191        self.consequent = self.consequent.transform(tw);
192        self.alternative = self.alternative.transform(tw);
193    });
194    DEF(AST_Array, function(self, tw) {
195        self.elements = do_list(self.elements, tw);
196    });
197    DEF(AST_DestructuredArray, function(self, tw) {
198        self.elements = do_list(self.elements, tw);
199        if (self.rest) self.rest = self.rest.transform(tw);
200    });
201    DEF(AST_DestructuredKeyVal, function(self, tw) {
202        if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
203        self.value = self.value.transform(tw);
204    });
205    DEF(AST_DestructuredObject, function(self, tw) {
206        self.properties = do_list(self.properties, tw);
207        if (self.rest) self.rest = self.rest.transform(tw);
208    });
209    DEF(AST_Object, function(self, tw) {
210        self.properties = do_list(self.properties, tw);
211    });
212    DEF(AST_ObjectProperty, function(self, tw) {
213        if (self.key instanceof AST_Node) self.key = self.key.transform(tw);
214        self.value = self.value.transform(tw);
215    });
216    DEF(AST_ExportDeclaration, function(self, tw) {
217        self.body = self.body.transform(tw);
218    });
219    DEF(AST_ExportDefault, function(self, tw) {
220        self.body = self.body.transform(tw);
221    });
222    DEF(AST_ExportReferences, function(self, tw) {
223        self.properties = do_list(self.properties, tw);
224    });
225    DEF(AST_Import, function(self, tw) {
226        if (self.all) self.all = self.all.transform(tw);
227        if (self.default) self.default = self.default.transform(tw);
228        if (self.properties) self.properties = do_list(self.properties, tw);
229    });
230    DEF(AST_Template, function(self, tw) {
231        if (self.tag) self.tag = self.tag.transform(tw);
232        self.expressions = do_list(self.expressions, tw);
233    });
234})(function(node, descend) {
235    node.DEFMETHOD("transform", function(tw, in_list) {
236        var x, y;
237        tw.push(this);
238        if (tw.before) x = tw.before(this, descend, in_list);
239        if (typeof x === "undefined") {
240            x = this;
241            descend(x, tw);
242            if (tw.after) {
243                y = tw.after(x, in_list);
244                if (typeof y !== "undefined") x = y;
245            }
246        }
247        tw.pop();
248        return x;
249    });
250});
251