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