Insert "%s" argument in printf calls with non-literal format string
[vala-lang.git] / vala / valaparser.vala
blob2fa695b11d50de00d44b733c7126c51dbbaa1caa
1 /* valaparser.vala
3 * Copyright (C) 2006-2009 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;
24 using Gee;
26 /**
27 * Code visitor parsing all Vala source files.
29 public class Vala.Parser : CodeVisitor {
30 Scanner scanner;
32 CodeContext context;
34 // token buffer
35 TokenInfo[] tokens;
36 // index of current token in buffer
37 int index;
38 // number of tokens in buffer
39 int size;
41 Comment comment;
43 const int BUFFER_SIZE = 32;
45 struct TokenInfo {
46 public TokenType type;
47 public SourceLocation begin;
48 public SourceLocation end;
51 enum ModifierFlags {
52 NONE,
53 ABSTRACT = 1 << 0,
54 CLASS = 1 << 1,
55 EXTERN = 1 << 2,
56 INLINE = 1 << 3,
57 NEW = 1 << 4,
58 OVERRIDE = 1 << 5,
59 STATIC = 1 << 6,
60 VIRTUAL = 1 << 7,
61 ASYNC = 1 << 8
64 public Parser () {
65 tokens = new TokenInfo[BUFFER_SIZE];
68 /**
69 * Parses all .vala and .vapi source files in the specified code
70 * context and builds a code tree.
72 * @param context a code context
74 public void parse (CodeContext context) {
75 this.context = context;
76 context.accept (this);
79 public override void visit_source_file (SourceFile source_file) {
80 if (source_file.filename.has_suffix (".vala") || source_file.filename.has_suffix (".vapi")) {
81 parse_file (source_file);
85 inline bool next () {
86 index = (index + 1) % BUFFER_SIZE;
87 size--;
88 if (size <= 0) {
89 SourceLocation begin, end;
90 TokenType type = scanner.read_token (out begin, out end);
91 tokens[index].type = type;
92 tokens[index].begin = begin;
93 tokens[index].end = end;
94 size = 1;
96 return (tokens[index].type != TokenType.EOF);
99 inline void prev () {
100 index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
101 size++;
102 assert (size <= BUFFER_SIZE);
105 inline TokenType current () {
106 return tokens[index].type;
109 inline bool accept (TokenType type) {
110 if (current () == type) {
111 next ();
112 return true;
114 return false;
117 string get_error (string msg) {
118 var begin = get_location ();
119 next ();
120 Report.error (get_src (begin), "syntax error, " + msg);
121 return msg;
124 inline bool expect (TokenType type) throws ParseError {
125 if (accept (type)) {
126 return true;
129 throw new ParseError.SYNTAX (get_error ("expected %s".printf (type.to_string ())));
132 inline SourceLocation get_location () {
133 return tokens[index].begin;
136 string get_current_string () {
137 return ((string) tokens[index].begin.pos).ndup ((tokens[index].end.pos - tokens[index].begin.pos));
140 string get_last_string () {
141 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
142 return ((string) tokens[last_index].begin.pos).ndup ((tokens[last_index].end.pos - tokens[last_index].begin.pos));
145 SourceReference get_src (SourceLocation begin) {
146 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
148 return new SourceReference (scanner.source_file, begin.line, begin.column, tokens[last_index].end.line, tokens[last_index].end.column);
151 SourceReference get_current_src () {
152 return new SourceReference (scanner.source_file, tokens[index].begin.line, tokens[index].begin.column, tokens[index].end.line, tokens[index].end.column);
155 SourceReference get_last_src () {
156 int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
158 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);
161 void rollback (SourceLocation location) {
162 while (tokens[index].begin.pos != location.pos) {
163 prev ();
167 void skip_identifier () throws ParseError {
168 // also accept keywords as identifiers where there is no conflict
169 switch (current ()) {
170 case TokenType.ABSTRACT:
171 case TokenType.AS:
172 case TokenType.ASYNC:
173 case TokenType.BASE:
174 case TokenType.BREAK:
175 case TokenType.CASE:
176 case TokenType.CATCH:
177 case TokenType.CLASS:
178 case TokenType.CONST:
179 case TokenType.CONSTRUCT:
180 case TokenType.CONTINUE:
181 case TokenType.DEFAULT:
182 case TokenType.DELEGATE:
183 case TokenType.DELETE:
184 case TokenType.DO:
185 case TokenType.DYNAMIC:
186 case TokenType.ELSE:
187 case TokenType.ENUM:
188 case TokenType.ENSURES:
189 case TokenType.ERRORDOMAIN:
190 case TokenType.EXTERN:
191 case TokenType.FALSE:
192 case TokenType.FINALLY:
193 case TokenType.FOR:
194 case TokenType.FOREACH:
195 case TokenType.GET:
196 case TokenType.IDENTIFIER:
197 case TokenType.IF:
198 case TokenType.IN:
199 case TokenType.INLINE:
200 case TokenType.INTERFACE:
201 case TokenType.INTERNAL:
202 case TokenType.IS:
203 case TokenType.LOCK:
204 case TokenType.NAMESPACE:
205 case TokenType.NEW:
206 case TokenType.NULL:
207 case TokenType.OUT:
208 case TokenType.OVERRIDE:
209 case TokenType.OWNED:
210 case TokenType.PARAMS:
211 case TokenType.PRIVATE:
212 case TokenType.PROTECTED:
213 case TokenType.PUBLIC:
214 case TokenType.REF:
215 case TokenType.REQUIRES:
216 case TokenType.RETURN:
217 case TokenType.SET:
218 case TokenType.SIGNAL:
219 case TokenType.SIZEOF:
220 case TokenType.STATIC:
221 case TokenType.STRUCT:
222 case TokenType.SWITCH:
223 case TokenType.THIS:
224 case TokenType.THROW:
225 case TokenType.THROWS:
226 case TokenType.TRUE:
227 case TokenType.TRY:
228 case TokenType.TYPEOF:
229 case TokenType.UNOWNED:
230 case TokenType.USING:
231 case TokenType.VAR:
232 case TokenType.VIRTUAL:
233 case TokenType.VOID:
234 case TokenType.VOLATILE:
235 case TokenType.WEAK:
236 case TokenType.WHILE:
237 case TokenType.YIELD:
238 next ();
239 return;
240 case TokenType.INTEGER_LITERAL:
241 case TokenType.REAL_LITERAL:
242 // also accept integer and real literals
243 // as long as they contain at least one character
244 // and no decimal point
245 // for example, 2D and 3D
246 string id = get_current_string ();
247 if (id[id.length - 1].isalpha () && !("." in id)) {
248 next ();
249 return;
251 break;
252 default:
253 throw new ParseError.SYNTAX (get_error ("expected identifier"));
257 string parse_identifier () throws ParseError {
258 skip_identifier ();
259 return get_last_string ();
262 Expression parse_literal () throws ParseError {
263 var begin = get_location ();
265 switch (current ()) {
266 case TokenType.TRUE:
267 next ();
268 return new BooleanLiteral (true, get_src (begin));
269 case TokenType.FALSE:
270 next ();
271 return new BooleanLiteral (false, get_src (begin));
272 case TokenType.INTEGER_LITERAL:
273 next ();
274 return new IntegerLiteral (get_last_string (), get_src (begin));
275 case TokenType.REAL_LITERAL:
276 next ();
277 return new RealLiteral (get_last_string (), get_src (begin));
278 case TokenType.CHARACTER_LITERAL:
279 next ();
280 // FIXME validate and unescape here and just pass unichar to CharacterLiteral
281 var lit = new CharacterLiteral (get_last_string (), get_src (begin));
282 if (lit.error) {
283 Report.error (lit.source_reference, "invalid character literal");
285 return lit;
286 case TokenType.STRING_LITERAL:
287 next ();
288 return new StringLiteral (get_last_string (), get_src (begin));
289 case TokenType.TEMPLATE_STRING_LITERAL:
290 next ();
291 return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
292 case TokenType.VERBATIM_STRING_LITERAL:
293 next ();
294 string raw_string = get_last_string ();
295 string escaped_string = raw_string.substring (3, raw_string.len () - 6).escape ("");
296 return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
297 case TokenType.NULL:
298 next ();
299 return new NullLiteral (get_src (begin));
300 default:
301 throw new ParseError.SYNTAX (get_error ("expected literal"));
305 public void parse_file (SourceFile source_file) {
306 scanner = new Scanner (source_file);
307 parse_file_comments ();
309 index = -1;
310 size = 0;
312 next ();
315 try {
316 parse_using_directives (context.root);
317 parse_declarations (context.root, true);
318 if (accept (TokenType.CLOSE_BRACE)) {
319 // only report error if it's not a secondary error
320 if (context.report.get_errors () == 0) {
321 Report.error (get_last_src (), "unexpected `}'");
324 } catch (ParseError e) {
325 // already reported
328 scanner = null;
331 void parse_file_comments () {
332 scanner.parse_file_comments ();
335 void skip_symbol_name () throws ParseError {
336 do {
337 skip_identifier ();
338 } while (accept (TokenType.DOT) || accept (TokenType.DOUBLE_COLON));
341 UnresolvedSymbol parse_symbol_name () throws ParseError {
342 var begin = get_location ();
343 UnresolvedSymbol sym = null;
344 do {
345 string name = parse_identifier ();
346 if (name == "global" && accept (TokenType.DOUBLE_COLON)) {
347 // global::Name
348 // qualified access to global symbol
349 name = parse_identifier ();
350 sym = new UnresolvedSymbol (sym, name, get_src (begin));
351 sym.qualified = true;
352 continue;
354 sym = new UnresolvedSymbol (sym, name, get_src (begin));
355 } while (accept (TokenType.DOT));
356 return sym;
359 void skip_type () throws ParseError {
360 if (accept (TokenType.VOID)) {
361 while (accept (TokenType.STAR)) {
363 return;
365 accept (TokenType.DYNAMIC);
366 accept (TokenType.OWNED);
367 accept (TokenType.UNOWNED);
368 accept (TokenType.WEAK);
369 skip_symbol_name ();
370 skip_type_argument_list ();
371 while (accept (TokenType.STAR)) {
373 accept (TokenType.INTERR);
374 while (accept (TokenType.OPEN_BRACKET)) {
375 do {
376 // required for decision between expression and declaration statement
377 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
378 parse_expression ();
380 } while (accept (TokenType.COMMA));
381 expect (TokenType.CLOSE_BRACKET);
382 accept (TokenType.INTERR);
384 accept (TokenType.OP_NEG);
385 accept (TokenType.HASH);
388 DataType parse_type (bool owned_by_default = true) throws ParseError {
389 var begin = get_location ();
391 if (accept (TokenType.VOID)) {
392 DataType type = new VoidType (get_src (begin));
393 while (accept (TokenType.STAR)) {
394 type = new PointerType (type);
396 return type;
399 bool is_dynamic = accept (TokenType.DYNAMIC);
401 bool value_owned = owned_by_default;
403 if (owned_by_default) {
404 if (accept (TokenType.UNOWNED)
405 || accept (TokenType.WEAK)) {
406 value_owned = false;
408 } else {
409 value_owned = accept (TokenType.OWNED);
412 var sym = parse_symbol_name ();
413 Gee.List<DataType> type_arg_list = parse_type_argument_list (false);
415 DataType type = new UnresolvedType.from_symbol (sym, get_src (begin));
416 if (type_arg_list != null) {
417 foreach (DataType type_arg in type_arg_list) {
418 type.add_type_argument (type_arg);
422 while (accept (TokenType.STAR)) {
423 type = new PointerType (type, get_src (begin));
426 if (!(type is PointerType)) {
427 type.nullable = accept (TokenType.INTERR);
430 // array brackets in types are read from right to left,
431 // this is more logical, especially when nullable arrays
432 // or pointers are involved
433 while (accept (TokenType.OPEN_BRACKET)) {
434 bool invalid_array = false;
435 int array_rank = 0;
436 do {
437 array_rank++;
438 // required for decision between expression and declaration statement
439 if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
440 parse_expression ();
441 // only used for parsing, reject use as real type
442 invalid_array = true;
444 } while (accept (TokenType.COMMA));
445 expect (TokenType.CLOSE_BRACKET);
447 // arrays contain strong references by default
448 type.value_owned = true;
450 var array_type = new ArrayType (type, array_rank, get_src (begin));
451 array_type.nullable = accept (TokenType.INTERR);
452 array_type.invalid_syntax = invalid_array;
454 type = array_type;
457 if (accept (TokenType.OP_NEG)) {
458 Report.warning (get_last_src (), "obsolete syntax, types are non-null by default");
461 if (!owned_by_default) {
462 if (accept (TokenType.HASH)) {
463 if (!context.deprecated) {
464 Report.warning (get_last_src (), "deprecated syntax, use `owned` modifier");
466 value_owned = true;
470 type.is_dynamic = is_dynamic;
471 type.value_owned = value_owned;
472 return type;
475 DataType? parse_inline_array_type (DataType? type) throws ParseError {
476 var begin = get_location ();
478 // inline-allocated array
479 if (type != null && accept (TokenType.OPEN_BRACKET)) {
480 int array_length = -1;
482 if (current () != TokenType.CLOSE_BRACKET) {
483 if (current () != TokenType.INTEGER_LITERAL) {
484 throw new ParseError.SYNTAX (get_error ("expected `]' or integer literal"));
487 var length_literal = (IntegerLiteral) parse_literal ();
488 array_length = length_literal.value.to_int ();
490 expect (TokenType.CLOSE_BRACKET);
492 var array_type = new ArrayType (type, 1, get_src (begin));
493 array_type.inline_allocated = true;
494 if (array_length > 0) {
495 array_type.fixed_length = true;
496 array_type.length = array_length;
499 return array_type;
501 return type;
504 Gee.List<Expression> parse_argument_list () throws ParseError {
505 var list = new ArrayList<Expression> ();
506 if (current () != TokenType.CLOSE_PARENS) {
507 do {
508 list.add (parse_argument ());
509 } while (accept (TokenType.COMMA));
511 return list;
514 Expression parse_argument () throws ParseError {
515 var begin = get_location ();
517 if (accept (TokenType.REF)) {
518 var inner = parse_expression ();
519 return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
520 } else if (accept (TokenType.OUT)) {
521 var inner = parse_expression ();
522 return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
523 } else {
524 return parse_expression ();
528 Expression parse_primary_expression () throws ParseError {
529 var begin = get_location ();
531 Expression expr;
533 switch (current ()) {
534 case TokenType.TRUE:
535 case TokenType.FALSE:
536 case TokenType.INTEGER_LITERAL:
537 case TokenType.REAL_LITERAL:
538 case TokenType.CHARACTER_LITERAL:
539 case TokenType.STRING_LITERAL:
540 case TokenType.TEMPLATE_STRING_LITERAL:
541 case TokenType.VERBATIM_STRING_LITERAL:
542 case TokenType.NULL:
543 expr = parse_literal ();
544 break;
545 case TokenType.OPEN_BRACE:
546 expr = parse_initializer ();
547 break;
548 case TokenType.OPEN_PARENS:
549 expr = parse_tuple ();
550 break;
551 case TokenType.OPEN_TEMPLATE:
552 expr = parse_template ();
553 break;
554 case TokenType.THIS:
555 expr = parse_this_access ();
556 break;
557 case TokenType.BASE:
558 expr = parse_base_access ();
559 break;
560 case TokenType.NEW:
561 expr = parse_object_or_array_creation_expression ();
562 break;
563 case TokenType.YIELD:
564 expr = parse_yield_expression ();
565 break;
566 case TokenType.SIZEOF:
567 expr = parse_sizeof_expression ();
568 break;
569 case TokenType.TYPEOF:
570 expr = parse_typeof_expression ();
571 break;
572 default:
573 expr = parse_simple_name ();
574 break;
577 // process primary expressions that start with an inner primary expression
578 bool found = true;
579 while (found) {
580 switch (current ()) {
581 case TokenType.DOT:
582 expr = parse_member_access (begin, expr);
583 break;
584 case TokenType.OP_PTR:
585 expr = parse_pointer_member_access (begin, expr);
586 break;
587 case TokenType.OPEN_PARENS:
588 expr = parse_method_call (begin, expr);
589 break;
590 case TokenType.OPEN_BRACKET:
591 expr = parse_element_access (begin, expr);
592 break;
593 case TokenType.OP_INC:
594 expr = parse_post_increment_expression (begin, expr);
595 break;
596 case TokenType.OP_DEC:
597 expr = parse_post_decrement_expression (begin, expr);
598 break;
599 default:
600 found = false;
601 break;
605 return expr;
608 Expression parse_simple_name () throws ParseError {
609 var begin = get_location ();
610 string id = parse_identifier ();
611 bool qualified = false;
612 if (id == "global" && accept (TokenType.DOUBLE_COLON)) {
613 id = parse_identifier ();
614 qualified = true;
616 Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
617 var expr = new MemberAccess (null, id, get_src (begin));
618 expr.qualified = qualified;
619 if (type_arg_list != null) {
620 foreach (DataType type_arg in type_arg_list) {
621 expr.add_type_argument (type_arg);
624 return expr;
627 Expression parse_tuple () throws ParseError {
628 expect (TokenType.OPEN_PARENS);
629 var expr_list = new ArrayList<Expression> ();
630 if (current () != TokenType.CLOSE_PARENS) {
631 do {
632 expr_list.add (parse_expression ());
633 } while (accept (TokenType.COMMA));
635 expect (TokenType.CLOSE_PARENS);
636 if (expr_list.size != 1) {
637 var tuple = new Tuple ();
638 foreach (Expression expr in expr_list) {
639 tuple.add_expression (expr);
641 return tuple;
643 return expr_list.get (0);
646 Expression parse_template () throws ParseError {
647 var begin = get_location ();
648 var template = new Template ();
650 expect (TokenType.OPEN_TEMPLATE);
651 while (current () != TokenType.CLOSE_TEMPLATE) {
652 template.add_expression (parse_expression ());
653 expect (TokenType.COMMA);
655 expect (TokenType.CLOSE_TEMPLATE);
657 template.source_reference = get_src (begin);
658 return template;
661 Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
662 expect (TokenType.DOT);
663 string id = parse_identifier ();
664 Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
665 var expr = new MemberAccess (inner, id, get_src (begin));
666 if (type_arg_list != null) {
667 foreach (DataType type_arg in type_arg_list) {
668 expr.add_type_argument (type_arg);
671 return expr;
674 Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
675 expect (TokenType.OP_PTR);
676 string id = parse_identifier ();
677 Gee.List<DataType> type_arg_list = parse_type_argument_list (true);
678 var expr = new MemberAccess.pointer (inner, id, get_src (begin));
679 if (type_arg_list != null) {
680 foreach (DataType type_arg in type_arg_list) {
681 expr.add_type_argument (type_arg);
684 return expr;
687 Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
688 expect (TokenType.OPEN_PARENS);
689 var arg_list = parse_argument_list ();
690 expect (TokenType.CLOSE_PARENS);
691 var init_list = parse_object_initializer ();
693 if (init_list.size > 0 && inner is MemberAccess) {
694 // struct creation expression
695 var member = (MemberAccess) inner;
696 member.creation_member = true;
698 var expr = new ObjectCreationExpression (member, get_src (begin));
699 expr.struct_creation = true;
700 foreach (Expression arg in arg_list) {
701 expr.add_argument (arg);
703 foreach (MemberInitializer initializer in init_list) {
704 expr.add_member_initializer (initializer);
706 return expr;
707 } else {
708 var expr = new MethodCall (inner, get_src (begin));
709 foreach (Expression arg in arg_list) {
710 expr.add_argument (arg);
712 return expr;
716 Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
717 expect (TokenType.OPEN_BRACKET);
718 var index_list = parse_expression_list ();
719 expect (TokenType.CLOSE_BRACKET);
721 var expr = new ElementAccess (inner, get_src (begin));
722 foreach (Expression index in index_list) {
723 expr.append_index (index);
725 return expr;
728 Gee.List<Expression> parse_expression_list () throws ParseError {
729 var list = new ArrayList<Expression> ();
730 do {
731 list.add (parse_expression ());
732 } while (accept (TokenType.COMMA));
733 return list;
736 Expression parse_this_access () throws ParseError {
737 var begin = get_location ();
738 expect (TokenType.THIS);
739 return new MemberAccess (null, "this", get_src (begin));
742 Expression parse_base_access () throws ParseError {
743 var begin = get_location ();
744 expect (TokenType.BASE);
745 return new BaseAccess (get_src (begin));
748 Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
749 expect (TokenType.OP_INC);
750 return new PostfixExpression (inner, true, get_src (begin));
753 Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
754 expect (TokenType.OP_DEC);
755 return new PostfixExpression (inner, false, get_src (begin));
758 Expression parse_object_or_array_creation_expression () throws ParseError {
759 var begin = get_location ();
760 expect (TokenType.NEW);
761 var member = parse_member_name ();
762 if (accept (TokenType.OPEN_PARENS)) {
763 var expr = parse_object_creation_expression (begin, member);
764 return expr;
765 } else if (accept (TokenType.OPEN_BRACKET)) {
766 var expr = parse_array_creation_expression (begin, member);
767 return expr;
768 } else {
769 throw new ParseError.SYNTAX (get_error ("expected ( or ["));
773 Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
774 member.creation_member = true;
775 var arg_list = parse_argument_list ();
776 expect (TokenType.CLOSE_PARENS);
777 var init_list = parse_object_initializer ();
779 var expr = new ObjectCreationExpression (member, get_src (begin));
780 foreach (Expression arg in arg_list) {
781 expr.add_argument (arg);
783 foreach (MemberInitializer initializer in init_list) {
784 expr.add_member_initializer (initializer);
786 return expr;
789 Expression parse_array_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
790 bool size_specified = false;
791 Gee.List<Expression> size_specifier_list = null;
792 bool first = true;
793 DataType element_type = UnresolvedType.new_from_expression (member);
794 do {
795 if (!first) {
796 // array of arrays: new T[][42]
797 element_type = new ArrayType (element_type, size_specifier_list.size, element_type.source_reference);
798 } else {
799 first = false;
802 size_specifier_list = new ArrayList<Expression> ();
803 do {
804 Expression size = null;
805 if (current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
806 size = parse_expression ();
807 size_specified = true;
809 size_specifier_list.add (size);
810 } while (accept (TokenType.COMMA));
811 expect (TokenType.CLOSE_BRACKET);
812 } while (accept (TokenType.OPEN_BRACKET));
814 InitializerList initializer = null;
815 if (current () == TokenType.OPEN_BRACE) {
816 initializer = parse_initializer ();
818 var expr = new ArrayCreationExpression (element_type, size_specifier_list.size, initializer, get_src (begin));
819 if (size_specified) {
820 foreach (Expression size in size_specifier_list) {
821 expr.append_size (size);
824 return expr;
827 Gee.List<MemberInitializer> parse_object_initializer () throws ParseError {
828 var list = new ArrayList<MemberInitializer> ();
829 if (accept (TokenType.OPEN_BRACE)) {
830 do {
831 list.add (parse_member_initializer ());
832 } while (accept (TokenType.COMMA));
833 expect (TokenType.CLOSE_BRACE);
835 return list;
838 MemberInitializer parse_member_initializer () throws ParseError {
839 var begin = get_location ();
840 string id = parse_identifier ();
841 expect (TokenType.ASSIGN);
842 var expr = parse_expression ();
844 return new MemberInitializer (id, expr, get_src (begin));
847 Expression parse_yield_expression () throws ParseError {
848 var begin = get_location ();
849 expect (TokenType.YIELD);
850 var member = parse_member_name ();
851 var call = (MethodCall) parse_method_call (begin, member);
852 call.is_yield_expression = true;
853 return call;
856 Expression parse_sizeof_expression () throws ParseError {
857 var begin = get_location ();
858 expect (TokenType.SIZEOF);
859 expect (TokenType.OPEN_PARENS);
860 var type = parse_type ();
861 expect (TokenType.CLOSE_PARENS);
863 return new SizeofExpression (type, get_src (begin));
866 Expression parse_typeof_expression () throws ParseError {
867 var begin = get_location ();
868 expect (TokenType.TYPEOF);
869 expect (TokenType.OPEN_PARENS);
870 var type = parse_type ();
871 expect (TokenType.CLOSE_PARENS);
873 return new TypeofExpression (type, get_src (begin));
876 UnaryOperator get_unary_operator (TokenType token_type) {
877 switch (token_type) {
878 case TokenType.PLUS: return UnaryOperator.PLUS;
879 case TokenType.MINUS: return UnaryOperator.MINUS;
880 case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
881 case TokenType.TILDE: return UnaryOperator.BITWISE_COMPLEMENT;
882 case TokenType.OP_INC: return UnaryOperator.INCREMENT;
883 case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
884 default: return UnaryOperator.NONE;
888 Expression parse_unary_expression () throws ParseError {
889 var begin = get_location ();
890 var operator = get_unary_operator (current ());
891 if (operator != UnaryOperator.NONE) {
892 next ();
893 var op = parse_unary_expression ();
894 return new UnaryExpression (operator, op, get_src (begin));
896 switch (current ()) {
897 case TokenType.HASH:
898 if (!context.deprecated) {
899 Report.warning (get_last_src (), "deprecated syntax, use `(owned)` cast");
901 next ();
902 var op = parse_unary_expression ();
903 return new ReferenceTransferExpression (op, get_src (begin));
904 case TokenType.OPEN_PARENS:
905 next ();
906 switch (current ()) {
907 case TokenType.OWNED:
908 // (owned) foo
909 next ();
910 if (accept (TokenType.CLOSE_PARENS)) {
911 var op = parse_unary_expression ();
912 return new ReferenceTransferExpression (op, get_src (begin));
914 break;
915 case TokenType.VOID:
916 case TokenType.DYNAMIC:
917 case TokenType.IDENTIFIER:
918 var type = parse_type ();
919 if (accept (TokenType.CLOSE_PARENS)) {
920 // check follower to decide whether to create cast expression
921 switch (current ()) {
922 case TokenType.OP_NEG:
923 case TokenType.TILDE:
924 case TokenType.OPEN_PARENS:
925 case TokenType.TRUE:
926 case TokenType.FALSE:
927 case TokenType.INTEGER_LITERAL:
928 case TokenType.REAL_LITERAL:
929 case TokenType.CHARACTER_LITERAL:
930 case TokenType.STRING_LITERAL:
931 case TokenType.TEMPLATE_STRING_LITERAL:
932 case TokenType.VERBATIM_STRING_LITERAL:
933 case TokenType.NULL:
934 case TokenType.THIS:
935 case TokenType.BASE:
936 case TokenType.NEW:
937 case TokenType.SIZEOF:
938 case TokenType.TYPEOF:
939 case TokenType.IDENTIFIER:
940 case TokenType.PARAMS:
941 var inner = parse_unary_expression ();
942 return new CastExpression (inner, type, get_src (begin), false);
943 default:
944 break;
947 break;
948 default:
949 break;
951 // no cast expression
952 rollback (begin);
953 break;
954 case TokenType.STAR:
955 next ();
956 var op = parse_unary_expression ();
957 return new PointerIndirection (op, get_src (begin));
958 case TokenType.BITWISE_AND:
959 next ();
960 var op = parse_unary_expression ();
961 return new AddressofExpression (op, get_src (begin));
962 default:
963 break;
966 var expr = parse_primary_expression ();
967 return expr;
970 BinaryOperator get_binary_operator (TokenType token_type) {
971 switch (token_type) {
972 case TokenType.STAR: return BinaryOperator.MUL;
973 case TokenType.DIV: return BinaryOperator.DIV;
974 case TokenType.PERCENT: return BinaryOperator.MOD;
975 case TokenType.PLUS: return BinaryOperator.PLUS;
976 case TokenType.MINUS: return BinaryOperator.MINUS;
977 case TokenType.OP_LT: return BinaryOperator.LESS_THAN;
978 case TokenType.OP_GT: return BinaryOperator.GREATER_THAN;
979 case TokenType.OP_LE: return BinaryOperator.LESS_THAN_OR_EQUAL;
980 case TokenType.OP_GE: return BinaryOperator.GREATER_THAN_OR_EQUAL;
981 case TokenType.OP_EQ: return BinaryOperator.EQUALITY;
982 case TokenType.OP_NE: return BinaryOperator.INEQUALITY;
983 default: return BinaryOperator.NONE;
987 Expression parse_multiplicative_expression () throws ParseError {
988 var begin = get_location ();
989 var left = parse_unary_expression ();
990 bool found = true;
991 while (found) {
992 var operator = get_binary_operator (current ());
993 switch (operator) {
994 case BinaryOperator.MUL:
995 case BinaryOperator.DIV:
996 case BinaryOperator.MOD:
997 next ();
998 var right = parse_unary_expression ();
999 left = new BinaryExpression (operator, left, right, get_src (begin));
1000 break;
1001 default:
1002 found = false;
1003 break;
1006 return left;
1009 Expression parse_additive_expression () throws ParseError {
1010 var begin = get_location ();
1011 var left = parse_multiplicative_expression ();
1012 bool found = true;
1013 while (found) {
1014 var operator = get_binary_operator (current ());
1015 switch (operator) {
1016 case BinaryOperator.PLUS:
1017 case BinaryOperator.MINUS:
1018 next ();
1019 var right = parse_multiplicative_expression ();
1020 left = new BinaryExpression (operator, left, right, get_src (begin));
1021 break;
1022 default:
1023 found = false;
1024 break;
1027 return left;
1030 Expression parse_shift_expression () throws ParseError {
1031 var begin = get_location ();
1032 var left = parse_additive_expression ();
1033 bool found = true;
1034 while (found) {
1035 switch (current ()) {
1036 case TokenType.OP_SHIFT_LEFT:
1037 next ();
1038 var right = parse_additive_expression ();
1039 left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1040 break;
1041 // don't use OP_SHIFT_RIGHT to support >> for nested generics
1042 case TokenType.OP_GT:
1043 char* first_gt_pos = tokens[index].begin.pos;
1044 next ();
1045 // only accept >> when there is no space between the two > signs
1046 if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1047 next ();
1048 var right = parse_additive_expression ();
1049 left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1050 } else {
1051 prev ();
1052 found = false;
1054 break;
1055 default:
1056 found = false;
1057 break;
1060 return left;
1063 Expression parse_relational_expression () throws ParseError {
1064 var begin = get_location ();
1065 var left = parse_shift_expression ();
1066 bool found = true;
1067 while (found) {
1068 var operator = get_binary_operator (current ());
1069 switch (operator) {
1070 case BinaryOperator.LESS_THAN:
1071 case BinaryOperator.LESS_THAN_OR_EQUAL:
1072 case BinaryOperator.GREATER_THAN_OR_EQUAL:
1073 next ();
1074 var right = parse_shift_expression ();
1075 left = new BinaryExpression (operator, left, right, get_src (begin));
1076 break;
1077 case BinaryOperator.GREATER_THAN:
1078 next ();
1079 // ignore >> and >>= (two tokens due to generics)
1080 if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1081 var right = parse_shift_expression ();
1082 left = new BinaryExpression (operator, left, right, get_src (begin));
1083 } else {
1084 prev ();
1085 found = false;
1087 break;
1088 default:
1089 switch (current ()) {
1090 case TokenType.IS:
1091 next ();
1092 var type = parse_type ();
1093 left = new TypeCheck (left, type, get_src (begin));
1094 break;
1095 case TokenType.AS:
1096 next ();
1097 var type = parse_type ();
1098 left = new CastExpression (left, type, get_src (begin), true);
1099 break;
1100 default:
1101 found = false;
1102 break;
1104 break;
1107 return left;
1110 Expression parse_equality_expression () throws ParseError {
1111 var begin = get_location ();
1112 var left = parse_relational_expression ();
1113 bool found = true;
1114 while (found) {
1115 var operator = get_binary_operator (current ());
1116 switch (operator) {
1117 case BinaryOperator.EQUALITY:
1118 case BinaryOperator.INEQUALITY:
1119 next ();
1120 var right = parse_relational_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_and_expression () throws ParseError {
1132 var begin = get_location ();
1133 var left = parse_equality_expression ();
1134 while (accept (TokenType.BITWISE_AND)) {
1135 var right = parse_equality_expression ();
1136 left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1138 return left;
1141 Expression parse_exclusive_or_expression () throws ParseError {
1142 var begin = get_location ();
1143 var left = parse_and_expression ();
1144 while (accept (TokenType.CARRET)) {
1145 var right = parse_and_expression ();
1146 left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1148 return left;
1151 Expression parse_inclusive_or_expression () throws ParseError {
1152 var begin = get_location ();
1153 var left = parse_exclusive_or_expression ();
1154 while (accept (TokenType.BITWISE_OR)) {
1155 var right = parse_exclusive_or_expression ();
1156 left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1158 return left;
1161 Expression parse_in_expression () throws ParseError {
1162 var begin = get_location ();
1163 var left = parse_inclusive_or_expression ();
1164 while (accept (TokenType.IN)) {
1165 var right = parse_inclusive_or_expression ();
1166 left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1168 return left;
1171 Expression parse_conditional_and_expression () throws ParseError {
1172 var begin = get_location ();
1173 var left = parse_in_expression ();
1174 while (accept (TokenType.OP_AND)) {
1175 var right = parse_in_expression ();
1176 left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1178 return left;
1181 Expression parse_conditional_or_expression () throws ParseError {
1182 var begin = get_location ();
1183 var left = parse_conditional_and_expression ();
1184 while (accept (TokenType.OP_OR)) {
1185 var right = parse_conditional_and_expression ();
1186 left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1188 return left;
1191 Expression parse_conditional_expression () throws ParseError {
1192 var begin = get_location ();
1193 var condition = parse_conditional_or_expression ();
1194 if (accept (TokenType.INTERR)) {
1195 var true_expr = parse_expression ();
1196 expect (TokenType.COLON);
1197 var false_expr = parse_expression ();
1198 return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1199 } else {
1200 return condition;
1204 Expression parse_lambda_expression () throws ParseError {
1205 var begin = get_location ();
1206 Gee.List<string> params = new ArrayList<string> ();
1207 if (accept (TokenType.OPEN_PARENS)) {
1208 if (current () != TokenType.CLOSE_PARENS) {
1209 do {
1210 params.add (parse_identifier ());
1211 } while (accept (TokenType.COMMA));
1213 expect (TokenType.CLOSE_PARENS);
1214 } else {
1215 params.add (parse_identifier ());
1217 expect (TokenType.LAMBDA);
1219 LambdaExpression lambda;
1220 if (current () == TokenType.OPEN_BRACE) {
1221 var block = parse_block ();
1222 lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1223 } else {
1224 var expr = parse_expression ();
1225 lambda = new LambdaExpression (expr, get_src (begin));
1227 foreach (string param in params) {
1228 lambda.add_parameter (param);
1230 return lambda;
1233 AssignmentOperator get_assignment_operator (TokenType token_type) {
1234 switch (token_type) {
1235 case TokenType.ASSIGN: return AssignmentOperator.SIMPLE;
1236 case TokenType.ASSIGN_ADD: return AssignmentOperator.ADD;
1237 case TokenType.ASSIGN_SUB: return AssignmentOperator.SUB;
1238 case TokenType.ASSIGN_BITWISE_OR: return AssignmentOperator.BITWISE_OR;
1239 case TokenType.ASSIGN_BITWISE_AND: return AssignmentOperator.BITWISE_AND;
1240 case TokenType.ASSIGN_BITWISE_XOR: return AssignmentOperator.BITWISE_XOR;
1241 case TokenType.ASSIGN_DIV: return AssignmentOperator.DIV;
1242 case TokenType.ASSIGN_MUL: return AssignmentOperator.MUL;
1243 case TokenType.ASSIGN_PERCENT: return AssignmentOperator.PERCENT;
1244 case TokenType.ASSIGN_SHIFT_LEFT: return AssignmentOperator.SHIFT_LEFT;
1245 default: return AssignmentOperator.NONE;
1249 Expression parse_expression () throws ParseError {
1250 var begin = get_location ();
1251 Expression expr = parse_conditional_expression ();
1253 if (current () == TokenType.LAMBDA) {
1254 rollback (begin);
1255 var lambda = parse_lambda_expression ();
1256 return lambda;
1259 while (true) {
1260 var operator = get_assignment_operator (current ());
1261 if (operator != AssignmentOperator.NONE) {
1262 next ();
1263 var rhs = parse_expression ();
1264 expr = new Assignment (expr, rhs, operator, get_src (begin));
1265 } else if (current () == TokenType.OP_GT) { // >>=
1266 char* first_gt_pos = tokens[index].begin.pos;
1267 next ();
1268 // only accept >>= when there is no space between the two > signs
1269 if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1270 next ();
1271 var rhs = parse_expression ();
1272 expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1273 } else {
1274 prev ();
1275 break;
1277 } else {
1278 break;
1282 return expr;
1285 void parse_statements (Block block) throws ParseError {
1286 while (current () != TokenType.CLOSE_BRACE
1287 && current () != TokenType.CASE
1288 && current () != TokenType.DEFAULT) {
1289 try {
1290 Statement stmt = null;
1291 bool is_decl = false;
1293 comment = scanner.pop_comment ();
1294 switch (current ()) {
1295 case TokenType.OPEN_BRACE:
1296 stmt = parse_block ();
1297 break;
1298 case TokenType.SEMICOLON:
1299 stmt = parse_empty_statement ();
1300 break;
1301 case TokenType.IF:
1302 stmt = parse_if_statement ();
1303 break;
1304 case TokenType.SWITCH:
1305 stmt = parse_switch_statement ();
1306 break;
1307 case TokenType.WHILE:
1308 stmt = parse_while_statement ();
1309 break;
1310 case TokenType.DO:
1311 stmt = parse_do_statement ();
1312 break;
1313 case TokenType.FOR:
1314 stmt = parse_for_statement ();
1315 break;
1316 case TokenType.FOREACH:
1317 stmt = parse_foreach_statement ();
1318 break;
1319 case TokenType.BREAK:
1320 stmt = parse_break_statement ();
1321 break;
1322 case TokenType.CONTINUE:
1323 stmt = parse_continue_statement ();
1324 break;
1325 case TokenType.RETURN:
1326 stmt = parse_return_statement ();
1327 break;
1328 case TokenType.YIELD:
1329 stmt = parse_yield_statement ();
1330 break;
1331 case TokenType.THROW:
1332 stmt = parse_throw_statement ();
1333 break;
1334 case TokenType.TRY:
1335 stmt = parse_try_statement ();
1336 break;
1337 case TokenType.LOCK:
1338 stmt = parse_lock_statement ();
1339 break;
1340 case TokenType.DELETE:
1341 stmt = parse_delete_statement ();
1342 break;
1343 case TokenType.VAR:
1344 is_decl = true;
1345 parse_local_variable_declarations (block);
1346 break;
1347 case TokenType.OP_INC:
1348 case TokenType.OP_DEC:
1349 case TokenType.BASE:
1350 case TokenType.THIS:
1351 case TokenType.OPEN_PARENS:
1352 case TokenType.STAR:
1353 case TokenType.NEW:
1354 stmt = parse_expression_statement ();
1355 break;
1356 default:
1357 bool is_expr = is_expression ();
1358 if (is_expr) {
1359 stmt = parse_expression_statement ();
1360 } else {
1361 is_decl = true;
1362 parse_local_variable_declarations (block);
1364 break;
1367 if (!is_decl) {
1368 block.add_statement (stmt);
1370 } catch (ParseError e) {
1371 if (recover () != RecoveryState.STATEMENT_BEGIN) {
1372 // beginning of next declaration or end of file reached
1373 // return what we have so far
1374 break;
1380 bool is_expression () throws ParseError {
1381 var begin = get_location ();
1383 // decide between declaration and expression statement
1384 skip_type ();
1385 switch (current ()) {
1386 // invocation expression
1387 case TokenType.OPEN_PARENS:
1388 // postfix increment
1389 case TokenType.OP_INC:
1390 // postfix decrement
1391 case TokenType.OP_DEC:
1392 // assignments
1393 case TokenType.ASSIGN:
1394 case TokenType.ASSIGN_ADD:
1395 case TokenType.ASSIGN_BITWISE_AND:
1396 case TokenType.ASSIGN_BITWISE_OR:
1397 case TokenType.ASSIGN_BITWISE_XOR:
1398 case TokenType.ASSIGN_DIV:
1399 case TokenType.ASSIGN_MUL:
1400 case TokenType.ASSIGN_PERCENT:
1401 case TokenType.ASSIGN_SHIFT_LEFT:
1402 case TokenType.ASSIGN_SUB:
1403 case TokenType.OP_GT: // >>=
1404 // member access
1405 case TokenType.DOT:
1406 // pointer member access
1407 case TokenType.OP_PTR:
1408 rollback (begin);
1409 return true;
1410 default:
1411 rollback (begin);
1412 return false;
1416 Block parse_embedded_statement () throws ParseError {
1417 if (current () == TokenType.OPEN_BRACE) {
1418 var block = parse_block ();
1419 return block;
1422 comment = scanner.pop_comment ();
1424 var block = new Block (get_src (get_location ()));
1425 block.add_statement (parse_embedded_statement_without_block ());
1426 return block;
1430 Statement parse_embedded_statement_without_block () throws ParseError {
1431 switch (current ()) {
1432 case TokenType.SEMICOLON: return parse_empty_statement ();
1433 case TokenType.IF: return parse_if_statement ();
1434 case TokenType.SWITCH: return parse_switch_statement ();
1435 case TokenType.WHILE: return parse_while_statement ();
1436 case TokenType.DO: return parse_do_statement ();
1437 case TokenType.FOR: return parse_for_statement ();
1438 case TokenType.FOREACH: return parse_foreach_statement ();
1439 case TokenType.BREAK: return parse_break_statement ();
1440 case TokenType.CONTINUE: return parse_continue_statement ();
1441 case TokenType.RETURN: return parse_return_statement ();
1442 case TokenType.YIELD: return parse_yield_statement ();
1443 case TokenType.THROW: return parse_throw_statement ();
1444 case TokenType.TRY: return parse_try_statement ();
1445 case TokenType.LOCK: return parse_lock_statement ();
1446 case TokenType.DELETE: return parse_delete_statement ();
1447 default: return parse_expression_statement ();
1451 Block parse_block () throws ParseError {
1452 var begin = get_location ();
1453 expect (TokenType.OPEN_BRACE);
1454 var block = new Block (get_src (begin));
1455 parse_statements (block);
1456 if (!accept (TokenType.CLOSE_BRACE)) {
1457 // only report error if it's not a secondary error
1458 if (context.report.get_errors () == 0) {
1459 Report.error (get_current_src (), "expected `}'");
1463 block.source_reference.last_line = get_current_src ().last_line;
1464 block.source_reference.last_column = get_current_src ().last_column;
1466 return block;
1469 Statement parse_empty_statement () throws ParseError {
1470 var begin = get_location ();
1471 expect (TokenType.SEMICOLON);
1472 return new EmptyStatement (get_src (begin));
1475 void parse_local_variable_declarations (Block block) throws ParseError {
1476 DataType variable_type;
1477 if (accept (TokenType.VAR)) {
1478 variable_type = null;
1479 } else {
1480 variable_type = parse_type ();
1482 do {
1483 DataType type_copy = null;
1484 if (variable_type != null) {
1485 type_copy = variable_type.copy ();
1487 var local = parse_local_variable (type_copy);
1488 block.add_statement (new DeclarationStatement (local, local.source_reference));
1489 } while (accept (TokenType.COMMA));
1490 expect (TokenType.SEMICOLON);
1493 LocalVariable parse_local_variable (DataType? variable_type) throws ParseError {
1494 var begin = get_location ();
1495 string id = parse_identifier ();
1497 var type = parse_inline_array_type (variable_type);
1499 Expression initializer = null;
1500 if (accept (TokenType.ASSIGN)) {
1501 initializer = parse_expression ();
1503 return new LocalVariable (type, id, initializer, get_src (begin));
1506 Statement parse_expression_statement () throws ParseError {
1507 var begin = get_location ();
1508 var expr = parse_statement_expression ();
1509 expect (TokenType.SEMICOLON);
1510 return new ExpressionStatement (expr, get_src (begin));
1513 Expression parse_statement_expression () throws ParseError {
1514 // invocation expression, assignment,
1515 // or pre/post increment/decrement expression
1516 var expr = parse_expression ();
1517 return expr;
1520 Statement parse_if_statement () throws ParseError {
1521 var begin = get_location ();
1522 expect (TokenType.IF);
1523 expect (TokenType.OPEN_PARENS);
1524 var condition = parse_expression ();
1525 expect (TokenType.CLOSE_PARENS);
1526 var src = get_src (begin);
1527 var true_stmt = parse_embedded_statement ();
1528 Block false_stmt = null;
1529 if (accept (TokenType.ELSE)) {
1530 false_stmt = parse_embedded_statement ();
1532 return new IfStatement (condition, true_stmt, false_stmt, src);
1535 Statement parse_switch_statement () throws ParseError {
1536 var begin = get_location ();
1537 expect (TokenType.SWITCH);
1538 expect (TokenType.OPEN_PARENS);
1539 var condition = parse_expression ();
1540 expect (TokenType.CLOSE_PARENS);
1541 var stmt = new SwitchStatement (condition, get_src (begin));
1542 expect (TokenType.OPEN_BRACE);
1543 while (current () != TokenType.CLOSE_BRACE) {
1544 var section = new SwitchSection (get_src (begin));
1545 do {
1546 if (accept (TokenType.CASE)) {
1547 section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
1548 } else {
1549 expect (TokenType.DEFAULT);
1550 section.add_label (new SwitchLabel.with_default (get_src (begin)));
1552 expect (TokenType.COLON);
1553 } while (current () == TokenType.CASE || current () == TokenType.DEFAULT);
1554 parse_statements (section);
1555 stmt.add_section (section);
1557 expect (TokenType.CLOSE_BRACE);
1558 return stmt;
1561 Statement parse_while_statement () throws ParseError {
1562 var begin = get_location ();
1563 expect (TokenType.WHILE);
1564 expect (TokenType.OPEN_PARENS);
1565 var condition = parse_expression ();
1566 expect (TokenType.CLOSE_PARENS);
1567 var body = parse_embedded_statement ();
1568 return new WhileStatement (condition, body, get_src (begin));
1571 Statement parse_do_statement () throws ParseError {
1572 var begin = get_location ();
1573 expect (TokenType.DO);
1574 var body = parse_embedded_statement ();
1575 expect (TokenType.WHILE);
1576 expect (TokenType.OPEN_PARENS);
1577 var condition = parse_expression ();
1578 expect (TokenType.CLOSE_PARENS);
1579 expect (TokenType.SEMICOLON);
1580 return new DoStatement (body, condition, get_src (begin));
1583 Statement parse_for_statement () throws ParseError {
1584 var begin = get_location ();
1585 Block block = null;
1586 expect (TokenType.FOR);
1587 expect (TokenType.OPEN_PARENS);
1588 var initializer_list = new ArrayList<Expression> ();
1589 if (!accept (TokenType.SEMICOLON)) {
1590 bool is_expr;
1591 switch (current ()) {
1592 case TokenType.VAR:
1593 is_expr = false;
1594 break;
1595 case TokenType.OP_INC:
1596 case TokenType.OP_DEC:
1597 is_expr = true;
1598 break;
1599 default:
1600 is_expr = is_expression ();
1601 break;
1604 if (is_expr) {
1605 do {
1606 initializer_list.add (parse_statement_expression ());
1607 } while (accept (TokenType.COMMA));
1608 } else {
1609 block = new Block (get_src (begin));
1610 DataType variable_type;
1611 if (accept (TokenType.VAR)) {
1612 variable_type = null;
1613 } else {
1614 variable_type = parse_type ();
1616 var local = parse_local_variable (variable_type);
1617 block.add_statement (new DeclarationStatement (local, local.source_reference));
1619 expect (TokenType.SEMICOLON);
1621 Expression condition = null;
1622 if (current () != TokenType.SEMICOLON) {
1623 condition = parse_expression ();
1625 expect (TokenType.SEMICOLON);
1626 var iterator_list = new ArrayList<Expression> ();
1627 if (current () != TokenType.CLOSE_PARENS) {
1628 do {
1629 iterator_list.add (parse_statement_expression ());
1630 } while (accept (TokenType.COMMA));
1632 expect (TokenType.CLOSE_PARENS);
1633 var src = get_src (begin);
1634 var body = parse_embedded_statement ();
1635 var stmt = new ForStatement (condition, body, src);
1636 foreach (Expression init in initializer_list) {
1637 stmt.add_initializer (init);
1639 foreach (Expression iter in iterator_list) {
1640 stmt.add_iterator (iter);
1642 if (block != null) {
1643 block.add_statement (stmt);
1644 return block;
1645 } else {
1646 return stmt;
1650 Statement parse_foreach_statement () throws ParseError {
1651 var begin = get_location ();
1652 expect (TokenType.FOREACH);
1653 expect (TokenType.OPEN_PARENS);
1654 DataType type = null;
1655 if (!accept (TokenType.VAR)) {
1656 type = parse_type ();
1658 string id = parse_identifier ();
1659 expect (TokenType.IN);
1660 var collection = parse_expression ();
1661 expect (TokenType.CLOSE_PARENS);
1662 var src = get_src (begin);
1663 var body = parse_embedded_statement ();
1664 return new ForeachStatement (type, id, collection, body, src);
1667 Statement parse_break_statement () throws ParseError {
1668 var begin = get_location ();
1669 expect (TokenType.BREAK);
1670 expect (TokenType.SEMICOLON);
1671 return new BreakStatement (get_src (begin));
1674 Statement parse_continue_statement () throws ParseError {
1675 var begin = get_location ();
1676 expect (TokenType.CONTINUE);
1677 expect (TokenType.SEMICOLON);
1678 return new ContinueStatement (get_src (begin));
1681 Statement parse_return_statement () throws ParseError {
1682 var begin = get_location ();
1683 expect (TokenType.RETURN);
1684 Expression expr = null;
1685 if (current () != TokenType.SEMICOLON) {
1686 expr = parse_expression ();
1688 expect (TokenType.SEMICOLON);
1689 return new ReturnStatement (expr, get_src (begin));
1692 Statement parse_yield_statement () throws ParseError {
1693 var begin = get_location ();
1694 expect (TokenType.YIELD);
1695 if (current () != TokenType.SEMICOLON && current () != TokenType.RETURN) {
1696 // yield expression
1697 prev ();
1698 return parse_expression_statement ();
1700 Expression expr = null;
1701 if (accept (TokenType.RETURN)) {
1702 expr = parse_expression ();
1704 expect (TokenType.SEMICOLON);
1705 return new YieldStatement (expr, get_src (begin));
1708 Statement parse_throw_statement () throws ParseError {
1709 var begin = get_location ();
1710 expect (TokenType.THROW);
1711 var expr = parse_expression ();
1712 expect (TokenType.SEMICOLON);
1713 return new ThrowStatement (expr, get_src (begin));
1716 Statement parse_try_statement () throws ParseError {
1717 var begin = get_location ();
1718 expect (TokenType.TRY);
1719 var try_block = parse_block ();
1720 Block finally_clause = null;
1721 var catch_clauses = new ArrayList<CatchClause> ();
1722 if (current () == TokenType.CATCH) {
1723 parse_catch_clauses (catch_clauses);
1724 if (current () == TokenType.FINALLY) {
1725 finally_clause = parse_finally_clause ();
1727 } else {
1728 finally_clause = parse_finally_clause ();
1730 var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
1731 foreach (CatchClause clause in catch_clauses) {
1732 stmt.add_catch_clause (clause);
1734 return stmt;
1737 void parse_catch_clauses (Gee.List<CatchClause> catch_clauses) throws ParseError {
1738 while (accept (TokenType.CATCH)) {
1739 var begin = get_location ();
1740 DataType type = null;
1741 string id = null;
1742 if (accept (TokenType.OPEN_PARENS)) {
1743 type = parse_type ();
1744 id = parse_identifier ();
1745 expect (TokenType.CLOSE_PARENS);
1747 var block = parse_block ();
1748 catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
1752 Block parse_finally_clause () throws ParseError {
1753 expect (TokenType.FINALLY);
1754 var block = parse_block ();
1755 return block;
1758 Statement parse_lock_statement () throws ParseError {
1759 var begin = get_location ();
1760 expect (TokenType.LOCK);
1761 expect (TokenType.OPEN_PARENS);
1762 var expr = parse_expression ();
1763 expect (TokenType.CLOSE_PARENS);
1764 var stmt = parse_embedded_statement ();
1765 return new LockStatement (expr, stmt, get_src (begin));
1768 Statement parse_delete_statement () throws ParseError {
1769 var begin = get_location ();
1770 expect (TokenType.DELETE);
1771 var expr = parse_expression ();
1772 expect (TokenType.SEMICOLON);
1773 return new DeleteStatement (expr, get_src (begin));
1776 Gee.List<Attribute>? parse_attributes () throws ParseError {
1777 if (current () != TokenType.OPEN_BRACKET) {
1778 return null;
1780 var attrs = new ArrayList<Attribute> ();
1781 while (accept (TokenType.OPEN_BRACKET)) {
1782 do {
1783 var begin = get_location ();
1784 string id = parse_identifier ();
1785 var attr = new Attribute (id, get_src (begin));
1786 if (accept (TokenType.OPEN_PARENS)) {
1787 if (current () != TokenType.CLOSE_PARENS) {
1788 do {
1789 id = parse_identifier ();
1790 expect (TokenType.ASSIGN);
1791 var expr = parse_expression ();
1792 attr.add_argument (id, expr);
1793 } while (accept (TokenType.COMMA));
1795 expect (TokenType.CLOSE_PARENS);
1797 attrs.add (attr);
1798 } while (accept (TokenType.COMMA));
1799 expect (TokenType.CLOSE_BRACKET);
1801 return attrs;
1804 void set_attributes (CodeNode node, Gee.List<Attribute>? attributes) {
1805 if (attributes != null) {
1806 foreach (Attribute attr in (Gee.List<Attribute>) attributes) {
1807 node.attributes.append (attr);
1812 Symbol parse_declaration () throws ParseError {
1813 comment = scanner.pop_comment ();
1814 var attrs = parse_attributes ();
1816 var begin = get_location ();
1818 TokenType last_keyword = current ();
1820 while (is_declaration_keyword (current ())) {
1821 last_keyword = current ();
1822 next ();
1825 switch (current ()) {
1826 case TokenType.CONSTRUCT:
1827 if (context.profile == Profile.GOBJECT) {
1828 rollback (begin);
1829 return parse_constructor_declaration (attrs);
1831 break;
1832 case TokenType.TILDE:
1833 rollback (begin);
1834 return parse_destructor_declaration (attrs);
1835 default:
1836 skip_type ();
1837 switch (current ()) {
1838 case TokenType.OPEN_BRACE:
1839 case TokenType.SEMICOLON:
1840 case TokenType.COLON:
1841 rollback (begin);
1842 switch (last_keyword) {
1843 case TokenType.CLASS: return parse_class_declaration (attrs);
1844 case TokenType.ENUM: return parse_enum_declaration (attrs);
1845 case TokenType.ERRORDOMAIN: return parse_errordomain_declaration (attrs);
1846 case TokenType.INTERFACE: return parse_interface_declaration (attrs);
1847 case TokenType.NAMESPACE: return parse_namespace_declaration (attrs);
1848 case TokenType.STRUCT: return parse_struct_declaration (attrs);
1849 default: break;
1851 break;
1852 case TokenType.OPEN_PARENS:
1853 rollback (begin);
1854 return parse_creation_method_declaration (attrs);
1855 default:
1856 skip_type (); // might contain type parameter list
1857 switch (current ()) {
1858 case TokenType.OPEN_PARENS:
1859 rollback (begin);
1860 switch (last_keyword) {
1861 case TokenType.DELEGATE: return parse_delegate_declaration (attrs);
1862 case TokenType.SIGNAL: return parse_signal_declaration (attrs);
1863 default: return parse_method_declaration (attrs);
1865 case TokenType.ASSIGN:
1866 case TokenType.SEMICOLON:
1867 rollback (begin);
1868 switch (last_keyword) {
1869 case TokenType.CONST: return parse_constant_declaration (attrs);
1870 default: return parse_field_declaration (attrs);
1872 case TokenType.OPEN_BRACE:
1873 case TokenType.THROWS:
1874 rollback (begin);
1875 return parse_property_declaration (attrs);
1876 default:
1877 break;
1879 break;
1881 break;
1884 rollback (begin);
1886 throw new ParseError.SYNTAX (get_error ("expected declaration"));
1889 void parse_declarations (Symbol parent, bool root = false) throws ParseError {
1890 if (!root) {
1891 expect (TokenType.OPEN_BRACE);
1893 while (current () != TokenType.CLOSE_BRACE && current () != TokenType.EOF) {
1894 try {
1895 if (parent is Namespace) {
1896 parse_namespace_member ((Namespace) parent);
1897 } else if (parent is Class) {
1898 parse_class_member ((Class) parent);
1899 } else if (parent is Struct) {
1900 parse_struct_member ((Struct) parent);
1901 } else if (parent is Interface) {
1902 parse_interface_member ((Interface) parent);
1904 } catch (ParseError e) {
1905 int r;
1906 do {
1907 r = recover ();
1908 if (r == RecoveryState.STATEMENT_BEGIN) {
1909 next ();
1910 } else {
1911 break;
1913 } while (true);
1914 if (r == RecoveryState.EOF) {
1915 return;
1919 if (!root) {
1920 if (!accept (TokenType.CLOSE_BRACE)) {
1921 // only report error if it's not a secondary error
1922 if (context.report.get_errors () == 0) {
1923 Report.error (get_current_src (), "expected `}'");
1929 enum RecoveryState {
1930 EOF,
1931 DECLARATION_BEGIN,
1932 STATEMENT_BEGIN
1935 RecoveryState recover () {
1936 while (current () != TokenType.EOF) {
1937 switch (current ()) {
1938 case TokenType.ABSTRACT:
1939 case TokenType.CLASS:
1940 case TokenType.CONST:
1941 case TokenType.CONSTRUCT:
1942 case TokenType.DELEGATE:
1943 case TokenType.ENUM:
1944 case TokenType.ERRORDOMAIN:
1945 case TokenType.EXTERN:
1946 case TokenType.INLINE:
1947 case TokenType.INTERFACE:
1948 case TokenType.INTERNAL:
1949 case TokenType.NAMESPACE:
1950 case TokenType.NEW:
1951 case TokenType.OVERRIDE:
1952 case TokenType.PRIVATE:
1953 case TokenType.PROTECTED:
1954 case TokenType.PUBLIC:
1955 case TokenType.SIGNAL:
1956 case TokenType.STATIC:
1957 case TokenType.STRUCT:
1958 case TokenType.VIRTUAL:
1959 case TokenType.VOLATILE:
1960 return RecoveryState.DECLARATION_BEGIN;
1961 case TokenType.BREAK:
1962 case TokenType.CONTINUE:
1963 case TokenType.DELETE:
1964 case TokenType.DO:
1965 case TokenType.FOR:
1966 case TokenType.FOREACH:
1967 case TokenType.IF:
1968 case TokenType.LOCK:
1969 case TokenType.RETURN:
1970 case TokenType.SWITCH:
1971 case TokenType.THROW:
1972 case TokenType.TRY:
1973 case TokenType.VAR:
1974 case TokenType.WHILE:
1975 case TokenType.YIELD:
1976 return RecoveryState.STATEMENT_BEGIN;
1977 default:
1978 next ();
1979 break;
1982 return RecoveryState.EOF;
1985 Namespace parse_namespace_declaration (Gee.List<Attribute>? attrs) throws ParseError {
1986 var begin = get_location ();
1987 expect (TokenType.NAMESPACE);
1988 var sym = parse_symbol_name ();
1989 var ns = new Namespace (sym.name, get_src (begin));
1990 if (comment != null) {
1991 ns.add_comment (comment);
1992 comment = null;
1995 set_attributes (ns, attrs);
1997 expect (TokenType.OPEN_BRACE);
1999 var old_using_directives = scanner.source_file.current_using_directives;
2000 parse_using_directives (ns);
2002 parse_declarations (ns, true);
2004 scanner.source_file.current_using_directives = old_using_directives;
2006 if (!accept (TokenType.CLOSE_BRACE)) {
2007 // only report error if it's not a secondary error
2008 if (context.report.get_errors () == 0) {
2009 Report.error (get_current_src (), "expected `}'");
2013 Namespace result = ns;
2014 while (sym.inner != null) {
2015 sym = sym.inner;
2016 ns = new Namespace (sym.name, result.source_reference);
2017 ns.add_namespace ((Namespace) result);
2018 result = ns;
2020 return result;
2023 void parse_namespace_member (Namespace ns) throws ParseError {
2024 var sym = parse_declaration ();
2026 if (sym is Namespace) {
2027 ns.add_namespace ((Namespace) sym);
2028 } else if (sym is Class) {
2029 ns.add_class ((Class) sym);
2030 } else if (sym is Interface) {
2031 ns.add_interface ((Interface) sym);
2032 } else if (sym is Struct) {
2033 ns.add_struct ((Struct) sym);
2034 } else if (sym is Enum) {
2035 ns.add_enum ((Enum) sym);
2036 } else if (sym is ErrorDomain) {
2037 ns.add_error_domain ((ErrorDomain) sym);
2038 } else if (sym is Delegate) {
2039 ns.add_delegate ((Delegate) sym);
2040 } else if (sym is Method) {
2041 var method = (Method) sym;
2042 if (method.binding == MemberBinding.INSTANCE) {
2043 // default to static member binding
2044 method.binding = MemberBinding.STATIC;
2046 ns.add_method (method);
2047 } else if (sym is Field) {
2048 var field = (Field) sym;
2049 if (field.binding == MemberBinding.INSTANCE) {
2050 // default to static member binding
2051 field.binding = MemberBinding.STATIC;
2053 ns.add_field (field);
2054 } else if (sym is Constant) {
2055 ns.add_constant ((Constant) sym);
2056 } else {
2057 Report.error (sym.source_reference, "unexpected declaration in namespace");
2059 scanner.source_file.add_node (sym);
2062 void parse_using_directives (Namespace ns) throws ParseError {
2063 while (accept (TokenType.USING)) {
2064 do {
2065 var begin = get_location ();
2066 var sym = parse_symbol_name ();
2067 var ns_ref = new UsingDirective (sym, get_src (begin));
2068 scanner.source_file.add_using_directive (ns_ref);
2069 ns.add_using_directive (ns_ref);
2070 } while (accept (TokenType.COMMA));
2071 expect (TokenType.SEMICOLON);
2075 Symbol parse_class_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2076 var begin = get_location ();
2077 var access = parse_access_modifier ();
2078 var flags = parse_type_declaration_modifiers ();
2079 expect (TokenType.CLASS);
2080 var sym = parse_symbol_name ();
2081 var type_param_list = parse_type_parameter_list ();
2082 var base_types = new ArrayList<DataType> ();
2083 if (accept (TokenType.COLON)) {
2084 do {
2085 base_types.add (parse_type ());
2086 } while (accept (TokenType.COMMA));
2089 var cl = new Class (sym.name, get_src (begin), comment);
2090 cl.access = access;
2091 if (ModifierFlags.ABSTRACT in flags) {
2092 cl.is_abstract = true;
2094 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2095 cl.external = true;
2097 set_attributes (cl, attrs);
2098 foreach (TypeParameter type_param in type_param_list) {
2099 cl.add_type_parameter (type_param);
2101 foreach (DataType base_type in base_types) {
2102 cl.add_base_type (base_type);
2105 parse_declarations (cl);
2107 // ensure there is always a default construction method
2108 if (!scanner.source_file.external_package
2109 && cl.default_construction_method == null) {
2110 var m = new CreationMethod (cl.name, null, cl.source_reference);
2111 m.access = SymbolAccessibility.PUBLIC;
2112 m.body = new Block (cl.source_reference);
2113 cl.add_method (m);
2116 Symbol result = cl;
2117 while (sym.inner != null) {
2118 sym = sym.inner;
2119 var ns = new Namespace (sym.name, cl.source_reference);
2120 if (result is Namespace) {
2121 ns.add_namespace ((Namespace) result);
2122 } else {
2123 ns.add_class ((Class) result);
2124 scanner.source_file.add_node (result);
2126 result = ns;
2128 return result;
2131 void parse_class_member (Class cl) throws ParseError {
2132 var sym = parse_declaration ();
2133 if (sym is Class) {
2134 cl.add_class ((Class) sym);
2135 } else if (sym is Struct) {
2136 cl.add_struct ((Struct) sym);
2137 } else if (sym is Enum) {
2138 cl.add_enum ((Enum) sym);
2139 } else if (sym is Delegate) {
2140 cl.add_delegate ((Delegate) sym);
2141 } else if (sym is Method) {
2142 cl.add_method ((Method) sym);
2143 } else if (sym is Signal) {
2144 cl.add_signal ((Signal) sym);
2145 } else if (sym is Field) {
2146 cl.add_field ((Field) sym);
2147 } else if (sym is Constant) {
2148 cl.add_constant ((Constant) sym);
2149 } else if (sym is Property) {
2150 cl.add_property ((Property) sym);
2151 } else if (sym is Constructor) {
2152 var c = (Constructor) sym;
2153 if (c.binding == MemberBinding.INSTANCE) {
2154 cl.constructor = c;
2155 } else if (c.binding == MemberBinding.CLASS) {
2156 cl.class_constructor = c;
2157 } else {
2158 cl.static_constructor = c;
2160 } else if (sym is Destructor) {
2161 var d = (Destructor) sym;
2162 if (d.binding == MemberBinding.STATIC) {
2163 cl.static_destructor = (Destructor) d;
2164 } else if (d.binding == MemberBinding.CLASS) {
2165 cl.class_destructor = (Destructor) d;
2166 } else {
2167 cl.destructor = (Destructor) d;
2169 } else {
2170 Report.error (sym.source_reference, "unexpected declaration in class");
2174 Constant parse_constant_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2175 var begin = get_location ();
2176 var access = parse_access_modifier ();
2177 var flags = parse_member_declaration_modifiers ();
2178 expect (TokenType.CONST);
2179 var type = parse_type (false);
2180 string id = parse_identifier ();
2182 type = parse_inline_array_type (type);
2184 Expression initializer = null;
2185 if (accept (TokenType.ASSIGN)) {
2186 initializer = parse_expression ();
2188 expect (TokenType.SEMICOLON);
2190 // constant arrays don't own their element
2191 var array_type = type as ArrayType;
2192 if (array_type != null) {
2193 array_type.element_type.value_owned = false;
2196 var c = new Constant (id, type, initializer, get_src (begin), comment);
2197 c.access = access;
2198 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2199 c.external = true;
2201 if (ModifierFlags.NEW in flags) {
2202 c.hides = true;
2204 set_attributes (c, attrs);
2205 return c;
2208 Field parse_field_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2209 var begin = get_location ();
2210 var access = parse_access_modifier ();
2211 var flags = parse_member_declaration_modifiers ();
2212 var type = parse_type ();
2213 string id = parse_identifier ();
2215 type = parse_inline_array_type (type);
2217 var f = new Field (id, type, null, get_src (begin), comment);
2218 f.access = access;
2219 set_attributes (f, attrs);
2220 if (ModifierFlags.STATIC in flags) {
2221 f.binding = MemberBinding.STATIC;
2222 } else if (ModifierFlags.CLASS in flags) {
2223 f.binding = MemberBinding.CLASS;
2225 if (ModifierFlags.ABSTRACT in flags
2226 || ModifierFlags.VIRTUAL in flags
2227 || ModifierFlags.OVERRIDE in flags) {
2228 Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2230 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2231 f.external = true;
2233 if (ModifierFlags.NEW in flags) {
2234 f.hides = true;
2236 if (accept (TokenType.ASSIGN)) {
2237 f.initializer = parse_expression ();
2239 expect (TokenType.SEMICOLON);
2240 return f;
2243 InitializerList parse_initializer () throws ParseError {
2244 var begin = get_location ();
2245 expect (TokenType.OPEN_BRACE);
2246 var initializer = new InitializerList (get_src (begin));
2247 if (current () != TokenType.CLOSE_BRACE) {
2248 do {
2249 var init = parse_argument ();
2250 initializer.append (init);
2251 } while (accept (TokenType.COMMA));
2253 expect (TokenType.CLOSE_BRACE);
2254 return initializer;
2257 Method parse_method_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2258 var begin = get_location ();
2259 var access = parse_access_modifier ();
2260 var flags = parse_member_declaration_modifiers ();
2261 var type = parse_type ();
2262 string id = parse_identifier ();
2263 var type_param_list = parse_type_parameter_list ();
2264 var method = new Method (id, type, get_src (begin), comment);
2265 method.access = access;
2266 set_attributes (method, attrs);
2267 foreach (TypeParameter type_param in type_param_list) {
2268 method.add_type_parameter (type_param);
2270 if (ModifierFlags.STATIC in flags) {
2271 method.binding = MemberBinding.STATIC;
2272 } else if (ModifierFlags.CLASS in flags) {
2273 method.binding = MemberBinding.CLASS;
2275 if (ModifierFlags.ASYNC in flags) {
2276 method.coroutine = true;
2278 if (ModifierFlags.NEW in flags) {
2279 method.hides = true;
2282 if (method.binding == MemberBinding.INSTANCE) {
2283 if (ModifierFlags.ABSTRACT in flags) {
2284 method.is_abstract = true;
2286 if (ModifierFlags.VIRTUAL in flags) {
2287 method.is_virtual = true;
2289 if (ModifierFlags.OVERRIDE in flags) {
2290 method.overrides = true;
2292 if ((method.is_abstract && method.is_virtual)
2293 || (method.is_abstract && method.overrides)
2294 || (method.is_virtual && method.overrides)) {
2295 throw new ParseError.SYNTAX (get_error ("only one of `abstract', `virtual', or `override' may be specified"));
2297 } else {
2298 if (ModifierFlags.ABSTRACT in flags
2299 || ModifierFlags.VIRTUAL in flags
2300 || ModifierFlags.OVERRIDE in flags) {
2301 throw new ParseError.SYNTAX (get_error ("the modifiers `abstract', `virtual', and `override' are not valid for static methods"));
2305 if (ModifierFlags.INLINE in flags) {
2306 method.is_inline = true;
2308 if (ModifierFlags.EXTERN in flags) {
2309 method.external = true;
2311 expect (TokenType.OPEN_PARENS);
2312 if (current () != TokenType.CLOSE_PARENS) {
2313 do {
2314 var param = parse_parameter ();
2315 method.add_parameter (param);
2316 } while (accept (TokenType.COMMA));
2318 expect (TokenType.CLOSE_PARENS);
2319 if (accept (TokenType.THROWS)) {
2320 do {
2321 method.add_error_type (parse_type ());
2322 } while (accept (TokenType.COMMA));
2324 while (accept (TokenType.REQUIRES)) {
2325 expect (TokenType.OPEN_PARENS);
2326 method.add_precondition (parse_expression ());
2327 expect (TokenType.CLOSE_PARENS);
2329 while (accept (TokenType.ENSURES)) {
2330 expect (TokenType.OPEN_PARENS);
2331 method.add_postcondition (parse_expression ());
2332 expect (TokenType.CLOSE_PARENS);
2334 if (!accept (TokenType.SEMICOLON)) {
2335 method.body = parse_block ();
2336 } else if (scanner.source_file.external_package) {
2337 method.external = true;
2339 return method;
2342 Property parse_property_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2343 var begin = get_location ();
2344 var access = parse_access_modifier ();
2345 var flags = parse_member_declaration_modifiers ();
2346 var type = parse_type ();
2348 bool getter_owned = false;
2349 if (accept (TokenType.HASH)) {
2350 if (!context.deprecated) {
2351 Report.warning (get_last_src (), "deprecated syntax, use `owned` modifier before `get'");
2353 getter_owned = true;
2356 string id = parse_identifier ();
2357 var prop = new Property (id, type, null, null, get_src (begin), comment);
2358 prop.access = access;
2359 set_attributes (prop, attrs);
2360 if (ModifierFlags.STATIC in flags) {
2361 prop.binding = MemberBinding.STATIC;
2362 } else if (ModifierFlags.CLASS in flags) {
2363 prop.binding = MemberBinding.CLASS;
2365 if (ModifierFlags.ABSTRACT in flags) {
2366 prop.is_abstract = true;
2368 if (ModifierFlags.VIRTUAL in flags) {
2369 prop.is_virtual = true;
2371 if (ModifierFlags.OVERRIDE in flags) {
2372 prop.overrides = true;
2374 if (ModifierFlags.NEW in flags) {
2375 prop.hides = true;
2377 if (ModifierFlags.ASYNC in flags) {
2378 Report.error (prop.source_reference, "async properties are not supported yet");
2380 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2381 prop.external = true;
2383 if (accept (TokenType.THROWS)) {
2384 do {
2385 prop.add_error_type (parse_type ());
2386 } while (accept (TokenType.COMMA));
2387 Report.error (prop.source_reference, "properties throwing errors are not supported yet");
2389 expect (TokenType.OPEN_BRACE);
2390 while (current () != TokenType.CLOSE_BRACE) {
2391 if (accept (TokenType.DEFAULT)) {
2392 if (prop.default_expression != null) {
2393 throw new ParseError.SYNTAX (get_error ("property default value already defined"));
2395 expect (TokenType.ASSIGN);
2396 prop.default_expression = parse_expression ();
2397 expect (TokenType.SEMICOLON);
2398 } else {
2399 var accessor_begin = get_location ();
2400 var accessor_attrs = parse_attributes ();
2401 var accessor_access = parse_access_modifier (SymbolAccessibility.PUBLIC);
2403 var value_type = type.copy ();
2404 value_type.value_owned = accept (TokenType.OWNED);
2406 if (accept (TokenType.GET)) {
2407 if (prop.get_accessor != null) {
2408 throw new ParseError.SYNTAX (get_error ("property get accessor already defined"));
2411 if (getter_owned) {
2412 value_type.value_owned = true;
2415 Block block = null;
2416 if (!accept (TokenType.SEMICOLON)) {
2417 block = parse_block ();
2418 prop.external = false;
2420 prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin));
2421 set_attributes (prop.get_accessor, accessor_attrs);
2422 prop.get_accessor.access = accessor_access;
2423 } else {
2424 bool writable, _construct;
2425 if (accept (TokenType.SET)) {
2426 writable = true;
2427 _construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT);
2428 } else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) {
2429 _construct = true;
2430 writable = accept (TokenType.SET);
2431 } else {
2432 throw new ParseError.SYNTAX (get_error ("expected get, set, or construct"));
2434 if (prop.set_accessor != null) {
2435 throw new ParseError.SYNTAX (get_error ("property set accessor already defined"));
2437 Block block = null;
2438 if (!accept (TokenType.SEMICOLON)) {
2439 block = parse_block ();
2440 prop.external = false;
2442 prop.set_accessor = new PropertyAccessor (false, writable, _construct, value_type, block, get_src (accessor_begin));
2443 set_attributes (prop.set_accessor, accessor_attrs);
2444 prop.set_accessor.access = accessor_access;
2448 expect (TokenType.CLOSE_BRACE);
2450 if (!prop.is_abstract && !prop.external) {
2451 bool empty_get = (prop.get_accessor != null && prop.get_accessor.body == null);
2452 bool empty_set = (prop.set_accessor != null && prop.set_accessor.body == null);
2454 if (empty_get != empty_set) {
2455 if (empty_get) {
2456 Report.error (prop.source_reference, "property getter must have a body");
2457 } else if (empty_set) {
2458 Report.error (prop.source_reference, "property setter must have a body");
2460 prop.error = true;
2463 if (empty_get && empty_set) {
2464 /* automatic property accessor body generation */
2465 var field_type = prop.property_type.copy ();
2466 prop.field = new Field ("_%s".printf (prop.name), field_type, prop.default_expression, prop.source_reference);
2467 prop.field.access = SymbolAccessibility.PRIVATE;
2468 prop.field.binding = prop.binding;
2472 return prop;
2475 Signal parse_signal_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2476 var begin = get_location ();
2477 var access = parse_access_modifier ();
2478 var flags = parse_member_declaration_modifiers ();
2479 expect (TokenType.SIGNAL);
2480 var type = parse_type ();
2481 string id = parse_identifier ();
2482 var sig = new Signal (id, type, get_src (begin), comment);
2483 sig.access = access;
2484 set_attributes (sig, attrs);
2485 if (ModifierFlags.STATIC in flags) {
2486 throw new ParseError.SYNTAX (get_error ("`static' modifier not allowed on signals"));
2487 } else if (ModifierFlags.CLASS in flags) {
2488 throw new ParseError.SYNTAX (get_error ("`class' modifier not allowed on signals"));
2490 if (ModifierFlags.VIRTUAL in flags) {
2491 sig.is_virtual = true;
2493 if (ModifierFlags.NEW in flags) {
2494 sig.hides = true;
2496 expect (TokenType.OPEN_PARENS);
2497 if (current () != TokenType.CLOSE_PARENS) {
2498 do {
2499 var param = parse_parameter ();
2500 sig.add_parameter (param);
2501 } while (accept (TokenType.COMMA));
2503 expect (TokenType.CLOSE_PARENS);
2504 if (!accept (TokenType.SEMICOLON)) {
2505 sig.body = parse_block ();
2508 return sig;
2511 Constructor parse_constructor_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2512 var begin = get_location ();
2513 var flags = parse_member_declaration_modifiers ();
2514 expect (TokenType.CONSTRUCT);
2515 if (ModifierFlags.NEW in flags) {
2516 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on constructor"));
2518 var c = new Constructor (get_src (begin));
2519 if (ModifierFlags.STATIC in flags) {
2520 c.binding = MemberBinding.STATIC;
2521 } else if (ModifierFlags.CLASS in flags) {
2522 c.binding = MemberBinding.CLASS;
2524 c.body = parse_block ();
2525 return c;
2528 Destructor parse_destructor_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2529 var begin = get_location ();
2530 var flags = parse_member_declaration_modifiers ();
2531 expect (TokenType.TILDE);
2532 parse_identifier ();
2533 expect (TokenType.OPEN_PARENS);
2534 expect (TokenType.CLOSE_PARENS);
2535 if (ModifierFlags.NEW in flags) {
2536 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on destructor"));
2538 var d = new Destructor (get_src (begin));
2539 if (ModifierFlags.STATIC in flags) {
2540 d.binding = MemberBinding.STATIC;
2541 } else if (ModifierFlags.CLASS in flags) {
2542 d.binding = MemberBinding.CLASS;
2544 d.body = parse_block ();
2545 return d;
2548 Symbol parse_struct_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2549 var begin = get_location ();
2550 var access = parse_access_modifier ();
2551 var flags = parse_type_declaration_modifiers ();
2552 expect (TokenType.STRUCT);
2553 var sym = parse_symbol_name ();
2554 var type_param_list = parse_type_parameter_list ();
2555 DataType base_type = null;
2556 if (accept (TokenType.COLON)) {
2557 base_type = parse_type ();
2559 var st = new Struct (sym.name, get_src (begin), comment);
2560 st.access = access;
2561 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2562 st.external = true;
2564 set_attributes (st, attrs);
2565 foreach (TypeParameter type_param in type_param_list) {
2566 st.add_type_parameter (type_param);
2568 if (base_type != null) {
2569 st.base_type = base_type;
2572 parse_declarations (st);
2574 Symbol result = st;
2575 while (sym.inner != null) {
2576 sym = sym.inner;
2578 var ns = new Namespace (sym.name, st.source_reference);
2579 if (result is Namespace) {
2580 ns.add_namespace ((Namespace) result);
2581 } else {
2582 ns.add_struct ((Struct) result);
2583 scanner.source_file.add_node (result);
2585 result = ns;
2587 return result;
2590 void parse_struct_member (Struct st) throws ParseError {
2591 var sym = parse_declaration ();
2592 if (sym is Method) {
2593 st.add_method ((Method) sym);
2594 } else if (sym is Field) {
2595 st.add_field ((Field) sym);
2596 } else if (sym is Constant) {
2597 st.add_constant ((Constant) sym);
2598 } else if (sym is Property) {
2599 st.add_property ((Property) sym);
2600 } else {
2601 Report.error (sym.source_reference, "unexpected declaration in struct");
2605 Symbol parse_interface_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2606 var begin = get_location ();
2607 var access = parse_access_modifier ();
2608 var flags = parse_type_declaration_modifiers ();
2609 expect (TokenType.INTERFACE);
2610 var sym = parse_symbol_name ();
2611 var type_param_list = parse_type_parameter_list ();
2612 var base_types = new ArrayList<DataType> ();
2613 if (accept (TokenType.COLON)) {
2614 do {
2615 var type = parse_type ();
2616 base_types.add (type);
2617 } while (accept (TokenType.COMMA));
2619 var iface = new Interface (sym.name, get_src (begin), comment);
2620 iface.access = access;
2621 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2622 iface.external = true;
2624 set_attributes (iface, attrs);
2625 foreach (TypeParameter type_param in type_param_list) {
2626 iface.add_type_parameter (type_param);
2628 foreach (DataType base_type in base_types) {
2629 iface.add_prerequisite (base_type);
2632 parse_declarations (iface);
2634 Symbol result = iface;
2635 while (sym.inner != null) {
2636 sym = sym.inner;
2637 var ns = new Namespace (sym.name, iface.source_reference);
2638 if (result is Namespace) {
2639 ns.add_namespace ((Namespace) result);
2640 } else {
2641 ns.add_interface ((Interface) result);
2642 scanner.source_file.add_node (result);
2644 result = ns;
2646 return result;
2649 void parse_interface_member (Interface iface) throws ParseError {
2650 var sym = parse_declaration ();
2651 if (sym is Class) {
2652 iface.add_class ((Class) sym);
2653 } else if (sym is Struct) {
2654 iface.add_struct ((Struct) sym);
2655 } else if (sym is Enum) {
2656 iface.add_enum ((Enum) sym);
2657 } else if (sym is Delegate) {
2658 iface.add_delegate ((Delegate) sym);
2659 } else if (sym is Method) {
2660 iface.add_method ((Method) sym);
2661 } else if (sym is Signal) {
2662 iface.add_signal ((Signal) sym);
2663 } else if (sym is Field) {
2664 iface.add_field ((Field) sym);
2665 } else if (sym is Constant) {
2666 iface.add_constant ((Constant) sym);
2667 } else if (sym is Property) {
2668 iface.add_property ((Property) sym);
2669 } else {
2670 Report.error (sym.source_reference, "unexpected declaration in interface");
2674 Symbol parse_enum_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2675 var begin = get_location ();
2676 var access = parse_access_modifier ();
2677 var flags = parse_type_declaration_modifiers ();
2678 expect (TokenType.ENUM);
2679 var sym = parse_symbol_name ();
2680 var en = new Enum (sym.name, get_src (begin), comment);
2681 en.access = access;
2682 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2683 en.external = true;
2685 set_attributes (en, attrs);
2687 expect (TokenType.OPEN_BRACE);
2688 do {
2689 if (current () == TokenType.CLOSE_BRACE
2690 && en.get_values ().size > 0) {
2691 // allow trailing comma
2692 break;
2694 var value_attrs = parse_attributes ();
2695 var value_begin = get_location ();
2696 string id = parse_identifier ();
2697 comment = scanner.pop_comment ();
2698 var ev = new EnumValue (id, get_src (value_begin), comment);
2699 set_attributes (ev, value_attrs);
2700 if (accept (TokenType.ASSIGN)) {
2701 ev.value = parse_expression ();
2703 en.add_value (ev);
2704 } while (accept (TokenType.COMMA));
2705 if (accept (TokenType.SEMICOLON)) {
2706 // enum methods
2707 while (current () != TokenType.CLOSE_BRACE) {
2708 var member_sym = parse_declaration ();
2709 if (member_sym is Method) {
2710 en.add_method ((Method) member_sym);
2711 } else {
2712 Report.error (member_sym.source_reference, "unexpected declaration in enum");
2716 expect (TokenType.CLOSE_BRACE);
2718 Symbol result = en;
2719 while (sym.inner != null) {
2720 sym = sym.inner;
2721 var ns = new Namespace (sym.name, en.source_reference);
2722 if (result is Namespace) {
2723 ns.add_namespace ((Namespace) result);
2724 } else {
2725 ns.add_enum ((Enum) result);
2726 scanner.source_file.add_node (result);
2728 result = ns;
2730 return result;
2733 Symbol parse_errordomain_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2734 var begin = get_location ();
2735 var access = parse_access_modifier ();
2736 var flags = parse_type_declaration_modifiers ();
2737 expect (TokenType.ERRORDOMAIN);
2738 var sym = parse_symbol_name ();
2739 var ed = new ErrorDomain (sym.name, get_src (begin), comment);
2740 ed.access = access;
2741 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2742 ed.external = true;
2744 set_attributes (ed, attrs);
2746 expect (TokenType.OPEN_BRACE);
2747 do {
2748 if (current () == TokenType.CLOSE_BRACE
2749 && ed.get_codes ().size > 0) {
2750 // allow trailing comma
2751 break;
2753 var code_attrs = parse_attributes ();
2754 var code_begin = get_location ();
2755 string id = parse_identifier ();
2756 comment = scanner.pop_comment ();
2757 var ec = new ErrorCode (id, get_src (code_begin), comment);
2758 set_attributes (ec, code_attrs);
2759 if (accept (TokenType.ASSIGN)) {
2760 ec.value = parse_expression ();
2762 ed.add_code (ec);
2763 } while (accept (TokenType.COMMA));
2764 if (accept (TokenType.SEMICOLON)) {
2765 // errordomain methods
2766 while (current () != TokenType.CLOSE_BRACE) {
2767 var member_sym = parse_declaration ();
2768 if (member_sym is Method) {
2769 ed.add_method ((Method) member_sym);
2770 } else {
2771 Report.error (member_sym.source_reference, "unexpected declaration in errordomain");
2775 expect (TokenType.CLOSE_BRACE);
2777 Symbol result = ed;
2778 while (sym.inner != null) {
2779 sym = sym.inner;
2780 var ns = new Namespace (sym.name, ed.source_reference);
2781 if (result is Namespace) {
2782 ns.add_namespace ((Namespace) result);
2783 } else {
2784 ns.add_error_domain ((ErrorDomain) result);
2785 scanner.source_file.add_node (result);
2787 result = ns;
2789 return result;
2792 SymbolAccessibility parse_access_modifier (SymbolAccessibility default_access = SymbolAccessibility.PRIVATE) {
2793 switch (current ()) {
2794 case TokenType.PRIVATE:
2795 next ();
2796 return SymbolAccessibility.PRIVATE;
2797 case TokenType.PROTECTED:
2798 next ();
2799 return SymbolAccessibility.PROTECTED;
2800 case TokenType.INTERNAL:
2801 next ();
2802 return SymbolAccessibility.INTERNAL;
2803 case TokenType.PUBLIC:
2804 next ();
2805 return SymbolAccessibility.PUBLIC;
2806 default:
2807 return default_access;
2811 ModifierFlags parse_type_declaration_modifiers () {
2812 ModifierFlags flags = 0;
2813 while (true) {
2814 switch (current ()) {
2815 case TokenType.ABSTRACT:
2816 next ();
2817 flags |= ModifierFlags.ABSTRACT;
2818 break;
2819 case TokenType.EXTERN:
2820 next ();
2821 flags |= ModifierFlags.EXTERN;
2822 break;
2823 case TokenType.STATIC:
2824 next ();
2825 flags |= ModifierFlags.STATIC;
2826 break;
2827 default:
2828 return flags;
2833 ModifierFlags parse_member_declaration_modifiers () {
2834 ModifierFlags flags = 0;
2835 while (true) {
2836 switch (current ()) {
2837 case TokenType.ABSTRACT:
2838 next ();
2839 flags |= ModifierFlags.ABSTRACT;
2840 break;
2841 case TokenType.ASYNC:
2842 next ();
2843 flags |= ModifierFlags.ASYNC;
2844 break;
2845 case TokenType.CLASS:
2846 next ();
2847 flags |= ModifierFlags.CLASS;
2848 break;
2849 case TokenType.EXTERN:
2850 next ();
2851 flags |= ModifierFlags.EXTERN;
2852 break;
2853 case TokenType.INLINE:
2854 next ();
2855 flags |= ModifierFlags.INLINE;
2856 break;
2857 case TokenType.NEW:
2858 next ();
2859 flags |= ModifierFlags.NEW;
2860 break;
2861 case TokenType.OVERRIDE:
2862 next ();
2863 flags |= ModifierFlags.OVERRIDE;
2864 break;
2865 case TokenType.STATIC:
2866 next ();
2867 flags |= ModifierFlags.STATIC;
2868 break;
2869 case TokenType.VIRTUAL:
2870 next ();
2871 flags |= ModifierFlags.VIRTUAL;
2872 break;
2873 default:
2874 return flags;
2879 FormalParameter parse_parameter () throws ParseError {
2880 var attrs = parse_attributes ();
2881 var begin = get_location ();
2882 if (accept (TokenType.ELLIPSIS)) {
2883 // varargs
2884 return new FormalParameter.with_ellipsis (get_src (begin));
2886 bool params_array = accept (TokenType.PARAMS);
2887 var direction = ParameterDirection.IN;
2888 if (accept (TokenType.OUT)) {
2889 direction = ParameterDirection.OUT;
2890 } else if (accept (TokenType.REF)) {
2891 direction = ParameterDirection.REF;
2894 DataType type;
2895 if (direction == ParameterDirection.IN) {
2896 // in parameters are weak by default
2897 type = parse_type (false);
2898 } else {
2899 // out parameters own the value by default
2900 type = parse_type (true);
2902 string id = parse_identifier ();
2903 var param = new FormalParameter (id, type, get_src (begin));
2904 set_attributes (param, attrs);
2905 param.direction = direction;
2906 param.params_array = params_array;
2907 if (accept (TokenType.ASSIGN)) {
2908 param.default_expression = parse_expression ();
2910 return param;
2913 CreationMethod parse_creation_method_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2914 var begin = get_location ();
2915 var access = parse_access_modifier ();
2916 var flags = parse_member_declaration_modifiers ();
2917 var sym = parse_symbol_name ();
2918 if (ModifierFlags.NEW in flags) {
2919 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on creation method"));
2921 CreationMethod method;
2922 if (sym.inner == null) {
2923 method = new CreationMethod (sym.name, null, get_src (begin), comment);
2924 } else {
2925 method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
2927 if (ModifierFlags.EXTERN in flags) {
2928 method.external = true;
2930 if (ModifierFlags.ABSTRACT in flags
2931 || ModifierFlags.VIRTUAL in flags
2932 || ModifierFlags.OVERRIDE in flags) {
2933 Report.error (method.source_reference, "abstract, virtual, and override modifiers are not applicable to creation methods");
2935 if (ModifierFlags.ASYNC in flags) {
2936 method.coroutine = true;
2938 expect (TokenType.OPEN_PARENS);
2939 if (current () != TokenType.CLOSE_PARENS) {
2940 do {
2941 var param = parse_parameter ();
2942 method.add_parameter (param);
2943 } while (accept (TokenType.COMMA));
2945 expect (TokenType.CLOSE_PARENS);
2946 if (accept (TokenType.THROWS)) {
2947 do {
2948 method.add_error_type (parse_type ());
2949 } while (accept (TokenType.COMMA));
2951 method.access = access;
2952 set_attributes (method, attrs);
2953 if (!accept (TokenType.SEMICOLON)) {
2954 method.body = parse_block ();
2955 } else if (scanner.source_file.external_package) {
2956 method.external = true;
2958 return method;
2961 Symbol parse_delegate_declaration (Gee.List<Attribute>? attrs) throws ParseError {
2962 var begin = get_location ();
2963 var access = parse_access_modifier ();
2964 var flags = parse_member_declaration_modifiers ();
2965 expect (TokenType.DELEGATE);
2966 if (ModifierFlags.NEW in flags) {
2967 throw new ParseError.SYNTAX (get_error ("`new' modifier not allowed on delegates"));
2969 var type = parse_type ();
2970 var sym = parse_symbol_name ();
2971 var type_param_list = parse_type_parameter_list ();
2972 var d = new Delegate (sym.name, type, get_src (begin), comment);
2973 d.access = access;
2974 set_attributes (d, attrs);
2975 if (ModifierFlags.STATIC in flags) {
2976 if (!context.deprecated) {
2977 // TODO enable warning in future releases
2978 // Report.warning (get_last_src (), "deprecated syntax, use [CCode (has_target = false)]");
2980 } else {
2981 d.has_target = true;
2983 if (ModifierFlags.EXTERN in flags || scanner.source_file.external_package) {
2984 d.external = true;
2986 foreach (TypeParameter type_param in type_param_list) {
2987 d.add_type_parameter (type_param);
2989 expect (TokenType.OPEN_PARENS);
2990 if (current () != TokenType.CLOSE_PARENS) {
2991 do {
2992 var param = parse_parameter ();
2993 d.add_parameter (param);
2994 } while (accept (TokenType.COMMA));
2996 expect (TokenType.CLOSE_PARENS);
2997 if (accept (TokenType.THROWS)) {
2998 do {
2999 d.add_error_type (parse_type ());
3000 } while (accept (TokenType.COMMA));
3002 expect (TokenType.SEMICOLON);
3004 Symbol result = d;
3005 while (sym.inner != null) {
3006 sym = sym.inner;
3007 var ns = new Namespace (sym.name, d.source_reference);
3008 if (result is Namespace) {
3009 ns.add_namespace ((Namespace) result);
3010 } else {
3011 ns.add_delegate ((Delegate) result);
3012 scanner.source_file.add_node (result);
3014 result = ns;
3016 return result;
3019 Gee.List<TypeParameter> parse_type_parameter_list () throws ParseError {
3020 var list = new ArrayList<TypeParameter> ();
3021 if (accept (TokenType.OP_LT)) {
3022 do {
3023 var begin = get_location ();
3024 string id = parse_identifier ();
3025 list.add (new TypeParameter (id, get_src (begin)));
3026 } while (accept (TokenType.COMMA));
3027 expect (TokenType.OP_GT);
3029 return list;
3032 void skip_type_argument_list () throws ParseError {
3033 if (accept (TokenType.OP_LT)) {
3034 do {
3035 skip_type ();
3036 } while (accept (TokenType.COMMA));
3037 expect (TokenType.OP_GT);
3041 // try to parse type argument list
3042 Gee.List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3043 var begin = get_location ();
3044 if (accept (TokenType.OP_LT)) {
3045 var list = new ArrayList<DataType> ();
3046 do {
3047 switch (current ()) {
3048 case TokenType.VOID:
3049 case TokenType.DYNAMIC:
3050 case TokenType.UNOWNED:
3051 case TokenType.WEAK:
3052 case TokenType.IDENTIFIER:
3053 var type = parse_type ();
3054 list.add (type);
3055 break;
3056 default:
3057 rollback (begin);
3058 return null;
3060 } while (accept (TokenType.COMMA));
3061 if (!accept (TokenType.OP_GT)) {
3062 rollback (begin);
3063 return null;
3065 if (maybe_expression) {
3066 // check follower to decide whether to keep type argument list
3067 switch (current ()) {
3068 case TokenType.OPEN_PARENS:
3069 case TokenType.CLOSE_PARENS:
3070 case TokenType.CLOSE_BRACKET:
3071 case TokenType.COLON:
3072 case TokenType.SEMICOLON:
3073 case TokenType.COMMA:
3074 case TokenType.DOT:
3075 case TokenType.INTERR:
3076 case TokenType.OP_EQ:
3077 case TokenType.OP_NE:
3078 // keep type argument list
3079 break;
3080 default:
3081 // interpret tokens as expression
3082 rollback (begin);
3083 return null;
3086 return list;
3088 return null;
3091 MemberAccess parse_member_name () throws ParseError {
3092 var begin = get_location ();
3093 MemberAccess expr = null;
3094 bool first = true;
3095 do {
3096 string id = parse_identifier ();
3098 // The first member access can be global:: qualified
3099 bool qualified = false;
3100 if (first && id == "global" && accept (TokenType.DOUBLE_COLON)) {
3101 id = parse_identifier ();
3102 qualified = true;
3105 Gee.List<DataType> type_arg_list = parse_type_argument_list (false);
3106 expr = new MemberAccess (expr, id, get_src (begin));
3107 expr.qualified = qualified;
3108 if (type_arg_list != null) {
3109 foreach (DataType type_arg in type_arg_list) {
3110 expr.add_type_argument (type_arg);
3114 first = false;
3115 } while (accept (TokenType.DOT));
3116 return expr;
3119 bool is_declaration_keyword (TokenType type) {
3120 switch (type) {
3121 case TokenType.ABSTRACT:
3122 case TokenType.ASYNC:
3123 case TokenType.CLASS:
3124 case TokenType.CONST:
3125 case TokenType.DELEGATE:
3126 case TokenType.ENUM:
3127 case TokenType.ERRORDOMAIN:
3128 case TokenType.EXTERN:
3129 case TokenType.INLINE:
3130 case TokenType.INTERFACE:
3131 case TokenType.INTERNAL:
3132 case TokenType.NAMESPACE:
3133 case TokenType.NEW:
3134 case TokenType.OVERRIDE:
3135 case TokenType.PRIVATE:
3136 case TokenType.PROTECTED:
3137 case TokenType.PUBLIC:
3138 case TokenType.SIGNAL:
3139 case TokenType.STATIC:
3140 case TokenType.STRUCT:
3141 case TokenType.VIRTUAL:
3142 case TokenType.VOLATILE:
3143 return true;
3144 default:
3145 return false;
3150 public errordomain Vala.ParseError {
3151 FAILED,
3152 SYNTAX