File: | platform/mac/avmshell/../../../eval/eval-parse-stmt.cpp |
Location: | line 616, column 39 |
Description: | Access to field 'hd' results in a dereference of a null pointer (loaded from variable 'arguments') |
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 | ||
5 | * | ||
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/ | ||
10 | * | ||
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 | ||
14 | * License. | ||
15 | * | ||
16 | * The Original Code is [Open Source Virtual Machine.]. | ||
17 | * | ||
18 | * The Initial Developer of the Original Code is | ||
19 | * Adobe System Incorporated. | ||
20 | * Portions created by the Initial Developer are Copyright (C) 2008 | ||
21 | * the Initial Developer. All Rights Reserved. | ||
22 | * | ||
23 | * Contributor(s): | ||
24 | * Adobe AS3 Team | ||
25 | * | ||
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. | ||
37 | * | ||
38 | * ***** END LICENSE BLOCK ***** */ | ||
39 | |||
40 | #include "avmplus.h" | ||
41 | |||
42 | #ifdef VMCFG_EVAL | ||
43 | |||
44 | #include "eval.h" | ||
45 | |||
46 | namespace avmplus | ||
47 | { | ||
48 | namespace RTC | ||
49 | { | ||
50 | Stmt* Parser::statement(boolbool config) | ||
51 | { | ||
52 | AvmAssert(config == true || hd() == T_LeftBrace)do { } while (0); | ||
53 | switch (hd()) { | ||
54 | case T_Semicolon: { | ||
55 | Stmt* stmt = ALLOC(EmptyStmt, ())::new (allocator->alloc(sizeof(EmptyStmt))) EmptyStmt (); | ||
56 | next(); | ||
57 | return stmt; | ||
58 | } | ||
59 | |||
60 | case T_LeftBrace: | ||
61 | return ALLOC(BlockStmt, (statementBlock(config)))::new (allocator->alloc(sizeof(BlockStmt))) BlockStmt (statementBlock (config)); | ||
62 | |||
63 | case T_Break: { | ||
64 | Stmt* stmt = breakStatement(); | ||
65 | semicolon(); | ||
66 | return stmt; | ||
67 | } | ||
68 | |||
69 | case T_Continue: { | ||
70 | Stmt* stmt = continueStatement(); | ||
71 | semicolon(); | ||
72 | return stmt; | ||
73 | } | ||
74 | |||
75 | case T_Default: { | ||
76 | next(); | ||
77 | if (hd() == T_Identifier && identValue() == compiler->SYM_xml) { | ||
78 | Stmt* stmt = defaultXmlNamespaceStatement(); | ||
79 | semicolon(); | ||
80 | return stmt; | ||
81 | } | ||
82 | else { | ||
83 | compiler->syntaxError(position(), SYNTAXERR_DEFAULT_NOT_EXPECTED); | ||
84 | /*NOTREACHED*/ | ||
85 | return NULL__null; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | case T_Do: { | ||
90 | Stmt* stmt = doStatement(); | ||
91 | semicolon(); | ||
92 | return stmt; | ||
93 | } | ||
94 | |||
95 | case T_For: | ||
96 | return forStatement(); | ||
97 | |||
98 | case T_If: | ||
99 | return ifStatement(); | ||
100 | |||
101 | case T_Import: | ||
102 | return importStatement(); | ||
103 | |||
104 | case T_Return: { | ||
105 | Stmt* stmt = returnStatement(); | ||
106 | semicolon(); | ||
107 | return stmt; | ||
108 | } | ||
109 | |||
110 | case T_Switch: | ||
111 | return switchStatement(); | ||
112 | |||
113 | case T_Throw: { | ||
114 | Stmt* stmt = throwStatement(); | ||
115 | semicolon(); | ||
116 | return stmt; | ||
117 | } | ||
118 | |||
119 | case T_Try: | ||
120 | return tryStatement(); | ||
121 | |||
122 | case T_Use: { | ||
123 | Stmt* stmt = useStatement(); | ||
124 | semicolon(); | ||
125 | return stmt; | ||
126 | } | ||
127 | |||
128 | case T_Var: | ||
129 | case T_Const: { | ||
130 | Stmt* stmt = varStatement(hd() == T_Const); | ||
131 | semicolon(); | ||
132 | return stmt; | ||
133 | } | ||
134 | |||
135 | case T_While: | ||
136 | return whileStatement(); | ||
137 | |||
138 | case T_With: | ||
139 | return withStatement (); | ||
140 | |||
141 | case T_Function: | ||
142 | if (compiler->local_functions) { | ||
143 | // FIXME: should block-internal function definition be initialized on block entry? | ||
144 | uint32_t pos = position(); | ||
145 | Qualifier qual; | ||
146 | FunctionDefn* fn = functionGuts(&qual, truetrue, falsefalse, truetrue); | ||
147 | Str* name = fn->name; | ||
148 | fn->name = NULL__null; | ||
149 | addVarBinding(name, NULL__null); | ||
150 | return ALLOC(ExprStmt, (pos,::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, :: new (allocator->alloc(sizeof(AssignExpr))) AssignExpr (OPR_assign , ::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, pos), ::new (allocator->alloc(sizeof(LiteralFunction ))) LiteralFunction (fn))) | ||
151 | ALLOC(AssignExpr,::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, :: new (allocator->alloc(sizeof(AssignExpr))) AssignExpr (OPR_assign , ::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, pos), ::new (allocator->alloc(sizeof(LiteralFunction ))) LiteralFunction (fn))) | ||
152 | (OPR_assign,::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, :: new (allocator->alloc(sizeof(AssignExpr))) AssignExpr (OPR_assign , ::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, pos), ::new (allocator->alloc(sizeof(LiteralFunction ))) LiteralFunction (fn))) | ||
153 | ALLOC(QualifiedName, (NULL, ALLOC(SimpleName, (name)), false, pos)),::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, :: new (allocator->alloc(sizeof(AssignExpr))) AssignExpr (OPR_assign , ::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, pos), ::new (allocator->alloc(sizeof(LiteralFunction ))) LiteralFunction (fn))) | ||
154 | ALLOC(LiteralFunction, (fn))))))::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, :: new (allocator->alloc(sizeof(AssignExpr))) AssignExpr (OPR_assign , ::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, pos), ::new (allocator->alloc(sizeof(LiteralFunction ))) LiteralFunction (fn))); | ||
155 | } | ||
156 | else { | ||
157 | compiler->syntaxError(position(), SYNTAXERR_NO_FUNCTIONS_IN_BLOCKS); | ||
158 | /*NOTREACHED*/ | ||
159 | return NULL__null; | ||
160 | } | ||
161 | |||
162 | case T_Super: | ||
163 | return superStatement(); | ||
164 | |||
165 | default: { | ||
166 | if (hd() == T_Identifier && hd2() == T_Colon) | ||
167 | return labeledStatement(); | ||
168 | uint32_t pos = position(); | ||
169 | Stmt* stmt = ALLOC(ExprStmt, (pos, commaExpression(0)))::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, commaExpression (0)); | ||
170 | semicolon(); | ||
171 | return stmt; | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | void Parser::semicolon() | ||
177 | { | ||
178 | switch (hd ()) { | ||
179 | case T_Semicolon: | ||
180 | next(); | ||
181 | return; | ||
182 | case T_EOS: | ||
183 | case T_RightBrace: | ||
184 | // Inserting it | ||
185 | return; | ||
186 | default: | ||
187 | if (!newline ()) | ||
188 | compiler->syntaxError(position(), SYNTAXERR_SEMICOLON_OR_NEWLINE); | ||
189 | // Inserting it | ||
190 | return; | ||
191 | } | ||
192 | } | ||
193 | |||
194 | boolbool Parser::noNewline() | ||
195 | { | ||
196 | switch (hd ()) { | ||
197 | case T_EOS: | ||
198 | case T_Semicolon: | ||
199 | case T_RightBrace: | ||
200 | return falsefalse; | ||
201 | default: | ||
202 | if (newline()) | ||
203 | return falsefalse; | ||
204 | return truetrue; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | Seq<Stmt*>* Parser::statementBlock(boolbool config) | ||
209 | { | ||
210 | SeqBuilder<Stmt*> stmts(allocator); | ||
211 | eat (T_LeftBrace); | ||
212 | while (hd() != T_RightBrace) | ||
213 | stmts.addAtEnd(statement(config)); | ||
214 | eat (T_RightBrace); | ||
215 | return stmts.get(); | ||
216 | } | ||
217 | |||
218 | // updates bindings by side effect, returns a single expression | ||
219 | // statement for the initialization. | ||
220 | |||
221 | Stmt* Parser::varStatement(boolbool is_const) | ||
222 | { | ||
223 | uint32_t pos = 0; | ||
224 | Expr* inits = varBindings(&pos, is_const); | ||
225 | return ALLOC(ExprStmt, (pos, inits))::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, inits ); | ||
226 | } | ||
227 | |||
228 | // updates bindings by side effect, returns a single expression for | ||
229 | // the initialization, a LiteralUndefined node if there was no useful | ||
230 | // initialization. | ||
231 | |||
232 | Expr* Parser::varBindings(uint32_t* pos, boolbool is_const, int flags, uint32_t* numbindings, Expr** firstName) | ||
233 | { | ||
234 | AvmAssert( !is_const || firstName == NULL )do { } while (0); | ||
235 | |||
236 | Expr* inits = NULL__null; | ||
237 | eat(is_const ? T_Const : T_Var); | ||
238 | *pos = position(); | ||
239 | if (numbindings) | ||
240 | *numbindings = 0; | ||
241 | if (firstName) | ||
242 | *firstName = NULL__null; | ||
243 | for (;;) { | ||
244 | Str* name = identifier(); | ||
245 | QualifiedName* type_name = NULL__null; | ||
246 | if (match(T_Colon)) | ||
247 | type_name = typeExpression(); | ||
248 | if (numbindings) | ||
249 | *numbindings += 1; | ||
250 | if (!is_const) | ||
251 | addVarBinding(name, type_name); | ||
252 | /* | ||
253 | if (is_const && hd() != T_Assign) | ||
254 | compiler->syntaxError(*pos, SYNTAXERR_CONST_INIT_REQD); | ||
255 | */ | ||
256 | if (match(T_Assign)) { | ||
257 | Expr* init = assignmentExpression(flags); | ||
258 | Expr* lhs = ALLOC(QualifiedName, (NULL, ALLOC(SimpleName, (name)), false, *pos))::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, *pos); | ||
259 | if (is_const) | ||
260 | addConstBinding(name, type_name); | ||
261 | Expr* assign = ALLOC(AssignExpr, (is_const ? OPR_init : OPR_assign, lhs, init))::new (allocator->alloc(sizeof(AssignExpr))) AssignExpr (is_const ? OPR_init : OPR_assign, lhs, init); | ||
262 | if (firstName && *firstName == NULL__null) | ||
263 | *firstName = lhs; | ||
264 | if (inits == NULL__null) | ||
265 | inits = assign; | ||
266 | else | ||
267 | inits = ALLOC(BinaryExpr, (OPR_comma, inits, assign))::new (allocator->alloc(sizeof(BinaryExpr))) BinaryExpr (OPR_comma , inits, assign); | ||
268 | } | ||
269 | else if (firstName && *firstName == NULL__null) { | ||
270 | *firstName = ALLOC(QualifiedName, (NULL, ALLOC(SimpleName, (name)), false, *pos))::new (allocator->alloc(sizeof(QualifiedName))) QualifiedName (__null, ::new (allocator->alloc(sizeof(SimpleName))) SimpleName (name), false, *pos); | ||
271 | } | ||
272 | |||
273 | if (!match(T_Comma)) | ||
274 | break; | ||
275 | } | ||
276 | return inits ? inits : ALLOC(LiteralUndefined, (*pos))::new (allocator->alloc(sizeof(LiteralUndefined))) LiteralUndefined (*pos); | ||
277 | } | ||
278 | |||
279 | Stmt* Parser::useStatement() | ||
280 | { | ||
281 | uint32_t pos = position(); | ||
282 | eat(T_Use); | ||
283 | if (!match(T_Namespace)) | ||
284 | compiler->syntaxError(pos, SYNTAXERR_ILLEGAL_USE); | ||
285 | Str* ns = identifier(); | ||
286 | addOpenNamespace(ALLOC(NamespaceRef, (ns))::new (allocator->alloc(sizeof(NamespaceRef))) NamespaceRef (ns)); | ||
287 | return ALLOC(EmptyStmt, ())::new (allocator->alloc(sizeof(EmptyStmt))) EmptyStmt (); | ||
288 | } | ||
289 | |||
290 | // <import> ::= "import" <ident> { "." <ident> }* { "." "*" } | ||
291 | Stmt* Parser::importStatement() | ||
292 | { | ||
293 | SeqBuilder<Str*> name(allocator); | ||
294 | StringBuilder id(compiler); | ||
295 | |||
296 | eat(T_Import); | ||
297 | if (hd() == T_Identifier) { | ||
298 | name.addAtEnd(identValue()); | ||
299 | id.append(identValue()); | ||
300 | } | ||
301 | eat(T_Identifier); | ||
302 | boolbool qualified = truetrue; | ||
303 | while (match(T_Dot)) { | ||
304 | if (hd() == T_Multiply) { | ||
305 | match(T_Multiply); | ||
306 | qualified = falsefalse; | ||
307 | break; | ||
308 | } | ||
309 | id.append("."); | ||
310 | if (hd() == T_Identifier) { | ||
311 | name.addAtEnd(identValue()); | ||
312 | id.append(identValue()); | ||
313 | } | ||
314 | eat(T_Identifier); | ||
315 | } | ||
316 | Seq<Str*>* n = name.get(); | ||
317 | if (qualified) | ||
318 | addQualifiedImport(n); | ||
319 | else { | ||
320 | addOpenNamespace(ALLOC(CommonNamespace, (id.str()))::new (allocator->alloc(sizeof(CommonNamespace))) CommonNamespace (id.str())); | ||
321 | addUnqualifiedImport(n); | ||
322 | } | ||
323 | return ALLOC(EmptyStmt, ())::new (allocator->alloc(sizeof(EmptyStmt))) EmptyStmt (); | ||
324 | } | ||
325 | |||
326 | Stmt* Parser::labeledStatement() | ||
327 | { | ||
328 | Str* label = identifier(); | ||
329 | eat(T_Colon); | ||
330 | |||
331 | Stmt* stmt = statement(); | ||
332 | |||
333 | Stmt* s = stmt; | ||
334 | while (s->isLabeledStmt()) | ||
335 | s = ((LabeledStmt*)s)->stmt; | ||
336 | if (s->isLabelSetStmt()) { | ||
337 | LabelSetStmt* ls = (LabelSetStmt*)s; | ||
338 | ls->labels = ALLOC(Seq<Str*>, (label, ls->labels))::new (allocator->alloc(sizeof(Seq<Str*>))) Seq<Str *> (label, ls->labels); | ||
339 | } | ||
340 | |||
341 | return ALLOC(LabeledStmt, (label, stmt))::new (allocator->alloc(sizeof(LabeledStmt))) LabeledStmt ( label, stmt); | ||
342 | } | ||
343 | |||
344 | Stmt* Parser::returnStatement() | ||
345 | { | ||
346 | eat (T_Return); | ||
347 | uint32_t pos = position(); | ||
348 | if (topRib->tag != RIB_Function) | ||
349 | compiler->syntaxError(pos, SYNTAXERR_RETURN_OUTSIDE_FN); | ||
350 | Expr* expr = NULL__null; | ||
351 | if (noNewline()) { | ||
352 | if (topRib->is_void) | ||
353 | compiler->syntaxError(pos, SYNTAXERR_VOIDFN_RETURNS_VALUE); | ||
354 | expr = commaExpression(0); | ||
355 | } | ||
356 | return ALLOC(ReturnStmt, (pos, expr))::new (allocator->alloc(sizeof(ReturnStmt))) ReturnStmt (pos , expr); | ||
357 | } | ||
358 | |||
359 | Stmt* Parser::breakStatement() | ||
360 | { | ||
361 | uint32_t pos = position(); | ||
362 | return ALLOC(BreakStmt, (pos, breakOrContinueLabel(T_Break)))::new (allocator->alloc(sizeof(BreakStmt))) BreakStmt (pos , breakOrContinueLabel(T_Break)); | ||
363 | } | ||
364 | |||
365 | Stmt* Parser::continueStatement() | ||
366 | { | ||
367 | uint32_t pos = position(); | ||
368 | return ALLOC(ContinueStmt, (pos, breakOrContinueLabel(T_Continue)))::new (allocator->alloc(sizeof(ContinueStmt))) ContinueStmt (pos, breakOrContinueLabel(T_Continue)); | ||
369 | } | ||
370 | |||
371 | Str* Parser::breakOrContinueLabel(Token tok) | ||
372 | { | ||
373 | eat(tok); | ||
374 | return noNewline() ? identifier() : NULL__null; | ||
375 | } | ||
376 | |||
377 | // 'default' has been consumed, hd() is the identifier 'xml' | ||
378 | Stmt* Parser::defaultXmlNamespaceStatement() | ||
379 | { | ||
380 | uint32_t pos = position(); | ||
381 | if(hd() != T_Identifier || identValue() != compiler->SYM_xml) | ||
382 | goto failure; | ||
383 | eat(T_Identifier); | ||
384 | if(hd() != T_Namespace) | ||
385 | goto failure; | ||
386 | eat(T_Namespace); | ||
387 | eat(T_Assign); | ||
388 | setUsesDefaultXmlNamespace(); | ||
389 | return ALLOC(DefaultXmlNamespaceStmt, (pos, commaExpression(0)))::new (allocator->alloc(sizeof(DefaultXmlNamespaceStmt))) DefaultXmlNamespaceStmt (pos, commaExpression(0)); | ||
390 | failure: | ||
391 | compiler->syntaxError(pos, SYNTAXERR_EXPECT_DXNS); | ||
392 | /*NOTREACHED*/ | ||
393 | return NULL__null; | ||
394 | } | ||
395 | |||
396 | Stmt* Parser::ifStatement() | ||
397 | { | ||
398 | eat(T_If); | ||
399 | uint32_t pos = position(); | ||
400 | Expr* test = parenExpression(); | ||
401 | Stmt* consequent = statement(); | ||
402 | Stmt* alternate = NULL__null; | ||
403 | if (match(T_Else)) | ||
404 | alternate = statement(); | ||
405 | |||
406 | return ALLOC(IfStmt, (pos, test, consequent, alternate))::new (allocator->alloc(sizeof(IfStmt))) IfStmt (pos, test , consequent, alternate); | ||
407 | } | ||
408 | |||
409 | Stmt* Parser::whileStatement() | ||
410 | { | ||
411 | eat(T_While); | ||
412 | uint32_t pos = position(); | ||
413 | Expr* expr = parenExpression(); | ||
414 | Stmt* body = statement(); | ||
415 | |||
416 | return ALLOC(WhileStmt, (pos, expr, body))::new (allocator->alloc(sizeof(WhileStmt))) WhileStmt (pos , expr, body); | ||
417 | } | ||
418 | |||
419 | Stmt* Parser::doStatement() | ||
420 | { | ||
421 | eat(T_Do); | ||
422 | Stmt* body = statement(); | ||
423 | eat(T_While); | ||
424 | uint32_t pos = position(); | ||
425 | Expr* expr = parenExpression (); | ||
426 | |||
427 | return ALLOC(DoWhileStmt, (pos, expr, body))::new (allocator->alloc(sizeof(DoWhileStmt))) DoWhileStmt ( pos, expr, body); | ||
428 | } | ||
429 | |||
430 | Stmt* Parser::forStatement() | ||
431 | { | ||
432 | Expr* init=NULL__null; | ||
433 | Expr* lhs=NULL__null; | ||
434 | uint32_t numbindings = 0; | ||
435 | boolbool is_each = falsefalse; | ||
436 | |||
437 | eat (T_For); | ||
438 | if (hd() == T_Identifier && identValue() == compiler->SYM_each) { | ||
439 | is_each = truetrue; | ||
440 | eat(T_Identifier); | ||
441 | } | ||
442 | uint32_t pos = position(); | ||
443 | eat (T_LeftParen); | ||
444 | |||
445 | if (hd() == T_Var) | ||
446 | { | ||
447 | uint32_t dummy = 0; | ||
448 | init = varBindings(&dummy, falsefalse, EFLAG_NoIn, &numbindings, &lhs); | ||
449 | } | ||
450 | else if (hd() == T_Semicolon) | ||
451 | ; | ||
452 | else | ||
453 | lhs = init = commaExpression(EFLAG_NoIn); | ||
454 | |||
455 | if (match(T_In)) { | ||
456 | if (numbindings > 1) | ||
457 | compiler->syntaxError(pos, SYNTAXERR_FOR_IN_ONEBINDING); | ||
458 | |||
459 | Expr* objexpr = commaExpression(0); | ||
460 | eat (T_RightParen); | ||
461 | Stmt* body = statement(); | ||
462 | |||
463 | AvmAssert( lhs != NULL )do { } while (0); | ||
464 | return ALLOC(ForInStmt, (pos, lhs, init, objexpr, body, is_each))::new (allocator->alloc(sizeof(ForInStmt))) ForInStmt (pos , lhs, init, objexpr, body, is_each); | ||
465 | } | ||
466 | else { | ||
467 | if (is_each) | ||
468 | compiler->syntaxError(pos, SYNTAXERR_FOR_EACH_REQS_IN); | ||
469 | |||
470 | eat(T_Semicolon); | ||
471 | Expr* test = hd() == T_Semicolon ? NULL__null : commaExpression(0); | ||
472 | eat(T_Semicolon); | ||
473 | Expr* update = hd() == T_RightParen ? NULL__null : commaExpression(0); | ||
474 | eat(T_RightParen); | ||
475 | Stmt* body = statement (); | ||
476 | |||
477 | return ALLOC(ForStmt, (pos, init, test, update, body))::new (allocator->alloc(sizeof(ForStmt))) ForStmt (pos, init , test, update, body); | ||
478 | } | ||
479 | } | ||
480 | |||
481 | Stmt* Parser::switchStatement() | ||
482 | { | ||
483 | eat (T_Switch); | ||
484 | uint32_t pos = position(); | ||
485 | Expr* expr = parenExpression (); | ||
486 | |||
487 | eat (T_LeftBrace); | ||
488 | Seq<CaseClause*>* cases = NULL__null; | ||
489 | if (hd() == T_Case || hd() == T_Default) | ||
490 | cases = caseElements(); | ||
491 | eat(T_RightBrace); | ||
492 | |||
493 | return ALLOC(SwitchStmt, (pos, expr, cases))::new (allocator->alloc(sizeof(SwitchStmt))) SwitchStmt (pos , expr, cases); | ||
494 | } | ||
495 | |||
496 | Seq<CaseClause*>* Parser::caseElements() | ||
497 | { | ||
498 | SeqBuilder<CaseClause*> cases(allocator); | ||
499 | boolbool hasDefault = falsefalse; | ||
500 | CaseClause* last = NULL__null; | ||
501 | |||
502 | for (;;) { | ||
503 | switch (hd ()) { | ||
504 | case T_RightBrace: | ||
505 | return cases.get(); | ||
506 | |||
507 | case T_Default: { | ||
508 | if (hd2() != T_Colon) | ||
509 | goto just_a_statement; // default xml namespace | ||
510 | eat(T_Default); | ||
511 | eat(T_Colon); | ||
512 | if (hasDefault) | ||
513 | compiler->syntaxError(position(), SYNTAXERR_DUPLICATE_DEFAULT); | ||
514 | hasDefault = truetrue; | ||
515 | cases.addAtEnd(last = ALLOC(CaseClause, (0, NULL))::new (allocator->alloc(sizeof(CaseClause))) CaseClause (0 , __null)); | ||
516 | break; | ||
517 | } | ||
518 | |||
519 | case T_Case: { | ||
520 | eat(T_Case); | ||
521 | uint32_t pos = position(); | ||
522 | Expr* expr = commaExpression(0); | ||
523 | eat(T_Colon); | ||
524 | cases.addAtEnd(last = ALLOC(CaseClause, (pos, expr))::new (allocator->alloc(sizeof(CaseClause))) CaseClause (pos , expr)); | ||
525 | } | ||
526 | /*FALLTHROUGH*/ | ||
527 | just_a_statement: | ||
528 | default: { | ||
529 | if (last == NULL__null) | ||
530 | compiler->syntaxError(position(), SYNTAXERR_EXPECT_CASE_OR_DEFAULT); | ||
531 | AvmAssert(last->stmts == NULL)do { } while (0); | ||
532 | SeqBuilder<Stmt*> stmts(allocator); | ||
533 | while (hd() != T_RightBrace && hd() != T_Case && hd() != T_Default) | ||
534 | stmts.addAtEnd(statement()); | ||
535 | last->stmts = stmts.get(); | ||
536 | break; | ||
537 | } | ||
538 | } | ||
539 | } | ||
540 | } | ||
541 | |||
542 | Stmt* Parser::throwStatement() | ||
543 | { | ||
544 | eat (T_Throw); | ||
545 | uint32_t pos = position(); | ||
546 | return ALLOC(ThrowStmt, (pos, commaExpression(0)))::new (allocator->alloc(sizeof(ThrowStmt))) ThrowStmt (pos , commaExpression(0)); | ||
547 | } | ||
548 | |||
549 | Stmt* Parser::tryStatement() | ||
550 | { | ||
551 | eat (T_Try); | ||
552 | |||
553 | Seq<Stmt*>* tryblock = statementBlock(); | ||
554 | Seq<CatchClause*>* catchblocks = catches(); | ||
555 | Seq<Stmt*>* finallyblock = NULL__null; | ||
556 | |||
557 | if (match(T_Finally)) { | ||
558 | setUsesFinally(); | ||
559 | finallyblock = statementBlock(); | ||
560 | } | ||
561 | |||
562 | return ALLOC(TryStmt, (tryblock, catchblocks,finallyblock))::new (allocator->alloc(sizeof(TryStmt))) TryStmt (tryblock , catchblocks,finallyblock); | ||
563 | } | ||
564 | |||
565 | Seq<CatchClause*>* Parser::catches() | ||
566 | { | ||
567 | SeqBuilder<CatchClause*> catches(allocator); | ||
568 | |||
569 | // Sort of silly that this allows multiple catches yet catchClause() does not | ||
570 | // allow the clauses to discriminate by type. | ||
571 | |||
572 | while (match(T_Catch)) { | ||
573 | setUsesCatch(); | ||
574 | catches.addAtEnd(catchClause()); | ||
575 | } | ||
576 | |||
577 | return catches.get(); | ||
578 | } | ||
579 | |||
580 | CatchClause* Parser::catchClause() | ||
581 | { | ||
582 | eat (T_LeftParen); | ||
583 | Str* catchvar_name = identifier(); | ||
584 | QualifiedName* catchvar_type_name = NULL__null; | ||
585 | if (match(T_Colon)) | ||
586 | catchvar_type_name = typeExpression(); | ||
587 | eat (T_RightParen); | ||
588 | Seq<Stmt*>* catchblock = statementBlock(); | ||
589 | return ALLOC(CatchClause, (catchvar_name, catchvar_type_name, catchblock))::new (allocator->alloc(sizeof(CatchClause))) CatchClause ( catchvar_name, catchvar_type_name, catchblock); | ||
590 | } | ||
591 | |||
592 | Stmt* Parser::withStatement() | ||
593 | { | ||
594 | eat (T_With); | ||
595 | uint32_t pos = position(); | ||
596 | Expr* expr = parenExpression(); | ||
597 | Stmt* body = statement(); | ||
598 | return ALLOC(WithStmt, (pos, expr, body))::new (allocator->alloc(sizeof(WithStmt))) WithStmt (pos, expr , body); | ||
599 | } | ||
600 | |||
601 | // This also parses super expressions when they appear in the statement position. | ||
602 | Stmt* Parser::superStatement() | ||
603 | { | ||
604 | eat (T_Super); | ||
605 | uint32_t pos = position(); | ||
606 | Seq<Expr*>* arguments = NULL__null; | ||
607 | boolbool argsPresent = falsefalse; | ||
608 | if (hd() == T_LeftParen) { | ||
| |||
609 | argsPresent = truetrue; | ||
610 | arguments = argumentList(); | ||
611 | } | ||
612 | if (argsPresent && hd() != T_Dot && hd() != T_LeftBracket) | ||
| |||
613 | return ALLOC(SuperStmt, (pos, arguments))::new (allocator->alloc(sizeof(SuperStmt))) SuperStmt (pos , arguments); | ||
614 | if (argsPresent && (arguments == NULL__null || arguments->tl != NULL__null)) | ||
| |||
615 | compiler->syntaxError(pos, SYNTAXERR_ONE_ARGUMENT_REQUIRED); | ||
616 | Expr* obj = argsPresent ? arguments->hd : ALLOC(ThisExpr, ())::new (allocator->alloc(sizeof(ThisExpr))) ThisExpr (); | ||
| |||
| |||
617 | return ALLOC(ExprStmt, (pos, propertyOperator(ALLOC(SuperExpr, (obj)))))::new (allocator->alloc(sizeof(ExprStmt))) ExprStmt (pos, propertyOperator (::new (allocator->alloc(sizeof(SuperExpr))) SuperExpr (obj ))); | ||
618 | } | ||
619 | } | ||
620 | } | ||
621 | |||
622 | #endif // VMCFG_EVAL |