girparser: Skip priv fields
[vala-lang.git] / vala / valaparser.vala
blob136bf01696c3779e905a19ee396de7eff3376a29
1 /* valaparser.vala
3 * Copyright (C) 2006-2011 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);
81 public override void visit_source_file (SourceFile source_file) {
82 if (context.run_output || source_file.filename.has_suffix (".vala") || source_file.filename.has_suffix (".vapi")) {
83 parse_file (source_file);
87 inline bool next () {
88 index = (index + 1) % BUFFER_SIZE;
89 size--;
90 if (size <= 0) {
91 SourceLocation begin, end;
92 TokenType type = scanner.read_token (out begin, out end);
93 tokens[index].type = type;
94 tokens[index].begin = begin;
95 tokens[index].end = end;
96 size = 1;
98 return (tokens[index].type != TokenType.EOF);
101 inline void prev () {
102 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
103 size++;
104 assert (size <= BUFFER_SIZE);
107 inline TokenType current () {
108 return tokens[index].type;
111 inline bool accept (TokenType type) {
112 if (current () == type) {
113 next ();
114 return true;
116 return false;
119 string get_error (string msg) {
120 var begin = get_location ();
121 next ();
122 Report.error (get_src (begin), "syntax error, " + msg);
123 return msg;
126 inline bool expect (TokenType type) throws ParseError {
127 if (accept (type)) {
128 return true;
131 throw new ParseError.SYNTAX (get_error ("expected %s".printf (type.to_string ())));
134 inline SourceLocation get_location () {
135 return tokens[index].begin;
138 string get_current_string () {
139 return ((string) tokens[index].begin.pos).substring (0, (int) (tokens[index].end.pos - tokens[index].begin.pos));
142 string get_last_string () {
143 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
144 return ((string) tokens[last_index].begin.pos).substring (0, (int) (tokens[last_index].end.pos - tokens[last_index].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.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
153 SourceReference get_current_src () {
154 return new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column);
157 SourceReference get_last_src () {
158 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
160 return new SourceReference (scanner.source_file, tokens[last_index].begin.line, tokens[last_index].begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
163 void rollback (SourceLocation location) {
164 while (tokens[index].begin.pos != location.pos) {
165 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
166 size++;
167 if (size > BUFFER_SIZE) {
168 scanner.seek (location);
169 size = 0;
170 index = 0;
172 next ();
177 void skip_identifier () throws ParseError {
178 // also accept keywords as identifiers where there is no conflict
179 switch (current ()) {
180 case TokenType.ABSTRACT:
181 case TokenType.AS:
182 case TokenType.ASYNC:
183 case TokenType.BASE:
184 case TokenType.BREAK:
185 case TokenType.CASE:
186 case TokenType.CATCH:
187 case TokenType.CLASS:
188 case TokenType.CONST:
189 case TokenType.CONSTRUCT:
190 case TokenType.CONTINUE:
191 case TokenType.DEFAULT:
192 case TokenType.DELEGATE:
193 case TokenType.DELETE:
194 case TokenType.DO:
195 case TokenType.DYNAMIC:
196 case TokenType.ELSE:
197 case TokenType.ENUM:
198 case TokenType.ENSURES:
199 case TokenType.ERRORDOMAIN:
200 case TokenType.EXTERN:
201 case TokenType.FALSE:
202 case TokenType.FINALLY:
203 case TokenType.FOR:
204 case TokenType.FOREACH:
205 case TokenType.GET:
206 case TokenType.IDENTIFIER:
207 case TokenType.IF:
208 case TokenType.IN:
209 case TokenType.INLINE:
210 case TokenType.INTERFACE:
211 case TokenType.INTERNAL:
212 case TokenType.IS:
213 case TokenType.LOCK:
214 case TokenType.NAMESPACE:
215 case TokenType.NEW:
216 case TokenType.NULL:
217 case TokenType.OUT:
218 case TokenType.OVERRIDE:
219 case TokenType.OWNED:
220 case TokenType.PARAMS:
221 case TokenType.PRIVATE:
222 case TokenType.PROTECTED:
223 case TokenType.PUBLIC:
224 case TokenType.REF:
225 case TokenType.REQUIRES:
226 case TokenType.RETURN:
227 case TokenType.SEALED:
228 case TokenType.SET:
229 case TokenType.SIGNAL:
230 case TokenType.SIZEOF:
231 case TokenType.STATIC:
232 case TokenType.STRUCT:
233 case TokenType.SWITCH:
234 case TokenType.THIS:
235 case TokenType.THROW:
236 case TokenType.THROWS:
237 case TokenType.TRUE:
238 case TokenType.TRY:
239 case TokenType.TYPEOF:
240 case TokenType.UNOWNED:
241 case TokenType.USING:
242 case TokenType.VAR:
243 case TokenType.VIRTUAL:
244 case TokenType.VOID:
245 case TokenType.VOLATILE:
246 case TokenType.WEAK:
247 case TokenType.WHILE:
248 case TokenType.YIELD:
249 next ();
250 return;
251 case TokenType.INTEGER_LITERAL:
252 case TokenType.REAL_LITERAL:
253 // also accept integer and real literals
254 // as long as they contain at least one character
255 // and no decimal point
256 // for example, 2D and 3D
257 string id = get_current_string ();
258 if (id[id.length - 1].isalpha () && !("." in id)) {
259 next ();
260 return;
262 break;
263 default:
264 throw new ParseError.SYNTAX (get_error ("expected identifier"));
268 string parse_identifier () throws ParseError {
269 skip_identifier ();
270 return get_last_string ();
273 Expression parse_literal () throws ParseError {
274 var begin = get_location ();
276 switch (current ()) {
277 case TokenType.TRUE:
278 next ();
279 return new BooleanLiteral (true, get_src (begin));
280 case TokenType.FALSE:
281 next ();
282 return new BooleanLiteral (false, get_src (begin));
283 case TokenType.INTEGER_LITERAL:
284 next ();
285 return new IntegerLiteral (get_last_string (), get_src (begin));
286 case TokenType.REAL_LITERAL:
287 next ();
288 return new RealLiteral (get_last_string (), get_src (begin));
289 case TokenType.CHARACTER_LITERAL:
290 next ();
291 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
292 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
293 if (lit.error) {
294 Report.error (lit.source_reference, "invalid character literal");
296 return lit;
297 case TokenType.REGEX_LITERAL:
298 next ();
299 string match_part = get_last_string ();
300 SourceReference src_begin = get_src (begin);
301 expect (TokenType.CLOSE_REGEX_LITERAL);
302 string close_token = get_last_string ();
303 return new RegexLiteral ("%s/%s".printf (close_token, match_part), src_begin);
304 case TokenType.STRING_LITERAL:
305 next ();
306 return new StringLiteral (get_last_string (), get_src (begin));
307 case TokenType.TEMPLATE_STRING_LITERAL:
308 next ();
309 return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
310 case TokenType.VERBATIM_STRING_LITERAL:
311 next ();
312 string raw_string = get_last_string ();
313 string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
314 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
315 case TokenType.NULL:
316 next ();
317 return new NullLiteral (get_src (begin));
318 default:
319 throw new ParseError.SYNTAX (get_error ("expected literal"));
323 public void parse_file (SourceFile source_file) {
324 scanner = new Scanner (source_file);
325 parse_file_comments ();
327 index = -1;
328 size = 0;
330 next ();
333 try {
334 parse_using_directives (context.root);
335 parse_declarations (context.root, true);
336 if (accept (TokenType.CLOSE_BRACE)) {
337 // only report error if it's not a secondary error
338 if (context.report.get_errors () == 0) {
339 Report.error (get_last_src (), "unexpected `}'");
342 } catch (ParseError e) {
343 // already reported
346 scanner = null;
349 void parse_file_comments () {
350 scanner.parse_file_comments ();
353 void skip_symbol_name () throws ParseError {
354 do {
355 skip_identifier ();
356 } while (accept (TokenType.DOT) || accept (TokenType.DOUBLE_COLON));
359 UnresolvedSymbol parse_symbol_name () throws ParseError {
360 var begin = get_location ();
361 UnresolvedSymbol sym = null;
362 do {
363 string name = parse_identifier ();
364 if (name == "global" && accept (TokenType.DOUBLE_COLON)) {
365 // global::Name
366 // qualified access to global symbol
367 name = parse_identifier ();
368 sym = new UnresolvedSymbol (sym, name, get_src (begin));
369 sym.qualified = true;
370 continue;
372 sym = new UnresolvedSymbol (sym, name, get_src (begin));
373 } while (accept (TokenType.DOT));
374 return sym;
377 void skip_type () throws ParseError {
378 if (accept (TokenType.VOID)) {
379 while (accept (TokenType.STAR)) {
381 return;
383 accept (TokenType.DYNAMIC);
384 accept (TokenType.OWNED);
385 accept (TokenType.UNOWNED);
386 accept (TokenType.WEAK);
387 skip_symbol_name ();
388 skip_type_argument_list ();
389 while (accept (TokenType.STAR)) {
391 accept (TokenType.INTERR);
392 while (accept (TokenType.OPEN_BRACKET)) {
393 do {
394 // required for decision between expression and declaration statement
395 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
396 parse_expression ();
398 } while (accept (TokenType.COMMA));
399 expect (TokenType.CLOSE_BRACKET);
400 accept (TokenType.INTERR);
402 accept (TokenType.OP_NEG);
403 accept (TokenType.HASH);
406 DataType parse_type (bool owned_by_default, bool can_weak_ref) throws ParseError {
407 var begin = get_location ();
409 if (accept (TokenType.VOID)) {
410 DataType type = new VoidType (get_src (begin));
411 while (accept (TokenType.STAR)) {
412 type = new PointerType (type);
414 return type;
417 bool is_dynamic = accept (TokenType.DYNAMIC);
419 bool value_owned = owned_by_default;
421 if (owned_by_default) {
422 if (context.profile == Profile.DOVA) {
423 if (can_weak_ref && accept (TokenType.WEAK)) {
424 value_owned = false;
426 } else if (accept (TokenType.UNOWNED)) {
427 value_owned = false;
428 } else if (accept (TokenType.WEAK)) {
429 if (!can_weak_ref && !context.deprecated) {
430 Report.warning (get_last_src (), "deprecated syntax, use `unowned` modifier");
432 value_owned = false;
434 } else {
435 value_owned = (context.profile != Profile.DOVA && accept (TokenType.OWNED));
438 var sym = parse_symbol_name ();
439 List<DataType> type_arg_list = parse_type_argument_list (false);
441 DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
442 if (type_arg_list != null) {
443 foreach (DataType type_arg in type_arg_list) {
444 type.add_type_argument (type_arg);
448 while (accept (TokenType.STAR)) {
449 type = new PointerType (type, get_src (begin));
452 if (!(type is PointerType)) {
453 type.nullable = accept (TokenType.INTERR);
456 // array brackets in types are read from right to left,
457 // this is more logical, especially when nullable arrays
458 // or pointers are involved
459 while (accept (TokenType.OPEN_BRACKET)) {
460 bool invalid_array = false;
461 int array_rank = 0;
462 do {
463 array_rank++;
464 // required for decision between expression and declaration statement
465 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
466 parse_expression ();
467 // only used for parsing, reject use as real type
468 invalid_array = true;
470 } while (context.profile != Profile.DOVA && accept (TokenType.COMMA));
471 expect (TokenType.CLOSE_BRACKET);
473 // arrays contain strong references by default
474 type.value_owned = true;
476 var array_type = new ArrayType (type, array_rank, get_src (begin));
477 array_type.nullable = accept (TokenType.INTERR);
478 array_type.invalid_syntax = invalid_array;
480 type = array_type;
483 if (accept (TokenType.OP_NEG)) {
484 Report.warning (get_last_src (), "obsolete syntax, types are non-null by default");
487 if (!owned_by_default) {
488 if (context.profile != Profile.DOVA && accept (TokenType.HASH)) {
489 if (!context.deprecated) {
490 Report.warning (get_last_src (), "deprecated syntax, use `owned` modifier");
492 value_owned = true;
496 type.is_dynamic = is_dynamic;
497 type.value_owned = value_owned;
498 return type;
501 DataType? parse_inline_array_type (DataType? type) throws ParseError {
502 var begin = get_location ();
504 // inline-allocated array
505 if (type != null && accept (TokenType.OPEN_BRACKET)) {
506 int array_length = -1;
508 if (current () != TokenType.CLOSE_BRACKET) {
509 if (current () != TokenType.INTEGER_LITERAL) {
510 throw new ParseError.SYNTAX (get_error ("expected `]' or integer literal"));
513 var length_literal = (IntegerLiteral) parse_literal ();
514 array_length = int.parse (length_literal.value);
516 expect (TokenType.CLOSE_BRACKET);
518 var array_type = new ArrayType (type, 1, get_src (begin));
519 array_type.inline_allocated = true;
520 if (array_length > 0) {
521 array_type.fixed_length = true;
522 array_type.length = array_length;
524 array_type.value_owned = type.value_owned;
526 return array_type;
528 return type;
531 List<Expression> parse_argument_list () throws ParseError {
532 var list = new ArrayList<Expression> ();
533 if (current () != TokenType.CLOSE_PARENS) {
534 do {
535 list.add (parse_argument ());
536 } while (accept (TokenType.COMMA));
538 return list;
541 Expression parse_argument () throws ParseError {
542 var begin = get_location ();
544 if (accept (TokenType.REF)) {
545 var inner = parse_expression ();
546 return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
547 } else if (accept (TokenType.OUT)) {
548 var inner = parse_expression ();
549 return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
550 } else {
551 var expr = parse_expression ();
552 var ma = expr as MemberAccess;
553 if (ma != null && ma.inner == null && accept (TokenType.COLON)) {
554 // named argument
555 expr = parse_expression ();
556 return new NamedArgument (ma.member_name, expr, get_src (begin));
557 } else {
558 return expr;
563 Expression parse_primary_expression () throws ParseError {
564 var begin = get_location ();
566 Expression expr;
568 switch (current ()) {
569 case TokenType.TRUE:
570 case TokenType.FALSE:
571 case TokenType.INTEGER_LITERAL:
572 case TokenType.REAL_LITERAL:
573 case TokenType.CHARACTER_LITERAL:
574 case TokenType.STRING_LITERAL:
575 case TokenType.REGEX_LITERAL:
576 case TokenType.TEMPLATE_STRING_LITERAL:
577 case TokenType.VERBATIM_STRING_LITERAL:
578 case TokenType.NULL:
579 expr = parse_literal ();
580 break;
581 case TokenType.OPEN_BRACE:
582 if (context.profile == Profile.DOVA) {
583 expr = parse_set_literal ();
584 } else {
585 expr = parse_initializer ();
587 break;
588 case TokenType.OPEN_BRACKET:
589 if (context.profile == Profile.DOVA) {
590 expr = parse_list_literal ();
591 } else {
592 expr = parse_simple_name ();
594 break;
595 case TokenType.OPEN_PARENS:
596 expr = parse_tuple ();
597 break;
598 case TokenType.OPEN_TEMPLATE:
599 expr = parse_template ();
600 break;
601 case TokenType.OPEN_REGEX_LITERAL:
602 expr = parse_regex_literal ();
603 break;
604 case TokenType.THIS:
605 expr = parse_this_access ();
606 break;
607 case TokenType.BASE:
608 expr = parse_base_access ();
609 break;
610 case TokenType.NEW:
611 expr = parse_object_or_array_creation_expression ();
612 break;
613 case TokenType.YIELD:
614 expr = parse_yield_expression ();
615 break;
616 case TokenType.SIZEOF:
617 expr = parse_sizeof_expression ();
618 break;
619 case TokenType.TYPEOF:
620 expr = parse_typeof_expression ();
621 break;
622 default:
623 expr = parse_simple_name ();
624 break;
627 // process primary expressions that start with an inner primary expression
628 bool found = true;
629 while (found) {
630 switch (current ()) {
631 case TokenType.DOT:
632 expr = parse_member_access (begin, expr);
633 break;
634 case TokenType.OP_PTR:
635 if (context.profile == Profile.DOVA) {
636 found = false;
637 } else {
638 expr = parse_pointer_member_access (begin, expr);
640 break;
641 case TokenType.OPEN_PARENS:
642 expr = parse_method_call (begin, expr);
643 break;
644 case TokenType.OPEN_BRACKET:
645 expr = parse_element_access (begin, expr);
646 break;
647 case TokenType.OPEN_BRACE:
648 var ma = expr as MemberAccess;
649 if (context.profile == Profile.DOVA && ma != null) {
650 expr = parse_object_literal (begin, ma);
651 } else {
652 found = false;
654 break;
655 case TokenType.OP_INC:
656 expr = parse_post_increment_expression (begin, expr);
657 break;
658 case TokenType.OP_DEC:
659 expr = parse_post_decrement_expression (begin, expr);
660 break;
661 default:
662 found = false;
663 break;
667 return expr;
670 Expression parse_simple_name () throws ParseError {
671 var begin = get_location ();
672 string id = parse_identifier ();
673 bool qualified = false;
674 if (id == "global" && accept (TokenType.DOUBLE_COLON)) {
675 id = parse_identifier ();
676 qualified = true;
678 List<DataType> type_arg_list = parse_type_argument_list (true);
679 var expr = new MemberAccess (null, id, get_src (begin));
680 expr.qualified = qualified;
681 if (type_arg_list != null) {
682 foreach (DataType type_arg in type_arg_list) {
683 expr.add_type_argument (type_arg);
686 return expr;
689 Expression parse_tuple () throws ParseError {
690 var begin = get_location ();
692 expect (TokenType.OPEN_PARENS);
693 var expr_list = new ArrayList<Expression> ();
694 if (current () != TokenType.CLOSE_PARENS) {
695 do {
696 expr_list.add (parse_expression ());
697 } while (accept (TokenType.COMMA));
699 expect (TokenType.CLOSE_PARENS);
700 if (expr_list.size != 1) {
701 var tuple = new Tuple (get_src (begin));
702 foreach (Expression expr in expr_list) {
703 tuple.add_expression (expr);
705 return tuple;
707 return expr_list.get (0);
710 Expression parse_template () throws ParseError {
711 var begin = get_location ();
712 var template = new Template ();
714 expect (TokenType.OPEN_TEMPLATE);
715 while (current () != TokenType.CLOSE_TEMPLATE) {
716 template.add_expression (parse_expression ());
717 expect (TokenType.COMMA);
719 expect (TokenType.CLOSE_TEMPLATE);
721 template.source_reference = get_src (begin);
722 return template;
725 Expression parse_regex_literal () throws ParseError {
726 expect (TokenType.OPEN_REGEX_LITERAL);
728 var expr = parse_literal ();
730 return expr;
733 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
734 expect (TokenType.DOT);
735 string id = parse_identifier ();
736 List<DataType> type_arg_list = parse_type_argument_list (true);
737 var expr = new MemberAccess (inner, id, get_src (begin));
738 if (type_arg_list != null) {
739 foreach (DataType type_arg in type_arg_list) {
740 expr.add_type_argument (type_arg);
743 return expr;
746 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
747 expect (TokenType.OP_PTR);
748 string id = parse_identifier ();
749 List<DataType> type_arg_list = parse_type_argument_list (true);
750 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
751 if (type_arg_list != null) {
752 foreach (DataType type_arg in type_arg_list) {
753 expr.add_type_argument (type_arg);
756 return expr;
759 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
760 expect (TokenType.OPEN_PARENS);
761 var arg_list = parse_argument_list ();
762 expect (TokenType.CLOSE_PARENS);
763 var init_list = parse_object_initializer ();
765 if (init_list.size > 0 && inner is MemberAccess) {
766 // struct creation expression
767 var member = (MemberAccess) inner;
768 member.creation_member = true;
770 var expr = new ObjectCreationExpression (member, get_src (begin));
771 expr.struct_creation = true;
772 foreach (Expression arg in arg_list) {
773 expr.add_argument (arg);
775 foreach (MemberInitializer initializer in init_list) {
776 expr.add_member_initializer (initializer);
778 return expr;
779 } else {
780 var expr = new MethodCall (inner, get_src (begin));
781 foreach (Expression arg in arg_list) {
782 expr.add_argument (arg);
784 return expr;
788 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
789 expect (TokenType.OPEN_BRACKET);
790 var index_list = parse_expression_list ();
791 Expression? stop = null;
792 if (index_list.size == 1 && accept (TokenType.COLON)) {
793 // slice expression
794 stop = parse_expression ();
796 expect (TokenType.CLOSE_BRACKET);
798 if (stop == null) {
799 var expr = new ElementAccess (inner, get_src (begin));
800 foreach (Expression index in index_list) {
801 expr.append_index (index);
803 return expr;
804 } else {
805 return new SliceExpression (inner, index_list[0], stop, get_src (begin));
809 List<Expression> parse_expression_list () throws ParseError {
810 var list = new ArrayList<Expression> ();
811 do {
812 list.add (parse_expression ());
813 } while (accept (TokenType.COMMA));
814 return list;
817 Expression parse_this_access () throws ParseError {
818 var begin = get_location ();
819 expect (TokenType.THIS);
820 return new MemberAccess (null, "this", get_src (begin));
823 Expression parse_base_access () throws ParseError {
824 var begin = get_location ();
825 expect (TokenType.BASE);
826 return new BaseAccess (get_src (begin));
829 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
830 expect (TokenType.OP_INC);
831 return new PostfixExpression (inner, true, get_src (begin));
834 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
835 expect (TokenType.OP_DEC);
836 return new PostfixExpression (inner, false, get_src (begin));
839 Expression parse_object_or_array_creation_expression () throws ParseError {
840 var begin = get_location ();
841 expect (TokenType.NEW);
842 var member = parse_member_name ();
843 if (accept (TokenType.OPEN_PARENS)) {
844 var expr = parse_object_creation_expression (begin, member);
845 return expr;
846 } else if (accept (TokenType.OPEN_BRACKET)) {
847 var expr = parse_array_creation_expression (begin, member);
848 return expr;
849 } else {
850 throw new ParseError.SYNTAX (get_error ("expected ( or ["));
854 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
855 member.creation_member = true;
856 var arg_list = parse_argument_list ();
857 expect (TokenType.CLOSE_PARENS);
858 var init_list = parse_object_initializer ();
860 var expr = new ObjectCreationExpression (member, get_src (begin));
861 foreach (Expression arg in arg_list) {
862 expr.add_argument (arg);
864 foreach (MemberInitializer initializer in init_list) {
865 expr.add_member_initializer (initializer);
867 return expr;
870 Expression parse_object_literal (SourceLocation begin, MemberAccess member) throws ParseError {
871 member.creation_member = true;
873 var expr = new ObjectCreationExpression (member, get_src (begin));
875 expect (TokenType.OPEN_BRACE);
877 do {
878 var member_begin = get_location ();
879 string id = parse_identifier ();
880 expect (TokenType.COLON);
881 var member_expr = parse_expression ();
883 expr.add_member_initializer (new MemberInitializer (id, member_expr, get_src (member_begin)));
884 } while (accept (TokenType.COMMA));
886 expect (TokenType.CLOSE_BRACE);
888 return expr;
891 Expression parse_array_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
892 bool size_specified = false;
893 List<Expression> size_specifier_list = null;
894 bool first = true;
895 DataType element_type = UnresolvedType.new_from_expression (member);
896 do {
897 if (!first) {
898 // array of arrays: new T[][42]
900 if (size_specified) {
901 throw new ParseError.SYNTAX (get_error ("size of inner arrays must not be specified in array creation expression"));
904 element_type = new ArrayType (element_type, size_specifier_list.size, element_type.source_reference);
905 } else {
906 first = false;
909 size_specifier_list = new ArrayList<Expression> ();
910 do {
911 Expression size = null;
912 if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
913 size = parse_expression ();
914 size_specified = true;
916 size_specifier_list.add (size);
917 } while (context.profile != Profile.DOVA && accept (TokenType.COMMA));
918 expect (TokenType.CLOSE_BRACKET);
919 } while (accept (TokenType.OPEN_BRACKET));
921 InitializerList initializer = null;
922 if (context.profile != Profile.DOVA && current () == TokenType.OPEN_BRACE) {
923 initializer = parse_initializer ();
925 var expr = new ArrayCreationExpression (element_type, size_specifier_list.size, initializer, get_src (begin));
926 if (size_specified) {
927 foreach (Expression size in size_specifier_list) {
928 expr.append_size (size);
931 return expr;
934 List<MemberInitializer> parse_object_initializer () throws ParseError {
935 var list = new ArrayList<MemberInitializer> ();
936 if (context.profile != Profile.DOVA && accept (TokenType.OPEN_BRACE)) {
937 do {
938 list.add (parse_member_initializer ());
939 } while (accept (TokenType.COMMA));
940 expect (TokenType.CLOSE_BRACE);
942 return list;
945 MemberInitializer parse_member_initializer () throws ParseError {
946 var begin = get_location ();
947 string id = parse_identifier ();
948 expect (TokenType.ASSIGN);
949 var expr = parse_expression ();
951 return new MemberInitializer (id, expr, get_src (begin));
954 Expression parse_yield_expression () throws ParseError {
955 expect (TokenType.YIELD);
956 var expr = parse_expression ();
958 var call = expr as MethodCall;
959 if (call == null) {
960 Report.error (expr.source_reference, "syntax error, expected method call");
961 throw new ParseError.SYNTAX ("expected method call");
964 call.is_yield_expression = true;
965 return call;
968 Expression parse_sizeof_expression () throws ParseError {
969 var begin = get_location ();
970 expect (TokenType.SIZEOF);
971 expect (TokenType.OPEN_PARENS);
972 var type = parse_type (true, false);
973 expect (TokenType.CLOSE_PARENS);
975 return new SizeofExpression (type, get_src (begin));
978 Expression parse_typeof_expression () throws ParseError {
979 var begin = get_location ();
980 expect (TokenType.TYPEOF);
981 expect (TokenType.OPEN_PARENS);
982 var type = parse_type (true, false);
983 expect (TokenType.CLOSE_PARENS);
985 return new TypeofExpression (type, get_src (begin));
988 UnaryOperator get_unary_operator (TokenType token_type) {
989 switch (token_type) {
990 case TokenType.PLUS: return UnaryOperator.PLUS;
991 case TokenType.MINUS: return UnaryOperator.MINUS;
992 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
993 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
994 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
995 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
996 default: return UnaryOperator.NONE;
1000 Expression parse_unary_expression () throws ParseError {
1001 var begin = get_location ();
1002 var operator = get_unary_operator (current ());
1003 if (operator != UnaryOperator.NONE) {
1004 next ();
1005 var op = parse_unary_expression ();
1006 return new UnaryExpression (operator, op, get_src (begin));
1008 switch (current ()) {
1009 case TokenType.HASH:
1010 if (!context.deprecated) {
1011 Report.warning (get_last_src (), "deprecated syntax, use `(owned)` cast");
1013 next ();
1014 var op = parse_unary_expression ();
1015 return new ReferenceTransferExpression (op, get_src (begin));
1016 case TokenType.OPEN_PARENS:
1017 next ();
1018 switch (current ()) {
1019 case TokenType.OWNED:
1020 // (owned) foo
1021 next ();
1022 if (accept (TokenType.CLOSE_PARENS)) {
1023 var op = parse_unary_expression ();
1024 return new ReferenceTransferExpression (op, get_src (begin));
1026 break;
1027 case TokenType.VOID:
1028 case TokenType.DYNAMIC:
1029 case TokenType.IDENTIFIER:
1030 var type = parse_type (true, false);
1031 if (accept (TokenType.CLOSE_PARENS)) {
1032 // check follower to decide whether to create cast expression
1033 switch (current ()) {
1034 case TokenType.OP_NEG:
1035 case TokenType.TILDE:
1036 case TokenType.OPEN_PARENS:
1037 case TokenType.TRUE:
1038 case TokenType.FALSE:
1039 case TokenType.INTEGER_LITERAL:
1040 case TokenType.REAL_LITERAL:
1041 case TokenType.CHARACTER_LITERAL:
1042 case TokenType.STRING_LITERAL:
1043 case TokenType.TEMPLATE_STRING_LITERAL:
1044 case TokenType.VERBATIM_STRING_LITERAL:
1045 case TokenType.REGEX_LITERAL:
1046 case TokenType.NULL:
1047 case TokenType.THIS:
1048 case TokenType.BASE:
1049 case TokenType.NEW:
1050 case TokenType.YIELD:
1051 case TokenType.SIZEOF:
1052 case TokenType.TYPEOF:
1053 case TokenType.IDENTIFIER:
1054 case TokenType.PARAMS:
1055 var inner = parse_unary_expression ();
1056 return new CastExpression (inner, type, get_src (begin), false);
1057 default:
1058 break;
1061 break;
1062 case TokenType.OP_NEG:
1063 next ();
1064 if (accept (TokenType.CLOSE_PARENS)) {
1065 // (!) non-null cast
1066 var inner = parse_unary_expression ();
1067 return new CastExpression.non_null (inner, get_src (begin));
1069 break;
1070 default:
1071 break;
1073 // no cast expression
1074 rollback (begin);
1075 break;
1076 case TokenType.STAR:
1077 next ();
1078 var op = parse_unary_expression ();
1079 return new PointerIndirection (op, get_src (begin));
1080 case TokenType.BITWISE_AND:
1081 next ();
1082 var op = parse_unary_expression ();
1083 return new AddressofExpression (op, get_src (begin));
1084 default:
1085 break;
1088 var expr = parse_primary_expression ();
1089 return expr;
1092 BinaryOperator get_binary_operator (TokenType token_type) {
1093 switch (token_type) {
1094 case TokenType.STAR: return BinaryOperator.MUL;
1095 case TokenType.DIV: return BinaryOperator.DIV;
1096 case TokenType.PERCENT: return BinaryOperator.MOD;
1097 case TokenType.PLUS: return BinaryOperator.PLUS;
1098 case TokenType.MINUS: return BinaryOperator.MINUS;
1099 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
1100 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
1101 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
1102 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
1103 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
1104 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
1105 default: return BinaryOperator.NONE;
1109 Expression parse_multiplicative_expression () throws ParseError {
1110 var begin = get_location ();
1111 var left = parse_unary_expression ();
1112 bool found = true;
1113 while (found) {
1114 var operator = get_binary_operator (current ());
1115 switch (operator) {
1116 case BinaryOperator.MUL:
1117 case BinaryOperator.DIV:
1118 case BinaryOperator.MOD:
1119 next ();
1120 var right = parse_unary_expression ();
1121 left = new BinaryExpression (operator, left, right, get_src (begin));
1122 break;
1123 default:
1124 found = false;
1125 break;
1128 return left;
1131 Expression parse_additive_expression () throws ParseError {
1132 var begin = get_location ();
1133 var left = parse_multiplicative_expression ();
1134 bool found = true;
1135 while (found) {
1136 var operator = get_binary_operator (current ());
1137 switch (operator) {
1138 case BinaryOperator.PLUS:
1139 case BinaryOperator.MINUS:
1140 next ();
1141 var right = parse_multiplicative_expression ();
1142 left = new BinaryExpression (operator, left, right, get_src (begin));
1143 break;
1144 default:
1145 found = false;
1146 break;
1149 return left;
1152 Expression parse_shift_expression () throws ParseError {
1153 var begin = get_location ();
1154 var left = parse_additive_expression ();
1155 bool found = true;
1156 while (found) {
1157 switch (current ()) {
1158 case TokenType.OP_SHIFT_LEFT:
1159 next ();
1160 var right = parse_additive_expression ();
1161 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1162 break;
1163 // don't use OP_SHIFT_RIGHT to support >> for nested generics
1164 case TokenType.OP_GT:
1165 char* first_gt_pos = tokens[index].begin.pos;
1166 next ();
1167 // only accept >> when there is no space between the two > signs
1168 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1169 next ();
1170 var right = parse_additive_expression ();
1171 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1172 } else {
1173 prev ();
1174 found = false;
1176 break;
1177 default:
1178 found = false;
1179 break;
1182 return left;
1185 Expression parse_relational_expression () throws ParseError {
1186 var begin = get_location ();
1187 var left = parse_shift_expression ();
1189 bool first = true;
1190 bool found = true;
1191 while (found) {
1192 var operator = get_binary_operator (current ());
1193 switch (operator) {
1194 case BinaryOperator.LESS_THAN:
1195 case BinaryOperator.LESS_THAN_OR_EQUAL:
1196 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1197 next ();
1198 var right = parse_shift_expression ();
1199 left = new BinaryExpression (operator, left, right, get_src (begin));
1200 if (!first) {
1201 var be = (BinaryExpression) left;
1202 be.chained = true;
1203 if (!context.experimental) {
1204 Report.warning (left.source_reference, "chained relational expressions are experimental");
1207 first = false;
1208 break;
1209 case BinaryOperator.GREATER_THAN:
1210 next ();
1211 // ignore >> and >>= (two tokens due to generics)
1212 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1213 var right = parse_shift_expression ();
1214 left = new BinaryExpression (operator, left, right, get_src (begin));
1215 if (!first) {
1216 var be = (BinaryExpression) left;
1217 be.chained = true;
1218 if (!context.experimental) {
1219 Report.warning (left.source_reference, "chained relational expressions are experimental");
1222 first = false;
1223 } else {
1224 prev ();
1225 found = false;
1227 break;
1228 default:
1229 switch (current ()) {
1230 case TokenType.IS:
1231 next ();
1232 var type = parse_type (true, false);
1233 left = new TypeCheck (left, type, get_src (begin));
1234 break;
1235 case TokenType.AS:
1236 next ();
1237 var type = parse_type (true, false);
1238 left = new CastExpression (left, type, get_src (begin), true);
1239 break;
1240 default:
1241 found = false;
1242 break;
1244 break;
1247 return left;
1250 Expression parse_equality_expression () throws ParseError {
1251 var begin = get_location ();
1252 var left = parse_relational_expression ();
1253 bool found = true;
1254 while (found) {
1255 var operator = get_binary_operator (current ());
1256 switch (operator) {
1257 case BinaryOperator.EQUALITY:
1258 case BinaryOperator.INEQUALITY:
1259 next ();
1260 var right = parse_relational_expression ();
1261 left = new BinaryExpression (operator, left, right, get_src (begin));
1262 break;
1263 default:
1264 found = false;
1265 break;
1268 return left;
1271 Expression parse_and_expression () throws ParseError {
1272 var begin = get_location ();
1273 var left = parse_equality_expression ();
1274 while (accept (TokenType.BITWISE_AND)) {
1275 var right = parse_equality_expression ();
1276 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1278 return left;
1281 Expression parse_exclusive_or_expression () throws ParseError {
1282 var begin = get_location ();
1283 var left = parse_and_expression ();
1284 while (accept (TokenType.CARRET)) {
1285 var right = parse_and_expression ();
1286 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1288 return left;
1291 Expression parse_inclusive_or_expression () throws ParseError {
1292 var begin = get_location ();
1293 var left = parse_exclusive_or_expression ();
1294 while (accept (TokenType.BITWISE_OR)) {
1295 var right = parse_exclusive_or_expression ();
1296 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1298 return left;
1301 Expression parse_in_expression () throws ParseError {
1302 var begin = get_location ();
1303 var left = parse_inclusive_or_expression ();
1304 while (accept (TokenType.IN)) {
1305 var right = parse_inclusive_or_expression ();
1306 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1308 return left;
1311 Expression parse_conditional_and_expression () throws ParseError {
1312 var begin = get_location ();
1313 var left = parse_in_expression ();
1314 while (accept (TokenType.OP_AND)) {
1315 var right = parse_in_expression ();
1316 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1318 return left;
1321 Expression parse_conditional_or_expression () throws ParseError {
1322 var begin = get_location ();
1323 var left = parse_conditional_and_expression ();
1324 while (accept (TokenType.OP_OR)) {
1325 var right = parse_conditional_and_expression ();
1326 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1328 return left;
1331 Expression parse_coalescing_expression () throws ParseError {
1332 var begin = get_location ();
1333 var left = parse_conditional_or_expression ();
1334 if (accept (TokenType.OP_COALESCING)) {
1335 var right = parse_coalescing_expression ();
1336 return new BinaryExpression (BinaryOperator.COALESCE, left, right, get_src (begin));
1337 } else {
1338 return left;
1342 Expression parse_conditional_expression () throws ParseError {
1343 var begin = get_location ();
1344 var condition = parse_coalescing_expression ();
1345 if (accept (TokenType.INTERR)) {
1346 var true_expr = parse_expression ();
1347 expect (TokenType.COLON);
1348 var false_expr = parse_expression ();
1349 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1350 } else {
1351 return condition;
1355 Expression parse_lambda_expression () throws ParseError {
1356 var begin = get_location ();
1357 List<string> params = new ArrayList<string> ();
1358 if (accept (TokenType.OPEN_PARENS)) {
1359 if (current () != TokenType.CLOSE_PARENS) {
1360 do {
1361 params.add (parse_identifier ());
1362 } while (accept (TokenType.COMMA));
1364 expect (TokenType.CLOSE_PARENS);
1365 } else {
1366 params.add (parse_identifier ());
1368 expect (TokenType.LAMBDA);
1370 LambdaExpression lambda;
1371 if (current () == TokenType.OPEN_BRACE) {
1372 var block = parse_block ();
1373 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1374 } else {
1375 var expr = parse_expression ();
1376 lambda = new LambdaExpression (expr, get_src (begin));
1378 foreach (string param in params) {
1379 lambda.add_parameter (param);
1381 return lambda;
1384 AssignmentOperator get_assignment_operator (TokenType token_type) {
1385 switch (token_type) {
1386 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1387 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1388 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1389 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1390 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1391 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1392 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1393 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1394 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1395 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1396 default: return AssignmentOperator.NONE;
1400 Expression parse_expression () throws ParseError {
1401 var begin = get_location ();
1402 Expression expr = parse_conditional_expression ();
1404 if (current () == TokenType.LAMBDA) {
1405 rollback (begin);
1406 var lambda = parse_lambda_expression ();
1407 return lambda;
1410 while (true) {
1411 var operator = get_assignment_operator (current ());
1412 if (operator != AssignmentOperator.NONE) {
1413 next ();
1414 var rhs = parse_expression ();
1415 expr = new Assignment (expr, rhs, operator, get_src (begin));
1416 } else if (current () == TokenType.OP_GT) { // >>=
1417 char* first_gt_pos = tokens[index].begin.pos;
1418 next ();
1419 // only accept >>= when there is no space between the two > signs
1420 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1421 next ();
1422 var rhs = parse_expression ();
1423 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1424 } else {
1425 prev ();
1426 break;
1428 } else {
1429 break;
1433 return expr;
1436 void parse_statements (Block block) throws ParseError {
1437 while (current () != TokenType.CLOSE_BRACE
1438 && current () != TokenType.CASE
1439 && current () != TokenType.DEFAULT
1440 && current () != TokenType.EOF) {
1441 try {
1442 Statement stmt = null;
1443 bool is_decl = false;
1445 comment = scanner.pop_comment ();
1446 switch (current ()) {
1447 case TokenType.OPEN_BRACE:
1448 stmt = parse_block ();
1449 break;
1450 case TokenType.SEMICOLON:
1451 stmt = parse_empty_statement ();
1452 break;
1453 case TokenType.IF:
1454 stmt = parse_if_statement ();
1455 break;
1456 case TokenType.SWITCH:
1457 stmt = parse_switch_statement ();
1458 break;
1459 case TokenType.WHILE:
1460 stmt = parse_while_statement ();
1461 break;
1462 case TokenType.DO:
1463 stmt = parse_do_statement ();
1464 break;
1465 case TokenType.FOR:
1466 stmt = parse_for_statement ();
1467 break;
1468 case TokenType.FOREACH:
1469 stmt = parse_foreach_statement ();
1470 break;
1471 case TokenType.BREAK:
1472 stmt = parse_break_statement ();
1473 break;
1474 case TokenType.CONTINUE:
1475 stmt = parse_continue_statement ();
1476 break;
1477 case TokenType.RETURN:
1478 stmt = parse_return_statement ();
1479 break;
1480 case TokenType.YIELD:
1481 stmt = parse_yield_statement ();
1482 break;
1483 case TokenType.THROW:
1484 stmt = parse_throw_statement ();
1485 break;
1486 case TokenType.TRY:
1487 stmt = parse_try_statement ();
1488 break;
1489 case TokenType.LOCK:
1490 stmt = parse_lock_statement ();
1491 break;
1492 case TokenType.DELETE:
1493 stmt = parse_delete_statement ();
1494 break;
1495 case TokenType.VAR:
1496 is_decl = true;
1497 parse_local_variable_declarations (block);
1498 break;
1499 case TokenType.CONST:
1500 is_decl = true;
1501 parse_local_constant_declarations (block);
1502 break;
1503 case TokenType.OP_INC:
1504 case TokenType.OP_DEC:
1505 case TokenType.BASE:
1506 case TokenType.THIS:
1507 case TokenType.OPEN_PARENS:
1508 case TokenType.STAR:
1509 case TokenType.NEW:
1510 stmt = parse_expression_statement ();
1511 break;
1512 default:
1513 bool is_expr = is_expression ();
1514 if (is_expr) {
1515 stmt = parse_expression_statement ();
1516 } else {
1517 is_decl = true;
1518 parse_local_variable_declarations (block);
1520 break;
1523 if (!is_decl) {
1524 if (context.profile == Profile.DOVA && stmt is ReturnStatement) {
1525 // split
1526 // return foo;
1527 // into
1528 // result = foo;
1529 // return;
1530 var ret_stmt = (ReturnStatement) stmt;
1531 if (ret_stmt.return_expression != null) {
1532 var assignment = new Assignment (new MemberAccess.simple ("result", stmt.source_reference), ret_stmt.return_expression, AssignmentOperator.SIMPLE, stmt.source_reference);
1533 ret_stmt.return_expression = null;
1534 block.add_statement (new ExpressionStatement (assignment, stmt.source_reference));
1537 block.add_statement (stmt);
1539 } catch (ParseError e) {
1540 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1541 // beginning of next declaration or end of file reached
1542 // return what we have so far
1543 break;
1549 bool is_expression () throws ParseError {
1550 var begin = get_location ();
1552 // decide between declaration and expression statement
1553 skip_type ();
1554 switch (current ()) {
1555 // invocation expression
1556 case TokenType.OPEN_PARENS:
1557 // postfix increment
1558 case TokenType.OP_INC:
1559 // postfix decrement
1560 case TokenType.OP_DEC:
1561 // assignments
1562 case TokenType.ASSIGN:
1563 case TokenType.ASSIGN_ADD:
1564 case TokenType.ASSIGN_BITWISE_AND:
1565 case TokenType.ASSIGN_BITWISE_OR:
1566 case TokenType.ASSIGN_BITWISE_XOR:
1567 case TokenType.ASSIGN_DIV:
1568 case TokenType.ASSIGN_MUL:
1569 case TokenType.ASSIGN_PERCENT:
1570 case TokenType.ASSIGN_SHIFT_LEFT:
1571 case TokenType.ASSIGN_SUB:
1572 case TokenType.OP_GT: // >>=
1573 // member access
1574 case TokenType.DOT:
1575 // pointer member access
1576 case TokenType.OP_PTR:
1577 rollback (begin);
1578 return true;
1579 default:
1580 rollback (begin);
1581 return false;
1585 Block parse_embedded_statement () throws ParseError {
1586 if (current () == TokenType.OPEN_BRACE) {
1587 var block = parse_block ();
1588 return block;
1591 comment = scanner.pop_comment ();
1593 var block = new Block (get_src (get_location ()));
1595 var stmt = parse_embedded_statement_without_block ();
1596 if (context.profile == Profile.DOVA && stmt is ReturnStatement) {
1597 // split
1598 // return foo;
1599 // into
1600 // result = foo;
1601 // return;
1602 var ret_stmt = (ReturnStatement) stmt;
1603 if (ret_stmt.return_expression != null) {
1604 var assignment = new Assignment (new MemberAccess.simple ("result"), ret_stmt.return_expression);
1605 ret_stmt.return_expression = null;
1606 block.add_statement (new ExpressionStatement (assignment));
1609 block.add_statement (stmt);
1611 return block;
1615 Statement parse_embedded_statement_without_block () throws ParseError {
1616 switch (current ()) {
1617 case TokenType.SEMICOLON: return parse_empty_statement ();
1618 case TokenType.IF: return parse_if_statement ();
1619 case TokenType.SWITCH: return parse_switch_statement ();
1620 case TokenType.WHILE: return parse_while_statement ();
1621 case TokenType.DO: return parse_do_statement ();
1622 case TokenType.FOR: return parse_for_statement ();
1623 case TokenType.FOREACH: return parse_foreach_statement ();
1624 case TokenType.BREAK: return parse_break_statement ();
1625 case TokenType.CONTINUE: return parse_continue_statement ();
1626 case TokenType.RETURN: return parse_return_statement ();
1627 case TokenType.YIELD: return parse_yield_statement ();
1628 case TokenType.THROW: return parse_throw_statement ();
1629 case TokenType.TRY: return parse_try_statement ();
1630 case TokenType.LOCK: return parse_lock_statement ();
1631 case TokenType.DELETE: return parse_delete_statement ();
1632 case TokenType.VAR:
1633 case TokenType.CONST:
1634 throw new ParseError.SYNTAX (get_error ("embedded statement cannot be declaration "));
1635 case TokenType.OP_INC:
1636 case TokenType.OP_DEC:
1637 case TokenType.BASE:
1638 case TokenType.THIS:
1639 case TokenType.OPEN_PARENS:
1640 case TokenType.STAR:
1641 case TokenType.NEW:
1642 return parse_expression_statement ();
1643 default:
1644 if (is_expression ()) {
1645 return parse_expression_statement ();
1646 } else {
1647 throw new ParseError.SYNTAX (get_error ("embedded statement cannot be declaration"));
1652 Block parse_block () throws ParseError {
1653 var begin = get_location ();
1654 expect (TokenType.OPEN_BRACE);
1655 var block = new Block (get_src (begin));
1656 parse_statements (block);
1657 if (!accept (TokenType.CLOSE_BRACE)) {
1658 // only report error if it's not a secondary error
1659 if (context.report.get_errors () == 0) {
1660 Report.error (get_current_src (), "expected `}'");
1664 block.source_reference.last_line = get_current_src ().last_line;
1665 block.source_reference.last_column = get_current_src ().last_column;
1667 return block;
1670 Statement parse_empty_statement () throws ParseError {
1671 var begin = get_location ();
1672 expect (TokenType.SEMICOLON);
1673 return new EmptyStatement (get_src (begin));
1676 void parse_local_variable_declarations (Block block) throws ParseError {
1677 DataType variable_type;
1678 if (accept (TokenType.VAR)) {
1679 variable_type = null;
1680 } else {
1681 variable_type = parse_type (true, true);
1683 do {
1684 if (variable_type == null && accept (TokenType.OPEN_PARENS)) {
1685 // tuple
1686 var begin = get_location ();
1688 string[] identifiers = {};
1689 do {
1690 identifiers += parse_identifier ();
1691 } while (accept (TokenType.COMMA));
1692 expect (TokenType.CLOSE_PARENS);
1694 expect (TokenType.ASSIGN);
1695 var tuple = parse_expression ();
1696 var tuple_local = new LocalVariable (null, CodeNode.get_temp_name (), tuple, get_src (begin));
1697 block.add_statement (new DeclarationStatement (tuple_local, tuple_local.source_reference));
1699 for (int i = 0; i < identifiers.length; i++) {
1700 var temp_access = new MemberAccess.simple (tuple_local.name, tuple_local.source_reference);
1701 var ea = new ElementAccess (temp_access, tuple_local.source_reference);
1702 ea.append_index (new IntegerLiteral (i.to_string ()));
1703 var local = new LocalVariable (null, identifiers[i], ea, tuple_local.source_reference);
1704 block.add_statement (new DeclarationStatement (local, local.source_reference));
1707 continue;
1710 DataType type_copy = null;
1711 if (variable_type != null) {
1712 type_copy = variable_type.copy ();
1714 var local = parse_local_variable (type_copy);
1715 block.add_statement (new DeclarationStatement (local, local.source_reference));
1716 } while (accept (TokenType.COMMA));
1717 expect (TokenType.SEMICOLON);
1720 LocalVariable parse_local_variable (DataType? variable_type) throws ParseError {
1721 var begin = get_location ();
1722 string id = parse_identifier ();
1724 var type = parse_inline_array_type (variable_type);
1726 Expression initializer = null;
1727 if (accept (TokenType.ASSIGN)) {
1728 initializer = parse_expression ();
1730 return new LocalVariable (type, id, initializer, get_src (begin));
1733 void parse_local_constant_declarations (Block block) throws ParseError {
1734 expect (TokenType.CONST);
1735 var constant_type = parse_type (false, false);
1736 do {
1737 DataType type_copy = constant_type.copy ();
1738 var local = parse_local_constant (type_copy);
1739 block.add_statement (new DeclarationStatement (local, local.source_reference));
1740 block.add_local_constant (local);
1741 local.active = false;
1742 } while (accept (TokenType.COMMA));
1743 expect (TokenType.SEMICOLON);
1746 Constant parse_local_constant (DataType constant_type) throws ParseError {
1747 var begin = get_location ();
1748 string id = parse_identifier ();
1750 var type = parse_inline_array_type (constant_type);
1752 expect (TokenType.ASSIGN);
1753 var initializer = parse_expression ();
1755 return new Constant (id, type, initializer, get_src (begin));
1758 Statement parse_expression_statement () throws ParseError {
1759 var begin = get_location ();
1760 var expr = parse_statement_expression ();
1761 expect (TokenType.SEMICOLON);
1762 return new ExpressionStatement (expr, get_src (begin));
1765 Expression parse_statement_expression () throws ParseError {
1766 // invocation expression, assignment,
1767 // or pre/post increment/decrement expression
1768 var expr = parse_expression ();
1769 return expr;
1772 Statement parse_if_statement () throws ParseError {
1773 var begin = get_location ();
1774 expect (TokenType.IF);
1775 expect (TokenType.OPEN_PARENS);
1776 var condition = parse_expression ();
1777 expect (TokenType.CLOSE_PARENS);
1778 var src = get_src (begin);
1779 var true_stmt = parse_embedded_statement ();
1780 Block false_stmt = null;
1781 if (accept (TokenType.ELSE)) {
1782 false_stmt = parse_embedded_statement ();
1784 return new IfStatement (condition, true_stmt, false_stmt, src);
1787 Statement parse_switch_statement () throws ParseError {
1788 var begin = get_location ();
1789 expect (TokenType.SWITCH);
1790 expect (TokenType.OPEN_PARENS);
1791 var condition = parse_expression ();
1792 expect (TokenType.CLOSE_PARENS);
1793 var stmt = new SwitchStatement (condition, get_src (begin));
1794 expect (TokenType.OPEN_BRACE);
1795 while (current () != TokenType.CLOSE_BRACE) {
1796 var section = new SwitchSection (get_src (begin));
1797 do {
1798 if (accept (TokenType.CASE)) {
1799 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
1800 } else {
1801 expect (TokenType.DEFAULT);
1802 section.add_label (new SwitchLabel.with_default (get_src (begin)));
1804 expect (TokenType.COLON);
1805 } while (current () == TokenType.CASE || current () == TokenType.DEFAULT);
1806 parse_statements (section);
1807 stmt.add_section (section);
1809 expect (TokenType.CLOSE_BRACE);
1810 return stmt;
1813 Statement parse_while_statement () throws ParseError {
1814 var begin = get_location ();
1815 expect (TokenType.WHILE);
1816 expect (TokenType.OPEN_PARENS);
1817 var condition = parse_expression ();
1818 expect (TokenType.CLOSE_PARENS);
1819 var body = parse_embedded_statement ();
1820 return new WhileStatement (condition, body, get_src (begin));
1823 Statement parse_do_statement () throws ParseError {
1824 var begin = get_location ();
1825 expect (TokenType.DO);
1826 var body = parse_embedded_statement ();
1827 expect (TokenType.WHILE);
1828 expect (TokenType.OPEN_PARENS);
1829 var condition = parse_expression ();
1830 expect (TokenType.CLOSE_PARENS);
1831 expect (TokenType.SEMICOLON);
1832 return new DoStatement (body, condition, get_src (begin));
1835 Statement parse_for_statement () throws ParseError {
1836 var begin = get_location ();
1837 Block block = null;
1838 expect (TokenType.FOR);
1839 expect (TokenType.OPEN_PARENS);
1840 var initializer_list = new ArrayList<Expression> ();
1841 if (!accept (TokenType.SEMICOLON)) {
1842 bool is_expr;
1843 switch (current ()) {
1844 case TokenType.VAR:
1845 is_expr = false;
1846 break;
1847 case TokenType.OP_INC:
1848 case TokenType.OP_DEC:
1849 is_expr = true;
1850 break;
1851 default:
1852 is_expr = is_expression ();
1853 break;
1856 if (is_expr) {
1857 do {
1858 initializer_list.add (parse_statement_expression ());
1859 } while (accept (TokenType.COMMA));
1860 expect (TokenType.SEMICOLON);
1861 } else {
1862 // variable declaration in initializer
1863 block = new Block (get_src (begin));
1864 parse_local_variable_declarations (block);
1867 Expression condition = null;
1868 if (current () != TokenType.SEMICOLON) {
1869 condition = parse_expression ();
1871 expect (TokenType.SEMICOLON);
1872 var iterator_list = new ArrayList<Expression> ();
1873 if (current () != TokenType.CLOSE_PARENS) {
1874 do {
1875 iterator_list.add (parse_statement_expression ());
1876 } while (accept (TokenType.COMMA));
1878 expect (TokenType.CLOSE_PARENS);
1879 var src = get_src (begin);
1880 var body = parse_embedded_statement ();
1881 var stmt = new ForStatement (condition, body, src);
1882 foreach (Expression init in initializer_list) {
1883 stmt.add_initializer (init);
1885 foreach (Expression iter in iterator_list) {
1886 stmt.add_iterator (iter);
1888 if (block != null) {
1889 block.add_statement (stmt);
1890 return block;
1891 } else {
1892 return stmt;
1896 Statement parse_foreach_statement () throws ParseError {
1897 var begin = get_location ();
1898 expect (TokenType.FOREACH);
1899 expect (TokenType.OPEN_PARENS);
1900 DataType type = null;
1901 if (!accept (TokenType.VAR)) {
1902 type = parse_type (true, true);
1903 if (accept (TokenType.IN)) {
1904 Report.error (type.source_reference, "syntax error, expected var or type");
1905 throw new ParseError.SYNTAX ("expected var or type");
1908 string id = parse_identifier ();
1909 expect (TokenType.IN);
1910 var collection = parse_expression ();
1911 expect (TokenType.CLOSE_PARENS);
1912 var src = get_src (begin);
1913 var body = parse_embedded_statement ();
1914 return new ForeachStatement (type, id, collection, body, src);
1917 Statement parse_break_statement () throws ParseError {
1918 var begin = get_location ();
1919 expect (TokenType.BREAK);
1920 expect (TokenType.SEMICOLON);
1921 return new BreakStatement (get_src (begin));
1924 Statement parse_continue_statement () throws ParseError {
1925 var begin = get_location ();
1926 expect (TokenType.CONTINUE);
1927 expect (TokenType.SEMICOLON);
1928 return new ContinueStatement (get_src (begin));
1931 Statement parse_return_statement () throws ParseError {
1932 var begin = get_location ();
1933 expect (TokenType.RETURN);
1934 Expression expr = null;
1935 if (current () != TokenType.SEMICOLON) {
1936 expr = parse_expression ();
1938 expect (TokenType.SEMICOLON);
1939 return new ReturnStatement (expr, get_src (begin));
1942 Statement parse_yield_statement () throws ParseError {
1943 var begin = get_location ();
1944 expect (TokenType.YIELD);
1945 if (current () != TokenType.SEMICOLON && current () != TokenType.RETURN) {
1946 // yield expression
1947 prev ();
1948 return parse_expression_statement ();
1950 Expression expr = null;
1951 if (accept (TokenType.RETURN)) {
1952 expr = parse_expression ();
1954 expect (TokenType.SEMICOLON);
1955 return new YieldStatement (expr, get_src (begin));
1958 Statement parse_throw_statement () throws ParseError {
1959 var begin = get_location ();
1960 expect (TokenType.THROW);
1961 var expr = parse_expression ();
1962 expect (TokenType.SEMICOLON);
1963 return new ThrowStatement (expr, get_src (begin));
1966 Statement parse_try_statement () throws ParseError {
1967 var begin = get_location ();
1968 expect (TokenType.TRY);
1969 var try_block = parse_block ();
1970 Block finally_clause = null;
1971 var catch_clauses = new ArrayList<CatchClause> ();
1972 if (current () == TokenType.CATCH) {
1973 parse_catch_clauses (catch_clauses);
1974 if (current () == TokenType.FINALLY) {
1975 finally_clause = parse_finally_clause ();
1977 } else {
1978 finally_clause = parse_finally_clause ();
1980 var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
1981 foreach (CatchClause clause in catch_clauses) {
1982 stmt.add_catch_clause (clause);
1984 return stmt;
1987 void parse_catch_clauses (List<CatchClause> catch_clauses) throws ParseError {
1988 while (accept (TokenType.CATCH)) {
1989 var begin = get_location ();
1990 DataType type = null;
1991 string id = null;
1992 if (accept (TokenType.OPEN_PARENS)) {
1993 type = parse_type (true, true);
1994 id = parse_identifier ();
1995 expect (TokenType.CLOSE_PARENS);
1997 var block = parse_block ();
1998 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
2002 Block parse_finally_clause () throws ParseError {
2003 expect (TokenType.FINALLY);
2004 var block = parse_block ();
2005 return block;
2008 Statement parse_lock_statement () throws ParseError {
2009 var begin = get_location ();
2010 expect (TokenType.LOCK);
2011 expect (TokenType.OPEN_PARENS);
2012 var expr = parse_expression ();
2013 expect (TokenType.CLOSE_PARENS);
2014 var stmt = parse_embedded_statement ();
2015 return new LockStatement (expr, stmt, get_src (begin));
2018 Statement parse_delete_statement () throws ParseError {
2019 var begin = get_location ();
2020 expect (TokenType.DELETE);
2021 var expr = parse_expression ();
2022 expect (TokenType.SEMICOLON);
2023 return new DeleteStatement (expr, get_src (begin));
2026 string parse_attribute_value () throws ParseError {
2027 switch (current ()) {
2028 case TokenType.NULL:
2029 case TokenType.TRUE:
2030 case TokenType.FALSE:
2031 case TokenType.INTEGER_LITERAL:
2032 case TokenType.REAL_LITERAL:
2033 case TokenType.STRING_LITERAL:
2034 next ();
2035 return get_last_string ();
2036 case TokenType.MINUS:
2037 next ();
2038 switch (current ()) {
2039 case TokenType.INTEGER_LITERAL:
2040 case TokenType.REAL_LITERAL:
2041 next ();
2042 return "-" + get_last_string ();
2043 default:
2044 throw new ParseError.SYNTAX (get_error ("expected number"));
2046 default:
2047 throw new ParseError.SYNTAX (get_error ("expected literal"));
2051 List<Attribute>? parse_attributes () throws ParseError {
2052 if (current () != TokenType.OPEN_BRACKET) {
2053 return null;
2055 var attrs = new ArrayList<Attribute> ();
2056 while (accept (TokenType.OPEN_BRACKET)) {
2057 do {
2058 var begin = get_location ();
2059 string id = parse_identifier ();
2060 var attr = new Attribute (id, get_src (begin));
2061 if (accept (TokenType.OPEN_PARENS)) {
2062 if (current () != TokenType.CLOSE_PARENS) {
2063 do {
2064 id = parse_identifier ();
2065 expect (TokenType.ASSIGN);
2066 attr.add_argument (id, parse_attribute_value ());
2067 } while (accept (TokenType.COMMA));
2069 expect (TokenType.CLOSE_PARENS);
2071 attrs.add (attr);
2072 } while (accept (TokenType.COMMA));
2073 expect (TokenType.CLOSE_BRACKET);
2075 return attrs;
2078 void set_attributes (CodeNode node, List<Attribute>? attributes) {
2079 if (attributes != null) {
2080 foreach (Attribute attr in (List<Attribute>) attributes) {
2081 node.attributes.append (attr);
2086 void parse_main_block (Symbol parent) throws ParseError {
2087 var begin = get_location ();
2089 var method = new Method ("main", new VoidType (), get_src (begin));
2090 method.body = new Block (get_src (begin));
2091 parse_statements (method.body);
2092 if (current () != TokenType.EOF) {
2093 Report.error (get_current_src (), "expected end of file");
2096 method.body.source_reference.last_line = get_current_src ().last_line;
2097 method.body.source_reference.last_column = get_current_src ().last_column;
2099 if (!context.experimental && context.profile != Profile.DOVA) {
2100 Report.warning (method.source_reference, "main blocks are experimental");
2103 parent.add_method (method);
2106 void parse_declaration (Symbol parent, bool root = false) throws ParseError {
2107 comment = scanner.pop_comment ();
2108 var attrs = parse_attributes ();
2110 var begin = get_location ();
2112 TokenType last_keyword = current ();
2114 while (is_declaration_keyword (current ())) {
2115 last_keyword = current ();
2116 next ();
2119 switch (current ()) {
2120 case TokenType.CONSTRUCT:
2121 if (context.profile == Profile.GOBJECT) {
2122 rollback (begin);
2123 parse_constructor_declaration (parent, attrs);
2124 return;
2126 break;
2127 case TokenType.TILDE:
2128 rollback (begin);
2129 parse_destructor_declaration (parent, attrs);
2130 return;
2131 case TokenType.OPEN_BRACE:
2132 case TokenType.SEMICOLON:
2133 case TokenType.IF:
2134 case TokenType.SWITCH:
2135 case TokenType.WHILE:
2136 case TokenType.DO:
2137 case TokenType.FOR:
2138 case TokenType.FOREACH:
2139 case TokenType.BREAK:
2140 case TokenType.CONTINUE:
2141 case TokenType.RETURN:
2142 case TokenType.YIELD:
2143 case TokenType.THROW:
2144 case TokenType.TRY:
2145 case TokenType.LOCK:
2146 case TokenType.DELETE:
2147 case TokenType.VAR:
2148 case TokenType.OP_INC:
2149 case TokenType.OP_DEC:
2150 case TokenType.BASE:
2151 case TokenType.THIS:
2152 case TokenType.OPEN_PARENS:
2153 case TokenType.STAR:
2154 case TokenType.NEW:
2155 // statement
2156 if (attrs != null) {
2157 // no attributes allowed before statements
2158 throw new ParseError.SYNTAX (get_error ("expected statement"));
2160 if (!root) {
2161 throw new ParseError.SYNTAX (get_error ("statements outside blocks allowed only in root namespace"));
2163 rollback (begin);
2164 parse_main_block (parent);
2165 return;
2166 default:
2167 if (root) {
2168 bool is_expr = is_expression ();
2169 if (is_expr) {
2170 rollback (begin);
2171 parse_main_block (parent);
2172 return;
2176 skip_type ();
2177 switch (current ()) {
2178 case TokenType.OPEN_BRACE:
2179 case TokenType.SEMICOLON:
2180 case TokenType.COLON:
2181 rollback (begin);
2182 switch (last_keyword) {
2183 case TokenType.CLASS:
2184 parse_class_declaration (parent, attrs);
2185 return;
2186 case TokenType.ENUM:
2187 parse_enum_declaration (parent, attrs);
2188 return;
2189 case TokenType.ERRORDOMAIN:
2190 parse_errordomain_declaration (parent, attrs);
2191 return;
2192 case TokenType.INTERFACE:
2193 parse_interface_declaration (parent, attrs);
2194 return;
2195 case TokenType.NAMESPACE:
2196 parse_namespace_declaration (parent, attrs);
2197 return;
2198 case TokenType.STRUCT:
2199 parse_struct_declaration (parent, attrs);
2200 return;
2201 default:
2202 break;
2204 break;
2205 case TokenType.OPEN_PARENS:
2206 rollback (begin);
2207 parse_creation_method_declaration (parent, attrs);
2208 return;
2209 default:
2210 skip_type (); // might contain type parameter list
2211 switch (current ()) {
2212 case TokenType.OPEN_PARENS:
2213 rollback (begin);
2214 switch (last_keyword) {
2215 case TokenType.DELEGATE:
2216 parse_delegate_declaration (parent, attrs);
2217 return;
2218 case TokenType.SIGNAL:
2219 parse_signal_declaration (parent, attrs);
2220 return;
2221 default:
2222 parse_method_declaration (parent, attrs);
2223 return;
2225 case TokenType.ASSIGN:
2226 case TokenType.SEMICOLON:
2227 rollback (begin);
2228 switch (last_keyword) {
2229 case TokenType.CONST:
2230 parse_constant_declaration (parent, attrs);
2231 return;
2232 default:
2233 parse_field_declaration (parent, attrs);
2234 return;
2236 case TokenType.OPEN_BRACE:
2237 case TokenType.THROWS:
2238 rollback (begin);
2239 parse_property_declaration (parent, attrs);
2240 return;
2241 default:
2242 break;
2244 break;
2246 break;
2249 rollback (begin);
2251 throw new ParseError.SYNTAX (get_error ("expected declaration"));
2254 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
2255 if (!root) {
2256 expect (TokenType.OPEN_BRACE);
2258 while (current () != TokenType.CLOSE_BRACE && current () != TokenType.EOF) {
2259 try {
2260 parse_declaration (parent, (parent == context.root));
2261 } catch (ParseError e) {
2262 int r;
2263 do {
2264 r = recover ();
2265 if (r == RecoveryState.STATEMENT_BEGIN) {
2266 next ();
2267 } else {
2268 break;
2270 } while (true);
2271 if (r == RecoveryState.EOF) {
2272 return;
2276 if (!root) {
2277 if (!accept (TokenType.CLOSE_BRACE)) {
2278 // only report error if it's not a secondary error
2279 if (context.report.get_errors () == 0) {
2280 Report.error (get_current_src (), "expected `}'");
2286 enum RecoveryState {
2287 EOF,
2288 DECLARATION_BEGIN,
2289 STATEMENT_BEGIN
2292 RecoveryState recover () {
2293 while (current () != TokenType.EOF) {
2294 switch (current ()) {
2295 case TokenType.ABSTRACT:
2296 case TokenType.CLASS:
2297 case TokenType.CONST:
2298 case TokenType.CONSTRUCT:
2299 case TokenType.DELEGATE:
2300 case TokenType.ENUM:
2301 case TokenType.ERRORDOMAIN:
2302 case TokenType.EXTERN:
2303 case TokenType.INLINE:
2304 case TokenType.INTERFACE:
2305 case TokenType.INTERNAL:
2306 case TokenType.NAMESPACE:
2307 case TokenType.NEW:
2308 case TokenType.OVERRIDE:
2309 case TokenType.PRIVATE:
2310 case TokenType.PROTECTED:
2311 case TokenType.PUBLIC:
2312 case TokenType.SEALED:
2313 case TokenType.SIGNAL:
2314 case TokenType.STATIC:
2315 case TokenType.STRUCT:
2316 case TokenType.VIRTUAL:
2317 case TokenType.VOLATILE:
2318 return RecoveryState.DECLARATION_BEGIN;
2319 case TokenType.BREAK:
2320 case TokenType.CONTINUE:
2321 case TokenType.DELETE:
2322 case TokenType.DO:
2323 case TokenType.FOR:
2324 case TokenType.FOREACH:
2325 case TokenType.IF:
2326 case TokenType.LOCK:
2327 case TokenType.RETURN:
2328 case TokenType.SWITCH:
2329 case TokenType.THROW:
2330 case TokenType.TRY:
2331 case TokenType.VAR:
2332 case TokenType.WHILE:
2333 case TokenType.YIELD:
2334 return RecoveryState.STATEMENT_BEGIN;
2335 default:
2336 next ();
2337 break;
2340 return RecoveryState.EOF;
2343 void parse_namespace_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2344 var begin = get_location ();
2345 expect (TokenType.NAMESPACE);
2346 var sym = parse_symbol_name ();
2347 var ns = new Namespace (sym.name, get_src (begin));
2348 if (comment != null) {
2349 ns.add_comment (comment);
2350 comment = null;
2353 set_attributes (ns, attrs);
2355 expect (TokenType.OPEN_BRACE);
2357 var old_using_directives = scanner.source_file.current_using_directives;
2358 parse_using_directives (ns);
2360 parse_declarations (ns, true);
2362 scanner.source_file.current_using_directives = old_using_directives;
2364 if (!accept (TokenType.CLOSE_BRACE)) {
2365 // only report error if it's not a secondary error
2366 if (context.report.get_errors () == 0) {
2367 Report.error (get_current_src (), "expected `}'");
2371 Symbol result = ns;
2372 while (sym != null) {
2373 sym = sym.inner;
2375 Symbol next = (sym != null ? new Namespace (sym.name, ns.source_reference) : parent);
2376 next.add_namespace ((Namespace) result);
2377 result = next;
2381 void parse_using_directives (Namespace ns) throws ParseError {
2382 while (accept (TokenType.USING)) {
2383 do {
2384 var begin = get_location ();
2385 var sym = parse_symbol_name ();
2386 var ns_ref = new UsingDirective (sym, get_src (begin));
2387 scanner.source_file.add_using_directive (ns_ref);
2388 ns.add_using_directive (ns_ref);
2389 } while (accept (TokenType.COMMA));
2390 expect (TokenType.SEMICOLON);
2394 void parse_class_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2395 var begin = get_location ();
2396 var access = parse_access_modifier ();
2397 var flags = parse_type_declaration_modifiers ();
2398 expect (TokenType.CLASS);
2399 var sym = parse_symbol_name ();
2400 var type_param_list = parse_type_parameter_list ();
2401 var base_types = new ArrayList<DataType> ();
2402 if (accept (TokenType.COLON)) {
2403 do {
2404 base_types.add (parse_type (true, false));
2405 } while (accept (TokenType.COMMA));
2408 var cl = new Class (sym.name, get_src (begin), comment);
2409 cl.access = access;
2410 if (ModifierFlags.ABSTRACT in flags) {
2411 cl.is_abstract = true;
2413 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2414 cl.external = true;
2416 set_attributes (cl, attrs);
2417 foreach (TypeParameter type_param in type_param_list) {
2418 cl.add_type_parameter (type_param);
2420 foreach (DataType base_type in base_types) {
2421 cl.add_base_type (base_type);
2424 parse_declarations (cl);
2426 // ensure there is always a default construction method
2427 if (scanner.source_file.file_type == SourceFileType.SOURCE
2428 && cl.default_construction_method == null) {
2429 var m = new CreationMethod (cl.name, null, cl.source_reference);
2430 m.access = SymbolAccessibility.PUBLIC;
2431 m.body = new Block (cl.source_reference);
2432 cl.add_method (m);
2435 Symbol result = cl;
2436 while (sym != null) {
2437 sym = sym.inner;
2439 Symbol next = (sym != null ? new Namespace (sym.name, cl.source_reference) : parent);
2440 if (result is Namespace) {
2441 next.add_namespace ((Namespace) result);
2442 } else {
2443 next.add_class ((Class) result);
2445 result = next;
2449 void parse_constant_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2450 var begin = get_location ();
2451 var access = parse_access_modifier ();
2452 var flags = parse_member_declaration_modifiers ();
2453 expect (TokenType.CONST);
2454 var type = parse_type (false, false);
2455 string id = parse_identifier ();
2457 type = parse_inline_array_type (type);
2459 Expression initializer = null;
2460 if (accept (TokenType.ASSIGN)) {
2461 initializer = parse_expression ();
2463 expect (TokenType.SEMICOLON);
2465 // constant arrays don't own their element
2466 var array_type = type as ArrayType;
2467 if (array_type != null) {
2468 array_type.element_type.value_owned = false;
2471 var c = new Constant (id, type, initializer, get_src (begin), comment);
2472 c.access = access;
2473 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2474 c.external = true;
2476 if (ModifierFlags.NEW in flags) {
2477 c.hides = true;
2479 set_attributes (c, attrs);
2481 parent.add_constant (c);
2484 void parse_field_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2485 var begin = get_location ();
2486 var access = parse_access_modifier ();
2487 var flags = parse_member_declaration_modifiers ();
2488 if (context.profile == Profile.DOVA) {
2489 accept (TokenType.VOLATILE);
2491 var type = parse_type (true, true);
2492 string id = parse_identifier ();
2494 type = parse_inline_array_type (type);
2496 var f = new Field (id, type, null, get_src (begin), comment);
2497 f.access = access;
2498 set_attributes (f, attrs);
2499 if (ModifierFlags.STATIC in flags) {
2500 f.binding = MemberBinding.STATIC;
2501 } else if (ModifierFlags.CLASS in flags) {
2502 f.binding = MemberBinding.CLASS;
2504 if (ModifierFlags.ABSTRACT in flags
2505 || ModifierFlags.VIRTUAL in flags
2506 || ModifierFlags.OVERRIDE in flags) {
2507 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2509 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2510 f.external = true;
2512 if (ModifierFlags.NEW in flags) {
2513 f.hides = true;
2515 if (accept (TokenType.ASSIGN)) {
2516 f.initializer = parse_expression ();
2518 expect (TokenType.SEMICOLON);
2520 parent.add_field (f);
2523 InitializerList parse_initializer () throws ParseError {
2524 var begin = get_location ();
2525 expect (TokenType.OPEN_BRACE);
2526 var initializer = new InitializerList (get_src (begin));
2527 if (current () != TokenType.CLOSE_BRACE) {
2528 do {
2529 var init = parse_argument ();
2530 initializer.append (init);
2531 } while (accept (TokenType.COMMA));
2533 expect (TokenType.CLOSE_BRACE);
2534 return initializer;
2537 ListLiteral parse_list_literal () throws ParseError {
2538 var begin = get_location ();
2539 expect (TokenType.OPEN_BRACKET);
2540 var initializer = new ListLiteral (get_src (begin));
2541 if (current () != TokenType.CLOSE_BRACKET) {
2542 do {
2543 var init = parse_expression ();
2544 initializer.add_expression (init);
2545 } while (accept (TokenType.COMMA));
2547 expect (TokenType.CLOSE_BRACKET);
2548 return initializer;
2551 Expression parse_set_literal () throws ParseError {
2552 var begin = get_location ();
2553 expect (TokenType.OPEN_BRACE);
2554 var set = new SetLiteral (get_src (begin));
2555 bool first = true;
2556 if (current () != TokenType.CLOSE_BRACE) {
2557 do {
2558 var expr = parse_expression ();
2559 if (first && accept (TokenType.COLON)) {
2560 // found colon after expression, it's a map
2561 rollback (begin);
2562 return parse_map_literal ();
2564 first = false;
2565 set.add_expression (expr);
2566 } while (accept (TokenType.COMMA));
2568 expect (TokenType.CLOSE_BRACE);
2569 return set;
2572 Expression parse_map_literal () throws ParseError {
2573 var begin = get_location ();
2574 expect (TokenType.OPEN_BRACE);
2575 var map = new MapLiteral (get_src (begin));
2576 if (current () != TokenType.CLOSE_BRACE) {
2577 do {
2578 var key = parse_expression ();
2579 map.add_key (key);
2580 expect (TokenType.COLON);
2581 var value = parse_expression ();
2582 map.add_value (value);
2583 } while (accept (TokenType.COMMA));
2585 expect (TokenType.CLOSE_BRACE);
2586 return map;
2589 void parse_method_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2590 var begin = get_location ();
2591 var access = parse_access_modifier ();
2592 var flags = parse_member_declaration_modifiers ();
2593 var type = parse_type (true, false);
2594 string id = parse_identifier ();
2595 var type_param_list = parse_type_parameter_list ();
2596 var method = new Method (id, type, get_src (begin), comment);
2597 method.access = access;
2598 set_attributes (method, attrs);
2599 foreach (TypeParameter type_param in type_param_list) {
2600 method.add_type_parameter (type_param);
2602 if (ModifierFlags.STATIC in flags) {
2603 method.binding = MemberBinding.STATIC;
2604 } else if (ModifierFlags.CLASS in flags) {
2605 method.binding = MemberBinding.CLASS;
2607 if (ModifierFlags.ASYNC in flags) {
2608 method.coroutine = true;
2610 if (ModifierFlags.NEW in flags) {
2611 method.hides = true;
2614 if (method.binding == MemberBinding.INSTANCE) {
2615 if (ModifierFlags.ABSTRACT in flags) {
2616 method.is_abstract = true;
2618 if (ModifierFlags.VIRTUAL in flags) {
2619 method.is_virtual = true;
2621 if (ModifierFlags.OVERRIDE in flags) {
2622 method.overrides = true;
2624 if ((method.is_abstract && method.is_virtual)
2625 || (method.is_abstract && method.overrides)
2626 || (method.is_virtual && method.overrides)) {
2627 throw new ParseError.SYNTAX (get_error ("only one of `abstract', `virtual', or `override' may be specified"));
2629 } else {
2630 if (ModifierFlags.ABSTRACT in flags
2631 || ModifierFlags.VIRTUAL in flags
2632 || ModifierFlags.OVERRIDE in flags) {
2633 throw new ParseError.SYNTAX (get_error ("the modifiers `abstract', `virtual', and `override' are not valid for static methods"));
2637 if (ModifierFlags.INLINE in flags) {
2638 method.is_inline = true;
2640 if (ModifierFlags.EXTERN in flags) {
2641 method.external = true;
2643 expect (TokenType.OPEN_PARENS);
2644 if (current () != TokenType.CLOSE_PARENS) {
2645 do {
2646 var param = parse_parameter ();
2647 method.add_parameter (param);
2648 } while (accept (TokenType.COMMA));
2650 expect (TokenType.CLOSE_PARENS);
2651 if (context.profile == Profile.DOVA) {
2652 var error_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (new UnresolvedSymbol (null, "Dova"), "Error"), method.source_reference);
2653 method.add_error_type (error_type);
2654 if (accept (TokenType.THROWS)) {
2655 do {
2656 parse_type (true, false);
2657 } while (accept (TokenType.COMMA));
2658 Report.warning (method.source_reference, "`throws' is ignored in the Dova profile");
2660 } else {
2661 if (accept (TokenType.THROWS)) {
2662 do {
2663 method.add_error_type (parse_type (true, false));
2664 } while (accept (TokenType.COMMA));
2667 while (accept (TokenType.REQUIRES)) {
2668 expect (TokenType.OPEN_PARENS);
2669 method.add_precondition (parse_expression ());
2670 expect (TokenType.CLOSE_PARENS);
2672 while (accept (TokenType.ENSURES)) {
2673 expect (TokenType.OPEN_PARENS);
2674 method.add_postcondition (parse_expression ());
2675 expect (TokenType.CLOSE_PARENS);
2677 if (!accept (TokenType.SEMICOLON)) {
2678 method.body = parse_block ();
2679 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
2680 method.external = true;
2683 parent.add_method (method);
2686 void parse_property_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2687 var begin = get_location ();
2688 var access = parse_access_modifier ();
2689 var flags = parse_member_declaration_modifiers ();
2690 var type = parse_type (true, true);
2692 bool getter_owned = false;
2693 if (context.profile == Profile.DOVA) {
2694 getter_owned = true;
2695 } else if (accept (TokenType.HASH)) {
2696 if (!context.deprecated) {
2697 Report.warning (get_last_src (), "deprecated syntax, use `owned` modifier before `get'");
2699 getter_owned = true;
2702 string id = parse_identifier ();
2703 var prop = new Property (id, type, null, null, get_src (begin), comment);
2704 prop.access = access;
2705 set_attributes (prop, attrs);
2706 if (ModifierFlags.STATIC in flags) {
2707 prop.binding = MemberBinding.STATIC;
2708 } else if (ModifierFlags.CLASS in flags) {
2709 prop.binding = MemberBinding.CLASS;
2711 if (ModifierFlags.ABSTRACT in flags) {
2712 prop.is_abstract = true;
2714 if (ModifierFlags.VIRTUAL in flags) {
2715 prop.is_virtual = true;
2717 if (ModifierFlags.OVERRIDE in flags) {
2718 prop.overrides = true;
2720 if (ModifierFlags.NEW in flags) {
2721 prop.hides = true;
2723 if (ModifierFlags.ASYNC in flags) {
2724 Report.error (prop.source_reference, "async properties are not supported yet");
2726 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2727 prop.external = true;
2729 if (context.profile == Profile.DOVA) {
2730 } else {
2731 if (accept (TokenType.THROWS)) {
2732 do {
2733 prop.add_error_type (parse_type (true, false));
2734 } while (accept (TokenType.COMMA));
2735 Report.error (prop.source_reference, "properties throwing errors are not supported yet");
2738 expect (TokenType.OPEN_BRACE);
2739 while (current () != TokenType.CLOSE_BRACE) {
2740 if (accept (TokenType.DEFAULT)) {
2741 if (prop.initializer != null) {
2742 throw new ParseError.SYNTAX (get_error ("property default value already defined"));
2744 expect (TokenType.ASSIGN);
2745 prop.initializer = parse_expression ();
2746 expect (TokenType.SEMICOLON);
2747 } else {
2748 comment = scanner.pop_comment ();
2750 var accessor_begin = get_location ();
2751 var accessor_attrs = parse_attributes ();
2752 var accessor_access = parse_access_modifier (SymbolAccessibility.PUBLIC);
2754 var value_type = type.copy ();
2755 value_type.value_owned = (context.profile != Profile.DOVA && accept (TokenType.OWNED));
2757 if (accept (TokenType.GET)) {
2758 if (prop.get_accessor != null) {
2759 throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
2762 if (getter_owned) {
2763 value_type.value_owned = true;
2766 Block block = null;
2767 if (!accept (TokenType.SEMICOLON)) {
2768 block = parse_block ();
2769 prop.external = false;
2771 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin), comment);
2772 set_attributes (prop.get_accessor, accessor_attrs);
2773 prop.get_accessor.access = accessor_access;
2774 } else {
2775 bool writable, _construct;
2776 if (accept (TokenType.SET)) {
2777 writable = true;
2778 _construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT);
2779 } else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) {
2780 _construct = true;
2781 writable = accept (TokenType.SET);
2782 } else {
2783 throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
2785 if (prop.set_accessor != null) {
2786 throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
2788 Block block = null;
2789 if (!accept (TokenType.SEMICOLON)) {
2790 block = parse_block ();
2791 prop.external = false;
2793 prop.set_accessor = new PropertyAccessor (false, writable, _construct, value_type, block, get_src (accessor_begin), comment);
2794 set_attributes (prop.set_accessor, accessor_attrs);
2795 prop.set_accessor.access = accessor_access;
2799 expect (TokenType.CLOSE_BRACE);
2801 if (!prop.is_abstract && prop.source_type == SourceFileType.SOURCE) {
2802 bool empty_get = (prop.get_accessor != null && prop.get_accessor.body == null);
2803 bool empty_set = (prop.set_accessor != null && prop.set_accessor.body == null);
2805 if (empty_get != empty_set) {
2806 if (empty_get) {
2807 Report.error (prop.source_reference, "property getter must have a body");
2808 } else if (empty_set) {
2809 Report.error (prop.source_reference, "property setter must have a body");
2811 prop.error = true;
2814 if (empty_get && empty_set) {
2815 /* automatic property accessor body generation */
2816 var variable_type = prop.property_type.copy ();
2817 prop.field = new Field ("_%s".printf (prop.name), variable_type, prop.initializer, prop.source_reference);
2818 prop.field.access = SymbolAccessibility.PRIVATE;
2819 prop.field.binding = prop.binding;
2820 } else if (prop.initializer != null) {
2821 Report.error (prop.initializer.source_reference, "only automatic properties can have default values");
2825 parent.add_property (prop);
2828 void parse_signal_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2829 var begin = get_location ();
2830 var access = parse_access_modifier ();
2831 var flags = parse_member_declaration_modifiers ();
2832 expect (TokenType.SIGNAL);
2833 var type = parse_type (true, false);
2834 string id = parse_identifier ();
2835 var sig = new Signal (id, type, get_src (begin), comment);
2836 sig.access = access;
2837 set_attributes (sig, attrs);
2838 if (ModifierFlags.STATIC in flags) {
2839 throw new ParseError.SYNTAX (get_error ("`static' modifier not allowed on signals"));
2840 } else if (ModifierFlags.CLASS in flags) {
2841 throw new ParseError.SYNTAX (get_error ("`class' modifier not allowed on signals"));
2843 if (ModifierFlags.VIRTUAL in flags) {
2844 sig.is_virtual = true;
2846 if (ModifierFlags.NEW in flags) {
2847 sig.hides = true;
2849 expect (TokenType.OPEN_PARENS);
2850 if (current () != TokenType.CLOSE_PARENS) {
2851 do {
2852 var param = parse_parameter ();
2853 sig.add_parameter (param);
2854 } while (accept (TokenType.COMMA));
2856 expect (TokenType.CLOSE_PARENS);
2857 if (!accept (TokenType.SEMICOLON)) {
2858 sig.body = parse_block ();
2861 parent.add_signal (sig);
2864 void parse_constructor_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2865 var begin = get_location ();
2866 var flags = parse_member_declaration_modifiers ();
2867 expect (TokenType.CONSTRUCT);
2868 if (ModifierFlags.NEW in flags) {
2869 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on constructor"));
2871 var c = new Constructor (get_src (begin));
2872 if (ModifierFlags.STATIC in flags) {
2873 c.binding = MemberBinding.STATIC;
2874 } else if (ModifierFlags.CLASS in flags) {
2875 c.binding = MemberBinding.CLASS;
2877 c.body = parse_block ();
2879 parent.add_constructor (c);
2882 void parse_destructor_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2883 var begin = get_location ();
2884 var flags = parse_member_declaration_modifiers ();
2885 expect (TokenType.TILDE);
2886 parse_identifier ();
2887 expect (TokenType.OPEN_PARENS);
2888 expect (TokenType.CLOSE_PARENS);
2889 if (ModifierFlags.NEW in flags) {
2890 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on destructor"));
2892 var d = new Destructor (get_src (begin));
2893 if (ModifierFlags.STATIC in flags) {
2894 d.binding = MemberBinding.STATIC;
2895 } else if (ModifierFlags.CLASS in flags) {
2896 d.binding = MemberBinding.CLASS;
2898 d.body = parse_block ();
2900 parent.add_destructor (d);
2903 void parse_struct_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2904 var begin = get_location ();
2905 var access = parse_access_modifier ();
2906 var flags = parse_type_declaration_modifiers ();
2907 expect (TokenType.STRUCT);
2908 var sym = parse_symbol_name ();
2909 var type_param_list = parse_type_parameter_list ();
2910 DataType base_type = null;
2911 if (accept (TokenType.COLON)) {
2912 base_type = parse_type (true, false);
2914 var st = new Struct (sym.name, get_src (begin), comment);
2915 st.access = access;
2916 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2917 st.external = true;
2919 set_attributes (st, attrs);
2920 foreach (TypeParameter type_param in type_param_list) {
2921 st.add_type_parameter (type_param);
2923 if (base_type != null) {
2924 st.base_type = base_type;
2927 parse_declarations (st);
2929 Symbol result = st;
2930 while (sym != null) {
2931 sym = sym.inner;
2933 Symbol next = (sym != null ? new Namespace (sym.name, st.source_reference) : parent);
2934 if (result is Namespace) {
2935 next.add_namespace ((Namespace) result);
2936 } else {
2937 next.add_struct ((Struct) result);
2939 result = next;
2943 void parse_interface_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2944 var begin = get_location ();
2945 var access = parse_access_modifier ();
2946 var flags = parse_type_declaration_modifiers ();
2947 expect (TokenType.INTERFACE);
2948 var sym = parse_symbol_name ();
2949 var type_param_list = parse_type_parameter_list ();
2950 var base_types = new ArrayList<DataType> ();
2951 if (accept (TokenType.COLON)) {
2952 do {
2953 var type = parse_type (true, false);
2954 base_types.add (type);
2955 } while (accept (TokenType.COMMA));
2957 var iface = new Interface (sym.name, get_src (begin), comment);
2958 iface.access = access;
2959 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2960 iface.external = true;
2962 set_attributes (iface, attrs);
2963 foreach (TypeParameter type_param in type_param_list) {
2964 iface.add_type_parameter (type_param);
2966 foreach (DataType base_type in base_types) {
2967 iface.add_prerequisite (base_type);
2970 parse_declarations (iface);
2972 Symbol result = iface;
2973 while (sym != null) {
2974 sym = sym.inner;
2976 Symbol next = (sym != null ? new Namespace (sym.name, iface.source_reference) : parent);
2977 if (result is Namespace) {
2978 next.add_namespace ((Namespace) result);
2979 } else {
2980 next.add_interface ((Interface) result);
2982 result = next;
2986 void parse_enum_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
2987 var begin = get_location ();
2988 var access = parse_access_modifier ();
2989 var flags = parse_type_declaration_modifiers ();
2990 expect (TokenType.ENUM);
2991 var sym = parse_symbol_name ();
2992 var en = new Enum (sym.name, get_src (begin), comment);
2993 en.access = access;
2994 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
2995 en.external = true;
2997 set_attributes (en, attrs);
2999 expect (TokenType.OPEN_BRACE);
3000 do {
3001 if (current () == TokenType.CLOSE_BRACE
3002 && en.get_values ().size > 0) {
3003 // allow trailing comma
3004 break;
3006 var value_attrs = parse_attributes ();
3007 var value_begin = get_location ();
3008 string id = parse_identifier ();
3009 comment = scanner.pop_comment ();
3011 Expression value = null;
3012 if (accept (TokenType.ASSIGN)) {
3013 value = parse_expression ();
3016 var ev = new EnumValue (id, value, get_src (value_begin), comment);
3017 ev.access = SymbolAccessibility.PUBLIC;
3018 set_attributes (ev, value_attrs);
3019 en.add_value (ev);
3020 } while (accept (TokenType.COMMA));
3021 if (accept (TokenType.SEMICOLON)) {
3022 // enum methods
3023 while (current () != TokenType.CLOSE_BRACE) {
3024 parse_declaration (en);
3027 expect (TokenType.CLOSE_BRACE);
3029 Symbol result = en;
3030 while (sym != null) {
3031 sym = sym.inner;
3033 Symbol next = (sym != null ? new Namespace (sym.name, en.source_reference) : parent);
3034 if (result is Namespace) {
3035 next.add_namespace ((Namespace) result);
3036 } else {
3037 next.add_enum ((Enum) result);
3039 result = next;
3043 void parse_errordomain_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3044 var begin = get_location ();
3045 var access = parse_access_modifier ();
3046 var flags = parse_type_declaration_modifiers ();
3047 expect (TokenType.ERRORDOMAIN);
3048 var sym = parse_symbol_name ();
3049 var ed = new ErrorDomain (sym.name, get_src (begin), comment);
3050 ed.access = access;
3051 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3052 ed.external = true;
3054 set_attributes (ed, attrs);
3056 expect (TokenType.OPEN_BRACE);
3057 do {
3058 if (current () == TokenType.CLOSE_BRACE
3059 && ed.get_codes ().size > 0) {
3060 // allow trailing comma
3061 break;
3063 var code_attrs = parse_attributes ();
3064 var code_begin = get_location ();
3065 string id = parse_identifier ();
3066 comment = scanner.pop_comment ();
3067 var ec = new ErrorCode (id, get_src (code_begin), comment);
3068 set_attributes (ec, code_attrs);
3069 if (accept (TokenType.ASSIGN)) {
3070 ec.value = parse_expression ();
3072 ed.add_code (ec);
3073 } while (accept (TokenType.COMMA));
3074 if (accept (TokenType.SEMICOLON)) {
3075 // errordomain methods
3076 while (current () != TokenType.CLOSE_BRACE) {
3077 parse_declaration (ed);
3080 expect (TokenType.CLOSE_BRACE);
3082 Symbol result = ed;
3083 while (sym != null) {
3084 sym = sym.inner;
3086 Symbol next = (sym != null ? new Namespace (sym.name, ed.source_reference) : parent);
3087 if (result is Namespace) {
3088 next.add_namespace ((Namespace) result);
3089 } else {
3090 next.add_error_domain ((ErrorDomain) result);
3092 result = next;
3096 SymbolAccessibility parse_access_modifier (SymbolAccessibility default_access = SymbolAccessibility.PRIVATE) {
3097 switch (current ()) {
3098 case TokenType.PRIVATE:
3099 next ();
3100 return SymbolAccessibility.PRIVATE;
3101 case TokenType.PROTECTED:
3102 next ();
3103 return SymbolAccessibility.PROTECTED;
3104 case TokenType.INTERNAL:
3105 next ();
3106 return SymbolAccessibility.INTERNAL;
3107 case TokenType.PUBLIC:
3108 next ();
3109 return SymbolAccessibility.PUBLIC;
3110 default:
3111 return default_access;
3115 ModifierFlags parse_type_declaration_modifiers () {
3116 ModifierFlags flags = 0;
3117 while (true) {
3118 switch (current ()) {
3119 case TokenType.ABSTRACT:
3120 next ();
3121 flags |= ModifierFlags.ABSTRACT;
3122 break;
3123 case TokenType.EXTERN:
3124 next ();
3125 flags |= ModifierFlags.EXTERN;
3126 break;
3127 case TokenType.SEALED:
3128 next ();
3129 flags |= ModifierFlags.SEALED;
3130 break;
3131 case TokenType.STATIC:
3132 next ();
3133 flags |= ModifierFlags.STATIC;
3134 break;
3135 default:
3136 return flags;
3141 ModifierFlags parse_member_declaration_modifiers () {
3142 ModifierFlags flags = 0;
3143 while (true) {
3144 switch (current ()) {
3145 case TokenType.ABSTRACT:
3146 next ();
3147 flags |= ModifierFlags.ABSTRACT;
3148 break;
3149 case TokenType.ASYNC:
3150 next ();
3151 flags |= ModifierFlags.ASYNC;
3152 break;
3153 case TokenType.CLASS:
3154 next ();
3155 flags |= ModifierFlags.CLASS;
3156 break;
3157 case TokenType.EXTERN:
3158 next ();
3159 flags |= ModifierFlags.EXTERN;
3160 break;
3161 case TokenType.INLINE:
3162 next ();
3163 flags |= ModifierFlags.INLINE;
3164 break;
3165 case TokenType.NEW:
3166 next ();
3167 flags |= ModifierFlags.NEW;
3168 break;
3169 case TokenType.OVERRIDE:
3170 next ();
3171 flags |= ModifierFlags.OVERRIDE;
3172 break;
3173 case TokenType.SEALED:
3174 next ();
3175 flags |= ModifierFlags.SEALED;
3176 break;
3177 case TokenType.STATIC:
3178 next ();
3179 flags |= ModifierFlags.STATIC;
3180 break;
3181 case TokenType.VIRTUAL:
3182 next ();
3183 flags |= ModifierFlags.VIRTUAL;
3184 break;
3185 default:
3186 return flags;
3191 Parameter parse_parameter () throws ParseError {
3192 var attrs = parse_attributes ();
3193 var begin = get_location ();
3194 if (accept (TokenType.ELLIPSIS)) {
3195 // varargs
3196 return new Parameter.with_ellipsis (get_src (begin));
3198 bool params_array = accept (TokenType.PARAMS);
3199 var direction = ParameterDirection.IN;
3200 if (accept (TokenType.OUT)) {
3201 direction = ParameterDirection.OUT;
3202 } else if (accept (TokenType.REF)) {
3203 direction = ParameterDirection.REF;
3206 if (context.profile == Profile.DOVA) {
3207 accept (TokenType.VOLATILE);
3209 DataType type;
3210 if (direction == ParameterDirection.IN) {
3211 // in parameters are unowned by default
3212 type = parse_type (false, false);
3213 } else if (direction == ParameterDirection.REF) {
3214 // ref parameters own the value by default
3215 type = parse_type (true, true);
3216 } else {
3217 // out parameters own the value by default
3218 type = parse_type (true, false);
3220 string id = parse_identifier ();
3222 type = parse_inline_array_type (type);
3224 var param = new Parameter (id, type, get_src (begin));
3225 set_attributes (param, attrs);
3226 param.direction = direction;
3227 param.params_array = params_array;
3228 if (accept (TokenType.ASSIGN)) {
3229 param.initializer = parse_expression ();
3231 return param;
3234 void parse_creation_method_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3235 var begin = get_location ();
3236 var access = parse_access_modifier ();
3237 var flags = parse_member_declaration_modifiers ();
3238 var sym = parse_symbol_name ();
3239 if (ModifierFlags.NEW in flags) {
3240 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on creation method"));
3242 CreationMethod method;
3243 if (sym.inner == null) {
3244 method = new CreationMethod (sym.name, null, get_src (begin), comment);
3245 } else {
3246 method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
3248 if (ModifierFlags.EXTERN in flags) {
3249 method.external = true;
3251 if (ModifierFlags.ABSTRACT in flags
3252 || ModifierFlags.VIRTUAL in flags
3253 || ModifierFlags.OVERRIDE in flags) {
3254 Report.error (method.source_reference, "abstract, virtual, and override modifiers are not applicable to creation methods");
3256 if (ModifierFlags.ASYNC in flags) {
3257 method.coroutine = true;
3259 expect (TokenType.OPEN_PARENS);
3260 if (current () != TokenType.CLOSE_PARENS) {
3261 do {
3262 var param = parse_parameter ();
3263 method.add_parameter (param);
3264 } while (accept (TokenType.COMMA));
3266 expect (TokenType.CLOSE_PARENS);
3267 if (context.profile == Profile.DOVA) {
3268 var error_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (new UnresolvedSymbol (null, "Dova"), "Error"), method.source_reference);
3269 method.add_error_type (error_type);
3270 if (accept (TokenType.THROWS)) {
3271 do {
3272 parse_type (true, false);
3273 } while (accept (TokenType.COMMA));
3274 Report.warning (method.source_reference, "`throws' is ignored in the Dova profile");
3276 } else {
3277 if (accept (TokenType.THROWS)) {
3278 do {
3279 method.add_error_type (parse_type (true, false));
3280 } while (accept (TokenType.COMMA));
3283 while (accept (TokenType.REQUIRES)) {
3284 expect (TokenType.OPEN_PARENS);
3285 method.add_precondition (parse_expression ());
3286 expect (TokenType.CLOSE_PARENS);
3288 while (accept (TokenType.ENSURES)) {
3289 expect (TokenType.OPEN_PARENS);
3290 method.add_postcondition (parse_expression ());
3291 expect (TokenType.CLOSE_PARENS);
3293 method.access = access;
3294 set_attributes (method, attrs);
3295 if (!accept (TokenType.SEMICOLON)) {
3296 method.body = parse_block ();
3297 } else if (scanner.source_file.file_type == SourceFileType.PACKAGE) {
3298 method.external = true;
3301 parent.add_method (method);
3304 void parse_delegate_declaration (Symbol parent, List<Attribute>? attrs) throws ParseError {
3305 var begin = get_location ();
3306 var access = parse_access_modifier ();
3307 var flags = parse_member_declaration_modifiers ();
3308 expect (TokenType.DELEGATE);
3309 if (ModifierFlags.NEW in flags) {
3310 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on delegates"));
3312 var type = parse_type (true, false);
3313 var sym = parse_symbol_name ();
3314 var type_param_list = parse_type_parameter_list ();
3315 var d = new Delegate (sym.name, type, get_src (begin), comment);
3316 d.access = access;
3317 set_attributes (d, attrs);
3318 if (ModifierFlags.STATIC in flags) {
3319 if (!context.deprecated) {
3320 // TODO enable warning in future releases
3321 Report.warning (get_last_src (), "deprecated syntax, use [CCode (has_target = false)]");
3323 } else {
3324 d.has_target = true;
3326 if (ModifierFlags.EXTERN in flags || scanner.source_file.file_type == SourceFileType.PACKAGE) {
3327 d.external = true;
3329 foreach (TypeParameter type_param in type_param_list) {
3330 d.add_type_parameter (type_param);
3332 expect (TokenType.OPEN_PARENS);
3333 if (current () != TokenType.CLOSE_PARENS) {
3334 do {
3335 var param = parse_parameter ();
3336 d.add_parameter (param);
3337 } while (accept (TokenType.COMMA));
3339 expect (TokenType.CLOSE_PARENS);
3340 if (context.profile == Profile.DOVA) {
3341 var error_type = new UnresolvedType.from_symbol (new UnresolvedSymbol (new UnresolvedSymbol (null, "Dova"), "Error"), d.source_reference);
3342 d.add_error_type (error_type);
3343 if (accept (TokenType.THROWS)) {
3344 do {
3345 parse_type (true, false);
3346 } while (accept (TokenType.COMMA));
3347 Report.warning (d.source_reference, "`throws' is ignored in the Dova profile");
3349 } else {
3350 if (accept (TokenType.THROWS)) {
3351 do {
3352 d.add_error_type (parse_type (true, false));
3353 } while (accept (TokenType.COMMA));
3356 expect (TokenType.SEMICOLON);
3358 Symbol result = d;
3359 while (sym != null) {
3360 sym = sym.inner;
3362 Symbol next = (sym != null ? new Namespace (sym.name, d.source_reference) : parent);
3363 if (result is Namespace) {
3364 next.add_namespace ((Namespace) result);
3365 } else {
3366 next.add_delegate ((Delegate) result);
3368 result = next;
3372 List<TypeParameter> parse_type_parameter_list () throws ParseError {
3373 if (accept (TokenType.OP_LT)) {
3374 var list = new ArrayList<TypeParameter> ();
3375 do {
3376 var begin = get_location ();
3377 string id = parse_identifier ();
3378 list.add (new TypeParameter (id, get_src (begin)));
3379 } while (accept (TokenType.COMMA));
3380 expect (TokenType.OP_GT);
3381 return list;
3382 } else {
3383 if (_empty_type_parameter_list == null) {
3384 _empty_type_parameter_list = new ArrayList<TypeParameter> ();
3386 return _empty_type_parameter_list;
3390 void skip_type_argument_list () throws ParseError {
3391 if (accept (TokenType.OP_LT)) {
3392 do {
3393 skip_type ();
3394 } while (accept (TokenType.COMMA));
3395 expect (TokenType.OP_GT);
3399 // try to parse type argument list
3400 List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3401 var begin = get_location ();
3402 if (accept (TokenType.OP_LT)) {
3403 var list = new ArrayList<DataType> ();
3404 do {
3405 switch (current ()) {
3406 case TokenType.VOID:
3407 case TokenType.DYNAMIC:
3408 case TokenType.UNOWNED:
3409 case TokenType.WEAK:
3410 case TokenType.IDENTIFIER:
3411 var type = parse_type (true, true);
3412 list.add (type);
3413 break;
3414 default:
3415 rollback (begin);
3416 return null;
3418 } while (accept (TokenType.COMMA));
3419 if (!accept (TokenType.OP_GT)) {
3420 rollback (begin);
3421 return null;
3423 if (maybe_expression) {
3424 // check follower to decide whether to keep type argument list
3425 switch (current ()) {
3426 case TokenType.OPEN_PARENS:
3427 case TokenType.CLOSE_PARENS:
3428 case TokenType.CLOSE_BRACKET:
3429 case TokenType.OPEN_BRACE:
3430 case TokenType.COLON:
3431 case TokenType.SEMICOLON:
3432 case TokenType.COMMA:
3433 case TokenType.DOT:
3434 case TokenType.INTERR:
3435 case TokenType.OP_EQ:
3436 case TokenType.OP_NE:
3437 // keep type argument list
3438 break;
3439 default:
3440 // interpret tokens as expression
3441 rollback (begin);
3442 return null;
3445 return list;
3447 return null;
3450 MemberAccess parse_member_name (Expression? base_expr = null) throws ParseError {
3451 var begin = get_location ();
3452 MemberAccess expr = null;
3453 bool first = true;
3454 do {
3455 string id = parse_identifier ();
3457 // The first member access can be global:: qualified
3458 bool qualified = false;
3459 if (first && id == "global" && accept (TokenType.DOUBLE_COLON)) {
3460 id = parse_identifier ();
3461 qualified = true;
3464 List<DataType> type_arg_list = parse_type_argument_list (false);
3465 expr = new MemberAccess (expr != null ? expr : base_expr, id, get_src (begin));
3466 expr.qualified = qualified;
3467 if (type_arg_list != null) {
3468 foreach (DataType type_arg in type_arg_list) {
3469 expr.add_type_argument (type_arg);
3473 first = false;
3474 } while (accept (TokenType.DOT));
3475 return expr;
3478 bool is_declaration_keyword (TokenType type) {
3479 switch (type) {
3480 case TokenType.ABSTRACT:
3481 case TokenType.ASYNC:
3482 case TokenType.CLASS:
3483 case TokenType.CONST:
3484 case TokenType.DELEGATE:
3485 case TokenType.ENUM:
3486 case TokenType.ERRORDOMAIN:
3487 case TokenType.EXTERN:
3488 case TokenType.INLINE:
3489 case TokenType.INTERFACE:
3490 case TokenType.INTERNAL:
3491 case TokenType.NAMESPACE:
3492 case TokenType.NEW:
3493 case TokenType.OVERRIDE:
3494 case TokenType.PRIVATE:
3495 case TokenType.PROTECTED:
3496 case TokenType.PUBLIC:
3497 case TokenType.SEALED:
3498 case TokenType.SIGNAL:
3499 case TokenType.STATIC:
3500 case TokenType.STRUCT:
3501 case TokenType.VIRTUAL:
3502 case TokenType.VOLATILE:
3503 return true;
3504 default:
3505 return false;
3510 public errordomain Vala.ParseError {
3511 FAILED,
3512 SYNTAX