1 | /* |
2 | * This file is part of the KDE libraries |
3 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
4 | * Copyright (C) 2006 Apple Computer, Inc. |
5 | * |
6 | * This library is free software; you can redistribute it and/or |
7 | * modify it under the terms of the GNU Lesser General Public |
8 | * License as published by the Free Software Foundation; either |
9 | * version 2 of the License, or (at your option) any later version. |
10 | * |
11 | * This library is distributed in the hope that it will be useful, |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | * Lesser General Public License for more details. |
15 | * |
16 | * You should have received a copy of the GNU Lesser General Public |
17 | * License along with this library; if not, write to the Free Software |
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
19 | * |
20 | */ |
21 | |
22 | #ifndef MAKENODES_H |
23 | #define MAKENODES_H |
24 | |
25 | #include "nodes.h" |
26 | #include "identifier.h" |
27 | |
28 | #define OPTIMIZE_NODES |
29 | //#define TRACE_OPTIMIZER |
30 | |
31 | namespace KJS { |
32 | |
33 | // Shorthand wrappers for entering function contexts |
34 | static void inFuncExpr() { |
35 | parser().pushFunctionContext(FuncFl_Expr); |
36 | } |
37 | |
38 | static void inFuncDecl() { |
39 | parser().pushFunctionContext(FuncFl_Decl); |
40 | } |
41 | |
42 | |
43 | static Node* makeAssignNode(Node* loc, Operator op, Node* expr) |
44 | { |
45 | return new AssignNode(loc, op, expr); |
46 | } |
47 | |
48 | static Node* makeConditionalNode(Node* l, Node* e1, Node* e2) |
49 | { |
50 | return new ConditionalNode(l, e1, e2); |
51 | } |
52 | |
53 | static Node* makePrefixNode(Node *expr, Operator op) |
54 | { |
55 | return new PrefixNode(expr, op); |
56 | } |
57 | |
58 | static Node* makePostfixNode(Node* expr, Operator op) |
59 | { |
60 | return new PostfixNode(expr, op); |
61 | } |
62 | |
63 | static Node *makeFunctionCallNode(Node *func, ArgumentsNode *args) |
64 | { |
65 | Node *n = func->nodeInsideAllParens(); |
66 | |
67 | if (!n->isLocation()) |
68 | return new FunctionCallValueNode(func, args); |
69 | else |
70 | return new FunctionCallReferenceNode(func, args); |
71 | } |
72 | |
73 | static Node *makeTypeOfNode(Node *expr) |
74 | { |
75 | Node *n = expr->nodeInsideAllParens(); |
76 | |
77 | // We only need to use the special path for variable references, |
78 | // since they may throw a ResolveError on evaluate where we don't |
79 | // want that... |
80 | if (n->isVarAccessNode()) |
81 | return new TypeOfVarNode(static_cast<VarAccessNode*>(n)); |
82 | else |
83 | return new TypeOfValueNode(expr); |
84 | } |
85 | |
86 | static Node *makeDeleteNode(Node *expr) |
87 | { |
88 | Node *n = expr->nodeInsideAllParens(); |
89 | |
90 | if (!n->isLocation()) |
91 | return new DeleteValueNode(expr); |
92 | else |
93 | return new DeleteReferenceNode(static_cast<LocationNode*>(n));//### not 100% faithful listing? |
94 | } |
95 | |
96 | static bool makeGetterOrSetterPropertyNode(PropertyNode*& result, Identifier& getOrSet, Identifier& name, ParameterNode *params, FunctionBodyNode *body) |
97 | { |
98 | PropertyNode::Type type; |
99 | |
100 | if (getOrSet == "get" ) |
101 | type = PropertyNode::Getter; |
102 | else if (getOrSet == "set" ) |
103 | type = PropertyNode::Setter; |
104 | else |
105 | return false; |
106 | |
107 | result = new PropertyNode(new PropertyNameNode(name), |
108 | new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, body, params), type); |
109 | |
110 | return true; |
111 | } |
112 | |
113 | static Node* makeAddNode(Node* n1, Node* n2, Operator op) |
114 | { |
115 | #ifdef OPTIMIZE_NODES |
116 | if (n1->isNumber()) { |
117 | if (n2->isNumber()) { |
118 | #ifdef TRACE_OPTIMIZER |
119 | printf("Optimizing ADDNODE NUMBER NUMBER as NUMBER\n" ); |
120 | #endif |
121 | NumberNode* number1 = static_cast< NumberNode * >(n1); |
122 | NumberNode* number2 = static_cast< NumberNode * >(n2); |
123 | double d1 = number1->value(); |
124 | double d2 = number2->value(); |
125 | number1->setValue(op == OpPlus ? d1 + d2 : d1 - d2); |
126 | return number1; |
127 | } |
128 | #ifdef TRACE_OPTIMIZER |
129 | printf("could optimize as ADD NODE NUMBER\n" ); |
130 | #endif |
131 | } |
132 | if (n2->isNumber()) { |
133 | #ifdef TRACE_OPTIMIZER |
134 | printf("could optimize as ADD NODE NUMBER\n" ); |
135 | #endif |
136 | } |
137 | if (op == OpPlus && n1->isString() && n2->isString()) { |
138 | #ifdef TRACE_OPTIMIZER |
139 | printf("Optimizing ADDNODE STRING STRING as STRING\n" ); |
140 | #endif |
141 | StringNode* str1 = static_cast<StringNode*>(n1); |
142 | StringNode* str2 = static_cast<StringNode*>(n2); |
143 | str1->setValue(str1->value() + str2->value()); |
144 | return str1; |
145 | } |
146 | #endif |
147 | return new BinaryOperatorNode(n1, n2, op); |
148 | } |
149 | |
150 | static Node* makeMultNode(Node* n1, Node* n2, Operator op) |
151 | { |
152 | #ifdef OPTIMIZE_NODES |
153 | if (n1->isNumber()) { |
154 | if (n2->isNumber()) { |
155 | #ifdef TRACE_OPTIMIZER |
156 | printf("Optimizing MULTNODE NUMBER NUMBER as NUMBER\n" ); |
157 | #endif |
158 | NumberNode* number1 = static_cast< NumberNode * >(n1); |
159 | NumberNode* number2 = static_cast< NumberNode * >(n2); |
160 | double d1 = number1->value(); |
161 | double d2 = number2->value(); |
162 | double res; |
163 | if (op == OpMult) |
164 | res = d1 * d2; |
165 | else if (op == OpDiv) |
166 | res = d1 / d2; |
167 | else // OpMod |
168 | res = fmod(d1, d2); |
169 | number1->setValue(res); |
170 | return number1; |
171 | } |
172 | #ifdef TRACE_OPTIMIZER |
173 | printf("could optimize as MULT NODE NUMBER\n" ); |
174 | #endif |
175 | } |
176 | if (n2->isNumber()) { |
177 | #ifdef TRACE_OPTIMIZER |
178 | printf("could optimize as MULT NODE NUMBER\n" ); |
179 | #endif |
180 | } |
181 | #endif |
182 | return new BinaryOperatorNode(n1, n2, op); |
183 | } |
184 | |
185 | static Node* makeShiftNode(Node* n1, Node* n2, Operator op) |
186 | { |
187 | #ifdef OPTIMIZE_NODES |
188 | if (n1->isNumber() && n2->isNumber()) { |
189 | #ifdef TRACE_OPTIMIZER |
190 | printf("Optimizing MULTNODE NUMBER NUMBER as NUMBER\n" ); |
191 | #endif |
192 | NumberNode* number1 = static_cast< NumberNode * >(n1); |
193 | NumberNode* number2 = static_cast< NumberNode * >(n2); |
194 | double val = number1->value(); |
195 | uint32_t shiftAmount = toUInt32(number2->value()); |
196 | switch (op) { |
197 | case OpLShift: |
198 | // operator << |
199 | number1->setValue(toInt32(val) << (shiftAmount & 0x1f)); |
200 | break; |
201 | case OpRShift: |
202 | // operator >> |
203 | number1->setValue(toInt32(val) >> (shiftAmount & 0x1f)); |
204 | break; |
205 | case OpURShift: |
206 | // operator >>> |
207 | number1->setValue(toUInt32(val) >> (shiftAmount & 0x1f)); |
208 | break; |
209 | default: |
210 | assert(false); |
211 | break; |
212 | } |
213 | return number1; |
214 | } |
215 | #endif |
216 | return new BinaryOperatorNode(n1, n2, op); |
217 | } |
218 | |
219 | static Node* makeRelationalNode(Node* n1, Operator op, Node* n2) |
220 | { |
221 | return new BinaryOperatorNode(n1, n2, op); |
222 | } |
223 | |
224 | static Node* makeEqualNode(Node* n1, Operator op, Node* n2) |
225 | { |
226 | return new BinaryOperatorNode(n1, n2, op); |
227 | } |
228 | |
229 | static Node* makeBitOperNode(Node* n1, Operator op, Node* n2) |
230 | { |
231 | return new BinaryOperatorNode(n1, n2, op); |
232 | } |
233 | |
234 | static Node* makeBinaryLogicalNode(Node* n1, Operator op, Node* n2) |
235 | { |
236 | return new BinaryLogicalNode(n1, op, n2); |
237 | } |
238 | |
239 | static Node* makeUnaryPlusNode(Node *n) |
240 | { |
241 | #ifdef OPTIMIZE_NODES |
242 | if (n->isNumber()) { |
243 | #ifdef TRACE_OPTIMIZER |
244 | printf("Optimizing UNARYPLUS NUMBER\n" ); |
245 | #endif |
246 | return n; |
247 | } |
248 | #endif |
249 | return new UnaryPlusNode(n); |
250 | } |
251 | |
252 | static Node* makeNegateNode(Node *n) |
253 | { |
254 | #ifdef OPTIMIZE_NODES |
255 | if (n->isNumber()) { |
256 | #ifdef TRACE_OPTIMIZER |
257 | printf("Optimizing NEGATE NUMBER\n" ); |
258 | #endif |
259 | NumberNode *number = static_cast <NumberNode *>(n); |
260 | number->setValue(-number->value()); |
261 | return number; |
262 | } |
263 | #endif |
264 | return new NegateNode(n); |
265 | } |
266 | |
267 | static Node* makeBitwiseNotNode(Node *n) |
268 | { |
269 | #ifdef OPTIMIZE_NODES |
270 | if (n->isNumber()) { |
271 | #ifdef TRACE_OPTIMIZER |
272 | printf("Optimizing BITWISENOT NUMBER\n" ); |
273 | #endif |
274 | NumberNode *number = static_cast <NumberNode *>(n); |
275 | number->setValue(~toInt32(number->value())); |
276 | return number; |
277 | } |
278 | #endif |
279 | return new BitwiseNotNode(n); |
280 | } |
281 | |
282 | static Node* makeLogicalNotNode(Node *n) |
283 | { |
284 | return new LogicalNotNode(n); |
285 | } |
286 | |
287 | static Node* makeGroupNode(Node *n) |
288 | { |
289 | if (n->isVarAccessNode() || n->isGroupNode()) |
290 | return n; |
291 | return new GroupNode(n); |
292 | } |
293 | |
294 | static StatementNode* makeIfNode(Node *e, StatementNode *s1, StatementNode *s2) |
295 | { |
296 | return new IfNode(e, s1, s2); |
297 | } |
298 | |
299 | static StatementNode *makeImportNode(PackageNameNode *n, |
300 | bool wildcard, const Identifier &a) |
301 | { |
302 | ImportStatement *stat = new ImportStatement(n); |
303 | if (wildcard) |
304 | stat->enableWildcard(); |
305 | stat->setAlias(a); |
306 | |
307 | return stat; |
308 | } |
309 | |
310 | static StatementNode *makeLabelNode(const Identifier& l, StatementNode* s) |
311 | { |
312 | return new LabelNode(l, s); |
313 | } |
314 | |
315 | } // namespace KJS |
316 | |
317 | #endif |
318 | // vi: set sw=4 : |
319 | |