1 /* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
2 /* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
3 /* ***** BEGIN LICENSE BLOCK *****
4 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 * The contents of this file are subject to the Mozilla Public License Version
7 * 1.1 (the "License"); you may not use this file except in compliance with
8 * the License. You may obtain a copy of the License at
9 * http://www.mozilla.org/MPL/
11 * Software distributed under the License is distributed on an "AS IS" basis,
12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 * for the specific language governing rights and limitations under the
16 * The Original Code is [Open Source Virtual Machine.].
18 * The Initial Developer of the Original Code is
19 * Adobe System Incorporated.
20 * Portions created by the Initial Developer are Copyright (C) 2010
21 * the Initial Developer. All Rights Reserved.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
50 Parser::ConfigBinding::ConfigBinding(Str
* ns
, Str
* name
, Expr
* value
)
57 void Parser::addConfigNamespace(Str
* ns
)
59 configNamespaces
= ALLOC(Seq
<Str
*>, (ns
, configNamespaces
));
62 void Parser::checkNoShadowingOfConfigNamespaces(uint32_t pos
, Str
* s
)
64 Seq
<Str
*>* nss
= configNamespaces
;
67 compiler
->syntaxError(pos
, SYNTAXERR_CONFIG_NAMESPACE_SHADOWING
);
72 void Parser::addConfigBinding(Str
* ns
, Str
* name
, Expr
* value
)
74 configBindings
= ALLOC(Seq
<ConfigBinding
*>, (ALLOC(ConfigBinding
, (ns
, name
, value
)), configBindings
));
77 bool Parser::findConfigNamespace(Str
* ns
)
79 Seq
<Str
*>* nss
= configNamespaces
;
88 Expr
* Parser::findConfigBinding(Str
* ns
, Str
* name
)
90 Seq
<ConfigBinding
*>* bs
= configBindings
;
92 if (bs
->hd
->ns
== ns
&& bs
->hd
->name
== name
)
99 bool Parser::isConfigReference(Expr
* e
)
101 if (e
->tag() != TAG_qualifiedName
)
103 QualifiedName
* qn
= (QualifiedName
*)e
;
104 if (qn
->qualifier
== NULL
|| qn
->qualifier
->tag() != TAG_simpleName
|| qn
->name
->tag() != TAG_simpleName
)
106 SimpleName
* sn
= (SimpleName
*)(qn
->qualifier
);
107 return findConfigNamespace(sn
->name
);
110 bool Parser::evaluateConfigReference(QualifiedName
* qname
)
115 AvmAssert(isConfigReference(qname
));
117 Str
* ns
= ((SimpleName
*)qname
->qualifier
)->name
;
118 Str
* name
= ((SimpleName
*)qname
->name
)->name
;
119 Expr
* value
= findConfigBinding(ns
, name
);
121 return evaluateToBoolean(value
);
123 compiler
->syntaxError(qname
->pos
, SYNTAXERR_UNBOUND_CONST_NAME
);
128 // POSSIBLE EXTENSION: structured data and field access
130 // It would be possible to support array, object, xml, and vector initializers
131 // whose initializing subexpressions are either literal values or references
132 // to config variables, as well as field selections on those initializers.
133 // It's possible to imagine some use cases. We need some clean semantics for
134 // when those initializers escape into non-config code - do we want a single
135 // copy or multiple copies?
137 Expr
* Parser::evaluateConfigDefinition(Str
* ns
, Expr
* e
)
139 // e is evaluated in an environment containing only config bindings.
140 // ns is the default namespace: it will be used to qualify any unqualified name.
143 case TAG_literalUndefined
:
144 case TAG_literalString
:
145 case TAG_literalNull
:
146 case TAG_literalUInt
:
148 case TAG_literalDouble
:
149 case TAG_literalBoolean
:
151 case TAG_simpleName
: {
152 Expr
* expr
= findConfigBinding(ns
, ((SimpleName
*)e
)->name
);
154 compiler
->syntaxError(expr
->pos
, SYNTAXERR_UNBOUND_CONST_NAME
);
157 case TAG_qualifiedName
: {
158 QualifiedName
* qname
= (QualifiedName
*)e
;
159 if (qname
->qualifier
->tag() != TAG_simpleName
|| qname
->name
->tag() != TAG_simpleName
)
160 compiler
->syntaxError(e
->pos
, SYNTAXERR_UNBOUND_CONST_NAME
); // Specifically an illegal const name
161 Str
* ns
= ((SimpleName
*)qname
->qualifier
)->name
;
162 Str
* name
= ((SimpleName
*)qname
->name
)->name
;
163 Expr
* value
= findConfigBinding(ns
, name
);
165 compiler
->syntaxError(e
->pos
, SYNTAXERR_UNBOUND_CONST_NAME
);
168 case TAG_binaryExpr
: {
169 // CLARIFICATION: no short-circuiting
171 // We evaluate both sides of && and || in order to uncover
172 // any undefined variables lurking in non-taken branches.
173 BinaryExpr
* binary
= (BinaryExpr
*)e
;
174 Expr
* lhs
= evaluateConfigDefinition(ns
, binary
->lhs
);
175 Expr
* rhs
= evaluateConfigDefinition(ns
, binary
->rhs
);
176 switch (binary
->op
) {
178 if (lhs
->tag() == TAG_literalString
|| rhs
->tag() == TAG_literalString
) {
179 StringBuilder
b(compiler
);
180 b
.append(((LiteralString
*)lhs
)->value
);
181 b
.append(((LiteralString
*)rhs
)->value
);
182 return boxString(b
.str());
184 return boxDouble(evaluateToNumber(lhs
) + evaluateToNumber(rhs
));
186 return boxDouble(evaluateToNumber(lhs
) - evaluateToNumber(rhs
));
188 return boxDouble(evaluateToNumber(lhs
) * evaluateToNumber(rhs
));
190 return boxDouble(evaluateToNumber(lhs
) / evaluateToNumber(rhs
));
192 return boxDouble(fmod(evaluateToNumber(lhs
), evaluateToNumber(rhs
)));
194 return boxInt(evaluateToInt32(lhs
) << (evaluateToUInt32(rhs
) & 0x1F));
196 return boxInt(evaluateToInt32(lhs
) >> (evaluateToUInt32(rhs
) & 0x1F));
197 case OPR_rightShiftUnsigned
:
198 return boxUInt(evaluateToUInt32(lhs
) >> (evaluateToUInt32(rhs
) & 0x1F));
200 return boxInt(evaluateToInt32(lhs
) & evaluateToInt32(rhs
));
202 return boxInt(evaluateToInt32(lhs
) | evaluateToInt32(rhs
));
204 return boxInt(evaluateToInt32(lhs
) ^ evaluateToInt32(rhs
));
206 return boxBoolean(int(evaluateToBoolean(lhs
)) + int(evaluateToBoolean(rhs
)) == 2);
208 return boxBoolean(int(evaluateToBoolean(lhs
)) + int(evaluateToBoolean(rhs
)) != 0);
210 int r
= evaluateRelational(lhs
, rhs
);
211 return boxBoolean(r
== -1 || r
== 0 ? false : true);
214 int r
= evaluateRelational(rhs
, lhs
);
215 return boxBoolean(r
== -1 || r
== 0 ? false : true);
217 case OPR_lessOrEqual
: {
218 int r
= evaluateRelational(rhs
, lhs
);
219 return boxBoolean(r
== -1 || r
== 1 ? false : true);
221 case OPR_greaterOrEqual
: {
222 int r
= evaluateRelational(lhs
, rhs
);
223 return boxBoolean(r
== -1 || r
== 1 ? false : true);
227 case OPR_strictEqual
:
228 case OPR_strictNotEqual
: {
229 if (lhs
->tag() == TAG_literalInt
|| lhs
->tag() == TAG_literalUInt
)
230 lhs
= boxDouble(evaluateToNumber(lhs
));
231 if (rhs
->tag() == TAG_literalInt
|| rhs
->tag() == TAG_literalUInt
)
232 rhs
= boxDouble(evaluateToNumber(rhs
));
235 if (binary
->op
== OPR_equal
|| binary
->op
== OPR_notEqual
)
236 equality
= binary
->op
== OPR_equal
;
238 equality
= binary
->op
== OPR_strictEqual
;
240 if (lhs
->tag() != rhs
->tag()) {
241 if (binary
->op
== OPR_equal
|| binary
->op
== OPR_notEqual
) {
242 if ((lhs
->tag() == TAG_literalUndefined
&& rhs
->tag() == TAG_literalNull
) ||
243 (lhs
->tag() == TAG_literalNull
&& rhs
->tag() == TAG_literalUndefined
))
244 return boxBoolean(true == equality
);
245 if ((lhs
->tag() == TAG_literalString
&& rhs
->tag() == TAG_literalDouble
) ||
246 (lhs
->tag() == TAG_literalDouble
&& rhs
->tag() == TAG_literalString
))
247 return boxBoolean((evaluateToNumber(lhs
) == evaluateToNumber(rhs
)) == equality
);
248 if (lhs
->tag() == TAG_literalBoolean
|| rhs
->tag() == TAG_literalBoolean
)
249 return boxBoolean((evaluateToBoolean(lhs
) == evaluateToBoolean(rhs
)) == equality
);
251 return boxBoolean(false == equality
);
253 if (lhs
->tag() == TAG_literalUndefined
|| lhs
->tag() == TAG_literalNull
)
254 return boxBoolean(true == equality
);
255 if (lhs
->tag() == TAG_literalDouble
)
256 return boxBoolean((evaluateToNumber(lhs
) == evaluateToNumber(rhs
)) == equality
);
257 if (lhs
->tag() == TAG_literalBoolean
)
258 return boxBoolean((evaluateToBoolean(lhs
) == evaluateToBoolean(rhs
)) == equality
);
259 if (lhs
->tag() == TAG_literalString
)
260 return boxBoolean((evaluateToString(lhs
) == evaluateToString(rhs
)) == equality
);
261 failNonConstant(lhs
);
266 // "as", "is", "in", ",", "="
267 compiler
->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR
);
274 case TAG_unaryExpr
: {
277 // Supporting "typeof" makes some sort of sense (for example, the
278 // operand of typeof can be a config constant that can take on
279 // various values, and computing the name of the type into the
280 // program can be useful).
284 // Supporting "void" probably does not make a lot of sense, but it
286 UnaryExpr
* unary
= (UnaryExpr
*)e
;
287 Expr
* opd
= evaluateConfigDefinition(ns
, unary
->expr
);
290 switch (opd
->tag()) {
291 case TAG_literalUndefined
: return boxString("undefined");
292 case TAG_literalString
: return boxString("string");
293 case TAG_literalNull
: return boxString("object");
294 case TAG_literalUInt
:
296 case TAG_literalDouble
: return boxString("number");
297 case TAG_literalBoolean
: return boxString("boolean");
299 failNonConstant(opd
);
302 case OPR_bitwiseNot
: return boxUInt(~evaluateToUInt32(opd
));
303 case OPR_unminus
: return boxDouble(-evaluateToNumber(opd
));
304 case OPR_unplus
: return boxDouble(evaluateToNumber(opd
));
305 case OPR_not
: return boxBoolean(!evaluateToBoolean(opd
));
306 case OPR_void
: return boxUndefined();
308 // "delete", "++", "--"
309 compiler
->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR
);
316 case TAG_conditionalExpr
: {
317 // EXTENSION: conditional operator
319 // It seems totally sensible to support "... ? ... : ...", though
320 // it's not mentioned in the conditional compilation spec.
322 // We evaluate both arms in order to uncover references to undefined
323 // configuration variables, same as for && and ||.
324 ConditionalExpr
* cond
= (ConditionalExpr
*)e
;
325 Expr
* e1
= evaluateConfigDefinition(ns
, cond
->e1
);
326 Expr
* e2
= evaluateConfigDefinition(ns
, cond
->e2
);
327 Expr
* e3
= evaluateConfigDefinition(ns
, cond
->e3
);
328 return evaluateToBoolean(e1
) ? e2
: e3
;
331 // Property references, 'new', 'call' - lots of things
332 compiler
->syntaxError(position(), SYNTAXERR_ILLEGAL_OP_IN_CONSTEXPR
);
340 Expr
* Parser::boxDouble(double n
) { return ALLOC(LiteralDouble
, (n
, 0)); }
341 Expr
* Parser::boxUInt(uint32_t n
) { return ALLOC(LiteralUInt
, (n
, 0)); }
342 Expr
* Parser::boxInt(int32_t n
) { return ALLOC(LiteralInt
, (n
, 0)); }
343 Expr
* Parser::boxBoolean(bool b
) { return ALLOC(LiteralBoolean
, (b
, 0)); }
344 Expr
* Parser::boxString(const char* s
) { return ALLOC(LiteralString
, (compiler
->intern(s
), 0)); }
345 Expr
* Parser::boxString(Str
* s
) { return ALLOC(LiteralString
, (s
, 0)); }
346 Expr
* Parser::boxUndefined() { return ALLOC(LiteralUndefined
, (0)); }
348 uint32_t Parser::evaluateToUInt32(Expr
* e
)
350 if (e
->tag() == TAG_literalUInt
)
351 return ((LiteralUInt
*)e
)->value
;
352 double d
= evaluateToNumber(e
);
353 if (d
== 0 || MathUtils::isNaN(d
) || MathUtils::isInfinite(d
))
355 d
= (d
< 0 ? -1 : 1) * floor(fabs(d
));
356 d
= fmod(d
, 4294967296.0);
360 int32_t Parser::evaluateToInt32(Expr
* e
)
362 if (e
->tag() == TAG_literalInt
)
363 return ((LiteralInt
*)e
)->value
;
364 double d
= evaluateToNumber(e
);
365 if (d
== 0 || MathUtils::isNaN(d
) || MathUtils::isInfinite(d
))
367 d
= (d
< 0 ? -1 : 1) * floor(fabs(d
));
368 d
= fmod(d
, 4294967296.0);
369 if (d
>= 2147483648.0)
370 return int32_t(d
- 4294967296.0);
375 double Parser::evaluateToNumber(Expr
* e
)
378 case TAG_literalUndefined
: return MathUtils::kNaN
;
379 case TAG_literalNull
: return 0.0;
380 case TAG_literalBoolean
: return ((LiteralBoolean
*)e
)->value
? 1.0 : 0.0;
381 case TAG_literalDouble
: return ((LiteralDouble
*)e
)->value
;
382 case TAG_literalInt
: return (double)(((LiteralInt
*)e
)->value
);
383 case TAG_literalUInt
: return (double)(((LiteralUInt
*)e
)->value
);
384 case TAG_literalString
: return strToDouble(((LiteralString
*)e
)->value
);
391 bool Parser::evaluateToBoolean(Expr
* e
)
394 case TAG_literalUndefined
: return false;
395 case TAG_literalNull
: return false;
396 case TAG_literalBoolean
: return ((LiteralBoolean
*)e
)->value
;
397 case TAG_literalDouble
: { double v
= ((LiteralDouble
*)e
)->value
; return !MathUtils::isNaN(v
) && v
!= 0.0; }
398 case TAG_literalInt
: return ((LiteralInt
*)e
)->value
!= 0;
399 case TAG_literalUInt
: return ((LiteralUInt
*)e
)->value
!= 0;
400 case TAG_literalString
: return ((LiteralString
*)e
)->value
->length
> 0;
407 Str
* Parser::evaluateToString(Expr
* e
)
410 case TAG_literalUndefined
: return compiler
->intern("undefined");
411 case TAG_literalNull
: return compiler
->intern("null");
412 case TAG_literalBoolean
: return ((LiteralBoolean
*)e
)->value
? compiler
->intern("true") : compiler
->intern("false");
413 case TAG_literalDouble
: return doubleToStr(((LiteralDouble
*)e
)->value
);
414 case TAG_literalInt
: return doubleToStr(((LiteralInt
*)e
)->value
);
415 case TAG_literalUInt
: return doubleToStr(((LiteralUInt
*)e
)->value
);
416 case TAG_literalString
: return ((LiteralString
*)e
)->value
;
423 // Returns -1 for undefined, 0 for false, 1 for true. Generally true means "x < y",
424 // false means "!(x < y)" and undefined means x and y are not comparable.
426 int Parser::evaluateRelational(Expr
* lhs
, Expr
* rhs
)
428 if (lhs
->tag() == TAG_literalString
&& rhs
->tag() == TAG_literalString
)
429 return (((LiteralString
*)lhs
)->value
)->compareTo(((LiteralString
*)rhs
)->value
) < 0 ? 1 : 0;
431 double l
= evaluateToNumber(lhs
);
432 double r
= evaluateToNumber(rhs
);
433 if (MathUtils::isNaN(l
) || MathUtils::isNaN(r
))
435 return l
< r
? 1 : 0;
438 void Parser::failNonConstant(Expr
* e
)
440 compiler
->internalError(position(), "Non-constant value in expression evaluation, tag=%d", int(e
->tag()));