Release 0.7.8
[vala-lang.git] / vala / valagenieparser.vala
blobaa94c12409145970c215e48a6f74df6b3c8b24c8
1 /* valagenieparser.vala
3 * Copyright (C) 2008 Jamie McCracken, Jürg Billeter
4 * Based on code by Jürg Billeter
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jamie McCracken jamiemcc gnome org
24 using GLib;
27 /**
28 * Code visitor parsing all Genie source files.
30 public class Vala.Genie.Parser : CodeVisitor {
31 Scanner scanner;
33 CodeContext context;
35 // token buffer
36 TokenInfo[] tokens;
37 // index of current token in buffer
38 int index;
39 // number of tokens in buffer
40 int size;
42 Comment comment;
44 string class_name;
46 /* hack needed to know if any part of an expression is a lambda one */
47 bool current_expr_is_lambda;
49 const int BUFFER_SIZE = 32;
51 struct TokenInfo {
52 public TokenType type;
53 public SourceLocation begin;
54 public SourceLocation end;
57 enum ModifierFlags {
58 NONE,
59 ABSTRACT = 1 << 0,
60 CLASS = 1 << 1,
61 EXTERN = 1 << 2,
62 INLINE = 1 << 3,
63 NEW = 1 << 4,
64 OVERRIDE = 1 << 5,
65 STATIC = 1 << 6,
66 VIRTUAL = 1 << 7,
67 PRIVATE = 1 << 8,
68 ASYNC = 1 << 9
71 public Parser () {
72 tokens = new TokenInfo[BUFFER_SIZE];
73 class_name = null;
74 current_expr_is_lambda = false;
77 /**
78 * Parses all .gs source files in the specified code context and
79 * builds a code tree.
81 * @param context a code context
83 public void parse (CodeContext context) {
84 this.context = context;
85 context.accept (this);
88 public override void visit_source_file (SourceFile source_file) {
89 if (source_file.filename.has_suffix (".gs")) {
90 parse_file (source_file);
94 inline bool next () {
95 index = (index + 1) % BUFFER_SIZE;
96 size--;
97 if (size <= 0) {
98 SourceLocation begin, end;
99 TokenType type = scanner.read_token (out begin, out end);
100 tokens[index].type = type;
101 tokens[index].begin = begin;
102 tokens[index].end = end;
103 size = 1;
105 return (tokens[index].type != TokenType.EOF);
108 inline void prev () {
109 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
110 size++;
111 assert (size <= BUFFER_SIZE);
114 inline TokenType current () {
115 return tokens[index].type;
118 inline bool accept (TokenType type) {
119 if (current () == type) {
120 next ();
121 return true;
123 return false;
126 inline bool accept_terminator () {
127 if (current () == TokenType.SEMICOLON || current () == TokenType.EOL) {
128 next ();
129 return true;
131 return false;
134 inline bool accept_block () {
136 bool has_term = accept_terminator ();
138 if (accept (TokenType.INDENT)) {
139 prev();
140 return true;
143 if (has_term) {
144 prev ();
147 return false;
150 string get_error (string msg) {
151 var begin = get_location ();
152 next ();
153 Report.error (get_src (begin), "syntax error, " + msg);
154 return msg;
157 inline bool expect (TokenType type) throws ParseError {
158 if (accept (type)) {
159 return true;
162 TokenType cur = current ();
163 TokenType pre = tokens[index - 1].type;
165 throw new ParseError.SYNTAX (get_error ("expected %s but got %s with previous %s".printf (type.to_string (), cur.to_string (), pre.to_string())));
168 inline bool expect_terminator () throws ParseError {
169 if (accept_terminator ()) {
170 return true;
173 TokenType cur = current ();
175 throw new ParseError.SYNTAX (get_error ("expected line end or semicolon but got %s".printf (cur.to_string())));
178 inline SourceLocation get_location () {
179 return tokens[index].begin;
182 string get_current_string () {
183 return ((string) tokens[index].begin.pos).ndup ((tokens[index].end.pos - tokens[index].begin.pos));
186 string get_last_string () {
187 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
188 return ((string) tokens[last_index].begin.pos).ndup ((tokens[last_index].end.pos - tokens[last_index].begin.pos));
191 SourceReference get_src (SourceLocation begin) {
192 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
194 return new SourceReference (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
197 SourceReference get_current_src () {
198 return new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column);
201 void rollback (SourceLocation location) {
202 while (tokens[index].begin.pos != location.pos) {
203 prev ();
207 inline SymbolAccessibility get_access (string s) {
208 if (s[0] == '_') {
209 return SymbolAccessibility.PRIVATE;
212 return SymbolAccessibility.PUBLIC;
215 void skip_identifier () throws ParseError {
216 // also accept keywords as identifiers where there is no conflict
217 switch (current ()) {
218 case TokenType.ABSTRACT:
219 case TokenType.AS:
220 case TokenType.ASSERT:
221 case TokenType.ASYNC:
222 case TokenType.BREAK:
223 case TokenType.CLASS:
224 case TokenType.CONST:
225 case TokenType.CONTINUE:
226 case TokenType.DEDENT:
227 case TokenType.DEF:
228 case TokenType.DEFAULT:
229 case TokenType.DELEGATE:
230 case TokenType.DELETE:
231 case TokenType.DO:
232 case TokenType.DOWNTO:
233 case TokenType.DYNAMIC:
234 case TokenType.ELSE:
235 case TokenType.EOL:
236 case TokenType.ENUM:
237 case TokenType.ENSURES:
238 case TokenType.ERRORDOMAIN:
239 case TokenType.EVENT:
240 case TokenType.EXCEPT:
241 case TokenType.EXTERN:
242 case TokenType.FALSE:
243 case TokenType.FINAL:
244 case TokenType.FINALLY:
245 case TokenType.FOR:
246 case TokenType.GET:
247 case TokenType.IDENTIFIER:
248 case TokenType.IF:
249 case TokenType.IN:
250 case TokenType.INDENT:
251 case TokenType.INIT:
252 case TokenType.INLINE:
253 case TokenType.INTERFACE:
254 case TokenType.INTERNAL:
255 case TokenType.IS:
256 case TokenType.ISA:
257 case TokenType.LOCK:
258 case TokenType.NAMESPACE:
259 case TokenType.NEW:
260 case TokenType.NULL:
261 case TokenType.OF:
262 case TokenType.OUT:
263 case TokenType.OVERRIDE:
264 case TokenType.OWNED:
265 case TokenType.PASS:
266 case TokenType.PRINT:
267 case TokenType.PRIVATE:
268 case TokenType.PROP:
269 case TokenType.RAISE:
270 case TokenType.RAISES:
271 case TokenType.REF:
272 case TokenType.REQUIRES:
273 case TokenType.RETURN:
274 case TokenType.SET:
275 case TokenType.SIZEOF:
276 case TokenType.STATIC:
277 case TokenType.STRUCT:
278 case TokenType.SUPER:
279 case TokenType.THIS:
280 case TokenType.TO:
281 case TokenType.TRUE:
282 case TokenType.TRY:
283 case TokenType.TYPEOF:
284 case TokenType.UNOWNED:
285 case TokenType.USES:
286 case TokenType.VAR:
287 case TokenType.VIRTUAL:
288 case TokenType.VOID:
289 case TokenType.VOLATILE:
290 case TokenType.WEAK:
291 case TokenType.WHEN:
292 case TokenType.WHILE:
293 case TokenType.YIELD:
294 next ();
295 return;
296 case TokenType.INTEGER_LITERAL:
297 case TokenType.REAL_LITERAL:
298 // also accept integer and real literals
299 // as long as they contain at least one character
300 // and no decimal point
301 // for example, 2D and 3D
302 string id = get_current_string ();
303 if (id[id.length - 1].isalpha () && !("." in id)) {
304 next ();
305 return;
307 break;
308 default:
309 throw new ParseError.SYNTAX (get_error ("expected identifier"));
313 string parse_identifier () throws ParseError {
314 skip_identifier ();
315 return get_last_string ();
318 Expression parse_literal () throws ParseError {
319 var begin = get_location ();
321 switch (current ()) {
322 case TokenType.TRUE:
323 next ();
324 return new BooleanLiteral (true, get_src (begin));
325 case TokenType.FALSE:
326 next ();
327 return new BooleanLiteral (false, get_src (begin));
328 case TokenType.INTEGER_LITERAL:
329 next ();
330 return new IntegerLiteral (get_last_string (), get_src (begin));
331 case TokenType.REAL_LITERAL:
332 next ();
333 return new RealLiteral (get_last_string (), get_src (begin));
334 case TokenType.CHARACTER_LITERAL:
335 next ();
336 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
337 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
338 if (lit.error) {
339 Report.error (lit.source_reference, "invalid character literal");
341 return lit;
342 case TokenType.STRING_LITERAL:
343 next ();
344 return new StringLiteral (get_last_string (), get_src (begin));
345 case TokenType.VERBATIM_STRING_LITERAL:
346 next ();
347 string raw_string = get_last_string ();
348 string escaped_string = raw_string.substring (3, raw_string.len () - 6).escape ("");
349 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
350 case TokenType.NULL:
351 next ();
352 return new NullLiteral (get_src (begin));
353 default:
354 throw new ParseError.SYNTAX (get_error ("expected literal"));
358 public void parse_file (SourceFile source_file) {
359 scanner = new Scanner (source_file);
360 scanner.parse_file_comments ();
361 scanner.indent_spaces = 0;
362 index = -1;
363 size = 0;
365 next ();
367 try {
368 var begin = get_location ();
369 /* see if there is an indent attribute */
370 if (accept (TokenType.OPEN_BRACKET)) {
371 var id = parse_identifier ();
372 if (id == "indent") {
373 expect (TokenType.ASSIGN);
374 expect (TokenType.INTEGER_LITERAL);
375 scanner.indent_spaces = get_last_string().to_int();
376 expect (TokenType.CLOSE_BRACKET);
377 expect (TokenType.EOL);
378 } else {
379 rollback (begin);
383 parse_using_directives (context.root);
384 parse_declarations (context.root, true);
385 } catch (ParseError e) {
386 // already reported
389 scanner = null;
392 void skip_symbol_name () throws ParseError {
393 do {
394 skip_identifier ();
395 } while (accept (TokenType.DOT));
398 UnresolvedSymbol parse_symbol_name () throws ParseError {
399 var begin = get_location ();
400 UnresolvedSymbol sym = null;
401 do {
402 string name = parse_identifier ();
403 sym = new UnresolvedSymbol (sym, name, get_src (begin));
404 } while (accept (TokenType.DOT));
405 return sym;
408 void skip_type () throws ParseError {
409 if (accept (TokenType.VOID)) {
410 while (accept (TokenType.STAR)) {
412 return;
414 accept (TokenType.DYNAMIC);
415 accept (TokenType.OWNED);
416 accept (TokenType.UNOWNED);
417 accept (TokenType.WEAK);
418 if (accept (TokenType.ARRAY) || accept (TokenType.LIST) || accept (TokenType.DICT)) {
419 accept (TokenType.OF);
422 skip_symbol_name ();
423 skip_type_argument_list ();
424 while (accept (TokenType.OPEN_BRACKET)) {
425 do {
426 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
427 parse_expression ();
429 } while (accept (TokenType.COMMA));
430 expect (TokenType.CLOSE_BRACKET);
432 accept (TokenType.OP_NEG);
433 accept (TokenType.INTERR);
434 accept (TokenType.HASH);
437 DataType parse_type (bool owned_by_default = true) throws ParseError {
438 var begin = get_location ();
440 if (accept (TokenType.VOID)) {
441 DataType type = new VoidType ();
442 while (accept (TokenType.STAR)) {
443 type = new PointerType (type);
445 return type;
448 List<DataType> type_arg_list = null;
449 UnresolvedSymbol sym = null;
451 bool is_dynamic = accept (TokenType.DYNAMIC);
452 bool value_owned = owned_by_default;
453 if (owned_by_default) {
454 if (accept (TokenType.UNOWNED)
455 || accept (TokenType.WEAK)) {
456 value_owned = false;
458 } else {
459 value_owned = accept (TokenType.OWNED);
462 /* handle arrays */
463 bool is_array = false;
465 if (accept (TokenType.ARRAY)) {
466 expect (TokenType.OF);
467 is_array = true;
470 /* handle lists */
471 bool is_list = false;
473 if (accept (TokenType.LIST)) {
474 expect (TokenType.OF);
475 prev ();
476 is_list = true;
479 /* handle dicts */
480 bool is_dict = false;
482 if (accept (TokenType.DICT)) {
483 expect (TokenType.OF);
484 prev ();
485 is_dict = true;
488 if (is_list) {
489 var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
490 sym = new UnresolvedSymbol (sym_parent, "ArrayList", get_src (begin));
491 } else if (is_dict) {
492 var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
493 sym = new UnresolvedSymbol (sym_parent, "HashMap", get_src (begin));
494 } else {
495 sym = parse_symbol_name ();
498 type_arg_list = parse_type_argument_list (false);
500 DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
501 if (type_arg_list != null) {
502 foreach (DataType type_arg in type_arg_list) {
503 type.add_type_argument (type_arg);
507 while (accept (TokenType.STAR)) {
508 type = new PointerType (type, get_src (begin));
511 if (!(type is PointerType)) {
512 type.nullable = accept (TokenType.INTERR);
515 if (is_array) {
517 if (!accept (TokenType.OPEN_BRACKET)) {
518 type.value_owned = true;
519 type = new ArrayType (type, 1, get_src (begin));
520 type.nullable = accept (TokenType.INTERR);
522 } else {
523 prev ();
525 while (accept (TokenType.OPEN_BRACKET)) {
526 bool invalid_array = false;
527 int array_rank = 0;
528 do {
529 array_rank++;
530 // required for decision between expression and declaration statement
531 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
532 parse_expression ();
533 // only used for parsing, reject use as real type
534 invalid_array = true;
537 while (accept (TokenType.COMMA));
538 expect (TokenType.CLOSE_BRACKET);
540 type.value_owned = true;
541 var array_type = new ArrayType (type, array_rank, get_src (begin));
542 array_type.nullable = accept (TokenType.INTERR);
544 array_type.invalid_syntax = invalid_array;
546 type = array_type;
551 if (!owned_by_default) {
552 value_owned = accept (TokenType.HASH);
555 type.is_dynamic = is_dynamic;
556 type.value_owned = value_owned;
557 return type;
560 DataType? parse_inline_array_type (DataType? type) throws ParseError {
561 var begin = get_location ();
563 // inline-allocated array
564 if (type != null && accept (TokenType.OPEN_BRACKET)) {
565 int array_length = -1;
567 if (current () != TokenType.CLOSE_BRACKET) {
568 if (current () != TokenType.INTEGER_LITERAL) {
569 throw new ParseError.SYNTAX (get_error ("expected `]' or integer literal"));
572 var length_literal = (IntegerLiteral) parse_literal ();
573 array_length = length_literal.value.to_int ();
575 expect (TokenType.CLOSE_BRACKET);
577 var array_type = new ArrayType (type, 1, get_src (begin));
578 array_type.inline_allocated = true;
579 if (array_length > 0) {
580 array_type.fixed_length = true;
581 array_type.length = array_length;
584 return array_type;
586 return type;
590 List<Expression> parse_argument_list () throws ParseError {
591 var list = new ArrayList<Expression> ();
592 if (current () != TokenType.CLOSE_PARENS) {
593 do {
594 list.add (parse_argument ());
595 } while (accept (TokenType.COMMA));
597 return list;
600 Expression parse_argument () throws ParseError {
601 var begin = get_location ();
603 if (accept (TokenType.REF)) {
604 var inner = parse_expression ();
605 return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
606 } else if (accept (TokenType.OUT)) {
607 var inner = parse_expression ();
608 return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
609 } else {
610 return parse_expression ();
614 Expression parse_primary_expression () throws ParseError {
615 var begin = get_location ();
617 Expression expr;
619 switch (current ()) {
620 case TokenType.TRUE:
621 case TokenType.FALSE:
622 case TokenType.INTEGER_LITERAL:
623 case TokenType.REAL_LITERAL:
624 case TokenType.CHARACTER_LITERAL:
625 case TokenType.STRING_LITERAL:
626 case TokenType.VERBATIM_STRING_LITERAL:
627 case TokenType.NULL:
628 expr = parse_literal ();
629 break;
630 case TokenType.ASSERT:
631 return parse_assert_expression ();
632 case TokenType.OPEN_BRACE:
633 expr = parse_initializer ();
634 break;
635 case TokenType.OPEN_PARENS:
636 expr = parse_tuple ();
637 break;
638 case TokenType.THIS:
639 expr = parse_this_access ();
640 break;
641 case TokenType.SUPER:
642 expr = parse_base_access ();
643 break;
644 case TokenType.NEW:
645 expr = parse_object_or_array_creation_expression ();
646 break;
647 case TokenType.PRINT:
648 return parse_print_expression ();
649 case TokenType.SIZEOF:
650 expr = parse_sizeof_expression ();
651 break;
652 case TokenType.TYPEOF:
653 expr = parse_typeof_expression ();
654 break;
655 case TokenType.YIELD:
656 expr = parse_yield_expression ();
657 break;
658 default:
659 expr = parse_simple_name ();
660 break;
663 // process primary expressions that start with an inner primary expression
664 bool found = true;
665 while (found) {
666 switch (current ()) {
667 case TokenType.DOT:
668 expr = parse_member_access (begin, expr);
669 break;
670 case TokenType.OP_PTR:
671 expr = parse_pointer_member_access (begin, expr);
672 break;
673 case TokenType.OPEN_PARENS:
674 expr = parse_method_call (begin, expr);
675 break;
676 case TokenType.OPEN_BRACKET:
677 expr = parse_element_access (begin, expr);
678 break;
679 case TokenType.OP_INC:
680 expr = parse_post_increment_expression (begin, expr);
681 break;
682 case TokenType.OP_DEC:
683 expr = parse_post_decrement_expression (begin, expr);
684 break;
686 default:
687 found = false;
688 break;
692 return expr;
695 Expression parse_simple_name () throws ParseError {
696 var begin = get_location ();
697 string id = parse_identifier ();
698 List<DataType> type_arg_list = parse_type_argument_list (true);
699 var expr = new MemberAccess (null, id, get_src (begin));
700 if (type_arg_list != null) {
701 foreach (DataType type_arg in type_arg_list) {
702 expr.add_type_argument (type_arg);
705 return expr;
708 Expression parse_tuple () throws ParseError {
709 expect (TokenType.OPEN_PARENS);
710 var expr_list = new ArrayList<Expression> ();
711 if (current () != TokenType.CLOSE_PARENS) {
712 do {
713 expr_list.add (parse_expression ());
714 } while (accept (TokenType.COMMA));
716 expect (TokenType.CLOSE_PARENS);
717 if (expr_list.size != 1) {
718 var tuple = new Tuple ();
719 foreach (Expression expr in expr_list) {
720 tuple.add_expression (expr);
722 return tuple;
724 return expr_list.get (0);
727 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
728 expect (TokenType.DOT);
729 string id = parse_identifier ();
730 List<DataType> type_arg_list = parse_type_argument_list (true);
731 var expr = new MemberAccess (inner, id, get_src (begin));
732 if (type_arg_list != null) {
733 foreach (DataType type_arg in type_arg_list) {
734 expr.add_type_argument (type_arg);
737 return expr;
740 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
741 expect (TokenType.OP_PTR);
742 string id = parse_identifier ();
743 List<DataType> type_arg_list = parse_type_argument_list (true);
744 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
745 if (type_arg_list != null) {
746 foreach (DataType type_arg in type_arg_list) {
747 expr.add_type_argument (type_arg);
750 return expr;
754 List<Expression> parse_print_argument_list () throws ParseError {
755 var list = new ArrayList<Expression> ();
756 var i = 0;
757 var begin = get_location ();
759 if (current () != TokenType.CLOSE_PARENS) {
760 do {
761 var p_expr = parse_expression ();
762 if (i == 0) {
763 i++;
765 if (p_expr != null) {
768 if (p_expr is StringLiteral) {
769 var s_exp = (StringLiteral) p_expr;
770 var len = s_exp.value.size ();
772 if (len > 2) {
773 string s = "\\n\"";
774 var st = s_exp.value.ndup (len-1);
775 st += s;
776 s_exp.value = st;
778 } else {
779 string s = "\"\\n\"";
780 var rhs = new StringLiteral (s, get_src (begin));
781 p_expr = new BinaryExpression (BinaryOperator.PLUS, p_expr, rhs, get_src (begin));
786 list.add (p_expr);
788 } while (accept (TokenType.COMMA));
790 return list;
793 Expression parse_print_expression () throws ParseError {
794 var begin = get_location ();
796 expect (TokenType.PRINT);
797 accept (TokenType.OPEN_PARENS);
799 var expr = new MemberAccess (null, "print", get_src (begin));
801 var arg_list = parse_print_argument_list ();
803 accept (TokenType.CLOSE_PARENS);
805 var print_expr = new MethodCall (expr, get_src (begin));
807 foreach (Expression arg in arg_list) {
808 print_expr.add_argument (arg);
811 return print_expr;
815 Expression parse_assert_expression () throws ParseError {
816 var begin = get_location ();
818 expect (TokenType.ASSERT);
819 accept (TokenType.OPEN_PARENS);
821 var expr = new MemberAccess (null, "assert", get_src (begin));
823 var arg_list = parse_argument_list ();
825 accept (TokenType.CLOSE_PARENS);
827 var assert_expr = new MethodCall (expr, get_src (begin));
829 foreach (Expression arg in arg_list) {
830 assert_expr.add_argument (arg);
833 return assert_expr;
837 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
838 expect (TokenType.OPEN_PARENS);
839 var arg_list = parse_argument_list ();
840 expect (TokenType.CLOSE_PARENS);
841 var init_list = parse_object_initializer ();
843 if (init_list.size > 0 && inner is MemberAccess) {
844 // struct creation expression
845 var member = (MemberAccess) inner;
846 member.creation_member = true;
848 var expr = new ObjectCreationExpression (member, get_src (begin));
849 expr.struct_creation = true;
850 foreach (Expression arg in arg_list) {
851 expr.add_argument (arg);
853 foreach (MemberInitializer initializer in init_list) {
854 expr.add_member_initializer (initializer);
856 return expr;
857 } else {
858 var expr = new MethodCall (inner, get_src (begin));
859 foreach (Expression arg in arg_list) {
860 expr.add_argument (arg);
862 return expr;
866 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
867 expect (TokenType.OPEN_BRACKET);
868 var index_list = parse_expression_list ();
869 expect (TokenType.CLOSE_BRACKET);
871 var expr = new ElementAccess (inner, get_src (begin));
872 foreach (Expression index in index_list) {
873 expr.append_index (index);
875 return expr;
878 List<Expression> parse_expression_list () throws ParseError {
879 var list = new ArrayList<Expression> ();
880 do {
881 list.add (parse_expression ());
882 } while (accept (TokenType.COMMA));
883 return list;
886 Expression parse_this_access () throws ParseError {
887 var begin = get_location ();
888 expect (TokenType.THIS);
889 return new MemberAccess (null, "this", get_src (begin));
892 Expression parse_base_access () throws ParseError {
893 var begin = get_location ();
894 expect (TokenType.SUPER);
895 return new BaseAccess (get_src (begin));
898 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
899 expect (TokenType.OP_INC);
900 return new PostfixExpression (inner, true, get_src (begin));
903 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
904 expect (TokenType.OP_DEC);
905 return new PostfixExpression (inner, false, get_src (begin));
908 Expression parse_object_or_array_creation_expression () throws ParseError {
909 var begin = get_location ();
910 expect (TokenType.NEW);
912 if (accept (TokenType.ARRAY)) {
913 expect (TokenType.OF);
914 var mtype = parse_type ();
915 var expr = parse_array_creation_expression (begin, mtype);
916 return expr;
919 if (accept (TokenType.LIST)) {
920 expect (TokenType.OF);
921 var mtype = parse_type ();
922 var expr = parse_list_creation_expression (begin, mtype);
923 return expr;
926 if (accept (TokenType.DICT)) {
927 expect (TokenType.OF);
928 var mtype1 = parse_type ();
929 expect (TokenType.COMMA);
930 var mtype2 = parse_type ();
931 var expr = parse_dict_creation_expression (begin, mtype1, mtype2);
932 return expr;
936 var member = parse_member_name ();
937 var expr = parse_object_creation_expression (begin, member);
938 return expr;
942 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
943 member.creation_member = true;
944 List<Expression> arg_list;
945 if (accept (TokenType.OPEN_PARENS)) {
946 arg_list = parse_argument_list ();
947 expect (TokenType.CLOSE_PARENS);
948 } else {
949 arg_list = new ArrayList<Expression> ();
952 var init_list = parse_object_initializer ();
954 var expr = new ObjectCreationExpression (member, get_src (begin));
955 foreach (Expression arg in arg_list) {
956 expr.add_argument (arg);
958 foreach (MemberInitializer initializer in init_list) {
959 expr.add_member_initializer (initializer);
961 return expr;
964 Expression parse_array_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
965 bool size_specified = false;
966 List<Expression> size_specifier_list = null;
967 bool first = true;
968 DataType etype = element_type.copy ();
970 var has_bracket = accept (TokenType.OPEN_BRACKET);
972 do {
973 if (!first) {
974 // array of arrays: new T[][42]
975 etype = new ArrayType (etype, size_specifier_list.size, etype.source_reference);
976 } else {
977 first = false;
980 size_specifier_list = new ArrayList<Expression> ();
981 do {
982 Expression size = null;
983 if (has_bracket && current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
984 size = parse_expression ();
985 size_specified = true;
987 size_specifier_list.add (size);
988 } while (accept (TokenType.COMMA));
990 if (has_bracket) {
991 expect (TokenType.CLOSE_BRACKET);
993 } while (accept (TokenType.OPEN_BRACKET));
995 InitializerList initializer = null;
996 if (accept (TokenType.ASSIGN)) {
997 initializer = parse_initializer ();
1000 var expr = new ArrayCreationExpression (etype, size_specifier_list.size, initializer, get_src (begin));
1001 if (size_specified) {
1002 foreach (Expression size in size_specifier_list) {
1003 expr.append_size (size);
1006 return expr;
1010 Expression parse_list_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1012 MemberAccess list_member = null, parent_member = null;
1014 parent_member = new MemberAccess (null, "Gee", get_src (begin));
1015 list_member = new MemberAccess (parent_member, "ArrayList", get_src (begin));
1016 list_member.add_type_argument (element_type);
1018 list_member.creation_member = true;
1020 var expr = new ObjectCreationExpression (list_member, get_src (begin));
1021 var t = element_type.to_qualified_string ();
1022 if (t == "string") {
1023 parent_member = new MemberAccess (null, "GLib", get_src (begin));
1024 expr.add_argument (new MemberAccess (parent_member, "str_equal", get_src (begin)));
1026 } else if (t == "int") {
1027 parent_member = new MemberAccess (null, "GLib", get_src (begin));
1028 expr.add_argument (new MemberAccess (parent_member, "int_equal", get_src (begin)));
1031 return expr;
1034 Expression parse_dict_creation_expression (SourceLocation begin, DataType key_type, DataType value_type) throws ParseError {
1036 MemberAccess dict_member = null, parent_member = null, dict_hash = null, dict_equal = null;
1038 parent_member = new MemberAccess (null, "Gee", get_src (begin));
1039 dict_member = new MemberAccess (parent_member, "HashMap", get_src (begin));
1040 dict_member.add_type_argument (key_type);
1041 dict_member.add_type_argument (value_type);
1043 var key_type_name = key_type.to_qualified_string ();
1044 if (key_type_name == "string") {
1045 parent_member = new MemberAccess (null, "GLib", get_src (begin));
1046 dict_hash = new MemberAccess (parent_member, "str_hash", get_src (begin));
1047 dict_equal = new MemberAccess (parent_member, "str_equal", get_src (begin));
1049 } else if (key_type_name == "int") {
1050 parent_member = new MemberAccess (null, "GLib", get_src (begin));
1051 dict_hash = new MemberAccess (parent_member, "int_hash", get_src (begin));
1052 dict_equal = new MemberAccess (parent_member, "int_equal", get_src (begin));
1055 dict_member.creation_member = true;
1057 var expr = new ObjectCreationExpression (dict_member, get_src (begin));
1059 if (dict_hash != null && dict_equal != null) {
1060 expr.add_argument (dict_hash);
1061 expr.add_argument (dict_equal);
1065 return expr;
1069 List<MemberInitializer> parse_object_initializer () throws ParseError {
1070 var list = new ArrayList<MemberInitializer> ();
1071 if (accept (TokenType.OPEN_BRACE)) {
1072 do {
1073 list.add (parse_member_initializer ());
1074 } while (accept (TokenType.COMMA));
1075 expect (TokenType.CLOSE_BRACE);
1077 return list;
1080 MemberInitializer parse_member_initializer () throws ParseError {
1081 var begin = get_location ();
1082 string id = parse_identifier ();
1083 expect (TokenType.ASSIGN);
1084 var expr = parse_expression ();
1086 return new MemberInitializer (id, expr, get_src (begin));
1089 Expression parse_yield_expression () throws ParseError {
1090 var begin = get_location ();
1091 expect (TokenType.YIELD);
1092 var member = parse_member_name ();
1093 var call = (MethodCall) parse_method_call (begin, member);
1094 call.is_yield_expression = true;
1095 return call;
1098 Expression parse_sizeof_expression () throws ParseError {
1099 var begin = get_location ();
1100 expect (TokenType.SIZEOF);
1101 expect (TokenType.OPEN_PARENS);
1102 var type = parse_type ();
1103 expect (TokenType.CLOSE_PARENS);
1105 return new SizeofExpression (type, get_src (begin));
1108 Expression parse_typeof_expression () throws ParseError {
1109 var begin = get_location ();
1110 expect (TokenType.TYPEOF);
1111 expect (TokenType.OPEN_PARENS);
1112 var type = parse_type ();
1113 expect (TokenType.CLOSE_PARENS);
1115 return new TypeofExpression (type, get_src (begin));
1118 UnaryOperator get_unary_operator (TokenType token_type) {
1119 switch (token_type) {
1120 case TokenType.PLUS: return UnaryOperator.PLUS;
1121 case TokenType.MINUS: return UnaryOperator.MINUS;
1122 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
1123 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
1124 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
1125 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
1126 default: return UnaryOperator.NONE;
1130 Expression parse_unary_expression () throws ParseError {
1131 var begin = get_location ();
1132 var operator = get_unary_operator (current ());
1133 if (operator != UnaryOperator.NONE) {
1134 next ();
1135 var op = parse_unary_expression ();
1136 return new UnaryExpression (operator, op, get_src (begin));
1138 switch (current ()) {
1139 case TokenType.HASH:
1140 next ();
1141 var op = parse_unary_expression ();
1142 return new ReferenceTransferExpression (op, get_src (begin));
1143 case TokenType.OPEN_PARENS:
1144 next ();
1145 switch (current ()) {
1146 case TokenType.OWNED:
1147 // (owned) foo
1148 next ();
1149 if (accept (TokenType.CLOSE_PARENS)) {
1150 var op = parse_unary_expression ();
1151 return new ReferenceTransferExpression (op, get_src (begin));
1153 break;
1154 case TokenType.VOID:
1155 case TokenType.DYNAMIC:
1156 case TokenType.IDENTIFIER:
1157 case TokenType.ARRAY:
1158 case TokenType.LIST:
1159 case TokenType.DICT:
1160 var type = parse_type ();
1161 if (accept (TokenType.CLOSE_PARENS)) {
1162 // check follower to decide whether to create cast expression
1163 switch (current ()) {
1164 case TokenType.OP_NEG:
1165 case TokenType.TILDE:
1166 case TokenType.OPEN_PARENS:
1167 case TokenType.TRUE:
1168 case TokenType.FALSE:
1169 case TokenType.INTEGER_LITERAL:
1170 case TokenType.REAL_LITERAL:
1171 case TokenType.CHARACTER_LITERAL:
1172 case TokenType.STRING_LITERAL:
1173 case TokenType.VERBATIM_STRING_LITERAL:
1174 case TokenType.NULL:
1175 case TokenType.THIS:
1176 case TokenType.SUPER:
1177 case TokenType.NEW:
1178 case TokenType.SIZEOF:
1179 case TokenType.TYPEOF:
1180 case TokenType.IDENTIFIER:
1181 case TokenType.PARAMS:
1182 var inner = parse_unary_expression ();
1183 return new CastExpression (inner, type, get_src (begin), false);
1184 default:
1185 break;
1188 break;
1189 default:
1190 break;
1192 // no cast expression
1193 rollback (begin);
1194 break;
1195 case TokenType.STAR:
1196 next ();
1197 var op = parse_unary_expression ();
1198 return new PointerIndirection (op, get_src (begin));
1199 case TokenType.BITWISE_AND:
1200 next ();
1201 var op = parse_unary_expression ();
1202 return new AddressofExpression (op, get_src (begin));
1203 default:
1204 break;
1207 var expr = parse_primary_expression ();
1208 return expr;
1211 BinaryOperator get_binary_operator (TokenType token_type) {
1212 switch (token_type) {
1213 case TokenType.STAR: return BinaryOperator.MUL;
1214 case TokenType.DIV: return BinaryOperator.DIV;
1215 case TokenType.PERCENT: return BinaryOperator.MOD;
1216 case TokenType.PLUS: return BinaryOperator.PLUS;
1217 case TokenType.MINUS: return BinaryOperator.MINUS;
1218 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
1219 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
1220 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
1221 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
1222 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
1223 case TokenType.IS:
1224 next();
1225 if (current () == TokenType.OP_NEG) {
1226 prev ();
1227 return BinaryOperator.INEQUALITY;
1229 prev ();
1230 return BinaryOperator.EQUALITY;
1231 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
1232 default: return BinaryOperator.NONE;
1236 Expression parse_multiplicative_expression () throws ParseError {
1237 var begin = get_location ();
1238 var left = parse_unary_expression ();
1239 bool found = true;
1240 while (found) {
1241 var operator = get_binary_operator (current ());
1242 switch (operator) {
1243 case BinaryOperator.MUL:
1244 case BinaryOperator.DIV:
1245 case BinaryOperator.MOD:
1246 next ();
1247 var right = parse_unary_expression ();
1248 left = new BinaryExpression (operator, left, right, get_src (begin));
1249 break;
1250 default:
1251 found = false;
1252 break;
1255 return left;
1258 Expression parse_additive_expression () throws ParseError {
1259 var begin = get_location ();
1260 var left = parse_multiplicative_expression ();
1261 bool found = true;
1262 while (found) {
1263 var operator = get_binary_operator (current ());
1264 switch (operator) {
1265 case BinaryOperator.PLUS:
1266 case BinaryOperator.MINUS:
1267 next ();
1268 var right = parse_multiplicative_expression ();
1269 left = new BinaryExpression (operator, left, right, get_src (begin));
1270 break;
1271 default:
1272 found = false;
1273 break;
1276 return left;
1279 Expression parse_shift_expression () throws ParseError {
1280 var begin = get_location ();
1281 var left = parse_additive_expression ();
1282 bool found = true;
1283 while (found) {
1284 switch (current ()) {
1285 case TokenType.OP_SHIFT_LEFT:
1286 next ();
1287 var right = parse_additive_expression ();
1288 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1289 break;
1290 // don't use OP_SHIFT_RIGHT to support >> for nested generics
1291 case TokenType.OP_GT:
1292 char* first_gt_pos = tokens[index].begin.pos;
1293 next ();
1294 // only accept >> when there is no space between the two > signs
1295 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1296 next ();
1297 var right = parse_additive_expression ();
1298 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1299 } else {
1300 prev ();
1301 found = false;
1303 break;
1304 default:
1305 found = false;
1306 break;
1309 return left;
1312 Expression parse_relational_expression () throws ParseError {
1313 var begin = get_location ();
1314 var left = parse_shift_expression ();
1315 bool found = true;
1316 while (found) {
1317 var operator = get_binary_operator (current ());
1318 switch (operator) {
1319 case BinaryOperator.LESS_THAN:
1320 case BinaryOperator.LESS_THAN_OR_EQUAL:
1321 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1322 next ();
1323 var right = parse_shift_expression ();
1324 left = new BinaryExpression (operator, left, right, get_src (begin));
1325 break;
1326 case BinaryOperator.GREATER_THAN:
1327 next ();
1328 // ignore >> and >>= (two tokens due to generics)
1329 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1330 var right = parse_shift_expression ();
1331 left = new BinaryExpression (operator, left, right, get_src (begin));
1332 } else {
1333 prev ();
1334 found = false;
1336 break;
1337 default:
1338 switch (current ()) {
1339 case TokenType.ISA:
1340 next ();
1341 var type = parse_type ();
1342 left = new TypeCheck (left, type, get_src (begin));
1343 break;
1344 case TokenType.AS:
1345 next ();
1346 var type = parse_type ();
1347 left = new CastExpression (left, type, get_src (begin), true);
1348 break;
1349 default:
1350 found = false;
1351 break;
1353 break;
1356 return left;
1359 Expression parse_equality_expression () throws ParseError {
1360 var begin = get_location ();
1361 var left = parse_relational_expression ();
1362 bool found = true;
1363 while (found) {
1364 var operator = get_binary_operator (current ());
1365 switch (operator) {
1366 case BinaryOperator.INEQUALITY:
1367 case BinaryOperator.EQUALITY:
1368 if ((operator == BinaryOperator.INEQUALITY) && (current () == TokenType.IS)) {
1369 next ();
1371 next ();
1372 var right = parse_relational_expression ();
1373 left = new BinaryExpression (operator, left, right, get_src (begin));
1374 break;
1375 default:
1376 found = false;
1377 break;
1380 return left;
1383 Expression parse_and_expression () throws ParseError {
1384 var begin = get_location ();
1385 var left = parse_equality_expression ();
1386 while (accept (TokenType.BITWISE_AND)) {
1387 var right = parse_equality_expression ();
1388 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1390 return left;
1393 Expression parse_exclusive_or_expression () throws ParseError {
1394 var begin = get_location ();
1395 var left = parse_and_expression ();
1396 while (accept (TokenType.CARRET)) {
1397 var right = parse_and_expression ();
1398 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1400 return left;
1403 Expression parse_inclusive_or_expression () throws ParseError {
1404 var begin = get_location ();
1405 var left = parse_exclusive_or_expression ();
1406 while (accept (TokenType.BITWISE_OR)) {
1407 var right = parse_exclusive_or_expression ();
1408 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1410 return left;
1413 Expression parse_in_expression () throws ParseError {
1414 var begin = get_location ();
1415 var left = parse_inclusive_or_expression ();
1416 while (accept (TokenType.IN)) {
1417 var right = parse_inclusive_or_expression ();
1418 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1420 return left;
1423 Expression parse_conditional_and_expression () throws ParseError {
1424 var begin = get_location ();
1425 var left = parse_in_expression ();
1426 while (accept (TokenType.OP_AND)) {
1427 var right = parse_in_expression ();
1428 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1430 return left;
1433 Expression parse_conditional_or_expression () throws ParseError {
1434 var begin = get_location ();
1435 var left = parse_conditional_and_expression ();
1436 while (accept (TokenType.OP_OR)) {
1437 var right = parse_conditional_and_expression ();
1438 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1440 return left;
1443 Expression parse_conditional_expression () throws ParseError {
1444 var begin = get_location ();
1445 var condition = parse_conditional_or_expression ();
1446 if (accept (TokenType.INTERR)) {
1447 var true_expr = parse_expression ();
1448 expect (TokenType.COLON);
1449 var false_expr = parse_expression ();
1450 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1451 } else {
1452 return condition;
1456 Expression parse_lambda_expression () throws ParseError {
1457 var begin = get_location ();
1458 List<string> params = new ArrayList<string> ();
1460 expect (TokenType.DEF);
1462 if (accept (TokenType.OPEN_PARENS)) {
1463 if (current () != TokenType.CLOSE_PARENS) {
1464 do {
1465 params.add (parse_identifier ());
1466 } while (accept (TokenType.COMMA));
1468 expect (TokenType.CLOSE_PARENS);
1469 } else {
1470 params.add (parse_identifier ());
1474 LambdaExpression lambda;
1475 if (accept_block ()) {
1476 var block = parse_block ();
1477 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1478 } else {
1479 var expr = parse_expression ();
1480 lambda = new LambdaExpression (expr, get_src (begin));
1481 expect_terminator ();
1486 foreach (string param in params) {
1487 lambda.add_parameter (param);
1489 return lambda;
1492 AssignmentOperator get_assignment_operator (TokenType token_type) {
1493 switch (token_type) {
1494 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1495 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1496 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1497 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1498 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1499 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1500 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1501 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1502 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1503 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1504 default: return AssignmentOperator.NONE;
1508 Expression parse_expression () throws ParseError {
1509 if (current () == TokenType.DEF) {
1510 var lambda = parse_lambda_expression ();
1511 current_expr_is_lambda = true;
1512 return lambda;
1515 var begin = get_location ();
1516 Expression expr = parse_conditional_expression ();
1518 while (true) {
1519 var operator = get_assignment_operator (current ());
1520 if (operator != AssignmentOperator.NONE) {
1521 next ();
1522 var rhs = parse_expression ();
1523 expr = new Assignment (expr, rhs, operator, get_src (begin));
1524 } else if (current () == TokenType.OP_GT) { // >>=
1525 char* first_gt_pos = tokens[index].begin.pos;
1526 next ();
1527 // only accept >>= when there is no space between the two > signs
1528 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1529 next ();
1530 var rhs = parse_expression ();
1531 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1532 } else {
1533 prev ();
1534 break;
1536 } else {
1537 break;
1541 return expr;
1545 Statement get_for_statement_type () throws ParseError {
1547 var begin = get_location ();
1548 bool is_foreach = false;
1550 while (current () != TokenType.EOL && current () != TokenType.DO) {
1551 next ();
1552 if (accept (TokenType.IN)) {
1553 is_foreach = true;
1554 break;
1558 rollback (begin);
1560 if (is_foreach) {
1561 return parse_foreach_statement ();
1562 } else {
1563 return parse_for_statement ();
1568 void parse_statements (Block block) throws ParseError {
1569 while (current () != TokenType.DEDENT
1570 && current () != TokenType.WHEN
1571 && current () != TokenType.DEFAULT) {
1572 try {
1573 Statement stmt = null;
1574 bool is_decl = false;
1575 comment = scanner.pop_comment ();
1576 switch (current ()) {
1578 /* skip over requires and ensures as we handled them in method declaration */
1579 case TokenType.REQUIRES:
1580 case TokenType.ENSURES:
1581 var begin = get_location ();
1582 next ();
1584 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
1585 while (current () != TokenType.DEDENT) {
1586 next();
1589 expect (TokenType.DEDENT);
1590 } else {
1591 while (current () != TokenType.EOL) {
1592 next();
1595 expect (TokenType.EOL);
1598 stmt = new EmptyStatement (get_src (begin));
1599 break;
1602 case TokenType.INDENT:
1603 stmt = parse_block ();
1604 break;
1605 case TokenType.SEMICOLON:
1606 case TokenType.PASS:
1607 stmt = parse_empty_statement ();
1608 break;
1609 case TokenType.PRINT:
1610 case TokenType.ASSERT:
1611 stmt = parse_expression_statement ();
1612 break;
1613 case TokenType.IF:
1614 stmt = parse_if_statement ();
1615 break;
1616 case TokenType.CASE:
1617 stmt = parse_switch_statement ();
1618 break;
1619 case TokenType.WHILE:
1620 stmt = parse_while_statement ();
1621 break;
1622 case TokenType.DO:
1623 stmt = parse_do_statement ();
1624 break;
1625 case TokenType.FOR:
1626 stmt = get_for_statement_type ();
1627 break;
1628 case TokenType.BREAK:
1629 stmt = parse_break_statement ();
1630 break;
1631 case TokenType.CONTINUE:
1632 stmt = parse_continue_statement ();
1633 break;
1634 case TokenType.RETURN:
1635 stmt = parse_return_statement ();
1636 break;
1637 case TokenType.RAISE:
1638 stmt = parse_throw_statement ();
1639 break;
1640 case TokenType.TRY:
1641 stmt = parse_try_statement ();
1642 break;
1643 case TokenType.LOCK:
1644 stmt = parse_lock_statement ();
1645 break;
1646 case TokenType.DELETE:
1647 stmt = parse_delete_statement ();
1648 break;
1649 case TokenType.VAR:
1650 is_decl = true;
1651 parse_local_variable_declarations (block);
1652 break;
1653 case TokenType.YIELD:
1654 stmt = parse_yield_statement ();
1655 break;
1657 case TokenType.OP_INC:
1658 case TokenType.OP_DEC:
1659 case TokenType.SUPER:
1660 case TokenType.THIS:
1661 case TokenType.OPEN_PARENS:
1662 case TokenType.STAR:
1663 case TokenType.NEW:
1664 stmt = parse_expression_statement ();
1665 break;
1666 default:
1667 bool is_expr = is_expression ();
1668 if (is_expr) {
1669 stmt = parse_expression_statement ();
1670 } else {
1671 is_decl = true;
1672 parse_local_variable_declarations (block);
1674 break;
1677 if (!is_decl) {
1678 block.add_statement (stmt);
1680 } catch (ParseError e) {
1681 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1682 // beginning of next declaration or end of file reached
1683 // return what we have so far
1684 break;
1690 bool is_expression () throws ParseError {
1691 var begin = get_location ();
1693 // decide between declaration and expression statement
1694 skip_type ();
1695 switch (current ()) {
1696 // invocation expression
1697 case TokenType.OPEN_PARENS:
1698 // postfix increment
1699 case TokenType.OP_INC:
1700 // postfix decrement
1701 case TokenType.OP_DEC:
1702 // assignments
1703 case TokenType.ASSIGN:
1704 case TokenType.ASSIGN_ADD:
1705 case TokenType.ASSIGN_BITWISE_AND:
1706 case TokenType.ASSIGN_BITWISE_OR:
1707 case TokenType.ASSIGN_BITWISE_XOR:
1708 case TokenType.ASSIGN_DIV:
1709 case TokenType.ASSIGN_MUL:
1710 case TokenType.ASSIGN_PERCENT:
1711 case TokenType.ASSIGN_SHIFT_LEFT:
1712 case TokenType.ASSIGN_SUB:
1713 case TokenType.OP_GT: // >>=
1714 // member access
1715 case TokenType.DOT:
1716 // pointer member access
1717 case TokenType.OP_PTR:
1718 rollback (begin);
1719 return true;
1720 default:
1721 rollback (begin);
1722 return false;
1726 Block parse_embedded_statement () throws ParseError {
1727 if (current () == TokenType.INDENT) {
1728 var block = parse_block ();
1729 return block;
1732 comment = scanner.pop_comment ();
1734 var block = new Block (get_src (get_location ()));
1735 block.add_statement (parse_embedded_statement_without_block ());
1736 return block;
1740 Statement parse_embedded_statement_without_block () throws ParseError {
1741 switch (current ()) {
1742 case TokenType.PASS:
1743 case TokenType.SEMICOLON: return parse_empty_statement ();
1744 case TokenType.IF: return parse_if_statement ();
1745 case TokenType.CASE: return parse_switch_statement ();
1746 case TokenType.WHILE: return parse_while_statement ();
1747 case TokenType.DO: return parse_do_statement ();
1748 case TokenType.FOR: return get_for_statement_type ();
1749 case TokenType.BREAK: return parse_break_statement ();
1750 case TokenType.CONTINUE: return parse_continue_statement ();
1751 case TokenType.RETURN: return parse_return_statement ();
1752 case TokenType.YIELD: return parse_yield_statement ();
1753 case TokenType.RAISE: return parse_throw_statement ();
1754 case TokenType.TRY: return parse_try_statement ();
1755 case TokenType.LOCK: return parse_lock_statement ();
1756 case TokenType.DELETE: return parse_delete_statement ();
1757 default: return parse_expression_statement ();
1761 Block parse_block () throws ParseError {
1762 var begin = get_location ();
1763 expect (TokenType.INDENT);
1764 var block = new Block (get_src (begin));
1765 parse_statements (block);
1766 if (!accept (TokenType.DEDENT)) {
1767 // only report error if it's not a secondary error
1768 if (context.report.get_errors () == 0) {
1769 Report.error (get_current_src (), "tab indentation is incorrect");
1773 block.source_reference.last_line = get_current_src ().last_line;
1774 block.source_reference.last_column = get_current_src ().last_column;
1776 return block;
1779 Statement parse_empty_statement () throws ParseError {
1780 var begin = get_location ();
1782 accept (TokenType.PASS);
1783 accept (TokenType.SEMICOLON);
1784 expect_terminator ();
1786 return new EmptyStatement (get_src (begin));
1789 void add_local_var_variable (Block block, string id) throws ParseError {
1790 DataType type_copy = null;
1791 var local = parse_local_variable (type_copy, id);
1792 block.add_statement (new DeclarationStatement (local, local.source_reference));
1795 void parse_local_variable_declarations (Block block) throws ParseError {
1796 if (accept (TokenType.VAR)) {
1797 /* support block vars */
1798 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
1799 while (current () != TokenType.DEDENT) {
1800 var s = parse_identifier ();
1801 add_local_var_variable (block, s);
1802 accept (TokenType.EOL);
1803 accept (TokenType.SEMICOLON);
1806 expect (TokenType.DEDENT);
1807 } else {
1808 var s = parse_identifier ();
1809 add_local_var_variable (block, s);
1810 expect_terminator ();
1813 return;
1816 var id_list = new ArrayList<string> ();
1817 DataType variable_type = null;
1819 do {
1820 id_list.add (parse_identifier ());
1821 } while (accept (TokenType.COMMA));
1823 expect (TokenType.COLON);
1825 variable_type = parse_type ();
1826 var type = parse_inline_array_type (variable_type);
1828 foreach (string id in id_list) {
1829 DataType type_copy = null;
1830 if (type != null) {
1831 type_copy = type.copy ();
1833 var local = parse_local_variable (type_copy, id);
1834 block.add_statement (new DeclarationStatement (local, local.source_reference));
1837 expect_terminator ();
1840 LocalVariable parse_local_variable (DataType? variable_type, string id) throws ParseError {
1841 var begin = get_location ();
1842 Expression initializer = null;
1843 if (accept (TokenType.ASSIGN)) {
1844 initializer = parse_expression ();
1846 return new LocalVariable (variable_type, id, initializer, get_src (begin));
1849 Statement parse_expression_statement () throws ParseError {
1850 var begin = get_location ();
1851 var expr = parse_statement_expression ();
1853 if (current_expr_is_lambda) {
1854 current_expr_is_lambda = false;
1855 } else {
1856 expect_terminator ();
1859 return new ExpressionStatement (expr, get_src (begin));
1862 Expression parse_statement_expression () throws ParseError {
1863 // invocation expression, assignment,
1864 // or pre/post increment/decrement expression
1865 var expr = parse_expression ();
1866 return expr;
1869 Statement parse_if_statement () throws ParseError {
1870 var begin = get_location ();
1872 expect (TokenType.IF);
1874 var condition = parse_expression ();
1876 if (!accept (TokenType.DO)) {
1877 expect (TokenType.EOL);
1878 } else {
1879 accept (TokenType.EOL);
1882 var src = get_src (begin);
1883 var true_stmt = parse_embedded_statement ();
1884 Block false_stmt = null;
1885 if (accept (TokenType.ELSE)) {
1886 // allow `else if' on the same line without `do'
1887 if (!accept (TokenType.DO) && current () != TokenType.IF) {
1888 expect (TokenType.EOL);
1889 } else {
1890 accept (TokenType.EOL);
1893 false_stmt = parse_embedded_statement ();
1895 return new IfStatement (condition, true_stmt, false_stmt, src);
1898 Statement parse_switch_statement () throws ParseError {
1899 var begin = get_location ();
1900 expect (TokenType.CASE);
1901 var condition = parse_expression ();
1903 expect (TokenType.EOL);
1905 var stmt = new SwitchStatement (condition, get_src (begin));
1906 expect (TokenType.INDENT);
1907 while (current () != TokenType.DEDENT) {
1908 var section = new SwitchSection (get_src (begin));
1910 if (accept (TokenType.WHEN)) {
1911 do {
1912 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
1914 while (accept (TokenType.COMMA));
1915 } else {
1916 expect (TokenType.DEFAULT);
1917 section.add_label (new SwitchLabel.with_default (get_src (begin)));
1920 if (!accept (TokenType.EOL)) {
1921 expect (TokenType.DO);
1924 parse_statements (section);
1926 /* add break statement for each block */
1927 var break_stmt = new BreakStatement (get_src (begin));
1928 section.add_statement (break_stmt);
1930 stmt.add_section (section);
1932 expect (TokenType.DEDENT);
1933 return stmt;
1936 Statement parse_while_statement () throws ParseError {
1937 var begin = get_location ();
1938 expect (TokenType.WHILE);
1939 var condition = parse_expression ();
1941 if (!accept (TokenType.DO)) {
1942 expect (TokenType.EOL);
1943 } else {
1944 accept (TokenType.EOL);
1947 var body = parse_embedded_statement ();
1948 return new WhileStatement (condition, body, get_src (begin));
1951 Statement parse_do_statement () throws ParseError {
1952 var begin = get_location ();
1953 expect (TokenType.DO);
1954 expect (TokenType.EOL);
1955 var body = parse_embedded_statement ();
1956 expect (TokenType.WHILE);
1958 var condition = parse_expression ();
1960 expect_terminator ();
1962 return new DoStatement (body, condition, get_src (begin));
1966 Statement parse_for_statement () throws ParseError {
1967 var begin = get_location ();
1968 Block block = null;
1969 Expression initializer = null;
1970 Expression condition = null;
1971 Expression iterator = null;
1972 bool is_expr;
1973 string id;
1975 expect (TokenType.FOR);
1977 switch (current ()) {
1978 case TokenType.VAR:
1979 is_expr = false;
1980 break;
1981 default:
1983 bool local_is_expr = is_expression ();
1984 is_expr = local_is_expr;
1985 break;
1988 if (is_expr) {
1989 var expr_begin = get_location ();
1990 id = parse_identifier ();
1991 rollback (expr_begin);
1992 initializer = parse_statement_expression ();
1993 } else {
1994 block = new Block (get_src (begin));
1995 DataType variable_type;
1996 if (accept (TokenType.VAR)) {
1997 variable_type = null;
1998 id = parse_identifier ();
1999 } else {
2000 id = parse_identifier ();
2001 expect (TokenType.COLON);
2002 variable_type = parse_type ();
2005 DataType type_copy = null;
2006 if (variable_type != null) {
2007 type_copy = variable_type.copy ();
2009 var local = parse_local_variable (type_copy, id);
2011 block.add_statement (new DeclarationStatement (local, local.source_reference));
2016 if (accept (TokenType.TO)) {
2017 /* create expression for condition and incrementing iterator */
2018 var to_begin = get_location ();
2019 var to_src = get_src (to_begin);
2020 var left = new MemberAccess (null, id, to_src);
2021 var right = parse_primary_expression ();
2023 condition = new BinaryExpression (BinaryOperator.LESS_THAN_OR_EQUAL, left, right, to_src);
2025 iterator = new PostfixExpression (left, true, to_src);
2026 } else {
2027 expect (TokenType.DOWNTO);
2028 var downto_begin = get_location ();
2029 var downto_src = get_src (downto_begin);
2030 /* create expression for condition and decrementing iterator */
2031 var left = new MemberAccess (null, id, downto_src);
2032 var right = parse_primary_expression ();
2034 condition = new BinaryExpression (BinaryOperator.GREATER_THAN_OR_EQUAL, left, right, downto_src);
2036 iterator = new PostfixExpression (left, false, downto_src);
2039 if (!accept (TokenType.EOL)) {
2040 expect (TokenType.DO);
2043 var src = get_src (begin);
2044 var body = parse_embedded_statement ();
2045 var stmt = new ForStatement (condition, body, src);
2047 if (initializer != null) stmt.add_initializer (initializer);
2049 stmt.add_iterator (iterator);
2052 if (block != null) {
2053 block.add_statement (stmt);
2054 return block;
2055 } else {
2056 return stmt;
2060 Statement parse_foreach_statement () throws ParseError {
2061 var begin = get_location ();
2062 DataType type = null;
2063 string id = null;
2065 expect (TokenType.FOR);
2067 if (accept (TokenType.VAR)) {
2068 id = parse_identifier ();
2069 } else {
2070 id = parse_identifier ();
2071 if (accept (TokenType.COLON)) {
2072 type = parse_type ();
2076 expect (TokenType.IN);
2077 var collection = parse_expression ();
2078 if (!accept (TokenType.EOL)) {
2079 expect (TokenType.DO);
2081 var src = get_src (begin);
2082 var body = parse_embedded_statement ();
2083 return new ForeachStatement (type, id, collection, body, src);
2086 Statement parse_break_statement () throws ParseError {
2087 var begin = get_location ();
2088 expect (TokenType.BREAK);
2089 expect_terminator ();
2090 return new BreakStatement (get_src (begin));
2093 Statement parse_continue_statement () throws ParseError {
2094 var begin = get_location ();
2095 expect (TokenType.CONTINUE);
2096 expect_terminator ();
2097 return new ContinueStatement (get_src (begin));
2100 Statement parse_return_statement () throws ParseError {
2101 var begin = get_location ();
2102 expect (TokenType.RETURN);
2103 Expression expr = null;
2104 if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) {
2105 expr = parse_expression ();
2107 expect_terminator ();
2108 return new ReturnStatement (expr, get_src (begin));
2111 Statement parse_yield_statement () throws ParseError {
2112 var begin = get_location ();
2113 expect (TokenType.YIELD);
2114 if (current () != TokenType.SEMICOLON && current () != TokenType.EOL && current () != TokenType.RETURN) {
2115 prev ();
2116 return parse_expression_statement ();
2118 Expression expr = null;
2119 if (accept (TokenType.RETURN)) {
2120 expr = parse_expression ();
2122 expect_terminator ();
2123 return new YieldStatement (expr, get_src (begin));
2126 Statement parse_throw_statement () throws ParseError {
2127 var begin = get_location ();
2128 expect (TokenType.RAISE);
2129 var expr = parse_expression ();
2130 expect_terminator ();
2131 return new ThrowStatement (expr, get_src (begin));
2134 Statement parse_try_statement () throws ParseError {
2135 var begin = get_location ();
2136 expect (TokenType.TRY);
2137 expect (TokenType.EOL);
2138 var try_block = parse_block ();
2139 Block finally_clause = null;
2140 var catch_clauses = new ArrayList<CatchClause> ();
2141 if (current () == TokenType.EXCEPT) {
2142 parse_catch_clauses (catch_clauses);
2143 if (current () == TokenType.FINALLY) {
2144 finally_clause = parse_finally_clause ();
2146 } else {
2147 finally_clause = parse_finally_clause ();
2149 var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
2150 foreach (CatchClause clause in catch_clauses) {
2151 stmt.add_catch_clause (clause);
2153 return stmt;
2156 void parse_catch_clauses (List<CatchClause> catch_clauses) throws ParseError {
2157 while (accept (TokenType.EXCEPT)) {
2158 var begin = get_location ();
2159 DataType type = null;
2160 string id = null;
2161 if (!accept (TokenType.EOL)) {
2162 id = parse_identifier ();
2163 expect (TokenType.COLON);
2164 type = parse_type ();
2165 expect (TokenType.EOL);
2168 var block = parse_block ();
2169 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
2173 Block parse_finally_clause () throws ParseError {
2174 expect (TokenType.FINALLY);
2175 accept_block ();
2176 var block = parse_block ();
2177 return block;
2180 Statement parse_lock_statement () throws ParseError {
2181 var begin = get_location ();
2182 expect (TokenType.LOCK);
2183 expect (TokenType.OPEN_PARENS);
2184 var expr = parse_expression ();
2185 expect (TokenType.CLOSE_PARENS);
2186 var stmt = parse_embedded_statement ();
2187 return new LockStatement (expr, stmt, get_src (begin));
2190 Statement parse_delete_statement () throws ParseError {
2191 var begin = get_location ();
2192 expect (TokenType.DELETE);
2193 var expr = parse_expression ();
2194 expect_terminator ();
2195 return new DeleteStatement (expr, get_src (begin));
2198 List<Attribute>? parse_attributes () throws ParseError {
2199 if (current () != TokenType.OPEN_BRACKET) {
2200 return null;
2202 var attrs = new ArrayList<Attribute> ();
2203 while (accept (TokenType.OPEN_BRACKET)) {
2204 do {
2205 var begin = get_location ();
2206 string id = parse_identifier ();
2207 var attr = new Attribute (id, get_src (begin));
2208 if (accept (TokenType.OPEN_PARENS)) {
2209 if (current () != TokenType.CLOSE_PARENS) {
2210 do {
2211 id = parse_identifier ();
2212 expect (TokenType.ASSIGN);
2213 var expr = parse_expression ();
2214 attr.add_argument (id, expr);
2215 } while (accept (TokenType.COMMA));
2217 expect (TokenType.CLOSE_PARENS);
2219 attrs.add (attr);
2220 } while (accept (TokenType.COMMA));
2221 expect (TokenType.CLOSE_BRACKET);
2223 expect (TokenType.EOL);
2225 return attrs;
2228 void set_attributes (CodeNode node, List<Attribute>? attributes) {
2229 if (attributes != null) {
2230 foreach (Attribute attr in (List<Attribute>) attributes) {
2231 node.attributes.append (attr);
2236 Symbol parse_declaration (bool is_root = false) throws ParseError {
2237 comment = scanner.pop_comment ();
2238 var attrs = parse_attributes ();
2239 var begin = get_location ();
2241 switch (current ()) {
2242 case TokenType.CONST:
2243 return parse_constant_declaration (attrs);
2244 case TokenType.CONSTRUCT:
2245 return parse_creation_method_declaration (attrs);
2246 case TokenType.CLASS:
2247 return parse_class_declaration (attrs);
2248 case TokenType.INIT:
2249 if (is_root) {
2250 return parse_main_method_declaration (attrs);
2252 if (context.profile == Profile.GOBJECT) {
2253 rollback (begin);
2254 return parse_constructor_declaration (attrs);
2256 break;
2257 case TokenType.DELEGATE:
2258 return parse_delegate_declaration (attrs);
2259 case TokenType.DEF:
2260 return parse_method_declaration (attrs);
2261 case TokenType.ENUM:
2262 return parse_enum_declaration (attrs);
2263 case TokenType.ERRORDOMAIN:
2264 return parse_errordomain_declaration (attrs);
2265 case TokenType.FINAL:
2266 return parse_destructor_declaration (attrs);
2267 case TokenType.INTERFACE:
2268 return parse_interface_declaration (attrs);
2269 case TokenType.NAMESPACE:
2270 return parse_namespace_declaration (attrs);
2271 case TokenType.PROP:
2272 return parse_property_declaration (attrs);
2273 case TokenType.EVENT:
2274 return parse_signal_declaration (attrs);
2275 case TokenType.STRUCT:
2276 return parse_struct_declaration (attrs);
2277 default:
2279 while (current () != TokenType.EOL && current () != TokenType.SEMICOLON && current () != TokenType.EOF) {
2280 if (current () == TokenType.COLON) {
2281 rollback (begin);
2282 return parse_field_declaration (attrs);
2283 } else {
2284 next ();
2287 rollback (begin);
2289 break;
2292 TokenType cur = current ();
2293 TokenType pre = tokens[index-1].type;
2295 throw new ParseError.SYNTAX (get_error ("expected declaration but got %s with previous %s".printf (cur.to_string (), pre.to_string())));
2298 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
2299 if (!root) {
2300 expect (TokenType.INDENT);
2302 while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2303 try {
2304 if (parent is Namespace) {
2305 parse_namespace_member ((Namespace) parent);
2306 } else if (parent is Class) {
2307 parse_class_member ((Class) parent);
2308 } else if (parent is Struct) {
2309 parse_struct_member ((Struct) parent);
2310 } else if (parent is Interface) {
2311 parse_interface_member ((Interface) parent);
2313 } catch (ParseError e) {
2314 int r;
2315 do {
2316 r = recover ();
2317 if (r == RecoveryState.STATEMENT_BEGIN) {
2318 next ();
2319 } else {
2320 break;
2322 } while (true);
2323 if (r == RecoveryState.EOF) {
2324 return;
2328 if (!root) {
2329 if (!accept (TokenType.DEDENT)) {
2330 // only report error if it's not a secondary error
2331 if (context.report.get_errors () == 0) {
2332 Report.error (get_current_src (), "expected dedent");
2338 enum RecoveryState {
2339 EOF,
2340 DECLARATION_BEGIN,
2341 STATEMENT_BEGIN
2344 RecoveryState recover () {
2345 while (current () != TokenType.EOF) {
2346 switch (current ()) {
2347 case TokenType.CLASS:
2348 case TokenType.CONST:
2349 case TokenType.CONSTRUCT:
2350 case TokenType.INIT:
2351 case TokenType.DEF:
2352 case TokenType.DELEGATE:
2353 case TokenType.ENUM:
2354 case TokenType.ERRORDOMAIN:
2355 case TokenType.FINAL:
2356 case TokenType.INTERFACE:
2357 case TokenType.NAMESPACE:
2358 case TokenType.PROP:
2359 case TokenType.EVENT:
2360 case TokenType.STRUCT:
2361 return RecoveryState.DECLARATION_BEGIN;
2362 case TokenType.BREAK:
2363 case TokenType.CASE:
2364 case TokenType.CONTINUE:
2365 case TokenType.DELETE:
2366 case TokenType.DO:
2367 case TokenType.FOR:
2368 case TokenType.FOREACH:
2369 case TokenType.IF:
2370 case TokenType.LOCK:
2371 case TokenType.RETURN:
2372 case TokenType.RAISE:
2373 case TokenType.TRY:
2374 case TokenType.VAR:
2375 case TokenType.WHILE:
2376 case TokenType.YIELD:
2377 return RecoveryState.STATEMENT_BEGIN;
2378 default:
2379 next ();
2380 break;
2383 return RecoveryState.EOF;
2386 Namespace parse_namespace_declaration (List<Attribute>? attrs) throws ParseError {
2387 var begin = get_location ();
2388 expect (TokenType.NAMESPACE);
2389 var sym = parse_symbol_name ();
2390 var ns = new Namespace (sym.name, get_src (begin));
2391 if (comment != null) {
2392 ns.add_comment (comment);
2393 comment = null;
2395 set_attributes (ns, attrs);
2396 expect (TokenType.EOL);
2397 parse_declarations (ns);
2399 Namespace result = ns;
2400 while (sym.inner != null) {
2401 sym = sym.inner;
2402 ns = new Namespace (sym.name, result.source_reference);
2403 ns.add_namespace ((Namespace) result);
2404 result = ns;
2406 return result;
2409 void parse_namespace_member (Namespace ns) throws ParseError {
2411 var sym = parse_declaration ((ns == context.root));
2412 if (sym is Namespace) {
2413 ns.add_namespace ((Namespace) sym);
2414 } else if (sym is Class) {
2415 ns.add_class ((Class) sym);
2416 } else if (sym is Interface) {
2417 ns.add_interface ((Interface) sym);
2418 } else if (sym is Struct) {
2419 ns.add_struct ((Struct) sym);
2420 } else if (sym is Enum) {
2421 ns.add_enum ((Enum) sym);
2422 } else if (sym is ErrorDomain) {
2423 ns.add_error_domain ((ErrorDomain) sym);
2424 } else if (sym is Delegate) {
2425 ns.add_delegate ((Delegate) sym);
2426 } else if (sym is Method) {
2427 var method = (Method) sym;
2428 if (method.binding == MemberBinding.INSTANCE) {
2429 method.binding = MemberBinding.STATIC;
2431 ns.add_method (method);
2432 } else if (sym is Field) {
2433 var field = (Field) sym;
2434 if (field.binding == MemberBinding.INSTANCE) {
2435 field.binding = MemberBinding.STATIC;
2437 ns.add_field (field);
2438 } else if (sym is Constant) {
2439 ns.add_constant ((Constant) sym);
2440 } else {
2441 Report.error (sym.source_reference, "unexpected declaration in namespace");
2443 scanner.source_file.add_node (sym);
2447 void add_uses_clause (Namespace ns) throws ParseError {
2448 var begin = get_location ();
2449 var sym = parse_symbol_name ();
2450 var ns_ref = new UsingDirective (sym, get_src (begin));
2452 scanner.source_file.add_using_directive (ns_ref);
2453 ns.add_using_directive (ns_ref);
2456 void parse_using_directives (Namespace ns) throws ParseError {
2457 while (accept (TokenType.USES)) {
2458 if (accept_block ()) {
2459 expect (TokenType.INDENT);
2461 while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2462 add_uses_clause (ns);
2463 expect (TokenType.EOL);
2466 expect (TokenType.DEDENT);
2467 } else {
2468 do {
2469 add_uses_clause (ns);
2470 } while (accept (TokenType.COMMA));
2472 expect_terminator ();
2478 Symbol parse_class_declaration (List<Attribute>? attrs) throws ParseError {
2479 var begin = get_location ();
2480 expect (TokenType.CLASS);
2482 var flags = parse_type_declaration_modifiers ();
2484 var sym = parse_symbol_name ();
2485 var type_param_list = parse_type_parameter_list ();
2486 var base_types = new ArrayList<DataType> ();
2487 if (accept (TokenType.COLON)) {
2488 var type1 = parse_type ();
2489 base_types.add (type1);
2491 if (accept (TokenType.IMPLEMENTS)) {
2492 do {
2493 var type2 = parse_type ();
2494 base_types.add (type2);
2495 } while (accept (TokenType.COMMA));
2499 accept (TokenType.EOL);
2501 var cl = new Class (sym.name, get_src (begin), comment);
2503 if (ModifierFlags.PRIVATE in flags) {
2504 cl.access = SymbolAccessibility.PRIVATE;
2505 } else {
2506 /* class must always be Public unless its name starts wtih underscore */
2507 if (sym.name[0] == '_') {
2508 cl.access = SymbolAccessibility.PRIVATE;
2509 } else {
2510 cl.access = SymbolAccessibility.PUBLIC;
2514 if (ModifierFlags.ABSTRACT in flags) {
2515 cl.is_abstract = true;
2517 set_attributes (cl, attrs);
2518 foreach (TypeParameter type_param in type_param_list) {
2519 cl.add_type_parameter (type_param);
2521 foreach (DataType base_type in base_types) {
2522 cl.add_base_type (base_type);
2525 class_name = cl.name;
2527 parse_declarations (cl);
2529 // ensure there is always a default construction method
2530 if (!scanner.source_file.external_package
2531 && cl.default_construction_method == null) {
2532 var m = new CreationMethod (cl.name, null, cl.source_reference);
2533 m.access = SymbolAccessibility.PUBLIC;
2534 m.body = new Block (cl.source_reference);
2535 cl.add_method (m);
2538 Symbol result = cl;
2539 while (sym.inner != null) {
2540 sym = sym.inner;
2541 var ns = new Namespace (sym.name, cl.source_reference);
2542 if (result is Namespace) {
2543 ns.add_namespace ((Namespace) result);
2544 } else {
2545 ns.add_class ((Class) result);
2546 scanner.source_file.add_node (result);
2548 result = ns;
2550 return result;
2553 void parse_class_member (Class cl) throws ParseError {
2554 var sym = parse_declaration ();
2555 if (sym is Class) {
2556 cl.add_class ((Class) sym);
2557 } else if (sym is Struct) {
2558 cl.add_struct ((Struct) sym);
2559 } else if (sym is Enum) {
2560 cl.add_enum ((Enum) sym);
2561 } else if (sym is Delegate) {
2562 cl.add_delegate ((Delegate) sym);
2563 } else if (sym is Method) {
2564 cl.add_method ((Method) sym);
2565 } else if (sym is Vala.Signal) {
2566 cl.add_signal ((Vala.Signal) sym);
2567 } else if (sym is Field) {
2568 cl.add_field ((Field) sym);
2569 } else if (sym is Constant) {
2570 cl.add_constant ((Constant) sym);
2571 } else if (sym is Property) {
2572 cl.add_property ((Property) sym);
2573 } else if (sym is Constructor) {
2574 var c = (Constructor) sym;
2575 if (c.binding == MemberBinding.INSTANCE) {
2576 cl.constructor = c;
2577 } else if (c.binding == MemberBinding.CLASS) {
2578 cl.class_constructor = c;
2579 } else {
2580 cl.static_constructor = c;
2582 } else if (sym is Destructor) {
2583 var d = (Destructor) sym;
2584 if (d.binding == MemberBinding.STATIC) {
2585 cl.static_destructor = (Destructor) d;
2586 } else if (d.binding == MemberBinding.CLASS) {
2587 cl.class_destructor = (Destructor) d;
2588 } else {
2589 cl.destructor = (Destructor) d;
2591 } else {
2592 Report.error (sym.source_reference, "unexpected declaration in class");
2596 Constant parse_constant_declaration (List<Attribute>? attrs) throws ParseError {
2597 var begin = get_location ();
2599 expect (TokenType.CONST);
2601 var flags = parse_member_declaration_modifiers ();
2603 string id = parse_identifier ();
2605 expect (TokenType.COLON);
2606 var type = parse_type (false);
2607 type = parse_inline_array_type (type);
2609 Expression initializer = null;
2610 if (accept (TokenType.ASSIGN)) {
2611 initializer = parse_expression ();
2613 expect_terminator ();
2615 // constant arrays don't own their element
2616 var array_type = type as ArrayType;
2617 if (array_type != null) {
2618 array_type.element_type.value_owned = false;
2621 var c = new Constant (id, type, initializer, get_src (begin), comment);
2622 c.access = get_access (id);
2624 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2625 c.external = true;
2627 if (ModifierFlags.NEW in flags) {
2628 c.hides = true;
2631 set_attributes (c, attrs);
2632 return c;
2635 Field parse_field_declaration (List<Attribute>? attrs) throws ParseError {
2636 var begin = get_location ();
2637 string id = parse_identifier ();
2638 expect (TokenType.COLON);
2640 var flags = parse_member_declaration_modifiers ();
2642 var type = parse_type ();
2644 type = parse_inline_array_type (type);
2646 var f = new Field (id, type, null, get_src (begin), comment);
2648 if (ModifierFlags.ABSTRACT in flags || ModifierFlags.VIRTUAL in flags || ModifierFlags.OVERRIDE in flags) {
2649 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2652 if (ModifierFlags.PRIVATE in flags) {
2653 f.access = SymbolAccessibility.PRIVATE;
2654 } else {
2655 f.access = get_access (id);
2658 set_attributes (f, attrs);
2660 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2661 f.external = true;
2663 if (ModifierFlags.NEW in flags) {
2664 f.hides = true;
2667 if (accept (TokenType.ASSIGN)) {
2668 f.initializer = parse_expression ();
2671 if (ModifierFlags.STATIC in flags) {
2672 f.binding = MemberBinding.STATIC;
2673 } else if (ModifierFlags.CLASS in flags) {
2674 f.binding = MemberBinding.CLASS;
2677 expect_terminator ();
2679 return f;
2682 InitializerList parse_initializer () throws ParseError {
2683 var begin = get_location ();
2684 if (!accept (TokenType.OPEN_PARENS)) {
2685 expect (TokenType.OPEN_BRACE);
2687 var initializer = new InitializerList (get_src (begin));
2688 if (current () != TokenType.DEDENT) {
2689 do {
2690 var init = parse_argument ();
2691 initializer.append (init);
2692 } while (accept (TokenType.COMMA));
2694 if (!accept (TokenType.CLOSE_PARENS)) {
2695 expect (TokenType.CLOSE_BRACE);
2697 return initializer;
2703 Method parse_main_method_declaration (List<Attribute>? attrs) throws ParseError {
2704 var id = "main";
2705 var begin = get_location ();
2706 DataType type = new VoidType ();
2707 expect (TokenType.INIT);
2709 var method = new Method (id, type, get_src (begin), comment);
2710 method.access = SymbolAccessibility.PUBLIC;
2712 set_attributes (method, attrs);
2714 method.binding = MemberBinding.STATIC;
2716 var sym = new UnresolvedSymbol (null, "string", get_src (begin));
2717 type = new UnresolvedType.from_symbol (sym, get_src (begin));
2718 type.value_owned = true;
2719 type = new ArrayType (type, 1, get_src (begin));
2720 type.nullable = false;
2722 var param = new FormalParameter ("args", type, get_src (begin));
2723 method.add_parameter (param);
2726 expect (TokenType.EOL);
2728 if (accept_block ()) {
2729 method.body = parse_block ();
2732 return method;
2735 Method parse_method_declaration (List<Attribute>? attrs) throws ParseError {
2736 var begin = get_location ();
2737 DataType type = new VoidType ();
2738 expect (TokenType.DEF);
2739 var flags = parse_member_declaration_modifiers ();
2741 string id = parse_identifier ();
2743 var params = new ArrayList<FormalParameter> ();
2744 expect (TokenType.OPEN_PARENS);
2746 if (current () != TokenType.CLOSE_PARENS) {
2747 do {
2748 var param = parse_parameter ();
2749 params.add (param);
2750 } while (accept (TokenType.COMMA));
2753 expect (TokenType.CLOSE_PARENS);
2756 /* deal with return value */
2757 if (accept (TokenType.COLON)) {
2758 type = parse_type ();
2761 var type_param_list = parse_type_parameter_list ();
2763 var method = new Method (id, type, get_src (begin), comment);
2764 if (ModifierFlags.PRIVATE in flags) {
2765 method.access = SymbolAccessibility.PRIVATE;
2766 } else {
2767 method.access = get_access (id);
2771 set_attributes (method, attrs);
2773 foreach (TypeParameter type_param in type_param_list) {
2774 method.add_type_parameter (type_param);
2778 foreach (FormalParameter param in params) {
2779 method.add_parameter (param);
2782 if (accept (TokenType.RAISES)) {
2783 do {
2784 method.add_error_type (parse_type ());
2785 } while (accept (TokenType.COMMA));
2789 if (ModifierFlags.STATIC in flags || id == "main") {
2790 method.binding = MemberBinding.STATIC;
2791 } else if (ModifierFlags.CLASS in flags) {
2792 method.binding = MemberBinding.CLASS;
2794 if (ModifierFlags.ASYNC in flags) {
2795 method.coroutine = true;
2798 if (ModifierFlags.NEW in flags) {
2799 method.hides = true;
2802 if (method.binding == MemberBinding.INSTANCE) {
2803 if (ModifierFlags.ABSTRACT in flags) {
2804 method.is_abstract = true;
2806 if (ModifierFlags.VIRTUAL in flags) {
2807 method.is_virtual = true;
2809 if (ModifierFlags.OVERRIDE in flags) {
2810 method.overrides = true;
2812 if ((method.is_abstract && method.is_virtual)
2813 || (method.is_abstract && method.overrides)
2814 || (method.is_virtual && method.overrides)) {
2815 throw new ParseError.SYNTAX (get_error ("only one of `abstract', `virtual', or `override' may be specified"));
2817 } else {
2818 if (ModifierFlags.ABSTRACT in flags
2819 || ModifierFlags.VIRTUAL in flags
2820 || ModifierFlags.OVERRIDE in flags) {
2821 throw new ParseError.SYNTAX (get_error ("the modifiers `abstract', `virtual', and `override' are not valid for static methods"));
2825 if (ModifierFlags.INLINE in flags) {
2826 method.is_inline = true;
2828 if (ModifierFlags.EXTERN in flags) {
2829 method.external = true;
2832 expect (TokenType.EOL);
2834 var body_location = get_location ();
2837 /* "requires" and "ensures" if present will be at start of the method body */
2838 if (accept (TokenType.INDENT)) {
2839 if (accept (TokenType.REQUIRES)) {
2841 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
2842 while (current() != TokenType.DEDENT) {
2843 method.add_precondition (parse_expression ());
2844 expect (TokenType.EOL);
2847 expect (TokenType.DEDENT);
2848 accept_terminator ();
2849 } else {
2851 method.add_precondition (parse_expression ());
2852 expect_terminator ();
2858 if (accept (TokenType.ENSURES)) {
2859 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
2860 while (current() != TokenType.DEDENT) {
2861 method.add_postcondition (parse_expression ());
2862 expect (TokenType.EOL);
2865 expect (TokenType.DEDENT);
2866 accept_terminator ();
2867 } else {
2868 method.add_postcondition (parse_expression ());
2869 expect_terminator ();
2874 rollback (body_location);
2877 if (accept_block ()) {
2878 method.body = parse_block ();
2879 } else if (scanner.source_file.external_package) {
2880 method.external = true;
2882 return method;
2885 Property parse_property_declaration (List<Attribute>? attrs) throws ParseError {
2886 var begin = get_location ();
2887 var readonly = false;
2889 expect (TokenType.PROP);
2891 var flags = parse_member_declaration_modifiers ();
2893 readonly = accept (TokenType.READONLY);
2895 string id = parse_identifier ();
2896 expect (TokenType.COLON);
2898 var type = parse_type (false);
2900 var prop = new Property (id, type, null, null, get_src (begin), comment);
2901 if (ModifierFlags.PRIVATE in flags) {
2902 prop.access = SymbolAccessibility.PRIVATE;
2903 } else {
2904 prop.access = get_access (id);
2907 set_attributes (prop, attrs);
2909 if (ModifierFlags.STATIC in flags) {
2910 prop.binding = MemberBinding.STATIC;
2911 } else if (ModifierFlags.CLASS in flags) {
2912 prop.binding = MemberBinding.CLASS;
2914 if (ModifierFlags.ABSTRACT in flags) {
2915 prop.is_abstract = true;
2917 if (ModifierFlags.VIRTUAL in flags) {
2918 prop.is_virtual = true;
2920 if (ModifierFlags.OVERRIDE in flags) {
2921 prop.overrides = true;
2924 if (ModifierFlags.NEW in flags) {
2925 prop.hides = true;
2927 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2928 prop.external = true;
2931 if (ModifierFlags.ASYNC in flags) {
2932 Report.error (prop.source_reference, "async properties are not supported yet");
2935 if (accept (TokenType.ASSIGN)) {
2936 prop.default_expression = parse_expression ();
2940 if (accept_block ()) {
2941 expect (TokenType.INDENT);
2942 while (current () != TokenType.DEDENT) {
2943 var accessor_begin = get_location ();
2944 var attribs = parse_attributes ();
2946 var value_type = type.copy ();
2947 value_type.value_owned = accept (TokenType.OWNED);
2949 if (accept (TokenType.GET)) {
2950 if (prop.get_accessor != null) {
2951 throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
2953 Block block = null;
2954 if (accept_block ()) {
2955 block = parse_block ();
2956 prop.external = false;
2958 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin));
2959 set_attributes (prop.get_accessor, attribs);
2960 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
2961 } else {
2962 bool _construct = false;
2963 if (accept (TokenType.SET)) {
2964 if (readonly) {
2965 throw new ParseError.SYNTAX (get_error ("set block not allowed for a read only property"));
2967 _construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT);
2968 } else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) {
2969 _construct = true;
2970 } else if (!accept (TokenType.EOL)) {
2971 throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
2974 if (prop.set_accessor != null) {
2975 throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
2978 Block block = null;
2979 if (accept_block ()) {
2980 block = parse_block ();
2981 prop.external = false;
2983 prop.set_accessor = new PropertyAccessor (false, !readonly, _construct, value_type, block, get_src (accessor_begin));
2984 set_attributes (prop.set_accessor, attribs);
2985 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
2988 accept (TokenType.EOL);
2989 expect (TokenType.DEDENT);
2990 } else {
2991 var value_type = type.copy ();
2992 value_type.value_owned = false;
2994 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, null, get_src (begin));
2995 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
2997 if (!readonly) {
2998 value_type = type.copy ();
2999 value_type.value_owned = false;
3001 prop.set_accessor = new PropertyAccessor (false, true, false, value_type, null, get_src (begin));
3002 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3006 expect_terminator ();
3009 if (!prop.is_abstract && !scanner.source_file.external_package) {
3010 var needs_var = (readonly && (prop.get_accessor != null && prop.get_accessor.body == null));
3012 if (!needs_var) {
3013 needs_var = (prop.get_accessor != null && prop.get_accessor.body == null) || (prop.set_accessor != null && prop.set_accessor.body == null);
3016 if (needs_var) {
3017 /* automatic property accessor body generation */
3018 var field_type = prop.property_type.copy ();
3019 prop.field = new Field ("_%s".printf (prop.name), field_type, prop.default_expression, prop.source_reference);
3020 prop.field.access = SymbolAccessibility.PRIVATE;
3021 prop.field.binding = prop.binding;
3025 return prop;
3028 Vala.Signal parse_signal_declaration (List<Attribute>? attrs) throws ParseError {
3029 var begin = get_location ();
3030 DataType type;
3032 expect (TokenType.EVENT);
3033 var flags = parse_member_declaration_modifiers ();
3034 string id = parse_identifier ();
3037 var params = new ArrayList<FormalParameter> ();
3039 expect (TokenType.OPEN_PARENS);
3040 if (current () != TokenType.CLOSE_PARENS) {
3041 do {
3042 var param = parse_parameter ();
3043 params.add (param);
3044 } while (accept (TokenType.COMMA));
3046 expect (TokenType.CLOSE_PARENS);
3048 if (accept (TokenType.COLON)) {
3049 type = parse_type ();
3050 } else {
3051 type = new VoidType ();
3054 var sig = new Vala.Signal (id, type, get_src (begin), comment);
3055 if (ModifierFlags.PRIVATE in flags) {
3056 sig.access = SymbolAccessibility.PRIVATE;
3057 } else {
3058 sig.access = get_access (id);
3061 if (ModifierFlags.VIRTUAL in flags) {
3062 sig.is_virtual = true;
3064 if (ModifierFlags.NEW in flags) {
3065 sig.hides = true;
3067 set_attributes (sig, attrs);
3069 if (ModifierFlags.STATIC in flags) {
3070 throw new ParseError.SYNTAX (get_error ("`static' modifier not allowed on signals"));
3071 } else if (ModifierFlags.CLASS in flags) {
3072 throw new ParseError.SYNTAX (get_error ("`class' modifier not allowed on signals"));
3075 foreach (FormalParameter formal_param in params) {
3076 sig.add_parameter (formal_param);
3079 if (!accept_terminator ()) {
3080 sig.body = parse_block ();
3082 return sig;
3085 Constructor parse_constructor_declaration (List<Attribute>? attrs) throws ParseError {
3086 var begin = get_location ();
3088 expect (TokenType.INIT);
3089 var flags = parse_member_declaration_modifiers ();
3091 var c = new Constructor (get_src (begin));
3092 if (ModifierFlags.STATIC in flags) {
3093 c.binding = MemberBinding.STATIC;
3094 } else if (ModifierFlags.CLASS in flags) {
3095 c.binding = MemberBinding.CLASS;
3098 accept_block ();
3099 c.body = parse_block ();
3100 return c;
3103 Destructor parse_destructor_declaration (List<Attribute>? attrs) throws ParseError {
3104 var begin = get_location ();
3105 expect (TokenType.FINAL);
3106 var d = new Destructor (get_src (begin));
3107 accept_block ();
3108 d.body = parse_block ();
3109 return d;
3112 Symbol parse_struct_declaration (List<Attribute>? attrs) throws ParseError {
3113 var begin = get_location ();
3115 expect (TokenType.STRUCT);
3116 var flags = parse_type_declaration_modifiers ();
3117 var sym = parse_symbol_name ();
3118 var type_param_list = parse_type_parameter_list ();
3119 DataType base_type = null;
3120 if (accept (TokenType.COLON)) {
3121 base_type = parse_type ();
3124 var st = new Struct (sym.name, get_src (begin), comment);
3125 if (ModifierFlags.PRIVATE in flags) {
3126 st.access = SymbolAccessibility.PRIVATE;
3127 } else {
3128 st.access = get_access (sym.name);
3130 set_attributes (st, attrs);
3131 foreach (TypeParameter type_param in type_param_list) {
3132 st.add_type_parameter (type_param);
3134 if (base_type != null) {
3135 st.base_type = base_type;
3138 expect (TokenType.EOL);
3140 parse_declarations (st);
3142 Symbol result = st;
3143 while (sym.inner != null) {
3144 sym = sym.inner;
3145 var ns = new Namespace (sym.name, st.source_reference);
3146 if (result is Namespace) {
3147 ns.add_namespace ((Namespace) result);
3148 } else {
3149 ns.add_struct ((Struct) result);
3150 scanner.source_file.add_node (result);
3152 result = ns;
3154 return result;
3157 void parse_struct_member (Struct st) throws ParseError {
3158 var sym = parse_declaration ();
3159 if (sym is Method) {
3160 st.add_method ((Method) sym);
3161 } else if (sym is Field) {
3162 st.add_field ((Field) sym);
3163 } else if (sym is Constant) {
3164 st.add_constant ((Constant) sym);
3165 } else {
3166 Report.error (sym.source_reference, "unexpected declaration in struct");
3170 Symbol parse_interface_declaration (List<Attribute>? attrs) throws ParseError {
3171 var begin = get_location ();
3173 expect (TokenType.INTERFACE);
3174 var flags = parse_type_declaration_modifiers ();
3175 var sym = parse_symbol_name ();
3176 var type_param_list = parse_type_parameter_list ();
3177 var base_types = new ArrayList<DataType> ();
3178 if (accept (TokenType.COLON)) {
3179 do {
3180 var type = parse_type ();
3181 base_types.add (type);
3182 } while (accept (TokenType.COMMA));
3185 var iface = new Interface (sym.name, get_src (begin), comment);
3186 if (ModifierFlags.PRIVATE in flags) {
3187 iface.access = SymbolAccessibility.PRIVATE;
3188 } else {
3189 iface.access = get_access (sym.name);
3191 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
3192 iface.external = true;
3194 set_attributes (iface, attrs);
3195 foreach (TypeParameter type_param in type_param_list) {
3196 iface.add_type_parameter (type_param);
3198 foreach (DataType base_type in base_types) {
3199 iface.add_prerequisite (base_type);
3203 expect (TokenType.EOL);
3205 parse_declarations (iface);
3208 Symbol result = iface;
3209 while (sym.inner != null) {
3210 sym = sym.inner;
3211 var ns = new Namespace (sym.name, iface.source_reference);
3212 if (result is Namespace) {
3213 ns.add_namespace ((Namespace) result);
3214 } else {
3215 ns.add_interface ((Interface) result);
3216 scanner.source_file.add_node (result);
3218 result = ns;
3220 return result;
3223 void parse_interface_member (Interface iface) throws ParseError {
3224 var sym = parse_declaration ();
3225 if (sym is Class) {
3226 iface.add_class ((Class) sym);
3227 } else if (sym is Struct) {
3228 iface.add_struct ((Struct) sym);
3229 } else if (sym is Enum) {
3230 iface.add_enum ((Enum) sym);
3231 } else if (sym is Delegate) {
3232 iface.add_delegate ((Delegate) sym);
3233 } else if (sym is Method) {
3234 iface.add_method ((Method) sym);
3235 } else if (sym is Vala.Signal) {
3236 iface.add_signal ((Vala.Signal) sym);
3237 } else if (sym is Field) {
3238 iface.add_field ((Field) sym);
3239 } else if (sym is Constant) {
3240 iface.add_constant ((Constant) sym);
3241 } else if (sym is Property) {
3242 iface.add_property ((Property) sym);
3243 } else {
3244 Report.error (sym.source_reference, "unexpected declaration in interface");
3248 Symbol parse_enum_declaration (List<Attribute>? attrs) throws ParseError {
3249 var begin = get_location ();
3250 expect (TokenType.ENUM);
3251 var flags = parse_type_declaration_modifiers ();
3253 var sym = parse_symbol_name ();
3254 var en = new Enum (sym.name, get_src (begin), comment);
3255 if (ModifierFlags.PRIVATE in flags) {
3256 en.access = SymbolAccessibility.PRIVATE;
3257 } else {
3258 en.access = get_access (sym.name);
3260 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
3261 en.external = true;
3263 set_attributes (en, attrs);
3265 expect (TokenType.EOL);
3266 expect (TokenType.INDENT);
3267 do {
3268 if (current () == TokenType.DEDENT) {
3269 // allow trailing comma
3270 break;
3272 var value_attrs = parse_attributes ();
3273 var value_begin = get_location ();
3274 string id = parse_identifier ();
3275 comment = scanner.pop_comment ();
3276 var ev = new EnumValue (id, get_src (value_begin), comment);
3277 set_attributes (ev, value_attrs);
3279 if (accept (TokenType.ASSIGN)) {
3280 ev.value = parse_expression ();
3282 en.add_value (ev);
3283 expect (TokenType.EOL);
3284 } while (true);
3286 expect (TokenType.DEDENT);
3288 Symbol result = en;
3289 while (sym.inner != null) {
3290 sym = sym.inner;
3291 var ns = new Namespace (sym.name, en.source_reference);
3292 if (result is Namespace) {
3293 ns.add_namespace ((Namespace) result);
3294 } else {
3295 ns.add_enum ((Enum) result);
3296 scanner.source_file.add_node (result);
3298 result = ns;
3300 return result;
3303 Symbol parse_errordomain_declaration (List<Attribute>? attrs) throws ParseError {
3304 var begin = get_location ();
3305 expect (TokenType.ERRORDOMAIN);
3306 var flags = parse_type_declaration_modifiers ();
3308 var sym = parse_symbol_name ();
3309 var ed = new ErrorDomain (sym.name, get_src (begin), comment);
3310 if (ModifierFlags.PRIVATE in flags) {
3311 ed.access = SymbolAccessibility.PRIVATE;
3312 } else {
3313 ed.access = get_access (sym.name);
3316 set_attributes (ed, attrs);
3318 expect (TokenType.EOL);
3319 expect (TokenType.INDENT);
3321 do {
3322 if (current () == TokenType.DEDENT) {
3323 // allow trailing comma
3324 break;
3326 var code_attrs = parse_attributes ();
3327 var code_begin = get_location ();
3328 string id = parse_identifier ();
3329 comment = scanner.pop_comment ();
3330 var ec = new ErrorCode (id, get_src (code_begin), comment);
3331 set_attributes (ec, code_attrs);
3332 if (accept (TokenType.ASSIGN)) {
3333 ec.value = parse_expression ();
3335 ed.add_code (ec);
3336 accept (TokenType.EOL);
3337 } while (true);
3340 expect (TokenType.DEDENT);
3342 Symbol result = ed;
3343 while (sym.inner != null) {
3344 sym = sym.inner;
3345 var ns = new Namespace (sym.name, ed.source_reference);
3347 if (result is Namespace) {
3348 ns.add_namespace ((Namespace) result);
3349 } else {
3350 ns.add_error_domain ((ErrorDomain) result);
3351 scanner.source_file.add_node (result);
3353 result = ns;
3355 return result;
3358 ModifierFlags parse_type_declaration_modifiers () {
3359 ModifierFlags flags = 0;
3360 while (true) {
3361 switch (current ()) {
3362 case TokenType.ABSTRACT:
3363 next ();
3364 flags |= ModifierFlags.ABSTRACT;
3365 break;
3367 case TokenType.EXTERN:
3368 next ();
3369 flags |= ModifierFlags.EXTERN;
3370 break;
3372 case TokenType.STATIC:
3373 next ();
3374 flags |= ModifierFlags.STATIC;
3375 break;
3377 case TokenType.PRIVATE:
3378 next ();
3379 flags |= ModifierFlags.PRIVATE;
3380 break;
3382 default:
3383 return flags;
3388 ModifierFlags parse_member_declaration_modifiers () {
3389 ModifierFlags flags = 0;
3390 while (true) {
3391 switch (current ()) {
3392 case TokenType.ABSTRACT:
3393 next ();
3394 flags |= ModifierFlags.ABSTRACT;
3395 break;
3396 case TokenType.ASYNC:
3397 next ();
3398 flags |= ModifierFlags.ASYNC;
3399 break;
3400 case TokenType.CLASS:
3401 next ();
3402 flags |= ModifierFlags.CLASS;
3403 break;
3404 case TokenType.EXTERN:
3405 next ();
3406 flags |= ModifierFlags.EXTERN;
3407 break;
3408 case TokenType.INLINE:
3409 next ();
3410 flags |= ModifierFlags.INLINE;
3411 break;
3412 case TokenType.NEW:
3413 next ();
3414 flags |= ModifierFlags.NEW;
3415 break;
3416 case TokenType.OVERRIDE:
3417 next ();
3418 flags |= ModifierFlags.OVERRIDE;
3419 break;
3420 case TokenType.STATIC:
3421 next ();
3422 flags |= ModifierFlags.STATIC;
3423 break;
3424 case TokenType.VIRTUAL:
3425 next ();
3426 flags |= ModifierFlags.VIRTUAL;
3427 break;
3428 case TokenType.PRIVATE:
3429 next ();
3430 flags |= ModifierFlags.PRIVATE;
3431 break;
3432 default:
3433 return flags;
3438 FormalParameter parse_parameter () throws ParseError {
3439 var attrs = parse_attributes ();
3440 var begin = get_location ();
3441 if (accept (TokenType.ELLIPSIS)) {
3442 // varargs
3443 return new FormalParameter.with_ellipsis (get_src (begin));
3445 bool params_array = accept (TokenType.PARAMS);
3446 var direction = ParameterDirection.IN;
3447 if (accept (TokenType.OUT)) {
3448 direction = ParameterDirection.OUT;
3449 } else if (accept (TokenType.REF)) {
3450 direction = ParameterDirection.REF;
3453 string id = parse_identifier ();
3455 expect (TokenType.COLON);
3457 DataType type;
3458 if (direction == ParameterDirection.IN) {
3459 type = parse_type (false);
3460 } else {
3461 type = parse_type (true);
3464 var param = new FormalParameter (id, type, get_src (begin));
3465 set_attributes (param, attrs);
3466 param.direction = direction;
3467 param.params_array = params_array;
3468 if (accept (TokenType.ASSIGN)) {
3469 param.default_expression = parse_expression ();
3471 return param;
3474 CreationMethod parse_creation_method_declaration (List<Attribute>? attrs) throws ParseError {
3475 var begin = get_location ();
3476 CreationMethod method;
3478 expect (TokenType.CONSTRUCT);
3479 parse_member_declaration_modifiers ();
3481 if (accept (TokenType.OPEN_PARENS)) {
3482 /* create default name using class name */
3483 method = new CreationMethod (class_name, null, get_src (begin), comment);
3484 } else {
3485 var sym = parse_symbol_name ();
3486 if (sym.inner == null) {
3488 if (sym.name != class_name) {
3489 method = new CreationMethod (class_name, sym.name, get_src (begin), comment);
3490 } else {
3491 method = new CreationMethod (sym.name, null, get_src (begin), comment);
3493 } else {
3494 method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
3496 expect (TokenType.OPEN_PARENS);
3499 if (current () != TokenType.CLOSE_PARENS) {
3500 do {
3501 var param = parse_parameter ();
3502 method.add_parameter (param);
3503 } while (accept (TokenType.COMMA));
3505 expect (TokenType.CLOSE_PARENS);
3506 if (accept (TokenType.RAISES)) {
3507 do {
3508 method.add_error_type (parse_type ());
3509 } while (accept (TokenType.COMMA));
3511 method.access = SymbolAccessibility.PUBLIC;
3512 set_attributes (method, attrs);
3513 method.binding = MemberBinding.STATIC;
3515 if (accept_block ()) {
3516 method.body = parse_block ();
3517 } else if (scanner.source_file.external_package) {
3518 method.external = true;
3521 return method;
3524 Symbol parse_delegate_declaration (List<Attribute>? attrs) throws ParseError {
3525 var begin = get_location ();
3526 DataType type;
3528 expect (TokenType.DELEGATE);
3530 var flags = parse_member_declaration_modifiers ();
3532 var sym = parse_symbol_name ();
3534 var type_param_list = parse_type_parameter_list ();
3536 if (ModifierFlags.NEW in flags) {
3537 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on delegates"));
3540 var params = new ArrayList<FormalParameter> ();
3542 expect (TokenType.OPEN_PARENS);
3543 if (current () != TokenType.CLOSE_PARENS) {
3544 do {
3545 var param = parse_parameter ();
3546 params.add (param);
3547 } while (accept (TokenType.COMMA));
3549 expect (TokenType.CLOSE_PARENS);
3551 if (accept (TokenType.COLON)) {
3552 type = parse_type ();
3554 } else {
3555 type = new VoidType ();
3558 var d = new Delegate (sym.name, type, get_src (begin), comment);
3560 if (accept (TokenType.RAISES)) {
3561 do {
3562 d.add_error_type (parse_type ());
3563 } while (accept (TokenType.COMMA));
3566 expect_terminator ();
3569 if (ModifierFlags.PRIVATE in flags) {
3570 d.access = SymbolAccessibility.PRIVATE;
3571 } else {
3572 d.access = get_access (sym.name);
3575 if (!(ModifierFlags.STATIC in flags)) {
3576 d.has_target = true;
3578 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
3579 d.external = true;
3582 set_attributes (d, attrs);
3584 foreach (TypeParameter type_param in type_param_list) {
3585 d.add_type_parameter (type_param);
3588 foreach (FormalParameter formal_param in params) {
3589 d.add_parameter (formal_param);
3594 Symbol result = d;
3595 while (sym.inner != null) {
3596 sym = sym.inner;
3597 var ns = new Namespace (sym.name, d.source_reference);
3599 if (result is Namespace) {
3600 ns.add_namespace ((Namespace) result);
3601 } else {
3602 ns.add_delegate ((Delegate) result);
3603 scanner.source_file.add_node (result);
3605 result = ns;
3607 return result;
3610 List<TypeParameter> parse_type_parameter_list () throws ParseError {
3611 var list = new ArrayList<TypeParameter> ();
3612 if (accept (TokenType.OF)) {
3613 do {
3614 var begin = get_location ();
3615 string id = parse_identifier ();
3616 list.add (new TypeParameter (id, get_src (begin)));
3617 } while (accept (TokenType.COMMA));
3620 return list;
3623 void skip_type_argument_list () throws ParseError {
3624 if (accept (TokenType.OF)) {
3625 do {
3626 skip_type ();
3627 } while (accept (TokenType.COMMA));
3631 // try to parse type argument list
3632 List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3633 var begin = get_location ();
3634 if (accept (TokenType.OF)) {
3635 var list = new ArrayList<DataType> ();
3636 do {
3637 switch (current ()) {
3638 case TokenType.VOID:
3639 case TokenType.DYNAMIC:
3640 case TokenType.UNOWNED:
3641 case TokenType.WEAK:
3642 case TokenType.IDENTIFIER:
3643 var type = parse_type ();
3645 list.add (type);
3646 break;
3647 default:
3648 rollback (begin);
3649 return null;
3651 } while (accept (TokenType.COMMA));
3653 return list;
3655 return null;
3658 MemberAccess parse_member_name () throws ParseError {
3659 var begin = get_location ();
3660 MemberAccess expr = null;
3661 do {
3662 string id = parse_identifier ();
3663 List<DataType> type_arg_list = parse_type_argument_list (false);
3664 expr = new MemberAccess (expr, id, get_src (begin));
3665 if (type_arg_list != null) {
3666 foreach (DataType type_arg in type_arg_list) {
3667 expr.add_type_argument (type_arg);
3670 } while (accept (TokenType.DOT));
3671 return expr;