vala: Report error for error-domains without any code
[vala-gnome.git] / vala / valaparser.vala
blob9a26015c11330325cab37f6f8be42485bbd39e73
1 /* valaparser.vala
3 * Copyright (C) 2006-2013 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Code visitor parsing all Vala source files.
28 public class Vala.Parser : CodeVisitor {
29 Scanner scanner;
31 CodeContext context;
33 // token buffer
34 TokenInfo[] tokens;
35 // index of current token in buffer
36 int index;
37 // number of tokens in buffer
38 int size;
40 Comment comment;
42 const int BUFFER_SIZE = 32;
44 static List<TypeParameter> _empty_type_parameter_list;
46 struct TokenInfo {
47 public TokenType type;
48 public SourceLocation begin;
49 public SourceLocation end;
52 enum ModifierFlags {
53 NONE,
54 ABSTRACT = 1 << 0,
55 CLASS = 1 << 1,
56 EXTERN = 1 << 2,
57 INLINE = 1 << 3,
58 NEW = 1 << 4,
59 OVERRIDE = 1 << 5,
60 STATIC = 1 << 6,
61 VIRTUAL = 1 << 7,
62 ASYNC = 1 << 8,
63 SEALED = 1 << 9
66 public Parser () {
67 tokens = new TokenInfo[BUFFER_SIZE];
70 /**
71 * Parses all .vala and .vapi source files in the specified code
72 * context and builds a code tree.
74 * @param context a code context
76 public void parse (CodeContext context) {
77 this.context = context;
78 context.accept (this);
79 this.context = null;
82 public override void visit_source_file (SourceFile source_file) {
83 if ((context != null && context.run_output) || source_file.filename.has_suffix (".vala") || source_file.filename.has_suffix (".vapi")) {
84 parse_file (source_file);
88 inline bool next () {
89 index = (index + 1) % BUFFER_SIZE;
90 size--;
91 if (size <= 0) {
92 SourceLocation begin, end;
93 TokenType type = scanner.read_token (out begin, out end);
94 tokens[index] = { type, begin, end };
95 size = 1;
97 return (tokens[index].type != TokenType.EOF);
100 inline void prev () {
101 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
102 size++;
103 assert (size <= BUFFER_SIZE);
106 inline TokenType current () {
107 return tokens[index].type;
110 inline bool accept (TokenType type) {
111 if (current () == type) {
112 next ();
113 return true;
115 return false;
118 void report_parse_error (ParseError e) {
119 var begin = get_location ();
120 next ();
121 Report.error (get_src (begin), "syntax error, " + e.message);
124 inline bool expect (TokenType type) throws ParseError {
125 if (accept (type)) {
126 return true;
129 throw new ParseError.SYNTAX ("expected %s", type.to_string ());
132 inline SourceLocation get_location () {
133 return tokens[index].begin;
136 string get_current_string () {
137 var token = tokens[index];
138 return ((string) token.begin.pos).substring (0, (int) (token.end.pos - token.begin.pos));
141 string get_last_string () {
142 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
143 var token = tokens[last_index];
144 return ((string) token.begin.pos).substring (0, (int) (token.end.pos - token.begin.pos));
147 SourceReference get_src (SourceLocation begin) {
148 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
150 return new SourceReference (scanner.source_file, begin, tokens[last_index].end);
153 SourceReference get_current_src () {
154 var token = tokens[index];
155 return new SourceReference (scanner.source_file, token.begin, token.end);
158 SourceReference get_last_src () {
159 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
160 var token = tokens[last_index];
161 return new SourceReference (scanner.source_file, token.begin, token.end);
164 void rollback (SourceLocation location) {
165 while (tokens[index].begin.pos != location.pos) {
166 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
167 size++;
168 if (size > BUFFER_SIZE) {
169 scanner.seek (location);
170 size = 0;
171 index = 0;
173 next ();
178 void skip_identifier () throws ParseError {
179 // also accept keywords as identifiers where there is no conflict
180 switch (current ()) {
181 case TokenType.ABSTRACT:
182 case TokenType.AS:
183 case TokenType.ASYNC:
184 case TokenType.BASE:
185 case TokenType.BREAK:
186 case TokenType.CASE:
187 case TokenType.CATCH:
188 case TokenType.CLASS:
189 case TokenType.CONST:
190 case TokenType.CONSTRUCT:
191 case TokenType.CONTINUE:
192 case TokenType.DEFAULT:
193 case TokenType.DELEGATE:
194 case TokenType.DELETE:
195 case TokenType.DO:
196 case TokenType.DYNAMIC:
197 case TokenType.ELSE:
198 case TokenType.ENUM:
199 case TokenType.ENSURES:
200 case TokenType.ERRORDOMAIN:
201 case TokenType.EXTERN:
202 case TokenType.FALSE:
203 case TokenType.FINALLY:
204 case TokenType.FOR:
205 case TokenType.FOREACH:
206 case TokenType.GET:
207 case TokenType.IDENTIFIER:
208 case TokenType.IF:
209 case TokenType.IN:
210 case TokenType.INLINE:
211 case TokenType.INTERFACE:
212 case TokenType.INTERNAL:
213 case TokenType.IS:
214 case TokenType.LOCK:
215 case TokenType.NAMESPACE:
216 case TokenType.NEW:
217 case TokenType.NULL:
218 case TokenType.OUT:
219 case TokenType.OVERRIDE:
220 case TokenType.OWNED:
221 case TokenType.PARAMS:
222 case TokenType.PRIVATE:
223 case TokenType.PROTECTED:
224 case TokenType.PUBLIC:
225 case TokenType.REF:
226 case TokenType.REQUIRES:
227 case TokenType.RETURN:
228 case TokenType.SEALED:
229 case TokenType.SET:
230 case TokenType.SIGNAL:
231 case TokenType.SIZEOF:
232 case TokenType.STATIC:
233 case TokenType.STRUCT:
234 case TokenType.SWITCH:
235 case TokenType.THIS:
236 case TokenType.THROW:
237 case TokenType.THROWS:
238 case TokenType.TRUE:
239 case TokenType.TRY:
240 case TokenType.TYPEOF:
241 case TokenType.UNLOCK:
242 case TokenType.UNOWNED:
243 case TokenType.USING:
244 case TokenType.VAR:
245 case TokenType.VIRTUAL:
246 case TokenType.VOID:
247 case TokenType.VOLATILE:
248 case TokenType.WEAK:
249 case TokenType.WHILE:
250 case TokenType.YIELD:
251 next ();
252 return;
253 case TokenType.INTEGER_LITERAL:
254 case TokenType.REAL_LITERAL:
255 // also accept integer and real literals
256 // as long as they contain at least one character
257 // and no decimal point
258 // for example, 2D and 3D
259 string id = get_current_string ();
260 if (id[id.length - 1].isalpha () && !("." in id)) {
261 next ();
262 return;
264 break;
265 default:
266 throw new ParseError.SYNTAX ("expected identifier");
270 string parse_identifier () throws ParseError {
271 skip_identifier ();
272 return get_last_string ();
275 Expression parse_literal () throws ParseError {
276 var begin = get_location ();
278 switch (current ()) {
279 case TokenType.TRUE:
280 next ();
281 return new BooleanLiteral (true, get_src (begin));
282 case TokenType.FALSE:
283 next ();
284 return new BooleanLiteral (false, get_src (begin));
285 case TokenType.INTEGER_LITERAL:
286 next ();
287 return new IntegerLiteral (get_last_string (), get_src (begin));
288 case TokenType.REAL_LITERAL:
289 next ();
290 return new RealLiteral (get_last_string (), get_src (begin));
291 case TokenType.CHARACTER_LITERAL:
292 next ();
293 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
294 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
295 if (lit.error) {
296 Report.error (lit.source_reference, "invalid character literal");
298 return lit;
299 case TokenType.REGEX_LITERAL:
300 next ();
301 string match_part = get_last_string ();
302 SourceReference src_begin = get_src (begin);
303 expect (TokenType.CLOSE_REGEX_LITERAL);
304 string close_token = get_last_string ();
305 return new RegexLiteral ("%s/%s".printf (close_token, match_part), src_begin);
306 case TokenType.STRING_LITERAL:
307 next ();
308 return new StringLiteral (get_last_string (), get_src (begin));
309 case TokenType.TEMPLATE_STRING_LITERAL:
310 next ();
311 return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
312 case TokenType.VERBATIM_STRING_LITERAL:
313 next ();
314 string raw_string = get_last_string ();
315 string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
316 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
317 case TokenType.NULL:
318 next ();
319 return new NullLiteral (get_src (begin));
320 default:
321 throw new ParseError.SYNTAX ("expected literal");
325 public void parse_file (SourceFile source_file) {
326 var has_global_context = (context != null);
327 if (!has_global_context) {
328 context = source_file.context;
331 scanner = new Scanner (source_file);
332 parse_file_comments ();
334 index = -1;
335 size = 0;
337 next ();
340 try {
341 parse_using_directives (context.root);
342 parse_declarations (context.root, true);
343 if (accept (TokenType.CLOSE_BRACE)) {
344 // only report error if it's not a secondary error
345 if (context.report.get_errors () == 0) {
346 Report.error (get_last_src (), "unexpected `}'");
349 } catch (ParseError e) {
350 report_parse_error (e);
353 scanner = null;
354 if (!has_global_context) {
355 context = null;
359 void parse_file_comments () {
360 scanner.parse_file_comments ();
363 void skip_symbol_name () throws ParseError {
364 do {
365 skip_identifier ();
366 } while (accept (TokenType.DOT) || accept (TokenType.DOUBLE_COLON));
369 UnresolvedSymbol parse_symbol_name () throws ParseError {
370 var begin = get_location ();
371 UnresolvedSymbol sym = null;
372 do {
373 string name = parse_identifier ();
374 if (name == "global" && accept (TokenType.DOUBLE_COLON)) {
375 // global::Name
376 // qualified access to global symbol
377 name = parse_identifier ();
378 sym = new UnresolvedSymbol (sym, name, get_src (begin));
379 sym.qualified = true;
380 continue;
382 sym = new UnresolvedSymbol (sym, name, get_src (begin));
383 } while (accept (TokenType.DOT));
384 return sym;
387 void skip_type () throws ParseError {
388 accept (TokenType.DYNAMIC);
389 accept (TokenType.OWNED);
390 accept (TokenType.UNOWNED);
391 accept (TokenType.WEAK);
393 if (is_inner_array_type ()) {
394 expect (TokenType.OPEN_PARENS);
395 expect (TokenType.UNOWNED);
396 skip_type ();
397 expect (TokenType.CLOSE_PARENS);
398 expect (TokenType.OPEN_BRACKET);
399 prev ();
400 } else {
401 if (accept (TokenType.VOID)) {
402 } else {
403 skip_symbol_name ();
404 skip_type_argument_list ();
406 while (accept (TokenType.STAR)) {
408 accept (TokenType.INTERR);
411 while (accept (TokenType.OPEN_BRACKET)) {
412 do {
413 // required for decision between expression and declaration statement
414 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
415 parse_expression ();
417 } while (accept (TokenType.COMMA));
418 expect (TokenType.CLOSE_BRACKET);
419 accept (TokenType.INTERR);
421 accept (TokenType.OP_NEG);
422 accept (TokenType.HASH);
425 bool is_inner_array_type () {
426 var begin = get_location ();
428 var result = accept (TokenType.OPEN_PARENS) && accept (TokenType.UNOWNED) && current() != TokenType.CLOSE_PARENS;
429 rollback (begin);
430 return result;
433 DataType parse_type (bool owned_by_default, bool can_weak_ref, bool require_unowned = false) throws ParseError {
434 var begin = get_location ();
436 bool is_dynamic = accept (TokenType.DYNAMIC);
438 bool value_owned = owned_by_default;
440 if (require_unowned) {
441 expect (TokenType.UNOWNED);
442 } else {
443 if (owned_by_default) {
444 if (accept (TokenType.UNOWNED)) {
445 value_owned = false;
446 } else if (accept (TokenType.WEAK)) {
447 if (!can_weak_ref && !context.deprecated) {
448 Report.warning (get_last_src (), "deprecated syntax, use `unowned` modifier");
450 value_owned = false;
451 } else if (accept (TokenType.OWNED)) {
452 Report.warning (get_last_src (), "`owned' is default in this context");
454 } else {
455 if (accept (TokenType.OWNED)) {
456 value_owned = true;
457 } else {
458 value_owned = false;
459 if (accept (TokenType.UNOWNED)) {
460 Report.warning (get_last_src (), "`unowned' is default in this context");
466 DataType type;
468 bool inner_type_owned = true;
469 if (accept (TokenType.OPEN_PARENS)) {
470 type = parse_type (false, false, true);
471 expect (TokenType.CLOSE_PARENS);
473 inner_type_owned = false;
475 expect (TokenType.OPEN_BRACKET);
476 prev ();
477 } else {
478 if (!is_dynamic && value_owned == owned_by_default && accept (TokenType.VOID)) {
479 type = new VoidType (get_src (begin));
480 } else {
481 var sym = parse_symbol_name ();
482 List<DataType> type_arg_list = parse_type_argument_list (false);
484 type = new UnresolvedType.from_symbol (sym, get_src (begin));
485 if (type_arg_list != null) {
486 foreach (DataType type_arg in type_arg_list) {
487 type.add_type_argument (type_arg);
492 while (accept (TokenType.STAR)) {
493 type = new PointerType (type, get_src (begin));
496 if (!(type is PointerType)) {
497 type.nullable = accept (TokenType.INTERR);
501 // array brackets in types are read from right to left,
502 // this is more logical, especially when nullable arrays
503 // or pointers are involved
504 while (accept (TokenType.OPEN_BRACKET)) {
505 bool invalid_array = false;
506 int array_rank = 0;
507 do {
508 array_rank++;
509 // required for decision between expression and declaration statement
510 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
511 parse_expression ();
512 // only used for parsing, reject use as real type
513 invalid_array = true;
515 } while (accept (TokenType.COMMA));
516 expect (TokenType.CLOSE_BRACKET);
518 type.value_owned = inner_type_owned;
520 var array_type = new ArrayType (type, array_rank, get_src (begin));
521 array_type.nullable = accept (TokenType.INTERR);
522 array_type.invalid_syntax = invalid_array;
524 type = array_type;
527 if (accept (TokenType.OP_NEG)) {
528 Report.warning (get_last_src (), "obsolete syntax, types are non-null by default");
531 if (!owned_by_default) {
532 if (accept (TokenType.HASH)) {
533 if (!context.deprecated) {
534 Report.warning (get_last_src (), "deprecated syntax, use `owned` modifier");
536 value_owned = true;
540 if (type is PointerType) {
541 value_owned = false;
544 type.is_dynamic = is_dynamic;
545 type.value_owned = value_owned;
546 return type;
549 DataType? parse_inline_array_type (DataType? type) throws ParseError {
550 var begin = get_location ();
552 // inline-allocated array
553 if (type != null && accept (TokenType.OPEN_BRACKET)) {
554 Expression array_length = null;
556 if (current () != TokenType.CLOSE_BRACKET) {
557 array_length = parse_expression ();
559 expect (TokenType.CLOSE_BRACKET);
561 var array_type = new ArrayType (type, 1, get_src (begin));
562 array_type.inline_allocated = true;
563 if (array_length != null) {
564 array_type.fixed_length = true;
565 array_type.length = array_length;
567 array_type.value_owned = type.value_owned;
569 return array_type;
571 return type;
574 List<Expression> parse_argument_list () throws ParseError {
575 var list = new ArrayList<Expression> ();
576 if (current () != TokenType.CLOSE_PARENS) {
577 do {
578 list.add (parse_argument ());
579 } while (accept (TokenType.COMMA));
581 return list;
584 Expression parse_argument () throws ParseError {
585 var begin = get_location ();
587 if (accept (TokenType.REF)) {
588 var inner = parse_expression ();
589 return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
590 } else if (accept (TokenType.OUT)) {
591 var inner = parse_expression ();
592 return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
593 } else {
594 var expr = parse_expression ();
595 var ma = expr as MemberAccess;
596 if (ma != null && ma.inner == null && accept (TokenType.COLON)) {
597 // named argument
598 expr = parse_expression ();
599 return new NamedArgument (ma.member_name, expr, get_src (begin));
600 } else {
601 return expr;
606 Expression parse_primary_expression () throws ParseError {
607 var begin = get_location ();
609 Expression expr;
611 switch (current ()) {
612 case TokenType.TRUE:
613 case TokenType.FALSE:
614 case TokenType.INTEGER_LITERAL:
615 case TokenType.REAL_LITERAL:
616 case TokenType.CHARACTER_LITERAL:
617 case TokenType.STRING_LITERAL:
618 case TokenType.REGEX_LITERAL:
619 case TokenType.TEMPLATE_STRING_LITERAL:
620 case TokenType.VERBATIM_STRING_LITERAL:
621 case TokenType.NULL:
622 expr = parse_literal ();
623 break;
624 case TokenType.OPEN_BRACE:
625 expr = parse_initializer ();
626 break;
627 case TokenType.OPEN_BRACKET:
628 expr = parse_simple_name ();
629 break;
630 case TokenType.OPEN_PARENS:
631 expr = parse_tuple ();
632 break;
633 case TokenType.OPEN_TEMPLATE:
634 expr = parse_template ();
635 break;
636 case TokenType.OPEN_REGEX_LITERAL:
637 expr = parse_regex_literal ();
638 break;
639 case TokenType.THIS:
640 expr = parse_this_access ();
641 break;
642 case TokenType.BASE:
643 expr = parse_base_access ();
644 break;
645 case TokenType.NEW:
646 expr = parse_object_or_array_creation_expression ();
647 break;
648 case TokenType.YIELD:
649 expr = parse_yield_expression ();
650 break;
651 case TokenType.SIZEOF:
652 expr = parse_sizeof_expression ();
653 break;
654 case TokenType.TYPEOF:
655 expr = parse_typeof_expression ();
656 break;
657 default:
658 expr = parse_simple_name ();
659 break;
662 // process primary expressions that start with an inner primary expression
663 bool found = true;
664 while (found) {
665 switch (current ()) {
666 case TokenType.DOT:
667 expr = parse_member_access (begin, expr);
668 break;
669 case TokenType.OP_PTR:
670 expr = parse_pointer_member_access (begin, expr);
671 break;
672 case TokenType.OPEN_PARENS:
673 expr = parse_method_call (begin, expr);
674 break;
675 case TokenType.OPEN_BRACKET:
676 expr = parse_element_access (begin, expr);
677 break;
678 case TokenType.OP_INC:
679 expr = parse_post_increment_expression (begin, expr);
680 break;
681 case TokenType.OP_DEC:
682 expr = parse_post_decrement_expression (begin, expr);
683 break;
684 default:
685 found = false;
686 break;
690 return expr;
693 Expression parse_simple_name () throws ParseError {
694 var begin = get_location ();
695 string id = parse_identifier ();
696 bool qualified = false;
697 if (id == "global" && accept (TokenType.DOUBLE_COLON)) {
698 id = parse_identifier ();
699 qualified = true;
701 List<DataType> type_arg_list = parse_type_argument_list (true);
702 var expr = new MemberAccess (null, id, get_src (begin));
703 expr.qualified = qualified;
704 if (type_arg_list != null) {
705 foreach (DataType type_arg in type_arg_list) {
706 expr.add_type_argument (type_arg);
709 return expr;
712 Expression parse_tuple () throws ParseError {
713 var begin = get_location ();
715 expect (TokenType.OPEN_PARENS);
716 var expr_list = new ArrayList<Expression> ();
717 if (current () != TokenType.CLOSE_PARENS) {
718 do {
719 expr_list.add (parse_expression ());
720 } while (accept (TokenType.COMMA));
722 expect (TokenType.CLOSE_PARENS);
723 if (expr_list.size != 1) {
724 var tuple = new Tuple (get_src (begin));
725 foreach (Expression expr in expr_list) {
726 tuple.add_expression (expr);
728 return tuple;
730 return expr_list.get (0);
733 Expression parse_template () throws ParseError {
734 var begin = get_location ();
735 var template = new Template ();
737 expect (TokenType.OPEN_TEMPLATE);
738 while (current () != TokenType.CLOSE_TEMPLATE) {
739 template.add_expression (parse_expression ());
740 expect (TokenType.COMMA);
742 expect (TokenType.CLOSE_TEMPLATE);
744 template.source_reference = get_src (begin);
745 return template;
748 Expression parse_regex_literal () throws ParseError {
749 expect (TokenType.OPEN_REGEX_LITERAL);
751 var expr = parse_literal ();
753 return expr;
756 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
757 expect (TokenType.DOT);
758 string id = parse_identifier ();
759 List<DataType> type_arg_list = parse_type_argument_list (true);
760 var expr = new MemberAccess (inner, id, get_src (begin));
761 if (type_arg_list != null) {
762 foreach (DataType type_arg in type_arg_list) {
763 expr.add_type_argument (type_arg);
766 return expr;
769 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
770 expect (TokenType.OP_PTR);
771 string id = parse_identifier ();
772 List<DataType> type_arg_list = parse_type_argument_list (true);
773 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
774 if (type_arg_list != null) {
775 foreach (DataType type_arg in type_arg_list) {
776 expr.add_type_argument (type_arg);
779 return expr;
782 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
783 expect (TokenType.OPEN_PARENS);
784 var arg_list = parse_argument_list ();
785 expect (TokenType.CLOSE_PARENS);
786 var init_list = parse_object_initializer ();
788 if (init_list.size > 0 && inner is MemberAccess) {
789 // struct creation expression
790 var member = (MemberAccess) inner;
791 member.creation_member = true;
793 var expr = new ObjectCreationExpression (member, get_src (begin));
794 expr.struct_creation = true;
795 foreach (Expression arg in arg_list) {
796 expr.add_argument (arg);
798 foreach (MemberInitializer initializer in init_list) {
799 expr.add_member_initializer (initializer);
801 return expr;
802 } else {
803 var expr = new MethodCall (inner, get_src (begin));
804 foreach (Expression arg in arg_list) {
805 expr.add_argument (arg);
807 return expr;
811 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
812 expect (TokenType.OPEN_BRACKET);
813 var index_list = parse_expression_list ();
814 Expression? stop = null;
815 if (index_list.size == 1 && accept (TokenType.COLON)) {
816 // slice expression
817 stop = parse_expression ();
819 expect (TokenType.CLOSE_BRACKET);
821 if (stop == null) {
822 var expr = new ElementAccess (inner, get_src (begin));
823 foreach (Expression index in index_list) {
824 expr.append_index (index);
826 return expr;
827 } else {
828 return new SliceExpression (inner, index_list[0], stop, get_src (begin));
832 List<Expression> parse_expression_list () throws ParseError {
833 var list = new ArrayList<Expression> ();
834 do {
835 list.add (parse_expression ());
836 } while (accept (TokenType.COMMA));
837 return list;
840 Expression parse_this_access () throws ParseError {
841 var begin = get_location ();
842 expect (TokenType.THIS);
843 return new MemberAccess (null, "this", get_src (begin));
846 Expression parse_base_access () throws ParseError {
847 var begin = get_location ();
848 expect (TokenType.BASE);
849 return new BaseAccess (get_src (begin));
852 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
853 expect (TokenType.OP_INC);
854 return new PostfixExpression (inner, true, get_src (begin));
857 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
858 expect (TokenType.OP_DEC);
859 return new PostfixExpression (inner, false, get_src (begin));
862 Expression parse_object_or_array_creation_expression () throws ParseError {
863 var begin = get_location ();
864 expect (TokenType.NEW);
866 if (is_inner_array_type ()) {
867 rollback (begin);
868 return parse_array_creation_expression ();
871 var member = parse_member_name ();
872 if (accept (TokenType.OPEN_PARENS)) {
873 var expr = parse_object_creation_expression (begin, member);
874 return expr;
875 } else {
876 bool is_pointer_type = false;
877 while (accept (TokenType.STAR)) {
878 is_pointer_type = true;
880 if (!is_pointer_type) {
881 accept (TokenType.INTERR);
883 if (accept (TokenType.OPEN_BRACKET)) {
884 rollback (begin);
885 var expr = parse_array_creation_expression ();
886 return expr;
887 } else {
888 throw new ParseError.SYNTAX ("expected ( or [");
893 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
894 member.creation_member = true;
895 var arg_list = parse_argument_list ();
896 expect (TokenType.CLOSE_PARENS);
897 var init_list = parse_object_initializer ();
899 var expr = new ObjectCreationExpression (member, get_src (begin));
900 foreach (Expression arg in arg_list) {
901 expr.add_argument (arg);
903 foreach (MemberInitializer initializer in init_list) {
904 expr.add_member_initializer (initializer);
906 return expr;
909 Expression parse_array_creation_expression () throws ParseError {
910 var begin = get_location ();
911 expect (TokenType.NEW);
913 bool inner_array_type = is_inner_array_type ();
914 if (inner_array_type) {
915 expect (TokenType.OPEN_PARENS);
916 expect (TokenType.UNOWNED);
919 var member = parse_member_name ();
920 DataType element_type = UnresolvedType.new_from_expression (member);
921 bool is_pointer_type = false;
922 while (accept (TokenType.STAR)) {
923 element_type = new PointerType (element_type, get_src (begin));
924 is_pointer_type = true;
926 if (!is_pointer_type) {
927 if (accept (TokenType.INTERR)) {
928 element_type.nullable = true;
932 if (inner_array_type) {
933 expect (TokenType.CLOSE_PARENS);
934 element_type.value_owned = false;
935 } else {
936 element_type.value_owned = true;
939 expect (TokenType.OPEN_BRACKET);
941 bool size_specified = false;
942 List<Expression> size_specifier_list = null;
943 bool first = true;
944 do {
945 if (!first) {
946 // array of arrays: new T[][42]
948 if (size_specified) {
949 throw new ParseError.SYNTAX ("size of inner arrays must not be specified in array creation expression");
952 element_type = new ArrayType (element_type, size_specifier_list.size, element_type.source_reference);
953 } else {
954 first = false;
957 size_specifier_list = new ArrayList<Expression> ();
958 do {
959 Expression size = null;
960 if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
961 size = parse_expression ();
962 size_specified = true;
964 size_specifier_list.add (size);
965 } while (accept (TokenType.COMMA));
966 expect (TokenType.CLOSE_BRACKET);
967 } while (accept (TokenType.OPEN_BRACKET));
969 InitializerList initializer = null;
970 if (current () == TokenType.OPEN_BRACE) {
971 initializer = parse_initializer ();
973 var expr = new ArrayCreationExpression (element_type, size_specifier_list.size, initializer, get_src (begin));
974 if (size_specified) {
975 foreach (Expression size in size_specifier_list) {
976 expr.append_size (size);
979 return expr;
982 List<MemberInitializer> parse_object_initializer () throws ParseError {
983 var list = new ArrayList<MemberInitializer> ();
984 if (accept (TokenType.OPEN_BRACE)) {
985 do {
986 list.add (parse_member_initializer ());
987 } while (accept (TokenType.COMMA));
988 expect (TokenType.CLOSE_BRACE);
990 return list;
993 MemberInitializer parse_member_initializer () throws ParseError {
994 var begin = get_location ();
995 string id = parse_identifier ();
996 expect (TokenType.ASSIGN);
997 var expr = parse_expression ();
999 return new MemberInitializer (id, expr, get_src (begin));
1002 Expression parse_yield_expression () throws ParseError {
1003 expect (TokenType.YIELD);
1005 var expr = parse_expression ();
1007 var call = expr as MethodCall;
1008 var object_creation = expr as ObjectCreationExpression;
1009 if (call == null && object_creation == null) {
1010 Report.error (expr.source_reference, "syntax error, expected method call");
1011 throw new ParseError.SYNTAX ("expected method call");
1014 if (call != null) {
1015 call.is_yield_expression = true;
1016 } else if (object_creation != null) {
1017 object_creation.is_yield_expression = true;
1020 return expr;
1023 Expression parse_sizeof_expression () throws ParseError {
1024 var begin = get_location ();
1025 expect (TokenType.SIZEOF);
1026 expect (TokenType.OPEN_PARENS);
1027 var type = parse_type (true, false);
1028 expect (TokenType.CLOSE_PARENS);
1030 return new SizeofExpression (type, get_src (begin));
1033 Expression parse_typeof_expression () throws ParseError {
1034 var begin = get_location ();
1035 expect (TokenType.TYPEOF);
1036 expect (TokenType.OPEN_PARENS);
1037 var type = parse_type (true, false);
1038 expect (TokenType.CLOSE_PARENS);
1040 return new TypeofExpression (type, get_src (begin));
1043 UnaryOperator get_unary_operator (TokenType token_type) {
1044 switch (token_type) {
1045 case TokenType.PLUS: return UnaryOperator.PLUS;
1046 case TokenType.MINUS: return UnaryOperator.MINUS;
1047 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
1048 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
1049 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
1050 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
1051 default: return UnaryOperator.NONE;
1055 Expression parse_unary_expression () throws ParseError {
1056 var begin = get_location ();
1057 var operator = get_unary_operator (current ());
1058 if (operator != UnaryOperator.NONE) {
1059 next ();
1060 var op = parse_unary_expression ();
1061 var lit = op as IntegerLiteral;
1062 if (lit != null) {
1063 if (operator == UnaryOperator.PLUS) {
1064 return lit;
1065 } else if (operator == UnaryOperator.MINUS) {
1066 return new IntegerLiteral ("-"+lit.value, get_src (begin));
1069 return new UnaryExpression (operator, op, get_src (begin));
1071 switch (current ()) {
1072 case TokenType.HASH:
1073 if (!context.deprecated) {
1074 Report.warning (get_last_src (), "deprecated syntax, use `(owned)` cast");
1076 next ();
1077 var op = parse_unary_expression ();
1078 return new ReferenceTransferExpression (op, get_src (begin));
1079 case TokenType.OPEN_PARENS:
1080 next ();
1081 switch (current ()) {
1082 case TokenType.UNOWNED:
1083 // inner array type
1084 break;
1085 case TokenType.OWNED:
1086 // (owned) foo
1087 next ();
1088 if (accept (TokenType.CLOSE_PARENS)) {
1089 var op = parse_unary_expression ();
1090 return new ReferenceTransferExpression (op, get_src (begin));
1092 break;
1093 case TokenType.VOID:
1094 case TokenType.DYNAMIC:
1095 case TokenType.OPEN_PARENS:
1096 case TokenType.IDENTIFIER:
1097 if (current () != TokenType.OPEN_PARENS || is_inner_array_type ()) {
1098 var type = parse_type (true, false);
1099 if (accept (TokenType.CLOSE_PARENS)) {
1100 // check follower to decide whether to create cast expression
1101 switch (current ()) {
1102 case TokenType.OP_NEG:
1103 case TokenType.TILDE:
1104 case TokenType.OPEN_PARENS:
1105 case TokenType.TRUE:
1106 case TokenType.FALSE:
1107 case TokenType.INTEGER_LITERAL:
1108 case TokenType.REAL_LITERAL:
1109 case TokenType.CHARACTER_LITERAL:
1110 case TokenType.STRING_LITERAL:
1111 case TokenType.TEMPLATE_STRING_LITERAL:
1112 case TokenType.VERBATIM_STRING_LITERAL:
1113 case TokenType.REGEX_LITERAL:
1114 case TokenType.NULL:
1115 case TokenType.THIS:
1116 case TokenType.BASE:
1117 case TokenType.NEW:
1118 case TokenType.YIELD:
1119 case TokenType.SIZEOF:
1120 case TokenType.TYPEOF:
1121 case TokenType.IDENTIFIER:
1122 case TokenType.PARAMS:
1123 var inner = parse_unary_expression ();
1124 return new CastExpression (inner, type, get_src (begin));
1125 case TokenType.STAR:
1126 next ();
1127 var op = parse_unary_expression ();
1128 var inner = new PointerIndirection (op, get_src (begin));
1129 return new CastExpression (inner, type, get_src (begin));
1130 case TokenType.BITWISE_AND:
1131 next ();
1132 var op = parse_unary_expression ();
1133 var inner = new AddressofExpression (op, get_src (begin));
1134 return new CastExpression (inner, type, get_src (begin));
1135 default:
1136 break;
1140 break;
1141 case TokenType.OP_NEG:
1142 next ();
1143 if (accept (TokenType.CLOSE_PARENS)) {
1144 // (!) non-null cast
1145 var inner = parse_unary_expression ();
1146 return new CastExpression.non_null (inner, get_src (begin));
1148 break;
1149 default:
1150 break;
1152 // no cast expression
1153 rollback (begin);
1154 break;
1155 case TokenType.STAR:
1156 next ();
1157 var op = parse_unary_expression ();
1158 return new PointerIndirection (op, get_src (begin));
1159 case TokenType.BITWISE_AND:
1160 next ();
1161 var op = parse_unary_expression ();
1162 return new AddressofExpression (op, get_src (begin));
1163 default:
1164 break;
1167 var expr = parse_primary_expression ();
1168 return expr;
1171 BinaryOperator get_binary_operator (TokenType token_type) {
1172 switch (token_type) {
1173 case TokenType.STAR: return BinaryOperator.MUL;
1174 case TokenType.DIV: return BinaryOperator.DIV;
1175 case TokenType.PERCENT: return BinaryOperator.MOD;
1176 case TokenType.PLUS: return BinaryOperator.PLUS;
1177 case TokenType.MINUS: return BinaryOperator.MINUS;
1178 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
1179 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
1180 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
1181 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
1182 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
1183 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
1184 default: return BinaryOperator.NONE;
1188 Expression parse_multiplicative_expression () throws ParseError {
1189 var begin = get_location ();
1190 var left = parse_unary_expression ();
1191 bool found = true;
1192 while (found) {
1193 var operator = get_binary_operator (current ());
1194 switch (operator) {
1195 case BinaryOperator.MUL:
1196 case BinaryOperator.DIV:
1197 case BinaryOperator.MOD:
1198 next ();
1199 var right = parse_unary_expression ();
1200 left = new BinaryExpression (operator, left, right, get_src (begin));
1201 break;
1202 default:
1203 found = false;
1204 break;
1207 return left;
1210 Expression parse_additive_expression () throws ParseError {
1211 var begin = get_location ();
1212 var left = parse_multiplicative_expression ();
1213 bool found = true;
1214 while (found) {
1215 var operator = get_binary_operator (current ());
1216 switch (operator) {
1217 case BinaryOperator.PLUS:
1218 case BinaryOperator.MINUS:
1219 next ();
1220 var right = parse_multiplicative_expression ();
1221 left = new BinaryExpression (operator, left, right, get_src (begin));
1222 break;
1223 default:
1224 found = false;
1225 break;
1228 return left;
1231 Expression parse_shift_expression () throws ParseError {
1232 var begin = get_location ();
1233 var left = parse_additive_expression ();
1234 bool found = true;
1235 while (found) {
1236 switch (current ()) {
1237 case TokenType.OP_SHIFT_LEFT:
1238 next ();
1239 var right = parse_additive_expression ();
1240 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1241 break;
1242 // don't use OP_SHIFT_RIGHT to support >> for nested generics
1243 case TokenType.OP_GT:
1244 char* first_gt_pos = tokens[index].begin.pos;
1245 next ();
1246 // only accept >> when there is no space between the two > signs
1247 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1248 next ();
1249 var right = parse_additive_expression ();
1250 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1251 } else {
1252 prev ();
1253 found = false;
1255 break;
1256 default:
1257 found = false;
1258 break;
1261 return left;
1264 Expression parse_relational_expression () throws ParseError {
1265 var begin = get_location ();
1266 var left = parse_shift_expression ();
1268 bool first = true;
1269 bool found = true;
1270 while (found) {
1271 var operator = get_binary_operator (current ());
1272 switch (operator) {
1273 case BinaryOperator.LESS_THAN:
1274 case BinaryOperator.LESS_THAN_OR_EQUAL:
1275 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1276 next ();
1277 var right = parse_shift_expression ();
1278 if (first) {
1279 left = new BinaryExpression (operator, left, right, get_src (begin));
1280 } else {
1281 left = new BinaryExpression.chained (operator, left, right, get_src (begin));
1283 first = false;
1284 break;
1285 case BinaryOperator.GREATER_THAN:
1286 next ();
1287 // ignore >> and >>= (two tokens due to generics)
1288 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1289 var right = parse_shift_expression ();
1290 if (first) {
1291 left = new BinaryExpression (operator, left, right, get_src (begin));
1292 } else {
1293 left = new BinaryExpression.chained (operator, left, right, get_src (begin));
1295 first = false;
1296 } else {
1297 prev ();
1298 found = false;
1300 break;
1301 default:
1302 switch (current ()) {
1303 case TokenType.IS:
1304 next ();
1305 var type = parse_type (true, false);
1306 left = new TypeCheck (left, type, get_src (begin));
1307 break;
1308 case TokenType.AS:
1309 next ();
1310 var type = parse_type (true, false);
1311 left = new CastExpression.silent (left, type, get_src (begin));
1312 break;
1313 default:
1314 found = false;
1315 break;
1317 break;
1320 return left;
1323 Expression parse_equality_expression () throws ParseError {
1324 var begin = get_location ();
1325 var left = parse_relational_expression ();
1326 bool found = true;
1327 while (found) {
1328 var operator = get_binary_operator (current ());
1329 switch (operator) {
1330 case BinaryOperator.EQUALITY:
1331 case BinaryOperator.INEQUALITY:
1332 next ();
1333 var right = parse_relational_expression ();
1334 left = new BinaryExpression (operator, left, right, get_src (begin));
1335 break;
1336 default:
1337 found = false;
1338 break;
1341 return left;
1344 Expression parse_and_expression () throws ParseError {
1345 var begin = get_location ();
1346 var left = parse_equality_expression ();
1347 while (accept (TokenType.BITWISE_AND)) {
1348 var right = parse_equality_expression ();
1349 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1351 return left;
1354 Expression parse_exclusive_or_expression () throws ParseError {
1355 var begin = get_location ();
1356 var left = parse_and_expression ();
1357 while (accept (TokenType.CARRET)) {
1358 var right = parse_and_expression ();
1359 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1361 return left;
1364 Expression parse_inclusive_or_expression () throws ParseError {
1365 var begin = get_location ();
1366 var left = parse_exclusive_or_expression ();
1367 while (accept (TokenType.BITWISE_OR)) {
1368 var right = parse_exclusive_or_expression ();
1369 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1371 return left;
1374 Expression parse_in_expression () throws ParseError {
1375 var begin = get_location ();
1376 var left = parse_inclusive_or_expression ();
1377 while (accept (TokenType.IN)) {
1378 var right = parse_inclusive_or_expression ();
1379 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1381 return left;
1384 Expression parse_conditional_and_expression () throws ParseError {
1385 var begin = get_location ();
1386 var left = parse_in_expression ();
1387 while (accept (TokenType.OP_AND)) {
1388 var right = parse_in_expression ();
1389 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1391 return left;
1394 Expression parse_conditional_or_expression () throws ParseError {
1395 var begin = get_location ();
1396 var left = parse_conditional_and_expression ();
1397 while (accept (TokenType.OP_OR)) {
1398 var right = parse_conditional_and_expression ();
1399 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1401 return left;
1404 Expression parse_coalescing_expression () throws ParseError {
1405 var begin = get_location ();
1406 var left = parse_conditional_or_expression ();
1407 if (accept (TokenType.OP_COALESCING)) {
1408 var right = parse_coalescing_expression ();
1409 return new BinaryExpression (BinaryOperator.COALESCE, left, right, get_src (begin));
1410 } else {
1411 return left;
1415 Expression parse_conditional_expression () throws ParseError {
1416 var begin = get_location ();
1417 var condition = parse_coalescing_expression ();
1418 if (accept (TokenType.INTERR)) {
1419 var true_expr = parse_expression ();
1420 expect (TokenType.COLON);
1421 var false_expr = parse_expression ();
1422 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1423 } else {
1424 return condition;
1428 Parameter parse_lambda_parameter () throws ParseError {
1429 var begin = get_location ();
1430 var direction = ParameterDirection.IN;
1431 if (accept (TokenType.OUT)) {
1432 direction = ParameterDirection.OUT;
1433 } else if (accept (TokenType.REF)) {
1434 direction = ParameterDirection.REF;
1437 string id = parse_identifier ();
1439 var param = new Parameter (id, null, get_src (begin));
1440 param.direction = direction;
1441 return param;
1444 Expression parse_lambda_expression () throws ParseError {
1445 var begin = get_location ();
1446 List<Parameter> params = new ArrayList<Parameter> ();
1447 if (accept (TokenType.OPEN_PARENS)) {
1448 if (current () != TokenType.CLOSE_PARENS) {
1449 do {
1450 params.add (parse_lambda_parameter ());
1451 } while (accept (TokenType.COMMA));
1453 expect (TokenType.CLOSE_PARENS);
1454 } else {
1455 params.add (parse_lambda_parameter ());
1457 expect (TokenType.LAMBDA);
1459 LambdaExpression lambda;
1460 if (current () == TokenType.OPEN_BRACE) {
1461 var block = parse_block ();
1462 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1463 } else {
1464 var expr = parse_expression ();
1465 lambda = new LambdaExpression (expr, get_src (begin));
1467 foreach (var param in params) {
1468 lambda.add_parameter (param);
1470 return lambda;
1473 AssignmentOperator get_assignment_operator (TokenType token_type) {
1474 switch (token_type) {
1475 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1476 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1477 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1478 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1479 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1480 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1481 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1482 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1483 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1484 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1485 default: return AssignmentOperator.NONE;
1489 Expression parse_expression () throws ParseError {
1490 if (is_lambda_expression ()) {
1491 return parse_lambda_expression ();
1494 var begin = get_location ();
1496 Expression expr = parse_conditional_expression ();
1498 while (true) {
1499 var operator = get_assignment_operator (current ());
1500 if (operator != AssignmentOperator.NONE) {
1501 next ();
1502 var rhs = parse_expression ();
1503 expr = new Assignment (expr, rhs, operator, get_src (begin));
1504 } else if (current () == TokenType.OP_GT) { // >>=
1505 char* first_gt_pos = tokens[index].begin.pos;
1506 next ();
1507 // only accept >>= when there is no space between the two > signs
1508 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1509 next ();
1510 var rhs = parse_expression ();
1511 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1512 } else {
1513 prev ();
1514 break;
1516 } else {
1517 break;
1521 return expr;
1524 void parse_statements (Block block) throws ParseError {
1525 while (current () != TokenType.CLOSE_BRACE
1526 && current () != TokenType.CASE
1527 && current () != TokenType.DEFAULT
1528 && current () != TokenType.EOF) {
1529 try {
1530 Statement stmt = null;
1531 bool is_decl = false;
1533 comment = scanner.pop_comment ();
1534 switch (current ()) {
1535 case TokenType.OPEN_BRACE:
1536 stmt = parse_block ();
1537 break;
1538 case TokenType.SEMICOLON:
1539 stmt = parse_empty_statement ();
1540 break;
1541 case TokenType.IF:
1542 stmt = parse_if_statement ();
1543 break;
1544 case TokenType.SWITCH:
1545 stmt = parse_switch_statement ();
1546 break;
1547 case TokenType.WHILE:
1548 stmt = parse_while_statement ();
1549 break;
1550 case TokenType.DO:
1551 stmt = parse_do_statement ();
1552 break;
1553 case TokenType.FOR:
1554 stmt = parse_for_statement ();
1555 break;
1556 case TokenType.FOREACH:
1557 stmt = parse_foreach_statement ();
1558 break;
1559 case TokenType.BREAK:
1560 stmt = parse_break_statement ();
1561 break;
1562 case TokenType.CONTINUE:
1563 stmt = parse_continue_statement ();
1564 break;
1565 case TokenType.RETURN:
1566 stmt = parse_return_statement ();
1567 break;
1568 case TokenType.YIELD:
1569 stmt = parse_yield_statement ();
1570 break;
1571 case TokenType.THROW:
1572 stmt = parse_throw_statement ();
1573 break;
1574 case TokenType.TRY:
1575 stmt = parse_try_statement ();
1576 break;
1577 case TokenType.LOCK:
1578 stmt = parse_lock_statement ();
1579 break;
1580 case TokenType.UNLOCK:
1581 stmt = parse_unlock_statement ();
1582 break;
1583 case TokenType.DELETE:
1584 stmt = parse_delete_statement ();
1585 break;
1586 case TokenType.VAR:
1587 is_decl = true;
1588 parse_local_variable_declarations (block);
1589 break;
1590 case TokenType.CONST:
1591 is_decl = true;
1592 parse_local_constant_declarations (block);
1593 break;
1594 case TokenType.OP_INC:
1595 case TokenType.OP_DEC:
1596 case TokenType.BASE:
1597 case TokenType.THIS:
1598 case TokenType.STAR:
1599 case TokenType.NEW:
1600 stmt = parse_expression_statement ();
1601 break;
1602 default:
1603 bool is_expr = is_expression ();
1604 if (is_expr) {
1605 stmt = parse_expression_statement ();
1606 } else {
1607 is_decl = true;
1608 parse_local_variable_declarations (block);
1610 break;
1613 if (!is_decl) {
1614 block.add_statement (stmt);
1616 } catch (ParseError e) {
1617 report_parse_error (e);
1618 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1619 // beginning of next declaration or end of file reached
1620 // return what we have so far
1621 break;
1627 bool is_expression () throws ParseError {
1628 if (current () == TokenType.OPEN_PARENS) {
1629 return !is_inner_array_type ();
1632 var begin = get_location ();
1634 // decide between declaration and expression statement
1635 skip_type ();
1636 switch (current ()) {
1637 // invocation expression
1638 case TokenType.OPEN_PARENS:
1639 // postfix increment
1640 case TokenType.OP_INC:
1641 // postfix decrement
1642 case TokenType.OP_DEC:
1643 // assignments
1644 case TokenType.ASSIGN:
1645 case TokenType.ASSIGN_ADD:
1646 case TokenType.ASSIGN_BITWISE_AND:
1647 case TokenType.ASSIGN_BITWISE_OR:
1648 case TokenType.ASSIGN_BITWISE_XOR:
1649 case TokenType.ASSIGN_DIV:
1650 case TokenType.ASSIGN_MUL:
1651 case TokenType.ASSIGN_PERCENT:
1652 case TokenType.ASSIGN_SHIFT_LEFT:
1653 case TokenType.ASSIGN_SUB:
1654 case TokenType.OP_GT: // >>=
1655 // member access
1656 case TokenType.DOT:
1657 // pointer member access
1658 case TokenType.OP_PTR:
1659 rollback (begin);
1660 return true;
1661 default:
1662 rollback (begin);
1663 return false;
1667 bool is_lambda_expression () {
1668 var begin = get_location ();
1670 switch (current ()) {
1671 case TokenType.OUT:
1672 case TokenType.REF:
1673 next ();
1674 if (accept (TokenType.IDENTIFIER) && accept (TokenType.LAMBDA)) {
1675 rollback (begin);
1676 return true;
1678 break;
1679 case TokenType.IDENTIFIER:
1680 next ();
1681 if (accept (TokenType.LAMBDA)) {
1682 rollback (begin);
1683 return true;
1685 break;
1686 case TokenType.OPEN_PARENS:
1687 next ();
1688 if (current () != TokenType.CLOSE_PARENS) {
1689 do {
1690 if (current () == TokenType.OUT || current () == TokenType.REF) {
1691 next ();
1693 if (!accept (TokenType.IDENTIFIER)) {
1694 rollback (begin);
1695 return false;
1697 } while (accept (TokenType.COMMA));
1699 if (accept (TokenType.CLOSE_PARENS) && accept (TokenType.LAMBDA)) {
1700 rollback (begin);
1701 return true;
1703 break;
1706 rollback (begin);
1707 return false;
1710 Block parse_embedded_statement (string statement_name, bool accept_empty_body = true) throws ParseError {
1711 if (current () == TokenType.OPEN_BRACE) {
1712 var block = parse_block ();
1713 return block;
1716 comment = scanner.pop_comment ();
1718 var block = new Block (get_src (get_location ()));
1720 var stmt = parse_embedded_statement_without_block (statement_name, accept_empty_body);
1721 block.add_statement (stmt);
1723 return block;
1727 Statement parse_embedded_statement_without_block (string statement_name, bool accept_empty_body) throws ParseError {
1728 switch (current ()) {
1729 case TokenType.SEMICOLON:
1730 if (!accept_empty_body) {
1731 Report.warning (get_current_src (), "%s-statement without body".printf (statement_name));
1733 return parse_empty_statement ();
1734 case TokenType.IF: return parse_if_statement ();
1735 case TokenType.SWITCH: return parse_switch_statement ();
1736 case TokenType.WHILE: return parse_while_statement ();
1737 case TokenType.DO: return parse_do_statement ();
1738 case TokenType.FOR: return parse_for_statement ();
1739 case TokenType.FOREACH: return parse_foreach_statement ();
1740 case TokenType.BREAK: return parse_break_statement ();
1741 case TokenType.CONTINUE: return parse_continue_statement ();
1742 case TokenType.RETURN: return parse_return_statement ();
1743 case TokenType.YIELD: return parse_yield_statement ();
1744 case TokenType.THROW: return parse_throw_statement ();
1745 case TokenType.TRY: return parse_try_statement ();
1746 case TokenType.LOCK: return parse_lock_statement ();
1747 case TokenType.UNLOCK: return parse_unlock_statement ();
1748 case TokenType.DELETE: return parse_delete_statement ();
1749 case TokenType.VAR:
1750 case TokenType.CONST:
1751 throw new ParseError.SYNTAX ("embedded statement cannot be declaration ");
1752 case TokenType.OP_INC:
1753 case TokenType.OP_DEC:
1754 case TokenType.BASE:
1755 case TokenType.THIS:
1756 case TokenType.OPEN_PARENS:
1757 case TokenType.STAR:
1758 case TokenType.NEW:
1759 return parse_expression_statement ();
1760 default:
1761 if (is_expression ()) {
1762 return parse_expression_statement ();
1763 } else {
1764 throw new ParseError.SYNTAX ("embedded statement cannot be declaration");
1769 Block parse_block () throws ParseError {
1770 var begin = get_location ();
1771 expect (TokenType.OPEN_BRACE);
1772 var block = new Block (get_src (begin));
1773 parse_statements (block);
1774 if (!accept (TokenType.CLOSE_BRACE)) {
1775 // only report error if it's not a secondary error
1776 if (context.report.get_errors () == 0) {
1777 Report.error (get_current_src (), "expected `}'");
1781 block.source_reference.end = get_current_src ().end;
1783 return block;
1786 Statement parse_empty_statement () throws ParseError {
1787 var begin = get_location ();
1788 expect (TokenType.SEMICOLON);
1789 return new EmptyStatement (get_src (begin));
1792 void parse_local_variable_declarations (Block block) throws ParseError {
1793 DataType variable_type;
1794 if (accept (TokenType.VAR)) {
1795 variable_type = null;
1796 } else {
1797 variable_type = parse_type (true, true);
1799 do {
1800 if (variable_type == null && accept (TokenType.OPEN_PARENS)) {
1801 // tuple
1802 var begin = get_location ();
1804 string[] identifiers = {};
1805 do {
1806 identifiers += parse_identifier ();
1807 } while (accept (TokenType.COMMA));
1808 expect (TokenType.CLOSE_PARENS);
1810 expect (TokenType.ASSIGN);
1811 var tuple = parse_expression ();
1812 var tuple_local = new LocalVariable (null, CodeNode.get_temp_name (), tuple, get_src (begin));
1813 block.add_statement (new DeclarationStatement (tuple_local, tuple_local.source_reference));
1815 for (int i = 0; i < identifiers.length; i++) {
1816 var temp_access = new MemberAccess.simple (tuple_local.name, tuple_local.source_reference);
1817 var ea = new ElementAccess (temp_access, tuple_local.source_reference);
1818 ea.append_index (new IntegerLiteral (i.to_string ()));
1819 var local = new LocalVariable (null, identifiers[i], ea, tuple_local.source_reference);
1820 block.add_statement (new DeclarationStatement (local, local.source_reference));
1823 continue;
1826 DataType type_copy = null;
1827 if (variable_type != null) {
1828 type_copy = variable_type.copy ();
1830 var local = parse_local_variable (type_copy);
1831 block.add_statement (new DeclarationStatement (local, local.source_reference));
1832 } while (accept (TokenType.COMMA));
1833 expect (TokenType.SEMICOLON);
1836 LocalVariable parse_local_variable (DataType? variable_type) throws ParseError {
1837 var begin = get_location ();
1838 string id = parse_identifier ();
1840 var type = parse_inline_array_type (variable_type);
1842 Expression initializer = null;
1843 if (accept (TokenType.ASSIGN)) {
1844 initializer = parse_expression ();
1846 return new LocalVariable (type, id, initializer, get_src (begin));
1849 void parse_local_constant_declarations (Block block) throws ParseError {
1850 expect (TokenType.CONST);
1851 var constant_type = parse_type (false, false);
1853 // constant arrays don't own their element
1854 var array_type = constant_type as ArrayType;
1855 if (array_type != null) {
1856 array_type.element_type.value_owned = false;
1859 do {
1860 DataType type_copy = constant_type.copy ();
1861 var local = parse_local_constant (type_copy);
1862 block.add_statement (new DeclarationStatement (local, local.source_reference));
1863 block.add_local_constant (local);
1864 local.active = false;
1865 } while (accept (TokenType.COMMA));
1866 expect (TokenType.SEMICOLON);
1869 Constant parse_local_constant (DataType constant_type) throws ParseError {
1870 var begin = get_location ();
1871 string id = parse_identifier ();
1873 var type = parse_inline_array_type (constant_type);
1875 expect (TokenType.ASSIGN);
1876 var initializer = parse_expression ();
1878 return new Constant (id, type, initializer, get_src (begin));
1881 Statement parse_expression_statement () throws ParseError {
1882 var begin = get_location ();
1883 var expr = parse_statement_expression ();
1884 expect (TokenType.SEMICOLON);
1885 return new ExpressionStatement (expr, get_src (begin));
1888 Expression parse_statement_expression () throws ParseError {
1889 // invocation expression, assignment,
1890 // or pre/post increment/decrement expression
1891 var expr = parse_expression ();
1892 return expr;
1895 Statement parse_if_statement () throws ParseError {
1896 var begin = get_location ();
1897 expect (TokenType.IF);
1898 expect (TokenType.OPEN_PARENS);
1899 var condition = parse_expression ();
1900 expect (TokenType.CLOSE_PARENS);
1901 var src = get_src (begin);
1902 var true_stmt = parse_embedded_statement ("if", false);
1903 Block false_stmt = null;
1904 if (accept (TokenType.ELSE)) {
1905 false_stmt = parse_embedded_statement ("else", false);
1907 return new IfStatement (condition, true_stmt, false_stmt, src);
1910 Statement parse_switch_statement () throws ParseError {
1911 var begin = get_location ();
1912 expect (TokenType.SWITCH);
1913 expect (TokenType.OPEN_PARENS);
1914 var condition = parse_expression ();
1915 expect (TokenType.CLOSE_PARENS);
1916 var stmt = new SwitchStatement (condition, get_src (begin));
1917 expect (TokenType.OPEN_BRACE);
1918 while (current () != TokenType.CLOSE_BRACE) {
1919 begin = get_location ();
1920 var section = new SwitchSection (get_src (begin));
1921 do {
1922 if (accept (TokenType.CASE)) {
1923 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
1924 while (current () == TokenType.COMMA) {
1925 expect (TokenType.COMMA);
1926 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
1928 } else {
1929 expect (TokenType.DEFAULT);
1930 section.add_label (new SwitchLabel.with_default (get_src (begin)));
1932 expect (TokenType.COLON);
1933 } while (current () == TokenType.CASE || current () == TokenType.DEFAULT);
1934 parse_statements (section);
1935 stmt.add_section (section);
1937 expect (TokenType.CLOSE_BRACE);
1938 return stmt;
1941 Statement parse_while_statement () throws ParseError {
1942 var begin = get_location ();
1943 expect (TokenType.WHILE);
1944 expect (TokenType.OPEN_PARENS);
1945 var condition = parse_expression ();
1946 expect (TokenType.CLOSE_PARENS);
1947 var body = parse_embedded_statement ("while");
1948 return new WhileStatement (condition, body, get_src (begin));
1951 Statement parse_do_statement () throws ParseError {
1952 var begin = get_location ();
1953 expect (TokenType.DO);
1954 var body = parse_embedded_statement ("do");
1955 expect (TokenType.WHILE);
1956 expect (TokenType.OPEN_PARENS);
1957 var condition = parse_expression ();
1958 expect (TokenType.CLOSE_PARENS);
1959 expect (TokenType.SEMICOLON);
1960 return new DoStatement (body, condition, get_src (begin));
1963 Statement parse_for_statement () throws ParseError {
1964 var begin = get_location ();
1965 Block block = null;
1966 expect (TokenType.FOR);
1967 expect (TokenType.OPEN_PARENS);
1968 var initializer_list = new ArrayList<Expression> ();
1969 if (!accept (TokenType.SEMICOLON)) {
1970 bool is_expr;
1971 switch (current ()) {
1972 case TokenType.VAR:
1973 is_expr = false;
1974 break;
1975 case TokenType.OP_INC:
1976 case TokenType.OP_DEC:
1977 is_expr = true;
1978 break;
1979 default:
1980 is_expr = is_expression ();
1981 break;
1984 if (is_expr) {
1985 do {
1986 initializer_list.add (parse_statement_expression ());
1987 } while (accept (TokenType.COMMA));
1988 expect (TokenType.SEMICOLON);
1989 } else {
1990 // variable declaration in initializer
1991 block = new Block (get_src (begin));
1992 parse_local_variable_declarations (block);
1995 Expression condition = null;
1996 if (current () != TokenType.SEMICOLON) {
1997 condition = parse_expression ();
1999 expect (TokenType.SEMICOLON);
2000 var iterator_list = new ArrayList<Expression> ();
2001 if (current () != TokenType.CLOSE_PARENS) {
2002 do {
2003 iterator_list.add (parse_statement_expression ());
2004 } while (accept (TokenType.COMMA));
2006 expect (TokenType.CLOSE_PARENS);
2007 var src = get_src (begin);
2008 var body = parse_embedded_statement ("for");
2009 var stmt = new ForStatement (condition, body, src);
2010 foreach (Expression init in initializer_list) {
2011 stmt.add_initializer (init);
2013 foreach (Expression iter in iterator_list) {
2014 stmt.add_iterator (iter);
2016 if (block != null) {
2017 block.add_statement (stmt);
2018 return block;
2019 } else {
2020 return stmt;
2024 Statement parse_foreach_statement () throws ParseError {
2025 var begin = get_location ();
2026 expect (TokenType.FOREACH);
2027 expect (TokenType.OPEN_PARENS);
2028 DataType type = null;
2029 if (!accept (TokenType.VAR)) {
2030 type = parse_type (true, true);
2031 if (accept (TokenType.IN)) {
2032 Report.error (type.source_reference, "syntax error, expected var or type");
2033 throw new ParseError.SYNTAX ("expected var or type");
2036 string id = parse_identifier ();
2037 expect (TokenType.IN);
2038 var collection = parse_expression ();
2039 expect (TokenType.CLOSE_PARENS);
2040 var src = get_src (begin);
2041 var body = parse_embedded_statement ("foreach");
2042 return new ForeachStatement (type, id, collection, body, src);
2045 Statement parse_break_statement () throws ParseError {
2046 var begin = get_location ();
2047 expect (TokenType.BREAK);
2048 expect (TokenType.SEMICOLON);
2049 return new BreakStatement (get_src (begin));
2052 Statement parse_continue_statement () throws ParseError {
2053 var begin = get_location ();
2054 expect (TokenType.CONTINUE);
2055 expect (TokenType.SEMICOLON);
2056 return new ContinueStatement (get_src (begin));
2059 Statement parse_return_statement () throws ParseError {
2060 var begin = get_location ();
2061 expect (TokenType.RETURN);
2062 Expression expr = null;
2063 if (current () != TokenType.SEMICOLON) {
2064 expr = parse_expression ();
2066 expect (TokenType.SEMICOLON);
2067 return new ReturnStatement (expr, get_src (begin));
2070 Statement parse_yield_statement () throws ParseError {
2071 var begin = get_location ();
2072 expect (TokenType.YIELD);
2073 if (current () != TokenType.SEMICOLON && current () != TokenType.RETURN) {
2074 // yield expression
2075 prev ();
2076 return parse_expression_statement ();
2078 Expression expr = null;
2079 if (accept (TokenType.RETURN)) {
2080 expr = parse_expression ();
2082 expect (TokenType.SEMICOLON);
2083 return new YieldStatement (expr, get_src (begin));
2086 Statement parse_throw_statement () throws ParseError {
2087 var begin = get_location ();
2088 expect (TokenType.THROW);
2089 var expr = parse_expression ();
2090 expect (TokenType.SEMICOLON);
2091 return new ThrowStatement (expr, get_src (begin));
2094 Statement parse_try_statement () throws ParseError {
2095 var begin = get_location ();
2096 expect (TokenType.TRY);
2097 var try_block = parse_block ();
2098 Block finally_clause = null;
2099 var catch_clauses = new ArrayList<CatchClause> ();
2100 if (current () == TokenType.CATCH) {
2101 parse_catch_clauses (catch_clauses);
2102 if (current () == TokenType.FINALLY) {
2103 finally_clause = parse_finally_clause ();
2105 } else {
2106 finally_clause = parse_finally_clause ();
2108 var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
2109 foreach (CatchClause clause in catch_clauses) {
2110 stmt.add_catch_clause (clause);
2112 return stmt;
2115 void parse_catch_clauses (List<CatchClause> catch_clauses) throws ParseError {
2116 while (accept (TokenType.CATCH)) {
2117 var begin = get_location ();
2118 DataType type = null;
2119 string id = null;
2120 if (accept (TokenType.OPEN_PARENS)) {
2121 type = parse_type (true, true);
2122 id = parse_identifier ();
2123 expect (TokenType.CLOSE_PARENS);
2125 var block = parse_block ();
2126 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
2130 Block parse_finally_clause () throws ParseError {
2131 expect (TokenType.FINALLY);
2132 var block = parse_block ();
2133 return block;
2136 Statement parse_lock_statement () throws ParseError {
2137 var begin = get_location ();
2138 expect (TokenType.LOCK);
2139 expect (TokenType.OPEN_PARENS);
2140 var expr = parse_expression ();
2141 expect (TokenType.CLOSE_PARENS);
2142 Block? stmt = null;
2143 if (current () != TokenType.SEMICOLON) {
2144 stmt = parse_embedded_statement ("lock", false);
2146 return new LockStatement (expr, stmt, get_src (begin));
2149 Statement parse_unlock_statement () throws ParseError {
2150 var begin = get_location ();
2151 expect (TokenType.UNLOCK);
2152 expect (TokenType.OPEN_PARENS);
2153 var expr = parse_expression ();
2154 expect (TokenType.CLOSE_PARENS);
2155 expect (TokenType.SEMICOLON);
2156 return new UnlockStatement (expr, get_src (begin));
2159 Statement parse_delete_statement () throws ParseError {
2160 var begin = get_location ();
2161 expect (TokenType.DELETE);
2162 var expr = parse_expression ();
2163 expect (TokenType.SEMICOLON);
2164 return new DeleteStatement (expr, get_src (begin));
2167 string parse_attribute_value () throws ParseError {
2168 switch (current ()) {
2169 case TokenType.NULL:
2170 case TokenType.TRUE:
2171 case TokenType.FALSE:
2172 case TokenType.INTEGER_LITERAL:
2173 case TokenType.REAL_LITERAL:
2174 case TokenType.STRING_LITERAL:
2175 next ();
2176 return get_last_string ();
2177 case TokenType.MINUS:
2178 next ();
2179 switch (current ()) {
2180 case TokenType.INTEGER_LITERAL:
2181 case TokenType.REAL_LITERAL:
2182 next ();
2183 return "-" + get_last_string ();
2184 default:
2185 throw new ParseError.SYNTAX ("expected number");
2187 default:
2188 throw new ParseError.SYNTAX ("expected literal");
2192 List<Attribute>? parse_attributes () throws ParseError {
2193 if (current () != TokenType.OPEN_BRACKET) {
2194 return null;
2196 var attrs = new ArrayList<Attribute> ();
2197 while (accept (TokenType.OPEN_BRACKET)) {
2198 do {
2199 var begin = get_location ();
2200 string id = parse_identifier ();
2201 var attr = new Attribute (id, get_src (begin));
2202 if (accept (TokenType.OPEN_PARENS)) {
2203 if (current () != TokenType.CLOSE_PARENS) {
2204 do {
2205 id = parse_identifier ();
2206 expect (TokenType.ASSIGN);
2207 attr.add_argument (id, parse_attribute_value ());
2208 } while (accept (TokenType.COMMA));
2210 expect (TokenType.CLOSE_PARENS);
2212 attrs.add (attr);
2213 } while (accept (TokenType.COMMA));
2214 expect (TokenType.CLOSE_BRACKET);
2216 return attrs;
2219 void set_attributes (CodeNode node, List<Attribute>? attributes) {
2220 if (attributes != null) {
2221 foreach (Attribute attr in (List<Attribute>) attributes) {
2222 if (node.get_attribute (attr.name) != null) {
2223 Report.error (attr.source_reference, "duplicate attribute `%s`".printf (attr.name));
2225 node.attributes.append (attr);
2230 void parse_main_block (Symbol parent) throws ParseError {
2231 var begin = get_location ();
2233 var method = new Method ("main", new VoidType (), get_src (begin));
2234 method.body = new Block (get_src (begin));
2235 parse_statements (method.body);
2236 if (current () != TokenType.EOF) {
2237 Report.error (get_current_src (), "expected end of file");
2240 method.body.source_reference.end = get_current_src ().end;
2242 if (!context.experimental) {
2243 Report.warning (method.source_reference, "main blocks are experimental");
2246 parent.add_method (method);
2249 void parse_declaration (Symbol parent, bool root = false) throws ParseError {
2250 comment = scanner.pop_comment ();
2251 var attrs = parse_attributes ();
2253 var begin = get_location ();
2255 TokenType last_keyword = current ();
2257 while (is_declaration_keyword (current ())) {
2258 last_keyword = current ();
2259 next ();
2262 switch (current ()) {
2263 case TokenType.CONSTRUCT:
2264 if (context.profile == Profile.GOBJECT) {
2265 rollback (begin);
2266 parse_constructor_declaration (parent, attrs);
2267 return;
2269 break;
2270 case TokenType.TILDE:
2271 rollback (begin);
2272 parse_destructor_declaration (parent, attrs);
2273 return;
2274 case TokenType.OPEN_BRACE:
2275 case TokenType.SEMICOLON:
2276 case TokenType.IF:
2277 case TokenType.SWITCH:
2278 case TokenType.WHILE:
2279 case TokenType.DO:
2280 case TokenType.FOR:
2281 case TokenType.FOREACH:
2282 case TokenType.BREAK:
2283 case TokenType.CONTINUE:
2284 case TokenType.RETURN:
2285 case TokenType.YIELD:
2286 case TokenType.THROW:
2287 case TokenType.TRY:
2288 case TokenType.LOCK:
2289 case TokenType.UNLOCK:
2290 case TokenType.DELETE:
2291 case TokenType.VAR:
2292 case TokenType.OP_INC:
2293 case TokenType.OP_DEC:
2294 case TokenType.BASE:
2295 case TokenType.THIS:
2296 case TokenType.STAR:
2297 case TokenType.NEW:
2298 // statement
2299 if (attrs != null) {
2300 // no attributes allowed before statements
2301 throw new ParseError.SYNTAX ("expected statement");
2303 if (!root) {
2304 throw new ParseError.SYNTAX ("statements outside blocks allowed only in root namespace");
2306 rollback (begin);
2307 parse_main_block (parent);
2308 return;
2309 default:
2310 if (root) {
2311 bool is_expr = is_expression ();
2312 if (is_expr) {
2313 rollback (begin);
2314 parse_main_block (parent);
2315 return;
2319 skip_type ();
2320 switch (current ()) {
2321 case TokenType.OPEN_BRACE:
2322 case TokenType.SEMICOLON:
2323 case TokenType.COLON:
2324 rollback (begin);
2325 switch (last_keyword) {
2326 case TokenType.CLASS:
2327 parse_class_declaration (parent, attrs);
2328 return;
2329 case TokenType.ENUM:
2330 parse_enum_declaration (parent, attrs);
2331 return;
2332 case TokenType.ERRORDOMAIN:
2333 parse_errordomain_declaration (parent, attrs);
2334 return;
2335 case TokenType.INTERFACE:
2336 parse_interface_declaration (parent, attrs);
2337 return;
2338 case TokenType.NAMESPACE:
2339 parse_namespace_declaration (parent, attrs);
2340 return;
2341 case TokenType.STRUCT:
2342 parse_struct_declaration (parent, attrs);
2343 return;
2344 default:
2345 break;
2347 break;
2348 case TokenType.OPEN_PARENS:
2349 rollback (begin);
2350 parse_creation_method_declaration (parent, attrs);
2351 return;
2352 default:
2353 skip_type (); // might contain type parameter list
2354 switch (current ()) {
2355 case TokenType.OPEN_PARENS:
2356 rollback (begin);
2357 switch (last_keyword) {
2358 case TokenType.DELEGATE:
2359 parse_delegate_declaration (parent, attrs);
2360 return;
2361 case TokenType.SIGNAL:
2362 parse_signal_declaration (parent, attrs);
2363 return;
2364 default:
2365 parse_method_declaration (parent, attrs);
2366 return;
2368 case TokenType.ASSIGN:
2369 case TokenType.SEMICOLON:
2370 rollback (begin);
2371 switch (last_keyword) {
2372 case TokenType.CONST:
2373 parse_constant_declaration (parent, attrs);
2374 return;
2375 default:
2376 parse_field_declaration (parent, attrs);
2377 return;
2379 case TokenType.OPEN_BRACE:
2380 case TokenType.THROWS:
2381 rollback (begin);
2382 parse_property_declaration (parent, attrs);
2383 return;
2384 default:
2385 break;
2387 break;
2389 break;
2392 rollback (begin);
2394 throw new ParseError.SYNTAX ("expected declaration");
2397 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
2398 if (!root) {
2399 expect (TokenType.OPEN_BRACE);
2401 while (current () != TokenType.CLOSE_BRACE && current () != TokenType.EOF) {
2402 try {
2403 parse_declaration (parent, (parent == context.root));
2404 } catch (ParseError e) {
2405 report_parse_error (e);
2406 int r;
2407 do {
2408 r = recover ();
2409 if (r == RecoveryState.STATEMENT_BEGIN) {
2410 next ();
2411 } else {
2412 break;
2414 } while (true);
2415 if (r == RecoveryState.EOF) {
2416 return;
2420 if (!root) {
2421 if (!accept (TokenType.CLOSE_BRACE)) {
2422 // only report error if it's not a secondary error
2423 if (context.report.get_errors () == 0) {
2424 Report.error (get_current_src (), "expected `}'");
2430 enum RecoveryState {
2431 EOF,
2432 DECLARATION_BEGIN,
2433 STATEMENT_BEGIN
2436 RecoveryState recover () {
2437 while (current () != TokenType.EOF) {
2438 switch (current ()) {
2439 case TokenType.ABSTRACT:
2440 case TokenType.CLASS:
2441 case TokenType.CONST:
2442 case TokenType.CONSTRUCT:
2443 case TokenType.DELEGATE:
2444 case TokenType.ENUM:
2445 case TokenType.ERRORDOMAIN:
2446 case TokenType.EXTERN:
2447 case TokenType.INLINE:
2448 case TokenType.INTERFACE:
2449 case TokenType.INTERNAL:
2450 case TokenType.NAMESPACE:
2451 case TokenType.NEW:
2452 case TokenType.OVERRIDE:
2453 case TokenType.PRIVATE:
2454 case TokenType.PROTECTED:
2455 case TokenType.PUBLIC:
2456 case TokenType.SEALED:
2457 case TokenType.SIGNAL:
2458 case TokenType.STATIC:
2459 case TokenType.STRUCT:
2460 case TokenType.VIRTUAL:
2461 case TokenType.VOLATILE:
2462 return RecoveryState.DECLARATION_BEGIN;
2463 case TokenType.BREAK:
2464 case TokenType.CONTINUE:
2465 case TokenType.DELETE:
2466 case TokenType.DO:
2467 case TokenType.FOR:
2468 case TokenType.FOREACH:
2469 case TokenType.IF:
2470 case TokenType.LOCK:
2471 case TokenType.RETURN:
2472 case TokenType.SWITCH:
2473 case TokenType.THROW:
2474 case TokenType.TRY:
2475 case TokenType.UNLOCK:
2476 case TokenType.VAR:
2477 case TokenType.WHILE:
2478 case TokenType.YIELD:
2479 return RecoveryState.STATEMENT_BEGIN;
2480 default:
2481 next ();
2482 break;
2485 return RecoveryState.EOF;
2488 void parse_namespace_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2489 var begin = get_location ();
2490 expect (TokenType.NAMESPACE);
2491 var sym = parse_symbol_name ();
2492 var ns = new Namespace (sym.name, get_src (begin));
2493 if (comment != null) {
2494 ns.add_comment (comment);
2495 comment = null;
2498 set_attributes (ns, attrs);
2500 expect (TokenType.OPEN_BRACE);
2502 var old_using_directives = scanner.source_file.current_using_directives;
2503 parse_using_directives (ns);
2505 parse_declarations (ns, true);
2507 scanner.source_file.current_using_directives = old_using_directives;
2509 if (!accept (TokenType.CLOSE_BRACE)) {
2510 // only report error if it's not a secondary error
2511 if (context.report.get_errors () == 0) {
2512 Report.error (get_current_src (), "expected `}'");
2516 Symbol result = ns;
2517 while (sym != null) {
2518 sym = sym.inner;
2520 Symbol next = (sym != null ? new Namespace (sym.name, ns.source_reference) : parent);
2521 next.add_namespace ((Namespace) result);
2522 result = next;
2526 void parse_using_directives (Namespace ns) throws ParseError {
2527 while (accept (TokenType.USING)) {
2528 do {
2529 var begin = get_location ();
2530 var sym = parse_symbol_name ();
2531 var ns_ref = new UsingDirective (sym, get_src (begin));
2532 scanner.source_file.add_using_directive (ns_ref);
2533 ns.add_using_directive (ns_ref);
2534 } while (accept (TokenType.COMMA));
2535 expect (TokenType.SEMICOLON);
2539 void parse_class_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2540 var begin = get_location ();
2541 var access = parse_access_modifier ();
2542 var flags = parse_type_declaration_modifiers ();
2543 expect (TokenType.CLASS);
2544 var sym = parse_symbol_name ();
2545 var type_param_list = parse_type_parameter_list ();
2546 var base_types = new ArrayList<DataType> ();
2547 if (accept (TokenType.COLON)) {
2548 do {
2549 base_types.add (parse_type (true, false));
2550 } while (accept (TokenType.COMMA));
2553 var cl = new Class (sym.name, get_src (begin), comment);
2554 cl.access = access;
2555 if (ModifierFlags.ABSTRACT in flags) {
2556 cl.is_abstract = true;
2558 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2559 cl.external = true;
2561 set_attributes (cl, attrs);
2562 foreach (TypeParameter type_param in type_param_list) {
2563 cl.add_type_parameter (type_param);
2565 foreach (DataType base_type in base_types) {
2566 cl.add_base_type (base_type);
2569 parse_declarations (cl);
2571 // ensure there is always a default construction method
2572 if (scanner.source_file.file_type == SourceFileType.SOURCE
2573 && cl.default_construction_method == null) {
2574 var m = new CreationMethod (cl.name, null, cl.source_reference);
2575 m.access = SymbolAccessibility.PUBLIC;
2576 m.body = new Block (cl.source_reference);
2577 cl.add_method (m);
2580 Symbol result = cl;
2581 while (sym != null) {
2582 sym = sym.inner;
2584 Symbol next = (sym != null ? new Namespace (sym.name, cl.source_reference) : parent);
2585 if (result is Namespace) {
2586 next.add_namespace ((Namespace) result);
2587 } else {
2588 next.add_class ((Class) result);
2590 result = next;
2594 void parse_constant_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2595 var begin = get_location ();
2596 var access = parse_access_modifier ();
2597 var flags = parse_member_declaration_modifiers ();
2598 expect (TokenType.CONST);
2599 var type = parse_type (false, false);
2600 string id = parse_identifier ();
2602 type = parse_inline_array_type (type);
2604 Expression initializer = null;
2605 if (accept (TokenType.ASSIGN)) {
2606 initializer = parse_expression ();
2608 expect (TokenType.SEMICOLON);
2610 // constant arrays don't own their element
2611 var array_type = type as ArrayType;
2612 if (array_type != null) {
2613 array_type.element_type.value_owned = false;
2616 var c = new Constant (id, type, initializer, get_src (begin), comment);
2617 c.access = access;
2618 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2619 c.external = true;
2621 if (ModifierFlags.NEW in flags) {
2622 c.hides = true;
2624 set_attributes (c, attrs);
2626 if (ModifierFlags.STATIC in flags) {
2627 Report.warning (c.source_reference, "the modifier `static' is not applicable to constants");
2630 parent.add_constant (c);
2633 void parse_field_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2634 var begin = get_location ();
2635 var access = parse_access_modifier ((parent is Struct) ? SymbolAccessibility.PUBLIC : SymbolAccessibility.PRIVATE);
2636 var flags = parse_member_declaration_modifiers ();
2637 var type = parse_type (true, true);
2638 string id = parse_identifier ();
2639 type = parse_inline_array_type (type);
2641 var f = new Field (id, type, null, get_src (begin), comment);
2642 f.access = access;
2644 set_attributes (f, attrs);
2645 if (ModifierFlags.STATIC in flags && ModifierFlags.CLASS in flags) {
2646 Report.error (f.source_reference, "only one of `static' or `class' may be specified");
2647 } else if (ModifierFlags.STATIC in flags) {
2648 f.binding = MemberBinding.STATIC;
2649 } else if (ModifierFlags.CLASS in flags) {
2650 f.binding = MemberBinding.CLASS;
2653 if (parent is Struct && f.access != SymbolAccessibility.PUBLIC && f.binding == MemberBinding.INSTANCE) {
2654 Report.warning (f.source_reference, "accessibility of struct fields can only be `public`");
2657 if (ModifierFlags.ABSTRACT in flags
2658 || ModifierFlags.VIRTUAL in flags
2659 || ModifierFlags.OVERRIDE in flags) {
2660 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2662 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2663 f.external = true;
2665 if (ModifierFlags.NEW in flags) {
2666 f.hides = true;
2668 if (accept (TokenType.ASSIGN)) {
2669 f.initializer = parse_expression ();
2671 expect (TokenType.SEMICOLON);
2673 parent.add_field (f);
2676 InitializerList parse_initializer () throws ParseError {
2677 var begin = get_location ();
2678 expect (TokenType.OPEN_BRACE);
2679 var initializer = new InitializerList (get_src (begin));
2680 while (current () != TokenType.CLOSE_BRACE) {
2681 var init = parse_argument ();
2682 initializer.append (init);
2684 if (!accept (TokenType.COMMA)) {
2685 break;
2688 expect (TokenType.CLOSE_BRACE);
2689 return initializer;
2692 void parse_method_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2693 var begin = get_location ();
2694 var access = parse_access_modifier ();
2695 var flags = parse_member_declaration_modifiers ();
2696 var type = parse_type (true, false);
2697 var sym = parse_symbol_name ();
2698 var type_param_list = parse_type_parameter_list ();
2699 var method = new Method (sym.name, type, get_src (begin), comment);
2700 if (sym.inner != null) {
2701 method.base_interface_type = new UnresolvedType.from_symbol (sym.inner, sym.inner.source_reference);
2703 method.access = access;
2704 set_attributes (method, attrs);
2705 foreach (TypeParameter type_param in type_param_list) {
2706 method.add_type_parameter (type_param);
2708 if (ModifierFlags.STATIC in flags && ModifierFlags.CLASS in flags) {
2709 Report.error (method.source_reference, "only one of `static' or `class' may be specified");
2710 } else if (ModifierFlags.STATIC in flags) {
2711 method.binding = MemberBinding.STATIC;
2712 } else if (ModifierFlags.CLASS in flags) {
2713 method.binding = MemberBinding.CLASS;
2715 if (ModifierFlags.ASYNC in flags) {
2716 method.coroutine = true;
2718 if (ModifierFlags.NEW in flags) {
2719 method.hides = true;
2722 if (method.binding == MemberBinding.INSTANCE) {
2723 if (ModifierFlags.ABSTRACT in flags) {
2724 method.is_abstract = true;
2726 if (ModifierFlags.VIRTUAL in flags) {
2727 method.is_virtual = true;
2729 if (ModifierFlags.OVERRIDE in flags) {
2730 method.overrides = true;
2732 if ((method.is_abstract && method.is_virtual)
2733 || (method.is_abstract && method.overrides)
2734 || (method.is_virtual && method.overrides)) {
2735 throw new ParseError.SYNTAX ("only one of `abstract', `virtual', or `override' may be specified");
2737 } else {
2738 if (ModifierFlags.ABSTRACT in flags
2739 || ModifierFlags.VIRTUAL in flags
2740 || ModifierFlags.OVERRIDE in flags) {
2741 throw new ParseError.SYNTAX ("the modifiers `abstract', `virtual', and `override' are not valid for %s methods", (ModifierFlags.CLASS in flags) ? "class" : "static");
2745 if (ModifierFlags.INLINE in flags) {
2746 method.is_inline = true;
2748 if (ModifierFlags.EXTERN in flags) {
2749 method.external = true;
2751 expect (TokenType.OPEN_PARENS);
2752 if (current () != TokenType.CLOSE_PARENS) {
2753 do {
2754 var param = parse_parameter ();
2755 method.add_parameter (param);
2756 } while (accept (TokenType.COMMA));
2758 expect (TokenType.CLOSE_PARENS);
2759 if (accept (TokenType.THROWS)) {
2760 do {
2761 method.add_error_type (parse_type (true, false));
2762 } while (accept (TokenType.COMMA));
2764 while (accept (TokenType.REQUIRES)) {
2765 expect (TokenType.OPEN_PARENS);
2766 method.add_precondition (parse_expression ());
2767 expect (TokenType.CLOSE_PARENS);
2769 while (accept (TokenType.ENSURES)) {
2770 expect (TokenType.OPEN_PARENS);
2771 method.add_postcondition (parse_expression ());
2772 expect (TokenType.CLOSE_PARENS);
2774 if (!accept (TokenType.SEMICOLON)) {
2775 method.body = parse_block ();
2776 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
2777 method.external = true;
2780 parent.add_method (method);
2783 void parse_property_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2784 var begin = get_location ();
2785 var access = parse_access_modifier ();
2786 var flags = parse_member_declaration_modifiers ();
2787 var type = parse_type (true, true);
2789 bool getter_owned = false;
2790 if (accept (TokenType.HASH)) {
2791 if (!context.deprecated) {
2792 Report.warning (get_last_src (), "deprecated syntax, use `owned` modifier before `get'");
2794 getter_owned = true;
2797 string id = parse_identifier ();
2798 var prop = new Property (id, type, null, null, get_src (begin), comment);
2799 prop.access = access;
2800 set_attributes (prop, attrs);
2801 if (ModifierFlags.STATIC in flags && ModifierFlags.CLASS in flags) {
2802 Report.error (prop.source_reference, "only one of `static' or `class' may be specified");
2803 } else if (ModifierFlags.STATIC in flags) {
2804 prop.binding = MemberBinding.STATIC;
2805 } else if (ModifierFlags.CLASS in flags) {
2806 prop.binding = MemberBinding.CLASS;
2808 if (ModifierFlags.ABSTRACT in flags) {
2809 prop.is_abstract = true;
2811 if (ModifierFlags.VIRTUAL in flags) {
2812 prop.is_virtual = true;
2814 if (ModifierFlags.OVERRIDE in flags) {
2815 prop.overrides = true;
2817 if (ModifierFlags.NEW in flags) {
2818 prop.hides = true;
2820 if (ModifierFlags.ASYNC in flags) {
2821 Report.error (prop.source_reference, "async properties are not supported yet");
2823 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2824 prop.external = true;
2826 if ((prop.is_abstract && prop.is_virtual)
2827 || (prop.is_abstract && prop.overrides)
2828 || (prop.is_virtual && prop.overrides)) {
2829 throw new ParseError.SYNTAX ("only one of `abstract', `virtual', or `override' may be specified");
2832 if (accept (TokenType.THROWS)) {
2833 do {
2834 prop.add_error_type (parse_type (true, false));
2835 } while (accept (TokenType.COMMA));
2836 Report.error (prop.source_reference, "properties throwing errors are not supported yet");
2838 expect (TokenType.OPEN_BRACE);
2839 while (current () != TokenType.CLOSE_BRACE) {
2840 if (accept (TokenType.DEFAULT)) {
2841 if (prop.initializer != null) {
2842 throw new ParseError.SYNTAX ("property default value already defined");
2844 expect (TokenType.ASSIGN);
2845 prop.initializer = parse_expression ();
2846 expect (TokenType.SEMICOLON);
2847 } else {
2848 comment = scanner.pop_comment ();
2850 var accessor_begin = get_location ();
2851 var accessor_attrs = parse_attributes ();
2852 var accessor_access = parse_access_modifier (SymbolAccessibility.PUBLIC);
2854 var value_type = type.copy ();
2855 if (accept (TokenType.OWNED)) {
2856 value_type.value_owned = true;
2857 } else {
2858 value_type.value_owned = false;
2859 if (accept (TokenType.UNOWNED)) {
2860 Report.warning (get_last_src (), "property getters are `unowned' by default");
2864 if (accept (TokenType.GET)) {
2865 if (prop.get_accessor != null) {
2866 throw new ParseError.SYNTAX ("property get accessor already defined");
2869 if (getter_owned) {
2870 value_type.value_owned = true;
2873 Block block = null;
2874 if (!accept (TokenType.SEMICOLON)) {
2875 block = parse_block ();
2876 prop.external = false;
2878 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin), comment);
2879 set_attributes (prop.get_accessor, accessor_attrs);
2880 prop.get_accessor.access = accessor_access;
2881 } else {
2882 bool writable, _construct;
2883 if (accept (TokenType.SET)) {
2884 writable = true;
2885 _construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT);
2886 } else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) {
2887 _construct = true;
2888 writable = accept (TokenType.SET);
2889 } else {
2890 throw new ParseError.SYNTAX ("expected get, set, or construct");
2892 if (prop.set_accessor != null) {
2893 throw new ParseError.SYNTAX ("property set accessor already defined");
2895 Block block = null;
2896 if (!accept (TokenType.SEMICOLON)) {
2897 block = parse_block ();
2898 prop.external = false;
2900 prop.set_accessor = new PropertyAccessor (false, writable, _construct, value_type, block, get_src (accessor_begin), comment);
2901 set_attributes (prop.set_accessor, accessor_attrs);
2902 prop.set_accessor.access = accessor_access;
2906 expect (TokenType.CLOSE_BRACE);
2908 parent.add_property (prop);
2911 void parse_signal_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2912 var begin = get_location ();
2913 var access = parse_access_modifier ();
2914 var flags = parse_member_declaration_modifiers ();
2915 expect (TokenType.SIGNAL);
2916 var type = parse_type (true, false);
2917 string id = parse_identifier ();
2918 var sig = new Signal (id, type, get_src (begin), comment);
2919 sig.access = access;
2920 set_attributes (sig, attrs);
2921 if (ModifierFlags.STATIC in flags) {
2922 throw new ParseError.SYNTAX ("`static' modifier not allowed on signals");
2923 } else if (ModifierFlags.CLASS in flags) {
2924 throw new ParseError.SYNTAX ("`class' modifier not allowed on signals");
2926 if (ModifierFlags.VIRTUAL in flags) {
2927 sig.is_virtual = true;
2929 if (ModifierFlags.NEW in flags) {
2930 sig.hides = true;
2932 expect (TokenType.OPEN_PARENS);
2933 if (current () != TokenType.CLOSE_PARENS) {
2934 do {
2935 var param = parse_parameter ();
2936 sig.add_parameter (param);
2937 } while (accept (TokenType.COMMA));
2939 expect (TokenType.CLOSE_PARENS);
2940 if (!accept (TokenType.SEMICOLON)) {
2941 sig.body = parse_block ();
2944 parent.add_signal (sig);
2947 void parse_constructor_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2948 var begin = get_location ();
2949 var flags = parse_member_declaration_modifiers ();
2950 expect (TokenType.CONSTRUCT);
2951 if (ModifierFlags.NEW in flags) {
2952 throw new ParseError.SYNTAX ("`new' modifier not allowed on constructor");
2954 var c = new Constructor (get_src (begin));
2955 if (ModifierFlags.STATIC in flags && ModifierFlags.CLASS in flags) {
2956 Report.error (c.source_reference, "only one of `static' or `class' may be specified");
2957 } else if (ModifierFlags.STATIC in flags) {
2958 c.binding = MemberBinding.STATIC;
2959 } else if (ModifierFlags.CLASS in flags) {
2960 c.binding = MemberBinding.CLASS;
2962 c.body = parse_block ();
2964 parent.add_constructor (c);
2967 void parse_destructor_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2968 var begin = get_location ();
2969 var flags = parse_member_declaration_modifiers ();
2970 expect (TokenType.TILDE);
2971 string identifier = parse_identifier ();
2972 expect (TokenType.OPEN_PARENS);
2973 expect (TokenType.CLOSE_PARENS);
2974 if (ModifierFlags.NEW in flags) {
2975 throw new ParseError.SYNTAX ("`new' modifier not allowed on destructor");
2977 var d = new Destructor (get_src (begin));
2978 if (identifier != parent.name) {
2979 Report.error (d.source_reference, "destructor and parent symbol name do not match");
2981 if (ModifierFlags.STATIC in flags && ModifierFlags.CLASS in flags) {
2982 Report.error (d.source_reference, "only one of `static' or `class' may be specified");
2983 } else if (ModifierFlags.STATIC in flags) {
2984 d.binding = MemberBinding.STATIC;
2985 } else if (ModifierFlags.CLASS in flags) {
2986 d.binding = MemberBinding.CLASS;
2988 d.body = parse_block ();
2990 parent.add_destructor (d);
2993 void parse_struct_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2994 var begin = get_location ();
2995 var access = parse_access_modifier ();
2996 var flags = parse_type_declaration_modifiers ();
2997 expect (TokenType.STRUCT);
2998 var sym = parse_symbol_name ();
2999 var type_param_list = parse_type_parameter_list ();
3000 DataType base_type = null;
3001 if (accept (TokenType.COLON)) {
3002 base_type = parse_type (true, false);
3004 var st = new Struct (sym.name, get_src (begin), comment);
3005 st.access = access;
3006 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3007 st.external = true;
3009 set_attributes (st, attrs);
3010 foreach (TypeParameter type_param in type_param_list) {
3011 st.add_type_parameter (type_param);
3013 if (base_type != null) {
3014 st.base_type = base_type;
3017 parse_declarations (st);
3019 Symbol result = st;
3020 while (sym != null) {
3021 sym = sym.inner;
3023 Symbol next = (sym != null ? new Namespace (sym.name, st.source_reference) : parent);
3024 if (result is Namespace) {
3025 next.add_namespace ((Namespace) result);
3026 } else {
3027 next.add_struct ((Struct) result);
3029 result = next;
3033 void parse_interface_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3034 var begin = get_location ();
3035 var access = parse_access_modifier ();
3036 var flags = parse_type_declaration_modifiers ();
3037 expect (TokenType.INTERFACE);
3038 var sym = parse_symbol_name ();
3039 var type_param_list = parse_type_parameter_list ();
3040 var base_types = new ArrayList<DataType> ();
3041 if (accept (TokenType.COLON)) {
3042 do {
3043 var type = parse_type (true, false);
3044 base_types.add (type);
3045 } while (accept (TokenType.COMMA));
3047 var iface = new Interface (sym.name, get_src (begin), comment);
3048 iface.access = access;
3049 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3050 iface.external = true;
3052 set_attributes (iface, attrs);
3053 foreach (TypeParameter type_param in type_param_list) {
3054 iface.add_type_parameter (type_param);
3056 foreach (DataType base_type in base_types) {
3057 iface.add_prerequisite (base_type);
3060 parse_declarations (iface);
3062 Symbol result = iface;
3063 while (sym != null) {
3064 sym = sym.inner;
3066 Symbol next = (sym != null ? new Namespace (sym.name, iface.source_reference) : parent);
3067 if (result is Namespace) {
3068 next.add_namespace ((Namespace) result);
3069 } else {
3070 next.add_interface ((Interface) result);
3072 result = next;
3076 void parse_enum_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3077 var begin = get_location ();
3078 var access = parse_access_modifier ();
3079 var flags = parse_type_declaration_modifiers ();
3080 expect (TokenType.ENUM);
3081 var sym = parse_symbol_name ();
3082 var en = new Enum (sym.name, get_src (begin), comment);
3083 en.access = access;
3084 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3085 en.external = true;
3087 set_attributes (en, attrs);
3089 expect (TokenType.OPEN_BRACE);
3090 do {
3091 if (current () == TokenType.CLOSE_BRACE
3092 && en.get_values ().size > 0) {
3093 // allow trailing comma
3094 break;
3096 var value_attrs = parse_attributes ();
3097 var value_begin = get_location ();
3098 string id = parse_identifier ();
3099 comment = scanner.pop_comment ();
3101 Expression value = null;
3102 if (accept (TokenType.ASSIGN)) {
3103 value = parse_expression ();
3106 var ev = new EnumValue (id, value, get_src (value_begin), comment);
3107 ev.access = SymbolAccessibility.PUBLIC;
3108 set_attributes (ev, value_attrs);
3109 en.add_value (ev);
3110 } while (accept (TokenType.COMMA));
3111 if (accept (TokenType.SEMICOLON)) {
3112 // enum methods
3113 while (current () != TokenType.CLOSE_BRACE) {
3114 parse_declaration (en);
3117 expect (TokenType.CLOSE_BRACE);
3119 Symbol result = en;
3120 while (sym != null) {
3121 sym = sym.inner;
3123 Symbol next = (sym != null ? new Namespace (sym.name, en.source_reference) : parent);
3124 if (result is Namespace) {
3125 next.add_namespace ((Namespace) result);
3126 } else {
3127 next.add_enum ((Enum) result);
3129 result = next;
3133 void parse_errordomain_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3134 var begin = get_location ();
3135 var access = parse_access_modifier ();
3136 var flags = parse_type_declaration_modifiers ();
3137 expect (TokenType.ERRORDOMAIN);
3138 var sym = parse_symbol_name ();
3139 var ed = new ErrorDomain (sym.name, get_src (begin), comment);
3140 ed.access = access;
3141 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3142 ed.external = true;
3144 set_attributes (ed, attrs);
3146 expect (TokenType.OPEN_BRACE);
3147 do {
3148 if (current () == TokenType.CLOSE_BRACE
3149 && ed.get_codes ().size > 0) {
3150 // allow trailing comma
3151 break;
3153 var code_attrs = parse_attributes ();
3154 var code_begin = get_location ();
3155 string id = parse_identifier ();
3156 comment = scanner.pop_comment ();
3157 var ec = new ErrorCode (id, get_src (code_begin), comment);
3158 set_attributes (ec, code_attrs);
3159 if (accept (TokenType.ASSIGN)) {
3160 ec.value = parse_expression ();
3162 ed.add_code (ec);
3163 } while (accept (TokenType.COMMA));
3164 if (accept (TokenType.SEMICOLON)) {
3165 // errordomain methods
3166 while (current () != TokenType.CLOSE_BRACE) {
3167 parse_declaration (ed);
3170 expect (TokenType.CLOSE_BRACE);
3172 Symbol result = ed;
3173 while (sym != null) {
3174 sym = sym.inner;
3176 Symbol next = (sym != null ? new Namespace (sym.name, ed.source_reference) : parent);
3177 if (result is Namespace) {
3178 next.add_namespace ((Namespace) result);
3179 } else {
3180 next.add_error_domain ((ErrorDomain) result);
3182 result = next;
3186 SymbolAccessibility parse_access_modifier (SymbolAccessibility default_access = SymbolAccessibility.PRIVATE) {
3187 switch (current ()) {
3188 case TokenType.PRIVATE:
3189 next ();
3190 return SymbolAccessibility.PRIVATE;
3191 case TokenType.PROTECTED:
3192 next ();
3193 return SymbolAccessibility.PROTECTED;
3194 case TokenType.INTERNAL:
3195 next ();
3196 return SymbolAccessibility.INTERNAL;
3197 case TokenType.PUBLIC:
3198 next ();
3199 return SymbolAccessibility.PUBLIC;
3200 default:
3201 return default_access;
3205 ModifierFlags parse_type_declaration_modifiers () {
3206 ModifierFlags flags = 0;
3207 while (true) {
3208 switch (current ()) {
3209 case TokenType.ABSTRACT:
3210 next ();
3211 flags |= ModifierFlags.ABSTRACT;
3212 break;
3213 case TokenType.EXTERN:
3214 next ();
3215 flags |= ModifierFlags.EXTERN;
3216 break;
3217 case TokenType.SEALED:
3218 next ();
3219 flags |= ModifierFlags.SEALED;
3220 break;
3221 default:
3222 return flags;
3227 ModifierFlags parse_member_declaration_modifiers () {
3228 ModifierFlags flags = 0;
3229 while (true) {
3230 switch (current ()) {
3231 case TokenType.ABSTRACT:
3232 next ();
3233 flags |= ModifierFlags.ABSTRACT;
3234 break;
3235 case TokenType.ASYNC:
3236 next ();
3237 flags |= ModifierFlags.ASYNC;
3238 break;
3239 case TokenType.CLASS:
3240 next ();
3241 flags |= ModifierFlags.CLASS;
3242 break;
3243 case TokenType.EXTERN:
3244 next ();
3245 flags |= ModifierFlags.EXTERN;
3246 break;
3247 case TokenType.INLINE:
3248 next ();
3249 flags |= ModifierFlags.INLINE;
3250 break;
3251 case TokenType.NEW:
3252 next ();
3253 flags |= ModifierFlags.NEW;
3254 break;
3255 case TokenType.OVERRIDE:
3256 next ();
3257 flags |= ModifierFlags.OVERRIDE;
3258 break;
3259 case TokenType.SEALED:
3260 next ();
3261 flags |= ModifierFlags.SEALED;
3262 break;
3263 case TokenType.STATIC:
3264 next ();
3265 flags |= ModifierFlags.STATIC;
3266 break;
3267 case TokenType.VIRTUAL:
3268 next ();
3269 flags |= ModifierFlags.VIRTUAL;
3270 break;
3271 default:
3272 return flags;
3277 Parameter parse_parameter () throws ParseError {
3278 var attrs = parse_attributes ();
3279 var begin = get_location ();
3280 if (accept (TokenType.ELLIPSIS)) {
3281 // varargs
3282 return new Parameter.with_ellipsis (get_src (begin));
3284 bool params_array = accept (TokenType.PARAMS);
3285 var direction = ParameterDirection.IN;
3286 if (accept (TokenType.OUT)) {
3287 direction = ParameterDirection.OUT;
3288 } else if (accept (TokenType.REF)) {
3289 direction = ParameterDirection.REF;
3292 DataType type;
3293 if (direction == ParameterDirection.IN) {
3294 // in parameters are unowned by default
3295 type = parse_type (false, false);
3296 } else if (direction == ParameterDirection.REF) {
3297 // ref parameters own the value by default
3298 type = parse_type (true, true);
3299 } else {
3300 // out parameters own the value by default
3301 type = parse_type (true, false);
3303 string id = parse_identifier ();
3305 type = parse_inline_array_type (type);
3307 var param = new Parameter (id, type, get_src (begin));
3308 set_attributes (param, attrs);
3309 param.direction = direction;
3310 param.params_array = params_array;
3311 if (accept (TokenType.ASSIGN)) {
3312 param.initializer = parse_expression ();
3314 return param;
3317 void parse_creation_method_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3318 var begin = get_location ();
3319 var access = parse_access_modifier ();
3320 var flags = parse_member_declaration_modifiers ();
3321 var sym = parse_symbol_name ();
3322 if (ModifierFlags.NEW in flags) {
3323 throw new ParseError.SYNTAX ("`new' modifier not allowed on creation method");
3325 CreationMethod method;
3326 if (sym.inner == null) {
3327 method = new CreationMethod (sym.name, null, get_src (begin), comment);
3328 } else {
3329 method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
3331 if (ModifierFlags.EXTERN in flags) {
3332 method.external = true;
3334 if (ModifierFlags.ABSTRACT in flags
3335 || ModifierFlags.VIRTUAL in flags
3336 || ModifierFlags.OVERRIDE in flags) {
3337 Report.error (method.source_reference, "abstract, virtual, and override modifiers are not applicable to creation methods");
3339 if (ModifierFlags.ASYNC in flags) {
3340 method.coroutine = true;
3342 expect (TokenType.OPEN_PARENS);
3343 if (current () != TokenType.CLOSE_PARENS) {
3344 do {
3345 var param = parse_parameter ();
3346 method.add_parameter (param);
3347 } while (accept (TokenType.COMMA));
3349 expect (TokenType.CLOSE_PARENS);
3350 if (accept (TokenType.THROWS)) {
3351 do {
3352 method.add_error_type (parse_type (true, false));
3353 } while (accept (TokenType.COMMA));
3355 while (accept (TokenType.REQUIRES)) {
3356 expect (TokenType.OPEN_PARENS);
3357 method.add_precondition (parse_expression ());
3358 expect (TokenType.CLOSE_PARENS);
3360 while (accept (TokenType.ENSURES)) {
3361 expect (TokenType.OPEN_PARENS);
3362 method.add_postcondition (parse_expression ());
3363 expect (TokenType.CLOSE_PARENS);
3365 method.access = access;
3366 set_attributes (method, attrs);
3367 if (!accept (TokenType.SEMICOLON)) {
3368 method.body = parse_block ();
3369 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
3370 method.external = true;
3373 parent.add_method (method);
3376 void parse_delegate_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3377 var begin = get_location ();
3378 var access = parse_access_modifier ();
3379 var flags = parse_member_declaration_modifiers ();
3380 expect (TokenType.DELEGATE);
3381 if (ModifierFlags.NEW in flags) {
3382 throw new ParseError.SYNTAX ("`new' modifier not allowed on delegates");
3384 var type = parse_type (true, false);
3385 var sym = parse_symbol_name ();
3386 var type_param_list = parse_type_parameter_list ();
3387 var d = new Delegate (sym.name, type, get_src (begin), comment);
3388 d.access = access;
3389 set_attributes (d, attrs);
3390 if (ModifierFlags.STATIC in flags) {
3391 if (!context.deprecated) {
3392 // TODO enable warning in future releases
3393 Report.warning (get_last_src (), "deprecated syntax, use [CCode (has_target = false)]");
3395 d.has_target = false;
3397 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3398 d.external = true;
3400 if (!d.get_attribute_bool ("CCode", "has_typedef", true)) {
3401 if (!d.external) {
3402 Report.error (get_last_src (), "Delegates without definition must be external");
3404 d.anonymous = true;
3406 foreach (TypeParameter type_param in type_param_list) {
3407 d.add_type_parameter (type_param);
3409 expect (TokenType.OPEN_PARENS);
3410 if (current () != TokenType.CLOSE_PARENS) {
3411 do {
3412 var param = parse_parameter ();
3413 d.add_parameter (param);
3414 } while (accept (TokenType.COMMA));
3416 expect (TokenType.CLOSE_PARENS);
3417 if (accept (TokenType.THROWS)) {
3418 do {
3419 d.add_error_type (parse_type (true, false));
3420 } while (accept (TokenType.COMMA));
3422 expect (TokenType.SEMICOLON);
3424 Symbol result = d;
3425 while (sym != null) {
3426 sym = sym.inner;
3428 Symbol next = (sym != null ? new Namespace (sym.name, d.source_reference) : parent);
3429 if (result is Namespace) {
3430 next.add_namespace ((Namespace) result);
3431 } else {
3432 next.add_delegate ((Delegate) result);
3434 result = next;
3438 List<TypeParameter> parse_type_parameter_list () throws ParseError {
3439 if (accept (TokenType.OP_LT)) {
3440 var list = new ArrayList<TypeParameter> ();
3441 do {
3442 var begin = get_location ();
3443 string id = parse_identifier ();
3444 list.add (new TypeParameter (id, get_src (begin)));
3445 } while (accept (TokenType.COMMA));
3446 expect (TokenType.OP_GT);
3447 return list;
3448 } else {
3449 if (_empty_type_parameter_list == null) {
3450 _empty_type_parameter_list = new ArrayList<TypeParameter> ();
3452 return _empty_type_parameter_list;
3456 void skip_type_argument_list () throws ParseError {
3457 if (accept (TokenType.OP_LT)) {
3458 do {
3459 skip_type ();
3460 } while (accept (TokenType.COMMA));
3461 expect (TokenType.OP_GT);
3465 // try to parse type argument list
3466 List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3467 var begin = get_location ();
3468 if (accept (TokenType.OP_LT)) {
3469 var list = new ArrayList<DataType> ();
3470 do {
3471 switch (current ()) {
3472 case TokenType.VOID:
3473 case TokenType.DYNAMIC:
3474 case TokenType.UNOWNED:
3475 case TokenType.WEAK:
3476 case TokenType.IDENTIFIER:
3477 var type = parse_type (true, true);
3478 list.add (type);
3479 break;
3480 default:
3481 rollback (begin);
3482 return null;
3484 } while (accept (TokenType.COMMA));
3485 if (!accept (TokenType.OP_GT)) {
3486 rollback (begin);
3487 return null;
3489 if (maybe_expression) {
3490 // check follower to decide whether to keep type argument list
3491 switch (current ()) {
3492 case TokenType.OPEN_PARENS:
3493 case TokenType.CLOSE_PARENS:
3494 case TokenType.CLOSE_BRACKET:
3495 case TokenType.OPEN_BRACE:
3496 case TokenType.COLON:
3497 case TokenType.SEMICOLON:
3498 case TokenType.COMMA:
3499 case TokenType.DOT:
3500 case TokenType.INTERR:
3501 case TokenType.OP_EQ:
3502 case TokenType.OP_NE:
3503 // keep type argument list
3504 break;
3505 default:
3506 // interpret tokens as expression
3507 rollback (begin);
3508 return null;
3511 return list;
3513 return null;
3516 MemberAccess parse_member_name (Expression? base_expr = null) throws ParseError {
3517 var begin = get_location ();
3518 MemberAccess expr = null;
3519 bool first = true;
3520 do {
3521 string id = parse_identifier ();
3523 // The first member access can be global:: qualified
3524 bool qualified = false;
3525 if (first && id == "global" && accept (TokenType.DOUBLE_COLON)) {
3526 id = parse_identifier ();
3527 qualified = true;
3530 List<DataType> type_arg_list = parse_type_argument_list (false);
3531 expr = new MemberAccess (expr != null ? expr : base_expr, id, get_src (begin));
3532 expr.qualified = qualified;
3533 if (type_arg_list != null) {
3534 foreach (DataType type_arg in type_arg_list) {
3535 expr.add_type_argument (type_arg);
3539 first = false;
3540 } while (accept (TokenType.DOT));
3541 return expr;
3544 bool is_declaration_keyword (TokenType type) {
3545 switch (type) {
3546 case TokenType.ABSTRACT:
3547 case TokenType.ASYNC:
3548 case TokenType.CLASS:
3549 case TokenType.CONST:
3550 case TokenType.DELEGATE:
3551 case TokenType.ENUM:
3552 case TokenType.ERRORDOMAIN:
3553 case TokenType.EXTERN:
3554 case TokenType.INLINE:
3555 case TokenType.INTERFACE:
3556 case TokenType.INTERNAL:
3557 case TokenType.NAMESPACE:
3558 case TokenType.NEW:
3559 case TokenType.OVERRIDE:
3560 case TokenType.PRIVATE:
3561 case TokenType.PROTECTED:
3562 case TokenType.PUBLIC:
3563 case TokenType.SEALED:
3564 case TokenType.SIGNAL:
3565 case TokenType.STATIC:
3566 case TokenType.STRUCT:
3567 case TokenType.VIRTUAL:
3568 case TokenType.VOLATILE:
3569 return true;
3570 default:
3571 return false;
3576 public errordomain Vala.ParseError {
3577 FAILED,
3578 SYNTAX