Convert binary conditional expressions into if statements
[vala-lang.git] / vala / valaparser.vala
blob4d4230abb468e86cd9a929a09dc55c39efce9f48
1 /* valaparser.vala
3 * Copyright (C) 2006-2008 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
24 using Gee;
26 /**
27 * Code visitor parsing all Vala source files.
29 public class Vala.Parser : CodeVisitor {
30 Scanner scanner;
32 CodeContext context;
34 // token buffer
35 TokenInfo[] tokens;
36 // index of current token in buffer
37 int index;
38 // number of tokens in buffer
39 int size;
41 string comment;
43 const int BUFFER_SIZE = 32;
45 struct TokenInfo {
46 public TokenType type;
47 public SourceLocation begin;
48 public SourceLocation end;
51 enum ModifierFlags {
52 NONE,
53 ABSTRACT = 1 << 0,
54 CLASS = 1 << 1,
55 EXTERN = 1 << 2,
56 INLINE = 1 << 3,
57 OVERRIDE = 1 << 4,
58 STATIC = 1 << 5,
59 VIRTUAL = 1 << 6
62 public Parser () {
63 tokens = new TokenInfo[BUFFER_SIZE];
66 /**
67 * Parses all .vala and .vapi source files in the specified code
68 * context and builds a code tree.
70 * @param context a code context
72 public void parse (CodeContext context) {
73 this.context = context;
74 context.accept (this);
77 public override void visit_source_file (SourceFile source_file) {
78 if (source_file.filename.has_suffix (".vala") || source_file.filename.has_suffix (".vapi")) {
79 parse_file (source_file);
83 inline bool next () {
84 index = (index + 1) % BUFFER_SIZE;
85 size--;
86 if (size <= 0) {
87 SourceLocation begin, end;
88 TokenType type = scanner.read_token (out begin, out end);
89 tokens[index].type = type;
90 tokens[index].begin = begin;
91 tokens[index].end = end;
92 size = 1;
94 return (tokens[index].type != TokenType.EOF);
97 inline void prev () {
98 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
99 size++;
100 assert (size <= BUFFER_SIZE);
103 inline TokenType current () {
104 return tokens[index].type;
107 inline bool accept (TokenType type) {
108 if (current () == type) {
109 next ();
110 return true;
112 return false;
115 string get_error (string msg) {
116 var begin = get_location ();
117 next ();
118 Report.error (get_src (begin), "syntax error, " + msg);
119 return msg;
122 inline bool expect (TokenType type) throws ParseError {
123 if (accept (type)) {
124 return true;
127 throw new ParseError.SYNTAX (get_error ("expected %s".printf (type.to_string ())));
130 inline SourceLocation get_location () {
131 return tokens[index].begin;
134 string get_last_string () {
135 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
136 return ((string) tokens[last_index].begin.pos).ndup ((tokens[last_index].end.pos - tokens[last_index].begin.pos));
139 SourceReference get_src (SourceLocation begin) {
140 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
142 return new SourceReference (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
145 SourceReference get_src_com (SourceLocation begin) {
146 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
148 var src = new SourceReference.with_comment (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column, comment);
149 comment = null;
150 return src;
153 SourceReference get_current_src () {
154 return new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column);
157 SourceReference get_last_src () {
158 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
160 return new SourceReference (scanner.source_file, tokens[last_index].begin.line, tokens[last_index].begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
163 void rollback (SourceLocation location) {
164 while (tokens[index].begin.pos != location.pos) {
165 prev ();
169 void skip_identifier () throws ParseError {
170 // also accept keywords as identifiers where there is no conflict
171 switch (current ()) {
172 case TokenType.ABSTRACT:
173 case TokenType.AS:
174 case TokenType.BASE:
175 case TokenType.BREAK:
176 case TokenType.CASE:
177 case TokenType.CATCH:
178 case TokenType.CLASS:
179 case TokenType.CONST:
180 case TokenType.CONSTRUCT:
181 case TokenType.CONTINUE:
182 case TokenType.DEFAULT:
183 case TokenType.DELEGATE:
184 case TokenType.DELETE:
185 case TokenType.DO:
186 case TokenType.DYNAMIC:
187 case TokenType.ELSE:
188 case TokenType.ENUM:
189 case TokenType.ENSURES:
190 case TokenType.ERRORDOMAIN:
191 case TokenType.EXTERN:
192 case TokenType.FALSE:
193 case TokenType.FINALLY:
194 case TokenType.FOR:
195 case TokenType.FOREACH:
196 case TokenType.GET:
197 case TokenType.IDENTIFIER:
198 case TokenType.IF:
199 case TokenType.IN:
200 case TokenType.INLINE:
201 case TokenType.INTERFACE:
202 case TokenType.INTERNAL:
203 case TokenType.IS:
204 case TokenType.LOCK:
205 case TokenType.NAMESPACE:
206 case TokenType.NEW:
207 case TokenType.NULL:
208 case TokenType.OUT:
209 case TokenType.OVERRIDE:
210 case TokenType.PARAMS:
211 case TokenType.PRIVATE:
212 case TokenType.PROTECTED:
213 case TokenType.PUBLIC:
214 case TokenType.REF:
215 case TokenType.REQUIRES:
216 case TokenType.RETURN:
217 case TokenType.SET:
218 case TokenType.SIGNAL:
219 case TokenType.SIZEOF:
220 case TokenType.STATIC:
221 case TokenType.STRUCT:
222 case TokenType.SWITCH:
223 case TokenType.THIS:
224 case TokenType.THROW:
225 case TokenType.THROWS:
226 case TokenType.TRUE:
227 case TokenType.TRY:
228 case TokenType.TYPEOF:
229 case TokenType.USING:
230 case TokenType.VAR:
231 case TokenType.VIRTUAL:
232 case TokenType.VOID:
233 case TokenType.VOLATILE:
234 case TokenType.WEAK:
235 case TokenType.WHILE:
236 case TokenType.YIELD:
237 case TokenType.YIELDS:
238 next ();
239 return;
240 default:
241 throw new ParseError.SYNTAX (get_error ("expected identifier"));
245 string parse_identifier () throws ParseError {
246 skip_identifier ();
247 return get_last_string ();
250 Expression parse_literal () throws ParseError {
251 var begin = get_location ();
253 switch (current ()) {
254 case TokenType.TRUE:
255 next ();
256 return new BooleanLiteral (true, get_src (begin));
257 case TokenType.FALSE:
258 next ();
259 return new BooleanLiteral (false, get_src (begin));
260 case TokenType.INTEGER_LITERAL:
261 next ();
262 return new IntegerLiteral (get_last_string (), get_src (begin));
263 case TokenType.REAL_LITERAL:
264 next ();
265 return new RealLiteral (get_last_string (), get_src (begin));
266 case TokenType.CHARACTER_LITERAL:
267 next ();
268 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
269 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
270 if (lit.error) {
271 Report.error (lit.source_reference, "invalid character literal");
273 return lit;
274 case TokenType.STRING_LITERAL:
275 next ();
276 return new StringLiteral (get_last_string (), get_src (begin));
277 case TokenType.VERBATIM_STRING_LITERAL:
278 next ();
279 string raw_string = get_last_string ();
280 string escaped_string = raw_string.substring (3, raw_string.len () - 6).escape ("");
281 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
282 case TokenType.NULL:
283 next ();
284 return new NullLiteral (get_src (begin));
285 default:
286 throw new ParseError.SYNTAX (get_error ("expected literal"));
290 public void parse_file (SourceFile source_file) {
291 scanner = new Scanner (source_file);
293 index = -1;
294 size = 0;
296 next ();
298 try {
299 parse_using_directives ();
300 parse_declarations (context.root, true);
301 } catch (ParseError e) {
302 // already reported
305 scanner = null;
308 void skip_symbol_name () throws ParseError {
309 do {
310 skip_identifier ();
311 } while (accept (TokenType.DOT) || accept (TokenType.DOUBLE_COLON));
314 UnresolvedSymbol parse_symbol_name () throws ParseError {
315 var begin = get_location ();
316 UnresolvedSymbol sym = null;
317 do {
318 string name = parse_identifier ();
319 if (name == "global" && accept (TokenType.DOUBLE_COLON)) {
320 // global::Name
321 // qualified access to global symbol
322 name = parse_identifier ();
323 sym = new UnresolvedSymbol (sym, name, get_src (begin));
324 sym.qualified = true;
325 continue;
327 sym = new UnresolvedSymbol (sym, name, get_src (begin));
328 } while (accept (TokenType.DOT));
329 return sym;
332 void skip_type () throws ParseError {
333 if (accept (TokenType.VOID)) {
334 while (accept (TokenType.STAR)) {
336 return;
338 accept (TokenType.DYNAMIC);
339 accept (TokenType.WEAK);
340 skip_symbol_name ();
341 skip_type_argument_list ();
342 while (accept (TokenType.STAR)) {
344 accept (TokenType.INTERR);
345 while (accept (TokenType.OPEN_BRACKET)) {
346 do {
347 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
348 parse_expression ();
350 } while (accept (TokenType.COMMA));
351 expect (TokenType.CLOSE_BRACKET);
352 accept (TokenType.INTERR);
354 accept (TokenType.OP_NEG);
355 accept (TokenType.HASH);
358 DataType parse_type (bool owned_by_default = true) throws ParseError {
359 var begin = get_location ();
361 if (accept (TokenType.VOID)) {
362 DataType type = new VoidType ();
363 while (accept (TokenType.STAR)) {
364 type = new PointerType (type);
366 return type;
369 bool is_dynamic = accept (TokenType.DYNAMIC);
371 bool value_owned = owned_by_default;
372 if (owned_by_default) {
373 value_owned = !accept (TokenType.WEAK);
376 var sym = parse_symbol_name ();
377 Gee.List<DataType> type_arg_list = parse_type_argument_list (false);
379 DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
380 if (type_arg_list != null) {
381 foreach (DataType type_arg in type_arg_list) {
382 type.add_type_argument (type_arg);
386 while (accept (TokenType.STAR)) {
387 type = new PointerType (type, get_src (begin));
390 if (!(type is PointerType)) {
391 type.nullable = accept (TokenType.INTERR);
394 // array brackets in types are read from right to left,
395 // this is more logical, especially when nullable arrays
396 // or pointers are involved
397 while (accept (TokenType.OPEN_BRACKET)) {
398 int array_rank = 0;
399 do {
400 array_rank++;
401 // support for stack-allocated arrays
402 // also required for decision between expression and declaration statement
403 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
404 parse_expression ();
407 while (accept (TokenType.COMMA));
408 expect (TokenType.CLOSE_BRACKET);
410 // arrays contain strong references by default
411 type.value_owned = true;
413 type = new ArrayType (type, array_rank, get_src (begin));
414 type.nullable = accept (TokenType.INTERR);
417 if (accept (TokenType.OP_NEG)) {
418 Report.warning (get_last_src (), "obsolete syntax, types are non-null by default");
421 if (!owned_by_default) {
422 value_owned = accept (TokenType.HASH);
425 type.is_dynamic = is_dynamic;
426 type.value_owned = value_owned;
427 return type;
430 Gee.List<Expression> parse_argument_list () throws ParseError {
431 var list = new ArrayList<Expression> ();
432 if (current () != TokenType.CLOSE_PARENS) {
433 do {
434 list.add (parse_expression ());
435 } while (accept (TokenType.COMMA));
437 return list;
440 Expression parse_primary_expression () throws ParseError {
441 var begin = get_location ();
443 Expression expr;
445 switch (current ()) {
446 case TokenType.TRUE:
447 case TokenType.FALSE:
448 case TokenType.INTEGER_LITERAL:
449 case TokenType.REAL_LITERAL:
450 case TokenType.CHARACTER_LITERAL:
451 case TokenType.STRING_LITERAL:
452 case TokenType.VERBATIM_STRING_LITERAL:
453 case TokenType.NULL:
454 expr = parse_literal ();
455 break;
456 case TokenType.OPEN_PARENS:
457 expr = parse_tuple ();
458 break;
459 case TokenType.THIS:
460 expr = parse_this_access ();
461 break;
462 case TokenType.BASE:
463 expr = parse_base_access ();
464 break;
465 case TokenType.NEW:
466 expr = parse_object_or_array_creation_expression ();
467 break;
468 case TokenType.SIZEOF:
469 expr = parse_sizeof_expression ();
470 break;
471 case TokenType.TYPEOF:
472 expr = parse_typeof_expression ();
473 break;
474 default:
475 expr = parse_simple_name ();
476 break;
479 if (expr == null) {
480 // workaround for current limitation of exception handling
481 throw new ParseError.SYNTAX ("syntax error in primary expression");
484 // process primary expressions that start with an inner primary expression
485 bool found = true;
486 while (found) {
487 switch (current ()) {
488 case TokenType.DOT:
489 expr = parse_member_access (begin, expr);
490 break;
491 case TokenType.OP_PTR:
492 expr = parse_pointer_member_access (begin, expr);
493 break;
494 case TokenType.OPEN_PARENS:
495 expr = parse_method_call (begin, expr);
496 break;
497 case TokenType.OPEN_BRACKET:
498 expr = parse_element_access (begin, expr);
499 break;
500 case TokenType.OP_INC:
501 expr = parse_post_increment_expression (begin, expr);
502 break;
503 case TokenType.OP_DEC:
504 expr = parse_post_decrement_expression (begin, expr);
505 break;
506 default:
507 found = false;
508 break;
511 if (expr == null) {
512 // workaround for current limitation of exception handling
513 throw new ParseError.SYNTAX ("syntax error in primary expression");
517 return expr;
520 Expression parse_simple_name () throws ParseError {
521 var begin = get_location ();
522 string id = parse_identifier ();
523 bool qualified = false;
524 if (id == "global" && accept (TokenType.DOUBLE_COLON)) {
525 id = parse_identifier ();
526 qualified = true;
528 Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
529 var expr = new MemberAccess (null, id, get_src (begin));
530 expr.qualified = qualified;
531 if (type_arg_list != null) {
532 foreach (DataType type_arg in type_arg_list) {
533 expr.add_type_argument (type_arg);
536 return expr;
539 Expression parse_tuple () throws ParseError {
540 var begin = get_location ();
541 expect (TokenType.OPEN_PARENS);
542 var expr_list = new ArrayList<Expression> ();
543 if (current () != TokenType.CLOSE_PARENS) {
544 do {
545 expr_list.add (parse_expression ());
546 } while (accept (TokenType.COMMA));
548 expect (TokenType.CLOSE_PARENS);
549 if (expr_list.size != 1) {
550 var tuple = new Tuple ();
551 foreach (Expression expr in expr_list) {
552 tuple.add_expression (expr);
554 return tuple;
556 return new ParenthesizedExpression (expr_list.get (0), get_src (begin));
559 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
560 expect (TokenType.DOT);
561 string id = parse_identifier ();
562 Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
563 var expr = new MemberAccess (inner, id, get_src (begin));
564 if (type_arg_list != null) {
565 foreach (DataType type_arg in type_arg_list) {
566 expr.add_type_argument (type_arg);
569 return expr;
572 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
573 expect (TokenType.OP_PTR);
574 string id = parse_identifier ();
575 Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
576 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
577 if (type_arg_list != null) {
578 foreach (DataType type_arg in type_arg_list) {
579 expr.add_type_argument (type_arg);
582 return expr;
585 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
586 expect (TokenType.OPEN_PARENS);
587 var arg_list = parse_argument_list ();
588 expect (TokenType.CLOSE_PARENS);
589 var init_list = parse_object_initializer ();
591 if (init_list.size > 0 && inner is MemberAccess) {
592 // struct creation expression
593 var member = (MemberAccess) inner;
594 member.creation_member = true;
596 var expr = new ObjectCreationExpression (member, get_src (begin));
597 expr.struct_creation = true;
598 foreach (Expression arg in arg_list) {
599 expr.add_argument (arg);
601 foreach (MemberInitializer initializer in init_list) {
602 expr.add_member_initializer (initializer);
604 return expr;
605 } else {
606 var expr = new MethodCall (inner, get_src (begin));
607 foreach (Expression arg in arg_list) {
608 expr.add_argument (arg);
610 return expr;
614 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
615 expect (TokenType.OPEN_BRACKET);
616 var index_list = parse_expression_list ();
617 expect (TokenType.CLOSE_BRACKET);
619 var expr = new ElementAccess (inner, get_src (begin));
620 foreach (Expression index in index_list) {
621 expr.append_index (index);
623 return expr;
626 Gee.List<Expression> parse_expression_list () throws ParseError {
627 var list = new ArrayList<Expression> ();
628 do {
629 list.add (parse_expression ());
630 } while (accept (TokenType.COMMA));
631 return list;
634 Expression parse_this_access () throws ParseError {
635 var begin = get_location ();
636 expect (TokenType.THIS);
637 return new MemberAccess (null, "this", get_src (begin));
640 Expression parse_base_access () throws ParseError {
641 var begin = get_location ();
642 expect (TokenType.BASE);
643 return new BaseAccess (get_src (begin));
646 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
647 expect (TokenType.OP_INC);
648 return new PostfixExpression (inner, true, get_src (begin));
651 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
652 expect (TokenType.OP_DEC);
653 return new PostfixExpression (inner, false, get_src (begin));
656 Expression parse_object_or_array_creation_expression () throws ParseError {
657 var begin = get_location ();
658 expect (TokenType.NEW);
659 var member = parse_member_name ();
660 if (accept (TokenType.OPEN_PARENS)) {
661 var expr = parse_object_creation_expression (begin, member);
662 return expr;
663 } else if (accept (TokenType.OPEN_BRACKET)) {
664 var expr = parse_array_creation_expression (begin, member);
665 return expr;
666 } else {
667 throw new ParseError.SYNTAX (get_error ("expected ( or ["));
671 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
672 member.creation_member = true;
673 var arg_list = parse_argument_list ();
674 expect (TokenType.CLOSE_PARENS);
675 var init_list = parse_object_initializer ();
677 var expr = new ObjectCreationExpression (member, get_src (begin));
678 foreach (Expression arg in arg_list) {
679 expr.add_argument (arg);
681 foreach (MemberInitializer initializer in init_list) {
682 expr.add_member_initializer (initializer);
684 return expr;
687 Expression parse_array_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
688 bool size_specified = false;
689 Gee.List<Expression> size_specifier_list = null;
690 bool first = true;
691 DataType element_type = UnresolvedType.new_from_expression (member);
692 do {
693 if (!first) {
694 // array of arrays: new T[][42]
695 element_type = new ArrayType (element_type, size_specifier_list.size, element_type.source_reference);
696 } else {
697 first = false;
700 size_specifier_list = new ArrayList<Expression> ();
701 do {
702 Expression size = null;
703 if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
704 size = parse_expression ();
705 size_specified = true;
707 size_specifier_list.add (size);
708 } while (accept (TokenType.COMMA));
709 expect (TokenType.CLOSE_BRACKET);
710 } while (accept (TokenType.OPEN_BRACKET));
712 InitializerList initializer = null;
713 if (current () == TokenType.OPEN_BRACE) {
714 initializer = parse_initializer ();
716 var expr = new ArrayCreationExpression (element_type, size_specifier_list.size, initializer, get_src (begin));
717 if (size_specified) {
718 foreach (Expression size in size_specifier_list) {
719 expr.append_size (size);
722 return expr;
725 Gee.List<MemberInitializer> parse_object_initializer () throws ParseError {
726 var list = new ArrayList<MemberInitializer> ();
727 if (accept (TokenType.OPEN_BRACE)) {
728 do {
729 list.add (parse_member_initializer ());
730 } while (accept (TokenType.COMMA));
731 expect (TokenType.CLOSE_BRACE);
733 return list;
736 MemberInitializer parse_member_initializer () throws ParseError {
737 var begin = get_location ();
738 string id = parse_identifier ();
739 expect (TokenType.ASSIGN);
740 var expr = parse_expression ();
742 return new MemberInitializer (id, expr, get_src (begin));
745 Expression parse_sizeof_expression () throws ParseError {
746 var begin = get_location ();
747 expect (TokenType.SIZEOF);
748 expect (TokenType.OPEN_PARENS);
749 var type = parse_type ();
750 expect (TokenType.CLOSE_PARENS);
752 return new SizeofExpression (type, get_src (begin));
755 Expression parse_typeof_expression () throws ParseError {
756 var begin = get_location ();
757 expect (TokenType.TYPEOF);
758 expect (TokenType.OPEN_PARENS);
759 var type = parse_type ();
760 expect (TokenType.CLOSE_PARENS);
762 return new TypeofExpression (type, get_src (begin));
765 UnaryOperator get_unary_operator (TokenType token_type) {
766 switch (token_type) {
767 case TokenType.PLUS: return UnaryOperator.PLUS;
768 case TokenType.MINUS: return UnaryOperator.MINUS;
769 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
770 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
771 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
772 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
773 case TokenType.REF: return UnaryOperator.REF;
774 case TokenType.OUT: return UnaryOperator.OUT;
775 default: return UnaryOperator.NONE;
779 Expression parse_unary_expression () throws ParseError {
780 var begin = get_location ();
781 var operator = get_unary_operator (current ());
782 if (operator != UnaryOperator.NONE) {
783 next ();
784 var op = parse_unary_expression ();
785 return new UnaryExpression (operator, op, get_src (begin));
787 switch (current ()) {
788 case TokenType.HASH:
789 next ();
790 var op = parse_unary_expression ();
791 return new ReferenceTransferExpression (op, get_src (begin));
792 case TokenType.OPEN_PARENS:
793 next ();
794 switch (current ()) {
795 case TokenType.VOID:
796 case TokenType.DYNAMIC:
797 case TokenType.WEAK:
798 case TokenType.IDENTIFIER:
799 var type = parse_type ();
800 if (accept (TokenType.CLOSE_PARENS)) {
801 // check follower to decide whether to create cast expression
802 switch (current ()) {
803 case TokenType.OP_NEG:
804 case TokenType.TILDE:
805 case TokenType.OPEN_PARENS:
806 case TokenType.TRUE:
807 case TokenType.FALSE:
808 case TokenType.INTEGER_LITERAL:
809 case TokenType.REAL_LITERAL:
810 case TokenType.CHARACTER_LITERAL:
811 case TokenType.STRING_LITERAL:
812 case TokenType.VERBATIM_STRING_LITERAL:
813 case TokenType.NULL:
814 case TokenType.THIS:
815 case TokenType.BASE:
816 case TokenType.NEW:
817 case TokenType.SIZEOF:
818 case TokenType.TYPEOF:
819 case TokenType.IDENTIFIER:
820 if (!(type is PointerType) && !type.value_owned) {
821 Report.warning (get_src (begin), "obsolete syntax, weak type modifier unused in cast expressions");
823 var inner = parse_unary_expression ();
824 return new CastExpression (inner, type, get_src (begin), false);
825 default:
826 break;
829 break;
830 default:
831 break;
833 // no cast expression
834 rollback (begin);
835 break;
836 case TokenType.STAR:
837 next ();
838 var op = parse_unary_expression ();
839 return new PointerIndirection (op, get_src (begin));
840 case TokenType.BITWISE_AND:
841 next ();
842 var op = parse_unary_expression ();
843 return new AddressofExpression (op, get_src (begin));
844 default:
845 break;
848 var expr = parse_primary_expression ();
849 return expr;
852 BinaryOperator get_binary_operator (TokenType token_type) {
853 switch (token_type) {
854 case TokenType.STAR: return BinaryOperator.MUL;
855 case TokenType.DIV: return BinaryOperator.DIV;
856 case TokenType.PERCENT: return BinaryOperator.MOD;
857 case TokenType.PLUS: return BinaryOperator.PLUS;
858 case TokenType.MINUS: return BinaryOperator.MINUS;
859 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
860 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
861 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
862 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
863 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
864 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
865 default: return BinaryOperator.NONE;
869 Expression parse_multiplicative_expression () throws ParseError {
870 var begin = get_location ();
871 var left = parse_unary_expression ();
872 bool found = true;
873 while (found) {
874 var operator = get_binary_operator (current ());
875 switch (operator) {
876 case BinaryOperator.MUL:
877 case BinaryOperator.DIV:
878 case BinaryOperator.MOD:
879 next ();
880 var right = parse_unary_expression ();
881 left = new BinaryExpression (operator, left, right, get_src (begin));
882 break;
883 default:
884 found = false;
885 break;
888 return left;
891 Expression parse_additive_expression () throws ParseError {
892 var begin = get_location ();
893 var left = parse_multiplicative_expression ();
894 bool found = true;
895 while (found) {
896 var operator = get_binary_operator (current ());
897 switch (operator) {
898 case BinaryOperator.PLUS:
899 case BinaryOperator.MINUS:
900 next ();
901 var right = parse_multiplicative_expression ();
902 left = new BinaryExpression (operator, left, right, get_src (begin));
903 break;
904 default:
905 found = false;
906 break;
909 return left;
912 Expression parse_shift_expression () throws ParseError {
913 var begin = get_location ();
914 var left = parse_additive_expression ();
915 bool found = true;
916 while (found) {
917 switch (current ()) {
918 case TokenType.OP_SHIFT_LEFT:
919 next ();
920 var right = parse_additive_expression ();
921 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
922 break;
923 // don't use OP_SHIFT_RIGHT to support >> for nested generics
924 case TokenType.OP_GT:
925 char* first_gt_pos = tokens[index].begin.pos;
926 next ();
927 // only accept >> when there is no space between the two > signs
928 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
929 next ();
930 var right = parse_additive_expression ();
931 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
932 } else {
933 prev ();
934 found = false;
936 break;
937 default:
938 found = false;
939 break;
942 return left;
945 Expression parse_relational_expression () throws ParseError {
946 var begin = get_location ();
947 var left = parse_shift_expression ();
948 bool found = true;
949 while (found) {
950 var operator = get_binary_operator (current ());
951 switch (operator) {
952 case BinaryOperator.LESS_THAN:
953 case BinaryOperator.LESS_THAN_OR_EQUAL:
954 case BinaryOperator.GREATER_THAN_OR_EQUAL:
955 next ();
956 var right = parse_shift_expression ();
957 left = new BinaryExpression (operator, left, right, get_src (begin));
958 break;
959 case BinaryOperator.GREATER_THAN:
960 next ();
961 // ignore >> and >>= (two tokens due to generics)
962 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
963 var right = parse_shift_expression ();
964 left = new BinaryExpression (operator, left, right, get_src (begin));
965 } else {
966 prev ();
967 found = false;
969 break;
970 default:
971 switch (current ()) {
972 case TokenType.IS:
973 next ();
974 var type = parse_type ();
975 left = new TypeCheck (left, type, get_src (begin));
976 break;
977 case TokenType.AS:
978 next ();
979 var type = parse_type ();
980 left = new CastExpression (left, type, get_src (begin), true);
981 break;
982 default:
983 found = false;
984 break;
986 break;
989 return left;
992 Expression parse_equality_expression () throws ParseError {
993 var begin = get_location ();
994 var left = parse_relational_expression ();
995 bool found = true;
996 while (found) {
997 var operator = get_binary_operator (current ());
998 switch (operator) {
999 case BinaryOperator.EQUALITY:
1000 case BinaryOperator.INEQUALITY:
1001 next ();
1002 var right = parse_relational_expression ();
1003 left = new BinaryExpression (operator, left, right, get_src (begin));
1004 break;
1005 default:
1006 found = false;
1007 break;
1010 return left;
1013 Expression parse_and_expression () throws ParseError {
1014 var begin = get_location ();
1015 var left = parse_equality_expression ();
1016 while (accept (TokenType.BITWISE_AND)) {
1017 var right = parse_equality_expression ();
1018 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1020 return left;
1023 Expression parse_exclusive_or_expression () throws ParseError {
1024 var begin = get_location ();
1025 var left = parse_and_expression ();
1026 while (accept (TokenType.CARRET)) {
1027 var right = parse_and_expression ();
1028 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1030 return left;
1033 Expression parse_inclusive_or_expression () throws ParseError {
1034 var begin = get_location ();
1035 var left = parse_exclusive_or_expression ();
1036 while (accept (TokenType.BITWISE_OR)) {
1037 var right = parse_exclusive_or_expression ();
1038 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1040 return left;
1043 Expression parse_in_expression () throws ParseError {
1044 var begin = get_location ();
1045 var left = parse_inclusive_or_expression ();
1046 while (accept (TokenType.IN)) {
1047 var right = parse_inclusive_or_expression ();
1048 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1050 return left;
1053 Expression parse_conditional_and_expression () throws ParseError {
1054 var begin = get_location ();
1055 var left = parse_in_expression ();
1056 while (accept (TokenType.OP_AND)) {
1057 var right = parse_in_expression ();
1058 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1060 return left;
1063 Expression parse_conditional_or_expression () throws ParseError {
1064 var begin = get_location ();
1065 var left = parse_conditional_and_expression ();
1066 while (accept (TokenType.OP_OR)) {
1067 var right = parse_conditional_and_expression ();
1068 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1070 return left;
1073 Expression parse_conditional_expression () throws ParseError {
1074 var begin = get_location ();
1075 var condition = parse_conditional_or_expression ();
1076 if (accept (TokenType.INTERR)) {
1077 var true_expr = parse_expression ();
1078 expect (TokenType.COLON);
1079 var false_expr = parse_expression ();
1080 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1081 } else {
1082 return condition;
1086 Expression parse_lambda_expression () throws ParseError {
1087 var begin = get_location ();
1088 Gee.List<string> params = new ArrayList<string> ();
1089 if (accept (TokenType.OPEN_PARENS)) {
1090 if (current () != TokenType.CLOSE_PARENS) {
1091 do {
1092 params.add (parse_identifier ());
1093 } while (accept (TokenType.COMMA));
1095 expect (TokenType.CLOSE_PARENS);
1096 } else {
1097 params.add (parse_identifier ());
1099 expect (TokenType.LAMBDA);
1101 LambdaExpression lambda;
1102 if (current () == TokenType.OPEN_BRACE) {
1103 var block = parse_block ();
1104 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1105 } else {
1106 var expr = parse_expression ();
1107 lambda = new LambdaExpression (expr, get_src (begin));
1109 foreach (string param in params) {
1110 lambda.add_parameter (param);
1112 return lambda;
1115 AssignmentOperator get_assignment_operator (TokenType token_type) {
1116 switch (token_type) {
1117 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1118 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1119 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1120 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1121 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1122 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1123 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1124 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1125 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1126 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1127 default: return AssignmentOperator.NONE;
1131 Expression parse_expression () throws ParseError {
1132 var begin = get_location ();
1133 Expression expr = parse_conditional_expression ();
1135 if (current () == TokenType.LAMBDA) {
1136 rollback (begin);
1137 var lambda = parse_lambda_expression ();
1138 return lambda;
1141 while (true) {
1142 var operator = get_assignment_operator (current ());
1143 if (operator != AssignmentOperator.NONE) {
1144 next ();
1145 var rhs = parse_expression ();
1146 expr = new Assignment (expr, rhs, operator, get_src (begin));
1147 if (expr == null) {
1148 // workaround for current limitation of exception handling
1149 throw new ParseError.SYNTAX ("syntax error in assignment");
1151 } else if (current () == TokenType.OP_GT) { // >>=
1152 char* first_gt_pos = tokens[index].begin.pos;
1153 next ();
1154 // only accept >>= when there is no space between the two > signs
1155 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1156 next ();
1157 var rhs = parse_expression ();
1158 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1159 if (expr == null) {
1160 // workaround for current limitation of exception handling
1161 throw new ParseError.SYNTAX ("syntax error in assignment");
1163 } else {
1164 prev ();
1165 break;
1167 } else {
1168 break;
1172 return expr;
1175 void parse_statements (Block block) throws ParseError {
1176 while (current () != TokenType.CLOSE_BRACE
1177 && current () != TokenType.CASE
1178 && current () != TokenType.DEFAULT) {
1179 try {
1180 Statement stmt = null;
1181 bool is_decl = false;
1182 comment = scanner.pop_comment ();
1183 switch (current ()) {
1184 case TokenType.OPEN_BRACE:
1185 stmt = parse_block ();
1186 break;
1187 case TokenType.SEMICOLON:
1188 stmt = parse_empty_statement ();
1189 break;
1190 case TokenType.IF:
1191 stmt = parse_if_statement ();
1192 break;
1193 case TokenType.SWITCH:
1194 stmt = parse_switch_statement ();
1195 break;
1196 case TokenType.WHILE:
1197 stmt = parse_while_statement ();
1198 break;
1199 case TokenType.DO:
1200 stmt = parse_do_statement ();
1201 break;
1202 case TokenType.FOR:
1203 stmt = parse_for_statement ();
1204 break;
1205 case TokenType.FOREACH:
1206 stmt = parse_foreach_statement ();
1207 break;
1208 case TokenType.BREAK:
1209 stmt = parse_break_statement ();
1210 break;
1211 case TokenType.CONTINUE:
1212 stmt = parse_continue_statement ();
1213 break;
1214 case TokenType.RETURN:
1215 stmt = parse_return_statement ();
1216 break;
1217 case TokenType.YIELD:
1218 stmt = parse_yield_statement ();
1219 break;
1220 case TokenType.THROW:
1221 stmt = parse_throw_statement ();
1222 break;
1223 case TokenType.TRY:
1224 stmt = parse_try_statement ();
1225 break;
1226 case TokenType.LOCK:
1227 stmt = parse_lock_statement ();
1228 break;
1229 case TokenType.DELETE:
1230 stmt = parse_delete_statement ();
1231 break;
1232 case TokenType.VAR:
1233 is_decl = true;
1234 parse_local_variable_declarations (block);
1235 break;
1236 case TokenType.OP_INC:
1237 case TokenType.OP_DEC:
1238 case TokenType.BASE:
1239 case TokenType.THIS:
1240 case TokenType.OPEN_PARENS:
1241 case TokenType.STAR:
1242 case TokenType.NEW:
1243 stmt = parse_expression_statement ();
1244 break;
1245 default:
1246 bool is_expr = is_expression ();
1247 if (is_expr) {
1248 stmt = parse_expression_statement ();
1249 } else {
1250 is_decl = true;
1251 parse_local_variable_declarations (block);
1253 break;
1256 if (!is_decl) {
1257 if (stmt == null) {
1258 // workaround for current limitation of exception handling
1259 throw new ParseError.SYNTAX ("syntax error in statement");
1261 block.add_statement (stmt);
1263 } catch (ParseError e) {
1264 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1265 // beginning of next declaration or end of file reached
1266 // return what we have so far
1267 break;
1273 bool is_expression () throws ParseError {
1274 var begin = get_location ();
1276 // decide between declaration and expression statement
1277 skip_type ();
1278 switch (current ()) {
1279 // invocation expression
1280 case TokenType.OPEN_PARENS:
1281 // postfix increment
1282 case TokenType.OP_INC:
1283 // postfix decrement
1284 case TokenType.OP_DEC:
1285 // assignments
1286 case TokenType.ASSIGN:
1287 case TokenType.ASSIGN_ADD:
1288 case TokenType.ASSIGN_BITWISE_AND:
1289 case TokenType.ASSIGN_BITWISE_OR:
1290 case TokenType.ASSIGN_BITWISE_XOR:
1291 case TokenType.ASSIGN_DIV:
1292 case TokenType.ASSIGN_MUL:
1293 case TokenType.ASSIGN_PERCENT:
1294 case TokenType.ASSIGN_SHIFT_LEFT:
1295 case TokenType.ASSIGN_SUB:
1296 case TokenType.OP_GT: // >>=
1297 // member access
1298 case TokenType.DOT:
1299 // pointer member access
1300 case TokenType.OP_PTR:
1301 rollback (begin);
1302 return true;
1303 default:
1304 rollback (begin);
1305 return false;
1309 Block parse_embedded_statement () throws ParseError {
1310 if (current () == TokenType.OPEN_BRACE) {
1311 var block = parse_block ();
1312 return block;
1315 comment = scanner.pop_comment ();
1317 var block = new Block (get_src_com (get_location ()));
1318 var stmt = parse_embedded_statement_without_block ();
1319 if (stmt == null) {
1320 // workaround for current limitation of exception handling
1321 throw new ParseError.SYNTAX ("syntax error in embedded statement");
1323 block.add_statement (stmt);
1324 return block;
1328 Statement parse_embedded_statement_without_block () throws ParseError {
1329 switch (current ()) {
1330 case TokenType.SEMICOLON: return parse_empty_statement ();
1331 case TokenType.IF: return parse_if_statement ();
1332 case TokenType.SWITCH: return parse_switch_statement ();
1333 case TokenType.WHILE: return parse_while_statement ();
1334 case TokenType.DO: return parse_do_statement ();
1335 case TokenType.FOR: return parse_for_statement ();
1336 case TokenType.FOREACH: return parse_foreach_statement ();
1337 case TokenType.BREAK: return parse_break_statement ();
1338 case TokenType.CONTINUE: return parse_continue_statement ();
1339 case TokenType.RETURN: return parse_return_statement ();
1340 case TokenType.YIELD: return parse_yield_statement ();
1341 case TokenType.THROW: return parse_throw_statement ();
1342 case TokenType.TRY: return parse_try_statement ();
1343 case TokenType.LOCK: return parse_lock_statement ();
1344 case TokenType.DELETE: return parse_delete_statement ();
1345 default: return parse_expression_statement ();
1349 Block parse_block () throws ParseError {
1350 var begin = get_location ();
1351 expect (TokenType.OPEN_BRACE);
1352 var block = new Block (get_src_com (begin));
1353 parse_statements (block);
1354 if (!accept (TokenType.CLOSE_BRACE)) {
1355 // only report error if it's not a secondary error
1356 if (Report.get_errors () == 0) {
1357 Report.error (get_current_src (), "expected `}'");
1361 block.source_reference.last_line = get_current_src ().last_line;
1362 block.source_reference.last_column = get_current_src ().last_column;
1364 return block;
1367 Statement parse_empty_statement () throws ParseError {
1368 var begin = get_location ();
1369 expect (TokenType.SEMICOLON);
1370 return new EmptyStatement (get_src_com (begin));
1373 void parse_local_variable_declarations (Block block) throws ParseError {
1374 DataType variable_type;
1375 if (accept (TokenType.VAR)) {
1376 variable_type = null;
1377 } else {
1378 variable_type = parse_type ();
1380 do {
1381 DataType type_copy = null;
1382 if (variable_type != null) {
1383 type_copy = variable_type.copy ();
1385 var local = parse_local_variable (type_copy);
1386 block.add_statement (new DeclarationStatement (local, local.source_reference));
1387 } while (accept (TokenType.COMMA));
1388 expect (TokenType.SEMICOLON);
1391 LocalVariable parse_local_variable (DataType? variable_type) throws ParseError {
1392 var begin = get_location ();
1393 string id = parse_identifier ();
1394 Expression initializer = null;
1395 if (accept (TokenType.ASSIGN)) {
1396 initializer = parse_variable_initializer ();
1398 // transform shorthand form
1399 // int[] array = { 42 };
1400 // into
1401 // int[] array = new int[] { 42 };
1402 var array_type = variable_type as ArrayType;
1403 if (array_type != null && initializer is InitializerList) {
1404 initializer = new ArrayCreationExpression (array_type.element_type.copy (), array_type.rank, (InitializerList) initializer, initializer.source_reference);
1407 return new LocalVariable (variable_type, id, initializer, get_src_com (begin));
1410 Statement parse_expression_statement () throws ParseError {
1411 var begin = get_location ();
1412 var expr = parse_statement_expression ();
1413 expect (TokenType.SEMICOLON);
1414 return new ExpressionStatement (expr, get_src_com (begin));
1417 Expression parse_statement_expression () throws ParseError {
1418 // invocation expression, assignment,
1419 // or pre/post increment/decrement expression
1420 var expr = parse_expression ();
1421 return expr;
1424 Statement parse_if_statement () throws ParseError {
1425 var begin = get_location ();
1426 expect (TokenType.IF);
1427 expect (TokenType.OPEN_PARENS);
1428 var condition = parse_expression ();
1429 expect (TokenType.CLOSE_PARENS);
1430 var src = get_src_com (begin);
1431 var true_stmt = parse_embedded_statement ();
1432 Block false_stmt = null;
1433 if (accept (TokenType.ELSE)) {
1434 false_stmt = parse_embedded_statement ();
1436 return new IfStatement (condition, true_stmt, false_stmt, src);
1439 Statement parse_switch_statement () throws ParseError {
1440 var begin = get_location ();
1441 expect (TokenType.SWITCH);
1442 expect (TokenType.OPEN_PARENS);
1443 var condition = parse_expression ();
1444 expect (TokenType.CLOSE_PARENS);
1445 var stmt = new SwitchStatement (condition, get_src_com (begin));
1446 expect (TokenType.OPEN_BRACE);
1447 while (current () != TokenType.CLOSE_BRACE) {
1448 var section = new SwitchSection (get_src_com (begin));
1449 do {
1450 if (accept (TokenType.CASE)) {
1451 section.add_label (new SwitchLabel (parse_expression (), get_src_com (begin)));
1452 } else {
1453 expect (TokenType.DEFAULT);
1454 section.add_label (new SwitchLabel.with_default (get_src_com (begin)));
1456 expect (TokenType.COLON);
1457 } while (current () == TokenType.CASE || current () == TokenType.DEFAULT);
1458 parse_statements (section);
1459 stmt.add_section (section);
1461 expect (TokenType.CLOSE_BRACE);
1462 return stmt;
1465 Statement parse_while_statement () throws ParseError {
1466 var begin = get_location ();
1467 expect (TokenType.WHILE);
1468 expect (TokenType.OPEN_PARENS);
1469 var condition = parse_expression ();
1470 expect (TokenType.CLOSE_PARENS);
1471 var body = parse_embedded_statement ();
1472 return new WhileStatement (condition, body, get_src_com (begin));
1475 Statement parse_do_statement () throws ParseError {
1476 var begin = get_location ();
1477 expect (TokenType.DO);
1478 var body = parse_embedded_statement ();
1479 expect (TokenType.WHILE);
1480 expect (TokenType.OPEN_PARENS);
1481 var condition = parse_expression ();
1482 expect (TokenType.CLOSE_PARENS);
1483 expect (TokenType.SEMICOLON);
1484 return new DoStatement (body, condition, get_src_com (begin));
1487 Statement parse_for_statement () throws ParseError {
1488 var begin = get_location ();
1489 Block block = null;
1490 expect (TokenType.FOR);
1491 expect (TokenType.OPEN_PARENS);
1492 var initializer_list = new ArrayList<Expression> ();
1493 if (!accept (TokenType.SEMICOLON)) {
1494 bool is_expr;
1495 switch (current ()) {
1496 case TokenType.VAR:
1497 is_expr = false;
1498 break;
1499 case TokenType.OP_INC:
1500 case TokenType.OP_DEC:
1501 is_expr = true;
1502 break;
1503 default:
1504 // workaround for current limitation of exception handling
1505 bool local_is_expr = is_expression ();
1506 is_expr = local_is_expr;
1507 break;
1510 if (is_expr) {
1511 do {
1512 initializer_list.add (parse_statement_expression ());
1513 } while (accept (TokenType.COMMA));
1514 } else {
1515 block = new Block (get_src (begin));
1516 DataType variable_type;
1517 if (accept (TokenType.VAR)) {
1518 variable_type = null;
1519 } else {
1520 variable_type = parse_type ();
1522 var local = parse_local_variable (variable_type);
1523 block.add_statement (new DeclarationStatement (local, local.source_reference));
1525 expect (TokenType.SEMICOLON);
1527 Expression condition = null;
1528 if (current () != TokenType.SEMICOLON) {
1529 condition = parse_expression ();
1531 expect (TokenType.SEMICOLON);
1532 var iterator_list = new ArrayList<Expression> ();
1533 if (current () != TokenType.CLOSE_PARENS) {
1534 do {
1535 iterator_list.add (parse_statement_expression ());
1536 } while (accept (TokenType.COMMA));
1538 expect (TokenType.CLOSE_PARENS);
1539 var src = get_src_com (begin);
1540 var body = parse_embedded_statement ();
1541 var stmt = new ForStatement (condition, body, src);
1542 foreach (Expression init in initializer_list) {
1543 stmt.add_initializer (init);
1545 foreach (Expression iter in iterator_list) {
1546 stmt.add_iterator (iter);
1548 if (block != null) {
1549 block.add_statement (stmt);
1550 return block;
1551 } else {
1552 return stmt;
1556 Statement parse_foreach_statement () throws ParseError {
1557 var begin = get_location ();
1558 expect (TokenType.FOREACH);
1559 expect (TokenType.OPEN_PARENS);
1560 DataType type = null;
1561 if (!accept (TokenType.VAR)) {
1562 type = parse_type ();
1564 string id = parse_identifier ();
1565 expect (TokenType.IN);
1566 var collection = parse_expression ();
1567 expect (TokenType.CLOSE_PARENS);
1568 var src = get_src_com (begin);
1569 var body = parse_embedded_statement ();
1570 return new ForeachStatement (type, id, collection, body, src);
1573 Statement parse_break_statement () throws ParseError {
1574 var begin = get_location ();
1575 expect (TokenType.BREAK);
1576 expect (TokenType.SEMICOLON);
1577 return new BreakStatement (get_src_com (begin));
1580 Statement parse_continue_statement () throws ParseError {
1581 var begin = get_location ();
1582 expect (TokenType.CONTINUE);
1583 expect (TokenType.SEMICOLON);
1584 return new ContinueStatement (get_src_com (begin));
1587 Statement parse_return_statement () throws ParseError {
1588 var begin = get_location ();
1589 expect (TokenType.RETURN);
1590 Expression expr = null;
1591 if (current () != TokenType.SEMICOLON) {
1592 expr = parse_expression ();
1594 expect (TokenType.SEMICOLON);
1595 return new ReturnStatement (expr, get_src_com (begin));
1598 Statement parse_yield_statement () throws ParseError {
1599 var begin = get_location ();
1600 expect (TokenType.YIELD);
1601 Expression expr = null;
1602 if (current () != TokenType.SEMICOLON) {
1603 expr = parse_expression ();
1605 expect (TokenType.SEMICOLON);
1606 return new YieldStatement (expr, get_src (begin));
1609 Statement parse_throw_statement () throws ParseError {
1610 var begin = get_location ();
1611 expect (TokenType.THROW);
1612 var expr = parse_expression ();
1613 expect (TokenType.SEMICOLON);
1614 return new ThrowStatement (expr, get_src_com (begin));
1617 Statement parse_try_statement () throws ParseError {
1618 var begin = get_location ();
1619 expect (TokenType.TRY);
1620 var try_block = parse_block ();
1621 Block finally_clause = null;
1622 var catch_clauses = new ArrayList<CatchClause> ();
1623 if (current () == TokenType.CATCH) {
1624 parse_catch_clauses (catch_clauses);
1625 if (current () == TokenType.FINALLY) {
1626 finally_clause = parse_finally_clause ();
1628 } else {
1629 finally_clause = parse_finally_clause ();
1631 var stmt = new TryStatement (try_block, finally_clause, get_src_com (begin));
1632 foreach (CatchClause clause in catch_clauses) {
1633 stmt.add_catch_clause (clause);
1635 return stmt;
1638 void parse_catch_clauses (Gee.List<CatchClause> catch_clauses) throws ParseError {
1639 while (accept (TokenType.CATCH)) {
1640 var begin = get_location ();
1641 DataType type = null;
1642 string id = null;
1643 if (accept (TokenType.OPEN_PARENS)) {
1644 type = parse_type ();
1645 id = parse_identifier ();
1646 expect (TokenType.CLOSE_PARENS);
1648 var block = parse_block ();
1649 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
1653 Block parse_finally_clause () throws ParseError {
1654 expect (TokenType.FINALLY);
1655 var block = parse_block ();
1656 return block;
1659 Statement parse_lock_statement () throws ParseError {
1660 var begin = get_location ();
1661 expect (TokenType.LOCK);
1662 expect (TokenType.OPEN_PARENS);
1663 var expr = parse_expression ();
1664 expect (TokenType.CLOSE_PARENS);
1665 var stmt = parse_embedded_statement ();
1666 return new LockStatement (expr, stmt, get_src_com (begin));
1669 Statement parse_delete_statement () throws ParseError {
1670 var begin = get_location ();
1671 expect (TokenType.DELETE);
1672 var expr = parse_expression ();
1673 expect (TokenType.SEMICOLON);
1674 return new DeleteStatement (expr, get_src_com (begin));
1677 Gee.List<Attribute>? parse_attributes () throws ParseError {
1678 if (current () != TokenType.OPEN_BRACKET) {
1679 return null;
1681 var attrs = new ArrayList<Attribute> ();
1682 while (accept (TokenType.OPEN_BRACKET)) {
1683 do {
1684 var begin = get_location ();
1685 string id = parse_identifier ();
1686 var attr = new Attribute (id, get_src (begin));
1687 if (accept (TokenType.OPEN_PARENS)) {
1688 if (current () != TokenType.CLOSE_PARENS) {
1689 do {
1690 string id = parse_identifier ();
1691 expect (TokenType.ASSIGN);
1692 var expr = parse_expression ();
1693 attr.add_argument (id, expr);
1694 } while (accept (TokenType.COMMA));
1696 expect (TokenType.CLOSE_PARENS);
1698 attrs.add (attr);
1699 } while (accept (TokenType.COMMA));
1700 expect (TokenType.CLOSE_BRACKET);
1702 return attrs;
1705 void set_attributes (CodeNode node, Gee.List<Attribute>? attributes) {
1706 if (attributes != null) {
1707 foreach (Attribute attr in (Gee.List<Attribute>) attributes) {
1708 node.attributes.append (attr);
1713 Symbol parse_declaration () throws ParseError {
1714 comment = scanner.pop_comment ();
1715 var attrs = parse_attributes ();
1717 var begin = get_location ();
1719 TokenType last_keyword = current ();
1721 while (is_declaration_keyword (current ())) {
1722 last_keyword = current ();
1723 next ();
1726 switch (current ()) {
1727 case TokenType.CONSTRUCT:
1728 rollback (begin);
1729 return parse_constructor_declaration (attrs);
1730 case TokenType.TILDE:
1731 rollback (begin);
1732 return parse_destructor_declaration (attrs);
1733 default:
1734 skip_type ();
1735 switch (current ()) {
1736 case TokenType.OPEN_BRACE:
1737 case TokenType.SEMICOLON:
1738 case TokenType.COLON:
1739 rollback (begin);
1740 switch (last_keyword) {
1741 case TokenType.CLASS: return parse_class_declaration (attrs);
1742 case TokenType.ENUM: return parse_enum_declaration (attrs);
1743 case TokenType.ERRORDOMAIN: return parse_errordomain_declaration (attrs);
1744 case TokenType.INTERFACE: return parse_interface_declaration (attrs);
1745 case TokenType.NAMESPACE: return parse_namespace_declaration (attrs);
1746 case TokenType.STRUCT: return parse_struct_declaration (attrs);
1747 default: break;
1749 break;
1750 case TokenType.OPEN_PARENS:
1751 rollback (begin);
1752 return parse_creation_method_declaration (attrs);
1753 default:
1754 skip_type (); // might contain type parameter list
1755 switch (current ()) {
1756 case TokenType.OPEN_PARENS:
1757 rollback (begin);
1758 switch (last_keyword) {
1759 case TokenType.DELEGATE: return parse_delegate_declaration (attrs);
1760 case TokenType.SIGNAL: return parse_signal_declaration (attrs);
1761 default: return parse_method_declaration (attrs);
1763 case TokenType.ASSIGN:
1764 case TokenType.SEMICOLON:
1765 rollback (begin);
1766 switch (last_keyword) {
1767 case TokenType.CONST: return parse_constant_declaration (attrs);
1768 default: return parse_field_declaration (attrs);
1770 case TokenType.OPEN_BRACE:
1771 rollback (begin);
1772 return parse_property_declaration (attrs);
1773 default:
1774 break;
1776 break;
1778 break;
1781 throw new ParseError.SYNTAX (get_error ("expected declaration"));
1784 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
1785 if (!root) {
1786 expect (TokenType.OPEN_BRACE);
1788 while (current () != TokenType.CLOSE_BRACE && current () != TokenType.EOF) {
1789 try {
1790 if (parent is Namespace) {
1791 parse_namespace_member ((Namespace) parent);
1792 } else if (parent is Class) {
1793 parse_class_member ((Class) parent);
1794 } else if (parent is Struct) {
1795 parse_struct_member ((Struct) parent);
1796 } else if (parent is Interface) {
1797 parse_interface_member ((Interface) parent);
1799 } catch (ParseError e) {
1800 int r;
1801 do {
1802 r = recover ();
1803 if (r == RecoveryState.STATEMENT_BEGIN) {
1804 next ();
1805 } else {
1806 break;
1808 } while (true);
1809 if (r == RecoveryState.EOF) {
1810 return;
1814 if (!root) {
1815 if (!accept (TokenType.CLOSE_BRACE)) {
1816 // only report error if it's not a secondary error
1817 if (Report.get_errors () == 0) {
1818 Report.error (get_current_src (), "expected `}'");
1824 enum RecoveryState {
1825 EOF,
1826 DECLARATION_BEGIN,
1827 STATEMENT_BEGIN
1830 RecoveryState recover () {
1831 while (current () != TokenType.EOF) {
1832 switch (current ()) {
1833 case TokenType.ABSTRACT:
1834 case TokenType.CLASS:
1835 case TokenType.CONST:
1836 case TokenType.CONSTRUCT:
1837 case TokenType.DELEGATE:
1838 case TokenType.ENUM:
1839 case TokenType.ERRORDOMAIN:
1840 case TokenType.EXTERN:
1841 case TokenType.INLINE:
1842 case TokenType.INTERFACE:
1843 case TokenType.INTERNAL:
1844 case TokenType.NAMESPACE:
1845 case TokenType.OVERRIDE:
1846 case TokenType.PRIVATE:
1847 case TokenType.PROTECTED:
1848 case TokenType.PUBLIC:
1849 case TokenType.SIGNAL:
1850 case TokenType.STATIC:
1851 case TokenType.STRUCT:
1852 case TokenType.VIRTUAL:
1853 case TokenType.VOLATILE:
1854 return RecoveryState.DECLARATION_BEGIN;
1855 case TokenType.BREAK:
1856 case TokenType.CONTINUE:
1857 case TokenType.DELETE:
1858 case TokenType.DO:
1859 case TokenType.FOR:
1860 case TokenType.FOREACH:
1861 case TokenType.IF:
1862 case TokenType.LOCK:
1863 case TokenType.RETURN:
1864 case TokenType.SWITCH:
1865 case TokenType.THROW:
1866 case TokenType.TRY:
1867 case TokenType.VAR:
1868 case TokenType.WHILE:
1869 case TokenType.YIELD:
1870 return RecoveryState.STATEMENT_BEGIN;
1871 default:
1872 next ();
1873 break;
1876 return RecoveryState.EOF;
1879 Namespace parse_namespace_declaration (Gee.List<Attribute>? attrs) throws ParseError {
1880 var begin = get_location ();
1881 expect (TokenType.NAMESPACE);
1882 var sym = parse_symbol_name ();
1883 var ns = new Namespace (sym.name, get_src_com (begin));
1884 set_attributes (ns, attrs);
1885 parse_declarations (ns);
1887 Namespace result = ns;
1888 while (sym.inner != null) {
1889 sym = sym.inner;
1890 ns = new Namespace (sym.name, result.source_reference);
1891 ns.add_namespace ((Namespace) result);
1892 result = ns;
1894 return result;
1897 void parse_namespace_member (Namespace ns) throws ParseError {
1898 var sym = parse_declaration ();
1899 if (sym is Namespace) {
1900 ns.add_namespace ((Namespace) sym);
1901 } else if (sym is Class) {
1902 ns.add_class ((Class) sym);
1903 } else if (sym is Interface) {
1904 ns.add_interface ((Interface) sym);
1905 } else if (sym is Struct) {
1906 ns.add_struct ((Struct) sym);
1907 } else if (sym is Enum) {
1908 ns.add_enum ((Enum) sym);
1909 } else if (sym is ErrorDomain) {
1910 ns.add_error_domain ((ErrorDomain) sym);
1911 } else if (sym is Delegate) {
1912 ns.add_delegate ((Delegate) sym);
1913 } else if (sym is Method) {
1914 var method = (Method) sym;
1915 if (method.binding == MemberBinding.INSTANCE) {
1916 // default to static member binding
1917 method.binding = MemberBinding.STATIC;
1919 ns.add_method (method);
1920 } else if (sym is Field) {
1921 var field = (Field) sym;
1922 if (field.binding == MemberBinding.INSTANCE) {
1923 // default to static member binding
1924 field.binding = MemberBinding.STATIC;
1926 ns.add_field (field);
1927 } else if (sym is Constant) {
1928 ns.add_constant ((Constant) sym);
1929 } else if (sym == null) {
1930 // workaround for current limitation of exception handling
1931 throw new ParseError.SYNTAX ("syntax error in declaration");
1932 } else {
1933 Report.error (sym.source_reference, "unexpected declaration in namespace");
1935 scanner.source_file.add_node (sym);
1938 void parse_using_directives () throws ParseError {
1939 while (accept (TokenType.USING)) {
1940 do {
1941 var begin = get_location ();
1942 var sym = parse_symbol_name ();
1943 var ns_ref = new UsingDirective (sym, get_src (begin));
1944 scanner.source_file.add_using_directive (ns_ref);
1945 } while (accept (TokenType.COMMA));
1946 expect (TokenType.SEMICOLON);
1950 Symbol parse_class_declaration (Gee.List<Attribute>? attrs) throws ParseError {
1951 var begin = get_location ();
1952 var access = parse_access_modifier ();
1953 var flags = parse_type_declaration_modifiers ();
1954 expect (TokenType.CLASS);
1955 var sym = parse_symbol_name ();
1956 var type_param_list = parse_type_parameter_list ();
1957 var base_types = new ArrayList<DataType> ();
1958 if (accept (TokenType.COLON)) {
1959 do {
1960 base_types.add (parse_type ());
1961 } while (accept (TokenType.COMMA));
1964 var cl = new Class (sym.name, get_src_com (begin));
1965 cl.access = access;
1966 if (ModifierFlags.ABSTRACT in flags) {
1967 cl.is_abstract = true;
1969 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
1970 cl.external = true;
1972 set_attributes (cl, attrs);
1973 foreach (TypeParameter type_param in type_param_list) {
1974 cl.add_type_parameter (type_param);
1976 foreach (DataType base_type in base_types) {
1977 cl.add_base_type (base_type);
1980 parse_declarations (cl);
1982 // ensure there is always a default construction method
1983 if (!scanner.source_file.external_package
1984 && !cl.is_abstract
1985 && cl.default_construction_method == null) {
1986 var m = new CreationMethod (cl.name, null, cl.source_reference);
1987 m.access = SymbolAccessibility.PUBLIC;
1988 m.body = new Block (cl.source_reference);
1989 cl.add_method (m);
1992 Symbol result = cl;
1993 while (sym.inner != null) {
1994 sym = sym.inner;
1995 var ns = new Namespace (sym.name, cl.source_reference);
1996 if (result is Namespace) {
1997 ns.add_namespace ((Namespace) result);
1998 } else {
1999 ns.add_class ((Class) result);
2000 scanner.source_file.add_node (result);
2002 result = ns;
2004 return result;
2007 void parse_class_member (Class cl) throws ParseError {
2008 var sym = parse_declaration ();
2009 if (sym is Class) {
2010 cl.add_class ((Class) sym);
2011 } else if (sym is Struct) {
2012 cl.add_struct ((Struct) sym);
2013 } else if (sym is Enum) {
2014 cl.add_enum ((Enum) sym);
2015 } else if (sym is Delegate) {
2016 cl.add_delegate ((Delegate) sym);
2017 } else if (sym is Method) {
2018 cl.add_method ((Method) sym);
2019 } else if (sym is Signal) {
2020 cl.add_signal ((Signal) sym);
2021 } else if (sym is Field) {
2022 cl.add_field ((Field) sym);
2023 } else if (sym is Constant) {
2024 cl.add_constant ((Constant) sym);
2025 } else if (sym is Property) {
2026 cl.add_property ((Property) sym);
2027 } else if (sym is Constructor) {
2028 var c = (Constructor) sym;
2029 if (c.binding == MemberBinding.INSTANCE) {
2030 cl.constructor = c;
2031 } else if (c.binding == MemberBinding.CLASS) {
2032 cl.class_constructor = c;
2033 } else {
2034 cl.static_constructor = c;
2036 } else if (sym is Destructor) {
2037 cl.destructor = (Destructor) sym;
2038 } else if (sym == null) {
2039 // workaround for current limitation of exception handling
2040 throw new ParseError.SYNTAX ("syntax error in declaration");
2041 } else {
2042 Report.error (sym.source_reference, "unexpected declaration in class");
2046 Constant parse_constant_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2047 var begin = get_location ();
2048 var access = parse_access_modifier ();
2049 var flags = parse_member_declaration_modifiers ();
2050 expect (TokenType.CONST);
2051 var type = parse_type (false);
2052 string id = parse_identifier ();
2053 Expression initializer = null;
2054 if (accept (TokenType.ASSIGN)) {
2055 initializer = parse_variable_initializer ();
2057 expect (TokenType.SEMICOLON);
2059 // constant arrays don't own their element
2060 var array_type = type as ArrayType;
2061 if (array_type != null) {
2062 array_type.element_type.value_owned = false;
2065 var c = new Constant (id, type, initializer, get_src_com (begin));
2066 c.access = access;
2067 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2068 c.external = true;
2070 set_attributes (c, attrs);
2071 return c;
2074 Field parse_field_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2075 var begin = get_location ();
2076 var access = parse_access_modifier ();
2077 var flags = parse_member_declaration_modifiers ();
2078 var type = parse_type ();
2079 string id = parse_identifier ();
2080 var f = new Field (id, type, null, get_src_com (begin));
2081 f.access = access;
2082 set_attributes (f, attrs);
2083 if (ModifierFlags.STATIC in flags) {
2084 f.binding = MemberBinding.STATIC;
2085 } else if (ModifierFlags.CLASS in flags) {
2086 f.binding = MemberBinding.CLASS;
2088 if (ModifierFlags.ABSTRACT in flags
2089 || ModifierFlags.VIRTUAL in flags
2090 || ModifierFlags.OVERRIDE in flags) {
2091 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2093 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2094 f.external = true;
2096 if (accept (TokenType.ASSIGN)) {
2097 f.initializer = parse_expression ();
2099 expect (TokenType.SEMICOLON);
2100 return f;
2103 InitializerList parse_initializer () throws ParseError {
2104 var begin = get_location ();
2105 expect (TokenType.OPEN_BRACE);
2106 var initializer = new InitializerList (get_src (begin));
2107 if (current () != TokenType.CLOSE_BRACE) {
2108 do {
2109 var init = parse_variable_initializer ();
2110 initializer.append (init);
2111 } while (accept (TokenType.COMMA));
2113 expect (TokenType.CLOSE_BRACE);
2114 return initializer;
2117 Expression parse_variable_initializer () throws ParseError {
2118 if (current () == TokenType.OPEN_BRACE) {
2119 var expr = parse_initializer ();
2120 return expr;
2121 } else {
2122 var expr = parse_expression ();
2123 return expr;
2127 Method parse_method_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2128 var begin = get_location ();
2129 var access = parse_access_modifier ();
2130 var flags = parse_member_declaration_modifiers ();
2131 var type = parse_type ();
2132 string id = parse_identifier ();
2133 parse_type_parameter_list ();
2134 var method = new Method (id, type, get_src_com (begin));
2135 method.access = access;
2136 set_attributes (method, attrs);
2137 if (ModifierFlags.STATIC in flags) {
2138 method.binding = MemberBinding.STATIC;
2139 } else if (ModifierFlags.CLASS in flags) {
2140 method.binding = MemberBinding.CLASS;
2143 if (method.binding == MemberBinding.INSTANCE) {
2144 if (ModifierFlags.ABSTRACT in flags) {
2145 method.is_abstract = true;
2147 if (ModifierFlags.VIRTUAL in flags) {
2148 method.is_virtual = true;
2150 if (ModifierFlags.OVERRIDE in flags) {
2151 method.overrides = true;
2153 if ((method.is_abstract && method.is_virtual)
2154 || (method.is_abstract && method.overrides)
2155 || (method.is_virtual && method.overrides)) {
2156 throw new ParseError.SYNTAX (get_error ("only one of `abstract', `virtual', or `override' may be specified"));
2158 } else {
2159 if (ModifierFlags.ABSTRACT in flags
2160 || ModifierFlags.VIRTUAL in flags
2161 || ModifierFlags.OVERRIDE in flags) {
2162 throw new ParseError.SYNTAX (get_error ("the modifiers `abstract', `virtual', and `override' are not valid for static methods"));
2166 if (ModifierFlags.INLINE in flags) {
2167 method.is_inline = true;
2169 if (ModifierFlags.EXTERN in flags) {
2170 method.external = true;
2172 expect (TokenType.OPEN_PARENS);
2173 if (current () != TokenType.CLOSE_PARENS) {
2174 do {
2175 var param = parse_parameter ();
2176 method.add_parameter (param);
2177 } while (accept (TokenType.COMMA));
2179 expect (TokenType.CLOSE_PARENS);
2180 if (accept (TokenType.YIELDS)) {
2181 method.coroutine = true;
2183 if (accept (TokenType.THROWS)) {
2184 do {
2185 method.add_error_type (parse_type ());
2186 } while (accept (TokenType.COMMA));
2188 while (accept (TokenType.REQUIRES)) {
2189 expect (TokenType.OPEN_PARENS);
2190 method.add_precondition (parse_expression ());
2191 expect (TokenType.CLOSE_PARENS);
2193 while (accept (TokenType.ENSURES)) {
2194 expect (TokenType.OPEN_PARENS);
2195 method.add_postcondition (parse_expression ());
2196 expect (TokenType.CLOSE_PARENS);
2198 if (!accept (TokenType.SEMICOLON)) {
2199 method.body = parse_block ();
2200 } else if (scanner.source_file.external_package) {
2201 method.external = true;
2203 return method;
2206 Property parse_property_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2207 var begin = get_location ();
2208 var access = parse_access_modifier ();
2209 var flags = parse_member_declaration_modifiers ();
2210 bool is_weak = accept (TokenType.WEAK);
2211 var type = parse_type (false);
2212 string id = parse_identifier ();
2213 var prop = new Property (id, type, null, null, get_src_com (begin));
2214 prop.access = access;
2215 set_attributes (prop, attrs);
2216 if (ModifierFlags.STATIC in flags) {
2217 prop.binding = MemberBinding.STATIC;
2218 } else if (ModifierFlags.CLASS in flags) {
2219 prop.binding = MemberBinding.CLASS;
2221 if (ModifierFlags.ABSTRACT in flags) {
2222 prop.is_abstract = true;
2224 if (ModifierFlags.VIRTUAL in flags) {
2225 prop.is_virtual = true;
2227 if (ModifierFlags.OVERRIDE in flags) {
2228 prop.overrides = true;
2230 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2231 prop.external = true;
2233 expect (TokenType.OPEN_BRACE);
2234 while (current () != TokenType.CLOSE_BRACE) {
2235 if (accept (TokenType.DEFAULT)) {
2236 if (prop.default_expression != null) {
2237 throw new ParseError.SYNTAX (get_error ("property default value already defined"));
2239 if (accept (TokenType.OPEN_PARENS)) {
2240 Report.warning (get_last_src (), "deprecated syntax, use `default = value;`");
2241 prop.default_expression = parse_expression ();
2242 expect (TokenType.CLOSE_PARENS);
2243 } else {
2244 expect (TokenType.ASSIGN);
2245 prop.default_expression = parse_expression ();
2247 expect (TokenType.SEMICOLON);
2248 } else {
2249 var accessor_begin = get_location ();
2250 var attrs = parse_attributes ();
2251 var accessor_access = parse_access_modifier (SymbolAccessibility.PUBLIC);
2252 if (accept (TokenType.GET)) {
2253 if (prop.get_accessor != null) {
2254 throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
2256 Block block = null;
2257 if (!accept (TokenType.SEMICOLON)) {
2258 block = parse_block ();
2259 prop.external = false;
2261 prop.get_accessor = new PropertyAccessor (true, false, false, block, get_src (accessor_begin));
2262 set_attributes (prop.get_accessor, attrs);
2263 prop.get_accessor.access = accessor_access;
2264 } else {
2265 bool writable, _construct;
2266 if (accept (TokenType.SET)) {
2267 writable = true;
2268 _construct = accept (TokenType.CONSTRUCT);
2269 } else if (accept (TokenType.CONSTRUCT)) {
2270 _construct = true;
2271 writable = accept (TokenType.SET);
2272 } else {
2273 throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
2275 if (prop.set_accessor != null) {
2276 throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
2278 Block block = null;
2279 if (!accept (TokenType.SEMICOLON)) {
2280 block = parse_block ();
2281 prop.external = false;
2283 prop.set_accessor = new PropertyAccessor (false, writable, _construct, block, get_src (accessor_begin));
2284 set_attributes (prop.set_accessor, attrs);
2285 prop.set_accessor.access = accessor_access;
2289 expect (TokenType.CLOSE_BRACE);
2291 if (!prop.is_abstract && !scanner.source_file.external_package) {
2292 bool empty_get = (prop.get_accessor != null && prop.get_accessor.body == null);
2293 bool empty_set = (prop.set_accessor != null && prop.set_accessor.body == null);
2295 if (empty_get != empty_set) {
2296 if (empty_get) {
2297 Report.error (prop.source_reference, "property getter must have a body");
2298 } else if (empty_set) {
2299 Report.error (prop.source_reference, "property setter must have a body");
2301 prop.error = true;
2304 if (empty_get && empty_set) {
2305 /* automatic property accessor body generation */
2306 var field_type = prop.property_type.copy ();
2307 field_type.value_owned = !is_weak;
2308 prop.field = new Field ("_%s".printf (prop.name), field_type, prop.default_expression, prop.source_reference);
2309 prop.field.access = SymbolAccessibility.PRIVATE;
2313 return prop;
2316 Signal parse_signal_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2317 var begin = get_location ();
2318 var access = parse_access_modifier ();
2319 var flags = parse_member_declaration_modifiers ();
2320 expect (TokenType.SIGNAL);
2321 var type = parse_type ();
2322 string id = parse_identifier ();
2323 var sig = new Signal (id, type, get_src_com (begin));
2324 sig.access = access;
2325 set_attributes (sig, attrs);
2326 if (ModifierFlags.VIRTUAL in flags) {
2327 sig.is_virtual = true;
2329 expect (TokenType.OPEN_PARENS);
2330 if (current () != TokenType.CLOSE_PARENS) {
2331 do {
2332 var param = parse_parameter ();
2333 sig.add_parameter (param);
2334 } while (accept (TokenType.COMMA));
2336 expect (TokenType.CLOSE_PARENS);
2337 expect (TokenType.SEMICOLON);
2338 return sig;
2341 Constructor parse_constructor_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2342 var begin = get_location ();
2343 var flags = parse_member_declaration_modifiers ();
2344 expect (TokenType.CONSTRUCT);
2345 var c = new Constructor (get_src_com (begin));
2346 if (ModifierFlags.STATIC in flags) {
2347 c.binding = MemberBinding.STATIC;
2348 } else if (ModifierFlags.CLASS in flags) {
2349 c.binding = MemberBinding.CLASS;
2351 c.body = parse_block ();
2352 return c;
2355 Destructor parse_destructor_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2356 var begin = get_location ();
2357 expect (TokenType.TILDE);
2358 parse_identifier ();
2359 expect (TokenType.OPEN_PARENS);
2360 expect (TokenType.CLOSE_PARENS);
2361 var d = new Destructor (get_src_com (begin));
2362 d.body = parse_block ();
2363 return d;
2366 Symbol parse_struct_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2367 var begin = get_location ();
2368 var access = parse_access_modifier ();
2369 var flags = parse_type_declaration_modifiers ();
2370 expect (TokenType.STRUCT);
2371 var sym = parse_symbol_name ();
2372 var type_param_list = parse_type_parameter_list ();
2373 var base_types = new ArrayList<DataType> ();
2374 if (accept (TokenType.COLON)) {
2375 do {
2376 base_types.add (parse_type ());
2377 } while (accept (TokenType.COMMA));
2379 var st = new Struct (sym.name, get_src_com (begin));
2380 st.access = access;
2381 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2382 st.external = true;
2384 set_attributes (st, attrs);
2385 foreach (TypeParameter type_param in type_param_list) {
2386 st.add_type_parameter (type_param);
2388 foreach (DataType base_type in base_types) {
2389 st.add_base_type (base_type);
2392 parse_declarations (st);
2394 Symbol result = st;
2395 while (sym.inner != null) {
2396 sym = sym.inner;
2397 var ns = new Namespace (sym.name, st.source_reference);
2398 if (result is Namespace) {
2399 ns.add_namespace ((Namespace) result);
2400 } else {
2401 ns.add_struct ((Struct) result);
2402 scanner.source_file.add_node (result);
2404 result = ns;
2406 return result;
2409 void parse_struct_member (Struct st) throws ParseError {
2410 var sym = parse_declaration ();
2411 if (sym is Method) {
2412 st.add_method ((Method) sym);
2413 } else if (sym is Field) {
2414 st.add_field ((Field) sym);
2415 } else if (sym is Constant) {
2416 st.add_constant ((Constant) sym);
2417 } else if (sym == null) {
2418 // workaround for current limitation of exception handling
2419 throw new ParseError.SYNTAX ("syntax error in declaration");
2420 } else {
2421 Report.error (sym.source_reference, "unexpected declaration in struct");
2425 Symbol parse_interface_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2426 var begin = get_location ();
2427 var access = parse_access_modifier ();
2428 var flags = parse_type_declaration_modifiers ();
2429 expect (TokenType.INTERFACE);
2430 var sym = parse_symbol_name ();
2431 var type_param_list = parse_type_parameter_list ();
2432 var base_types = new ArrayList<DataType> ();
2433 if (accept (TokenType.COLON)) {
2434 do {
2435 var type = parse_type ();
2436 base_types.add (type);
2437 } while (accept (TokenType.COMMA));
2439 var iface = new Interface (sym.name, get_src_com (begin));
2440 iface.access = access;
2441 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2442 iface.external = true;
2444 set_attributes (iface, attrs);
2445 foreach (TypeParameter type_param in type_param_list) {
2446 iface.add_type_parameter (type_param);
2448 foreach (DataType base_type in base_types) {
2449 iface.add_prerequisite (base_type);
2452 parse_declarations (iface);
2454 Symbol result = iface;
2455 while (sym.inner != null) {
2456 sym = sym.inner;
2457 var ns = new Namespace (sym.name, iface.source_reference);
2458 if (result is Namespace) {
2459 ns.add_namespace ((Namespace) result);
2460 } else {
2461 ns.add_interface ((Interface) result);
2462 scanner.source_file.add_node (result);
2464 result = ns;
2466 return result;
2469 void parse_interface_member (Interface iface) throws ParseError {
2470 var sym = parse_declaration ();
2471 if (sym is Class) {
2472 iface.add_class ((Class) sym);
2473 } else if (sym is Struct) {
2474 iface.add_struct ((Struct) sym);
2475 } else if (sym is Enum) {
2476 iface.add_enum ((Enum) sym);
2477 } else if (sym is Delegate) {
2478 iface.add_delegate ((Delegate) sym);
2479 } else if (sym is Method) {
2480 iface.add_method ((Method) sym);
2481 } else if (sym is Signal) {
2482 iface.add_signal ((Signal) sym);
2483 } else if (sym is Field) {
2484 iface.add_field ((Field) sym);
2485 } else if (sym is Property) {
2486 iface.add_property ((Property) sym);
2487 } else if (sym == null) {
2488 // workaround for current limitation of exception handling
2489 throw new ParseError.SYNTAX ("syntax error in declaration");
2490 } else {
2491 Report.error (sym.source_reference, "unexpected declaration in interface");
2495 Symbol parse_enum_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2496 var begin = get_location ();
2497 var access = parse_access_modifier ();
2498 var flags = parse_type_declaration_modifiers ();
2499 expect (TokenType.ENUM);
2500 var sym = parse_symbol_name ();
2501 var en = new Enum (sym.name, get_src_com (begin));
2502 en.access = access;
2503 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2504 en.external = true;
2506 set_attributes (en, attrs);
2508 expect (TokenType.OPEN_BRACE);
2509 do {
2510 if (current () == TokenType.CLOSE_BRACE) {
2511 // allow trailing comma
2512 break;
2514 var value_attrs = parse_attributes ();
2515 var value_begin = get_location ();
2516 string id = parse_identifier ();
2517 var ev = new EnumValue (id, get_src (value_begin));
2518 set_attributes (ev, value_attrs);
2519 if (accept (TokenType.ASSIGN)) {
2520 ev.value = parse_expression ();
2522 en.add_value (ev);
2523 } while (accept (TokenType.COMMA));
2524 if (accept (TokenType.SEMICOLON)) {
2525 // enum methods
2526 while (current () != TokenType.CLOSE_BRACE) {
2527 var sym = parse_declaration ();
2528 if (sym is Method) {
2529 en.add_method ((Method) sym);
2530 } else if (sym == null) {
2531 // workaround for current limitation of exception handling
2532 throw new ParseError.SYNTAX ("syntax error in declaration");
2533 } else {
2534 Report.error (sym.source_reference, "unexpected declaration in enum");
2538 expect (TokenType.CLOSE_BRACE);
2540 Symbol result = en;
2541 while (sym.inner != null) {
2542 sym = sym.inner;
2543 var ns = new Namespace (sym.name, en.source_reference);
2544 if (result is Namespace) {
2545 ns.add_namespace ((Namespace) result);
2546 } else {
2547 ns.add_enum ((Enum) result);
2548 scanner.source_file.add_node (result);
2550 result = ns;
2552 return result;
2555 Symbol parse_errordomain_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2556 var begin = get_location ();
2557 var access = parse_access_modifier ();
2558 var flags = parse_type_declaration_modifiers ();
2559 expect (TokenType.ERRORDOMAIN);
2560 var sym = parse_symbol_name ();
2561 var ed = new ErrorDomain (sym.name, get_src_com (begin));
2562 ed.access = access;
2563 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2564 ed.external = true;
2566 set_attributes (ed, attrs);
2568 expect (TokenType.OPEN_BRACE);
2569 do {
2570 if (current () == TokenType.CLOSE_BRACE) {
2571 // allow trailing comma
2572 break;
2574 var code_attrs = parse_attributes ();
2575 var code_begin = get_location ();
2576 string id = parse_identifier ();
2577 var ec = new ErrorCode (id, get_src (code_begin));
2578 set_attributes (ec, code_attrs);
2579 if (accept (TokenType.ASSIGN)) {
2580 ec.value = parse_expression ();
2582 ed.add_code (ec);
2583 } while (accept (TokenType.COMMA));
2584 if (accept (TokenType.SEMICOLON)) {
2585 // errordomain methods
2586 while (current () != TokenType.CLOSE_BRACE) {
2587 var sym = parse_declaration ();
2588 if (sym is Method) {
2589 ed.add_method ((Method) sym);
2590 } else if (sym == null) {
2591 // workaround for current limitation of exception handling
2592 throw new ParseError.SYNTAX ("syntax error in declaration");
2593 } else {
2594 Report.error (sym.source_reference, "unexpected declaration in errordomain");
2598 expect (TokenType.CLOSE_BRACE);
2600 Symbol result = ed;
2601 while (sym.inner != null) {
2602 sym = sym.inner;
2603 var ns = new Namespace (sym.name, ed.source_reference);
2604 if (result is Namespace) {
2605 ns.add_namespace ((Namespace) result);
2606 } else {
2607 ns.add_error_domain ((ErrorDomain) result);
2608 scanner.source_file.add_node (result);
2610 result = ns;
2612 return result;
2615 SymbolAccessibility parse_access_modifier (SymbolAccessibility default_access = SymbolAccessibility.PRIVATE) {
2616 switch (current ()) {
2617 case TokenType.PRIVATE:
2618 next ();
2619 return SymbolAccessibility.PRIVATE;
2620 case TokenType.PROTECTED:
2621 next ();
2622 return SymbolAccessibility.PROTECTED;
2623 case TokenType.INTERNAL:
2624 next ();
2625 return SymbolAccessibility.INTERNAL;
2626 case TokenType.PUBLIC:
2627 next ();
2628 return SymbolAccessibility.PUBLIC;
2629 default:
2630 return default_access;
2634 ModifierFlags parse_type_declaration_modifiers () {
2635 ModifierFlags flags = 0;
2636 while (true) {
2637 switch (current ()) {
2638 case TokenType.ABSTRACT:
2639 next ();
2640 flags |= ModifierFlags.ABSTRACT;
2641 break;
2642 case TokenType.EXTERN:
2643 next ();
2644 flags |= ModifierFlags.EXTERN;
2645 break;
2646 case TokenType.STATIC:
2647 next ();
2648 flags |= ModifierFlags.STATIC;
2649 break;
2650 default:
2651 return flags;
2654 return flags;
2657 ModifierFlags parse_member_declaration_modifiers () {
2658 ModifierFlags flags = 0;
2659 while (true) {
2660 switch (current ()) {
2661 case TokenType.ABSTRACT:
2662 next ();
2663 flags |= ModifierFlags.ABSTRACT;
2664 break;
2665 case TokenType.CLASS:
2666 next ();
2667 flags |= ModifierFlags.CLASS;
2668 break;
2669 case TokenType.EXTERN:
2670 next ();
2671 flags |= ModifierFlags.EXTERN;
2672 break;
2673 case TokenType.INLINE:
2674 next ();
2675 flags |= ModifierFlags.INLINE;
2676 break;
2677 case TokenType.OVERRIDE:
2678 next ();
2679 flags |= ModifierFlags.OVERRIDE;
2680 break;
2681 case TokenType.STATIC:
2682 next ();
2683 flags |= ModifierFlags.STATIC;
2684 break;
2685 case TokenType.VIRTUAL:
2686 next ();
2687 flags |= ModifierFlags.VIRTUAL;
2688 break;
2689 default:
2690 return flags;
2693 return flags;
2696 FormalParameter parse_parameter () throws ParseError {
2697 var attrs = parse_attributes ();
2698 var begin = get_location ();
2699 if (accept (TokenType.ELLIPSIS)) {
2700 // varargs
2701 return new FormalParameter.with_ellipsis (get_src (begin));
2703 bool params_array = accept (TokenType.PARAMS);
2704 bool construct_param = false;
2705 if (accept (TokenType.CONSTRUCT)) {
2706 Report.warning (get_last_src (), "deprecated syntax, use assignments in the method body");
2707 construct_param = true;
2709 var direction = ParameterDirection.IN;
2710 if (accept (TokenType.OUT)) {
2711 direction = ParameterDirection.OUT;
2712 } else if (accept (TokenType.REF)) {
2713 direction = ParameterDirection.REF;
2716 DataType type;
2717 if (direction == ParameterDirection.IN) {
2718 // in parameters are weak by default
2719 type = parse_type (false);
2720 } else {
2721 // out parameters own the value by default
2722 type = parse_type (true);
2724 string id = parse_identifier ();
2725 var param = new FormalParameter (id, type, get_src (begin));
2726 set_attributes (param, attrs);
2727 param.direction = direction;
2728 param.params_array = params_array;
2729 param.construct_parameter = construct_param;
2730 if (accept (TokenType.ASSIGN)) {
2731 param.default_expression = parse_expression ();
2733 return param;
2736 CreationMethod parse_creation_method_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2737 var begin = get_location ();
2738 var access = parse_access_modifier ();
2739 var flags = parse_member_declaration_modifiers ();
2740 var sym = parse_symbol_name ();
2741 CreationMethod method;
2742 if (sym.inner == null) {
2743 method = new CreationMethod (sym.name, null, get_src_com (begin));
2744 } else {
2745 method = new CreationMethod (sym.inner.name, sym.name, get_src_com (begin));
2747 if (ModifierFlags.EXTERN in flags) {
2748 method.external = true;
2750 expect (TokenType.OPEN_PARENS);
2751 if (current () != TokenType.CLOSE_PARENS) {
2752 do {
2753 var param = parse_parameter ();
2754 method.add_parameter (param);
2755 } while (accept (TokenType.COMMA));
2757 expect (TokenType.CLOSE_PARENS);
2758 if (accept (TokenType.YIELDS)) {
2759 method.coroutine = true;
2761 if (accept (TokenType.THROWS)) {
2762 do {
2763 method.add_error_type (parse_type ());
2764 } while (accept (TokenType.COMMA));
2766 method.access = access;
2767 set_attributes (method, attrs);
2768 if (!accept (TokenType.SEMICOLON)) {
2769 method.body = parse_block ();
2770 } else if (scanner.source_file.external_package) {
2771 method.external = true;
2773 return method;
2776 Symbol parse_delegate_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2777 var begin = get_location ();
2778 var access = parse_access_modifier ();
2779 var flags = parse_member_declaration_modifiers ();
2780 expect (TokenType.DELEGATE);
2781 var type = parse_type ();
2782 var sym = parse_symbol_name ();
2783 var type_param_list = parse_type_parameter_list ();
2784 var d = new Delegate (sym.name, type, get_src_com (begin));
2785 d.access = access;
2786 set_attributes (d, attrs);
2787 if (!(ModifierFlags.STATIC in flags)) {
2788 d.has_target = true;
2790 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2791 d.external = true;
2793 foreach (TypeParameter type_param in type_param_list) {
2794 d.add_type_parameter (type_param);
2796 expect (TokenType.OPEN_PARENS);
2797 if (current () != TokenType.CLOSE_PARENS) {
2798 do {
2799 var param = parse_parameter ();
2800 d.add_parameter (param);
2801 } while (accept (TokenType.COMMA));
2803 expect (TokenType.CLOSE_PARENS);
2804 if (accept (TokenType.THROWS)) {
2805 do {
2806 parse_type ();
2807 } while (accept (TokenType.COMMA));
2809 expect (TokenType.SEMICOLON);
2811 Symbol result = d;
2812 while (sym.inner != null) {
2813 sym = sym.inner;
2814 var ns = new Namespace (sym.name, d.source_reference);
2815 if (result is Namespace) {
2816 ns.add_namespace ((Namespace) result);
2817 } else {
2818 ns.add_delegate ((Delegate) result);
2819 scanner.source_file.add_node (result);
2821 result = ns;
2823 return result;
2826 Gee.List<TypeParameter> parse_type_parameter_list () throws ParseError {
2827 var list = new ArrayList<TypeParameter> ();
2828 if (accept (TokenType.OP_LT)) {
2829 do {
2830 var begin = get_location ();
2831 string id = parse_identifier ();
2832 list.add (new TypeParameter (id, get_src (begin)));
2833 } while (accept (TokenType.COMMA));
2834 expect (TokenType.OP_GT);
2836 return list;
2839 void skip_type_argument_list () throws ParseError {
2840 if (accept (TokenType.OP_LT)) {
2841 do {
2842 skip_type ();
2843 } while (accept (TokenType.COMMA));
2844 expect (TokenType.OP_GT);
2848 // try to parse type argument list
2849 Gee.List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
2850 var begin = get_location ();
2851 if (accept (TokenType.OP_LT)) {
2852 var list = new ArrayList<DataType> ();
2853 do {
2854 switch (current ()) {
2855 case TokenType.VOID:
2856 case TokenType.DYNAMIC:
2857 case TokenType.WEAK:
2858 case TokenType.IDENTIFIER:
2859 var type = parse_type ();
2860 list.add (type);
2861 break;
2862 default:
2863 rollback (begin);
2864 return null;
2866 } while (accept (TokenType.COMMA));
2867 if (!accept (TokenType.OP_GT)) {
2868 rollback (begin);
2869 return null;
2871 if (maybe_expression) {
2872 // check follower to decide whether to keep type argument list
2873 switch (current ()) {
2874 case TokenType.OPEN_PARENS:
2875 case TokenType.CLOSE_PARENS:
2876 case TokenType.CLOSE_BRACKET:
2877 case TokenType.COLON:
2878 case TokenType.SEMICOLON:
2879 case TokenType.COMMA:
2880 case TokenType.DOT:
2881 case TokenType.INTERR:
2882 case TokenType.OP_EQ:
2883 case TokenType.OP_NE:
2884 // keep type argument list
2885 break;
2886 default:
2887 // interpret tokens as expression
2888 rollback (begin);
2889 return null;
2892 return list;
2894 return null;
2897 MemberAccess parse_member_name () throws ParseError {
2898 var begin = get_location ();
2899 MemberAccess expr = null;
2900 bool first = true;
2901 do {
2902 string id = parse_identifier ();
2904 // The first member access can be global:: qualified
2905 bool qualified = false;
2906 if (first && id == "global" && accept (TokenType.DOUBLE_COLON)) {
2907 id = parse_identifier ();
2908 qualified = true;
2911 Gee.List<DataType> type_arg_list = parse_type_argument_list (false);
2912 expr = new MemberAccess (expr, id, get_src (begin));
2913 expr.qualified = qualified;
2914 if (type_arg_list != null) {
2915 foreach (DataType type_arg in type_arg_list) {
2916 expr.add_type_argument (type_arg);
2920 first = false;
2921 } while (accept (TokenType.DOT));
2922 return expr;
2925 bool is_declaration_keyword (TokenType type) {
2926 switch (type) {
2927 case TokenType.ABSTRACT:
2928 case TokenType.CLASS:
2929 case TokenType.CONST:
2930 case TokenType.DELEGATE:
2931 case TokenType.ENUM:
2932 case TokenType.ERRORDOMAIN:
2933 case TokenType.EXTERN:
2934 case TokenType.INLINE:
2935 case TokenType.INTERFACE:
2936 case TokenType.INTERNAL:
2937 case TokenType.NAMESPACE:
2938 case TokenType.OVERRIDE:
2939 case TokenType.PRIVATE:
2940 case TokenType.PROTECTED:
2941 case TokenType.PUBLIC:
2942 case TokenType.SIGNAL:
2943 case TokenType.STATIC:
2944 case TokenType.STRUCT:
2945 case TokenType.VIRTUAL:
2946 case TokenType.VOLATILE:
2947 return true;
2948 default:
2949 return false;
2954 public errordomain Vala.ParseError {
2955 FAILED,
2956 SYNTAX