linux: Add psiginfo(3)
[vala-gnome.git] / vala / valagenieparser.vala
blobdfffa23a7a51220bac59e39ba679a36463375748
1 /* valagenieparser.vala
3 * Copyright (C) 2008-2012 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,
71 SEALED = 1 << 10
74 public Parser () {
75 tokens = new TokenInfo[BUFFER_SIZE];
76 class_name = null;
77 current_expr_is_lambda = false;
80 /**
81 * Parses all .gs source files in the specified code context and
82 * builds a code tree.
84 * @param context a code context
86 public void parse (CodeContext context) {
87 this.context = context;
88 context.accept (this);
89 this.context = null;
92 public override void visit_source_file (SourceFile source_file) {
93 if (source_file.filename.has_suffix (".gs")) {
94 parse_file (source_file);
98 inline bool next () {
99 index = (index + 1) % BUFFER_SIZE;
100 size--;
101 if (size <= 0) {
102 SourceLocation begin, end;
103 TokenType type = scanner.read_token (out begin, out end);
104 tokens[index] = { type, begin, 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_separator () {
129 if (current () == TokenType.COMMA || current () == TokenType.EOL) {
130 next ();
131 return true;
133 return false;
136 inline bool accept_terminator () {
137 if (current () == TokenType.SEMICOLON || current () == TokenType.EOL) {
138 next ();
139 return true;
141 return false;
144 inline bool accept_block () {
146 bool has_term = accept_terminator ();
148 if (accept (TokenType.INDENT)) {
149 prev();
150 return true;
153 if (has_term) {
154 prev ();
157 return false;
160 void report_parse_error (ParseError e) {
161 var begin = get_location ();
162 next ();
163 Report.error (get_src (begin), "syntax error, " + e.message);
166 inline bool expect (TokenType type) throws ParseError {
167 if (accept (type)) {
168 return true;
171 TokenType cur = current ();
172 TokenType pre = tokens[index - 1].type;
174 throw new ParseError.SYNTAX ("expected %s but got %s with previous %s", type.to_string (), cur.to_string (), pre.to_string());
177 inline bool expect_separator () throws ParseError {
178 if (accept_separator ()) {
179 return true;
182 TokenType cur = current ();
184 throw new ParseError.SYNTAX ("expected line end or comma but got %s", cur.to_string());
187 inline bool expect_terminator () throws ParseError {
188 if (accept_terminator ()) {
189 return true;
192 TokenType cur = current ();
194 throw new ParseError.SYNTAX ("expected line end or semicolon but got %s", cur.to_string());
197 inline SourceLocation get_location () {
198 return tokens[index].begin;
201 string get_current_string () {
202 var token = tokens[index];
203 return ((string) token.begin.pos).substring (0, (int) (token.end.pos - token.begin.pos));
206 string get_last_string () {
207 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
208 var token = tokens[last_index];
209 return ((string) token.begin.pos).substring (0, (int) (token.end.pos - token.begin.pos));
212 SourceReference get_src (SourceLocation begin) {
213 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
215 return new SourceReference (scanner.source_file, begin, tokens[last_index].end);
218 SourceReference get_current_src () {
219 var token = tokens[index];
220 return new SourceReference (scanner.source_file, token.begin, token.end);
223 void rollback (SourceLocation location) {
224 while (tokens[index].begin.pos != location.pos) {
225 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
226 size++;
227 if (size > BUFFER_SIZE) {
228 scanner.seek (location);
229 size = 0;
230 index = 0;
232 next ();
237 inline SymbolAccessibility get_access (string s) {
238 if (s[0] == '_') {
239 return SymbolAccessibility.PRIVATE;
242 return SymbolAccessibility.PUBLIC;
245 void skip_identifier () throws ParseError {
246 // also accept keywords as identifiers where there is no conflict
247 switch (current ()) {
248 case TokenType.ABSTRACT:
249 case TokenType.AS:
250 case TokenType.ASSERT:
251 case TokenType.ASYNC:
252 case TokenType.BREAK:
253 case TokenType.CLASS:
254 case TokenType.CONST:
255 case TokenType.CONTINUE:
256 case TokenType.DEDENT:
257 case TokenType.DEF:
258 case TokenType.DEFAULT:
259 case TokenType.DELEGATE:
260 case TokenType.DELETE:
261 case TokenType.DO:
262 case TokenType.DOWNTO:
263 case TokenType.DYNAMIC:
264 case TokenType.ELSE:
265 case TokenType.EOL:
266 case TokenType.ENUM:
267 case TokenType.ENSURES:
268 case TokenType.ERRORDOMAIN:
269 case TokenType.EVENT:
270 case TokenType.EXCEPT:
271 case TokenType.EXTERN:
272 case TokenType.FALSE:
273 case TokenType.FINAL:
274 case TokenType.FINALLY:
275 case TokenType.FOR:
276 case TokenType.GET:
277 case TokenType.IDENTIFIER:
278 case TokenType.IF:
279 case TokenType.IN:
280 case TokenType.INDENT:
281 case TokenType.INIT:
282 case TokenType.INLINE:
283 case TokenType.INTERFACE:
284 case TokenType.INTERNAL:
285 case TokenType.IS:
286 case TokenType.ISA:
287 case TokenType.LOCK:
288 case TokenType.NAMESPACE:
289 case TokenType.NEW:
290 case TokenType.NULL:
291 case TokenType.OF:
292 case TokenType.OUT:
293 case TokenType.OVERRIDE:
294 case TokenType.OWNED:
295 case TokenType.PASS:
296 case TokenType.PRINT:
297 case TokenType.PRIVATE:
298 case TokenType.PROP:
299 case TokenType.RAISE:
300 case TokenType.RAISES:
301 case TokenType.REF:
302 case TokenType.REQUIRES:
303 case TokenType.RETURN:
304 case TokenType.SEALED:
305 case TokenType.SET:
306 case TokenType.SIZEOF:
307 case TokenType.STATIC:
308 case TokenType.STRUCT:
309 case TokenType.SUPER:
310 case TokenType.THIS:
311 case TokenType.TO:
312 case TokenType.TRUE:
313 case TokenType.TRY:
314 case TokenType.TYPEOF:
315 case TokenType.UNOWNED:
316 case TokenType.USES:
317 case TokenType.VAR:
318 case TokenType.VIRTUAL:
319 case TokenType.VOID:
320 case TokenType.VOLATILE:
321 case TokenType.WEAK:
322 case TokenType.WHEN:
323 case TokenType.WHILE:
324 case TokenType.YIELD:
325 next ();
326 return;
327 case TokenType.INTEGER_LITERAL:
328 case TokenType.REAL_LITERAL:
329 // also accept integer and real literals
330 // as long as they contain at least one character
331 // and no decimal point
332 // for example, 2D and 3D
333 string id = get_current_string ();
334 if (id[id.length - 1].isalpha () && !("." in id)) {
335 next ();
336 return;
338 break;
339 default:
340 break;
343 throw new ParseError.SYNTAX ("expected identifier");
346 string parse_identifier () throws ParseError {
347 skip_identifier ();
348 return get_last_string ();
351 Expression parse_literal () throws ParseError {
352 var begin = get_location ();
354 switch (current ()) {
355 case TokenType.TRUE:
356 next ();
357 return new BooleanLiteral (true, get_src (begin));
358 case TokenType.FALSE:
359 next ();
360 return new BooleanLiteral (false, get_src (begin));
361 case TokenType.INTEGER_LITERAL:
362 next ();
363 return new IntegerLiteral (get_last_string (), get_src (begin));
364 case TokenType.REAL_LITERAL:
365 next ();
366 return new RealLiteral (get_last_string (), get_src (begin));
367 case TokenType.CHARACTER_LITERAL:
368 next ();
369 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
370 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
371 if (lit.error) {
372 Report.error (lit.source_reference, "invalid character literal");
374 return lit;
375 case TokenType.REGEX_LITERAL:
376 next ();
377 string match_part = get_last_string ();
378 SourceReference src_begin = get_src (begin);
379 expect (TokenType.CLOSE_REGEX_LITERAL);
380 string close_token = get_last_string ();
381 return new RegexLiteral ("%s/%s".printf (close_token, match_part), src_begin);
382 case TokenType.STRING_LITERAL:
383 next ();
384 return new StringLiteral (get_last_string (), get_src (begin));
385 case TokenType.TEMPLATE_STRING_LITERAL:
386 next ();
387 return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
388 case TokenType.VERBATIM_STRING_LITERAL:
389 next ();
390 string raw_string = get_last_string ();
391 string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
392 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
393 case TokenType.NULL:
394 next ();
395 return new NullLiteral (get_src (begin));
396 default:
397 throw new ParseError.SYNTAX ("expected literal");
401 public void parse_file (SourceFile source_file) {
402 var has_global_context = (context != null);
403 if (!has_global_context) {
404 context = source_file.context;
407 scanner = new Scanner (source_file);
408 scanner.parse_file_comments ();
409 scanner.indent_spaces = 0;
410 index = -1;
411 size = 0;
413 next ();
415 try {
416 var begin = get_location ();
417 /* see if there is an indent attribute */
418 if (accept (TokenType.OPEN_BRACKET)) {
419 var id = parse_identifier ();
420 if (id == "indent") {
421 expect (TokenType.ASSIGN);
422 expect (TokenType.INTEGER_LITERAL);
423 scanner.indent_spaces = int.parse (get_last_string());
424 expect (TokenType.CLOSE_BRACKET);
425 expect (TokenType.EOL);
426 } else {
427 rollback (begin);
431 parse_using_directives (context.root);
432 parse_declarations (context.root, true);
433 } catch (ParseError e) {
434 report_parse_error (e);
437 scanner = null;
438 if (!has_global_context) {
439 context = null;
443 void skip_symbol_name () throws ParseError {
444 do {
445 skip_identifier ();
446 } while (accept (TokenType.DOT));
449 UnresolvedSymbol parse_symbol_name () throws ParseError {
450 var begin = get_location ();
451 UnresolvedSymbol sym = null;
452 do {
453 string name = parse_identifier ();
454 sym = new UnresolvedSymbol (sym, name, get_src (begin));
455 } while (accept (TokenType.DOT));
456 return sym;
459 void skip_type () throws ParseError {
461 accept (TokenType.DYNAMIC);
462 accept (TokenType.OWNED);
463 accept (TokenType.UNOWNED);
464 accept (TokenType.WEAK);
467 if (accept (TokenType.ARRAY) || accept (TokenType.LIST) || accept (TokenType.DICT)) {
468 accept (TokenType.OF);
471 if (accept (TokenType.VOID)) {
472 } else {
473 skip_symbol_name ();
474 skip_type_argument_list ();
477 while (accept (TokenType.OPEN_BRACKET)) {
478 do {
479 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
480 parse_expression ();
482 } while (accept (TokenType.COMMA));
483 expect (TokenType.CLOSE_BRACKET);
485 accept (TokenType.OP_NEG);
486 accept (TokenType.INTERR);
487 accept (TokenType.HASH);
491 Expression parse_regex_literal () throws ParseError {
492 expect (TokenType.OPEN_REGEX_LITERAL);
494 var expr = parse_literal ();
496 return expr;
499 DataType parse_type (bool owned_by_default, bool can_weak_ref) throws ParseError {
500 var begin = get_location ();
502 List<DataType> type_arg_list = null;
503 UnresolvedSymbol sym = null;
505 bool is_dynamic = accept (TokenType.DYNAMIC);
506 bool value_owned = owned_by_default;
508 if (owned_by_default) {
509 if (accept (TokenType.UNOWNED)) {
510 value_owned = false;
511 } else if (accept (TokenType.WEAK)) {
512 if (!can_weak_ref && !context.deprecated) {
513 Report.warning (get_src (begin), "deprecated syntax, use `unowned` modifier");
515 value_owned = false;
517 } else {
518 value_owned = accept (TokenType.OWNED);
521 /* handle arrays */
522 bool is_array = false;
524 if (accept (TokenType.ARRAY)) {
525 expect (TokenType.OF);
526 is_array = true;
529 /* handle lists */
530 bool is_list = false;
532 if (accept (TokenType.LIST)) {
533 expect (TokenType.OF);
534 prev ();
535 is_list = true;
538 /* handle dicts */
539 bool is_dict = false;
541 if (accept (TokenType.DICT)) {
542 expect (TokenType.OF);
543 prev ();
544 is_dict = true;
547 DataType type;
549 if (!is_dynamic && value_owned == owned_by_default && accept (TokenType.VOID)) {
550 type = new VoidType (get_src (begin));
551 } else {
553 if (is_list) {
554 var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
555 sym = new UnresolvedSymbol (sym_parent, "ArrayList", get_src (begin));
556 } else if (is_dict) {
557 var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
558 sym = new UnresolvedSymbol (sym_parent, "HashMap", get_src (begin));
559 } else {
560 sym = parse_symbol_name ();
563 type_arg_list = parse_type_argument_list (false);
565 type = new UnresolvedType.from_symbol (sym, get_src (begin));
566 if (type_arg_list != null) {
567 foreach (DataType type_arg in type_arg_list) {
568 type.add_type_argument (type_arg);
573 while (accept (TokenType.STAR)) {
574 type = new PointerType (type, get_src (begin));
577 if (!(type is PointerType)) {
578 type.nullable = accept (TokenType.INTERR);
581 if (is_array) {
583 if (!accept (TokenType.OPEN_BRACKET)) {
584 type.value_owned = true;
585 type = new ArrayType (type, 1, get_src (begin));
586 type.nullable = accept (TokenType.INTERR);
588 } else {
589 prev ();
591 while (accept (TokenType.OPEN_BRACKET)) {
592 bool invalid_array = false;
593 int array_rank = 0;
594 do {
595 array_rank++;
596 // required for decision between expression and declaration statement
597 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
598 parse_expression ();
599 // only used for parsing, reject use as real type
600 invalid_array = true;
602 } while (accept (TokenType.COMMA));
603 expect (TokenType.CLOSE_BRACKET);
605 type.value_owned = true;
606 var array_type = new ArrayType (type, array_rank, get_src (begin));
607 array_type.nullable = accept (TokenType.INTERR);
609 array_type.invalid_syntax = invalid_array;
611 type = array_type;
616 if (!owned_by_default) {
617 value_owned = accept (TokenType.HASH);
620 if (type is PointerType) {
621 value_owned = false;
624 type.is_dynamic = is_dynamic;
625 type.value_owned = value_owned;
626 return type;
629 DataType? parse_inline_array_type (DataType? type) throws ParseError {
630 var begin = get_location ();
632 // inline-allocated array
633 if (type != null && accept (TokenType.OPEN_BRACKET)) {
634 Expression array_length = null;
636 if (current () != TokenType.CLOSE_BRACKET) {
637 array_length = parse_expression ();
639 expect (TokenType.CLOSE_BRACKET);
641 var array_type = new ArrayType (type, 1, get_src (begin));
642 array_type.inline_allocated = true;
643 if (array_length != null) {
644 array_type.fixed_length = true;
645 array_type.length = array_length;
647 array_type.value_owned = type.value_owned;
648 return array_type;
650 return type;
654 List<Expression> parse_argument_list () throws ParseError {
655 var list = new ArrayList<Expression> ();
656 if (current () != TokenType.CLOSE_PARENS) {
657 do {
658 list.add (parse_argument ());
659 } while (accept (TokenType.COMMA));
661 return list;
664 Expression parse_argument () throws ParseError {
665 var begin = get_location ();
667 if (accept (TokenType.REF)) {
668 var inner = parse_expression ();
669 return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
670 } else if (accept (TokenType.OUT)) {
671 var inner = parse_expression ();
672 return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
673 } else {
674 var expr = parse_expression ();
675 var ma = expr as MemberAccess;
676 if (ma != null && ma.inner == null && accept (TokenType.COLON)) {
677 // named argument
678 expr = parse_expression ();
679 return new NamedArgument (ma.member_name, expr, get_src (begin));
680 } else {
681 return expr;
687 Expression parse_primary_expression () throws ParseError {
688 var begin = get_location ();
690 Expression expr;
692 switch (current ()) {
693 case TokenType.TRUE:
694 case TokenType.FALSE:
695 case TokenType.INTEGER_LITERAL:
696 case TokenType.REAL_LITERAL:
697 case TokenType.CHARACTER_LITERAL:
698 case TokenType.REGEX_LITERAL:
699 case TokenType.STRING_LITERAL:
700 case TokenType.TEMPLATE_STRING_LITERAL:
701 case TokenType.VERBATIM_STRING_LITERAL:
702 case TokenType.NULL:
703 expr = parse_literal ();
704 break;
705 case TokenType.ASSERT:
706 return parse_assert_expression ();
707 case TokenType.OPEN_BRACE:
708 expr = parse_initializer ();
709 break;
710 case TokenType.OPEN_PARENS:
711 expr = parse_tuple ();
712 break;
713 case TokenType.OPEN_REGEX_LITERAL:
714 expr = parse_regex_literal ();
715 break;
716 case TokenType.OPEN_TEMPLATE:
717 expr = parse_template ();
718 break;
719 case TokenType.THIS:
720 expr = parse_this_access ();
721 break;
722 case TokenType.SUPER:
723 expr = parse_base_access ();
724 break;
725 case TokenType.NEW:
726 expr = parse_object_or_array_creation_expression ();
727 break;
728 case TokenType.PRINT:
729 return parse_print_expression ();
730 case TokenType.SIZEOF:
731 expr = parse_sizeof_expression ();
732 break;
733 case TokenType.TYPEOF:
734 expr = parse_typeof_expression ();
735 break;
736 case TokenType.YIELD:
737 expr = parse_yield_expression ();
738 break;
739 default:
740 expr = parse_simple_name ();
741 break;
744 // process primary expressions that start with an inner primary expression
745 bool found = true;
746 while (found) {
747 switch (current ()) {
748 case TokenType.DOT:
749 expr = parse_member_access (begin, expr);
750 break;
751 case TokenType.OP_PTR:
752 expr = parse_pointer_member_access (begin, expr);
753 break;
754 case TokenType.OPEN_PARENS:
755 expr = parse_method_call (begin, expr);
756 break;
757 case TokenType.OPEN_BRACKET:
758 expr = parse_element_access (begin, expr);
759 break;
760 case TokenType.OP_INC:
761 expr = parse_post_increment_expression (begin, expr);
762 break;
763 case TokenType.OP_DEC:
764 expr = parse_post_decrement_expression (begin, expr);
765 break;
767 default:
768 found = false;
769 break;
773 return expr;
776 Expression parse_simple_name () throws ParseError {
777 var begin = get_location ();
778 string id = parse_identifier ();
779 List<DataType> type_arg_list = parse_type_argument_list (true);
780 var expr = new MemberAccess (null, id, get_src (begin));
781 if (type_arg_list != null) {
782 foreach (DataType type_arg in type_arg_list) {
783 expr.add_type_argument (type_arg);
786 return expr;
789 Expression parse_template () throws ParseError {
790 var begin = get_location ();
791 var template = new Template ();
793 expect (TokenType.OPEN_TEMPLATE);
794 while (current () != TokenType.CLOSE_TEMPLATE) {
795 template.add_expression (parse_expression ());
796 expect (TokenType.COMMA);
798 expect (TokenType.CLOSE_TEMPLATE);
800 template.source_reference = get_src (begin);
801 return template;
804 Expression parse_tuple () throws ParseError {
805 expect (TokenType.OPEN_PARENS);
806 var expr_list = new ArrayList<Expression> ();
807 if (current () != TokenType.CLOSE_PARENS) {
808 do {
809 expr_list.add (parse_expression ());
810 } while (accept (TokenType.COMMA));
812 expect (TokenType.CLOSE_PARENS);
813 if (expr_list.size != 1) {
814 var tuple = new Tuple ();
815 foreach (Expression expr in expr_list) {
816 tuple.add_expression (expr);
818 return tuple;
820 return expr_list.get (0);
823 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
824 expect (TokenType.DOT);
825 string id = parse_identifier ();
826 List<DataType> type_arg_list = parse_type_argument_list (true);
827 var expr = new MemberAccess (inner, id, get_src (begin));
828 if (type_arg_list != null) {
829 foreach (DataType type_arg in type_arg_list) {
830 expr.add_type_argument (type_arg);
833 return expr;
836 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
837 expect (TokenType.OP_PTR);
838 string id = parse_identifier ();
839 List<DataType> type_arg_list = parse_type_argument_list (true);
840 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
841 if (type_arg_list != null) {
842 foreach (DataType type_arg in type_arg_list) {
843 expr.add_type_argument (type_arg);
846 return expr;
850 List<Expression> parse_print_argument_list () throws ParseError {
851 var list = new ArrayList<Expression> ();
852 var i = 0;
853 var begin = get_location ();
855 if (current () != TokenType.CLOSE_PARENS) {
856 do {
857 var p_expr = parse_expression ();
858 if (i == 0) {
859 i++;
861 if (p_expr != null) {
862 if (p_expr is StringLiteral) {
863 var s_exp = (StringLiteral) p_expr;
864 var len = s_exp.value.length;
866 if (len > 2) {
867 string s = "\\n\"";
868 var st = s_exp.value.substring (0, len-1);
869 st += s;
870 s_exp.value = st;
871 } else {
872 string s = "\"\\n\"";
873 p_expr = new StringLiteral (s, get_src (begin));
875 } else {
876 string s = "\"%s\\n\"";
877 var s_exp = new StringLiteral (s, get_src (begin));
878 list.add (s_exp);
882 list.add (p_expr);
884 } while (accept (TokenType.COMMA));
886 return list;
889 Expression parse_print_expression () throws ParseError {
890 var begin = get_location ();
892 expect (TokenType.PRINT);
893 bool parens = accept (TokenType.OPEN_PARENS);
895 var expr = new MemberAccess (null, "print", get_src (begin));
897 var arg_list = parse_print_argument_list ();
899 if (parens) {
900 expect (TokenType.CLOSE_PARENS);
903 var print_expr = new MethodCall (expr, get_src (begin));
905 foreach (Expression arg in arg_list) {
906 print_expr.add_argument (arg);
909 return print_expr;
913 Expression parse_assert_expression () throws ParseError {
914 var begin = get_location ();
916 expect (TokenType.ASSERT);
917 bool parens = accept (TokenType.OPEN_PARENS);
919 var expr = new MemberAccess (null, "assert", get_src (begin));
921 var arg_list = parse_argument_list ();
923 if (parens) {
924 expect (TokenType.CLOSE_PARENS);
927 var assert_expr = new MethodCall (expr, get_src (begin));
929 foreach (Expression arg in arg_list) {
930 assert_expr.add_argument (arg);
933 return assert_expr;
937 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
938 expect (TokenType.OPEN_PARENS);
939 var arg_list = parse_argument_list ();
940 expect (TokenType.CLOSE_PARENS);
942 var init_list = parse_object_initializer ();
944 if (init_list.size > 0 && inner is MemberAccess) {
945 // struct creation expression
946 var member = (MemberAccess) inner;
947 member.creation_member = true;
949 var expr = new ObjectCreationExpression (member, get_src (begin));
950 expr.struct_creation = true;
951 foreach (Expression arg in arg_list) {
952 expr.add_argument (arg);
954 foreach (MemberInitializer initializer in init_list) {
955 expr.add_member_initializer (initializer);
957 return expr;
958 } else {
959 var expr = new MethodCall (inner, get_src (begin));
960 foreach (Expression arg in arg_list) {
961 expr.add_argument (arg);
963 return expr;
967 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
968 expect (TokenType.OPEN_BRACKET);
969 var index_list = parse_expression_list ();
970 Expression? stop = null;
971 if (index_list.size == 1 && accept (TokenType.COLON)) {
972 // slice expression
973 stop = parse_expression ();
975 expect (TokenType.CLOSE_BRACKET);
977 if (stop == null) {
978 var expr = new ElementAccess (inner, get_src (begin));
979 foreach (Expression index in index_list) {
980 expr.append_index (index);
982 return expr;
983 } else {
984 return new SliceExpression (inner, index_list[0], stop, get_src (begin));
988 List<Expression> parse_expression_list () throws ParseError {
989 var list = new ArrayList<Expression> ();
990 do {
991 list.add (parse_expression ());
992 } while (accept (TokenType.COMMA));
993 return list;
996 Expression parse_this_access () throws ParseError {
997 var begin = get_location ();
998 expect (TokenType.THIS);
999 return new MemberAccess (null, "this", get_src (begin));
1002 Expression parse_base_access () throws ParseError {
1003 var begin = get_location ();
1004 expect (TokenType.SUPER);
1005 return new BaseAccess (get_src (begin));
1008 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
1009 expect (TokenType.OP_INC);
1010 return new PostfixExpression (inner, true, get_src (begin));
1013 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
1014 expect (TokenType.OP_DEC);
1015 return new PostfixExpression (inner, false, get_src (begin));
1018 Expression parse_object_or_array_creation_expression () throws ParseError {
1019 var begin = get_location ();
1020 expect (TokenType.NEW);
1022 if (accept (TokenType.ARRAY)) {
1023 expect (TokenType.OF);
1024 var mtype = parse_type (true, false);
1025 var expr = parse_array_creation_expression (begin, mtype);
1026 return expr;
1029 if (accept (TokenType.LIST)) {
1030 expect (TokenType.OF);
1031 var mtype = parse_type (true, false);
1032 var expr = parse_list_creation_expression (begin, mtype);
1033 return expr;
1036 if (accept (TokenType.DICT)) {
1037 expect (TokenType.OF);
1038 var mtype1 = parse_type (true, false);
1039 expect (TokenType.COMMA);
1040 var mtype2 = parse_type (true, false);
1041 var expr = parse_dict_creation_expression (begin, mtype1, mtype2);
1042 return expr;
1046 var member = parse_member_name ();
1047 var expr = parse_object_creation_expression (begin, member);
1048 return expr;
1052 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
1053 member.creation_member = true;
1054 List<Expression> arg_list;
1055 if (accept (TokenType.OPEN_PARENS)) {
1056 arg_list = parse_argument_list ();
1057 expect (TokenType.CLOSE_PARENS);
1058 } else {
1059 arg_list = new ArrayList<Expression> ();
1062 var init_list = parse_object_initializer ();
1064 var expr = new ObjectCreationExpression (member, get_src (begin));
1065 foreach (Expression arg in arg_list) {
1066 expr.add_argument (arg);
1068 foreach (MemberInitializer initializer in init_list) {
1069 expr.add_member_initializer (initializer);
1071 return expr;
1074 Expression parse_array_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1075 bool size_specified = false;
1076 List<Expression> size_specifier_list = null;
1077 bool first = true;
1078 DataType etype = element_type.copy ();
1080 var has_bracket = accept (TokenType.OPEN_BRACKET);
1082 do {
1083 if (!first) {
1084 // array of arrays: new T[][42]
1086 if (size_specified) {
1087 throw new ParseError.SYNTAX ("size of inner arrays must not be specified in array creation expression");
1090 etype = new ArrayType (etype, size_specifier_list.size, etype.source_reference);
1091 } else {
1092 first = false;
1095 size_specifier_list = new ArrayList<Expression> ();
1096 do {
1097 Expression size = null;
1098 if (has_bracket && current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
1099 size = parse_expression ();
1100 size_specified = true;
1102 size_specifier_list.add (size);
1103 } while (accept (TokenType.COMMA));
1105 if (has_bracket) {
1106 expect (TokenType.CLOSE_BRACKET);
1108 } while (accept (TokenType.OPEN_BRACKET));
1110 InitializerList initializer = null;
1111 if (accept (TokenType.ASSIGN)) {
1112 initializer = parse_initializer ();
1115 var expr = new ArrayCreationExpression (etype, size_specifier_list.size, initializer, get_src (begin));
1116 if (size_specified) {
1117 foreach (Expression size in size_specifier_list) {
1118 expr.append_size (size);
1121 return expr;
1125 Expression parse_list_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1127 MemberAccess list_member = null, parent_member = null;
1129 parent_member = new MemberAccess (null, "Gee", get_src (begin));
1130 list_member = new MemberAccess (parent_member, "ArrayList", get_src (begin));
1131 list_member.add_type_argument (element_type);
1133 list_member.creation_member = true;
1135 var expr = new ObjectCreationExpression (list_member, get_src (begin));
1136 return expr;
1139 Expression parse_dict_creation_expression (SourceLocation begin, DataType key_type, DataType value_type) throws ParseError {
1141 MemberAccess dict_member = null, parent_member = null;
1143 parent_member = new MemberAccess (null, "Gee", get_src (begin));
1144 dict_member = new MemberAccess (parent_member, "HashMap", get_src (begin));
1145 dict_member.add_type_argument (key_type);
1146 dict_member.add_type_argument (value_type);
1148 dict_member.creation_member = true;
1150 var expr = new ObjectCreationExpression (dict_member, get_src (begin));
1152 return expr;
1156 List<MemberInitializer> parse_object_initializer () throws ParseError {
1157 var list = new ArrayList<MemberInitializer> ();
1158 if (accept (TokenType.OPEN_BRACE)) {
1159 do {
1160 list.add (parse_member_initializer ());
1161 } while (accept (TokenType.COMMA));
1162 expect (TokenType.CLOSE_BRACE);
1164 return list;
1167 MemberInitializer parse_member_initializer () throws ParseError {
1168 var begin = get_location ();
1169 string id = parse_identifier ();
1170 expect (TokenType.ASSIGN);
1171 var expr = parse_expression ();
1173 return new MemberInitializer (id, expr, get_src (begin));
1176 Expression parse_yield_expression () throws ParseError {
1177 expect (TokenType.YIELD);
1179 var expr = parse_expression ();
1181 var call = expr as MethodCall;
1182 var object_creation = expr as ObjectCreationExpression;
1183 if (call == null && object_creation == null) {
1184 Report.error (expr.source_reference, "syntax error, expected method call");
1185 throw new ParseError.SYNTAX ("expected method call");
1188 if (call != null) {
1189 call.is_yield_expression = true;
1190 } else if (object_creation != null) {
1191 object_creation.is_yield_expression = true;
1194 return expr;
1197 Expression parse_sizeof_expression () throws ParseError {
1198 var begin = get_location ();
1199 expect (TokenType.SIZEOF);
1200 expect (TokenType.OPEN_PARENS);
1201 var type = parse_type (true, false);
1202 expect (TokenType.CLOSE_PARENS);
1204 return new SizeofExpression (type, get_src (begin));
1207 Expression parse_typeof_expression () throws ParseError {
1208 var begin = get_location ();
1209 expect (TokenType.TYPEOF);
1210 expect (TokenType.OPEN_PARENS);
1211 var type = parse_type (true, false);
1212 expect (TokenType.CLOSE_PARENS);
1214 return new TypeofExpression (type, get_src (begin));
1217 UnaryOperator get_unary_operator (TokenType token_type) {
1218 switch (token_type) {
1219 case TokenType.PLUS: return UnaryOperator.PLUS;
1220 case TokenType.MINUS: return UnaryOperator.MINUS;
1221 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
1222 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
1223 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
1224 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
1225 default: return UnaryOperator.NONE;
1229 Expression parse_unary_expression () throws ParseError {
1230 var begin = get_location ();
1231 var operator = get_unary_operator (current ());
1232 if (operator != UnaryOperator.NONE) {
1233 next ();
1234 var op = parse_unary_expression ();
1235 return new UnaryExpression (operator, op, get_src (begin));
1237 switch (current ()) {
1238 case TokenType.HASH:
1239 if (!context.deprecated) {
1240 Report.warning (get_src (begin), "deprecated syntax, use `(owned)` cast");
1242 next ();
1243 var op = parse_unary_expression ();
1244 return new ReferenceTransferExpression (op, get_src (begin));
1245 case TokenType.OPEN_PARENS:
1246 next ();
1247 switch (current ()) {
1248 case TokenType.OWNED:
1249 // (owned) foo
1250 next ();
1251 if (accept (TokenType.CLOSE_PARENS)) {
1252 var op = parse_unary_expression ();
1253 return new ReferenceTransferExpression (op, get_src (begin));
1255 break;
1256 case TokenType.VOID:
1257 case TokenType.DYNAMIC:
1258 case TokenType.IDENTIFIER:
1259 case TokenType.ARRAY:
1260 case TokenType.LIST:
1261 case TokenType.DICT:
1262 var type = parse_type (true, false);
1263 if (accept (TokenType.CLOSE_PARENS)) {
1264 // check follower to decide whether to create cast expression
1265 switch (current ()) {
1266 case TokenType.OP_NEG:
1267 case TokenType.TILDE:
1268 case TokenType.OPEN_PARENS:
1269 case TokenType.TRUE:
1270 case TokenType.FALSE:
1271 case TokenType.INTEGER_LITERAL:
1272 case TokenType.REAL_LITERAL:
1273 case TokenType.CHARACTER_LITERAL:
1274 case TokenType.REGEX_LITERAL:
1275 case TokenType.STRING_LITERAL:
1276 case TokenType.TEMPLATE_STRING_LITERAL:
1277 case TokenType.VERBATIM_STRING_LITERAL:
1278 case TokenType.NULL:
1279 case TokenType.THIS:
1280 case TokenType.SUPER:
1281 case TokenType.NEW:
1282 case TokenType.SIZEOF:
1283 case TokenType.TYPEOF:
1284 case TokenType.IDENTIFIER:
1285 case TokenType.PARAMS:
1286 case TokenType.YIELD:
1287 var inner = parse_unary_expression ();
1288 return new CastExpression (inner, type, get_src (begin));
1289 default:
1290 break;
1293 break;
1294 case TokenType.OP_NEG:
1295 next ();
1296 if (accept (TokenType.CLOSE_PARENS)) {
1297 // (!) non-null cast
1298 var inner = parse_unary_expression ();
1299 return new CastExpression.non_null (inner, get_src (begin));
1301 break;
1303 default:
1304 break;
1306 // no cast expression
1307 rollback (begin);
1308 break;
1309 case TokenType.STAR:
1310 next ();
1311 var op = parse_unary_expression ();
1312 return new PointerIndirection (op, get_src (begin));
1313 case TokenType.BITWISE_AND:
1314 next ();
1315 var op = parse_unary_expression ();
1316 return new AddressofExpression (op, get_src (begin));
1317 default:
1318 break;
1321 var expr = parse_primary_expression ();
1322 return expr;
1325 BinaryOperator get_binary_operator (TokenType token_type) {
1326 switch (token_type) {
1327 case TokenType.STAR: return BinaryOperator.MUL;
1328 case TokenType.DIV: return BinaryOperator.DIV;
1329 case TokenType.PERCENT: return BinaryOperator.MOD;
1330 case TokenType.PLUS: return BinaryOperator.PLUS;
1331 case TokenType.MINUS: return BinaryOperator.MINUS;
1332 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
1333 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
1334 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
1335 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
1336 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
1337 case TokenType.IS:
1338 next();
1339 if (current () == TokenType.OP_NEG) {
1340 prev ();
1341 return BinaryOperator.INEQUALITY;
1343 prev ();
1344 return BinaryOperator.EQUALITY;
1345 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
1346 default: return BinaryOperator.NONE;
1350 Expression parse_multiplicative_expression () throws ParseError {
1351 var begin = get_location ();
1352 var left = parse_unary_expression ();
1353 bool found = true;
1354 while (found) {
1355 var operator = get_binary_operator (current ());
1356 switch (operator) {
1357 case BinaryOperator.MUL:
1358 case BinaryOperator.DIV:
1359 case BinaryOperator.MOD:
1360 next ();
1361 var right = parse_unary_expression ();
1362 left = new BinaryExpression (operator, left, right, get_src (begin));
1363 break;
1364 default:
1365 found = false;
1366 break;
1369 return left;
1372 Expression parse_additive_expression () throws ParseError {
1373 var begin = get_location ();
1374 var left = parse_multiplicative_expression ();
1375 bool found = true;
1376 while (found) {
1377 var operator = get_binary_operator (current ());
1378 switch (operator) {
1379 case BinaryOperator.PLUS:
1380 case BinaryOperator.MINUS:
1381 next ();
1382 var right = parse_multiplicative_expression ();
1383 left = new BinaryExpression (operator, left, right, get_src (begin));
1384 break;
1385 default:
1386 found = false;
1387 break;
1390 return left;
1393 Expression parse_shift_expression () throws ParseError {
1394 var begin = get_location ();
1395 var left = parse_additive_expression ();
1396 bool found = true;
1397 while (found) {
1398 switch (current ()) {
1399 case TokenType.OP_SHIFT_LEFT:
1400 next ();
1401 var right = parse_additive_expression ();
1402 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1403 break;
1404 // don't use OP_SHIFT_RIGHT to support >> for nested generics
1405 case TokenType.OP_GT:
1406 char* first_gt_pos = tokens[index].begin.pos;
1407 next ();
1408 // only accept >> when there is no space between the two > signs
1409 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1410 next ();
1411 var right = parse_additive_expression ();
1412 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1413 } else {
1414 prev ();
1415 found = false;
1417 break;
1418 default:
1419 found = false;
1420 break;
1423 return left;
1426 Expression parse_relational_expression () throws ParseError {
1427 var begin = get_location ();
1428 var left = parse_shift_expression ();
1429 bool found = true;
1430 while (found) {
1431 var operator = get_binary_operator (current ());
1432 switch (operator) {
1433 case BinaryOperator.LESS_THAN:
1434 case BinaryOperator.LESS_THAN_OR_EQUAL:
1435 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1436 next ();
1437 var right = parse_shift_expression ();
1438 left = new BinaryExpression (operator, left, right, get_src (begin));
1439 break;
1440 case BinaryOperator.GREATER_THAN:
1441 next ();
1442 // ignore >> and >>= (two tokens due to generics)
1443 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1444 var right = parse_shift_expression ();
1445 left = new BinaryExpression (operator, left, right, get_src (begin));
1446 } else {
1447 prev ();
1448 found = false;
1450 break;
1451 default:
1452 switch (current ()) {
1453 case TokenType.ISA:
1454 next ();
1455 var type = parse_type (true, false);
1456 left = new TypeCheck (left, type, get_src (begin));
1457 break;
1458 case TokenType.AS:
1459 next ();
1460 var type = parse_type (true, false);
1461 left = new CastExpression.silent (left, type, get_src (begin));
1462 break;
1463 default:
1464 found = false;
1465 break;
1467 break;
1470 return left;
1473 Expression parse_equality_expression () throws ParseError {
1474 var begin = get_location ();
1475 var left = parse_relational_expression ();
1476 bool found = true;
1477 while (found) {
1478 var operator = get_binary_operator (current ());
1479 switch (operator) {
1480 case BinaryOperator.INEQUALITY:
1481 case BinaryOperator.EQUALITY:
1482 if ((operator == BinaryOperator.INEQUALITY) && (current () == TokenType.IS)) {
1483 next ();
1485 next ();
1486 var right = parse_relational_expression ();
1487 left = new BinaryExpression (operator, left, right, get_src (begin));
1488 break;
1489 default:
1490 found = false;
1491 break;
1494 return left;
1497 Expression parse_and_expression () throws ParseError {
1498 var begin = get_location ();
1499 var left = parse_equality_expression ();
1500 while (accept (TokenType.BITWISE_AND)) {
1501 var right = parse_equality_expression ();
1502 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1504 return left;
1507 Expression parse_exclusive_or_expression () throws ParseError {
1508 var begin = get_location ();
1509 var left = parse_and_expression ();
1510 while (accept (TokenType.CARRET)) {
1511 var right = parse_and_expression ();
1512 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1514 return left;
1517 Expression parse_inclusive_or_expression () throws ParseError {
1518 var begin = get_location ();
1519 var left = parse_exclusive_or_expression ();
1520 while (accept (TokenType.BITWISE_OR)) {
1521 var right = parse_exclusive_or_expression ();
1522 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1524 return left;
1527 Expression parse_in_expression () throws ParseError {
1528 var begin = get_location ();
1529 var left = parse_inclusive_or_expression ();
1530 while (accept (TokenType.IN)) {
1531 var right = parse_inclusive_or_expression ();
1532 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1534 return left;
1537 Expression parse_conditional_and_expression () throws ParseError {
1538 var begin = get_location ();
1539 var left = parse_in_expression ();
1540 while (accept (TokenType.OP_AND)) {
1541 var right = parse_in_expression ();
1542 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1544 return left;
1547 Expression parse_conditional_or_expression () throws ParseError {
1548 var begin = get_location ();
1549 var left = parse_conditional_and_expression ();
1550 while (accept (TokenType.OP_OR)) {
1551 var right = parse_conditional_and_expression ();
1552 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1554 return left;
1557 Expression parse_conditional_expression () throws ParseError {
1558 var begin = get_location ();
1559 var condition = parse_conditional_or_expression ();
1560 if (accept (TokenType.INTERR)) {
1561 var true_expr = parse_expression ();
1562 expect (TokenType.COLON);
1563 var false_expr = parse_expression ();
1564 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1565 } else {
1566 return condition;
1570 Parameter parse_lambda_parameter () throws ParseError {
1571 var begin = get_location ();
1572 var direction = ParameterDirection.IN;
1573 if (accept (TokenType.OUT)) {
1574 direction = ParameterDirection.OUT;
1575 } else if (accept (TokenType.REF)) {
1576 direction = ParameterDirection.REF;
1579 string id = parse_identifier ();
1581 var param = new Parameter (id, null, get_src (begin));
1582 param.direction = direction;
1583 return param;
1586 Expression parse_lambda_expression () throws ParseError {
1587 var begin = get_location ();
1588 List<Parameter> params = new ArrayList<Parameter> ();
1590 expect (TokenType.DEF);
1592 if (accept (TokenType.OPEN_PARENS)) {
1593 if (current () != TokenType.CLOSE_PARENS) {
1594 do {
1595 params.add (parse_lambda_parameter ());
1596 } while (accept (TokenType.COMMA));
1598 expect (TokenType.CLOSE_PARENS);
1599 } else {
1600 params.add (parse_lambda_parameter ());
1603 LambdaExpression lambda;
1605 if (accept_block ()) {
1606 var block = parse_block ();
1607 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1608 } else {
1609 var expr = parse_expression ();
1610 lambda = new LambdaExpression (expr, get_src (begin));
1611 expect_terminator ();
1616 foreach (var param in params) {
1617 lambda.add_parameter (param);
1619 return lambda;
1622 AssignmentOperator get_assignment_operator (TokenType token_type) {
1623 switch (token_type) {
1624 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1625 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1626 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1627 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1628 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1629 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1630 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1631 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1632 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1633 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1634 default: return AssignmentOperator.NONE;
1638 Expression parse_expression_with_terminator () throws ParseError {
1639 var expr = parse_expression ();
1640 if (current_expr_is_lambda) {
1641 current_expr_is_lambda = false;
1642 } else {
1643 expect_terminator ();
1645 return expr;
1648 Expression parse_expression () throws ParseError {
1649 if (current () == TokenType.DEF) {
1650 var lambda = parse_lambda_expression ();
1651 current_expr_is_lambda = true;
1652 return lambda;
1653 } else {
1654 current_expr_is_lambda = false;
1657 var begin = get_location ();
1658 Expression expr = parse_conditional_expression ();
1660 while (true) {
1661 var operator = get_assignment_operator (current ());
1662 if (operator != AssignmentOperator.NONE) {
1663 next ();
1664 var rhs = parse_expression ();
1665 expr = new Assignment (expr, rhs, operator, get_src (begin));
1666 } else if (current () == TokenType.OP_GT) { // >>=
1667 char* first_gt_pos = tokens[index].begin.pos;
1668 next ();
1669 // only accept >>= when there is no space between the two > signs
1670 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1671 next ();
1672 var rhs = parse_expression ();
1673 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1674 } else {
1675 prev ();
1676 break;
1678 } else {
1679 break;
1683 return expr;
1687 Statement get_for_statement_type () throws ParseError {
1689 var begin = get_location ();
1690 bool is_foreach = false;
1692 while (current () != TokenType.EOL && current () != TokenType.DO) {
1693 next ();
1694 if (accept (TokenType.IN)) {
1695 is_foreach = true;
1696 break;
1700 rollback (begin);
1702 if (is_foreach) {
1703 return parse_foreach_statement ();
1704 } else {
1705 return parse_for_statement ();
1710 void parse_statements (Block block) throws ParseError {
1711 while (current () != TokenType.DEDENT
1712 && current () != TokenType.WHEN
1713 && current () != TokenType.DEFAULT) {
1714 try {
1715 Statement stmt = null;
1716 bool is_decl = false;
1717 comment = scanner.pop_comment ();
1718 switch (current ()) {
1720 /* skip over requires and ensures as we handled them in method declaration */
1721 case TokenType.REQUIRES:
1722 case TokenType.ENSURES:
1723 var begin = get_location ();
1724 next ();
1726 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
1727 while (current () != TokenType.DEDENT) {
1728 next();
1731 expect (TokenType.DEDENT);
1732 } else {
1733 while (current () != TokenType.EOL) {
1734 next();
1737 expect (TokenType.EOL);
1740 stmt = new EmptyStatement (get_src (begin));
1741 break;
1744 case TokenType.INDENT:
1745 stmt = parse_block ();
1746 break;
1747 case TokenType.SEMICOLON:
1748 case TokenType.PASS:
1749 stmt = parse_empty_statement ();
1750 break;
1751 case TokenType.PRINT:
1752 case TokenType.ASSERT:
1753 stmt = parse_expression_statement ();
1754 break;
1755 case TokenType.IF:
1756 stmt = parse_if_statement ();
1757 break;
1758 case TokenType.CASE:
1759 stmt = parse_switch_statement ();
1760 break;
1761 case TokenType.WHILE:
1762 stmt = parse_while_statement ();
1763 break;
1764 case TokenType.DO:
1765 stmt = parse_do_statement ();
1766 break;
1767 case TokenType.FOR:
1768 stmt = get_for_statement_type ();
1769 break;
1770 case TokenType.BREAK:
1771 stmt = parse_break_statement ();
1772 break;
1773 case TokenType.CONTINUE:
1774 stmt = parse_continue_statement ();
1775 break;
1776 case TokenType.RETURN:
1777 stmt = parse_return_statement ();
1778 break;
1779 case TokenType.RAISE:
1780 stmt = parse_throw_statement ();
1781 break;
1782 case TokenType.TRY:
1783 stmt = parse_try_statement ();
1784 break;
1785 case TokenType.LOCK:
1786 stmt = parse_lock_statement ();
1787 break;
1788 case TokenType.DELETE:
1789 stmt = parse_delete_statement ();
1790 break;
1791 case TokenType.VAR:
1792 is_decl = true;
1793 parse_type_inference_declaration (block);
1794 break;
1795 case TokenType.YIELD:
1796 stmt = parse_yield_statement ();
1797 break;
1799 case TokenType.OP_INC:
1800 case TokenType.OP_DEC:
1801 case TokenType.SUPER:
1802 case TokenType.THIS:
1803 case TokenType.OPEN_PARENS:
1804 case TokenType.STAR:
1805 case TokenType.NEW:
1806 stmt = parse_expression_statement ();
1807 break;
1808 default:
1809 bool is_expr = is_expression ();
1810 if (is_expr) {
1811 stmt = parse_expression_statement ();
1812 } else {
1813 is_decl = true;
1814 parse_local_variable_declarations (block);
1816 break;
1819 if (!is_decl) {
1820 block.add_statement (stmt);
1822 } catch (ParseError e) {
1823 report_parse_error (e);
1824 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1825 // beginning of next declaration or end of file reached
1826 // return what we have so far
1827 break;
1833 bool is_expression () throws ParseError {
1834 var begin = get_location ();
1836 // decide between declaration and expression statement
1837 skip_type ();
1838 switch (current ()) {
1839 // invocation expression
1840 case TokenType.OPEN_PARENS:
1841 // postfix increment
1842 case TokenType.OP_INC:
1843 // postfix decrement
1844 case TokenType.OP_DEC:
1845 // assignments
1846 case TokenType.ASSIGN:
1847 case TokenType.ASSIGN_ADD:
1848 case TokenType.ASSIGN_BITWISE_AND:
1849 case TokenType.ASSIGN_BITWISE_OR:
1850 case TokenType.ASSIGN_BITWISE_XOR:
1851 case TokenType.ASSIGN_DIV:
1852 case TokenType.ASSIGN_MUL:
1853 case TokenType.ASSIGN_PERCENT:
1854 case TokenType.ASSIGN_SHIFT_LEFT:
1855 case TokenType.ASSIGN_SUB:
1856 case TokenType.OP_GT: // >>=
1857 // member access
1858 case TokenType.DOT:
1859 // pointer member access
1860 case TokenType.OP_PTR:
1861 rollback (begin);
1862 return true;
1863 default:
1864 rollback (begin);
1865 return false;
1869 Block parse_embedded_statement () throws ParseError {
1870 if (current () == TokenType.INDENT) {
1871 var block = parse_block ();
1872 return block;
1875 comment = scanner.pop_comment ();
1877 var block = new Block (get_src (get_location ()));
1878 block.add_statement (parse_embedded_statement_without_block ());
1879 return block;
1883 Statement parse_embedded_statement_without_block () throws ParseError {
1884 switch (current ()) {
1885 case TokenType.PASS:
1886 case TokenType.SEMICOLON: return parse_empty_statement ();
1887 case TokenType.IF: return parse_if_statement ();
1888 case TokenType.CASE: return parse_switch_statement ();
1889 case TokenType.WHILE: return parse_while_statement ();
1890 case TokenType.DO: return parse_do_statement ();
1891 case TokenType.FOR: return get_for_statement_type ();
1892 case TokenType.BREAK: return parse_break_statement ();
1893 case TokenType.CONTINUE: return parse_continue_statement ();
1894 case TokenType.RETURN: return parse_return_statement ();
1895 case TokenType.YIELD: return parse_yield_statement ();
1896 case TokenType.RAISE: return parse_throw_statement ();
1897 case TokenType.TRY: return parse_try_statement ();
1898 case TokenType.LOCK: return parse_lock_statement ();
1899 case TokenType.DELETE: return parse_delete_statement ();
1900 case TokenType.VAR:
1901 case TokenType.CONST:
1902 throw new ParseError.SYNTAX ("embedded statement cannot be declaration ");
1903 case TokenType.OP_INC:
1904 case TokenType.OP_DEC:
1905 case TokenType.SUPER:
1906 case TokenType.THIS:
1907 case TokenType.OPEN_PARENS:
1908 case TokenType.STAR:
1909 case TokenType.NEW:
1910 return parse_expression_statement ();
1911 default:
1912 if (is_expression ()) {
1913 return parse_expression_statement ();
1914 } else {
1915 throw new ParseError.SYNTAX ("embedded statement cannot be declaration");
1920 Block parse_block () throws ParseError {
1921 var begin = get_location ();
1922 expect (TokenType.INDENT);
1923 var block = new Block (get_src (begin));
1924 parse_statements (block);
1925 if (!accept (TokenType.DEDENT)) {
1926 // only report error if it's not a secondary error
1927 if (context.report.get_errors () == 0) {
1928 Report.error (get_current_src (), "tab indentation is incorrect");
1932 block.source_reference.end = get_current_src ().end;
1934 return block;
1937 Statement parse_empty_statement () throws ParseError {
1938 var begin = get_location ();
1940 accept (TokenType.PASS);
1941 accept (TokenType.SEMICOLON);
1942 expect_terminator ();
1944 return new EmptyStatement (get_src (begin));
1947 void parse_type_inference_declaration (Block block) throws ParseError {
1948 expect (TokenType.VAR);
1949 bool block_var = false;
1950 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) { block_var = true; }
1951 do {
1952 var s = parse_identifier ();
1953 var local = parse_local_variable (null, s, true);
1954 block.add_statement (new DeclarationStatement (local, local.source_reference));
1956 while ((block_var) && (current () != TokenType.DEDENT));
1957 if ( block_var ) { expect (TokenType.DEDENT); }
1960 void parse_local_variable_declarations (Block block) throws ParseError {
1961 var id_list = new ArrayList<string> ();
1962 id_list.add (parse_identifier ());
1963 // Allow multiple declarations
1964 while (accept (TokenType.COMMA)) {
1965 id_list.add (parse_identifier ());
1968 expect (TokenType.COLON);
1969 DataType variable_type = parse_type (true, true);
1970 var type = parse_inline_array_type (variable_type);
1972 var iterator = id_list.iterator();
1973 iterator.next();
1974 bool expect_terminator = false;
1975 while (!expect_terminator) {
1976 string id = iterator.get();
1977 DataType type_copy = null;
1978 if (type != null) {
1979 type_copy = type.copy ();
1981 if (!iterator.next()) {
1982 expect_terminator = true;
1984 var local = parse_local_variable (type_copy, id, expect_terminator);
1985 block.add_statement (new DeclarationStatement (local, local.source_reference));
1989 LocalVariable parse_local_variable (DataType? variable_type, string id, bool expect_terminator = false) throws ParseError {
1990 var begin = get_location ();
1991 Expression initializer = null;
1992 if (accept (TokenType.ASSIGN)) {
1993 if (expect_terminator) {
1994 initializer = parse_expression_with_terminator ();
1995 } else {
1996 initializer = parse_expression ();
1998 } else if (expect_terminator) {
1999 this.expect_terminator();
2001 return new LocalVariable (variable_type, id, initializer, get_src (begin));
2004 Statement parse_expression_statement () throws ParseError {
2005 var begin = get_location ();
2006 var expr = parse_expression_with_terminator ();
2007 return new ExpressionStatement (expr, get_src (begin));
2010 Expression parse_statement_expression () throws ParseError {
2011 // invocation expression, assignment,
2012 // or pre/post increment/decrement expression
2013 var expr = parse_expression ();
2014 return expr;
2017 Statement parse_if_statement () throws ParseError {
2018 var begin = get_location ();
2020 expect (TokenType.IF);
2022 var condition = parse_expression ();
2024 if (!accept (TokenType.DO)) {
2025 expect (TokenType.EOL);
2026 } else {
2027 accept (TokenType.EOL);
2030 var src = get_src (begin);
2031 var true_stmt = parse_embedded_statement ();
2032 Block false_stmt = null;
2033 if (accept (TokenType.ELSE)) {
2034 // allow `else if' on the same line without `do'
2035 if (!accept (TokenType.DO) && current () != TokenType.IF) {
2036 expect (TokenType.EOL);
2037 } else {
2038 accept (TokenType.EOL);
2041 false_stmt = parse_embedded_statement ();
2043 return new IfStatement (condition, true_stmt, false_stmt, src);
2046 Statement parse_switch_statement () throws ParseError {
2047 var begin = get_location ();
2048 expect (TokenType.CASE);
2049 var condition = parse_expression ();
2051 expect (TokenType.EOL);
2053 var stmt = new SwitchStatement (condition, get_src (begin));
2054 expect (TokenType.INDENT);
2055 while (current () != TokenType.DEDENT) {
2056 var section = new SwitchSection (get_src (begin));
2058 if (accept (TokenType.WHEN)) {
2059 do {
2060 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
2062 while (accept (TokenType.COMMA));
2063 } else {
2064 expect (TokenType.DEFAULT);
2065 section.add_label (new SwitchLabel.with_default (get_src (begin)));
2068 if (!accept (TokenType.EOL)) {
2069 expect (TokenType.DO);
2072 parse_statements (section);
2074 /* add break statement for each block */
2075 var break_stmt = new BreakStatement (get_src (begin));
2076 section.add_statement (break_stmt);
2078 stmt.add_section (section);
2080 expect (TokenType.DEDENT);
2081 return stmt;
2084 Statement parse_while_statement () throws ParseError {
2085 var begin = get_location ();
2086 expect (TokenType.WHILE);
2087 var condition = parse_expression ();
2089 if (!accept (TokenType.DO)) {
2090 expect (TokenType.EOL);
2091 } else {
2092 accept (TokenType.EOL);
2095 var body = parse_embedded_statement ();
2096 return new WhileStatement (condition, body, get_src (begin));
2099 Statement parse_do_statement () throws ParseError {
2100 var begin = get_location ();
2101 expect (TokenType.DO);
2102 expect (TokenType.EOL);
2103 var body = parse_embedded_statement ();
2104 expect (TokenType.WHILE);
2106 var condition = parse_expression ();
2108 expect_terminator ();
2110 return new DoStatement (body, condition, get_src (begin));
2114 Statement parse_for_statement () throws ParseError {
2115 var begin = get_location ();
2116 Block block = null;
2117 Expression initializer = null;
2118 Expression condition = null;
2119 Expression iterator = null;
2120 bool is_expr;
2121 string id;
2123 expect (TokenType.FOR);
2125 switch (current ()) {
2126 case TokenType.VAR:
2127 is_expr = false;
2128 break;
2129 default:
2131 bool local_is_expr = is_expression ();
2132 is_expr = local_is_expr;
2133 break;
2136 if (is_expr) {
2137 var expr_begin = get_location ();
2138 id = parse_identifier ();
2139 rollback (expr_begin);
2140 initializer = parse_statement_expression ();
2141 } else {
2142 block = new Block (get_src (begin));
2143 DataType variable_type;
2144 if (accept (TokenType.VAR)) {
2145 variable_type = null;
2146 id = parse_identifier ();
2147 } else {
2148 id = parse_identifier ();
2149 expect (TokenType.COLON);
2150 variable_type = parse_type (true, true);
2153 DataType type_copy = null;
2154 if (variable_type != null) {
2155 type_copy = variable_type.copy ();
2157 var local = parse_local_variable (type_copy, id);
2159 block.add_statement (new DeclarationStatement (local, local.source_reference));
2164 if (accept (TokenType.TO)) {
2165 /* create expression for condition and incrementing iterator */
2166 var to_begin = get_location ();
2167 var to_src = get_src (to_begin);
2168 var left = new MemberAccess (null, id, to_src);
2169 var right = parse_primary_expression ();
2171 condition = new BinaryExpression (BinaryOperator.LESS_THAN_OR_EQUAL, left, right, to_src);
2173 iterator = new PostfixExpression (left, true, to_src);
2174 } else {
2175 expect (TokenType.DOWNTO);
2176 var downto_begin = get_location ();
2177 var downto_src = get_src (downto_begin);
2178 /* create expression for condition and decrementing iterator */
2179 var left = new MemberAccess (null, id, downto_src);
2180 var right = parse_primary_expression ();
2182 condition = new BinaryExpression (BinaryOperator.GREATER_THAN_OR_EQUAL, left, right, downto_src);
2184 iterator = new PostfixExpression (left, false, downto_src);
2187 if (!accept (TokenType.EOL)) {
2188 expect (TokenType.DO);
2191 var src = get_src (begin);
2192 var body = parse_embedded_statement ();
2193 var stmt = new ForStatement (condition, body, src);
2195 if (initializer != null) stmt.add_initializer (initializer);
2197 stmt.add_iterator (iterator);
2200 if (block != null) {
2201 block.add_statement (stmt);
2202 return block;
2203 } else {
2204 return stmt;
2208 Statement parse_foreach_statement () throws ParseError {
2209 var begin = get_location ();
2210 DataType type = null;
2211 string id = null;
2213 expect (TokenType.FOR);
2215 if (accept (TokenType.VAR)) {
2216 id = parse_identifier ();
2217 } else {
2218 id = parse_identifier ();
2219 if (accept (TokenType.COLON)) {
2220 type = parse_type (true, true);
2224 expect (TokenType.IN);
2225 var collection = parse_expression ();
2226 if (!accept (TokenType.EOL)) {
2227 expect (TokenType.DO);
2229 var src = get_src (begin);
2230 var body = parse_embedded_statement ();
2231 return new ForeachStatement (type, id, collection, body, src);
2234 Statement parse_break_statement () throws ParseError {
2235 var begin = get_location ();
2236 expect (TokenType.BREAK);
2237 expect_terminator ();
2238 return new BreakStatement (get_src (begin));
2241 Statement parse_continue_statement () throws ParseError {
2242 var begin = get_location ();
2243 expect (TokenType.CONTINUE);
2244 expect_terminator ();
2245 return new ContinueStatement (get_src (begin));
2248 Statement parse_return_statement () throws ParseError {
2249 var begin = get_location ();
2250 expect (TokenType.RETURN);
2251 Expression expr = null;
2252 if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) {
2253 expr = parse_expression_with_terminator ();
2254 } else {
2255 expect_terminator ();
2257 return new ReturnStatement (expr, get_src (begin));
2260 Statement parse_yield_statement () throws ParseError {
2261 var begin = get_location ();
2262 expect (TokenType.YIELD);
2263 if (current () != TokenType.SEMICOLON && current () != TokenType.EOL && current () != TokenType.RETURN) {
2264 prev ();
2265 return parse_expression_statement ();
2267 Expression expr = null;
2268 if (accept (TokenType.RETURN)) {
2269 expr = parse_expression ();
2271 expect_terminator ();
2272 return new YieldStatement (expr, get_src (begin));
2275 Statement parse_throw_statement () throws ParseError {
2276 var begin = get_location ();
2277 expect (TokenType.RAISE);
2278 var expr = parse_expression ();
2279 expect_terminator ();
2280 return new ThrowStatement (expr, get_src (begin));
2283 Statement parse_try_statement () throws ParseError {
2284 var begin = get_location ();
2285 expect (TokenType.TRY);
2286 expect (TokenType.EOL);
2287 var try_block = parse_block ();
2288 Block finally_clause = null;
2289 var catch_clauses = new ArrayList<CatchClause> ();
2290 if (current () == TokenType.EXCEPT) {
2291 parse_catch_clauses (catch_clauses);
2292 if (current () == TokenType.FINALLY) {
2293 finally_clause = parse_finally_clause ();
2295 } else {
2296 finally_clause = parse_finally_clause ();
2298 var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
2299 foreach (CatchClause clause in catch_clauses) {
2300 stmt.add_catch_clause (clause);
2302 return stmt;
2305 void parse_catch_clauses (List<CatchClause> catch_clauses) throws ParseError {
2306 while (accept (TokenType.EXCEPT)) {
2307 var begin = get_location ();
2308 DataType type = null;
2309 string id = null;
2310 if (!accept (TokenType.EOL)) {
2311 id = parse_identifier ();
2312 expect (TokenType.COLON);
2313 type = parse_type (true, true);
2314 expect (TokenType.EOL);
2317 var block = parse_block ();
2318 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
2322 Block parse_finally_clause () throws ParseError {
2323 expect (TokenType.FINALLY);
2324 accept_block ();
2325 var block = parse_block ();
2326 return block;
2329 Statement parse_lock_statement () throws ParseError {
2330 var begin = get_location ();
2331 expect (TokenType.LOCK);
2332 expect (TokenType.OPEN_PARENS);
2333 var expr = parse_expression ();
2334 expect (TokenType.CLOSE_PARENS);
2335 var stmt = parse_embedded_statement ();
2336 return new LockStatement (expr, stmt, get_src (begin));
2339 Statement parse_delete_statement () throws ParseError {
2340 var begin = get_location ();
2341 expect (TokenType.DELETE);
2342 var expr = parse_expression ();
2343 expect_terminator ();
2344 return new DeleteStatement (expr, get_src (begin));
2347 string parse_attribute_value () throws ParseError {
2348 switch (current ()) {
2349 case TokenType.NULL:
2350 case TokenType.TRUE:
2351 case TokenType.FALSE:
2352 case TokenType.INTEGER_LITERAL:
2353 case TokenType.REAL_LITERAL:
2354 case TokenType.STRING_LITERAL:
2355 next ();
2356 return get_last_string ();
2357 case TokenType.MINUS:
2358 next ();
2359 switch (current ()) {
2360 case TokenType.INTEGER_LITERAL:
2361 case TokenType.REAL_LITERAL:
2362 next ();
2363 return "-" + get_last_string ();
2364 default:
2365 throw new ParseError.SYNTAX ("expected number");
2367 default:
2368 throw new ParseError.SYNTAX ("expected literal");
2372 List<Attribute>? parse_attributes (bool parameter) throws ParseError {
2373 if (current () != TokenType.OPEN_BRACKET) {
2374 return null;
2376 var attrs = new ArrayList<Attribute> ();
2377 while (accept (TokenType.OPEN_BRACKET)) {
2378 do {
2379 var begin = get_location ();
2380 string id = parse_identifier ();
2381 var attr = new Attribute (id, get_src (begin));
2382 if (accept (TokenType.OPEN_PARENS)) {
2383 if (current () != TokenType.CLOSE_PARENS) {
2384 do {
2385 id = parse_identifier ();
2386 expect (TokenType.ASSIGN);
2387 attr.add_argument (id, parse_attribute_value ());
2388 } while (accept (TokenType.COMMA));
2390 expect (TokenType.CLOSE_PARENS);
2392 attrs.add (attr);
2393 } while (accept (TokenType.COMMA));
2394 expect (TokenType.CLOSE_BRACKET);
2396 if (!parameter)
2397 expect (TokenType.EOL);
2398 return attrs;
2401 void set_attributes (CodeNode node, List<Attribute>? attributes) {
2402 if (attributes != null) {
2403 foreach (Attribute attr in (List<Attribute>) attributes) {
2404 if (node.get_attribute (attr.name) != null) {
2405 Report.error (attr.source_reference, "duplicate attribute `%s`".printf (attr.name));
2407 node.attributes.append (attr);
2412 Symbol parse_declaration (bool is_root = false) throws ParseError {
2413 comment = scanner.pop_comment ();
2414 var attrs = parse_attributes (false);
2415 var begin = get_location ();
2417 switch (current ()) {
2418 case TokenType.CONST:
2419 return parse_constant_declaration (attrs);
2420 case TokenType.CONSTRUCT:
2421 return parse_creation_method_declaration (attrs);
2422 case TokenType.CLASS:
2423 return parse_class_declaration (attrs);
2424 case TokenType.INIT:
2425 if (is_root) {
2426 return parse_main_method_declaration (attrs);
2428 rollback (begin);
2429 return parse_constructor_declaration (attrs);
2430 case TokenType.DELEGATE:
2431 return parse_delegate_declaration (attrs);
2432 case TokenType.DEF:
2433 return parse_method_declaration (attrs);
2434 case TokenType.ENUM:
2435 return parse_enum_declaration (attrs);
2436 case TokenType.ERRORDOMAIN:
2437 return parse_errordomain_declaration (attrs);
2438 case TokenType.FINAL:
2439 return parse_destructor_declaration (attrs);
2440 case TokenType.INTERFACE:
2441 return parse_interface_declaration (attrs);
2442 case TokenType.NAMESPACE:
2443 return parse_namespace_declaration (attrs);
2444 case TokenType.PROP:
2445 return parse_property_declaration (attrs);
2446 case TokenType.EVENT:
2447 return parse_signal_declaration (attrs);
2448 case TokenType.STRUCT:
2449 return parse_struct_declaration (attrs);
2450 default:
2452 while (current () != TokenType.EOL && current () != TokenType.SEMICOLON && current () != TokenType.EOF) {
2453 if (current () == TokenType.COLON) {
2454 rollback (begin);
2455 return parse_field_declaration (attrs);
2456 } else {
2457 next ();
2460 rollback (begin);
2462 break;
2465 TokenType cur = current ();
2466 TokenType pre = tokens[index-1].type;
2468 throw new ParseError.SYNTAX ("expected declaration but got %s with previous %s", cur.to_string (), pre.to_string());
2471 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
2472 if (!root) {
2473 expect (TokenType.INDENT);
2475 while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2476 try {
2477 if (parent is Namespace) {
2478 parse_namespace_member ((Namespace) parent);
2479 } else if (parent is Class) {
2480 parse_class_member ((Class) parent);
2481 } else if (parent is Struct) {
2482 parse_struct_member ((Struct) parent);
2483 } else if (parent is Interface) {
2484 parse_interface_member ((Interface) parent);
2486 } catch (ParseError e) {
2487 report_parse_error (e);
2488 int r;
2489 do {
2490 r = recover ();
2491 if (r == RecoveryState.STATEMENT_BEGIN) {
2492 next ();
2493 } else {
2494 break;
2496 } while (true);
2497 if (r == RecoveryState.EOF) {
2498 return;
2502 if (!root) {
2503 if (!accept (TokenType.DEDENT)) {
2504 // only report error if it's not a secondary error
2505 if (context.report.get_errors () == 0) {
2506 Report.error (get_current_src (), "expected dedent");
2512 enum RecoveryState {
2513 EOF,
2514 DECLARATION_BEGIN,
2515 STATEMENT_BEGIN
2518 RecoveryState recover () {
2519 while (current () != TokenType.EOF) {
2520 switch (current ()) {
2521 case TokenType.CLASS:
2522 case TokenType.CONST:
2523 case TokenType.CONSTRUCT:
2524 case TokenType.INIT:
2525 case TokenType.DEF:
2526 case TokenType.DELEGATE:
2527 case TokenType.ENUM:
2528 case TokenType.ERRORDOMAIN:
2529 case TokenType.FINAL:
2530 case TokenType.INTERFACE:
2531 case TokenType.NAMESPACE:
2532 case TokenType.PROP:
2533 case TokenType.EVENT:
2534 case TokenType.STRUCT:
2535 return RecoveryState.DECLARATION_BEGIN;
2536 case TokenType.BREAK:
2537 case TokenType.CASE:
2538 case TokenType.CONTINUE:
2539 case TokenType.DELETE:
2540 case TokenType.DO:
2541 case TokenType.FOR:
2542 case TokenType.IF:
2543 case TokenType.LOCK:
2544 case TokenType.RETURN:
2545 case TokenType.RAISE:
2546 case TokenType.TRY:
2547 case TokenType.VAR:
2548 case TokenType.WHILE:
2549 case TokenType.YIELD:
2550 return RecoveryState.STATEMENT_BEGIN;
2551 default:
2552 next ();
2553 break;
2556 return RecoveryState.EOF;
2559 Namespace parse_namespace_declaration (List<Attribute>? attrs) throws ParseError {
2560 var begin = get_location ();
2561 expect (TokenType.NAMESPACE);
2562 var sym = parse_symbol_name ();
2563 var ns = new Namespace (sym.name, get_src (begin));
2564 if (comment != null) {
2565 ns.add_comment (comment);
2566 comment = null;
2568 set_attributes (ns, attrs);
2569 expect (TokenType.EOL);
2570 parse_declarations (ns);
2572 Namespace result = ns;
2573 while (sym.inner != null) {
2574 sym = sym.inner;
2575 ns = new Namespace (sym.name, result.source_reference);
2576 ns.add_namespace ((Namespace) result);
2577 result = ns;
2579 return result;
2582 void parse_namespace_member (Namespace ns) throws ParseError {
2584 var sym = parse_declaration ((ns == context.root));
2585 if (sym is Namespace) {
2586 ns.add_namespace ((Namespace) sym);
2587 } else if (sym is Class) {
2588 ns.add_class ((Class) sym);
2589 } else if (sym is Interface) {
2590 ns.add_interface ((Interface) sym);
2591 } else if (sym is Struct) {
2592 ns.add_struct ((Struct) sym);
2593 } else if (sym is Enum) {
2594 ns.add_enum ((Enum) sym);
2595 } else if (sym is ErrorDomain) {
2596 ns.add_error_domain ((ErrorDomain) sym);
2597 } else if (sym is Delegate) {
2598 ns.add_delegate ((Delegate) sym);
2599 } else if (sym is Method) {
2600 var method = (Method) sym;
2601 if (method.binding == MemberBinding.INSTANCE) {
2602 method.binding = MemberBinding.STATIC;
2604 ns.add_method (method);
2605 } else if (sym is Field) {
2606 var field = (Field) sym;
2607 if (field.binding == MemberBinding.INSTANCE) {
2608 field.binding = MemberBinding.STATIC;
2610 ns.add_field (field);
2611 } else if (sym is Constant) {
2612 ns.add_constant ((Constant) sym);
2613 } else {
2614 Report.error (sym.source_reference, "unexpected declaration in namespace");
2619 void add_uses_clause (Namespace ns) throws ParseError {
2620 var begin = get_location ();
2621 var sym = parse_symbol_name ();
2622 var ns_ref = new UsingDirective (sym, get_src (begin));
2624 scanner.source_file.add_using_directive (ns_ref);
2625 ns.add_using_directive (ns_ref);
2628 void parse_using_directives (Namespace ns) throws ParseError {
2629 while (accept (TokenType.USES)) {
2630 if (accept_block ()) {
2631 expect (TokenType.INDENT);
2633 while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2634 add_uses_clause (ns);
2635 expect (TokenType.EOL);
2638 expect (TokenType.DEDENT);
2639 } else {
2640 do {
2641 add_uses_clause (ns);
2642 } while (accept (TokenType.COMMA));
2644 expect_terminator ();
2650 Symbol parse_class_declaration (List<Attribute>? attrs) throws ParseError {
2651 var begin = get_location ();
2652 expect (TokenType.CLASS);
2654 var flags = parse_type_declaration_modifiers ();
2656 var sym = parse_symbol_name ();
2657 var type_param_list = parse_type_parameter_list ();
2658 var base_types = new ArrayList<DataType> ();
2659 if (accept (TokenType.COLON)) {
2660 var type1 = parse_type (true, false);
2661 base_types.add (type1);
2663 if (accept (TokenType.IMPLEMENTS)) {
2664 do {
2665 var type2 = parse_type (true, true);
2666 base_types.add (type2);
2667 } while (accept (TokenType.COMMA));
2671 accept (TokenType.EOL);
2673 var cl = new Class (sym.name, get_src (begin), comment);
2675 if (ModifierFlags.PRIVATE in flags) {
2676 cl.access = SymbolAccessibility.PRIVATE;
2677 } else {
2678 /* class must always be Public unless its name starts with underscore */
2679 if (sym.name[0] == '_') {
2680 cl.access = SymbolAccessibility.PRIVATE;
2681 } else {
2682 cl.access = SymbolAccessibility.PUBLIC;
2686 if (ModifierFlags.ABSTRACT in flags) {
2687 cl.is_abstract = true;
2689 set_attributes (cl, attrs);
2690 foreach (TypeParameter type_param in type_param_list) {
2691 cl.add_type_parameter (type_param);
2693 foreach (DataType base_type in base_types) {
2694 cl.add_base_type (base_type);
2697 class_name = cl.name;
2699 parse_declarations (cl);
2701 // ensure there is always a default construction method
2702 if (scanner.source_file.file_type == SourceFileType.SOURCE
2703 && cl.default_construction_method == null) {
2704 var m = new CreationMethod (cl.name, null, cl.source_reference);
2705 m.access = SymbolAccessibility.PUBLIC;
2706 m.body = new Block (cl.source_reference);
2707 cl.add_method (m);
2710 Symbol result = cl;
2711 while (sym.inner != null) {
2712 sym = sym.inner;
2713 var ns = new Namespace (sym.name, cl.source_reference);
2714 if (result is Namespace) {
2715 ns.add_namespace ((Namespace) result);
2716 } else {
2717 ns.add_class ((Class) result);
2719 result = ns;
2721 return result;
2724 void parse_class_member (Class cl) throws ParseError {
2725 var sym = parse_declaration ();
2726 if (sym is Class) {
2727 cl.add_class ((Class) sym);
2728 } else if (sym is Struct) {
2729 cl.add_struct ((Struct) sym);
2730 } else if (sym is Enum) {
2731 cl.add_enum ((Enum) sym);
2732 } else if (sym is Delegate) {
2733 cl.add_delegate ((Delegate) sym);
2734 } else if (sym is Method) {
2735 cl.add_method ((Method) sym);
2736 } else if (sym is Vala.Signal) {
2737 cl.add_signal ((Vala.Signal) sym);
2738 } else if (sym is Field) {
2739 cl.add_field ((Field) sym);
2740 } else if (sym is Constant) {
2741 cl.add_constant ((Constant) sym);
2742 } else if (sym is Property) {
2743 cl.add_property ((Property) sym);
2744 } else if (sym is Constructor) {
2745 var c = (Constructor) sym;
2746 if (c.binding == MemberBinding.INSTANCE) {
2747 if (cl.constructor != null) {
2748 Report.error (c.source_reference, "class already contains a constructor");
2750 cl.constructor = c;
2751 } else if (c.binding == MemberBinding.CLASS) {
2752 if (cl.class_constructor != null) {
2753 Report.error (c.source_reference, "class already contains a class constructor");
2755 cl.class_constructor = c;
2756 } else {
2757 if (cl.static_constructor != null) {
2758 Report.error (c.source_reference, "class already contains a static constructor");
2760 cl.static_constructor = c;
2763 } else if (sym is Destructor) {
2764 var d = (Destructor) sym;
2765 if (d.binding == MemberBinding.STATIC) {
2766 if (cl.static_destructor != null) {
2767 Report.error (d.source_reference, "class already contains a static destructor");
2769 cl.static_destructor = (Destructor) d;
2770 } else if (d.binding == MemberBinding.CLASS) {
2771 if (cl.class_destructor != null) {
2772 Report.error (d.source_reference, "class already contains a class destructor");
2774 cl.class_destructor = (Destructor) d;
2775 } else {
2776 if (cl.destructor != null) {
2777 Report.error (d.source_reference, "class already contains a destructor");
2779 cl.destructor = (Destructor) d;
2782 } else {
2783 Report.error (sym.source_reference, "unexpected declaration in class");
2787 Constant parse_constant_declaration (List<Attribute>? attrs) throws ParseError {
2788 var begin = get_location ();
2790 expect (TokenType.CONST);
2792 var flags = parse_member_declaration_modifiers ();
2794 string id = parse_identifier ();
2796 expect (TokenType.COLON);
2797 var type = parse_type (false, false);
2798 type = parse_inline_array_type (type);
2800 Expression initializer = null;
2801 if (accept (TokenType.ASSIGN)) {
2802 initializer = parse_expression ();
2804 expect_terminator ();
2806 // constant arrays don't own their element
2807 var array_type = type as ArrayType;
2808 if (array_type != null) {
2809 array_type.element_type.value_owned = false;
2812 var c = new Constant (id, type, initializer, get_src (begin), comment);
2813 c.access = get_access (id);
2815 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2816 c.external = true;
2818 if (ModifierFlags.NEW in flags) {
2819 c.hides = true;
2822 set_attributes (c, attrs);
2824 if (ModifierFlags.STATIC in flags) {
2825 Report.warning (c.source_reference, "the modifier `static' is not applicable to constants");
2828 return c;
2831 Field parse_field_declaration (List<Attribute>? attrs) throws ParseError {
2832 var begin = get_location ();
2833 string id = parse_identifier ();
2834 expect (TokenType.COLON);
2836 var flags = parse_member_declaration_modifiers ();
2838 var type = parse_type (true, true);
2840 type = parse_inline_array_type (type);
2842 var f = new Field (id, type, null, get_src (begin), comment);
2844 if (ModifierFlags.ABSTRACT in flags || ModifierFlags.VIRTUAL in flags || ModifierFlags.OVERRIDE in flags) {
2845 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2848 if (ModifierFlags.PRIVATE in flags) {
2849 f.access = SymbolAccessibility.PRIVATE;
2850 } else {
2851 f.access = get_access (id);
2854 set_attributes (f, attrs);
2856 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2857 f.external = true;
2859 if (ModifierFlags.NEW in flags) {
2860 f.hides = true;
2863 if (accept (TokenType.ASSIGN)) {
2864 f.initializer = parse_expression ();
2867 if (ModifierFlags.STATIC in flags) {
2868 f.binding = MemberBinding.STATIC;
2869 } else if (ModifierFlags.CLASS in flags) {
2870 f.binding = MemberBinding.CLASS;
2873 expect_terminator ();
2875 return f;
2878 InitializerList parse_initializer () throws ParseError {
2879 var begin = get_location ();
2880 if (!accept (TokenType.OPEN_PARENS)) {
2881 expect (TokenType.OPEN_BRACE);
2883 var initializer = new InitializerList (get_src (begin));
2884 if (current () != TokenType.DEDENT) {
2885 do {
2886 var init = parse_argument ();
2887 initializer.append (init);
2888 } while (accept (TokenType.COMMA));
2890 if (!accept (TokenType.CLOSE_PARENS)) {
2891 expect (TokenType.CLOSE_BRACE);
2893 return initializer;
2899 Method parse_main_method_declaration (List<Attribute>? attrs) throws ParseError {
2900 var id = "main";
2901 var begin = get_location ();
2902 DataType type = new VoidType ();
2903 expect (TokenType.INIT);
2905 var method = new Method (id, type, get_src (begin), comment);
2906 method.access = SymbolAccessibility.PUBLIC;
2908 set_attributes (method, attrs);
2910 method.binding = MemberBinding.STATIC;
2912 var sym = new UnresolvedSymbol (null, "string", get_src (begin));
2913 type = new UnresolvedType.from_symbol (sym, get_src (begin));
2914 type.value_owned = true;
2915 type = new ArrayType (type, 1, get_src (begin));
2916 type.nullable = false;
2918 var param = new Parameter ("args", type, get_src (begin));
2919 method.add_parameter (param);
2922 expect (TokenType.EOL);
2924 if (accept_block ()) {
2925 method.body = parse_block ();
2928 return method;
2931 Method parse_method_declaration (List<Attribute>? attrs) throws ParseError {
2932 var begin = get_location ();
2933 DataType type = new VoidType ();
2934 expect (TokenType.DEF);
2935 var flags = parse_member_declaration_modifiers ();
2937 string id = parse_identifier ();
2939 var params = new ArrayList<Parameter> ();
2940 expect (TokenType.OPEN_PARENS);
2942 if (current () != TokenType.CLOSE_PARENS) {
2943 do {
2944 var param = parse_parameter ();
2945 params.add (param);
2946 } while (accept (TokenType.COMMA));
2949 expect (TokenType.CLOSE_PARENS);
2952 /* deal with return value */
2953 if (accept (TokenType.COLON)) {
2954 type = parse_type (true, false);
2957 var type_param_list = parse_type_parameter_list ();
2959 var method = new Method (id, type, get_src (begin), comment);
2960 if (ModifierFlags.PRIVATE in flags) {
2961 method.access = SymbolAccessibility.PRIVATE;
2962 } else {
2963 method.access = get_access (id);
2967 set_attributes (method, attrs);
2969 foreach (TypeParameter type_param in type_param_list) {
2970 method.add_type_parameter (type_param);
2974 foreach (Parameter param in params) {
2975 method.add_parameter (param);
2978 if (accept (TokenType.RAISES)) {
2979 do {
2980 method.add_error_type (parse_type (true, false));
2981 } while (accept (TokenType.COMMA));
2985 if (ModifierFlags.STATIC in flags || id == "main") {
2986 method.binding = MemberBinding.STATIC;
2987 } else if (ModifierFlags.CLASS in flags) {
2988 method.binding = MemberBinding.CLASS;
2990 if (ModifierFlags.ASYNC in flags) {
2991 method.coroutine = true;
2994 if (ModifierFlags.NEW in flags) {
2995 method.hides = true;
2998 if (method.binding == MemberBinding.INSTANCE) {
2999 if (ModifierFlags.ABSTRACT in flags) {
3000 method.is_abstract = true;
3002 if (ModifierFlags.VIRTUAL in flags) {
3003 method.is_virtual = true;
3005 if (ModifierFlags.OVERRIDE in flags) {
3006 method.overrides = true;
3008 if ((method.is_abstract && method.is_virtual)
3009 || (method.is_abstract && method.overrides)
3010 || (method.is_virtual && method.overrides)) {
3011 throw new ParseError.SYNTAX ("only one of `abstract', `virtual', or `override' may be specified");
3013 } else {
3014 if (ModifierFlags.ABSTRACT in flags
3015 || ModifierFlags.VIRTUAL in flags
3016 || ModifierFlags.OVERRIDE in flags) {
3017 throw new ParseError.SYNTAX ("the modifiers `abstract', `virtual', and `override' are not valid for static methods");
3021 if (ModifierFlags.INLINE in flags) {
3022 method.is_inline = true;
3024 if (ModifierFlags.EXTERN in flags) {
3025 method.external = true;
3028 expect (TokenType.EOL);
3030 var body_location = get_location ();
3033 /* "requires" and "ensures" if present will be at start of the method body */
3034 if (accept (TokenType.INDENT)) {
3035 if (accept (TokenType.REQUIRES)) {
3037 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
3038 while (current() != TokenType.DEDENT) {
3039 method.add_precondition (parse_expression ());
3040 expect (TokenType.EOL);
3043 expect (TokenType.DEDENT);
3044 accept_terminator ();
3045 } else {
3047 method.add_precondition (parse_expression ());
3048 expect_terminator ();
3054 if (accept (TokenType.ENSURES)) {
3055 if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
3056 while (current() != TokenType.DEDENT) {
3057 method.add_postcondition (parse_expression ());
3058 expect (TokenType.EOL);
3061 expect (TokenType.DEDENT);
3062 accept_terminator ();
3063 } else {
3064 method.add_postcondition (parse_expression ());
3065 expect_terminator ();
3070 rollback (body_location);
3073 if (accept_block ()) {
3074 method.body = parse_block ();
3075 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
3076 method.external = true;
3078 return method;
3081 Property parse_property_declaration (List<Attribute>? attrs) throws ParseError {
3082 var begin = get_location ();
3083 var readonly = false;
3085 expect (TokenType.PROP);
3087 var flags = parse_member_declaration_modifiers ();
3089 readonly = accept (TokenType.READONLY);
3091 string id = parse_identifier ();
3092 expect (TokenType.COLON);
3094 var type = parse_type (true, true);
3096 var prop = new Property (id, type, null, null, get_src (begin), comment);
3097 if (ModifierFlags.PRIVATE in flags) {
3098 prop.access = SymbolAccessibility.PRIVATE;
3099 } else {
3100 prop.access = get_access (id);
3103 set_attributes (prop, attrs);
3105 if (ModifierFlags.STATIC in flags) {
3106 prop.binding = MemberBinding.STATIC;
3107 } else if (ModifierFlags.CLASS in flags) {
3108 prop.binding = MemberBinding.CLASS;
3110 if (ModifierFlags.ABSTRACT in flags) {
3111 prop.is_abstract = true;
3113 if (ModifierFlags.VIRTUAL in flags) {
3114 prop.is_virtual = true;
3116 if (ModifierFlags.OVERRIDE in flags) {
3117 prop.overrides = true;
3120 if (ModifierFlags.NEW in flags) {
3121 prop.hides = true;
3123 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3124 prop.external = true;
3127 if (ModifierFlags.ASYNC in flags) {
3128 Report.error (prop.source_reference, "async properties are not supported yet");
3131 if (accept (TokenType.ASSIGN)) {
3132 prop.initializer = parse_expression ();
3136 if (accept_block ()) {
3137 expect (TokenType.INDENT);
3138 while (current () != TokenType.DEDENT) {
3139 var accessor_begin = get_location ();
3140 var attribs = parse_attributes (false);
3142 var value_type = type.copy ();
3143 value_type.value_owned = accept (TokenType.OWNED);
3145 if (accept (TokenType.GET)) {
3146 if (prop.get_accessor != null) {
3147 throw new ParseError.SYNTAX ("property get accessor already defined");
3149 Block block = null;
3150 if (accept_block ()) {
3151 block = parse_block ();
3152 prop.external = false;
3154 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin));
3155 set_attributes (prop.get_accessor, attribs);
3156 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
3157 } else {
3158 bool _construct = false;
3159 if (accept (TokenType.SET)) {
3160 if (readonly) {
3161 throw new ParseError.SYNTAX ("set block not allowed for a read only property");
3163 _construct = accept (TokenType.CONSTRUCT);
3164 } else if (accept (TokenType.CONSTRUCT)) {
3165 _construct = true;
3166 } else if (!accept (TokenType.EOL)) {
3167 throw new ParseError.SYNTAX ("expected get, set, or construct");
3170 if (prop.set_accessor != null) {
3171 throw new ParseError.SYNTAX ("property set accessor already defined");
3174 Block block = null;
3175 if (accept_block ()) {
3176 block = parse_block ();
3177 prop.external = false;
3179 prop.set_accessor = new PropertyAccessor (false, !readonly, _construct, value_type, block, get_src (accessor_begin));
3180 set_attributes (prop.set_accessor, attribs);
3181 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3184 accept (TokenType.EOL);
3185 expect (TokenType.DEDENT);
3186 } else {
3187 var value_type = type.copy ();
3188 value_type.value_owned = false;
3190 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, null, get_src (begin));
3191 prop.get_accessor.access = SymbolAccessibility.PUBLIC;
3193 if (!readonly) {
3194 value_type = type.copy ();
3195 value_type.value_owned = false;
3197 prop.set_accessor = new PropertyAccessor (false, true, false, value_type, null, get_src (begin));
3198 prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3202 expect_terminator ();
3205 if (!prop.is_abstract && scanner.source_file.file_type == SourceFileType.SOURCE) {
3206 var needs_var = (readonly && (prop.get_accessor != null && prop.get_accessor.body == null));
3208 if (!needs_var) {
3209 needs_var = (prop.get_accessor != null && prop.get_accessor.body == null) || (prop.set_accessor != null && prop.set_accessor.body == null);
3212 if (needs_var) {
3213 /* automatic property accessor body generation */
3214 var variable_type = prop.property_type.copy ();
3215 prop.field = new Field ("_%s".printf (prop.name), variable_type, prop.initializer, prop.source_reference);
3216 prop.field.access = SymbolAccessibility.PRIVATE;
3217 prop.field.binding = prop.binding;
3221 return prop;
3224 Vala.Signal parse_signal_declaration (List<Attribute>? attrs) throws ParseError {
3225 var begin = get_location ();
3226 DataType type;
3228 expect (TokenType.EVENT);
3229 var flags = parse_member_declaration_modifiers ();
3230 string id = parse_identifier ();
3233 var params = new ArrayList<Parameter> ();
3235 expect (TokenType.OPEN_PARENS);
3236 if (current () != TokenType.CLOSE_PARENS) {
3237 do {
3238 var param = parse_parameter ();
3239 params.add (param);
3240 } while (accept (TokenType.COMMA));
3242 expect (TokenType.CLOSE_PARENS);
3244 if (accept (TokenType.COLON)) {
3245 type = parse_type (true, false);
3246 } else {
3247 type = new VoidType ();
3250 var sig = new Vala.Signal (id, type, get_src (begin), comment);
3251 if (ModifierFlags.PRIVATE in flags) {
3252 sig.access = SymbolAccessibility.PRIVATE;
3253 } else {
3254 sig.access = get_access (id);
3257 if (ModifierFlags.VIRTUAL in flags) {
3258 sig.is_virtual = true;
3260 if (ModifierFlags.NEW in flags) {
3261 sig.hides = true;
3264 if (ModifierFlags.STATIC in flags) {
3265 throw new ParseError.SYNTAX ("`static' modifier not allowed on signals");
3266 } else if (ModifierFlags.CLASS in flags) {
3267 throw new ParseError.SYNTAX ("`class' modifier not allowed on signals");
3270 set_attributes (sig, attrs);
3272 foreach (Parameter formal_param in params) {
3273 sig.add_parameter (formal_param);
3276 if (!accept_terminator ()) {
3277 sig.body = parse_block ();
3279 return sig;
3282 Constructor parse_constructor_declaration (List<Attribute>? attrs) throws ParseError {
3283 var begin = get_location ();
3285 expect (TokenType.INIT);
3286 var flags = parse_member_declaration_modifiers ();
3288 var c = new Constructor (get_src (begin));
3289 if (ModifierFlags.STATIC in flags) {
3290 c.binding = MemberBinding.STATIC;
3291 } else if (ModifierFlags.CLASS in flags) {
3292 c.binding = MemberBinding.CLASS;
3295 accept_block ();
3296 c.body = parse_block ();
3297 return c;
3300 Destructor parse_destructor_declaration (List<Attribute>? attrs) throws ParseError {
3301 var begin = get_location ();
3302 expect (TokenType.FINAL);
3303 var d = new Destructor (get_src (begin));
3304 accept_block ();
3305 d.body = parse_block ();
3306 return d;
3309 Symbol parse_struct_declaration (List<Attribute>? attrs) throws ParseError {
3310 var begin = get_location ();
3312 expect (TokenType.STRUCT);
3313 var flags = parse_type_declaration_modifiers ();
3314 var sym = parse_symbol_name ();
3315 var type_param_list = parse_type_parameter_list ();
3316 DataType base_type = null;
3317 if (accept (TokenType.COLON)) {
3318 base_type = parse_type (true, false);
3321 var st = new Struct (sym.name, get_src (begin), comment);
3322 if (ModifierFlags.PRIVATE in flags) {
3323 st.access = SymbolAccessibility.PRIVATE;
3324 } else {
3325 st.access = get_access (sym.name);
3327 set_attributes (st, attrs);
3328 foreach (TypeParameter type_param in type_param_list) {
3329 st.add_type_parameter (type_param);
3331 if (base_type != null) {
3332 st.base_type = base_type;
3335 expect (TokenType.EOL);
3337 parse_declarations (st);
3339 Symbol result = st;
3340 while (sym.inner != null) {
3341 sym = sym.inner;
3342 var ns = new Namespace (sym.name, st.source_reference);
3343 if (result is Namespace) {
3344 ns.add_namespace ((Namespace) result);
3345 } else {
3346 ns.add_struct ((Struct) result);
3348 result = ns;
3350 return result;
3353 void parse_struct_member (Struct st) throws ParseError {
3354 var sym = parse_declaration ();
3355 if (sym is Method) {
3356 st.add_method ((Method) sym);
3357 } else if (sym is Field) {
3358 st.add_field ((Field) sym);
3359 } else if (sym is Constant) {
3360 st.add_constant ((Constant) sym);
3361 } else if (sym is Property) {
3362 st.add_property ((Property) sym);
3363 } else {
3364 Report.error (sym.source_reference, "unexpected declaration in struct");
3368 Symbol parse_interface_declaration (List<Attribute>? attrs) throws ParseError {
3369 var begin = get_location ();
3371 expect (TokenType.INTERFACE);
3372 var flags = parse_type_declaration_modifiers ();
3373 var sym = parse_symbol_name ();
3374 var type_param_list = parse_type_parameter_list ();
3375 var base_types = new ArrayList<DataType> ();
3376 if (accept (TokenType.COLON)) {
3377 do {
3378 var type = parse_type (true, false);
3379 base_types.add (type);
3380 } while (accept (TokenType.COMMA));
3383 var iface = new Interface (sym.name, get_src (begin), comment);
3384 if (ModifierFlags.PRIVATE in flags) {
3385 iface.access = SymbolAccessibility.PRIVATE;
3386 } else {
3387 iface.access = get_access (sym.name);
3389 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3390 iface.external = true;
3392 set_attributes (iface, attrs);
3393 foreach (TypeParameter type_param in type_param_list) {
3394 iface.add_type_parameter (type_param);
3396 foreach (DataType base_type in base_types) {
3397 iface.add_prerequisite (base_type);
3401 expect (TokenType.EOL);
3403 parse_declarations (iface);
3406 Symbol result = iface;
3407 while (sym.inner != null) {
3408 sym = sym.inner;
3409 var ns = new Namespace (sym.name, iface.source_reference);
3410 if (result is Namespace) {
3411 ns.add_namespace ((Namespace) result);
3412 } else {
3413 ns.add_interface ((Interface) result);
3415 result = ns;
3417 return result;
3420 void parse_interface_member (Interface iface) throws ParseError {
3421 var sym = parse_declaration ();
3422 if (sym is Class) {
3423 iface.add_class ((Class) sym);
3424 } else if (sym is Struct) {
3425 iface.add_struct ((Struct) sym);
3426 } else if (sym is Enum) {
3427 iface.add_enum ((Enum) sym);
3428 } else if (sym is Delegate) {
3429 iface.add_delegate ((Delegate) sym);
3430 } else if (sym is Method) {
3431 iface.add_method ((Method) sym);
3432 } else if (sym is Vala.Signal) {
3433 iface.add_signal ((Vala.Signal) sym);
3434 } else if (sym is Field) {
3435 iface.add_field ((Field) sym);
3436 } else if (sym is Constant) {
3437 iface.add_constant ((Constant) sym);
3438 } else if (sym is Property) {
3439 iface.add_property ((Property) sym);
3440 } else {
3441 Report.error (sym.source_reference, "unexpected declaration in interface");
3445 Symbol parse_enum_declaration (List<Attribute>? attrs) throws ParseError {
3446 var begin = get_location ();
3447 expect (TokenType.ENUM);
3448 var flags = parse_type_declaration_modifiers ();
3450 var sym = parse_symbol_name ();
3451 var en = new Enum (sym.name, get_src (begin), comment);
3452 if (ModifierFlags.PRIVATE in flags) {
3453 en.access = SymbolAccessibility.PRIVATE;
3454 } else {
3455 en.access = get_access (sym.name);
3457 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3458 en.external = true;
3460 set_attributes (en, attrs);
3462 expect (TokenType.EOL);
3463 expect (TokenType.INDENT);
3464 do {
3465 if (current () == TokenType.DEDENT && en.get_values ().size > 0) {
3466 // allow trailing comma
3467 break;
3469 var value_attrs = parse_attributes (false);
3470 var value_begin = get_location ();
3471 string id = parse_identifier ();
3472 comment = scanner.pop_comment ();
3474 Expression value = null;
3475 if (accept (TokenType.ASSIGN)) {
3476 value = parse_expression ();
3479 var ev = new EnumValue (id, value, get_src (value_begin), comment);
3480 ev.access = SymbolAccessibility.PUBLIC;
3481 set_attributes (ev, value_attrs);
3483 en.add_value (ev);
3484 if (expect_separator ()) {
3485 accept (TokenType.EOL);
3487 } while (true);
3489 expect (TokenType.DEDENT);
3491 Symbol result = en;
3492 while (sym.inner != null) {
3493 sym = sym.inner;
3494 var ns = new Namespace (sym.name, en.source_reference);
3495 if (result is Namespace) {
3496 ns.add_namespace ((Namespace) result);
3497 } else {
3498 ns.add_enum ((Enum) result);
3500 result = ns;
3502 return result;
3505 Symbol parse_errordomain_declaration (List<Attribute>? attrs) throws ParseError {
3506 var begin = get_location ();
3507 expect (TokenType.ERRORDOMAIN);
3508 var flags = parse_type_declaration_modifiers ();
3510 var sym = parse_symbol_name ();
3511 var ed = new ErrorDomain (sym.name, get_src (begin), comment);
3512 if (ModifierFlags.PRIVATE in flags) {
3513 ed.access = SymbolAccessibility.PRIVATE;
3514 } else {
3515 ed.access = get_access (sym.name);
3518 set_attributes (ed, attrs);
3520 expect (TokenType.EOL);
3521 expect (TokenType.INDENT);
3523 do {
3524 if (current () == TokenType.DEDENT && ed.get_codes ().size > 0) {
3525 // allow trailing comma
3526 break;
3528 var code_attrs = parse_attributes (false);
3529 var code_begin = get_location ();
3530 string id = parse_identifier ();
3531 comment = scanner.pop_comment ();
3532 var ec = new ErrorCode (id, get_src (code_begin), comment);
3533 set_attributes (ec, code_attrs);
3534 if (accept (TokenType.ASSIGN)) {
3535 ec.value = parse_expression ();
3537 ed.add_code (ec);
3538 accept (TokenType.EOL);
3539 } while (true);
3542 expect (TokenType.DEDENT);
3544 Symbol result = ed;
3545 while (sym.inner != null) {
3546 sym = sym.inner;
3547 var ns = new Namespace (sym.name, ed.source_reference);
3549 if (result is Namespace) {
3550 ns.add_namespace ((Namespace) result);
3551 } else {
3552 ns.add_error_domain ((ErrorDomain) result);
3554 result = ns;
3556 return result;
3559 ModifierFlags parse_type_declaration_modifiers () {
3560 ModifierFlags flags = 0;
3561 while (true) {
3562 switch (current ()) {
3563 case TokenType.ABSTRACT:
3564 next ();
3565 flags |= ModifierFlags.ABSTRACT;
3566 break;
3568 case TokenType.EXTERN:
3569 next ();
3570 flags |= ModifierFlags.EXTERN;
3571 break;
3573 case TokenType.STATIC:
3574 next ();
3575 flags |= ModifierFlags.STATIC;
3576 break;
3578 case TokenType.PRIVATE:
3579 next ();
3580 flags |= ModifierFlags.PRIVATE;
3581 break;
3583 default:
3584 return flags;
3589 ModifierFlags parse_member_declaration_modifiers () {
3590 ModifierFlags flags = 0;
3591 while (true) {
3592 switch (current ()) {
3593 case TokenType.ABSTRACT:
3594 next ();
3595 flags |= ModifierFlags.ABSTRACT;
3596 break;
3597 case TokenType.ASYNC:
3598 next ();
3599 flags |= ModifierFlags.ASYNC;
3600 break;
3601 case TokenType.CLASS:
3602 next ();
3603 flags |= ModifierFlags.CLASS;
3604 break;
3605 case TokenType.EXTERN:
3606 next ();
3607 flags |= ModifierFlags.EXTERN;
3608 break;
3609 case TokenType.INLINE:
3610 next ();
3611 flags |= ModifierFlags.INLINE;
3612 break;
3613 case TokenType.NEW:
3614 next ();
3615 flags |= ModifierFlags.NEW;
3616 break;
3617 case TokenType.OVERRIDE:
3618 next ();
3619 flags |= ModifierFlags.OVERRIDE;
3620 break;
3621 case TokenType.SEALED:
3622 next ();
3623 flags |= ModifierFlags.SEALED;
3624 break;
3625 case TokenType.STATIC:
3626 next ();
3627 flags |= ModifierFlags.STATIC;
3628 break;
3629 case TokenType.VIRTUAL:
3630 next ();
3631 flags |= ModifierFlags.VIRTUAL;
3632 break;
3633 case TokenType.PRIVATE:
3634 next ();
3635 flags |= ModifierFlags.PRIVATE;
3636 break;
3637 default:
3638 return flags;
3643 Parameter parse_parameter () throws ParseError {
3644 var attrs = parse_attributes (true);
3645 var begin = get_location ();
3646 if (accept (TokenType.ELLIPSIS)) {
3647 // varargs
3648 return new Parameter.with_ellipsis (get_src (begin));
3650 bool params_array = accept (TokenType.PARAMS);
3651 var direction = ParameterDirection.IN;
3652 if (accept (TokenType.OUT)) {
3653 direction = ParameterDirection.OUT;
3654 } else if (accept (TokenType.REF)) {
3655 direction = ParameterDirection.REF;
3658 string id = parse_identifier ();
3660 expect (TokenType.COLON);
3662 DataType type;
3663 if (direction == ParameterDirection.IN) {
3664 type = parse_type (false, false);
3665 } else if (direction == ParameterDirection.REF) {
3666 // ref parameters own the value by default
3667 type = parse_type (true, true);
3668 } else {
3669 // out parameters own the value by default
3670 type = parse_type (true, false);
3673 var param = new Parameter (id, type, get_src (begin));
3674 set_attributes (param, attrs);
3675 param.direction = direction;
3676 param.params_array = params_array;
3677 if (accept (TokenType.ASSIGN)) {
3678 param.initializer = parse_expression ();
3680 return param;
3683 CreationMethod parse_creation_method_declaration (List<Attribute>? attrs) throws ParseError {
3684 var begin = get_location ();
3685 CreationMethod method;
3687 expect (TokenType.CONSTRUCT);
3688 parse_member_declaration_modifiers ();
3690 if (accept (TokenType.OPEN_PARENS)) {
3691 /* create default name using class name */
3692 method = new CreationMethod (class_name, null, get_src (begin), comment);
3693 } else {
3694 var sym = parse_symbol_name ();
3695 if (sym.inner == null) {
3697 if (sym.name != class_name) {
3698 method = new CreationMethod (class_name, sym.name, get_src (begin), comment);
3699 } else {
3700 method = new CreationMethod (sym.name, null, get_src (begin), comment);
3702 } else {
3703 method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
3705 expect (TokenType.OPEN_PARENS);
3708 if (current () != TokenType.CLOSE_PARENS) {
3709 do {
3710 var param = parse_parameter ();
3711 method.add_parameter (param);
3712 } while (accept (TokenType.COMMA));
3714 expect (TokenType.CLOSE_PARENS);
3715 if (accept (TokenType.RAISES)) {
3716 do {
3717 method.add_error_type (parse_type (true, false));
3718 } while (accept (TokenType.COMMA));
3720 method.access = SymbolAccessibility.PUBLIC;
3721 set_attributes (method, attrs);
3722 method.binding = MemberBinding.STATIC;
3724 if (accept_block ()) {
3725 method.body = parse_block ();
3726 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
3727 method.external = true;
3730 return method;
3733 Symbol parse_delegate_declaration (List<Attribute>? attrs) throws ParseError {
3734 var begin = get_location ();
3735 DataType type;
3737 expect (TokenType.DELEGATE);
3739 var flags = parse_member_declaration_modifiers ();
3741 var sym = parse_symbol_name ();
3743 var type_param_list = parse_type_parameter_list ();
3745 if (ModifierFlags.NEW in flags) {
3746 throw new ParseError.SYNTAX ("`new' modifier not allowed on delegates");
3749 var params = new ArrayList<Parameter> ();
3751 expect (TokenType.OPEN_PARENS);
3752 if (current () != TokenType.CLOSE_PARENS) {
3753 do {
3754 var param = parse_parameter ();
3755 params.add (param);
3756 } while (accept (TokenType.COMMA));
3758 expect (TokenType.CLOSE_PARENS);
3760 if (accept (TokenType.COLON)) {
3761 type = parse_type (true, false);
3763 } else {
3764 type = new VoidType ();
3767 var d = new Delegate (sym.name, type, get_src (begin), comment);
3769 if (accept (TokenType.RAISES)) {
3770 do {
3771 d.add_error_type (parse_type (true, false));
3772 } while (accept (TokenType.COMMA));
3775 expect_terminator ();
3778 if (ModifierFlags.PRIVATE in flags) {
3779 d.access = SymbolAccessibility.PRIVATE;
3780 } else {
3781 d.access = get_access (sym.name);
3784 if (ModifierFlags.STATIC in flags) {
3785 d.has_target = false;
3787 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3788 d.external = true;
3791 set_attributes (d, attrs);
3793 foreach (TypeParameter type_param in type_param_list) {
3794 d.add_type_parameter (type_param);
3797 foreach (Parameter formal_param in params) {
3798 d.add_parameter (formal_param);
3803 Symbol result = d;
3804 while (sym.inner != null) {
3805 sym = sym.inner;
3806 var ns = new Namespace (sym.name, d.source_reference);
3808 if (result is Namespace) {
3809 ns.add_namespace ((Namespace) result);
3810 } else {
3811 ns.add_delegate ((Delegate) result);
3813 result = ns;
3815 return result;
3818 List<TypeParameter> parse_type_parameter_list () throws ParseError {
3819 if (accept (TokenType.OF)) {
3820 var list = new ArrayList<TypeParameter> ();
3821 do {
3822 var begin = get_location ();
3823 string id = parse_identifier ();
3824 list.add (new TypeParameter (id, get_src (begin)));
3825 } while (accept (TokenType.COMMA));
3826 return list;
3827 } else {
3828 if (_empty_type_parameter_list == null) {
3829 _empty_type_parameter_list = new ArrayList<TypeParameter> ();
3831 return _empty_type_parameter_list;
3835 void skip_type_argument_list () throws ParseError {
3836 if (accept (TokenType.OF)) {
3837 if (accept (TokenType.OPEN_PARENS)) {
3838 do {
3839 skip_type ();
3840 } while (accept (TokenType.COMMA));
3841 expect (TokenType.CLOSE_PARENS);
3842 } else {
3843 do {
3844 skip_type ();
3845 } while (accept (TokenType.COMMA));
3851 // try to parse type argument list
3852 List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3853 var begin = get_location ();
3854 if (accept (TokenType.OF)) {
3855 var list = new ArrayList<DataType> ();
3856 var inParens = false;
3858 // Optional parens allow multi arg types in function signature: "dict of (int, string)"
3859 // See: https://bugzilla.gnome.org/show_bug.cgi?id=611191
3860 if (accept (TokenType.OPEN_PARENS)) {
3861 inParens = true;
3864 do {
3865 switch (current ()) {
3866 case TokenType.VOID:
3867 case TokenType.DYNAMIC:
3868 case TokenType.UNOWNED:
3869 case TokenType.WEAK:
3870 case TokenType.IDENTIFIER:
3871 var type = parse_type (true, true);
3873 list.add (type);
3874 break;
3875 default:
3876 rollback (begin);
3877 return null;
3879 } while (accept (TokenType.COMMA));
3881 if (inParens) {
3882 expect (TokenType.CLOSE_PARENS);
3885 return list;
3887 return null;
3890 MemberAccess parse_member_name (Expression? base_expr = null) throws ParseError {
3891 var begin = get_location ();
3892 MemberAccess expr = null;
3893 do {
3894 string id = parse_identifier ();
3895 List<DataType> type_arg_list = parse_type_argument_list (false);
3896 expr = new MemberAccess (expr != null ? expr : base_expr, id, get_src (begin));
3897 if (type_arg_list != null) {
3898 foreach (DataType type_arg in type_arg_list) {
3899 expr.add_type_argument (type_arg);
3902 } while (accept (TokenType.DOT));
3903 return expr;