1 /* directive.c++ -- written by Alexis WILKE for Made to Order Software Corp. (c) 2005-2009 */
2
3 /*
4
5 Copyright (c) 2005-2009 Made to Order Software Corp.
6
7 Permission is hereby granted, free of charge, to any
8 person obtaining a copy of this software and
9 associated documentation files (the "Software"), to
10 deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify,
12 merge, publish, distribute, sublicense, and/or sell
13 copies of the Software, and to permit persons to whom
14 the Software is furnished to do so, subject to the
15 following conditions:
16
17 The above copyright notice and this permission notice
18 shall be included in all copies or substantial
19 portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
22 ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
23 LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
24 FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
25 EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
28 ARISING FROM, OUT OF OR IN CONNECTION WITH THE
29 SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 SOFTWARE.
31
32 */
33
34 #include "parser.h"
35
36
37 namespace sswf
38 {
39 namespace as
40 {
41
42
43 /**********************************************************************/
44 /**********************************************************************/
45 /*** PARSER DIRECTIVES **********************************************/
46 /**********************************************************************/
47 /**********************************************************************/
48
Attributes(NodePtr & node)49 void IntParser::Attributes(NodePtr& node)
50 {
51 // Attributes are read first.
52 // Depending on what follows the first set of attributes
53 // we can determine what we've got (expression, statement,
54 // etc.)
55 // There can be no attribute and the last IDENTIFIER may
56 // not be an attribute, also...
57 for(;;) {
58 switch(f_data.f_type) {
59 case NODE_FALSE:
60 case NODE_IDENTIFIER:
61 case NODE_PRIVATE:
62 case NODE_PUBLIC:
63 case NODE_TRUE:
64 break;
65
66 default:
67 return;
68
69 }
70
71 if(!node.HasNode()) {
72 node.CreateNode(NODE_ATTRIBUTES);
73 node.SetInputInfo(f_lexer.GetInput());
74 }
75
76 NodePtr attr;
77 attr.CreateNode();
78 attr.SetInputInfo(f_lexer.GetInput());
79 attr.SetData(f_data);
80 node.AddChild(attr);
81 GetToken();
82 }
83 }
84
85
86
87
DirectiveList(NodePtr & node)88 void IntParser::DirectiveList(NodePtr& node)
89 {
90 node.CreateNode(NODE_DIRECTIVE_LIST);
91 node.SetInputInfo(f_lexer.GetInput());
92 for(;;) {
93 // skip empty statements quickly
94 while(f_data.f_type == ';') {
95 GetToken();
96 }
97
98 if(f_data.f_type == NODE_EOF
99 || f_data.f_type == NODE_ELSE
100 || f_data.f_type == '}') {
101 return;
102 }
103
104 Directive(node);
105 }
106 }
107
108
Directive(NodePtr & node)109 void IntParser::Directive(NodePtr& node)
110 {
111 // we expect node to be a list of directives already
112 // when defined (see DirectiveList())
113 if(!node.HasNode()) {
114 node.CreateNode(NODE_DIRECTIVE_LIST);
115 node.SetInputInfo(f_lexer.GetInput());
116 }
117
118 // read attributes (identifiers, public/private, true/false)
119 // if we find attributes and the directive accepts them,
120 // then they are added to the directive as the last entry
121 NodePtr attr_list;
122 Attributes(attr_list);
123 long attr_count = attr_list.GetChildCount();
124
125 node_t type = f_data.f_type;
126 NodePtr last_attr;
127
128 // depending on the following token, we may want to restore
129 // the last attribute (if it is an identifier)
130 switch(type) {
131 case ':':
132 if(attr_count == 0) {
133 f_lexer.ErrMsg(AS_ERR_INVALID_OPERATOR, "unexpected ':' without an identifier");
134 break;
135 }
136 last_attr = attr_list.GetChild(attr_count - 1);
137 if(last_attr.GetData().f_type != NODE_IDENTIFIER) {
138 f_lexer.ErrMsg(AS_ERR_INVALID_OPERATOR, "unexpected ':' without an identifier");
139 break;
140 }
141 /*FALLTHROUGH*/
142 case NODE_AS:
143 case NODE_ASSIGNMENT:
144 case NODE_ASSIGNMENT_ADD:
145 case NODE_ASSIGNMENT_BITWISE_AND:
146 case NODE_ASSIGNMENT_BITWISE_OR:
147 case NODE_ASSIGNMENT_BITWISE_XOR:
148 case NODE_ASSIGNMENT_DIVIDE:
149 case NODE_ASSIGNMENT_LOGICAL_AND:
150 case NODE_ASSIGNMENT_LOGICAL_OR:
151 case NODE_ASSIGNMENT_LOGICAL_XOR:
152 case NODE_ASSIGNMENT_MAXIMUM:
153 case NODE_ASSIGNMENT_MINIMUM:
154 case NODE_ASSIGNMENT_MODULO:
155 case NODE_ASSIGNMENT_MULTIPLY:
156 case NODE_ASSIGNMENT_POWER:
157 case NODE_ASSIGNMENT_ROTATE_LEFT:
158 case NODE_ASSIGNMENT_ROTATE_RIGHT:
159 case NODE_ASSIGNMENT_SHIFT_LEFT:
160 case NODE_ASSIGNMENT_SHIFT_RIGHT:
161 case NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
162 case NODE_ASSIGNMENT_SUBTRACT:
163 case NODE_CONDITIONAL:
164 case NODE_DECREMENT:
165 case NODE_EQUAL:
166 case NODE_GREATER_EQUAL:
167 case NODE_IMPLEMENTS:
168 case NODE_INSTANCEOF:
169 case NODE_IN:
170 case NODE_INCREMENT:
171 case NODE_IS:
172 case NODE_LESS_EQUAL:
173 case NODE_LOGICAL_AND:
174 case NODE_LOGICAL_OR:
175 case NODE_LOGICAL_XOR:
176 case NODE_MATCH:
177 case NODE_MAXIMUM:
178 case NODE_MEMBER:
179 case NODE_MINIMUM:
180 case NODE_NOT_EQUAL:
181 case NODE_POWER:
182 case NODE_PRIVATE:
183 case NODE_PUBLIC:
184 case NODE_RANGE:
185 case NODE_REST:
186 case NODE_ROTATE_LEFT:
187 case NODE_ROTATE_RIGHT:
188 case NODE_SCOPE:
189 case NODE_SHIFT_LEFT:
190 case NODE_SHIFT_RIGHT:
191 case NODE_SHIFT_RIGHT_UNSIGNED:
192 case NODE_STRICTLY_EQUAL:
193 case NODE_STRICTLY_NOT_EQUAL:
194 case '*':
195 case '/':
196 case ',':
197 case '%':
198 case '&':
199 case '^':
200 case '|':
201 case '<':
202 case '>':
203 case '+':
204 case '-':
205 case '(':
206 case ';':
207 case '[':
208 if(attr_count > 0) {
209 last_attr = attr_list.GetChild(attr_count - 1);
210 UngetToken(f_data);
211 f_data = last_attr.GetData();
212 --attr_count;
213 attr_list.DeleteChild(attr_count);
214 if(type != ':') {
215 type = last_attr.GetData().f_type;
216 }
217 }
218 break;
219
220 default:
221 // do nothing here
222 break;
223
224 }
225
226 // we have a special case where a USE can be
227 // followed by NAMESPACE vs. an identifier.
228 // (i.e. use a namespace or define a pragma)
229 if(type == NODE_USE) {
230 GetToken();
231 }
232
233 // check for directives which can't have attributes
234 if(attr_count > 0) {
235 switch(type) {
236 case NODE_USE:
237 if(f_data.f_type == NODE_NAMESPACE) {
238 break;
239 }
240 /*FALLTHROUGH*/
241 // pragma can't be annotated
242 case NODE_ARRAY_LITERAL:
243 case NODE_BREAK:
244 case NODE_CONTINUE:
245 case NODE_CASE:
246 case NODE_CATCH:
247 case NODE_DEFAULT:
248 case NODE_DO:
249 case NODE_FOR:
250 case NODE_FINALLY:
251 case NODE_GOTO:
252 case NODE_IF:
253 case NODE_RETURN:
254 case NODE_SWITCH:
255 case NODE_THROW:
256 case NODE_TRY:
257 case NODE_WITH:
258 case NODE_WHILE:
259 case NODE_DECREMENT:
260 case NODE_DELETE:
261 case NODE_FLOAT64:
262 case NODE_IDENTIFIER:
263 case NODE_INCREMENT:
264 case NODE_INT64:
265 case NODE_NEW:
266 case NODE_NULL:
267 case NODE_OBJECT_LITERAL:
268 case NODE_UNDEFINED:
269 case NODE_REGULAR_EXPRESSION:
270 case NODE_STRING:
271 case NODE_SUPER: // will accept commas too even in expressions
272 case NODE_THIS:
273 case NODE_TYPEOF:
274 case NODE_VIDENTIFIER:
275 case NODE_VOID:
276 case '!':
277 case '+':
278 case '-':
279 case '(':
280 case '[':
281 case '~':
282 case ':':
283 case ';':
284 // annotated empty statements are not allowed
285 f_lexer.ErrMsg(AS_ERR_INVALID_ATTRIBUTES, "no attributes were expected here (statements, expressions and pragmas can't be annotated)");
286 attr_list.ClearNode();
287 attr_count = 0;
288 break;
289
290 // everything else can be annotated
291 default:
292 break;
293
294 }
295 }
296
297 // The directive node, if created by a sub-function, will
298 // be added to the list of directives.
299 NodePtr directive;
300 switch(type) {
301 // *** PRAGMA ***
302 case NODE_USE:
303 // we alread did a GetToken() to skip the NODE_USE
304 if(f_data.f_type == NODE_NAMESPACE) {
305 // use namespace ... ';'
306 GetToken();
307 UseNamespace(directive);
308 break;
309 }
310 // TODO? Pragmas are not part of the tree
311 // Note: pragmas affect the Options and
312 // are not currently added to the final
313 // tree of nodes. [is that correct?! it
314 // should be as long as we don't have
315 // run-time pragmas]
316 Pragma();
317 break;
318
319 // *** PACKAGE ***
320 case NODE_PACKAGE:
321 GetToken();
322 Package(directive);
323 break;
324
325 case NODE_IMPORT:
326 GetToken();
327 Import(directive);
328 break;
329
330 // *** CLASS DEFINITION ***
331 case NODE_CLASS:
332 case NODE_INTERFACE:
333 GetToken();
334 Class(directive, type);
335 break;
336
337 case NODE_ENUM:
338 GetToken();
339 Enum(directive);
340 break;
341
342 // *** FUNCTION DEFINITION ***
343 case NODE_FUNCTION:
344 GetToken();
345 Function(directive, false);
346 break;
347
348 // *** VARIABLE DEFINITION ***
349 case NODE_CONST:
350 GetToken();
351 if(f_data.f_type == NODE_VAR) {
352 GetToken();
353 }
354 Variable(directive, true);
355 break;
356
357 case NODE_VAR:
358 GetToken();
359 Variable(directive, false);
360 break;
361
362 // *** STATEMENT ***
363 case NODE_OPEN_CURVLY_BRACKET:
364 GetToken();
365 Block(directive);
366 break;
367
368 case ';':
369 // empty statements are just skipped
370 //
371 // NOTE: we reach here only when we find attributes
372 // which aren't identifiers and this means
373 // we will have gotten an error.
374 GetToken();
375 break;
376
377 case NODE_BREAK:
378 case NODE_CONTINUE:
379 GetToken();
380 BreakContinue(directive, type);
381 break;
382
383 case NODE_CASE:
384 GetToken();
385 Case(directive);
386 break;
387
388 case NODE_CATCH:
389 GetToken();
390 Catch(directive);
391 break;
392
393 case NODE_DEFAULT:
394 GetToken();
395 Default(directive);
396 break;
397
398 case NODE_DO:
399 GetToken();
400 Do(directive);
401 break;
402
403 case NODE_FOR:
404 GetToken();
405 For(directive);
406 break;
407
408 case NODE_FINALLY:
409 case NODE_TRY:
410 GetToken();
411 TryFinally(directive, type);
412 break;
413
414 case NODE_GOTO:
415 GetToken();
416 Goto(directive);
417 break;
418
419 case NODE_IF:
420 GetToken();
421 If(directive);
422 break;
423
424 case NODE_NAMESPACE:
425 GetToken();
426 Namespace(directive);
427 break;
428
429 case NODE_RETURN:
430 GetToken();
431 Return(directive);
432 break;
433
434 case NODE_SWITCH:
435 GetToken();
436 Switch(directive);
437 break;
438
439 case NODE_THROW:
440 GetToken();
441 Throw(directive);
442 break;
443
444 case NODE_WITH:
445 case NODE_WHILE:
446 GetToken();
447 WithWhile(directive, type);
448 break;
449
450 case ':':
451 // the label was the last identifier in the
452 // attributes which is now in f_data
453 directive.CreateNode();
454 directive.SetInputInfo(f_lexer.GetInput());
455 f_data.f_type = NODE_LABEL;
456 directive.SetData(f_data);
457 // we skip the identifier here
458 GetToken();
459 // and then the ':'
460 GetToken();
461 break;
462
463 // *** EXPRESSION ***
464 case NODE_ARRAY_LITERAL:
465 case NODE_DECREMENT:
466 case NODE_DELETE:
467 case NODE_FALSE:
468 case NODE_FLOAT64:
469 case NODE_IDENTIFIER:
470 case NODE_INCREMENT:
471 case NODE_INT64:
472 case NODE_NEW:
473 case NODE_NULL:
474 case NODE_OBJECT_LITERAL:
475 case NODE_PRIVATE:
476 case NODE_PUBLIC:
477 case NODE_UNDEFINED:
478 case NODE_REGULAR_EXPRESSION:
479 case NODE_STRING:
480 case NODE_SUPER: // will accept commas too even in expressions
481 case NODE_THIS:
482 case NODE_TRUE:
483 case NODE_TYPEOF:
484 case NODE_VIDENTIFIER:
485 case NODE_VOID:
486 case '!':
487 case '+':
488 case '-':
489 case '(':
490 case '[':
491 case '~':
492 Expression(directive);
493 break;
494
495 // *** TERMINATOR ***
496 case NODE_EOF:
497 case '}':
498 return;
499
500 // *** INVALID ***
501 // The following are for sure invalid tokens in this
502 // context. If it looks like some of these could be
503 // valid when this function returns, just comment
504 // out the corresponding case.
505 case NODE_AS:
506 case NODE_ASSIGNMENT:
507 case NODE_ASSIGNMENT_ADD:
508 case NODE_ASSIGNMENT_BITWISE_AND:
509 case NODE_ASSIGNMENT_BITWISE_OR:
510 case NODE_ASSIGNMENT_BITWISE_XOR:
511 case NODE_ASSIGNMENT_DIVIDE:
512 case NODE_ASSIGNMENT_LOGICAL_AND:
513 case NODE_ASSIGNMENT_LOGICAL_OR:
514 case NODE_ASSIGNMENT_LOGICAL_XOR:
515 case NODE_ASSIGNMENT_MAXIMUM:
516 case NODE_ASSIGNMENT_MINIMUM:
517 case NODE_ASSIGNMENT_MODULO:
518 case NODE_ASSIGNMENT_MULTIPLY:
519 case NODE_ASSIGNMENT_POWER:
520 case NODE_ASSIGNMENT_ROTATE_LEFT:
521 case NODE_ASSIGNMENT_ROTATE_RIGHT:
522 case NODE_ASSIGNMENT_SHIFT_LEFT:
523 case NODE_ASSIGNMENT_SHIFT_RIGHT:
524 case NODE_ASSIGNMENT_SHIFT_RIGHT_UNSIGNED:
525 case NODE_ASSIGNMENT_SUBTRACT:
526 case NODE_CONDITIONAL:
527 case NODE_EQUAL:
528 case NODE_GREATER_EQUAL:
529 case NODE_IMPLEMENTS:
530 case NODE_INSTANCEOF:
531 case NODE_IN:
532 case NODE_IS:
533 case NODE_LESS_EQUAL:
534 case NODE_LOGICAL_AND:
535 case NODE_LOGICAL_OR:
536 case NODE_LOGICAL_XOR:
537 case NODE_MATCH:
538 case NODE_MAXIMUM:
539 case NODE_MEMBER:
540 case NODE_MINIMUM:
541 case NODE_NOT_EQUAL:
542 case NODE_POWER:
543 case NODE_RANGE:
544 case NODE_REST:
545 case NODE_ROTATE_LEFT:
546 case NODE_ROTATE_RIGHT:
547 case NODE_SCOPE:
548 case NODE_SHIFT_LEFT:
549 case NODE_SHIFT_RIGHT:
550 case NODE_SHIFT_RIGHT_UNSIGNED:
551 case NODE_STRICTLY_EQUAL:
552 case NODE_STRICTLY_NOT_EQUAL:
553 case NODE_VARIABLE:
554 case ')':
555 case '*':
556 case '/':
557 case ',':
558 case '%':
559 case '&':
560 case '^':
561 case '|':
562 case '<':
563 case '>':
564 case ']':
565 f_lexer.ErrMsg(AS_ERR_INVALID_OPERATOR, "unexpected operator");
566 GetToken();
567 break;
568
569 case NODE_DEBUGGER: // just not handled yet...
570 case NODE_ELSE:
571 case NODE_EXTENDS:
572 f_lexer.ErrMsg(AS_ERR_INVALID_KEYWORD, "unexpected keyword");
573 GetToken();
574 break;
575
576 // *** NOT POSSIBLE ***
577 // These should never happen since they should be caught
578 // before this switch is reached or it can't be a node
579 // read by the lexer.
580 case NODE_ARRAY:
581 case NODE_ATTRIBUTES:
582 case NODE_AUTO:
583 case NODE_CALL:
584 case NODE_DIRECTIVE_LIST:
585 case NODE_EMPTY:
586 case NODE_ENTRY:
587 case NODE_EXCLUDE:
588 case NODE_FOR_IN: // maybe this should be a terminator?
589 case NODE_INCLUDE:
590 case NODE_LABEL:
591 case NODE_LIST:
592 case NODE_MASK:
593 case NODE_NAME:
594 case NODE_PARAM:
595 case NODE_PARAMETERS:
596 case NODE_PARAM_MATCH:
597 case NODE_POST_DECREMENT:
598 case NODE_POST_INCREMENT:
599 case NODE_PROGRAM:
600 case NODE_ROOT:
601 case NODE_SET:
602 case NODE_TYPE:
603 case NODE_UNKNOWN: // ?!
604 case NODE_VAR_ATTRIBUTES:
605 case NODE_other: // no node should be of this type
606 case NODE_max: // no node should be of this type
607 fprintf(stderr, "INTERNAL ERROR: invalid node (%d) in directive_list.\n", type);
608 AS_ASSERT(0);
609 break;
610
611 }
612 if(directive.HasNode()) {
613 if(attr_list.GetChildCount() > 0) {
614 directive.SetLink(NodePtr::LINK_ATTRIBUTES, attr_list);
615 }
616 node.AddChild(directive);
617 }
618
619 // Now make sure we have a semicolon for
620 // those statements which have to have it.
621 switch(type) {
622 case NODE_ARRAY_LITERAL:
623 case NODE_BREAK:
624 case NODE_CONST:
625 case NODE_CONTINUE:
626 case NODE_DECREMENT:
627 case NODE_DELETE:
628 case NODE_DO:
629 case NODE_FLOAT64:
630 case NODE_GOTO:
631 case NODE_IDENTIFIER:
632 case NODE_IMPORT:
633 case NODE_INCREMENT:
634 case NODE_INT64:
635 case NODE_NAMESPACE:
636 case NODE_NEW:
637 case NODE_NULL:
638 case NODE_OBJECT_LITERAL:
639 case NODE_RETURN:
640 case NODE_REGULAR_EXPRESSION:
641 case NODE_STRING:
642 case NODE_SUPER:
643 case NODE_THIS:
644 case NODE_THROW:
645 case NODE_TYPEOF:
646 case NODE_UNDEFINED:
647 case NODE_USE:
648 case NODE_VAR:
649 case NODE_VIDENTIFIER:
650 case NODE_VOID:
651 case '!':
652 case '+':
653 case '-':
654 case '(':
655 case '[':
656 case '~':
657 // accept missing ';' when we find a '}' next
658 if(f_data.f_type != ';' && f_data.f_type != '}') {
659 f_lexer.ErrMsg(AS_ERR_SEMICOLON_EXPECTED, "';' was expected");
660 }
661 while(f_data.f_type != ';'
662 && f_data.f_type != '}'
663 && f_data.f_type != NODE_ELSE
664 && f_data.f_type != NODE_EOF) {
665 GetToken();
666 }
667 // we need to skip one semi-color here
668 // in case we're not in a DirectiveList()
669 if(f_data.f_type == ';') {
670 GetToken();
671 }
672 break;
673
674 default:
675 break;
676
677 }
678 }
679
680
681
682
683
684 }; // namespace as
685 }; // namespace sswf
686