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 
34 // Shorthand wrappers for entering function contexts
inFuncExpr()35 static void inFuncExpr()
36 {
37     parser().pushFunctionContext(FuncFl_Expr);
38 }
39 
inFuncDecl()40 static void inFuncDecl()
41 {
42     parser().pushFunctionContext(FuncFl_Decl);
43 }
44 
makeAssignNode(Node * loc,Operator op,Node * expr)45 static Node *makeAssignNode(Node *loc, Operator op, Node *expr)
46 {
47     return new AssignNode(loc, op, expr);
48 }
49 
makeConditionalNode(Node * l,Node * e1,Node * e2)50 static Node *makeConditionalNode(Node *l, Node *e1, Node *e2)
51 {
52     return new ConditionalNode(l, e1, e2);
53 }
54 
makePrefixNode(Node * expr,Operator op)55 static Node *makePrefixNode(Node *expr, Operator op)
56 {
57     return new PrefixNode(expr, op);
58 }
59 
makePostfixNode(Node * expr,Operator op)60 static Node *makePostfixNode(Node *expr, Operator op)
61 {
62     return new PostfixNode(expr, op);
63 }
64 
makeFunctionCallNode(Node * func,ArgumentsNode * args)65 static Node *makeFunctionCallNode(Node *func, ArgumentsNode *args)
66 {
67     Node *n = func->nodeInsideAllParens();
68 
69     if (!n->isLocation()) {
70         return new FunctionCallValueNode(func, args);
71     } else {
72         return new FunctionCallReferenceNode(func, args);
73     }
74 }
75 
makeTypeOfNode(Node * expr)76 static Node *makeTypeOfNode(Node *expr)
77 {
78     Node *n = expr->nodeInsideAllParens();
79 
80     // We only need to use the special path for variable references,
81     // since they may throw a ResolveError on evaluate where we don't
82     // want that...
83     if (n->isVarAccessNode()) {
84         return new TypeOfVarNode(static_cast<VarAccessNode *>(n));
85     } else {
86         return new TypeOfValueNode(expr);
87     }
88 }
89 
makeDeleteNode(Node * expr)90 static Node *makeDeleteNode(Node *expr)
91 {
92     Node *n = expr->nodeInsideAllParens();
93 
94     if (!n->isLocation()) {
95         return new DeleteValueNode(expr);
96     } else {
97         return new DeleteReferenceNode(static_cast<LocationNode *>(n));    //### not 100% faithful listing?
98     }
99 }
100 
makeGetterOrSetterPropertyNode(PropertyNode * & result,Identifier & getOrSet,Identifier & name,ParameterNode * params,FunctionBodyNode * body)101 static bool makeGetterOrSetterPropertyNode(PropertyNode *&result, Identifier &getOrSet, Identifier &name, ParameterNode *params, FunctionBodyNode *body)
102 {
103     PropertyNode::Type type;
104 
105     if (getOrSet == "get") {
106         type = PropertyNode::Getter;
107     } else if (getOrSet == "set") {
108         type = PropertyNode::Setter;
109     } else {
110         return false;
111     }
112 
113     result = new PropertyNode(new PropertyNameNode(name),
114                               new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, body, params), type);
115 
116     return true;
117 }
118 
makeAddNode(Node * n1,Node * n2,Operator op)119 static Node *makeAddNode(Node *n1, Node *n2, Operator op)
120 {
121 #ifdef OPTIMIZE_NODES
122     if (n1->isNumber()) {
123         if (n2->isNumber()) {
124 #ifdef TRACE_OPTIMIZER
125             printf("Optimizing ADDNODE NUMBER NUMBER as NUMBER\n");
126 #endif
127             NumberNode *number1 = static_cast< NumberNode * >(n1);
128             NumberNode *number2 = static_cast< NumberNode * >(n2);
129             double d1 = number1->value();
130             double d2 = number2->value();
131             number1->setValue(op == OpPlus ? d1 + d2 : d1 - d2);
132             return number1;
133         }
134 #ifdef TRACE_OPTIMIZER
135         printf("could optimize as ADD NODE NUMBER\n");
136 #endif
137     }
138     if (n2->isNumber()) {
139 #ifdef TRACE_OPTIMIZER
140         printf("could optimize as ADD NODE NUMBER\n");
141 #endif
142     }
143     if (op == OpPlus && n1->isString() && n2->isString()) {
144 #ifdef TRACE_OPTIMIZER
145         printf("Optimizing ADDNODE STRING STRING as STRING\n");
146 #endif
147         StringNode *str1 = static_cast<StringNode *>(n1);
148         StringNode *str2 = static_cast<StringNode *>(n2);
149         str1->setValue(str1->value() + str2->value());
150         return str1;
151     }
152 #endif
153     return new BinaryOperatorNode(n1, n2, op);
154 }
155 
makeMultNode(Node * n1,Node * n2,Operator op)156 static Node *makeMultNode(Node *n1, Node *n2, Operator op)
157 {
158 #ifdef OPTIMIZE_NODES
159     if (n1->isNumber()) {
160         if (n2->isNumber()) {
161 #ifdef TRACE_OPTIMIZER
162             printf("Optimizing MULTNODE NUMBER NUMBER as NUMBER\n");
163 #endif
164             NumberNode *number1 = static_cast< NumberNode * >(n1);
165             NumberNode *number2 = static_cast< NumberNode * >(n2);
166             double d1 = number1->value();
167             double d2 = number2->value();
168             double res;
169             if (op == OpMult) {
170                 res = d1 * d2;
171             } else if (op == OpDiv) {
172                 res = d1 / d2;
173             } else if (op == OpMod) {
174                 res = fmod(d1, d2);
175             } else { // OpExp
176 		res = exponentiation(d1, d2);
177 	    }
178             number1->setValue(res);
179             return number1;
180         }
181 #ifdef TRACE_OPTIMIZER
182         printf("could optimize as MULT NODE NUMBER\n");
183 #endif
184     }
185     if (n2->isNumber()) {
186 #ifdef TRACE_OPTIMIZER
187         printf("could optimize as MULT NODE NUMBER\n");
188 #endif
189     }
190 #endif
191     return new BinaryOperatorNode(n1, n2, op);
192 }
193 
makeShiftNode(Node * n1,Node * n2,Operator op)194 static Node *makeShiftNode(Node *n1, Node *n2, Operator op)
195 {
196 #ifdef OPTIMIZE_NODES
197     if (n1->isNumber() && n2->isNumber()) {
198 #ifdef TRACE_OPTIMIZER
199         printf("Optimizing MULTNODE NUMBER NUMBER as NUMBER\n");
200 #endif
201         NumberNode *number1 = static_cast< NumberNode * >(n1);
202         NumberNode *number2 = static_cast< NumberNode * >(n2);
203         double val = number1->value();
204         uint32_t shiftAmount = toUInt32(number2->value());
205         switch (op) {
206         case OpLShift:
207             // operator <<
208             number1->setValue(toInt32(val) << (shiftAmount & 0x1f));
209             break;
210         case OpRShift:
211             // operator >>
212             number1->setValue(toInt32(val) >> (shiftAmount & 0x1f));
213             break;
214         case OpURShift:
215             // operator >>>
216             number1->setValue(toUInt32(val) >> (shiftAmount & 0x1f));
217             break;
218         default:
219             assert(false);
220             break;
221         }
222         return number1;
223     }
224 #endif
225     return new BinaryOperatorNode(n1, n2, op);
226 }
227 
makeRelationalNode(Node * n1,Operator op,Node * n2)228 static Node *makeRelationalNode(Node *n1, Operator op, Node *n2)
229 {
230     return new BinaryOperatorNode(n1, n2, op);
231 }
232 
makeEqualNode(Node * n1,Operator op,Node * n2)233 static Node *makeEqualNode(Node *n1, Operator op, Node *n2)
234 {
235     return new BinaryOperatorNode(n1, n2, op);
236 }
237 
makeBitOperNode(Node * n1,Operator op,Node * n2)238 static Node *makeBitOperNode(Node *n1, Operator op, Node *n2)
239 {
240     return new BinaryOperatorNode(n1, n2, op);
241 }
242 
makeBinaryLogicalNode(Node * n1,Operator op,Node * n2)243 static Node *makeBinaryLogicalNode(Node *n1, Operator op, Node *n2)
244 {
245     return new BinaryLogicalNode(n1, op, n2);
246 }
247 
makeUnaryPlusNode(Node * n)248 static Node *makeUnaryPlusNode(Node *n)
249 {
250 #ifdef OPTIMIZE_NODES
251     if (n->isNumber()) {
252 #ifdef TRACE_OPTIMIZER
253         printf("Optimizing UNARYPLUS NUMBER\n");
254 #endif
255         return n;
256     }
257 #endif
258     return new UnaryPlusNode(n);
259 }
260 
makeNegateNode(Node * n)261 static Node *makeNegateNode(Node *n)
262 {
263 #ifdef OPTIMIZE_NODES
264     if (n->isNumber()) {
265 #ifdef TRACE_OPTIMIZER
266         printf("Optimizing NEGATE NUMBER\n");
267 #endif
268         NumberNode *number = static_cast <NumberNode *>(n);
269         number->setValue(-number->value());
270         return number;
271     }
272 #endif
273     return new NegateNode(n);
274 }
275 
makeBitwiseNotNode(Node * n)276 static Node *makeBitwiseNotNode(Node *n)
277 {
278 #ifdef OPTIMIZE_NODES
279     if (n->isNumber()) {
280 #ifdef TRACE_OPTIMIZER
281         printf("Optimizing BITWISENOT NUMBER\n");
282 #endif
283         NumberNode *number = static_cast <NumberNode *>(n);
284         number->setValue(~toInt32(number->value()));
285         return number;
286     }
287 #endif
288     return new BitwiseNotNode(n);
289 }
290 
makeLogicalNotNode(Node * n)291 static Node *makeLogicalNotNode(Node *n)
292 {
293     return new LogicalNotNode(n);
294 }
295 
makeGroupNode(Node * n)296 static Node *makeGroupNode(Node *n)
297 {
298     if (n->isVarAccessNode() || n->isGroupNode()) {
299         return n;
300     }
301     return new GroupNode(n);
302 }
303 
makeIfNode(Node * e,StatementNode * s1,StatementNode * s2)304 static StatementNode *makeIfNode(Node *e, StatementNode *s1, StatementNode *s2)
305 {
306     return new IfNode(e, s1, s2);
307 }
308 
makeImportNode(PackageNameNode * n,bool wildcard,const Identifier & a)309 static StatementNode *makeImportNode(PackageNameNode *n,
310                                      bool wildcard, const Identifier &a)
311 {
312     ImportStatement *stat = new ImportStatement(n);
313     if (wildcard) {
314         stat->enableWildcard();
315     }
316     stat->setAlias(a);
317 
318     return stat;
319 }
320 
makeLabelNode(const Identifier & l,StatementNode * s)321 static StatementNode *makeLabelNode(const Identifier &l, StatementNode *s)
322 {
323     return new LabelNode(l, s);
324 }
325 
326 } // namespace KJS
327 
328 #endif
329 // vi: set sw=4 :
330