girparser: Guess virtual method wrapper variant when possible
[vala-lang.git] / vala / valagenieparser.vala
blob51ba7c1db191dd5fcb9808a5b2172db12b3f0858
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 static List<TypeParameter> _empty_type_parameter_list;
53 struct TokenInfo {
54 public TokenType type;
55 public SourceLocation begin;
56 public SourceLocation end;
59 enum ModifierFlags {
60 NONE,
61 ABSTRACT = 1 << 0,
62 CLASS = 1 << 1,
63 EXTERN = 1 << 2,
64 INLINE = 1 << 3,
65 NEW = 1 << 4,
66 OVERRIDE = 1 << 5,
67 STATIC = 1 << 6,
68 VIRTUAL = 1 << 7,
69 PRIVATE = 1 << 8,
70 ASYNC = 1 << 9
73 public Parser () {
74 tokens = new TokenInfo[BUFFER_SIZE];
75 class_name = null;
76 current_expr_is_lambda = false;
79 /**
80 * Parses all .gs source files in the specified code context and
81 * builds a code tree.
83 * @param context a code context
85 public void parse (CodeContext context) {
86 this.context = context;
87 context.accept (this);
90 public override void visit_source_file (SourceFile source_file) {
91 if (source_file.filename.has_suffix (".gs")) {
92 parse_file (source_file);
96 inline bool next () {
97 index = (index + 1) % BUFFER_SIZE;
98 size--;
99 if (size <= 0) {
100 SourceLocation begin, end;
101 TokenType type = scanner.read_token (out begin, out end);
102 tokens[index].type = type;
103 tokens[index].begin = begin;
104 tokens[index].end = end;
105 size = 1;
107 return (tokens[index].type != TokenType.EOF);
110 inline void prev () {
111 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
112 size++;
113 assert (size <= BUFFER_SIZE);
116 inline TokenType current () {
117 return tokens[index].type;
120 inline bool accept (TokenType type) {
121 if (current () == type) {
122 next ();
123 return true;
125 return false;
128 inline bool accept_terminator () {
129 if (current () == TokenType.SEMICOLON || current () == TokenType.EOL) {
130 next ();
131 return true;
133 return false;
136 inline bool accept_block () {
138 bool has_term = accept_terminator ();
140 if (accept (TokenType.INDENT)) {
141 prev();
142 return true;
145 if (has_term) {
146 prev ();
149 return false;
152 string get_error (string msg) {
153 var begin = get_location ();
154 next ();
155 Report.error (get_src (begin), "syntax error, " + msg);
156 return msg;
159 inline bool expect (TokenType type) throws ParseError {
160 if (accept (type)) {
161 return true;
164 TokenType cur = current ();
165 TokenType pre = tokens[index - 1].type;
167 throw new ParseError.SYNTAX (get_error ("expected %s but got %s with previous %s".printf (type.to_string (), cur.to_string (), pre.to_string())));
170 inline bool expect_terminator () throws ParseError {
171 if (accept_terminator ()) {
172 return true;
175 TokenType cur = current ();
177 throw new ParseError.SYNTAX (get_error ("expected line end or semicolon but got %s".printf (cur.to_string())));
180 inline SourceLocation get_location () {
181 return tokens[index].begin;
184 string get_current_string () {
185 return ((string) tokens[index].begin.pos).ndup ((tokens[index].end.pos - tokens[index].begin.pos));
188 string get_last_string () {
189 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
190 return ((string) tokens[last_index].begin.pos).ndup ((tokens[last_index].end.pos - tokens[last_index].begin.pos));
193 SourceReference get_src (SourceLocation begin) {
194 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
196 return new SourceReference (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
199 SourceReference get_current_src () {
200 return new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column);
203 void rollback (SourceLocation location) {
204 while (tokens[index].begin.pos != location.pos) {
205 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
206 size++;
207 if (size > BUFFER_SIZE) {
208 scanner.seek (location);
209 size = 0;
210 index = 0;
212 next ();
217 inline SymbolAccessibility get_access (string s) {
218 if (s[0] == '_') {
219 return SymbolAccessibility.PRIVATE;
222 return SymbolAccessibility.PUBLIC;
225 void skip_identifier () throws ParseError {
226 // also accept keywords as identifiers where there is no conflict
227 switch (current ()) {
228 case TokenType.ABSTRACT:
229 case TokenType.AS:
230 case TokenType.ASSERT:
231 case TokenType.ASYNC:
232 case TokenType.BREAK:
233 case TokenType.CLASS:
234 case TokenType.CONST:
235 case TokenType.CONTINUE:
236 case TokenType.DEDENT:
237 case TokenType.DEF:
238 case TokenType.DEFAULT:
239 case TokenType.DELEGATE:
240 case TokenType.DELETE:
241 case TokenType.DO:
242 case TokenType.DOWNTO:
243 case TokenType.DYNAMIC:
244 case TokenType.ELSE:
245 case TokenType.EOL:
246 case TokenType.ENUM:
247 case TokenType.ENSURES:
248 case TokenType.ERRORDOMAIN:
249 case TokenType.EVENT:
250 case TokenType.EXCEPT:
251 case TokenType.EXTERN:
252 case TokenType.FALSE:
253 case TokenType.FINAL:
254 case TokenType.FINALLY:
255 case TokenType.FOR:
256 case TokenType.GET:
257 case TokenType.IDENTIFIER:
258 case TokenType.IF:
259 case TokenType.IN:
260 case TokenType.INDENT:
261 case TokenType.INIT:
262 case TokenType.INLINE:
263 case TokenType.INTERFACE:
264 case TokenType.INTERNAL:
265 case TokenType.IS:
266 case TokenType.ISA:
267 case TokenType.LOCK:
268 case TokenType.NAMESPACE:
269 case TokenType.NEW:
270 case TokenType.NULL:
271 case TokenType.OF:
272 case TokenType.OUT:
273 case TokenType.OVERRIDE:
274 case TokenType.OWNED:
275 case TokenType.PASS:
276 case TokenType.PRINT:
277 case TokenType.PRIVATE:
278 case TokenType.PROP:
279 case TokenType.RAISE:
280 case TokenType.RAISES:
281 case TokenType.REF:
282 case TokenType.REQUIRES:
283 case TokenType.RETURN:
284 case TokenType.SET:
285 case TokenType.SIZEOF:
286 case TokenType.STATIC:
287 case TokenType.STRUCT:
288 case TokenType.SUPER:
289 case TokenType.THIS:
290 case TokenType.TO:
291 case TokenType.TRUE:
292 case TokenType.TRY:
293 case TokenType.TYPEOF:
294 case TokenType.UNOWNED:
295 case TokenType.USES:
296 case TokenType.VAR:
297 case TokenType.VIRTUAL:
298 case TokenType.VOID:
299 case TokenType.VOLATILE:
300 case TokenType.WEAK:
301 case TokenType.WHEN:
302 case TokenType.WHILE:
303 case TokenType.YIELD:
304 next ();
305 return;
306 case TokenType.INTEGER_LITERAL:
307 case TokenType.REAL_LITERAL:
308 // also accept integer and real literals
309 // as long as they contain at least one character
310 // and no decimal point
311 // for example, 2D and 3D
312 string id = get_current_string ();
313 if (id[id.length - 1].isalpha () && !("." in id)) {
314 next ();
315 return;
317 break;
318 default:
319 throw new ParseError.SYNTAX (get_error ("expected identifier"));
323 string parse_identifier () throws ParseError {
324 skip_identifier ();
325 return get_last_string ();
328 Expression parse_literal () throws ParseError {
329 var begin = get_location ();
331 switch (current ()) {
332 case TokenType.TRUE:
333 next ();
334 return new BooleanLiteral (true, get_src (begin));
335 case TokenType.FALSE:
336 next ();
337 return new BooleanLiteral (false, get_src (begin));
338 case TokenType.INTEGER_LITERAL:
339 next ();
340 return new IntegerLiteral (get_last_string (), get_src (begin));
341 case TokenType.REAL_LITERAL:
342 next ();
343 return new RealLiteral (get_last_string (), get_src (begin));
344 case TokenType.CHARACTER_LITERAL:
345 next ();
346 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
347 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
348 if (lit.error) {
349 Report.error (lit.source_reference, "invalid character literal");
351 return lit;
352 case TokenType.REGEX_LITERAL:
353 next ();
354 string match_part = get_last_string ();
355 SourceReference src_begin = get_src (begin);
356 expect (TokenType.CLOSE_REGEX_LITERAL);
357 string close_token = get_last_string ();
358 return new RegexLiteral ("%s/%s".printf (close_token, match_part), src_begin);
359 case TokenType.STRING_LITERAL:
360 next ();
361 return new StringLiteral (get_last_string (), get_src (begin));
362 case TokenType.TEMPLATE_STRING_LITERAL:
363 next ();
364 return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
365 case TokenType.VERBATIM_STRING_LITERAL:
366 next ();
367 string raw_string = get_last_string ();
368 string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
369 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
370 case TokenType.NULL:
371 next ();
372 return new NullLiteral (get_src (begin));
373 default:
374 throw new ParseError.SYNTAX (get_error ("expected literal"));
378 public void parse_file (SourceFile source_file) {
379 scanner = new Scanner (source_file);
380 scanner.parse_file_comments ();
381 scanner.indent_spaces = 0;
382 index = -1;
383 size = 0;
385 next ();
387 try {
388 var begin = get_location ();
389 /* see if there is an indent attribute */
390 if (accept (TokenType.OPEN_BRACKET)) {
391 var id = parse_identifier ();
392 if (id == "indent") {
393 expect (TokenType.ASSIGN);
394 expect (TokenType.INTEGER_LITERAL);
395 scanner.indent_spaces = get_last_string().to_int();
396 expect (TokenType.CLOSE_BRACKET);
397 expect (TokenType.EOL);
398 } else {
399 rollback (begin);
403 parse_using_directives (context.root);
404 parse_declarations (context.root, true);
405 } catch (ParseError e) {
406 // already reported
409 scanner = null;
412 void skip_symbol_name () throws ParseError {
413 do {
414 skip_identifier ();
415 } while (accept (TokenType.DOT));
418 UnresolvedSymbol parse_symbol_name () throws ParseError {
419 var begin = get_location ();
420 UnresolvedSymbol sym = null;
421 do {
422 string name = parse_identifier ();
423 sym = new UnresolvedSymbol (sym, name, get_src (begin));
424 } while (accept (TokenType.DOT));
425 return sym;
428 void skip_type () throws ParseError {
429 if (accept (TokenType.VOID)) {
430 while (accept (TokenType.STAR)) {
432 return;
434 accept (TokenType.DYNAMIC);
435 accept (TokenType.OWNED);
436 accept (TokenType.UNOWNED);
437 accept (TokenType.WEAK);
438 if (accept (TokenType.ARRAY) || accept (TokenType.LIST) || accept (TokenType.DICT)) {
439 accept (TokenType.OF);
442 skip_symbol_name ();
443 skip_type_argument_list ();
444 while (accept (TokenType.OPEN_BRACKET)) {
445 do {
446 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
447 parse_expression ();
449 } while (accept (TokenType.COMMA));
450 expect (TokenType.CLOSE_BRACKET);
452 accept (TokenType.OP_NEG);
453 accept (TokenType.INTERR);
454 accept (TokenType.HASH);
458 Expression parse_regex_literal () throws ParseError {
459 expect (TokenType.OPEN_REGEX_LITERAL);
461 var expr = parse_literal ();
463 return expr;
466 DataType parse_type (bool owned_by_default = true) throws ParseError {
467 var begin = get_location ();
469 if (accept (TokenType.VOID)) {
470 DataType type = new VoidType ();
471 while (accept (TokenType.STAR)) {
472 type = new PointerType (type);
474 return type;
477 List<DataType> type_arg_list = null;
478 UnresolvedSymbol sym = null;
480 bool is_dynamic = accept (TokenType.DYNAMIC);
481 bool value_owned = owned_by_default;
482 if (owned_by_default) {
483 if (accept (TokenType.UNOWNED)
484 || accept (TokenType.WEAK)) {
485 value_owned = false;
487 } else {
488 value_owned = accept (TokenType.OWNED);
491 /* handle arrays */
492 bool is_array = false;
494 if (accept (TokenType.ARRAY)) {
495 expect (TokenType.OF);
496 is_array = true;
499 /* handle lists */
500 bool is_list = false;
502 if (accept (TokenType.LIST)) {
503 expect (TokenType.OF);
504 prev ();
505 is_list = true;
508 /* handle dicts */
509 bool is_dict = false;
511 if (accept (TokenType.DICT)) {
512 expect (TokenType.OF);
513 prev ();
514 is_dict = true;
517 if (is_list) {
518 var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
519 sym = new UnresolvedSymbol (sym_parent, "ArrayList", get_src (begin));
520 } else if (is_dict) {
521 var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
522 sym = new UnresolvedSymbol (sym_parent, "HashMap", get_src (begin));
523 } else {
524 sym = parse_symbol_name ();
527 type_arg_list = parse_type_argument_list (false);
529 DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
530 if (type_arg_list != null) {
531 foreach (DataType type_arg in type_arg_list) {
532 type.add_type_argument (type_arg);
536 while (accept (TokenType.STAR)) {
537 type = new PointerType (type, get_src (begin));
540 if (!(type is PointerType)) {
541 type.nullable = accept (TokenType.INTERR);
544 if (is_array) {
546 if (!accept (TokenType.OPEN_BRACKET)) {
547 type.value_owned = true;
548 type = new ArrayType (type, 1, get_src (begin));
549 type.nullable = accept (TokenType.INTERR);
551 } else {
552 prev ();
554 while (accept (TokenType.OPEN_BRACKET)) {
555 bool invalid_array = false;
556 int array_rank = 0;
557 do {
558 array_rank++;
559 // required for decision between expression and declaration statement
560 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
561 parse_expression ();
562 // only used for parsing, reject use as real type
563 invalid_array = true;
566 while (accept (TokenType.COMMA));
567 expect (TokenType.CLOSE_BRACKET);
569 type.value_owned = true;
570 var array_type = new ArrayType (type, array_rank, get_src (begin));
571 array_type.nullable = accept (TokenType.INTERR);
573 array_type.invalid_syntax = invalid_array;
575 type = array_type;
580 if (!owned_by_default) {
581 value_owned = accept (TokenType.HASH);
584 type.is_dynamic = is_dynamic;
585 type.value_owned = value_owned;
586 return type;
589 DataType? parse_inline_array_type (DataType? type) throws ParseError {
590 var begin = get_location ();
592 // inline-allocated array
593 if (type != null && accept (TokenType.OPEN_BRACKET)) {
594 int array_length = -1;
596 if (current () != TokenType.CLOSE_BRACKET) {
597 if (current () != TokenType.INTEGER_LITERAL) {
598 throw new ParseError.SYNTAX (get_error ("expected `]' or integer literal"));
601 var length_literal = (IntegerLiteral) parse_literal ();
602 array_length = length_literal.value.to_int ();
604 expect (TokenType.CLOSE_BRACKET);
606 var array_type = new ArrayType (type, 1, get_src (begin));
607 array_type.inline_allocated = true;
608 if (array_length > 0) {
609 array_type.fixed_length = true;
610 array_type.length = array_length;
612 array_type.value_owned = type.value_owned;
613 return array_type;
615 return type;
619 List<Expression> parse_argument_list () throws ParseError {
620 var list = new ArrayList<Expression> ();
621 if (current () != TokenType.CLOSE_PARENS) {
622 do {
623 list.add (parse_argument ());
624 } while (accept (TokenType.COMMA));
626 return list;
629 Expression parse_argument () throws ParseError {
630 var begin = get_location ();
632 if (accept (TokenType.REF)) {
633 var inner = parse_expression ();
634 return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
635 } else if (accept (TokenType.OUT)) {
636 var inner = parse_expression ();
637 return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
638 } else {
639 var expr = parse_expression ();
640 var ma = expr as MemberAccess;
641 if (ma != null && ma.inner == null && accept (TokenType.COLON)) {
642 // named argument
643 expr = parse_expression ();
644 return new NamedArgument (ma.member_name, expr, get_src (begin));
645 } else {
646 return expr;
652 Expression parse_primary_expression () throws ParseError {
653 var begin = get_location ();
655 Expression expr;
657 switch (current ()) {
658 case TokenType.TRUE:
659 case TokenType.FALSE:
660 case TokenType.INTEGER_LITERAL:
661 case TokenType.REAL_LITERAL:
662 case TokenType.CHARACTER_LITERAL:
663 case TokenType.REGEX_LITERAL:
664 case TokenType.STRING_LITERAL:
665 case TokenType.TEMPLATE_STRING_LITERAL:
666 case TokenType.VERBATIM_STRING_LITERAL:
667 case TokenType.NULL:
668 expr = parse_literal ();
669 break;
670 case TokenType.ASSERT:
671 return parse_assert_expression ();
672 case TokenType.OPEN_BRACE:
673 expr = parse_initializer ();
674 break;
675 case TokenType.OPEN_PARENS:
676 expr = parse_tuple ();
677 break;
678 case TokenType.OPEN_REGEX_LITERAL:
679 expr = parse_regex_literal ();
680 break;
681 case TokenType.OPEN_TEMPLATE:
682 expr = parse_template ();
683 break;
684 case TokenType.THIS:
685 expr = parse_this_access ();
686 break;
687 case TokenType.SUPER:
688 expr = parse_base_access ();
689 break;
690 case TokenType.NEW:
691 expr = parse_object_or_array_creation_expression ();
692 break;
693 case TokenType.PRINT:
694 return parse_print_expression ();
695 case TokenType.SIZEOF:
696 expr = parse_sizeof_expression ();
697 break;
698 case TokenType.TYPEOF:
699 expr = parse_typeof_expression ();
700 break;
701 case TokenType.YIELD:
702 expr = parse_yield_expression ();
703 break;
704 default:
705 expr = parse_simple_name ();
706 break;
709 // process primary expressions that start with an inner primary expression
710 bool found = true;
711 while (found) {
712 switch (current ()) {
713 case TokenType.DOT:
714 expr = parse_member_access (begin, expr);
715 break;
716 case TokenType.OP_PTR:
717 expr = parse_pointer_member_access (begin, expr);
718 break;
719 case TokenType.OPEN_PARENS:
720 expr = parse_method_call (begin, expr);
721 break;
722 case TokenType.OPEN_BRACKET:
723 expr = parse_element_access (begin, expr);
724 break;
725 case TokenType.OP_INC:
726 expr = parse_post_increment_expression (begin, expr);
727 break;
728 case TokenType.OP_DEC:
729 expr = parse_post_decrement_expression (begin, expr);
730 break;
732 default:
733 found = false;
734 break;
738 return expr;
741 Expression parse_simple_name () throws ParseError {
742 var begin = get_location ();
743 string id = parse_identifier ();
744 List<DataType> type_arg_list = parse_type_argument_list (true);
745 var expr = new MemberAccess (null, id, get_src (begin));
746 if (type_arg_list != null) {
747 foreach (DataType type_arg in type_arg_list) {
748 expr.add_type_argument (type_arg);
751 return expr;
754 Expression parse_template () throws ParseError {
755 var begin = get_location ();
756 var template = new Template ();
758 expect (TokenType.OPEN_TEMPLATE);
759 while (current () != TokenType.CLOSE_TEMPLATE) {
760 template.add_expression (parse_expression ());
761 expect (TokenType.COMMA);
763 expect (TokenType.CLOSE_TEMPLATE);
765 template.source_reference = get_src (begin);
766 return template;
769 Expression parse_tuple () throws ParseError {
770 expect (TokenType.OPEN_PARENS);
771 var expr_list = new ArrayList<Expression> ();
772 if (current () != TokenType.CLOSE_PARENS) {
773 do {
774 expr_list.add (parse_expression ());
775 } while (accept (TokenType.COMMA));
777 expect (TokenType.CLOSE_PARENS);
778 if (expr_list.size != 1) {
779 var tuple = new Tuple ();
780 foreach (Expression expr in expr_list) {
781 tuple.add_expression (expr);
783 return tuple;
785 return expr_list.get (0);
788 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
789 expect (TokenType.DOT);
790 string id = parse_identifier ();
791 List<DataType> type_arg_list = parse_type_argument_list (true);
792 var expr = new MemberAccess (inner, id, get_src (begin));
793 if (type_arg_list != null) {
794 foreach (DataType type_arg in type_arg_list) {
795 expr.add_type_argument (type_arg);
798 return expr;
801 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
802 expect (TokenType.OP_PTR);
803 string id = parse_identifier ();
804 List<DataType> type_arg_list = parse_type_argument_list (true);
805 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
806 if (type_arg_list != null) {
807 foreach (DataType type_arg in type_arg_list) {
808 expr.add_type_argument (type_arg);
811 return expr;
815 List<Expression> parse_print_argument_list () throws ParseError {
816 var list = new ArrayList<Expression> ();
817 var i = 0;
818 var begin = get_location ();
820 if (current () != TokenType.CLOSE_PARENS) {
821 do {
822 var p_expr = parse_expression ();
823 if (i == 0) {
824 i++;
826 if (p_expr != null) {
829 if (p_expr is StringLiteral) {
830 var s_exp = (StringLiteral) p_expr;
831 var len = s_exp.value.length;
833 if (len > 2) {
834 string s = "\\n\"";
835 var st = s_exp.value.ndup (len-1);
836 st += s;
837 s_exp.value = st;
839 } else {
840 string s = "\"\\n\"";
841 var rhs = new StringLiteral (s, get_src (begin));
842 p_expr = new BinaryExpression (BinaryOperator.PLUS, p_expr, rhs, get_src (begin));
847 list.add (p_expr);
849 } while (accept (TokenType.COMMA));
851 return list;
854 Expression parse_print_expression () throws ParseError {
855 var begin = get_location ();
857 expect (TokenType.PRINT);
858 bool parens = accept (TokenType.OPEN_PARENS);
860 var expr = new MemberAccess (null, "print", get_src (begin));
862 var arg_list = parse_print_argument_list ();
864 if (parens) {
865 expect (TokenType.CLOSE_PARENS);
868 var print_expr = new MethodCall (expr, get_src (begin));
870 foreach (Expression arg in arg_list) {
871 print_expr.add_argument (arg);
874 return print_expr;
878 Expression parse_assert_expression () throws ParseError {
879 var begin = get_location ();
881 expect (TokenType.ASSERT);
882 bool parens = accept (TokenType.OPEN_PARENS);
884 var expr = new MemberAccess (null, "assert", get_src (begin));
886 var arg_list = parse_argument_list ();
888 if (parens) {
889 expect (TokenType.CLOSE_PARENS);
892 var assert_expr = new MethodCall (expr, get_src (begin));
894 foreach (Expression arg in arg_list) {
895 assert_expr.add_argument (arg);
898 return assert_expr;
902 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
903 expect (TokenType.OPEN_PARENS);
904 var arg_list = parse_argument_list ();
905 expect (TokenType.CLOSE_PARENS);
906 var init_list = parse_object_initializer ();
908 if (init_list.size > 0 && inner is MemberAccess) {
909 // struct creation expression
910 var member = (MemberAccess) inner;
911 member.creation_member = true;
913 var expr = new ObjectCreationExpression (member, get_src (begin));
914 expr.struct_creation = true;
915 foreach (Expression arg in arg_list) {
916 expr.add_argument (arg);
918 foreach (MemberInitializer initializer in init_list) {
919 expr.add_member_initializer (initializer);
921 return expr;
922 } else {
923 var expr = new MethodCall (inner, get_src (begin));
924 foreach (Expression arg in arg_list) {
925 expr.add_argument (arg);
927 return expr;
931 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
932 expect (TokenType.OPEN_BRACKET);
933 var index_list = parse_expression_list ();
934 Expression? stop = null;
935 if (index_list.size == 1 && accept (TokenType.COLON)) {
936 // slice expression
937 stop = parse_expression ();
939 expect (TokenType.CLOSE_BRACKET);
941 if (stop == null) {
942 var expr = new ElementAccess (inner, get_src (begin));
943 foreach (Expression index in index_list) {
944 expr.append_index (index);
946 return expr;
947 } else {
948 return new SliceExpression (inner, index_list[0], stop, get_src (begin));
952 List<Expression> parse_expression_list () throws ParseError {
953 var list = new ArrayList<Expression> ();
954 do {
955 list.add (parse_expression ());
956 } while (accept (TokenType.COMMA));
957 return list;
960 Expression parse_this_access () throws ParseError {
961 var begin = get_location ();
962 expect (TokenType.THIS);
963 return new MemberAccess (null, "this", get_src (begin));
966 Expression parse_base_access () throws ParseError {
967 var begin = get_location ();
968 expect (TokenType.SUPER);
969 return new BaseAccess (get_src (begin));
972 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
973 expect (TokenType.OP_INC);
974 return new PostfixExpression (inner, true, get_src (begin));
977 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
978 expect (TokenType.OP_DEC);
979 return new PostfixExpression (inner, false, get_src (begin));
982 Expression parse_object_or_array_creation_expression () throws ParseError {
983 var begin = get_location ();
984 expect (TokenType.NEW);
986 if (accept (TokenType.ARRAY)) {
987 expect (TokenType.OF);
988 var mtype = parse_type ();
989 var expr = parse_array_creation_expression (begin, mtype);
990 return expr;
993 if (accept (TokenType.LIST)) {
994 expect (TokenType.OF);
995 var mtype = parse_type ();
996 var expr = parse_list_creation_expression (begin, mtype);
997 return expr;
1000 if (accept (TokenType.DICT)) {
1001 expect (TokenType.OF);
1002 var mtype1 = parse_type ();
1003 expect (TokenType.COMMA);
1004 var mtype2 = parse_type ();
1005 var expr = parse_dict_creation_expression (begin, mtype1, mtype2);
1006 return expr;
1010 var member = parse_member_name ();
1011 var expr = parse_object_creation_expression (begin, member);
1012 return expr;
1016 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
1017 member.creation_member = true;
1018 List<Expression> arg_list;
1019 if (accept (TokenType.OPEN_PARENS)) {
1020 arg_list = parse_argument_list ();
1021 expect (TokenType.CLOSE_PARENS);
1022 } else {
1023 arg_list = new ArrayList<Expression> ();
1026 var init_list = parse_object_initializer ();
1028 var expr = new ObjectCreationExpression (member, get_src (begin));
1029 foreach (Expression arg in arg_list) {
1030 expr.add_argument (arg);
1032 foreach (MemberInitializer initializer in init_list) {
1033 expr.add_member_initializer (initializer);
1035 return expr;
1038 Expression parse_array_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1039 bool size_specified = false;
1040 List<Expression> size_specifier_list = null;
1041 bool first = true;
1042 DataType etype = element_type.copy ();
1044 var has_bracket = accept (TokenType.OPEN_BRACKET);
1046 do {
1047 if (!first) {
1048 // array of arrays: new T[][42]
1050 if (size_specified) {
1051 throw new ParseError.SYNTAX (get_error ("size of inner arrays must not be specified in array creation expression"));
1054 etype = new ArrayType (etype, size_specifier_list.size, etype.source_reference);
1055 } else {
1056 first = false;
1059 size_specifier_list = new ArrayList<Expression> ();
1060 do {
1061 Expression size = null;
1062 if (has_bracket && current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
1063 size = parse_expression ();
1064 size_specified = true;
1066 size_specifier_list.add (size);
1067 } while (accept (TokenType.COMMA));
1069 if (has_bracket) {
1070 expect (TokenType.CLOSE_BRACKET);
1072 } while (accept (TokenType.OPEN_BRACKET));
1074 InitializerList initializer = null;
1075 if (accept (TokenType.ASSIGN)) {
1076 initializer = parse_initializer ();
1079 var expr = new ArrayCreationExpression (etype, size_specifier_list.size, initializer, get_src (begin));
1080 if (size_specified) {
1081 foreach (Expression size in size_specifier_list) {
1082 expr.append_size (size);
1085 return expr;
1089 Expression parse_list_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1091 MemberAccess list_member = null, parent_member = null;
1093 parent_member = new MemberAccess (null, "Gee", get_src (begin));
1094 list_member = new MemberAccess (parent_member, "ArrayList", get_src (begin));
1095 list_member.add_type_argument (element_type);
1097 list_member.creation_member = true;
1099 var expr = new ObjectCreationExpression (list_member, get_src (begin));
1100 return expr;
1103 Expression parse_dict_creation_expression (SourceLocation begin, DataType key_type, DataType value_type) throws ParseError {
1105 MemberAccess dict_member = null, parent_member = null;
1107 parent_member = new MemberAccess (null, "Gee", get_src (begin));
1108 dict_member = new MemberAccess (parent_member, "HashMap", get_src (begin));
1109 dict_member.add_type_argument (key_type);
1110 dict_member.add_type_argument (value_type);
1112 dict_member.creation_member = true;
1114 var expr = new ObjectCreationExpression (dict_member, get_src (begin));
1116 return expr;
1120 List<MemberInitializer> parse_object_initializer () throws ParseError {
1121 var list = new ArrayList<MemberInitializer> ();
1122 if (accept (TokenType.OPEN_BRACE)) {
1123 do {
1124 list.add (parse_member_initializer ());
1125 } while (accept (TokenType.COMMA));
1126 expect (TokenType.CLOSE_BRACE);
1128 return list;
1131 MemberInitializer parse_member_initializer () throws ParseError {
1132 var begin = get_location ();
1133 string id = parse_identifier ();
1134 expect (TokenType.ASSIGN);
1135 var expr = parse_expression ();
1137 return new MemberInitializer (id, expr, get_src (begin));
1140 Expression parse_yield_expression () throws ParseError {
1141 var begin = get_location ();
1142 expect (TokenType.YIELD);
1143 Expression base_expr = null;
1144 if (current () == TokenType.SUPER) {
1145 base_expr = parse_base_access ();
1146 expect (TokenType.DOT);
1148 var member = parse_member_name (base_expr);
1149 var call = (MethodCall) parse_method_call (begin, member);
1150 call.is_yield_expression = true;
1151 return call;
1154 Expression parse_sizeof_expression () throws ParseError {
1155 var begin = get_location ();
1156 expect (TokenType.SIZEOF);
1157 expect (TokenType.OPEN_PARENS);
1158 var type = parse_type ();
1159 expect (TokenType.CLOSE_PARENS);
1161 return new SizeofExpression (type, get_src (begin));
1164 Expression parse_typeof_expression () throws ParseError {
1165 var begin = get_location ();
1166 expect (TokenType.TYPEOF);
1167 expect (TokenType.OPEN_PARENS);
1168 var type = parse_type ();
1169 expect (TokenType.CLOSE_PARENS);
1171 return new TypeofExpression (type, get_src (begin));
1174 UnaryOperator get_unary_operator (TokenType token_type) {
1175 switch (token_type) {
1176 case TokenType.PLUS: return UnaryOperator.PLUS;
1177 case TokenType.MINUS: return UnaryOperator.MINUS;
1178 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
1179 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
1180 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
1181 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
1182 default: return UnaryOperator.NONE;
1186 Expression parse_unary_expression () throws ParseError {
1187 var begin = get_location ();
1188 var operator = get_unary_operator (current ());
1189 if (operator != UnaryOperator.NONE) {
1190 next ();
1191 var op = parse_unary_expression ();
1192 return new UnaryExpression (operator, op, get_src (begin));
1194 switch (current ()) {
1195 case TokenType.HASH:
1196 next ();
1197 var op = parse_unary_expression ();
1198 return new ReferenceTransferExpression (op, get_src (begin));
1199 case TokenType.OPEN_PARENS:
1200 next ();
1201 switch (current ()) {
1202 case TokenType.OWNED:
1203 // (owned) foo
1204 next ();
1205 if (accept (TokenType.CLOSE_PARENS)) {
1206 var op = parse_unary_expression ();
1207 return new ReferenceTransferExpression (op, get_src (begin));
1209 break;
1210 case TokenType.VOID:
1211 case TokenType.DYNAMIC:
1212 case TokenType.IDENTIFIER:
1213 case TokenType.ARRAY:
1214 case TokenType.LIST:
1215 case TokenType.DICT:
1216 var type = parse_type ();
1217 if (accept (TokenType.CLOSE_PARENS)) {
1218 // check follower to decide whether to create cast expression
1219 switch (current ()) {
1220 case TokenType.OP_NEG:
1221 case TokenType.TILDE:
1222 case TokenType.OPEN_PARENS:
1223 case TokenType.TRUE:
1224 case TokenType.FALSE:
1225 case TokenType.INTEGER_LITERAL:
1226 case TokenType.REAL_LITERAL:
1227 case TokenType.CHARACTER_LITERAL:
1228 case TokenType.REGEX_LITERAL:
1229 case TokenType.STRING_LITERAL:
1230 case TokenType.TEMPLATE_STRING_LITERAL:
1231 case TokenType.VERBATIM_STRING_LITERAL:
1232 case TokenType.NULL:
1233 case TokenType.THIS:
1234 case TokenType.SUPER:
1235 case TokenType.NEW:
1236 case TokenType.SIZEOF:
1237 case TokenType.TYPEOF:
1238 case TokenType.IDENTIFIER:
1239 case TokenType.PARAMS:
1240 var inner = parse_unary_expression ();
1241 return new CastExpression (inner, type, get_src (begin), false);
1242 default:
1243 break;
1246 break;
1247 case TokenType.OP_NEG:
1248 next ();
1249 if (accept (TokenType.CLOSE_PARENS)) {
1250 // (!) non-null cast
1251 var inner = parse_unary_expression ();
1252 return new CastExpression.non_null (inner, get_src (begin));
1254 break;
1256 default:
1257 break;
1259 // no cast expression
1260 rollback (begin);
1261 break;
1262 case TokenType.STAR:
1263 next ();
1264 var op = parse_unary_expression ();
1265 return new PointerIndirection (op, get_src (begin));
1266 case TokenType.BITWISE_AND:
1267 next ();
1268 var op = parse_unary_expression ();
1269 return new AddressofExpression (op, get_src (begin));
1270 default:
1271 break;
1274 var expr = parse_primary_expression ();
1275 return expr;
1278 BinaryOperator get_binary_operator (TokenType token_type) {
1279 switch (token_type) {
1280 case TokenType.STAR: return BinaryOperator.MUL;
1281 case TokenType.DIV: return BinaryOperator.DIV;
1282 case TokenType.PERCENT: return BinaryOperator.MOD;
1283 case TokenType.PLUS: return BinaryOperator.PLUS;
1284 case TokenType.MINUS: return BinaryOperator.MINUS;
1285 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
1286 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
1287 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
1288 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
1289 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
1290 case TokenType.IS:
1291 next();
1292 if (current () == TokenType.OP_NEG) {
1293 prev ();
1294 return BinaryOperator.INEQUALITY;
1296 prev ();
1297 return BinaryOperator.EQUALITY;
1298 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
1299 default: return BinaryOperator.NONE;
1303 Expression parse_multiplicative_expression () throws ParseError {
1304 var begin = get_location ();
1305 var left = parse_unary_expression ();
1306 bool found = true;
1307 while (found) {
1308 var operator = get_binary_operator (current ());
1309 switch (operator) {
1310 case BinaryOperator.MUL:
1311 case BinaryOperator.DIV:
1312 case BinaryOperator.MOD:
1313 next ();
1314 var right = parse_unary_expression ();
1315 left = new BinaryExpression (operator, left, right, get_src (begin));
1316 break;
1317 default:
1318 found = false;
1319 break;
1322 return left;
1325 Expression parse_additive_expression () throws ParseError {
1326 var begin = get_location ();
1327 var left = parse_multiplicative_expression ();
1328 bool found = true;
1329 while (found) {
1330 var operator = get_binary_operator (current ());
1331 switch (operator) {
1332 case BinaryOperator.PLUS:
1333 case BinaryOperator.MINUS:
1334 next ();
1335 var right = parse_multiplicative_expression ();
1336 left = new BinaryExpression (operator, left, right, get_src (begin));
1337 break;
1338 default:
1339 found = false;
1340 break;
1343 return left;
1346 Expression parse_shift_expression () throws ParseError {
1347 var begin = get_location ();
1348 var left = parse_additive_expression ();
1349 bool found = true;
1350 while (found) {
1351 switch (current ()) {
1352 case TokenType.OP_SHIFT_LEFT:
1353 next ();
1354 var right = parse_additive_expression ();
1355 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1356 break;
1357 // don't use OP_SHIFT_RIGHT to support >> for nested generics
1358 case TokenType.OP_GT:
1359 char* first_gt_pos = tokens[index].begin.pos;
1360 next ();
1361 // only accept >> when there is no space between the two > signs
1362 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1363 next ();
1364 var right = parse_additive_expression ();
1365 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1366 } else {
1367 prev ();
1368 found = false;
1370 break;
1371 default:
1372 found = false;
1373 break;
1376 return left;
1379 Expression parse_relational_expression () throws ParseError {
1380 var begin = get_location ();
1381 var left = parse_shift_expression ();
1382 bool found = true;
1383 while (found) {
1384 var operator = get_binary_operator (current ());
1385 switch (operator) {
1386 case BinaryOperator.LESS_THAN:
1387 case BinaryOperator.LESS_THAN_OR_EQUAL:
1388 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1389 next ();
1390 var right = parse_shift_expression ();
1391 left = new BinaryExpression (operator, left, right, get_src (begin));
1392 break;
1393 case BinaryOperator.GREATER_THAN:
1394 next ();
1395 // ignore >> and >>= (two tokens due to generics)
1396 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1397 var right = parse_shift_expression ();
1398 left = new BinaryExpression (operator, left, right, get_src (begin));
1399 } else {
1400 prev ();
1401 found = false;
1403 break;
1404 default:
1405 switch (current ()) {
1406 case TokenType.ISA:
1407 next ();
1408 var type = parse_type ();
1409 left = new TypeCheck (left, type, get_src (begin));
1410 break;
1411 case TokenType.AS:
1412 next ();
1413 var type = parse_type ();
1414 left = new CastExpression (left, type, get_src (begin), true);
1415 break;
1416 default:
1417 found = false;
1418 break;
1420 break;
1423 return left;
1426 Expression parse_equality_expression () throws ParseError {
1427 var begin = get_location ();
1428 var left = parse_relational_expression ();
1429 bool found = true;
1430 while (found) {
1431 var operator = get_binary_operator (current ());
1432 switch (operator) {
1433 case BinaryOperator.INEQUALITY:
1434 case BinaryOperator.EQUALITY:
1435 if ((operator == BinaryOperator.INEQUALITY) && (current () == TokenType.IS)) {
1436 next ();
1438 next ();
1439 var right = parse_relational_expression ();
1440 left = new BinaryExpression (operator, left, right, get_src (begin));
1441 break;
1442 default:
1443 found = false;
1444 break;
1447 return left;
1450 Expression parse_and_expression () throws ParseError {
1451 var begin = get_location ();
1452 var left = parse_equality_expression ();
1453 while (accept (TokenType.BITWISE_AND)) {
1454 var right = parse_equality_expression ();
1455 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1457 return left;
1460 Expression parse_exclusive_or_expression () throws ParseError {
1461 var begin = get_location ();
1462 var left = parse_and_expression ();
1463 while (accept (TokenType.CARRET)) {
1464 var right = parse_and_expression ();
1465 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1467 return left;
1470 Expression parse_inclusive_or_expression () throws ParseError {
1471 var begin = get_location ();
1472 var left = parse_exclusive_or_expression ();
1473 while (accept (TokenType.BITWISE_OR)) {
1474 var right = parse_exclusive_or_expression ();
1475 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1477 return left;
1480 Expression parse_in_expression () throws ParseError {
1481 var begin = get_location ();
1482 var left = parse_inclusive_or_expression ();
1483 while (accept (TokenType.IN)) {
1484 var right = parse_inclusive_or_expression ();
1485 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1487 return left;
1490 Expression parse_conditional_and_expression () throws ParseError {
1491 var begin = get_location ();
1492 var left = parse_in_expression ();
1493 while (accept (TokenType.OP_AND)) {
1494 var right = parse_in_expression ();
1495 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1497 return left;
1500 Expression parse_conditional_or_expression () throws ParseError {
1501 var begin = get_location ();
1502 var left = parse_conditional_and_expression ();
1503 while (accept (TokenType.OP_OR)) {
1504 var right = parse_conditional_and_expression ();
1505 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1507 return left;
1510 Expression parse_conditional_expression () throws ParseError {
1511 var begin = get_location ();
1512 var condition = parse_conditional_or_expression ();
1513 if (accept (TokenType.INTERR)) {
1514 var true_expr = parse_expression ();
1515 expect (TokenType.COLON);
1516 var false_expr = parse_expression ();
1517 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1518 } else {
1519 return condition;
1523 Expression parse_lambda_expression () throws ParseError {
1524 var begin = get_location ();
1525 List<string> params = new ArrayList<string> ();
1527 expect (TokenType.DEF);
1529 if (accept (TokenType.OPEN_PARENS)) {
1530 if (current () != TokenType.CLOSE_PARENS) {
1531 do {
1532 params.add (parse_identifier ());
1533 } while (accept (TokenType.COMMA));
1535 expect (TokenType.CLOSE_PARENS);
1536 } else {
1537 params.add (parse_identifier ());
1541 LambdaExpression lambda;
1542 if (accept_block ()) {
1543 var block = parse_block ();
1544 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1545 } else {
1546 var expr = parse_expression ();
1547 lambda = new LambdaExpression (expr, get_src (begin));
1548 expect_terminator ();
1553 foreach (string param in params) {
1554 lambda.add_parameter (param);
1556 return lambda;
1559 AssignmentOperator get_assignment_operator (TokenType token_type) {
1560 switch (token_type) {
1561 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1562 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1563 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1564 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1565 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1566 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1567 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1568 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1569 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1570 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1571 default: return AssignmentOperator.NONE;
1575 Expression parse_expression () throws ParseError {
1576 if (current () == TokenType.DEF) {
1577 var lambda = parse_lambda_expression ();
1578 current_expr_is_lambda = true;
1579 return lambda;
1582 var begin = get_location ();
1583 Expression expr = parse_conditional_expression ();
1585 while (true) {
1586 var operator = get_assignment_operator (current ());
1587 if (operator != AssignmentOperator.NONE) {
1588 next ();
1589 var rhs = parse_expression ();
1590 expr = new Assignment (expr, rhs, operator, get_src (begin));
1591 } else if (current () == TokenType.OP_GT) { // >>=
1592 char* first_gt_pos = tokens[index].begin.pos;
1593 next ();
1594 // only accept >>= when there is no space between the two > signs
1595 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1596 next ();
1597 var rhs = parse_expression ();
1598 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1599 } else {
1600 prev ();
1601 break;
1603 } else {
1604 break;
1608 return expr;
1612 Statement get_for_statement_type () throws ParseError {
1614 var begin = get_location ();
1615 bool is_foreach = false;
1617 while (current () != TokenType.EOL && current () != TokenType.DO) {
1618 next ();
1619 if (accept (TokenType.IN)) {
1620 is_foreach = true;
1621 break;
1625 rollback (begin);
1627 if (is_foreach) {
1628 return parse_foreach_statement ();
1629 } else {
1630 return parse_for_statement ();
1635 void parse_statements (Block block) throws ParseError {
1636 while (current () != TokenType.DEDENT
1637 && current () != TokenType.WHEN
1638 && current () != TokenType.DEFAULT) {
1639 try {
1640 Statement stmt = null;
1641 bool is_decl = false;
1642 comment = scanner.pop_comment ();
1643 switch (current ()) {
1645 /* skip over requires and ensures as we handled them in method declaration */
1646 case TokenType.REQUIRES:
1647 case TokenType.ENSURES:
1648 var begin = get_location ();
1649 next ();
1651 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
1652 while (current () != TokenType.DEDENT) {
1653 next();
1656 expect (TokenType.DEDENT);
1657 } else {
1658 while (current () != TokenType.EOL) {
1659 next();
1662 expect (TokenType.EOL);
1665 stmt = new EmptyStatement (get_src (begin));
1666 break;
1669 case TokenType.INDENT:
1670 stmt = parse_block ();
1671 break;
1672 case TokenType.SEMICOLON:
1673 case TokenType.PASS:
1674 stmt = parse_empty_statement ();
1675 break;
1676 case TokenType.PRINT:
1677 case TokenType.ASSERT:
1678 stmt = parse_expression_statement ();
1679 break;
1680 case TokenType.IF:
1681 stmt = parse_if_statement ();
1682 break;
1683 case TokenType.CASE:
1684 stmt = parse_switch_statement ();
1685 break;
1686 case TokenType.WHILE:
1687 stmt = parse_while_statement ();
1688 break;
1689 case TokenType.DO:
1690 stmt = parse_do_statement ();
1691 break;
1692 case TokenType.FOR:
1693 stmt = get_for_statement_type ();
1694 break;
1695 case TokenType.BREAK:
1696 stmt = parse_break_statement ();
1697 break;
1698 case TokenType.CONTINUE:
1699 stmt = parse_continue_statement ();
1700 break;
1701 case TokenType.RETURN:
1702 stmt = parse_return_statement ();
1703 break;
1704 case TokenType.RAISE:
1705 stmt = parse_throw_statement ();
1706 break;
1707 case TokenType.TRY:
1708 stmt = parse_try_statement ();
1709 break;
1710 case TokenType.LOCK:
1711 stmt = parse_lock_statement ();
1712 break;
1713 case TokenType.DELETE:
1714 stmt = parse_delete_statement ();
1715 break;
1716 case TokenType.VAR:
1717 is_decl = true;
1718 parse_local_variable_declarations (block);
1719 break;
1720 case TokenType.YIELD:
1721 stmt = parse_yield_statement ();
1722 break;
1724 case TokenType.OP_INC:
1725 case TokenType.OP_DEC:
1726 case TokenType.SUPER:
1727 case TokenType.THIS:
1728 case TokenType.OPEN_PARENS:
1729 case TokenType.STAR:
1730 case TokenType.NEW:
1731 stmt = parse_expression_statement ();
1732 break;
1733 default:
1734 bool is_expr = is_expression ();
1735 if (is_expr) {
1736 stmt = parse_expression_statement ();
1737 } else {
1738 is_decl = true;
1739 parse_local_variable_declarations (block);
1741 break;
1744 if (!is_decl) {
1745 block.add_statement (stmt);
1747 } catch (ParseError e) {
1748 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1749 // beginning of next declaration or end of file reached
1750 // return what we have so far
1751 break;
1757 bool is_expression () throws ParseError {
1758 var begin = get_location ();
1760 // decide between declaration and expression statement
1761 skip_type ();
1762 switch (current ()) {
1763 // invocation expression
1764 case TokenType.OPEN_PARENS:
1765 // postfix increment
1766 case TokenType.OP_INC:
1767 // postfix decrement
1768 case TokenType.OP_DEC:
1769 // assignments
1770 case TokenType.ASSIGN:
1771 case TokenType.ASSIGN_ADD:
1772 case TokenType.ASSIGN_BITWISE_AND:
1773 case TokenType.ASSIGN_BITWISE_OR:
1774 case TokenType.ASSIGN_BITWISE_XOR:
1775 case TokenType.ASSIGN_DIV:
1776 case TokenType.ASSIGN_MUL:
1777 case TokenType.ASSIGN_PERCENT:
1778 case TokenType.ASSIGN_SHIFT_LEFT:
1779 case TokenType.ASSIGN_SUB:
1780 case TokenType.OP_GT: // >>=
1781 // member access
1782 case TokenType.DOT:
1783 // pointer member access
1784 case TokenType.OP_PTR:
1785 rollback (begin);
1786 return true;
1787 default:
1788 rollback (begin);
1789 return false;
1793 Block parse_embedded_statement () throws ParseError {
1794 if (current () == TokenType.INDENT) {
1795 var block = parse_block ();
1796 return block;
1799 comment = scanner.pop_comment ();
1801 var block = new Block (get_src (get_location ()));
1802 block.add_statement (parse_embedded_statement_without_block ());
1803 return block;
1807 Statement parse_embedded_statement_without_block () throws ParseError {
1808 switch (current ()) {
1809 case TokenType.PASS:
1810 case TokenType.SEMICOLON: return parse_empty_statement ();
1811 case TokenType.IF: return parse_if_statement ();
1812 case TokenType.CASE: return parse_switch_statement ();
1813 case TokenType.WHILE: return parse_while_statement ();
1814 case TokenType.DO: return parse_do_statement ();
1815 case TokenType.FOR: return get_for_statement_type ();
1816 case TokenType.BREAK: return parse_break_statement ();
1817 case TokenType.CONTINUE: return parse_continue_statement ();
1818 case TokenType.RETURN: return parse_return_statement ();
1819 case TokenType.YIELD: return parse_yield_statement ();
1820 case TokenType.RAISE: return parse_throw_statement ();
1821 case TokenType.TRY: return parse_try_statement ();
1822 case TokenType.LOCK: return parse_lock_statement ();
1823 case TokenType.DELETE: return parse_delete_statement ();
1824 default: return parse_expression_statement ();
1828 Block parse_block () throws ParseError {
1829 var begin = get_location ();
1830 expect (TokenType.INDENT);
1831 var block = new Block (get_src (begin));
1832 parse_statements (block);
1833 if (!accept (TokenType.DEDENT)) {
1834 // only report error if it's not a secondary error
1835 if (context.report.get_errors () == 0) {
1836 Report.error (get_current_src (), "tab indentation is incorrect");
1840 block.source_reference.last_line = get_current_src ().last_line;
1841 block.source_reference.last_column = get_current_src ().last_column;
1843 return block;
1846 Statement parse_empty_statement () throws ParseError {
1847 var begin = get_location ();
1849 accept (TokenType.PASS);
1850 accept (TokenType.SEMICOLON);
1851 expect_terminator ();
1853 return new EmptyStatement (get_src (begin));
1856 void add_local_var_variable (Block block, string id) throws ParseError {
1857 DataType type_copy = null;
1858 var local = parse_local_variable (type_copy, id);
1859 block.add_statement (new DeclarationStatement (local, local.source_reference));
1862 void parse_local_variable_declarations (Block block) throws ParseError {
1863 if (accept (TokenType.VAR)) {
1864 /* support block vars */
1865 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
1866 while (current () != TokenType.DEDENT) {
1867 var s = parse_identifier ();
1868 add_local_var_variable (block, s);
1869 accept (TokenType.EOL);
1870 accept (TokenType.SEMICOLON);
1873 expect (TokenType.DEDENT);
1874 } else {
1875 var s = parse_identifier ();
1876 add_local_var_variable (block, s);
1877 expect_terminator ();
1880 return;
1883 var id_list = new ArrayList<string> ();
1884 DataType variable_type = null;
1886 do {
1887 id_list.add (parse_identifier ());
1888 } while (accept (TokenType.COMMA));
1890 expect (TokenType.COLON);
1892 variable_type = parse_type ();
1893 var type = parse_inline_array_type (variable_type);
1895 foreach (string id in id_list) {
1896 DataType type_copy = null;
1897 if (type != null) {
1898 type_copy = type.copy ();
1900 var local = parse_local_variable (type_copy, id);
1901 block.add_statement (new DeclarationStatement (local, local.source_reference));
1904 expect_terminator ();
1907 LocalVariable parse_local_variable (DataType? variable_type, string id) throws ParseError {
1908 var begin = get_location ();
1909 Expression initializer = null;
1910 if (accept (TokenType.ASSIGN)) {
1911 initializer = parse_expression ();
1913 return new LocalVariable (variable_type, id, initializer, get_src (begin));
1916 Statement parse_expression_statement () throws ParseError {
1917 var begin = get_location ();
1918 var expr = parse_statement_expression ();
1920 if (current_expr_is_lambda) {
1921 current_expr_is_lambda = false;
1922 } else {
1923 expect_terminator ();
1926 return new ExpressionStatement (expr, get_src (begin));
1929 Expression parse_statement_expression () throws ParseError {
1930 // invocation expression, assignment,
1931 // or pre/post increment/decrement expression
1932 var expr = parse_expression ();
1933 return expr;
1936 Statement parse_if_statement () throws ParseError {
1937 var begin = get_location ();
1939 expect (TokenType.IF);
1941 var condition = parse_expression ();
1943 if (!accept (TokenType.DO)) {
1944 expect (TokenType.EOL);
1945 } else {
1946 accept (TokenType.EOL);
1949 var src = get_src (begin);
1950 var true_stmt = parse_embedded_statement ();
1951 Block false_stmt = null;
1952 if (accept (TokenType.ELSE)) {
1953 // allow `else if' on the same line without `do'
1954 if (!accept (TokenType.DO) && current () != TokenType.IF) {
1955 expect (TokenType.EOL);
1956 } else {
1957 accept (TokenType.EOL);
1960 false_stmt = parse_embedded_statement ();
1962 return new IfStatement (condition, true_stmt, false_stmt, src);
1965 Statement parse_switch_statement () throws ParseError {
1966 var begin = get_location ();
1967 expect (TokenType.CASE);
1968 var condition = parse_expression ();
1970 expect (TokenType.EOL);
1972 var stmt = new SwitchStatement (condition, get_src (begin));
1973 expect (TokenType.INDENT);
1974 while (current () != TokenType.DEDENT) {
1975 var section = new SwitchSection (get_src (begin));
1977 if (accept (TokenType.WHEN)) {
1978 do {
1979 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
1981 while (accept (TokenType.COMMA));
1982 } else {
1983 expect (TokenType.DEFAULT);
1984 section.add_label (new SwitchLabel.with_default (get_src (begin)));
1987 if (!accept (TokenType.EOL)) {
1988 expect (TokenType.DO);
1991 parse_statements (section);
1993 /* add break statement for each block */
1994 var break_stmt = new BreakStatement (get_src (begin));
1995 section.add_statement (break_stmt);
1997 stmt.add_section (section);
1999 expect (TokenType.DEDENT);
2000 return stmt;
2003 Statement parse_while_statement () throws ParseError {
2004 var begin = get_location ();
2005 expect (TokenType.WHILE);
2006 var condition = parse_expression ();
2008 if (!accept (TokenType.DO)) {
2009 expect (TokenType.EOL);
2010 } else {
2011 accept (TokenType.EOL);
2014 var body = parse_embedded_statement ();
2015 return new WhileStatement (condition, body, get_src (begin));
2018 Statement parse_do_statement () throws ParseError {
2019 var begin = get_location ();
2020 expect (TokenType.DO);
2021 expect (TokenType.EOL);
2022 var body = parse_embedded_statement ();
2023 expect (TokenType.WHILE);
2025 var condition = parse_expression ();
2027 expect_terminator ();
2029 return new DoStatement (body, condition, get_src (begin));
2033 Statement parse_for_statement () throws ParseError {
2034 var begin = get_location ();
2035 Block block = null;
2036 Expression initializer = null;
2037 Expression condition = null;
2038 Expression iterator = null;
2039 bool is_expr;
2040 string id;
2042 expect (TokenType.FOR);
2044 switch (current ()) {
2045 case TokenType.VAR:
2046 is_expr = false;
2047 break;
2048 default:
2050 bool local_is_expr = is_expression ();
2051 is_expr = local_is_expr;
2052 break;
2055 if (is_expr) {
2056 var expr_begin = get_location ();
2057 id = parse_identifier ();
2058 rollback (expr_begin);
2059 initializer = parse_statement_expression ();
2060 } else {
2061 block = new Block (get_src (begin));
2062 DataType variable_type;
2063 if (accept (TokenType.VAR)) {
2064 variable_type = null;
2065 id = parse_identifier ();
2066 } else {
2067 id = parse_identifier ();
2068 expect (TokenType.COLON);
2069 variable_type = parse_type ();
2072 DataType type_copy = null;
2073 if (variable_type != null) {
2074 type_copy = variable_type.copy ();
2076 var local = parse_local_variable (type_copy, id);
2078 block.add_statement (new DeclarationStatement (local, local.source_reference));
2083 if (accept (TokenType.TO)) {
2084 /* create expression for condition and incrementing iterator */
2085 var to_begin = get_location ();
2086 var to_src = get_src (to_begin);
2087 var left = new MemberAccess (null, id, to_src);
2088 var right = parse_primary_expression ();
2090 condition = new BinaryExpression (BinaryOperator.LESS_THAN_OR_EQUAL, left, right, to_src);
2092 iterator = new PostfixExpression (left, true, to_src);
2093 } else {
2094 expect (TokenType.DOWNTO);
2095 var downto_begin = get_location ();
2096 var downto_src = get_src (downto_begin);
2097 /* create expression for condition and decrementing iterator */
2098 var left = new MemberAccess (null, id, downto_src);
2099 var right = parse_primary_expression ();
2101 condition = new BinaryExpression (BinaryOperator.GREATER_THAN_OR_EQUAL, left, right, downto_src);
2103 iterator = new PostfixExpression (left, false, downto_src);
2106 if (!accept (TokenType.EOL)) {
2107 expect (TokenType.DO);
2110 var src = get_src (begin);
2111 var body = parse_embedded_statement ();
2112 var stmt = new ForStatement (condition, body, src);
2114 if (initializer != null) stmt.add_initializer (initializer);
2116 stmt.add_iterator (iterator);
2119 if (block != null) {
2120 block.add_statement (stmt);
2121 return block;
2122 } else {
2123 return stmt;
2127 Statement parse_foreach_statement () throws ParseError {
2128 var begin = get_location ();
2129 DataType type = null;
2130 string id = null;
2132 expect (TokenType.FOR);
2134 if (accept (TokenType.VAR)) {
2135 id = parse_identifier ();
2136 } else {
2137 id = parse_identifier ();
2138 if (accept (TokenType.COLON)) {
2139 type = parse_type ();
2143 expect (TokenType.IN);
2144 var collection = parse_expression ();
2145 if (!accept (TokenType.EOL)) {
2146 expect (TokenType.DO);
2148 var src = get_src (begin);
2149 var body = parse_embedded_statement ();
2150 return new ForeachStatement (type, id, collection, body, src);
2153 Statement parse_break_statement () throws ParseError {
2154 var begin = get_location ();
2155 expect (TokenType.BREAK);
2156 expect_terminator ();
2157 return new BreakStatement (get_src (begin));
2160 Statement parse_continue_statement () throws ParseError {
2161 var begin = get_location ();
2162 expect (TokenType.CONTINUE);
2163 expect_terminator ();
2164 return new ContinueStatement (get_src (begin));
2167 Statement parse_return_statement () throws ParseError {
2168 var begin = get_location ();
2169 expect (TokenType.RETURN);
2170 Expression expr = null;
2171 if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) {
2172 expr = parse_expression ();
2174 expect_terminator ();
2175 return new ReturnStatement (expr, get_src (begin));
2178 Statement parse_yield_statement () throws ParseError {
2179 var begin = get_location ();
2180 expect (TokenType.YIELD);
2181 if (current () != TokenType.SEMICOLON && current () != TokenType.EOL && current () != TokenType.RETURN) {
2182 prev ();
2183 return parse_expression_statement ();
2185 Expression expr = null;
2186 if (accept (TokenType.RETURN)) {
2187 expr = parse_expression ();
2189 expect_terminator ();
2190 return new YieldStatement (expr, get_src (begin));
2193 Statement parse_throw_statement () throws ParseError {
2194 var begin = get_location ();
2195 expect (TokenType.RAISE);
2196 var expr = parse_expression ();
2197 expect_terminator ();
2198 return new ThrowStatement (expr, get_src (begin));
2201 Statement parse_try_statement () throws ParseError {
2202 var begin = get_location ();
2203 expect (TokenType.TRY);
2204 expect (TokenType.EOL);
2205 var try_block = parse_block ();
2206 Block finally_clause = null;
2207 var catch_clauses = new ArrayList<CatchClause> ();
2208 if (current () == TokenType.EXCEPT) {
2209 parse_catch_clauses (catch_clauses);
2210 if (current () == TokenType.FINALLY) {
2211 finally_clause = parse_finally_clause ();
2213 } else {
2214 finally_clause = parse_finally_clause ();
2216 var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
2217 foreach (CatchClause clause in catch_clauses) {
2218 stmt.add_catch_clause (clause);
2220 return stmt;
2223 void parse_catch_clauses (List<CatchClause> catch_clauses) throws ParseError {
2224 while (accept (TokenType.EXCEPT)) {
2225 var begin = get_location ();
2226 DataType type = null;
2227 string id = null;
2228 if (!accept (TokenType.EOL)) {
2229 id = parse_identifier ();
2230 expect (TokenType.COLON);
2231 type = parse_type ();
2232 expect (TokenType.EOL);
2235 var block = parse_block ();
2236 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
2240 Block parse_finally_clause () throws ParseError {
2241 expect (TokenType.FINALLY);
2242 accept_block ();
2243 var block = parse_block ();
2244 return block;
2247 Statement parse_lock_statement () throws ParseError {
2248 var begin = get_location ();
2249 expect (TokenType.LOCK);
2250 expect (TokenType.OPEN_PARENS);
2251 var expr = parse_expression ();
2252 expect (TokenType.CLOSE_PARENS);
2253 var stmt = parse_embedded_statement ();
2254 return new LockStatement (expr, stmt, get_src (begin));
2257 Statement parse_delete_statement () throws ParseError {
2258 var begin = get_location ();
2259 expect (TokenType.DELETE);
2260 var expr = parse_expression ();
2261 expect_terminator ();
2262 return new DeleteStatement (expr, get_src (begin));
2265 string parse_attribute_value () throws ParseError {
2266 switch (current ()) {
2267 case TokenType.NULL:
2268 case TokenType.TRUE:
2269 case TokenType.FALSE:
2270 case TokenType.INTEGER_LITERAL:
2271 case TokenType.REAL_LITERAL:
2272 case TokenType.STRING_LITERAL:
2273 next ();
2274 return get_last_string ();
2275 case TokenType.MINUS:
2276 next ();
2277 switch (current ()) {
2278 case TokenType.INTEGER_LITERAL:
2279 case TokenType.REAL_LITERAL:
2280 next ();
2281 return "-" + get_last_string ();
2282 default:
2283 throw new ParseError.SYNTAX (get_error ("expected number"));
2285 default:
2286 throw new ParseError.SYNTAX (get_error ("expected literal"));
2290 List<Attribute>? parse_attributes () throws ParseError {
2291 if (current () != TokenType.OPEN_BRACKET) {
2292 return null;
2294 var attrs = new ArrayList<Attribute> ();
2295 while (accept (TokenType.OPEN_BRACKET)) {
2296 do {
2297 var begin = get_location ();
2298 string id = parse_identifier ();
2299 var attr = new Attribute (id, get_src (begin));
2300 if (accept (TokenType.OPEN_PARENS)) {
2301 if (current () != TokenType.CLOSE_PARENS) {
2302 do {
2303 id = parse_identifier ();
2304 expect (TokenType.ASSIGN);
2305 attr.add_argument (id, parse_attribute_value ());
2306 } while (accept (TokenType.COMMA));
2308 expect (TokenType.CLOSE_PARENS);
2310 attrs.add (attr);
2311 } while (accept (TokenType.COMMA));
2312 expect (TokenType.CLOSE_BRACKET);
2314 expect (TokenType.EOL);
2316 return attrs;
2319 void set_attributes (CodeNode node, List<Attribute>? attributes) {
2320 if (attributes != null) {
2321 foreach (Attribute attr in (List<Attribute>) attributes) {
2322 node.attributes.append (attr);
2327 Symbol parse_declaration (bool is_root = false) throws ParseError {
2328 comment = scanner.pop_comment ();
2329 var attrs = parse_attributes ();
2330 var begin = get_location ();
2332 switch (current ()) {
2333 case TokenType.CONST:
2334 return parse_constant_declaration (attrs);
2335 case TokenType.CONSTRUCT:
2336 return parse_creation_method_declaration (attrs);
2337 case TokenType.CLASS:
2338 return parse_class_declaration (attrs);
2339 case TokenType.INIT:
2340 if (is_root) {
2341 return parse_main_method_declaration (attrs);
2343 if (context.profile == Profile.GOBJECT) {
2344 rollback (begin);
2345 return parse_constructor_declaration (attrs);
2347 break;
2348 case TokenType.DELEGATE:
2349 return parse_delegate_declaration (attrs);
2350 case TokenType.DEF:
2351 return parse_method_declaration (attrs);
2352 case TokenType.ENUM:
2353 return parse_enum_declaration (attrs);
2354 case TokenType.ERRORDOMAIN:
2355 return parse_errordomain_declaration (attrs);
2356 case TokenType.FINAL:
2357 return parse_destructor_declaration (attrs);
2358 case TokenType.INTERFACE:
2359 return parse_interface_declaration (attrs);
2360 case TokenType.NAMESPACE:
2361 return parse_namespace_declaration (attrs);
2362 case TokenType.PROP:
2363 return parse_property_declaration (attrs);
2364 case TokenType.EVENT:
2365 return parse_signal_declaration (attrs);
2366 case TokenType.STRUCT:
2367 return parse_struct_declaration (attrs);
2368 default:
2370 while (current () != TokenType.EOL && current () != TokenType.SEMICOLON && current () != TokenType.EOF) {
2371 if (current () == TokenType.COLON) {
2372 rollback (begin);
2373 return parse_field_declaration (attrs);
2374 } else {
2375 next ();
2378 rollback (begin);
2380 break;
2383 TokenType cur = current ();
2384 TokenType pre = tokens[index-1].type;
2386 throw new ParseError.SYNTAX (get_error ("expected declaration but got %s with previous %s".printf (cur.to_string (), pre.to_string())));
2389 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
2390 if (!root) {
2391 expect (TokenType.INDENT);
2393 while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2394 try {
2395 if (parent is Namespace) {
2396 parse_namespace_member ((Namespace) parent);
2397 } else if (parent is Class) {
2398 parse_class_member ((Class) parent);
2399 } else if (parent is Struct) {
2400 parse_struct_member ((Struct) parent);
2401 } else if (parent is Interface) {
2402 parse_interface_member ((Interface) parent);
2404 } catch (ParseError e) {
2405 int r;
2406 do {
2407 r = recover ();
2408 if (r == RecoveryState.STATEMENT_BEGIN) {
2409 next ();
2410 } else {
2411 break;
2413 } while (true);
2414 if (r == RecoveryState.EOF) {
2415 return;
2419 if (!root) {
2420 if (!accept (TokenType.DEDENT)) {
2421 // only report error if it's not a secondary error
2422 if (context.report.get_errors () == 0) {
2423 Report.error (get_current_src (), "expected dedent");
2429 enum RecoveryState {
2430 EOF,
2431 DECLARATION_BEGIN,
2432 STATEMENT_BEGIN
2435 RecoveryState recover () {
2436 while (current () != TokenType.EOF) {
2437 switch (current ()) {
2438 case TokenType.CLASS:
2439 case TokenType.CONST:
2440 case TokenType.CONSTRUCT:
2441 case TokenType.INIT:
2442 case TokenType.DEF:
2443 case TokenType.DELEGATE:
2444 case TokenType.ENUM:
2445 case TokenType.ERRORDOMAIN:
2446 case TokenType.FINAL:
2447 case TokenType.INTERFACE:
2448 case TokenType.NAMESPACE:
2449 case TokenType.PROP:
2450 case TokenType.EVENT:
2451 case TokenType.STRUCT:
2452 return RecoveryState.DECLARATION_BEGIN;
2453 case TokenType.BREAK:
2454 case TokenType.CASE:
2455 case TokenType.CONTINUE:
2456 case TokenType.DELETE:
2457 case TokenType.DO:
2458 case TokenType.FOR:
2459 case TokenType.IF:
2460 case TokenType.LOCK:
2461 case TokenType.RETURN:
2462 case TokenType.RAISE:
2463 case TokenType.TRY:
2464 case TokenType.VAR:
2465 case TokenType.WHILE:
2466 case TokenType.YIELD:
2467 return RecoveryState.STATEMENT_BEGIN;
2468 default:
2469 next ();
2470 break;
2473 return RecoveryState.EOF;
2476 Namespace parse_namespace_declaration (List<Attribute>? attrs) throws ParseError {
2477 var begin = get_location ();
2478 expect (TokenType.NAMESPACE);
2479 var sym = parse_symbol_name ();
2480 var ns = new Namespace (sym.name, get_src (begin));
2481 if (comment != null) {
2482 ns.add_comment (comment);
2483 comment = null;
2485 set_attributes (ns, attrs);
2486 expect (TokenType.EOL);
2487 parse_declarations (ns);
2489 Namespace result = ns;
2490 while (sym.inner != null) {
2491 sym = sym.inner;
2492 ns = new Namespace (sym.name, result.source_reference);
2493 ns.add_namespace ((Namespace) result);
2494 result = ns;
2496 return result;
2499 void parse_namespace_member (Namespace ns) throws ParseError {
2501 var sym = parse_declaration ((ns == context.root));
2502 if (sym is Namespace) {
2503 ns.add_namespace ((Namespace) sym);
2504 } else if (sym is Class) {
2505 ns.add_class ((Class) sym);
2506 } else if (sym is Interface) {
2507 ns.add_interface ((Interface) sym);
2508 } else if (sym is Struct) {
2509 ns.add_struct ((Struct) sym);
2510 } else if (sym is Enum) {
2511 ns.add_enum ((Enum) sym);
2512 } else if (sym is ErrorDomain) {
2513 ns.add_error_domain ((ErrorDomain) sym);
2514 } else if (sym is Delegate) {
2515 ns.add_delegate ((Delegate) sym);
2516 } else if (sym is Method) {
2517 var method = (Method) sym;
2518 if (method.binding == MemberBinding.INSTANCE) {
2519 method.binding = MemberBinding.STATIC;
2521 ns.add_method (method);
2522 } else if (sym is Field) {
2523 var field = (Field) sym;
2524 if (field.binding == MemberBinding.INSTANCE) {
2525 field.binding = MemberBinding.STATIC;
2527 ns.add_field (field);
2528 } else if (sym is Constant) {
2529 ns.add_constant ((Constant) sym);
2530 } else {
2531 Report.error (sym.source_reference, "unexpected declaration in namespace");
2536 void add_uses_clause (Namespace ns) throws ParseError {
2537 var begin = get_location ();
2538 var sym = parse_symbol_name ();
2539 var ns_ref = new UsingDirective (sym, get_src (begin));
2541 scanner.source_file.add_using_directive (ns_ref);
2542 ns.add_using_directive (ns_ref);
2545 void parse_using_directives (Namespace ns) throws ParseError {
2546 while (accept (TokenType.USES)) {
2547 if (accept_block ()) {
2548 expect (TokenType.INDENT);
2550 while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2551 add_uses_clause (ns);
2552 expect (TokenType.EOL);
2555 expect (TokenType.DEDENT);
2556 } else {
2557 do {
2558 add_uses_clause (ns);
2559 } while (accept (TokenType.COMMA));
2561 expect_terminator ();
2567 Symbol parse_class_declaration (List<Attribute>? attrs) throws ParseError {
2568 var begin = get_location ();
2569 expect (TokenType.CLASS);
2571 var flags = parse_type_declaration_modifiers ();
2573 var sym = parse_symbol_name ();
2574 var type_param_list = parse_type_parameter_list ();
2575 var base_types = new ArrayList<DataType> ();
2576 if (accept (TokenType.COLON)) {
2577 var type1 = parse_type ();
2578 base_types.add (type1);
2580 if (accept (TokenType.IMPLEMENTS)) {
2581 do {
2582 var type2 = parse_type ();
2583 base_types.add (type2);
2584 } while (accept (TokenType.COMMA));
2588 accept (TokenType.EOL);
2590 var cl = new Class (sym.name, get_src (begin), comment);
2592 if (ModifierFlags.PRIVATE in flags) {
2593 cl.access = SymbolAccessibility.PRIVATE;
2594 } else {
2595 /* class must always be Public unless its name starts wtih underscore */
2596 if (sym.name[0] == '_') {
2597 cl.access = SymbolAccessibility.PRIVATE;
2598 } else {
2599 cl.access = SymbolAccessibility.PUBLIC;
2603 if (ModifierFlags.ABSTRACT in flags) {
2604 cl.is_abstract = true;
2606 set_attributes (cl, attrs);
2607 foreach (TypeParameter type_param in type_param_list) {
2608 cl.add_type_parameter (type_param);
2610 foreach (DataType base_type in base_types) {
2611 cl.add_base_type (base_type);
2614 class_name = cl.name;
2616 parse_declarations (cl);
2618 // ensure there is always a default construction method
2619 if (scanner.source_file.file_type == SourceFileType.SOURCE
2620 && cl.default_construction_method == null) {
2621 var m = new CreationMethod (cl.name, null, cl.source_reference);
2622 m.access = SymbolAccessibility.PUBLIC;
2623 m.body = new Block (cl.source_reference);
2624 cl.add_method (m);
2627 Symbol result = cl;
2628 while (sym.inner != null) {
2629 sym = sym.inner;
2630 var ns = new Namespace (sym.name, cl.source_reference);
2631 if (result is Namespace) {
2632 ns.add_namespace ((Namespace) result);
2633 } else {
2634 ns.add_class ((Class) result);
2636 result = ns;
2638 return result;
2641 void parse_class_member (Class cl) throws ParseError {
2642 var sym = parse_declaration ();
2643 if (sym is Class) {
2644 cl.add_class ((Class) sym);
2645 } else if (sym is Struct) {
2646 cl.add_struct ((Struct) sym);
2647 } else if (sym is Enum) {
2648 cl.add_enum ((Enum) sym);
2649 } else if (sym is Delegate) {
2650 cl.add_delegate ((Delegate) sym);
2651 } else if (sym is Method) {
2652 cl.add_method ((Method) sym);
2653 } else if (sym is Vala.Signal) {
2654 cl.add_signal ((Vala.Signal) sym);
2655 } else if (sym is Field) {
2656 cl.add_field ((Field) sym);
2657 } else if (sym is Constant) {
2658 cl.add_constant ((Constant) sym);
2659 } else if (sym is Property) {
2660 cl.add_property ((Property) sym);
2661 } else if (sym is Constructor) {
2662 var c = (Constructor) sym;
2663 if (c.binding == MemberBinding.INSTANCE) {
2664 if (cl.constructor != null) {
2665 Report.error (c.source_reference, "class already contains a constructor");
2667 cl.constructor = c;
2668 } else if (c.binding == MemberBinding.CLASS) {
2669 if (cl.class_constructor != null) {
2670 Report.error (c.source_reference, "class already contains a class constructor");
2672 cl.class_constructor = c;
2673 } else {
2674 if (cl.static_constructor != null) {
2675 Report.error (c.source_reference, "class already contains a static constructor");
2677 cl.static_constructor = c;
2680 } else if (sym is Destructor) {
2681 var d = (Destructor) sym;
2682 if (d.binding == MemberBinding.STATIC) {
2683 if (cl.static_destructor != null) {
2684 Report.error (d.source_reference, "class already contains a static destructor");
2686 cl.static_destructor = (Destructor) d;
2687 } else if (d.binding == MemberBinding.CLASS) {
2688 if (cl.class_destructor != null) {
2689 Report.error (d.source_reference, "class already contains a class destructor");
2691 cl.class_destructor = (Destructor) d;
2692 } else {
2693 if (cl.destructor != null) {
2694 Report.error (d.source_reference, "class already contains a destructor");
2696 cl.destructor = (Destructor) d;
2699 } else {
2700 Report.error (sym.source_reference, "unexpected declaration in class");
2704 Constant parse_constant_declaration (List<Attribute>? attrs) throws ParseError {
2705 var begin = get_location ();
2707 expect (TokenType.CONST);
2709 var flags = parse_member_declaration_modifiers ();
2711 string id = parse_identifier ();
2713 expect (TokenType.COLON);
2714 var type = parse_type (false);
2715 type = parse_inline_array_type (type);
2717 Expression initializer = null;
2718 if (accept (TokenType.ASSIGN)) {
2719 initializer = parse_expression ();
2721 expect_terminator ();
2723 // constant arrays don't own their element
2724 var array_type = type as ArrayType;
2725 if (array_type != null) {
2726 array_type.element_type.value_owned = false;
2729 var c = new Constant (id, type, initializer, get_src (begin), comment);
2730 c.access = get_access (id);
2732 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2733 c.external = true;
2735 if (ModifierFlags.NEW in flags) {
2736 c.hides = true;
2739 set_attributes (c, attrs);
2740 return c;
2743 Field parse_field_declaration (List<Attribute>? attrs) throws ParseError {
2744 var begin = get_location ();
2745 string id = parse_identifier ();
2746 expect (TokenType.COLON);
2748 var flags = parse_member_declaration_modifiers ();
2750 var type = parse_type ();
2752 type = parse_inline_array_type (type);
2754 var f = new Field (id, type, null, get_src (begin), comment);
2756 if (ModifierFlags.ABSTRACT in flags || ModifierFlags.VIRTUAL in flags || ModifierFlags.OVERRIDE in flags) {
2757 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2760 if (ModifierFlags.PRIVATE in flags) {
2761 f.access = SymbolAccessibility.PRIVATE;
2762 } else {
2763 f.access = get_access (id);
2766 set_attributes (f, attrs);
2768 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2769 f.external = true;
2771 if (ModifierFlags.NEW in flags) {
2772 f.hides = true;
2775 if (accept (TokenType.ASSIGN)) {
2776 f.initializer = parse_expression ();
2779 if (ModifierFlags.STATIC in flags) {
2780 f.binding = MemberBinding.STATIC;
2781 } else if (ModifierFlags.CLASS in flags) {
2782 f.binding = MemberBinding.CLASS;
2785 expect_terminator ();
2787 return f;
2790 InitializerList parse_initializer () throws ParseError {
2791 var begin = get_location ();
2792 if (!accept (TokenType.OPEN_PARENS)) {
2793 expect (TokenType.OPEN_BRACE);
2795 var initializer = new InitializerList (get_src (begin));
2796 if (current () != TokenType.DEDENT) {
2797 do {
2798 var init = parse_argument ();
2799 initializer.append (init);
2800 } while (accept (TokenType.COMMA));
2802 if (!accept (TokenType.CLOSE_PARENS)) {
2803 expect (TokenType.CLOSE_BRACE);
2805 return initializer;
2811 Method parse_main_method_declaration (List<Attribute>? attrs) throws ParseError {
2812 var id = "main";
2813 var begin = get_location ();
2814 DataType type = new VoidType ();
2815 expect (TokenType.INIT);
2817 var method = new Method (id, type, get_src (begin), comment);
2818 method.access = SymbolAccessibility.PUBLIC;
2820 set_attributes (method, attrs);
2822 method.binding = MemberBinding.STATIC;
2824 var sym = new UnresolvedSymbol (null, "string", get_src (begin));
2825 type = new UnresolvedType.from_symbol (sym, get_src (begin));
2826 type.value_owned = true;
2827 type = new ArrayType (type, 1, get_src (begin));
2828 type.nullable = false;
2830 var param = new Parameter ("args", type, get_src (begin));
2831 method.add_parameter (param);
2834 expect (TokenType.EOL);
2836 if (accept_block ()) {
2837 method.body = parse_block ();
2840 return method;
2843 Method parse_method_declaration (List<Attribute>? attrs) throws ParseError {
2844 var begin = get_location ();
2845 DataType type = new VoidType ();
2846 expect (TokenType.DEF);
2847 var flags = parse_member_declaration_modifiers ();
2849 string id = parse_identifier ();
2851 var params = new ArrayList<Parameter> ();
2852 expect (TokenType.OPEN_PARENS);
2854 if (current () != TokenType.CLOSE_PARENS) {
2855 do {
2856 var param = parse_parameter ();
2857 params.add (param);
2858 } while (accept (TokenType.COMMA));
2861 expect (TokenType.CLOSE_PARENS);
2864 /* deal with return value */
2865 if (accept (TokenType.COLON)) {
2866 type = parse_type ();
2869 var type_param_list = parse_type_parameter_list ();
2871 var method = new Method (id, type, get_src (begin), comment);
2872 if (ModifierFlags.PRIVATE in flags) {
2873 method.access = SymbolAccessibility.PRIVATE;
2874 } else {
2875 method.access = get_access (id);
2879 set_attributes (method, attrs);
2881 foreach (TypeParameter type_param in type_param_list) {
2882 method.add_type_parameter (type_param);
2886 foreach (Parameter param in params) {
2887 method.add_parameter (param);
2890 if (accept (TokenType.RAISES)) {
2891 do {
2892 method.add_error_type (parse_type ());
2893 } while (accept (TokenType.COMMA));
2897 if (ModifierFlags.STATIC in flags || id == "main") {
2898 method.binding = MemberBinding.STATIC;
2899 } else if (ModifierFlags.CLASS in flags) {
2900 method.binding = MemberBinding.CLASS;
2902 if (ModifierFlags.ASYNC in flags) {
2903 method.coroutine = true;
2906 if (ModifierFlags.NEW in flags) {
2907 method.hides = true;
2910 if (method.binding == MemberBinding.INSTANCE) {
2911 if (ModifierFlags.ABSTRACT in flags) {
2912 method.is_abstract = true;
2914 if (ModifierFlags.VIRTUAL in flags) {
2915 method.is_virtual = true;
2917 if (ModifierFlags.OVERRIDE in flags) {
2918 method.overrides = true;
2920 if ((method.is_abstract && method.is_virtual)
2921 || (method.is_abstract && method.overrides)
2922 || (method.is_virtual && method.overrides)) {
2923 throw new ParseError.SYNTAX (get_error ("only one of `abstract', `virtual', or `override' may be specified"));
2925 } else {
2926 if (ModifierFlags.ABSTRACT in flags
2927 || ModifierFlags.VIRTUAL in flags
2928 || ModifierFlags.OVERRIDE in flags) {
2929 throw new ParseError.SYNTAX (get_error ("the modifiers `abstract', `virtual', and `override' are not valid for static methods"));
2933 if (ModifierFlags.INLINE in flags) {
2934 method.is_inline = true;
2936 if (ModifierFlags.EXTERN in flags) {
2937 method.external = true;
2940 expect (TokenType.EOL);
2942 var body_location = get_location ();
2945 /* "requires" and "ensures" if present will be at start of the method body */
2946 if (accept (TokenType.INDENT)) {
2947 if (accept (TokenType.REQUIRES)) {
2949 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
2950 while (current() != TokenType.DEDENT) {
2951 method.add_precondition (parse_expression ());
2952 expect (TokenType.EOL);
2955 expect (TokenType.DEDENT);
2956 accept_terminator ();
2957 } else {
2959 method.add_precondition (parse_expression ());
2960 expect_terminator ();
2966 if (accept (TokenType.ENSURES)) {
2967 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
2968 while (current() != TokenType.DEDENT) {
2969 method.add_postcondition (parse_expression ());
2970 expect (TokenType.EOL);
2973 expect (TokenType.DEDENT);
2974 accept_terminator ();
2975 } else {
2976 method.add_postcondition (parse_expression ());
2977 expect_terminator ();
2982 rollback (body_location);
2985 if (accept_block ()) {
2986 method.body = parse_block ();
2987 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
2988 method.external = true;
2990 return method;
2993 Property parse_property_declaration (List<Attribute>? attrs) throws ParseError {
2994 var begin = get_location ();
2995 var readonly = false;
2997 expect (TokenType.PROP);
2999 var flags = parse_member_declaration_modifiers ();
3001 readonly = accept (TokenType.READONLY);
3003 string id = parse_identifier ();
3004 expect (TokenType.COLON);
3006 var type = parse_type (false);
3008 var prop = new Property (id, type, null, null, get_src (begin), comment);
3009 if (ModifierFlags.PRIVATE in flags) {
3010 prop.access = SymbolAccessibility.PRIVATE;
3011 } else {
3012 prop.access = get_access (id);
3015 set_attributes (prop, attrs);
3017 if (ModifierFlags.STATIC in flags) {
3018 prop.binding = MemberBinding.STATIC;
3019 } else if (ModifierFlags.CLASS in flags) {
3020 prop.binding = MemberBinding.CLASS;
3022 if (ModifierFlags.ABSTRACT in flags) {
3023 prop.is_abstract = true;
3025 if (ModifierFlags.VIRTUAL in flags) {
3026 prop.is_virtual = true;
3028 if (ModifierFlags.OVERRIDE in flags) {
3029 prop.overrides = true;
3032 if (ModifierFlags.NEW in flags) {
3033 prop.hides = true;
3035 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3036 prop.external = true;
3039 if (ModifierFlags.ASYNC in flags) {
3040 Report.error (prop.source_reference, "async properties are not supported yet");
3043 if (accept (TokenType.ASSIGN)) {
3044 prop.initializer = parse_expression ();
3048 if (accept_block ()) {
3049 expect (TokenType.INDENT);
3050 while (current () != TokenType.DEDENT) {
3051 var accessor_begin = get_location ();
3052 var attribs = parse_attributes ();
3054 var value_type = type.copy ();
3055 value_type.value_owned = accept (TokenType.OWNED);
3057 if (accept (TokenType.GET)) {
3058 if (prop.get_accessor != null) {
3059 throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
3061 Block block = null;
3062 if (accept_block ()) {
3063 block = parse_block ();
3064 prop.external = false;
3066 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin));
3067 set_attributes (prop.get_accessor, attribs);
3068 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
3069 } else {
3070 bool _construct = false;
3071 if (accept (TokenType.SET)) {
3072 if (readonly) {
3073 throw new ParseError.SYNTAX (get_error ("set block not allowed for a read only property"));
3075 _construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT);
3076 } else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) {
3077 _construct = true;
3078 } else if (!accept (TokenType.EOL)) {
3079 throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
3082 if (prop.set_accessor != null) {
3083 throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
3086 Block block = null;
3087 if (accept_block ()) {
3088 block = parse_block ();
3089 prop.external = false;
3091 prop.set_accessor = new PropertyAccessor (false, !readonly, _construct, value_type, block, get_src (accessor_begin));
3092 set_attributes (prop.set_accessor, attribs);
3093 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3096 accept (TokenType.EOL);
3097 expect (TokenType.DEDENT);
3098 } else {
3099 var value_type = type.copy ();
3100 value_type.value_owned = false;
3102 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, null, get_src (begin));
3103 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
3105 if (!readonly) {
3106 value_type = type.copy ();
3107 value_type.value_owned = false;
3109 prop.set_accessor = new PropertyAccessor (false, true, false, value_type, null, get_src (begin));
3110 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3114 expect_terminator ();
3117 if (!prop.is_abstract && scanner.source_file.file_type == SourceFileType.SOURCE) {
3118 var needs_var = (readonly && (prop.get_accessor != null && prop.get_accessor.body == null));
3120 if (!needs_var) {
3121 needs_var = (prop.get_accessor != null && prop.get_accessor.body == null) || (prop.set_accessor != null && prop.set_accessor.body == null);
3124 if (needs_var) {
3125 /* automatic property accessor body generation */
3126 var variable_type = prop.property_type.copy ();
3127 prop.field = new Field ("_%s".printf (prop.name), variable_type, prop.initializer, prop.source_reference);
3128 prop.field.access = SymbolAccessibility.PRIVATE;
3129 prop.field.binding = prop.binding;
3133 return prop;
3136 Vala.Signal parse_signal_declaration (List<Attribute>? attrs) throws ParseError {
3137 var begin = get_location ();
3138 DataType type;
3140 expect (TokenType.EVENT);
3141 var flags = parse_member_declaration_modifiers ();
3142 string id = parse_identifier ();
3145 var params = new ArrayList<Parameter> ();
3147 expect (TokenType.OPEN_PARENS);
3148 if (current () != TokenType.CLOSE_PARENS) {
3149 do {
3150 var param = parse_parameter ();
3151 params.add (param);
3152 } while (accept (TokenType.COMMA));
3154 expect (TokenType.CLOSE_PARENS);
3156 if (accept (TokenType.COLON)) {
3157 type = parse_type ();
3158 } else {
3159 type = new VoidType ();
3162 var sig = new Vala.Signal (id, type, get_src (begin), comment);
3163 if (ModifierFlags.PRIVATE in flags) {
3164 sig.access = SymbolAccessibility.PRIVATE;
3165 } else {
3166 sig.access = get_access (id);
3169 if (ModifierFlags.VIRTUAL in flags) {
3170 sig.is_virtual = true;
3172 if (ModifierFlags.NEW in flags) {
3173 sig.hides = true;
3176 if (ModifierFlags.STATIC in flags) {
3177 throw new ParseError.SYNTAX (get_error ("`static' modifier not allowed on signals"));
3178 } else if (ModifierFlags.CLASS in flags) {
3179 throw new ParseError.SYNTAX (get_error ("`class' modifier not allowed on signals"));
3182 set_attributes (sig, attrs);
3184 foreach (Parameter formal_param in params) {
3185 sig.add_parameter (formal_param);
3188 if (!accept_terminator ()) {
3189 sig.body = parse_block ();
3191 return sig;
3194 Constructor parse_constructor_declaration (List<Attribute>? attrs) throws ParseError {
3195 var begin = get_location ();
3197 expect (TokenType.INIT);
3198 var flags = parse_member_declaration_modifiers ();
3200 var c = new Constructor (get_src (begin));
3201 if (ModifierFlags.STATIC in flags) {
3202 c.binding = MemberBinding.STATIC;
3203 } else if (ModifierFlags.CLASS in flags) {
3204 c.binding = MemberBinding.CLASS;
3207 accept_block ();
3208 c.body = parse_block ();
3209 return c;
3212 Destructor parse_destructor_declaration (List<Attribute>? attrs) throws ParseError {
3213 var begin = get_location ();
3214 expect (TokenType.FINAL);
3215 var d = new Destructor (get_src (begin));
3216 accept_block ();
3217 d.body = parse_block ();
3218 return d;
3221 Symbol parse_struct_declaration (List<Attribute>? attrs) throws ParseError {
3222 var begin = get_location ();
3224 expect (TokenType.STRUCT);
3225 var flags = parse_type_declaration_modifiers ();
3226 var sym = parse_symbol_name ();
3227 var type_param_list = parse_type_parameter_list ();
3228 DataType base_type = null;
3229 if (accept (TokenType.COLON)) {
3230 base_type = parse_type ();
3233 var st = new Struct (sym.name, get_src (begin), comment);
3234 if (ModifierFlags.PRIVATE in flags) {
3235 st.access = SymbolAccessibility.PRIVATE;
3236 } else {
3237 st.access = get_access (sym.name);
3239 set_attributes (st, attrs);
3240 foreach (TypeParameter type_param in type_param_list) {
3241 st.add_type_parameter (type_param);
3243 if (base_type != null) {
3244 st.base_type = base_type;
3247 expect (TokenType.EOL);
3249 parse_declarations (st);
3251 Symbol result = st;
3252 while (sym.inner != null) {
3253 sym = sym.inner;
3254 var ns = new Namespace (sym.name, st.source_reference);
3255 if (result is Namespace) {
3256 ns.add_namespace ((Namespace) result);
3257 } else {
3258 ns.add_struct ((Struct) result);
3260 result = ns;
3262 return result;
3265 void parse_struct_member (Struct st) throws ParseError {
3266 var sym = parse_declaration ();
3267 if (sym is Method) {
3268 st.add_method ((Method) sym);
3269 } else if (sym is Field) {
3270 st.add_field ((Field) sym);
3271 } else if (sym is Constant) {
3272 st.add_constant ((Constant) sym);
3273 } else {
3274 Report.error (sym.source_reference, "unexpected declaration in struct");
3278 Symbol parse_interface_declaration (List<Attribute>? attrs) throws ParseError {
3279 var begin = get_location ();
3281 expect (TokenType.INTERFACE);
3282 var flags = parse_type_declaration_modifiers ();
3283 var sym = parse_symbol_name ();
3284 var type_param_list = parse_type_parameter_list ();
3285 var base_types = new ArrayList<DataType> ();
3286 if (accept (TokenType.COLON)) {
3287 do {
3288 var type = parse_type ();
3289 base_types.add (type);
3290 } while (accept (TokenType.COMMA));
3293 var iface = new Interface (sym.name, get_src (begin), comment);
3294 if (ModifierFlags.PRIVATE in flags) {
3295 iface.access = SymbolAccessibility.PRIVATE;
3296 } else {
3297 iface.access = get_access (sym.name);
3299 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3300 iface.external = true;
3302 set_attributes (iface, attrs);
3303 foreach (TypeParameter type_param in type_param_list) {
3304 iface.add_type_parameter (type_param);
3306 foreach (DataType base_type in base_types) {
3307 iface.add_prerequisite (base_type);
3311 expect (TokenType.EOL);
3313 parse_declarations (iface);
3316 Symbol result = iface;
3317 while (sym.inner != null) {
3318 sym = sym.inner;
3319 var ns = new Namespace (sym.name, iface.source_reference);
3320 if (result is Namespace) {
3321 ns.add_namespace ((Namespace) result);
3322 } else {
3323 ns.add_interface ((Interface) result);
3325 result = ns;
3327 return result;
3330 void parse_interface_member (Interface iface) throws ParseError {
3331 var sym = parse_declaration ();
3332 if (sym is Class) {
3333 iface.add_class ((Class) sym);
3334 } else if (sym is Struct) {
3335 iface.add_struct ((Struct) sym);
3336 } else if (sym is Enum) {
3337 iface.add_enum ((Enum) sym);
3338 } else if (sym is Delegate) {
3339 iface.add_delegate ((Delegate) sym);
3340 } else if (sym is Method) {
3341 iface.add_method ((Method) sym);
3342 } else if (sym is Vala.Signal) {
3343 iface.add_signal ((Vala.Signal) sym);
3344 } else if (sym is Field) {
3345 iface.add_field ((Field) sym);
3346 } else if (sym is Constant) {
3347 iface.add_constant ((Constant) sym);
3348 } else if (sym is Property) {
3349 iface.add_property ((Property) sym);
3350 } else {
3351 Report.error (sym.source_reference, "unexpected declaration in interface");
3355 Symbol parse_enum_declaration (List<Attribute>? attrs) throws ParseError {
3356 var begin = get_location ();
3357 expect (TokenType.ENUM);
3358 var flags = parse_type_declaration_modifiers ();
3360 var sym = parse_symbol_name ();
3361 var en = new Enum (sym.name, get_src (begin), comment);
3362 if (ModifierFlags.PRIVATE in flags) {
3363 en.access = SymbolAccessibility.PRIVATE;
3364 } else {
3365 en.access = get_access (sym.name);
3367 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3368 en.external = true;
3370 set_attributes (en, attrs);
3372 expect (TokenType.EOL);
3373 expect (TokenType.INDENT);
3374 do {
3375 if (current () == TokenType.DEDENT) {
3376 // allow trailing comma
3377 break;
3379 var value_attrs = parse_attributes ();
3380 var value_begin = get_location ();
3381 string id = parse_identifier ();
3382 comment = scanner.pop_comment ();
3384 Expression value = null;
3385 if (accept (TokenType.ASSIGN)) {
3386 value = parse_expression ();
3389 var ev = new EnumValue (id, value, get_src (value_begin), comment);
3390 ev.access = SymbolAccessibility.PUBLIC;
3391 set_attributes (ev, value_attrs);
3393 en.add_value (ev);
3394 expect (TokenType.EOL);
3395 } while (true);
3397 expect (TokenType.DEDENT);
3399 Symbol result = en;
3400 while (sym.inner != null) {
3401 sym = sym.inner;
3402 var ns = new Namespace (sym.name, en.source_reference);
3403 if (result is Namespace) {
3404 ns.add_namespace ((Namespace) result);
3405 } else {
3406 ns.add_enum ((Enum) result);
3408 result = ns;
3410 return result;
3413 Symbol parse_errordomain_declaration (List<Attribute>? attrs) throws ParseError {
3414 var begin = get_location ();
3415 expect (TokenType.ERRORDOMAIN);
3416 var flags = parse_type_declaration_modifiers ();
3418 var sym = parse_symbol_name ();
3419 var ed = new ErrorDomain (sym.name, get_src (begin), comment);
3420 if (ModifierFlags.PRIVATE in flags) {
3421 ed.access = SymbolAccessibility.PRIVATE;
3422 } else {
3423 ed.access = get_access (sym.name);
3426 set_attributes (ed, attrs);
3428 expect (TokenType.EOL);
3429 expect (TokenType.INDENT);
3431 do {
3432 if (current () == TokenType.DEDENT) {
3433 // allow trailing comma
3434 break;
3436 var code_attrs = parse_attributes ();
3437 var code_begin = get_location ();
3438 string id = parse_identifier ();
3439 comment = scanner.pop_comment ();
3440 var ec = new ErrorCode (id, get_src (code_begin), comment);
3441 set_attributes (ec, code_attrs);
3442 if (accept (TokenType.ASSIGN)) {
3443 ec.value = parse_expression ();
3445 ed.add_code (ec);
3446 accept (TokenType.EOL);
3447 } while (true);
3450 expect (TokenType.DEDENT);
3452 Symbol result = ed;
3453 while (sym.inner != null) {
3454 sym = sym.inner;
3455 var ns = new Namespace (sym.name, ed.source_reference);
3457 if (result is Namespace) {
3458 ns.add_namespace ((Namespace) result);
3459 } else {
3460 ns.add_error_domain ((ErrorDomain) result);
3462 result = ns;
3464 return result;
3467 ModifierFlags parse_type_declaration_modifiers () {
3468 ModifierFlags flags = 0;
3469 while (true) {
3470 switch (current ()) {
3471 case TokenType.ABSTRACT:
3472 next ();
3473 flags |= ModifierFlags.ABSTRACT;
3474 break;
3476 case TokenType.EXTERN:
3477 next ();
3478 flags |= ModifierFlags.EXTERN;
3479 break;
3481 case TokenType.STATIC:
3482 next ();
3483 flags |= ModifierFlags.STATIC;
3484 break;
3486 case TokenType.PRIVATE:
3487 next ();
3488 flags |= ModifierFlags.PRIVATE;
3489 break;
3491 default:
3492 return flags;
3497 ModifierFlags parse_member_declaration_modifiers () {
3498 ModifierFlags flags = 0;
3499 while (true) {
3500 switch (current ()) {
3501 case TokenType.ABSTRACT:
3502 next ();
3503 flags |= ModifierFlags.ABSTRACT;
3504 break;
3505 case TokenType.ASYNC:
3506 next ();
3507 flags |= ModifierFlags.ASYNC;
3508 break;
3509 case TokenType.CLASS:
3510 next ();
3511 flags |= ModifierFlags.CLASS;
3512 break;
3513 case TokenType.EXTERN:
3514 next ();
3515 flags |= ModifierFlags.EXTERN;
3516 break;
3517 case TokenType.INLINE:
3518 next ();
3519 flags |= ModifierFlags.INLINE;
3520 break;
3521 case TokenType.NEW:
3522 next ();
3523 flags |= ModifierFlags.NEW;
3524 break;
3525 case TokenType.OVERRIDE:
3526 next ();
3527 flags |= ModifierFlags.OVERRIDE;
3528 break;
3529 case TokenType.STATIC:
3530 next ();
3531 flags |= ModifierFlags.STATIC;
3532 break;
3533 case TokenType.VIRTUAL:
3534 next ();
3535 flags |= ModifierFlags.VIRTUAL;
3536 break;
3537 case TokenType.PRIVATE:
3538 next ();
3539 flags |= ModifierFlags.PRIVATE;
3540 break;
3541 default:
3542 return flags;
3547 Parameter parse_parameter () throws ParseError {
3548 var attrs = parse_attributes ();
3549 var begin = get_location ();
3550 if (accept (TokenType.ELLIPSIS)) {
3551 // varargs
3552 return new Parameter.with_ellipsis (get_src (begin));
3554 bool params_array = accept (TokenType.PARAMS);
3555 var direction = ParameterDirection.IN;
3556 if (accept (TokenType.OUT)) {
3557 direction = ParameterDirection.OUT;
3558 } else if (accept (TokenType.REF)) {
3559 direction = ParameterDirection.REF;
3562 string id = parse_identifier ();
3564 expect (TokenType.COLON);
3566 DataType type;
3567 if (direction == ParameterDirection.IN) {
3568 type = parse_type (false);
3569 } else {
3570 type = parse_type (true);
3573 var param = new Parameter (id, type, get_src (begin));
3574 set_attributes (param, attrs);
3575 param.direction = direction;
3576 param.params_array = params_array;
3577 if (accept (TokenType.ASSIGN)) {
3578 param.initializer = parse_expression ();
3580 return param;
3583 CreationMethod parse_creation_method_declaration (List<Attribute>? attrs) throws ParseError {
3584 var begin = get_location ();
3585 CreationMethod method;
3587 expect (TokenType.CONSTRUCT);
3588 parse_member_declaration_modifiers ();
3590 if (accept (TokenType.OPEN_PARENS)) {
3591 /* create default name using class name */
3592 method = new CreationMethod (class_name, null, get_src (begin), comment);
3593 } else {
3594 var sym = parse_symbol_name ();
3595 if (sym.inner == null) {
3597 if (sym.name != class_name) {
3598 method = new CreationMethod (class_name, sym.name, get_src (begin), comment);
3599 } else {
3600 method = new CreationMethod (sym.name, null, get_src (begin), comment);
3602 } else {
3603 method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
3605 expect (TokenType.OPEN_PARENS);
3608 if (current () != TokenType.CLOSE_PARENS) {
3609 do {
3610 var param = parse_parameter ();
3611 method.add_parameter (param);
3612 } while (accept (TokenType.COMMA));
3614 expect (TokenType.CLOSE_PARENS);
3615 if (accept (TokenType.RAISES)) {
3616 do {
3617 method.add_error_type (parse_type ());
3618 } while (accept (TokenType.COMMA));
3620 method.access = SymbolAccessibility.PUBLIC;
3621 set_attributes (method, attrs);
3622 method.binding = MemberBinding.STATIC;
3624 if (accept_block ()) {
3625 method.body = parse_block ();
3626 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
3627 method.external = true;
3630 return method;
3633 Symbol parse_delegate_declaration (List<Attribute>? attrs) throws ParseError {
3634 var begin = get_location ();
3635 DataType type;
3637 expect (TokenType.DELEGATE);
3639 var flags = parse_member_declaration_modifiers ();
3641 var sym = parse_symbol_name ();
3643 var type_param_list = parse_type_parameter_list ();
3645 if (ModifierFlags.NEW in flags) {
3646 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on delegates"));
3649 var params = new ArrayList<Parameter> ();
3651 expect (TokenType.OPEN_PARENS);
3652 if (current () != TokenType.CLOSE_PARENS) {
3653 do {
3654 var param = parse_parameter ();
3655 params.add (param);
3656 } while (accept (TokenType.COMMA));
3658 expect (TokenType.CLOSE_PARENS);
3660 if (accept (TokenType.COLON)) {
3661 type = parse_type ();
3663 } else {
3664 type = new VoidType ();
3667 var d = new Delegate (sym.name, type, get_src (begin), comment);
3669 if (accept (TokenType.RAISES)) {
3670 do {
3671 d.add_error_type (parse_type ());
3672 } while (accept (TokenType.COMMA));
3675 expect_terminator ();
3678 if (ModifierFlags.PRIVATE in flags) {
3679 d.access = SymbolAccessibility.PRIVATE;
3680 } else {
3681 d.access = get_access (sym.name);
3684 if (!(ModifierFlags.STATIC in flags)) {
3685 d.has_target = true;
3687 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3688 d.external = true;
3691 set_attributes (d, attrs);
3693 foreach (TypeParameter type_param in type_param_list) {
3694 d.add_type_parameter (type_param);
3697 foreach (Parameter formal_param in params) {
3698 d.add_parameter (formal_param);
3703 Symbol result = d;
3704 while (sym.inner != null) {
3705 sym = sym.inner;
3706 var ns = new Namespace (sym.name, d.source_reference);
3708 if (result is Namespace) {
3709 ns.add_namespace ((Namespace) result);
3710 } else {
3711 ns.add_delegate ((Delegate) result);
3713 result = ns;
3715 return result;
3718 List<TypeParameter> parse_type_parameter_list () throws ParseError {
3719 if (accept (TokenType.OF)) {
3720 var list = new ArrayList<TypeParameter> ();
3721 do {
3722 var begin = get_location ();
3723 string id = parse_identifier ();
3724 list.add (new TypeParameter (id, get_src (begin)));
3725 } while (accept (TokenType.COMMA));
3726 return list;
3727 } else {
3728 if (_empty_type_parameter_list == null) {
3729 _empty_type_parameter_list = new ArrayList<TypeParameter> ();
3731 return _empty_type_parameter_list;
3735 void skip_type_argument_list () throws ParseError {
3736 if (accept (TokenType.OF)) {
3737 do {
3738 skip_type ();
3739 } while (accept (TokenType.COMMA));
3743 // try to parse type argument list
3744 List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3745 var begin = get_location ();
3746 if (accept (TokenType.OF)) {
3747 var list = new ArrayList<DataType> ();
3748 do {
3749 switch (current ()) {
3750 case TokenType.VOID:
3751 case TokenType.DYNAMIC:
3752 case TokenType.UNOWNED:
3753 case TokenType.WEAK:
3754 case TokenType.IDENTIFIER:
3755 var type = parse_type ();
3757 list.add (type);
3758 break;
3759 default:
3760 rollback (begin);
3761 return null;
3763 } while (accept (TokenType.COMMA));
3765 return list;
3767 return null;
3770 MemberAccess parse_member_name (Expression? base_expr = null) throws ParseError {
3771 var begin = get_location ();
3772 MemberAccess expr = null;
3773 do {
3774 string id = parse_identifier ();
3775 List<DataType> type_arg_list = parse_type_argument_list (false);
3776 expr = new MemberAccess (expr != null ? expr : base_expr, id, get_src (begin));
3777 if (type_arg_list != null) {
3778 foreach (DataType type_arg in type_arg_list) {
3779 expr.add_type_argument (type_arg);
3782 } while (accept (TokenType.DOT));
3783 return expr;