1/* valagenieparser.vala
2 *
3 * Copyright (C) 2008-2012  Jamie McCracken, Jürg Billeter
4 * Based on code by Jürg Billeter
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 *
20 * Author:
21 * 	Jamie McCracken jamiemcc gnome org
22 */
23
24using GLib;
25
26
27/**
28 * Code visitor parsing all Genie source files.
29 */
30public class Vala.Genie.Parser : CodeVisitor {
31	Scanner scanner;
32
33	CodeContext context;
34
35	// token buffer
36	TokenInfo[] tokens;
37	// index of current token in buffer
38	int index;
39	// number of tokens in buffer
40	int size;
41
42	Comment comment;
43
44	string class_name;
45
46	/* hack needed to know if any part of an expression is a lambda one */
47	bool current_expr_is_lambda;
48
49	const int BUFFER_SIZE = 32;
50
51	static List<TypeParameter> _empty_type_parameter_list;
52
53	struct TokenInfo {
54		public TokenType type;
55		public SourceLocation begin;
56		public SourceLocation end;
57	}
58
59	enum ModifierFlags {
60		NONE,
61		ABSTRACT = 1 << 0,
62		CLASS = 1 << 1,
63		EXTERN = 1 << 2,
64		INLINE = 1 << 3,
65		NEW = 1 << 4,
66		OVERRIDE = 1 << 5,
67		STATIC = 1 << 6,
68		VIRTUAL = 1 << 7,
69		PRIVATE = 1 << 8,
70		ASYNC = 1 << 9,
71		SEALED = 1 << 10,
72		PUBLIC = 1 << 11,
73		PROTECTED = 1 << 12,
74	}
75
76	public Parser () {
77		tokens = new TokenInfo[BUFFER_SIZE];
78		class_name = null;
79		current_expr_is_lambda = false;
80	}
81
82	/**
83	 * Parses all .gs source files in the specified code context and
84	 * builds a code tree.
85	 *
86	 * @param context a code context
87	 */
88	public void parse (CodeContext context) {
89		this.context = context;
90		context.accept (this);
91		this.context = null;
92	}
93
94	public override void visit_source_file (SourceFile source_file) {
95		if (source_file.filename.has_suffix (".gs")) {
96			parse_file (source_file);
97		}
98	}
99
100	inline bool next () {
101		index = (index + 1) % BUFFER_SIZE;
102		size--;
103		if (size <= 0) {
104			SourceLocation begin, end;
105			TokenType type = scanner.read_token (out begin, out end);
106			tokens[index] = { type, begin, end };
107			size = 1;
108		}
109		return (tokens[index].type != TokenType.EOF);
110	}
111
112	inline void prev () {
113		index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
114		size++;
115		assert (size <= BUFFER_SIZE);
116	}
117
118	inline TokenType current () {
119		return tokens[index].type;
120	}
121
122	inline bool accept (TokenType type) {
123		if (current () == type) {
124			next ();
125			return true;
126		}
127		return false;
128	}
129
130	inline bool accept_separator () {
131		if (current () == TokenType.COMMA || current () == TokenType.EOL) {
132			next ();
133			return true;
134		}
135		return false;
136	}
137
138	inline bool accept_terminator () {
139		if (current () == TokenType.SEMICOLON || current () == TokenType.EOL) {
140			next ();
141			return true;
142		}
143		return false;
144	}
145
146	inline bool accept_block () {
147
148		bool has_term = accept_terminator ();
149
150		if (accept (TokenType.INDENT)) {
151			prev();
152			return true;
153		}
154
155		if (has_term) {
156			prev ();
157		}
158
159		return false;
160	}
161
162	void report_parse_error (ParseError e) {
163		var begin = get_location ();
164		next ();
165		Report.error (get_src (begin), "syntax error, " + e.message);
166	}
167
168	inline bool expect (TokenType type) throws ParseError {
169		if (accept (type)) {
170			return true;
171		}
172
173		TokenType cur = current ();
174		TokenType pre =  tokens[index - 1].type;
175
176		throw new ParseError.SYNTAX ("expected %s but got %s with previous %s", type.to_string (), cur.to_string (), pre.to_string());
177	}
178
179	inline bool expect_separator () throws ParseError {
180		if (accept_separator ()) {
181			return true;
182		}
183
184		TokenType cur = current ();
185
186		throw new ParseError.SYNTAX ("expected line end or comma but got %s", cur.to_string());
187	}
188
189	inline bool expect_terminator () throws ParseError {
190		if (accept_terminator ()) {
191			return true;
192		}
193
194		TokenType cur = current ();
195
196		throw new ParseError.SYNTAX ("expected line end or semicolon but got %s", cur.to_string());
197	}
198
199	inline SourceLocation get_location () {
200		return tokens[index].begin;
201	}
202
203	string get_current_string () {
204		var token = tokens[index];
205		return ((string) token.begin.pos).substring (0, (int) (token.end.pos - token.begin.pos));
206	}
207
208	string get_last_string () {
209		int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
210		var token = tokens[last_index];
211		return ((string) token.begin.pos).substring (0, (int) (token.end.pos - token.begin.pos));
212	}
213
214	SourceReference get_src (SourceLocation begin) {
215		int last_index = (index + BUFFER_SIZE - 1) % BUFFER_SIZE;
216
217		return new SourceReference (scanner.source_file, begin, tokens[last_index].end);
218	}
219
220	SourceReference get_current_src () {
221		var token = tokens[index];
222		return new SourceReference (scanner.source_file, token.begin, token.end);
223	}
224
225	void rollback (SourceLocation location) {
226		while (tokens[index].begin.pos != location.pos) {
227			index = (index - 1 + BUFFER_SIZE) % BUFFER_SIZE;
228			size++;
229			if (size > BUFFER_SIZE) {
230				scanner.seek (location);
231				size = 0;
232				index = 0;
233
234				next ();
235			}
236		}
237	}
238
239	inline  SymbolAccessibility get_default_accessibility (string s) {
240		if (s.has_prefix("_")) {
241			return SymbolAccessibility.PRIVATE;
242		}
243
244		return SymbolAccessibility.PUBLIC;
245	}
246
247	void skip_identifier () throws ParseError {
248		// also accept keywords as identifiers where there is no conflict
249		switch (current ()) {
250		case TokenType.ABSTRACT:
251		case TokenType.AS:
252		case TokenType.ASSERT:
253		case TokenType.ASYNC:
254		case TokenType.BREAK:
255		case TokenType.CLASS:
256		case TokenType.CONST:
257		case TokenType.CONTINUE:
258		case TokenType.DEDENT:
259		case TokenType.DEF:
260		case TokenType.DEFAULT:
261		case TokenType.DELEGATE:
262		case TokenType.DELETE:
263		case TokenType.DO:
264		case TokenType.DOWNTO:
265		case TokenType.DYNAMIC:
266		case TokenType.ELSE:
267		case TokenType.EOL:
268		case TokenType.ENUM:
269		case TokenType.ENSURES:
270		case TokenType.ERRORDOMAIN:
271		case TokenType.EVENT:
272		case TokenType.EXCEPT:
273		case TokenType.EXTERN:
274		case TokenType.FALSE:
275		case TokenType.FINAL:
276		case TokenType.FINALLY:
277		case TokenType.FOR:
278		case TokenType.GET:
279		case TokenType.IDENTIFIER:
280		case TokenType.IF:
281		case TokenType.IN:
282		case TokenType.INDENT:
283		case TokenType.INIT:
284		case TokenType.INLINE:
285		case TokenType.INTERFACE:
286		case TokenType.INTERNAL:
287		case TokenType.IS:
288		case TokenType.ISA:
289		case TokenType.LOCK:
290		case TokenType.NAMESPACE:
291		case TokenType.NEW:
292		case TokenType.NULL:
293		case TokenType.OF:
294		case TokenType.OUT:
295		case TokenType.OVERRIDE:
296		case TokenType.OWNED:
297		case TokenType.PASS:
298		case TokenType.PRINT:
299		case TokenType.PRIVATE:
300		case TokenType.PROTECTED:
301		case TokenType.PROP:
302		case TokenType.RAISE:
303		case TokenType.RAISES:
304		case TokenType.REF:
305		case TokenType.REQUIRES:
306		case TokenType.RETURN:
307		case TokenType.SEALED:
308		case TokenType.SELF:
309		case TokenType.SET:
310		case TokenType.SIZEOF:
311		case TokenType.STATIC:
312		case TokenType.STRUCT:
313		case TokenType.SUPER:
314		case TokenType.TO:
315		case TokenType.TRUE:
316		case TokenType.TRY:
317		case TokenType.TYPEOF:
318		case TokenType.UNOWNED:
319		case TokenType.USES:
320		case TokenType.VAR:
321		case TokenType.VIRTUAL:
322		case TokenType.VOID:
323		case TokenType.VOLATILE:
324		case TokenType.WEAK:
325		case TokenType.WHEN:
326		case TokenType.WHILE:
327		case TokenType.YIELD:
328			next ();
329			return;
330		case TokenType.INTEGER_LITERAL:
331		case TokenType.REAL_LITERAL:
332			// also accept integer and real literals
333			// as long as they contain at least one character
334			// and no decimal point
335			// for example, 2D and 3D
336			string id = get_current_string ();
337			if (id[id.length - 1].isalpha () && !("." in id)) {
338				next ();
339				return;
340			}
341			break;
342		default:
343			break;
344		}
345
346		throw new ParseError.SYNTAX ("expected identifier");
347	}
348
349	string parse_identifier () throws ParseError {
350		skip_identifier ();
351		return get_last_string ();
352	}
353
354	Expression parse_literal () throws ParseError {
355		var begin = get_location ();
356
357		switch (current ()) {
358		case TokenType.TRUE:
359			next ();
360			return new BooleanLiteral (true, get_src (begin));
361		case TokenType.FALSE:
362			next ();
363			return new BooleanLiteral (false, get_src (begin));
364		case TokenType.INTEGER_LITERAL:
365			next ();
366			return new IntegerLiteral (get_last_string (), get_src (begin));
367		case TokenType.REAL_LITERAL:
368			next ();
369			return new RealLiteral (get_last_string (), get_src (begin));
370		case TokenType.CHARACTER_LITERAL:
371			next ();
372			// FIXME validate and unescape here and just pass unichar to CharacterLiteral
373			var lit = new CharacterLiteral (get_last_string (), get_src (begin));
374			if (lit.error) {
375				Report.error (lit.source_reference, "invalid character literal");
376			}
377			return lit;
378		case TokenType.REGEX_LITERAL:
379			next ();
380			string match_part = get_last_string ();
381			SourceReference src_begin = get_src (begin);
382			expect (TokenType.CLOSE_REGEX_LITERAL);
383			string close_token = get_last_string ();
384			return new RegexLiteral ("%s/%s".printf (close_token, match_part), src_begin);
385		case TokenType.STRING_LITERAL:
386			next ();
387			return new StringLiteral (get_last_string (), get_src (begin));
388		case TokenType.TEMPLATE_STRING_LITERAL:
389			next ();
390			return new StringLiteral ("\"%s\"".printf (get_last_string ()), get_src (begin));
391		case TokenType.VERBATIM_STRING_LITERAL:
392			next ();
393			string raw_string = get_last_string ();
394			string escaped_string = raw_string.substring (3, raw_string.length - 6).escape ("");
395			return new StringLiteral ("\"%s\"".printf (escaped_string), get_src (begin));
396		case TokenType.NULL:
397			next ();
398			return new NullLiteral (get_src (begin));
399		default:
400			throw new ParseError.SYNTAX ("expected literal");
401		}
402	}
403
404	public void parse_file (SourceFile source_file) {
405		var has_global_context = (context != null);
406		if (!has_global_context) {
407			context = source_file.context;
408		}
409
410		scanner = new Scanner (source_file);
411		scanner.parse_file_comments ();
412		scanner.indent_spaces = 0;
413		index = -1;
414		size = 0;
415
416		next ();
417
418		try {
419			var begin = get_location ();
420			/* see if there is an indent attribute */
421			if (accept (TokenType.OPEN_BRACKET)) {
422				var id = parse_identifier ();
423				if (id == "indent") {
424					expect (TokenType.ASSIGN);
425					expect (TokenType.INTEGER_LITERAL);
426					scanner.indent_spaces = int.parse (get_last_string());
427					expect (TokenType.CLOSE_BRACKET);
428					expect (TokenType.EOL);
429				} else {
430					rollback (begin);
431				}
432			}
433
434			parse_using_directives (context.root);
435			parse_declarations (context.root, true);
436		} catch (ParseError e) {
437			report_parse_error (e);
438		}
439
440		scanner = null;
441		if (!has_global_context) {
442			context = null;
443		}
444	}
445
446	void skip_symbol_name () throws ParseError {
447		do {
448			skip_identifier ();
449		} while (accept (TokenType.DOT));
450	}
451
452	UnresolvedSymbol parse_symbol_name () throws ParseError {
453		var begin = get_location ();
454		UnresolvedSymbol sym = null;
455		do {
456			string name = parse_identifier ();
457			sym = new UnresolvedSymbol (sym, name, get_src (begin));
458		} while (accept (TokenType.DOT));
459		return sym;
460	}
461
462	void skip_type () throws ParseError {
463
464		accept (TokenType.DYNAMIC);
465		accept (TokenType.OWNED);
466		accept (TokenType.UNOWNED);
467		accept (TokenType.WEAK);
468
469
470		if (accept (TokenType.ARRAY) || accept (TokenType.LIST) || accept (TokenType.DICT)) {
471			accept (TokenType.OF);
472		}
473
474		if (accept (TokenType.VOID)) {
475		} else {
476			skip_symbol_name ();
477			skip_type_argument_list ();
478		}
479
480		while (accept (TokenType.OPEN_BRACKET)) {
481			do {
482				if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
483					parse_expression ();
484				}
485			} while (accept (TokenType.COMMA));
486			expect (TokenType.CLOSE_BRACKET);
487		}
488		accept (TokenType.OP_NEG);
489		accept (TokenType.INTERR);
490	}
491
492
493	Expression parse_regex_literal () throws ParseError {
494		expect (TokenType.OPEN_REGEX_LITERAL);
495
496		var expr = parse_literal ();
497
498		return expr;
499	}
500
501	DataType parse_type (bool owned_by_default, bool can_weak_ref) throws ParseError {
502		var begin = get_location ();
503
504		List<DataType> type_arg_list = null;
505		UnresolvedSymbol sym = null;
506
507		bool is_dynamic = accept (TokenType.DYNAMIC);
508		bool value_owned = owned_by_default;
509
510		if (owned_by_default) {
511			if (accept (TokenType.UNOWNED)) {
512				value_owned = false;
513			} else if (accept (TokenType.WEAK)) {
514				if (!can_weak_ref && !context.deprecated) {
515					Report.warning (get_src (begin), "deprecated syntax, use `unowned` modifier");
516				}
517				value_owned = false;
518			}
519		} else {
520			value_owned = accept (TokenType.OWNED);
521		}
522
523		/* handle arrays */
524		bool is_array = false;
525
526		if (accept (TokenType.ARRAY)) {
527			expect (TokenType.OF);
528			is_array = true;
529		}
530
531		/* handle lists */
532		bool is_list = false;
533
534		if (accept (TokenType.LIST)) {
535			expect (TokenType.OF);
536			prev ();
537			is_list = true;
538		}
539
540		/* handle dicts */
541		bool is_dict = false;
542
543		if (accept (TokenType.DICT)) {
544			expect (TokenType.OF);
545			prev ();
546			is_dict = true;
547		}
548
549		DataType type;
550
551		if (!is_dynamic && value_owned == owned_by_default && accept (TokenType.VOID)) {
552			type = new VoidType (get_src (begin));
553		} else {
554
555			if (is_list) {
556				var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
557				sym = new UnresolvedSymbol (sym_parent, "ArrayList", get_src (begin));
558			} else if (is_dict) {
559				var sym_parent = new UnresolvedSymbol (null, "Gee", get_src (begin));
560				sym = new UnresolvedSymbol (sym_parent, "HashMap", get_src (begin));
561			} else {
562				sym = parse_symbol_name ();
563			}
564
565			type_arg_list = parse_type_argument_list (false);
566
567			type = new UnresolvedType.from_symbol (sym, get_src (begin));
568			if (type_arg_list != null) {
569				foreach (DataType type_arg in type_arg_list) {
570					type.add_type_argument (type_arg);
571				}
572			}
573		}
574
575		while (accept (TokenType.STAR)) {
576			 type = new PointerType (type, get_src (begin));
577		}
578
579		if (!(type is PointerType)) {
580			type.nullable = accept (TokenType.INTERR);
581		}
582
583		if (is_array) {
584
585			if (!accept (TokenType.OPEN_BRACKET)) {
586				type.value_owned = true;
587				type = new ArrayType (type, 1, get_src (begin));
588				type.nullable = accept (TokenType.INTERR);
589
590			} else {
591				prev ();
592
593				while (accept (TokenType.OPEN_BRACKET))	{
594					bool invalid_array = false;
595					int array_rank = 0;
596					do {
597						array_rank++;
598						// required for decision between expression and declaration statement
599						if (current () != TokenType.COMMA && current () != TokenType.CLOSE_BRACKET) {
600							parse_expression ();
601							// only used for parsing, reject use as real type
602							invalid_array = true;
603						}
604					} while (accept (TokenType.COMMA));
605					expect (TokenType.CLOSE_BRACKET);
606
607					type.value_owned = true;
608					var array_type = new ArrayType (type, array_rank, get_src (begin));
609					array_type.nullable = accept (TokenType.INTERR);
610
611					array_type.invalid_syntax = invalid_array;
612
613					type = array_type;
614				}
615			}
616		}
617
618		if (type is PointerType) {
619			value_owned = false;
620		}
621
622		type.is_dynamic = is_dynamic;
623		type.value_owned = value_owned;
624		return type;
625	}
626
627	DataType? parse_inline_array_type (DataType? type) throws ParseError {
628		var begin = get_location ();
629
630		// inline-allocated array
631		if (type != null && accept (TokenType.OPEN_BRACKET)) {
632			Expression array_length = null;
633
634			if (current () != TokenType.CLOSE_BRACKET) {
635				array_length = parse_expression ();
636 			}
637			expect (TokenType.CLOSE_BRACKET);
638
639			var array_type = new ArrayType (type, 1, get_src (begin));
640			array_type.inline_allocated = true;
641			if (array_length != null) {
642				array_type.fixed_length = true;
643				array_type.length = array_length;
644			}
645			array_type.value_owned = type.value_owned;
646			return array_type;
647		}
648		return type;
649	}
650
651
652	List<Expression> parse_argument_list () throws ParseError {
653		var list = new ArrayList<Expression> ();
654		if (current () != TokenType.CLOSE_PARENS) {
655			do {
656				list.add (parse_argument ());
657			} while (accept (TokenType.COMMA));
658		}
659		return list;
660	}
661
662	Expression parse_argument () throws ParseError {
663		var begin = get_location ();
664
665		if (accept (TokenType.REF)) {
666			var inner = parse_expression ();
667			return new UnaryExpression (UnaryOperator.REF, inner, get_src (begin));
668		} else if (accept (TokenType.OUT)) {
669			var inner = parse_expression ();
670			return new UnaryExpression (UnaryOperator.OUT, inner, get_src (begin));
671		} else {
672			var expr = parse_expression ();
673			var ma = expr as MemberAccess;
674			if (ma != null && ma.inner == null && accept (TokenType.COLON)) {
675				// named argument
676				expr = parse_expression ();
677				return new NamedArgument (ma.member_name, expr, get_src (begin));
678			} else {
679				return expr;
680			}
681
682		}
683	}
684
685	Expression parse_primary_expression () throws ParseError {
686		var begin = get_location ();
687
688		Expression expr;
689
690		switch (current ()) {
691		case TokenType.TRUE:
692		case TokenType.FALSE:
693		case TokenType.INTEGER_LITERAL:
694		case TokenType.REAL_LITERAL:
695		case TokenType.CHARACTER_LITERAL:
696		case TokenType.REGEX_LITERAL:
697		case TokenType.STRING_LITERAL:
698		case TokenType.TEMPLATE_STRING_LITERAL:
699		case TokenType.VERBATIM_STRING_LITERAL:
700		case TokenType.NULL:
701			expr = parse_literal ();
702			break;
703		case TokenType.ASSERT:
704			return parse_assert_expression ();
705		case TokenType.OPEN_BRACE:
706			expr = parse_initializer ();
707			break;
708		case TokenType.OPEN_PARENS:
709			expr = parse_tuple ();
710			break;
711		case TokenType.OPEN_REGEX_LITERAL:
712			expr = parse_regex_literal ();
713			break;
714		case TokenType.OPEN_TEMPLATE:
715			expr = parse_template ();
716			break;
717		case TokenType.SELF:
718			expr = parse_this_access ();
719			break;
720		case TokenType.SUPER:
721			expr = parse_base_access ();
722			break;
723		case TokenType.NEW:
724			expr = parse_object_or_array_creation_expression ();
725			break;
726		case TokenType.PRINT:
727			return parse_print_expression ();
728		case TokenType.SIZEOF:
729			expr = parse_sizeof_expression ();
730			break;
731		case TokenType.TYPEOF:
732			expr = parse_typeof_expression ();
733			break;
734		case TokenType.YIELD:
735			expr = parse_yield_expression ();
736			break;
737		default:
738			expr = parse_simple_name ();
739			break;
740		}
741
742		// process primary expressions that start with an inner primary expression
743		bool found = true;
744		while (found) {
745			switch (current ()) {
746			case TokenType.DOT:
747				expr = parse_member_access (begin, expr);
748				break;
749			case TokenType.OP_PTR:
750				expr = parse_pointer_member_access (begin, expr);
751				break;
752			case TokenType.OPEN_PARENS:
753				expr = parse_method_call (begin, expr);
754				break;
755			case TokenType.OPEN_BRACKET:
756				expr = parse_element_access (begin, expr);
757				break;
758			case TokenType.OP_INC:
759				expr = parse_post_increment_expression (begin, expr);
760				break;
761			case TokenType.OP_DEC:
762				expr = parse_post_decrement_expression (begin, expr);
763				break;
764
765			default:
766				found = false;
767				break;
768			}
769		}
770
771		return expr;
772	}
773
774	Expression parse_simple_name () throws ParseError {
775		var begin = get_location ();
776		string id = parse_identifier ();
777		List<DataType> type_arg_list = parse_type_argument_list (true);
778		var expr = new MemberAccess (null, id, get_src (begin));
779		if (type_arg_list != null) {
780			foreach (DataType type_arg in type_arg_list) {
781				expr.add_type_argument (type_arg);
782			}
783		}
784		return expr;
785	}
786
787	Expression parse_template () throws ParseError {
788		var begin = get_location ();
789		var template = new Template ();
790
791		expect (TokenType.OPEN_TEMPLATE);
792		while (current () != TokenType.CLOSE_TEMPLATE) {
793			template.add_expression (parse_expression ());
794			expect (TokenType.COMMA);
795		}
796		expect (TokenType.CLOSE_TEMPLATE);
797
798		template.source_reference = get_src (begin);
799		return template;
800	}
801
802	Expression parse_tuple () throws ParseError {
803		expect (TokenType.OPEN_PARENS);
804		var expr_list = new ArrayList<Expression> ();
805		if (current () != TokenType.CLOSE_PARENS) {
806			do {
807				expr_list.add (parse_expression ());
808			} while (accept (TokenType.COMMA));
809		}
810		expect (TokenType.CLOSE_PARENS);
811		if (expr_list.size != 1) {
812			var tuple = new Tuple ();
813			foreach (Expression expr in expr_list) {
814				tuple.add_expression (expr);
815			}
816			return tuple;
817		}
818		return expr_list.get (0);
819	}
820
821	Expression parse_member_access (SourceLocation begin, Expression inner) throws ParseError {
822		expect (TokenType.DOT);
823		string id = parse_identifier ();
824		List<DataType> type_arg_list = parse_type_argument_list (true);
825		var expr = new MemberAccess (inner, id, get_src (begin));
826		if (type_arg_list != null) {
827			foreach (DataType type_arg in type_arg_list) {
828				expr.add_type_argument (type_arg);
829			}
830		}
831		return expr;
832	}
833
834	Expression parse_pointer_member_access (SourceLocation begin, Expression inner) throws ParseError {
835		expect (TokenType.OP_PTR);
836		string id = parse_identifier ();
837		List<DataType> type_arg_list = parse_type_argument_list (true);
838		var expr = new MemberAccess.pointer (inner, id, get_src (begin));
839		if (type_arg_list != null) {
840			foreach (DataType type_arg in type_arg_list) {
841				expr.add_type_argument (type_arg);
842			}
843		}
844		return expr;
845	}
846
847
848	List<Expression> parse_print_argument_list () throws ParseError {
849		var list = new ArrayList<Expression> ();
850		var i = 0;
851		var begin = get_location ();
852
853		if (current () != TokenType.CLOSE_PARENS) {
854			do {
855				var p_expr = parse_expression ();
856				if (i == 0) {
857					i++;
858
859					if (p_expr != null) {
860						if (p_expr is StringLiteral) {
861							var s_exp = (StringLiteral) p_expr;
862							var len = s_exp.value.length;
863
864							if (len > 2) {
865								string s = "\\n\"";
866								var st =  s_exp.value.substring (0, len-1);
867								st += s;
868								s_exp.value = st;
869							} else {
870								string s = "\"\\n\"";
871								p_expr = new StringLiteral (s, get_src (begin));
872							}
873						} else {
874							string s = "\"%s\\n\"";
875							var s_exp = new StringLiteral (s, get_src (begin));
876							list.add (s_exp);
877						}
878					}
879				}
880				list.add (p_expr);
881
882			} while (accept (TokenType.COMMA));
883		}
884		return list;
885	}
886
887	Expression parse_print_expression () throws ParseError {
888		var begin = get_location ();
889
890		expect (TokenType.PRINT);
891		bool parens = accept (TokenType.OPEN_PARENS);
892
893		var expr = new MemberAccess (null, "print", get_src (begin));
894
895		var arg_list = parse_print_argument_list ();
896
897		if (parens) {
898			expect (TokenType.CLOSE_PARENS);
899		}
900
901		var print_expr = new MethodCall (expr, get_src (begin));
902
903		foreach (Expression arg in arg_list) {
904			print_expr.add_argument (arg);
905		}
906
907		return print_expr;
908
909	}
910
911	Expression parse_assert_expression () throws ParseError {
912		var begin = get_location ();
913
914		expect (TokenType.ASSERT);
915		bool parens = accept (TokenType.OPEN_PARENS);
916
917		var expr = new MemberAccess (null, "assert", get_src (begin));
918
919		var arg_list = parse_argument_list ();
920
921		if (parens) {
922			expect (TokenType.CLOSE_PARENS);
923		}
924
925		var assert_expr = new MethodCall (expr, get_src (begin));
926
927		foreach (Expression arg in arg_list) {
928			assert_expr.add_argument (arg);
929		}
930
931		return assert_expr;
932
933	}
934
935	Expression parse_method_call (SourceLocation begin, Expression inner) throws ParseError {
936		expect (TokenType.OPEN_PARENS);
937		var arg_list = parse_argument_list ();
938		expect (TokenType.CLOSE_PARENS);
939
940		var init_list = parse_object_initializer ();
941
942		if (init_list.size > 0 && inner is MemberAccess) {
943			// struct creation expression
944			var member = (MemberAccess) inner;
945			member.creation_member = true;
946
947			var expr = new ObjectCreationExpression (member, get_src (begin));
948			expr.struct_creation = true;
949			foreach (Expression arg in arg_list) {
950				expr.add_argument (arg);
951			}
952			foreach (MemberInitializer initializer in init_list) {
953				expr.add_member_initializer (initializer);
954			}
955			return expr;
956		} else {
957			var expr = new MethodCall (inner, get_src (begin));
958			foreach (Expression arg in arg_list) {
959				expr.add_argument (arg);
960			}
961			return expr;
962		}
963	}
964
965	Expression parse_element_access (SourceLocation begin, Expression inner) throws ParseError {
966		expect (TokenType.OPEN_BRACKET);
967		var index_list = parse_expression_list ();
968		Expression? stop = null;
969		if (index_list.size == 1 && accept (TokenType.COLON)) {
970			// slice expression
971			stop = parse_expression ();
972		}
973		expect (TokenType.CLOSE_BRACKET);
974
975		if (stop == null) {
976			var expr = new ElementAccess (inner, get_src (begin));
977			foreach (Expression index in index_list) {
978				expr.append_index (index);
979			}
980			return expr;
981		} else {
982			return new SliceExpression (inner, index_list[0], stop, get_src (begin));
983		}
984	}
985
986	List<Expression> parse_expression_list () throws ParseError {
987		var list = new ArrayList<Expression> ();
988		do {
989			list.add (parse_expression ());
990		} while (accept (TokenType.COMMA));
991		return list;
992	}
993
994	Expression parse_this_access () throws ParseError {
995		var begin = get_location ();
996		expect (TokenType.SELF);
997		return new MemberAccess (null, "this", get_src (begin));
998	}
999
1000	Expression parse_base_access () throws ParseError {
1001		var begin = get_location ();
1002		expect (TokenType.SUPER);
1003		return new BaseAccess (get_src (begin));
1004	}
1005
1006	Expression parse_post_increment_expression (SourceLocation begin, Expression inner) throws ParseError {
1007		expect (TokenType.OP_INC);
1008		return new PostfixExpression (inner, true, get_src (begin));
1009	}
1010
1011	Expression parse_post_decrement_expression (SourceLocation begin, Expression inner) throws ParseError {
1012		expect (TokenType.OP_DEC);
1013		return new PostfixExpression (inner, false, get_src (begin));
1014	}
1015
1016	Expression parse_object_or_array_creation_expression () throws ParseError {
1017		var begin = get_location ();
1018		expect (TokenType.NEW);
1019
1020		if (accept (TokenType.ARRAY)) {
1021			expect (TokenType.OF);
1022			var mtype = parse_type (true, false);
1023			var expr = parse_array_creation_expression (begin, mtype);
1024			return expr;
1025		}
1026
1027		if (accept (TokenType.LIST)) {
1028			expect (TokenType.OF);
1029			var mtype = parse_type (true, false);
1030			var expr = parse_list_creation_expression (begin, mtype);
1031			return expr;
1032		}
1033
1034		if (accept (TokenType.DICT)) {
1035			expect (TokenType.OF);
1036			var mtype1 = parse_type (true, false);
1037			expect (TokenType.COMMA);
1038			var mtype2 = parse_type (true, false);
1039			var expr = parse_dict_creation_expression (begin, mtype1, mtype2);
1040			return expr;
1041		}
1042
1043
1044		var member = parse_member_name ();
1045		var expr = parse_object_creation_expression (begin, member);
1046		return expr;
1047
1048	}
1049
1050	Expression parse_object_creation_expression (SourceLocation begin, MemberAccess member) throws ParseError {
1051		member.creation_member = true;
1052		List<Expression> arg_list;
1053		if (accept (TokenType.OPEN_PARENS)) {
1054			arg_list = parse_argument_list ();
1055			expect (TokenType.CLOSE_PARENS);
1056		} else {
1057			arg_list = new ArrayList<Expression> ();
1058		}
1059
1060		var init_list = parse_object_initializer ();
1061
1062		var expr = new ObjectCreationExpression (member, get_src (begin));
1063		foreach (Expression arg in arg_list) {
1064			expr.add_argument (arg);
1065		}
1066		foreach (MemberInitializer initializer in init_list) {
1067			expr.add_member_initializer (initializer);
1068		}
1069		return expr;
1070	}
1071
1072	Expression parse_array_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1073		bool size_specified = false;
1074		List<Expression> size_specifier_list = null;
1075		bool first = true;
1076		DataType etype = element_type.copy ();
1077
1078		var has_bracket = accept (TokenType.OPEN_BRACKET);
1079
1080		do {
1081			if (!first) {
1082 				// array of arrays: new T[][42]
1083
1084 				if (size_specified) {
1085					throw new ParseError.SYNTAX ("size of inner arrays must not be specified in array creation expression");
1086				}
1087
1088				etype = new ArrayType (etype, size_specifier_list.size, etype.source_reference);
1089			} else {
1090				first = false;
1091			}
1092
1093			size_specifier_list = new ArrayList<Expression> ();
1094			do {
1095				Expression size = null;
1096				if (has_bracket && current () != TokenType.CLOSE_BRACKET && current () != TokenType.COMMA) {
1097					size = parse_expression ();
1098					size_specified = true;
1099				}
1100				size_specifier_list.add (size);
1101			} while (accept (TokenType.COMMA));
1102
1103			if (has_bracket) {
1104				expect (TokenType.CLOSE_BRACKET);
1105			}
1106		} while (accept (TokenType.OPEN_BRACKET));
1107
1108		InitializerList initializer = null;
1109		if (accept (TokenType.ASSIGN)) {
1110			initializer = parse_initializer ();
1111		}
1112
1113		var expr = new ArrayCreationExpression (etype, size_specifier_list.size, initializer, get_src (begin));
1114		if (size_specified) {
1115			foreach (Expression size in size_specifier_list) {
1116				expr.append_size (size);
1117			}
1118		}
1119		return expr;
1120	}
1121
1122
1123	Expression parse_list_creation_expression (SourceLocation begin, DataType element_type) throws ParseError {
1124
1125		MemberAccess list_member = null, parent_member = null;
1126
1127		parent_member = new MemberAccess (null, "Gee", get_src (begin));
1128		list_member = new MemberAccess (parent_member, "ArrayList", get_src (begin));
1129		list_member.add_type_argument (element_type);
1130
1131		list_member.creation_member = true;
1132
1133		var expr = new ObjectCreationExpression (list_member, get_src (begin));
1134		return expr;
1135	}
1136
1137	Expression parse_dict_creation_expression (SourceLocation begin, DataType key_type, DataType value_type) throws ParseError {
1138
1139		MemberAccess dict_member = null, parent_member = null;
1140
1141		parent_member = new MemberAccess (null, "Gee", get_src (begin));
1142		dict_member = new MemberAccess (parent_member, "HashMap", get_src (begin));
1143		dict_member.add_type_argument (key_type);
1144		dict_member.add_type_argument (value_type);
1145
1146		dict_member.creation_member = true;
1147
1148		var expr = new ObjectCreationExpression (dict_member, get_src (begin));
1149
1150		return expr;
1151	}
1152
1153
1154	List<MemberInitializer> parse_object_initializer () throws ParseError {
1155		var list = new ArrayList<MemberInitializer> ();
1156		if (accept (TokenType.OPEN_BRACE)) {
1157			do {
1158				list.add (parse_member_initializer ());
1159			} while (accept (TokenType.COMMA));
1160			expect (TokenType.CLOSE_BRACE);
1161		}
1162		return list;
1163	}
1164
1165	MemberInitializer parse_member_initializer () throws ParseError {
1166		var begin = get_location ();
1167		string id = parse_identifier ();
1168		expect (TokenType.ASSIGN);
1169		var expr = parse_expression ();
1170
1171		return new MemberInitializer (id, expr, get_src (begin));
1172	}
1173
1174	Expression parse_yield_expression () throws ParseError {
1175		expect (TokenType.YIELD);
1176
1177		var expr = parse_expression ();
1178
1179		unowned MethodCall? call = expr as MethodCall;
1180		unowned ObjectCreationExpression? object_creation = expr as ObjectCreationExpression;
1181		if (call == null && object_creation == null) {
1182			Report.error (expr.source_reference, "syntax error, expected method call");
1183			throw new ParseError.SYNTAX ("expected method call");
1184		}
1185
1186		if (call != null) {
1187			call.is_yield_expression = true;
1188		} else if (object_creation != null) {
1189			object_creation.is_yield_expression = true;
1190		}
1191
1192		return expr;
1193	}
1194
1195	Expression parse_sizeof_expression () throws ParseError {
1196		var begin = get_location ();
1197		expect (TokenType.SIZEOF);
1198		expect (TokenType.OPEN_PARENS);
1199		var type = parse_type (true, false);
1200		expect (TokenType.CLOSE_PARENS);
1201
1202		return new SizeofExpression (type, get_src (begin));
1203	}
1204
1205	Expression parse_typeof_expression () throws ParseError {
1206		var begin = get_location ();
1207		expect (TokenType.TYPEOF);
1208		expect (TokenType.OPEN_PARENS);
1209		var type = parse_type (true, false);
1210		expect (TokenType.CLOSE_PARENS);
1211
1212		return new TypeofExpression (type, get_src (begin));
1213	}
1214
1215	UnaryOperator get_unary_operator (TokenType token_type) {
1216		switch (token_type) {
1217		case TokenType.PLUS:   return UnaryOperator.PLUS;
1218		case TokenType.MINUS:  return UnaryOperator.MINUS;
1219		case TokenType.OP_NEG: return UnaryOperator.LOGICAL_NEGATION;
1220		case TokenType.TILDE:  return UnaryOperator.BITWISE_COMPLEMENT;
1221		case TokenType.OP_INC: return UnaryOperator.INCREMENT;
1222		case TokenType.OP_DEC: return UnaryOperator.DECREMENT;
1223		default:			   return UnaryOperator.NONE;
1224		}
1225	}
1226
1227	Expression parse_unary_expression () throws ParseError {
1228		var begin = get_location ();
1229		var operator = get_unary_operator (current ());
1230		if (operator != UnaryOperator.NONE) {
1231			next ();
1232			var op = parse_unary_expression ();
1233			return new UnaryExpression (operator, op, get_src (begin));
1234		}
1235		switch (current ()) {
1236		case TokenType.OPEN_PARENS:
1237			next ();
1238			switch (current ()) {
1239			case TokenType.OWNED:
1240				// (owned) foo
1241				next ();
1242				if (accept (TokenType.CLOSE_PARENS)) {
1243					var op = parse_unary_expression ();
1244					return new ReferenceTransferExpression (op, get_src (begin));
1245				}
1246				break;
1247			case TokenType.VOID:
1248			case TokenType.DYNAMIC:
1249			case TokenType.IDENTIFIER:
1250			case TokenType.ARRAY:
1251			case TokenType.LIST:
1252			case TokenType.DICT:
1253				var type = parse_type (true, false);
1254				if (accept (TokenType.CLOSE_PARENS)) {
1255					// check follower to decide whether to create cast expression
1256					switch (current ()) {
1257					case TokenType.OP_NEG:
1258					case TokenType.TILDE:
1259					case TokenType.OPEN_PARENS:
1260					case TokenType.TRUE:
1261					case TokenType.FALSE:
1262					case TokenType.INTEGER_LITERAL:
1263					case TokenType.REAL_LITERAL:
1264					case TokenType.CHARACTER_LITERAL:
1265					case TokenType.REGEX_LITERAL:
1266					case TokenType.STRING_LITERAL:
1267					case TokenType.TEMPLATE_STRING_LITERAL:
1268					case TokenType.VERBATIM_STRING_LITERAL:
1269					case TokenType.NULL:
1270					case TokenType.SELF:
1271					case TokenType.SUPER:
1272					case TokenType.NEW:
1273					case TokenType.SIZEOF:
1274					case TokenType.TYPEOF:
1275					case TokenType.IDENTIFIER:
1276					case TokenType.PARAMS:
1277					case TokenType.YIELD:
1278						var inner = parse_unary_expression ();
1279						return new CastExpression (inner, type, get_src (begin));
1280					default:
1281						break;
1282					}
1283				}
1284				break;
1285			case TokenType.OP_NEG:
1286				next ();
1287				if (accept (TokenType.CLOSE_PARENS)) {
1288					// (!) non-null cast
1289					var inner = parse_unary_expression ();
1290					return new CastExpression.non_null (inner, get_src (begin));
1291				}
1292				break;
1293
1294			default:
1295				break;
1296			}
1297			// no cast expression
1298			rollback (begin);
1299			break;
1300		case TokenType.STAR:
1301			next ();
1302			var op = parse_unary_expression ();
1303			return new PointerIndirection (op, get_src (begin));
1304		case TokenType.BITWISE_AND:
1305			next ();
1306			var op = parse_unary_expression ();
1307			return new AddressofExpression (op, get_src (begin));
1308		default:
1309			break;
1310		}
1311
1312		var expr = parse_primary_expression ();
1313		return expr;
1314	}
1315
1316	BinaryOperator get_binary_operator (TokenType token_type) {
1317		switch (token_type) {
1318		case TokenType.STAR:	return BinaryOperator.MUL;
1319		case TokenType.DIV:	 return BinaryOperator.DIV;
1320		case TokenType.PERCENT: return BinaryOperator.MOD;
1321		case TokenType.PLUS:	return BinaryOperator.PLUS;
1322		case TokenType.MINUS:   return BinaryOperator.MINUS;
1323		case TokenType.OP_LT:   return BinaryOperator.LESS_THAN;
1324		case TokenType.OP_GT:   return BinaryOperator.GREATER_THAN;
1325		case TokenType.OP_LE:   return BinaryOperator.LESS_THAN_OR_EQUAL;
1326		case TokenType.OP_GE:   return BinaryOperator.GREATER_THAN_OR_EQUAL;
1327		case TokenType.OP_EQ:   return BinaryOperator.EQUALITY;
1328		case TokenType.IS:
1329			next();
1330			if (current () == TokenType.OP_NEG) {
1331				prev ();
1332				return BinaryOperator.INEQUALITY;
1333			}
1334			prev ();
1335			return BinaryOperator.EQUALITY;
1336		case TokenType.OP_NE:   return BinaryOperator.INEQUALITY;
1337		default:				return BinaryOperator.NONE;
1338		}
1339	}
1340
1341	Expression parse_multiplicative_expression () throws ParseError {
1342		var begin = get_location ();
1343		var left = parse_unary_expression ();
1344		bool found = true;
1345		while (found) {
1346			var operator = get_binary_operator (current ());
1347			switch (operator) {
1348			case BinaryOperator.MUL:
1349			case BinaryOperator.DIV:
1350			case BinaryOperator.MOD:
1351				next ();
1352				var right = parse_unary_expression ();
1353				left = new BinaryExpression (operator, left, right, get_src (begin));
1354				break;
1355			default:
1356				found = false;
1357				break;
1358			}
1359		}
1360		return left;
1361	}
1362
1363	Expression parse_additive_expression () throws ParseError {
1364		var begin = get_location ();
1365		var left = parse_multiplicative_expression ();
1366		bool found = true;
1367		while (found) {
1368			var operator = get_binary_operator (current ());
1369			switch (operator) {
1370			case BinaryOperator.PLUS:
1371			case BinaryOperator.MINUS:
1372				next ();
1373				var right = parse_multiplicative_expression ();
1374				left = new BinaryExpression (operator, left, right, get_src (begin));
1375				break;
1376			default:
1377				found = false;
1378				break;
1379			}
1380		}
1381		return left;
1382	}
1383
1384	Expression parse_shift_expression () throws ParseError {
1385		var begin = get_location ();
1386		var left = parse_additive_expression ();
1387		bool found = true;
1388		while (found) {
1389			switch (current ()) {
1390			case TokenType.OP_SHIFT_LEFT:
1391				next ();
1392				var right = parse_additive_expression ();
1393				left = new BinaryExpression (BinaryOperator.SHIFT_LEFT, left, right, get_src (begin));
1394				break;
1395			// don't use OP_SHIFT_RIGHT to support >> for nested generics
1396			case TokenType.OP_GT:
1397				char* first_gt_pos = tokens[index].begin.pos;
1398				next ();
1399				// only accept >> when there is no space between the two > signs
1400				if (current () == TokenType.OP_GT && tokens[index].begin.pos == first_gt_pos + 1) {
1401					next ();
1402					var right = parse_additive_expression ();
1403					left = new BinaryExpression (BinaryOperator.SHIFT_RIGHT, left, right, get_src (begin));
1404				} else {
1405					prev ();
1406					found = false;
1407				}
1408				break;
1409			default:
1410				found = false;
1411				break;
1412			}
1413		}
1414		return left;
1415	}
1416
1417	Expression parse_relational_expression () throws ParseError {
1418		var begin = get_location ();
1419		var left = parse_shift_expression ();
1420		bool found = true;
1421		while (found) {
1422			var operator = get_binary_operator (current ());
1423			switch (operator) {
1424			case BinaryOperator.LESS_THAN:
1425			case BinaryOperator.LESS_THAN_OR_EQUAL:
1426			case BinaryOperator.GREATER_THAN_OR_EQUAL:
1427				next ();
1428				var right = parse_shift_expression ();
1429				left = new BinaryExpression (operator, left, right, get_src (begin));
1430				break;
1431			case BinaryOperator.GREATER_THAN:
1432				next ();
1433				// ignore >> and >>= (two tokens due to generics)
1434				if (current () != TokenType.OP_GT && current () != TokenType.OP_GE) {
1435					var right = parse_shift_expression ();
1436					left = new BinaryExpression (operator, left, right, get_src (begin));
1437				} else {
1438					prev ();
1439					found = false;
1440				}
1441				break;
1442			default:
1443				switch (current ()) {
1444				case TokenType.ISA:
1445					next ();
1446					var type = parse_type (true, false);
1447					left = new TypeCheck (left, type, get_src (begin));
1448					break;
1449				case TokenType.AS:
1450					next ();
1451					var type = parse_type (true, false);
1452					left = new CastExpression.silent (left, type, get_src (begin));
1453					break;
1454				default:
1455					found = false;
1456					break;
1457				}
1458				break;
1459			}
1460		}
1461		return left;
1462	}
1463
1464	Expression parse_equality_expression () throws ParseError {
1465		var begin = get_location ();
1466		var left = parse_relational_expression ();
1467		bool found = true;
1468		while (found) {
1469			var operator = get_binary_operator (current ());
1470			switch (operator) {
1471			case BinaryOperator.INEQUALITY:
1472			case BinaryOperator.EQUALITY:
1473				if ((operator == BinaryOperator.INEQUALITY) && (current () == TokenType.IS)) {
1474					next ();
1475				}
1476				next ();
1477				var right = parse_relational_expression ();
1478				left = new BinaryExpression (operator, left, right, get_src (begin));
1479				break;
1480			default:
1481				found = false;
1482				break;
1483			}
1484		}
1485		return left;
1486	}
1487
1488	Expression parse_and_expression () throws ParseError {
1489		var begin = get_location ();
1490		var left = parse_equality_expression ();
1491		while (accept (TokenType.BITWISE_AND)) {
1492			var right = parse_equality_expression ();
1493			left = new BinaryExpression (BinaryOperator.BITWISE_AND, left, right, get_src (begin));
1494		}
1495		return left;
1496	}
1497
1498	Expression parse_exclusive_or_expression () throws ParseError {
1499		var begin = get_location ();
1500		var left = parse_and_expression ();
1501		while (accept (TokenType.CARRET)) {
1502			var right = parse_and_expression ();
1503			left = new BinaryExpression (BinaryOperator.BITWISE_XOR, left, right, get_src (begin));
1504		}
1505		return left;
1506	}
1507
1508	Expression parse_inclusive_or_expression () throws ParseError {
1509		var begin = get_location ();
1510		var left = parse_exclusive_or_expression ();
1511		while (accept (TokenType.BITWISE_OR)) {
1512			var right = parse_exclusive_or_expression ();
1513			left = new BinaryExpression (BinaryOperator.BITWISE_OR, left, right, get_src (begin));
1514		}
1515		return left;
1516	}
1517
1518	Expression parse_in_expression () throws ParseError {
1519		var begin = get_location ();
1520		var left = parse_inclusive_or_expression ();
1521		while (accept (TokenType.IN)) {
1522			var right = parse_inclusive_or_expression ();
1523			left = new BinaryExpression (BinaryOperator.IN, left, right, get_src (begin));
1524		}
1525		return left;
1526	}
1527
1528	Expression parse_conditional_and_expression () throws ParseError {
1529		var begin = get_location ();
1530		var left = parse_in_expression ();
1531		while (accept (TokenType.OP_AND)) {
1532			var right = parse_in_expression ();
1533			left = new BinaryExpression (BinaryOperator.AND, left, right, get_src (begin));
1534		}
1535		return left;
1536	}
1537
1538	Expression parse_conditional_or_expression () throws ParseError {
1539		var begin = get_location ();
1540		var left = parse_conditional_and_expression ();
1541		while (accept (TokenType.OP_OR)) {
1542			var right = parse_conditional_and_expression ();
1543			left = new BinaryExpression (BinaryOperator.OR, left, right, get_src (begin));
1544		}
1545		return left;
1546	}
1547
1548	Expression parse_conditional_expression () throws ParseError {
1549		var begin = get_location ();
1550		var condition = parse_conditional_or_expression ();
1551		if (accept (TokenType.INTERR)) {
1552			var true_expr = parse_expression ();
1553			expect (TokenType.COLON);
1554			var false_expr = parse_expression ();
1555			return new ConditionalExpression (condition, true_expr, false_expr, get_src (begin));
1556		} else {
1557			return condition;
1558		}
1559	}
1560
1561	Parameter parse_lambda_parameter () throws ParseError {
1562		var begin = get_location ();
1563		var direction = ParameterDirection.IN;
1564		if (accept (TokenType.OUT)) {
1565			direction = ParameterDirection.OUT;
1566		} else if (accept (TokenType.REF)) {
1567			direction = ParameterDirection.REF;
1568		}
1569
1570		string id = parse_identifier ();
1571
1572		var param = new Parameter (id, null, get_src (begin));
1573		param.direction = direction;
1574		return param;
1575	}
1576
1577	Expression parse_lambda_expression () throws ParseError {
1578		var begin = get_location ();
1579		List<Parameter> params = new ArrayList<Parameter> ();
1580
1581		expect (TokenType.DEF);
1582
1583		if (accept (TokenType.OPEN_PARENS)) {
1584			if (current () != TokenType.CLOSE_PARENS) {
1585				do {
1586					params.add (parse_lambda_parameter ());
1587				} while (accept (TokenType.COMMA));
1588			}
1589			expect (TokenType.CLOSE_PARENS);
1590		} else {
1591			params.add (parse_lambda_parameter ());
1592		}
1593
1594		LambdaExpression lambda;
1595
1596		if (accept_block ()) {
1597			var block = parse_block ();
1598			lambda = new LambdaExpression.with_statement_body (block, get_src (begin));
1599		} else {
1600			var expr = parse_expression ();
1601			lambda = new LambdaExpression (expr, get_src (begin));
1602			expect_terminator ();
1603
1604		}
1605
1606
1607		foreach (var param in params) {
1608			lambda.add_parameter (param);
1609		}
1610		return lambda;
1611	}
1612
1613	AssignmentOperator get_assignment_operator (TokenType token_type) {
1614		switch (token_type) {
1615		case TokenType.ASSIGN:				return AssignmentOperator.SIMPLE;
1616		case TokenType.ASSIGN_ADD:			return AssignmentOperator.ADD;
1617		case TokenType.ASSIGN_SUB:			return AssignmentOperator.SUB;
1618		case TokenType.ASSIGN_BITWISE_OR:	return AssignmentOperator.BITWISE_OR;
1619		case TokenType.ASSIGN_BITWISE_AND:	return AssignmentOperator.BITWISE_AND;
1620		case TokenType.ASSIGN_BITWISE_XOR:	return AssignmentOperator.BITWISE_XOR;
1621		case TokenType.ASSIGN_DIV:			return AssignmentOperator.DIV;
1622		case TokenType.ASSIGN_MUL:			return AssignmentOperator.MUL;
1623		case TokenType.ASSIGN_PERCENT:		return AssignmentOperator.PERCENT;
1624		case TokenType.ASSIGN_SHIFT_LEFT:	return AssignmentOperator.SHIFT_LEFT;
1625		default:							return AssignmentOperator.NONE;
1626		}
1627	}
1628
1629	Expression parse_expression_with_terminator () throws ParseError {
1630		var expr = parse_expression ();
1631		if (current_expr_is_lambda) {
1632			current_expr_is_lambda = false;
1633		} else {
1634			expect_terminator ();
1635		}
1636		return expr;
1637	}
1638
1639	Expression parse_expression () throws ParseError {
1640		if (current () == TokenType.DEF) {
1641			var lambda = parse_lambda_expression ();
1642			current_expr_is_lambda = true;
1643			return lambda;
1644		} else {
1645			current_expr_is_lambda = false;
1646		}
1647
1648		var begin = get_location ();
1649		Expression expr = parse_conditional_expression ();
1650
1651		while (true) {
1652			var operator = get_assignment_operator (current ());
1653			if (operator != AssignmentOperator.NONE) {
1654				next ();
1655				var rhs = parse_expression ();
1656				expr = new Assignment (expr, rhs, operator, get_src (begin));
1657			} else if (current () == TokenType.OP_GT) { // >>=
1658				char* first_gt_pos = tokens[index].begin.pos;
1659				next ();
1660				// only accept >>= when there is no space between the two > signs
1661				if (current () == TokenType.OP_GE && tokens[index].begin.pos == first_gt_pos + 1) {
1662					next ();
1663					var rhs = parse_expression ();
1664					expr = new Assignment (expr, rhs, AssignmentOperator.SHIFT_RIGHT, get_src (begin));
1665				} else {
1666					prev ();
1667					break;
1668				}
1669			} else {
1670				break;
1671			}
1672		}
1673
1674		return expr;
1675	}
1676
1677
1678	Statement get_for_statement_type () throws ParseError {
1679
1680		var begin = get_location ();
1681		bool is_foreach = false;
1682
1683		while (current () != TokenType.EOL && current () != TokenType.DO) {
1684			next ();
1685			if (accept (TokenType.IN)) {
1686				is_foreach = true;
1687				break;
1688			}
1689		}
1690
1691		rollback (begin);
1692
1693		if (is_foreach) {
1694			return parse_foreach_statement ();
1695		} else {
1696			return parse_for_statement ();
1697		}
1698
1699	}
1700
1701	void parse_statements (Block block) throws ParseError {
1702		while (current () != TokenType.DEDENT
1703			   && current () != TokenType.WHEN
1704			   && current () != TokenType.DEFAULT) {
1705			try {
1706				Statement stmt = null;
1707				bool is_decl = false;
1708				comment = scanner.pop_comment ();
1709				switch (current ()) {
1710
1711				/* skip over requires and ensures as we handled them in method declaration */
1712				case TokenType.REQUIRES:
1713				case TokenType.ENSURES:
1714					var begin = get_location ();
1715					next ();
1716
1717					if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
1718						while (current () != TokenType.DEDENT) {
1719							next();
1720						}
1721
1722						expect (TokenType.DEDENT);
1723					} else {
1724						while (current () != TokenType.EOL) {
1725							next();
1726						}
1727
1728						expect (TokenType.EOL);
1729					}
1730
1731					stmt =  new EmptyStatement (get_src (begin));
1732					break;
1733
1734
1735				case TokenType.INDENT:
1736					stmt = parse_block ();
1737					break;
1738				case TokenType.SEMICOLON:
1739				case TokenType.PASS:
1740					stmt = parse_empty_statement ();
1741					break;
1742				case TokenType.PRINT:
1743				case TokenType.ASSERT:
1744					stmt = parse_expression_statement ();
1745					break;
1746				case TokenType.IF:
1747					stmt = parse_if_statement ();
1748					break;
1749				case TokenType.CASE:
1750					stmt = parse_switch_statement ();
1751					break;
1752				case TokenType.WHILE:
1753					stmt = parse_while_statement ();
1754					break;
1755				case TokenType.DO:
1756					stmt = parse_do_statement ();
1757					break;
1758				case TokenType.FOR:
1759					stmt = get_for_statement_type ();
1760					break;
1761				case TokenType.BREAK:
1762					stmt = parse_break_statement ();
1763					break;
1764				case TokenType.CONTINUE:
1765					stmt = parse_continue_statement ();
1766					break;
1767				case TokenType.RETURN:
1768					stmt = parse_return_statement ();
1769					break;
1770				case TokenType.RAISE:
1771					stmt = parse_throw_statement ();
1772					break;
1773				case TokenType.TRY:
1774					stmt = parse_try_statement ();
1775					break;
1776				case TokenType.LOCK:
1777					stmt = parse_lock_statement ();
1778					break;
1779				case TokenType.DELETE:
1780					stmt = parse_delete_statement ();
1781					break;
1782				case TokenType.VAR:
1783					is_decl = true;
1784					parse_type_inference_declaration (block);
1785					break;
1786				case TokenType.YIELD:
1787					stmt = parse_yield_statement ();
1788					break;
1789
1790				case TokenType.OP_INC:
1791				case TokenType.OP_DEC:
1792				case TokenType.SUPER:
1793				case TokenType.SELF:
1794				case TokenType.OPEN_PARENS:
1795				case TokenType.STAR:
1796				case TokenType.NEW:
1797					stmt = parse_expression_statement ();
1798					break;
1799				default:
1800					bool is_expr = is_expression ();
1801					if (is_expr) {
1802						stmt = parse_expression_statement ();
1803					} else {
1804						is_decl = true;
1805						parse_local_variable_declarations (block);
1806					}
1807					break;
1808				}
1809
1810				if (!is_decl) {
1811					block.add_statement (stmt);
1812				}
1813			} catch (ParseError e) {
1814				report_parse_error (e);
1815				if (recover () != RecoveryState.STATEMENT_BEGIN) {
1816					// beginning of next declaration or end of file reached
1817					// return what we have so far
1818					break;
1819				}
1820			}
1821		}
1822	}
1823
1824	bool is_expression () throws ParseError {
1825		var begin = get_location ();
1826
1827		// decide between declaration and expression statement
1828		skip_type ();
1829		switch (current ()) {
1830		// invocation expression
1831		case TokenType.OPEN_PARENS:
1832		// postfix increment
1833		case TokenType.OP_INC:
1834		// postfix decrement
1835		case TokenType.OP_DEC:
1836		// assignments
1837		case TokenType.ASSIGN:
1838		case TokenType.ASSIGN_ADD:
1839		case TokenType.ASSIGN_BITWISE_AND:
1840		case TokenType.ASSIGN_BITWISE_OR:
1841		case TokenType.ASSIGN_BITWISE_XOR:
1842		case TokenType.ASSIGN_DIV:
1843		case TokenType.ASSIGN_MUL:
1844		case TokenType.ASSIGN_PERCENT:
1845		case TokenType.ASSIGN_SHIFT_LEFT:
1846		case TokenType.ASSIGN_SUB:
1847		case TokenType.OP_GT: // >>=
1848		// member access
1849		case TokenType.DOT:
1850		// pointer member access
1851		case TokenType.OP_PTR:
1852			rollback (begin);
1853			return true;
1854		default:
1855			rollback (begin);
1856			return false;
1857		}
1858	}
1859
1860	Block parse_embedded_statement () throws ParseError {
1861		if (current () == TokenType.INDENT) {
1862			var block = parse_block ();
1863			return block;
1864		}
1865
1866		comment = scanner.pop_comment ();
1867
1868		var block = new Block (get_src (get_location ()));
1869		block.add_statement (parse_embedded_statement_without_block ());
1870		return block;
1871
1872	}
1873
1874	Statement parse_embedded_statement_without_block () throws ParseError {
1875		switch (current ()) {
1876		case TokenType.PASS:
1877		case TokenType.SEMICOLON: return parse_empty_statement ();
1878		case TokenType.IF:		return parse_if_statement ();
1879		case TokenType.CASE:	  return parse_switch_statement ();
1880		case TokenType.WHILE:	 return parse_while_statement ();
1881		case TokenType.DO:		return parse_do_statement ();
1882		case TokenType.FOR:	   return get_for_statement_type ();
1883		case TokenType.BREAK:	 return parse_break_statement ();
1884		case TokenType.CONTINUE:  return parse_continue_statement ();
1885		case TokenType.RETURN:	return parse_return_statement ();
1886		case TokenType.YIELD:	 return parse_yield_statement ();
1887		case TokenType.RAISE:	 return parse_throw_statement ();
1888		case TokenType.TRY:	   return parse_try_statement ();
1889		case TokenType.LOCK:	  return parse_lock_statement ();
1890		case TokenType.DELETE:	return parse_delete_statement ();
1891		case TokenType.VAR:
1892		case TokenType.CONST:
1893			throw new ParseError.SYNTAX ("embedded statement cannot be declaration ");
1894		case TokenType.OP_INC:
1895		case TokenType.OP_DEC:
1896		case TokenType.SUPER:
1897		case TokenType.SELF:
1898		case TokenType.OPEN_PARENS:
1899		case TokenType.STAR:
1900		case TokenType.NEW:
1901			return parse_expression_statement ();
1902		default:
1903			if (is_expression ()) {
1904				return parse_expression_statement ();
1905			} else {
1906				throw new ParseError.SYNTAX ("embedded statement cannot be declaration");
1907			}
1908		}
1909	}
1910
1911	Block parse_block () throws ParseError {
1912		var begin = get_location ();
1913		expect (TokenType.INDENT);
1914		var block = new Block (get_src (begin));
1915		parse_statements (block);
1916		if (!accept (TokenType.DEDENT)) {
1917			// only report error if it's not a secondary error
1918			if (context.report.get_errors () == 0) {
1919				Report.error (get_current_src (), "tab indentation is incorrect");
1920			}
1921		}
1922
1923		block.source_reference.end = get_current_src ().end;
1924
1925		return block;
1926	}
1927
1928	Statement parse_empty_statement () throws ParseError {
1929		var begin = get_location ();
1930
1931		accept (TokenType.PASS);
1932		accept (TokenType.SEMICOLON);
1933		expect_terminator ();
1934
1935		return new EmptyStatement (get_src (begin));
1936	}
1937
1938	void parse_type_inference_declaration (Block block)  throws ParseError {
1939		expect (TokenType.VAR);
1940		bool block_var = false;
1941		if (accept (TokenType.EOL) && accept (TokenType.INDENT)) { block_var = true; }
1942		do {
1943			var s = parse_identifier ();
1944			var local = parse_local_variable (null, s, true);
1945			block.add_statement (new DeclarationStatement (local, local.source_reference));
1946		}
1947		while ((block_var) && (current () != TokenType.DEDENT));
1948		if ( block_var ) { expect (TokenType.DEDENT); }
1949	}
1950
1951	void parse_local_variable_declarations (Block block) throws ParseError {
1952		var id_list = new ArrayList<string> (str_equal);
1953		id_list.add (parse_identifier ());
1954		// Allow multiple declarations
1955		while (accept (TokenType.COMMA)) {
1956			id_list.add (parse_identifier ());
1957		}
1958
1959		expect (TokenType.COLON);
1960		DataType variable_type = parse_type (true, true);
1961		var type = parse_inline_array_type (variable_type);
1962
1963		var iterator = id_list.iterator();
1964		iterator.next();
1965		bool expect_terminator = false;
1966		while (!expect_terminator) {
1967			string id = iterator.get();
1968			DataType type_copy = null;
1969			if (type != null) {
1970				type_copy = type.copy ();
1971			}
1972			if (!iterator.next()) {
1973				expect_terminator = true;
1974			}
1975			var local = parse_local_variable (type_copy, id, expect_terminator);
1976			block.add_statement (new DeclarationStatement (local, local.source_reference));
1977		}
1978	}
1979
1980	LocalVariable parse_local_variable (DataType? variable_type, string id, bool expect_terminator = false) throws ParseError {
1981		var begin = get_location ();
1982		Expression initializer = null;
1983		if (accept (TokenType.ASSIGN)) {
1984			if (expect_terminator) {
1985				initializer = parse_expression_with_terminator ();
1986			} else {
1987				initializer = parse_expression ();
1988			}
1989		} else if (expect_terminator) {
1990			this.expect_terminator();
1991			}
1992		return new LocalVariable (variable_type, id, initializer, get_src (begin));
1993	}
1994
1995	Statement parse_expression_statement () throws ParseError {
1996		var begin = get_location ();
1997		var expr = parse_expression_with_terminator ();
1998		return new ExpressionStatement (expr, get_src (begin));
1999	}
2000
2001	Expression parse_statement_expression () throws ParseError {
2002		// invocation expression, assignment,
2003		// or pre/post increment/decrement expression
2004		var expr = parse_expression ();
2005		return expr;
2006	}
2007
2008	Statement parse_if_statement () throws ParseError {
2009		var begin = get_location ();
2010
2011		expect (TokenType.IF);
2012
2013		var condition = parse_expression ();
2014
2015		if (!accept (TokenType.DO)) {
2016			expect (TokenType.EOL);
2017		} else {
2018			accept (TokenType.EOL);
2019		}
2020
2021		var src = get_src (begin);
2022		var true_stmt = parse_embedded_statement ();
2023		Block false_stmt = null;
2024		if (accept (TokenType.ELSE)) {
2025			// allow `else if' on the same line without `do'
2026			if (!accept (TokenType.DO) && current () != TokenType.IF) {
2027				expect (TokenType.EOL);
2028			} else {
2029				accept (TokenType.EOL);
2030			}
2031
2032			false_stmt = parse_embedded_statement ();
2033		}
2034		return new IfStatement (condition, true_stmt, false_stmt, src);
2035	}
2036
2037	Statement parse_switch_statement () throws ParseError {
2038		var begin = get_location ();
2039		expect (TokenType.CASE);
2040		var condition = parse_expression ();
2041
2042		expect (TokenType.EOL);
2043
2044		var stmt = new SwitchStatement (condition, get_src (begin));
2045		expect (TokenType.INDENT);
2046		while (current () != TokenType.DEDENT) {
2047			var section = new SwitchSection (get_src (begin));
2048
2049			if (accept (TokenType.WHEN)) {
2050				do {
2051					section.add_label (new SwitchLabel (parse_expression (), get_src (begin)));
2052				}
2053				while (accept (TokenType.COMMA));
2054			} else {
2055				expect (TokenType.DEFAULT);
2056				section.add_label (new SwitchLabel.with_default (get_src (begin)));
2057			}
2058
2059			if (!accept (TokenType.EOL)) {
2060				expect (TokenType.DO);
2061			}
2062
2063			parse_statements (section);
2064
2065			/* add break statement for each block */
2066			var break_stmt =  new BreakStatement (get_src (begin));
2067			section.add_statement (break_stmt);
2068
2069			stmt.add_section (section);
2070		}
2071		expect (TokenType.DEDENT);
2072		return stmt;
2073	}
2074
2075	Statement parse_while_statement () throws ParseError {
2076		var begin = get_location ();
2077		expect (TokenType.WHILE);
2078		var condition = parse_expression ();
2079
2080		if (!accept (TokenType.DO)) {
2081			expect (TokenType.EOL);
2082		} else {
2083			accept (TokenType.EOL);
2084		}
2085
2086		var body = parse_embedded_statement ();
2087		return new WhileStatement (condition, body, get_src (begin));
2088	}
2089
2090	Statement parse_do_statement () throws ParseError {
2091		var begin = get_location ();
2092		expect (TokenType.DO);
2093		expect (TokenType.EOL);
2094		var body = parse_embedded_statement ();
2095		expect (TokenType.WHILE);
2096
2097		var condition = parse_expression ();
2098
2099		expect_terminator ();
2100
2101		return new DoStatement (body, condition, get_src (begin));
2102	}
2103
2104
2105	Statement parse_for_statement () throws ParseError {
2106		var begin = get_location ();
2107		Block block = null;
2108		Expression initializer = null;
2109		Expression condition = null;
2110		Expression iterator = null;
2111		bool is_expr;
2112		string id;
2113
2114		expect (TokenType.FOR);
2115
2116		switch (current ()) {
2117		case TokenType.VAR:
2118			is_expr = false;
2119			break;
2120		default:
2121
2122			bool local_is_expr = is_expression ();
2123			is_expr = local_is_expr;
2124			break;
2125		}
2126
2127		if (is_expr) {
2128			var expr_begin = get_location ();
2129			id = parse_identifier ();
2130			rollback (expr_begin);
2131			initializer = parse_statement_expression ();
2132		} else {
2133			block = new Block (get_src (begin));
2134			DataType variable_type;
2135			if (accept (TokenType.VAR)) {
2136				variable_type = null;
2137				id = parse_identifier ();
2138			} else {
2139				id = parse_identifier ();
2140				expect (TokenType.COLON);
2141				variable_type = parse_type (true, true);
2142			}
2143
2144			DataType type_copy = null;
2145			if (variable_type != null) {
2146				type_copy = variable_type.copy ();
2147			}
2148			var local = parse_local_variable (type_copy, id);
2149
2150			block.add_statement (new DeclarationStatement (local, local.source_reference));
2151		}
2152
2153
2154
2155		if (accept (TokenType.TO)) {
2156			/* create expression for condition and incrementing iterator */
2157			var to_begin = get_location ();
2158			var to_src = get_src (to_begin);
2159			var left = new MemberAccess (null, id, to_src);
2160			var right = parse_primary_expression ();
2161
2162			condition = new BinaryExpression (BinaryOperator.LESS_THAN_OR_EQUAL, left, right, to_src);
2163
2164			iterator = new PostfixExpression (left, true, to_src);
2165		} else {
2166			expect (TokenType.DOWNTO);
2167			var downto_begin = get_location ();
2168			var downto_src = get_src (downto_begin);
2169			/* create expression for condition and decrementing iterator */
2170			var left = new MemberAccess (null, id, downto_src);
2171			var right = parse_primary_expression ();
2172
2173			condition = new BinaryExpression (BinaryOperator.GREATER_THAN_OR_EQUAL, left, right, downto_src);
2174
2175			iterator = new PostfixExpression (left, false, downto_src);
2176		}
2177
2178		if (!accept (TokenType.EOL)) {
2179			expect (TokenType.DO);
2180		}
2181
2182		var src = get_src (begin);
2183		var body = parse_embedded_statement ();
2184		var stmt = new ForStatement (condition, body, src);
2185
2186		if (initializer != null) stmt.add_initializer (initializer);
2187
2188		stmt.add_iterator (iterator);
2189
2190
2191		if (block != null) {
2192			block.add_statement (stmt);
2193			return block;
2194		} else {
2195			return stmt;
2196		}
2197	}
2198
2199	Statement parse_foreach_statement () throws ParseError {
2200		var begin = get_location ();
2201		DataType type = null;
2202		string id = null;
2203
2204		expect (TokenType.FOR);
2205
2206		if (accept (TokenType.VAR)) {
2207			 id = parse_identifier ();
2208		} else {
2209			id = parse_identifier ();
2210			if (accept (TokenType.COLON)) {
2211				type = parse_type (true, true);
2212			}
2213		}
2214
2215		expect (TokenType.IN);
2216		var collection = parse_expression ();
2217		if (!accept (TokenType.EOL)) {
2218			expect (TokenType.DO);
2219		}
2220		var src = get_src (begin);
2221		var body = parse_embedded_statement ();
2222		return new ForeachStatement (type, id, collection, body, src);
2223	}
2224
2225	Statement parse_break_statement () throws ParseError {
2226		var begin = get_location ();
2227		expect (TokenType.BREAK);
2228		expect_terminator ();
2229		return new BreakStatement (get_src (begin));
2230	}
2231
2232	Statement parse_continue_statement () throws ParseError {
2233		var begin = get_location ();
2234		expect (TokenType.CONTINUE);
2235		expect_terminator ();
2236		return new ContinueStatement (get_src (begin));
2237	}
2238
2239	Statement parse_return_statement () throws ParseError {
2240		var begin = get_location ();
2241		expect (TokenType.RETURN);
2242		Expression expr = null;
2243		if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) {
2244			expr = parse_expression_with_terminator ();
2245		} else {
2246			expect_terminator ();
2247		}
2248		return new ReturnStatement (expr, get_src (begin));
2249	}
2250
2251	Statement parse_yield_statement () throws ParseError {
2252		var begin = get_location ();
2253		expect (TokenType.YIELD);
2254		if (current () != TokenType.SEMICOLON && current () != TokenType.EOL) {
2255			prev ();
2256			return parse_expression_statement ();
2257		}
2258		expect_terminator ();
2259		return new YieldStatement (get_src (begin));
2260	}
2261
2262	Statement parse_throw_statement () throws ParseError {
2263		var begin = get_location ();
2264		expect (TokenType.RAISE);
2265		var expr = parse_expression ();
2266		expect_terminator ();
2267		return new ThrowStatement (expr, get_src (begin));
2268	}
2269
2270	Statement parse_try_statement () throws ParseError {
2271		var begin = get_location ();
2272		expect (TokenType.TRY);
2273		expect (TokenType.EOL);
2274		var try_block = parse_block ();
2275		Block finally_clause = null;
2276		var catch_clauses = new ArrayList<CatchClause> ();
2277		if (current () == TokenType.EXCEPT) {
2278			parse_catch_clauses (catch_clauses);
2279			if (current () == TokenType.FINALLY) {
2280				finally_clause = parse_finally_clause ();
2281			}
2282		} else {
2283			finally_clause = parse_finally_clause ();
2284		}
2285		var stmt = new TryStatement (try_block, finally_clause, get_src (begin));
2286		foreach (CatchClause clause in catch_clauses) {
2287			stmt.add_catch_clause (clause);
2288		}
2289		return stmt;
2290	}
2291
2292	void parse_catch_clauses (List<CatchClause> catch_clauses) throws ParseError {
2293		while (accept (TokenType.EXCEPT)) {
2294			var begin = get_location ();
2295			DataType type = null;
2296			string id = null;
2297			if (!accept (TokenType.EOL)) {
2298				id = parse_identifier ();
2299				expect (TokenType.COLON);
2300				type = parse_type (true, true);
2301				expect (TokenType.EOL);
2302
2303			}
2304			var block = parse_block ();
2305			catch_clauses.add (new CatchClause (type, id, block, get_src (begin)));
2306		}
2307	}
2308
2309	Block parse_finally_clause () throws ParseError {
2310		expect (TokenType.FINALLY);
2311		accept_block ();
2312		var block = parse_block ();
2313		return block;
2314	}
2315
2316	Statement parse_lock_statement () throws ParseError {
2317		var begin = get_location ();
2318		expect (TokenType.LOCK);
2319		expect (TokenType.OPEN_PARENS);
2320		var expr = parse_expression ();
2321		expect (TokenType.CLOSE_PARENS);
2322		var stmt = parse_embedded_statement ();
2323		return new LockStatement (expr, stmt, get_src (begin));
2324	}
2325
2326	Statement parse_delete_statement () throws ParseError {
2327		var begin = get_location ();
2328		expect (TokenType.DELETE);
2329		var expr = parse_expression ();
2330		expect_terminator ();
2331		return new DeleteStatement (expr, get_src (begin));
2332	}
2333
2334	string parse_attribute_value () throws ParseError {
2335		switch (current ()) {
2336		case TokenType.NULL:
2337		case TokenType.TRUE:
2338		case TokenType.FALSE:
2339		case TokenType.INTEGER_LITERAL:
2340		case TokenType.REAL_LITERAL:
2341		case TokenType.STRING_LITERAL:
2342			next ();
2343			return get_last_string ();
2344		case TokenType.MINUS:
2345			next ();
2346			switch (current ()) {
2347			case TokenType.INTEGER_LITERAL:
2348			case TokenType.REAL_LITERAL:
2349				next ();
2350				return "-" + get_last_string ();
2351			default:
2352				throw new ParseError.SYNTAX ("expected number");
2353			}
2354		default:
2355			throw new ParseError.SYNTAX ("expected literal");
2356		}
2357	}
2358
2359	List<Attribute>? parse_attributes (bool parameter) throws ParseError {
2360		if (current () != TokenType.OPEN_BRACKET) {
2361			return null;
2362		}
2363		var attrs = new ArrayList<Attribute> ();
2364		while (accept (TokenType.OPEN_BRACKET)) {
2365			do {
2366				var begin = get_location ();
2367				string id = parse_identifier ();
2368				var attr = new Attribute (id, get_src (begin));
2369				if (accept (TokenType.OPEN_PARENS)) {
2370					if (current () != TokenType.CLOSE_PARENS) {
2371						do {
2372							id = parse_identifier ();
2373							expect (TokenType.ASSIGN);
2374							attr.add_argument (id, parse_attribute_value ());
2375						} while (accept (TokenType.COMMA));
2376					}
2377					expect (TokenType.CLOSE_PARENS);
2378				}
2379				attrs.add (attr);
2380			} while (accept (TokenType.COMMA));
2381			expect (TokenType.CLOSE_BRACKET);
2382		}
2383		if (!parameter)
2384			expect (TokenType.EOL);
2385		return attrs;
2386	}
2387
2388	void set_attributes (CodeNode node, List<Attribute>? attributes) {
2389		if (attributes != null) {
2390			foreach (Attribute attr in (List<Attribute>) attributes) {
2391				if (node.get_attribute (attr.name) != null) {
2392					Report.error (attr.source_reference, "duplicate attribute `%s'".printf (attr.name));
2393				}
2394				node.attributes.append (attr);
2395			}
2396		}
2397	}
2398
2399	Symbol parse_declaration (bool is_root = false) throws ParseError {
2400		comment = scanner.pop_comment ();
2401		var attrs = parse_attributes (false);
2402		var begin = get_location ();
2403
2404		switch (current ()) {
2405		case TokenType.CONST:
2406			return parse_constant_declaration (attrs);
2407		case TokenType.CONSTRUCT:
2408			return parse_creation_method_declaration (attrs);
2409		case TokenType.CLASS:
2410			return parse_class_declaration (attrs);
2411		case TokenType.INIT:
2412			if (is_root) {
2413				return parse_main_method_declaration (attrs);
2414			}
2415			if (context.profile == Profile.GOBJECT) {
2416				rollback (begin);
2417				return parse_constructor_declaration (attrs);
2418			}
2419			break;
2420		case TokenType.DELEGATE:
2421			return parse_delegate_declaration (attrs);
2422		case TokenType.DEF:
2423			return parse_method_declaration (attrs);
2424		case TokenType.ENUM:
2425			return parse_enum_declaration (attrs);
2426		case TokenType.ERRORDOMAIN:
2427			return parse_errordomain_declaration (attrs);
2428		case TokenType.FINAL:
2429			return parse_destructor_declaration (attrs);
2430		case TokenType.INTERFACE:
2431			return parse_interface_declaration (attrs);
2432		case TokenType.NAMESPACE:
2433			return parse_namespace_declaration (attrs);
2434		case TokenType.PROP:
2435			return parse_property_declaration (attrs);
2436		case TokenType.EVENT:
2437			return parse_signal_declaration (attrs);
2438		case TokenType.STRUCT:
2439			return parse_struct_declaration (attrs);
2440		default:
2441
2442			while (current () != TokenType.EOL && current () != TokenType.SEMICOLON && current () != TokenType.EOF) {
2443				if (current () == TokenType.COLON) {
2444					rollback (begin);
2445					return parse_field_declaration (attrs);
2446				} else {
2447					next ();
2448				}
2449			}
2450			rollback (begin);
2451
2452			break;
2453		}
2454
2455		TokenType cur = current ();
2456		TokenType pre =  tokens[index-1].type;
2457
2458		throw new ParseError.SYNTAX ("expected declaration  but got %s with previous %s", cur.to_string (), pre.to_string());
2459	}
2460
2461	void parse_declarations (Symbol parent, bool root = false) throws ParseError {
2462		if (!root) {
2463			expect (TokenType.INDENT);
2464		}
2465		while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2466			try {
2467				if (parent is Namespace) {
2468					parse_namespace_member ((Namespace) parent);
2469				} else if (parent is Class) {
2470					parse_class_member ((Class) parent);
2471				} else if (parent is Struct) {
2472					parse_struct_member ((Struct) parent);
2473				} else if (parent is Interface) {
2474					parse_interface_member ((Interface) parent);
2475				}
2476			} catch (ParseError e) {
2477				report_parse_error (e);
2478				int r;
2479				do {
2480					r = recover ();
2481					if (r == RecoveryState.STATEMENT_BEGIN) {
2482						next ();
2483					} else {
2484						break;
2485					}
2486				} while (true);
2487				if (r == RecoveryState.EOF) {
2488					return;
2489				}
2490			}
2491		}
2492		if (!root) {
2493			if (!accept (TokenType.DEDENT)) {
2494				// only report error if it's not a secondary error
2495				if (context.report.get_errors () == 0) {
2496					Report.error (get_current_src (), "expected dedent");
2497				}
2498			}
2499		}
2500	}
2501
2502	enum RecoveryState {
2503		EOF,
2504		DECLARATION_BEGIN,
2505		STATEMENT_BEGIN
2506	}
2507
2508	RecoveryState recover () {
2509		while (current () != TokenType.EOF) {
2510			switch (current ()) {
2511			case TokenType.CLASS:
2512			case TokenType.CONST:
2513			case TokenType.CONSTRUCT:
2514			case TokenType.INIT:
2515			case TokenType.DEF:
2516			case TokenType.DELEGATE:
2517			case TokenType.ENUM:
2518			case TokenType.ERRORDOMAIN:
2519			case TokenType.FINAL:
2520			case TokenType.INTERFACE:
2521			case TokenType.NAMESPACE:
2522			case TokenType.PROP:
2523			case TokenType.EVENT:
2524			case TokenType.STRUCT:
2525				return RecoveryState.DECLARATION_BEGIN;
2526			case TokenType.BREAK:
2527			case TokenType.CASE:
2528			case TokenType.CONTINUE:
2529			case TokenType.DELETE:
2530			case TokenType.DO:
2531			case TokenType.FOR:
2532			case TokenType.IF:
2533			case TokenType.LOCK:
2534			case TokenType.RETURN:
2535			case TokenType.RAISE:
2536			case TokenType.TRY:
2537			case TokenType.VAR:
2538			case TokenType.WHILE:
2539			case TokenType.YIELD:
2540				return RecoveryState.STATEMENT_BEGIN;
2541			default:
2542				next ();
2543				break;
2544			}
2545		}
2546		return RecoveryState.EOF;
2547	}
2548
2549	Namespace parse_namespace_declaration (List<Attribute>? attrs) throws ParseError {
2550		var begin = get_location ();
2551		expect (TokenType.NAMESPACE);
2552		var sym = parse_symbol_name ();
2553		var ns = new Namespace (sym.name, get_src (begin));
2554		if (comment != null) {
2555			ns.add_comment (comment);
2556			comment = null;
2557		}
2558		set_attributes (ns, attrs);
2559		expect (TokenType.EOL);
2560		parse_declarations (ns);
2561
2562		Namespace result = ns;
2563		while (sym.inner != null) {
2564			sym = sym.inner;
2565			ns = new Namespace (sym.name, result.source_reference);
2566			ns.add_namespace ((Namespace) result);
2567			result = ns;
2568		}
2569		return result;
2570	}
2571
2572	void parse_namespace_member (Namespace ns) throws ParseError {
2573
2574		var sym = parse_declaration ((ns == context.root));
2575		if (sym is Namespace) {
2576			ns.add_namespace ((Namespace) sym);
2577		} else if (sym is Class) {
2578			ns.add_class ((Class) sym);
2579		} else if (sym is Interface) {
2580			ns.add_interface ((Interface) sym);
2581		} else if (sym is Struct) {
2582			ns.add_struct ((Struct) sym);
2583		} else if (sym is Enum) {
2584			ns.add_enum ((Enum) sym);
2585		} else if (sym is ErrorDomain) {
2586			ns.add_error_domain ((ErrorDomain) sym);
2587		} else if (sym is Delegate) {
2588			ns.add_delegate ((Delegate) sym);
2589		} else if (sym is Method) {
2590			unowned Method method = (Method) sym;
2591			if (method.binding == MemberBinding.INSTANCE) {
2592				method.binding = MemberBinding.STATIC;
2593			}
2594			ns.add_method (method);
2595		} else if (sym is Field) {
2596			unowned Field field = (Field) sym;
2597			if (field.binding == MemberBinding.INSTANCE) {
2598				field.binding = MemberBinding.STATIC;
2599			}
2600			ns.add_field (field);
2601		} else if (sym is Constant) {
2602			ns.add_constant ((Constant) sym);
2603		} else {
2604			Report.error (sym.source_reference, "unexpected declaration in namespace");
2605		}
2606	}
2607
2608
2609	void add_uses_clause (Namespace ns) throws ParseError {
2610		var begin = get_location ();
2611		var sym = parse_symbol_name ();
2612		var ns_ref = new UsingDirective (sym, get_src (begin));
2613
2614		scanner.source_file.add_using_directive (ns_ref);
2615		ns.add_using_directive (ns_ref);
2616	}
2617
2618	void parse_using_directives (Namespace ns) throws ParseError {
2619		while (accept (TokenType.USES)) {
2620			if (accept_block ()) {
2621				expect (TokenType.INDENT);
2622
2623				while (current () != TokenType.DEDENT && current () != TokenType.EOF) {
2624					add_uses_clause (ns);
2625					expect (TokenType.EOL);
2626				}
2627
2628				expect (TokenType.DEDENT);
2629			} else {
2630				do {
2631					add_uses_clause (ns);
2632				} while (accept (TokenType.COMMA));
2633
2634				expect_terminator ();
2635			}
2636		}
2637
2638	}
2639
2640	Symbol parse_class_declaration (List<Attribute>? attrs) throws ParseError {
2641		var begin = get_location ();
2642		expect (TokenType.CLASS);
2643
2644		var flags = parse_type_declaration_modifiers ();
2645
2646		var sym = parse_symbol_name ();
2647		var type_param_list = parse_type_parameter_list ();
2648		var base_types = new ArrayList<DataType> ();
2649		if (accept (TokenType.COLON)) {
2650			var type1 = parse_type (true, false);
2651			base_types.add (type1);
2652
2653			if (accept (TokenType.IMPLEMENTS)) {
2654				do {
2655					var type2 = parse_type (true, true);
2656					base_types.add (type2);
2657				} while (accept (TokenType.COMMA));
2658			}
2659		}
2660
2661		accept (TokenType.EOL);
2662
2663		var cl = new Class (sym.name, get_src (begin), comment);
2664
2665		if (ModifierFlags.PRIVATE in flags) {
2666			cl.access = SymbolAccessibility.PRIVATE;
2667		} else if (ModifierFlags.PROTECTED in flags) {
2668			cl.access = SymbolAccessibility.PROTECTED;
2669		} else {
2670			cl.access = get_default_accessibility (sym.name);
2671		}
2672
2673		if (ModifierFlags.ABSTRACT in flags) {
2674			cl.is_abstract = true;
2675		}
2676		set_attributes (cl, attrs);
2677		foreach (TypeParameter type_param in type_param_list) {
2678			cl.add_type_parameter (type_param);
2679		}
2680		foreach (DataType base_type in base_types) {
2681			cl.add_base_type (base_type);
2682		}
2683
2684		class_name = cl.name;
2685
2686		parse_declarations (cl);
2687
2688		// ensure there is always a default construction method
2689		if (scanner.source_file.file_type == SourceFileType.SOURCE
2690			&& cl.default_construction_method == null) {
2691			var m = new CreationMethod (cl.name, null, cl.source_reference);
2692			m.access = (cl.is_abstract ? SymbolAccessibility.PROTECTED : SymbolAccessibility.PUBLIC);
2693			m.body = new Block (cl.source_reference);
2694			cl.add_method (m);
2695		}
2696
2697		Symbol result = cl;
2698		while (sym.inner != null) {
2699			sym = sym.inner;
2700			var ns = new Namespace (sym.name, cl.source_reference);
2701			if (result is Namespace) {
2702				ns.add_namespace ((Namespace) result);
2703			} else {
2704				ns.add_class ((Class) result);
2705			}
2706			result = ns;
2707		}
2708		return result;
2709	}
2710
2711	void parse_class_member (Class cl) throws ParseError {
2712		var sym = parse_declaration ();
2713		if (sym is Class) {
2714			cl.add_class ((Class) sym);
2715		} else if (sym is Struct) {
2716			cl.add_struct ((Struct) sym);
2717		} else if (sym is Enum) {
2718			cl.add_enum ((Enum) sym);
2719		} else if (sym is Delegate) {
2720			cl.add_delegate ((Delegate) sym);
2721		} else if (sym is Method) {
2722			cl.add_method ((Method) sym);
2723		} else if (sym is Vala.Signal) {
2724			cl.add_signal ((Vala.Signal) sym);
2725		} else if (sym is Field) {
2726			cl.add_field ((Field) sym);
2727		} else if (sym is Constant) {
2728			cl.add_constant ((Constant) sym);
2729		} else if (sym is Property) {
2730			cl.add_property ((Property) sym);
2731		} else if (sym is Constructor) {
2732			cl.add_constructor ((Constructor) sym);
2733		} else if (sym is Destructor) {
2734			cl.add_destructor ((Destructor) sym);
2735		} else {
2736			Report.error (sym.source_reference, "unexpected declaration in class");
2737		}
2738	}
2739
2740	Constant parse_constant_declaration (List<Attribute>? attrs) throws ParseError {
2741		var begin = get_location ();
2742
2743		expect (TokenType.CONST);
2744
2745		var flags = parse_member_declaration_modifiers ();
2746
2747		string id = parse_identifier ();
2748
2749		expect (TokenType.COLON);
2750		var type = parse_type (false, false);
2751		type = parse_inline_array_type (type);
2752
2753		Expression initializer = null;
2754		if (accept (TokenType.ASSIGN)) {
2755			initializer = parse_expression ();
2756		}
2757		expect_terminator ();
2758
2759		// constant arrays don't own their element
2760		unowned ArrayType? array_type = type as ArrayType;
2761		if (array_type != null) {
2762			array_type.element_type.value_owned = false;
2763		}
2764
2765		var c = new Constant (id, type, initializer, get_src (begin), comment);
2766		c.access = get_default_accessibility (id);
2767
2768		if (ModifierFlags.EXTERN in flags) {
2769			c.is_extern = true;
2770		}
2771		if (ModifierFlags.NEW in flags) {
2772			c.hides = true;
2773		}
2774
2775		set_attributes (c, attrs);
2776
2777		if (ModifierFlags.STATIC in flags) {
2778			Report.warning (c.source_reference, "the modifier `static' is not applicable to constants");
2779		}
2780
2781		return c;
2782	}
2783
2784	Field parse_field_declaration (List<Attribute>? attrs) throws ParseError {
2785		var begin = get_location ();
2786		string id = parse_identifier ();
2787		expect (TokenType.COLON);
2788
2789		var flags = parse_member_declaration_modifiers ();
2790
2791		var type = parse_type (true, true);
2792
2793		type = parse_inline_array_type (type);
2794
2795		var f = new Field (id, type, null, get_src (begin), comment);
2796
2797		if (ModifierFlags.ABSTRACT in flags || ModifierFlags.VIRTUAL in flags || ModifierFlags.OVERRIDE in flags) {
2798			Report.error (f.source_reference, "abstract, virtual, and override modifiers are not applicable to fields");
2799		}
2800
2801		if (ModifierFlags.PRIVATE in flags) {
2802			f.access = SymbolAccessibility.PRIVATE;
2803		} else if (ModifierFlags.PROTECTED in flags) {
2804			f.access = SymbolAccessibility.PROTECTED;
2805		} else {
2806			f.access = get_default_accessibility (id);
2807		}
2808
2809		set_attributes (f, attrs);
2810
2811		if (ModifierFlags.EXTERN in flags) {
2812			f.is_extern = true;
2813		}
2814		if (ModifierFlags.NEW in flags) {
2815			f.hides = true;
2816		}
2817
2818		if (accept (TokenType.ASSIGN)) {
2819			f.initializer = parse_expression ();
2820		}
2821
2822		if (ModifierFlags.STATIC in flags) {
2823			f.binding = MemberBinding.STATIC;
2824		} else if (ModifierFlags.CLASS in flags) {
2825			f.binding = MemberBinding.CLASS;
2826		}
2827
2828		expect_terminator ();
2829
2830		return f;
2831	}
2832
2833	InitializerList parse_initializer () throws ParseError {
2834		var begin = get_location ();
2835		if  (!accept (TokenType.OPEN_PARENS)) {
2836			expect (TokenType.OPEN_BRACE);
2837		}
2838		var initializer = new InitializerList (get_src (begin));
2839		if (current () != TokenType.DEDENT) {
2840			do {
2841				var init = parse_argument ();
2842				initializer.append (init);
2843			} while (accept (TokenType.COMMA));
2844		}
2845		if  (!accept (TokenType.CLOSE_PARENS)) {
2846			expect (TokenType.CLOSE_BRACE);
2847		}
2848		return initializer;
2849	}
2850
2851
2852
2853
2854	Method parse_main_method_declaration (List<Attribute>? attrs) throws ParseError {
2855		var begin = get_location ();
2856		DataType type;
2857
2858		expect (TokenType.INIT);
2859
2860		if (accept (TokenType.COLON)) {
2861			type = parse_type (true, false);
2862			if (type.to_string () != "int") {
2863				throw new ParseError.SYNTAX ("main `init' must return void or `int', but got `%s'".printf (type.to_string ()));
2864			}
2865		} else {
2866			type = new VoidType ();
2867		}
2868
2869		var method = new Method ("main", type, get_src (begin), comment);
2870		method.access = SymbolAccessibility.PUBLIC;
2871		method.binding = MemberBinding.STATIC;
2872		set_attributes (method, attrs);
2873
2874		var sym = new UnresolvedSymbol (null, "string", get_src (begin));
2875		type = new UnresolvedType.from_symbol (sym, get_src (begin));
2876		type.value_owned = true;
2877		type = new ArrayType (type, 1, get_src (begin));
2878		type.nullable = false;
2879
2880		var param = new Parameter ("args", type, get_src (begin));
2881		method.add_parameter (param);
2882
2883
2884		expect (TokenType.EOL);
2885
2886		if (accept_block ()) {
2887			method.body = parse_block ();
2888		}
2889
2890		return method;
2891	}
2892
2893	Method parse_method_declaration (List<Attribute>? attrs) throws ParseError {
2894		var begin = get_location ();
2895		DataType type;
2896
2897		expect (TokenType.DEF);
2898		var flags = parse_member_declaration_modifiers ();
2899
2900		string id = parse_identifier ();
2901
2902		var params = new ArrayList<Parameter> ();
2903		expect (TokenType.OPEN_PARENS);
2904
2905		if (current () != TokenType.CLOSE_PARENS) {
2906			do {
2907				var param = parse_parameter ();
2908				params.add (param);
2909			} while (accept (TokenType.COMMA));
2910		}
2911
2912		expect (TokenType.CLOSE_PARENS);
2913
2914
2915		/* deal with return value */
2916		if (accept (TokenType.COLON)) {
2917			type = parse_type (true, false);
2918		} else {
2919			type = new VoidType ();
2920		}
2921
2922		var type_param_list = parse_type_parameter_list ();
2923
2924		var method = new Method (id, type, get_src (begin), comment);
2925		if (ModifierFlags.PRIVATE in flags) {
2926			method.access = SymbolAccessibility.PRIVATE;
2927		} else if (ModifierFlags.PROTECTED in flags) {
2928			method.access = SymbolAccessibility.PROTECTED;
2929		} else {
2930			method.access = get_default_accessibility (id);
2931		}
2932
2933
2934		set_attributes (method, attrs);
2935
2936		foreach (TypeParameter type_param in type_param_list) {
2937			method.add_type_parameter (type_param);
2938		}
2939
2940
2941		foreach (Parameter param in params) {
2942			method.add_parameter (param);
2943		}
2944
2945		if (accept (TokenType.RAISES)) {
2946			do {
2947				method.add_error_type (parse_type (true, false));
2948			} while (accept (TokenType.COMMA));
2949		}
2950
2951
2952		if (ModifierFlags.STATIC in flags || id == "main") {
2953			method.binding = MemberBinding.STATIC;
2954		} else if (ModifierFlags.CLASS in flags) {
2955			method.binding = MemberBinding.CLASS;
2956		}
2957		if (ModifierFlags.ASYNC in flags) {
2958			method.coroutine = true;
2959		}
2960
2961		if (ModifierFlags.NEW in flags) {
2962			method.hides = true;
2963		}
2964
2965		if (method.binding == MemberBinding.INSTANCE) {
2966			if (ModifierFlags.ABSTRACT in flags) {
2967				method.is_abstract = true;
2968			}
2969			if (ModifierFlags.VIRTUAL in flags) {
2970				method.is_virtual = true;
2971			}
2972			if (ModifierFlags.OVERRIDE in flags) {
2973				method.overrides = true;
2974			}
2975			if ((method.is_abstract && method.is_virtual)
2976				|| (method.is_abstract && method.overrides)
2977				|| (method.is_virtual && method.overrides)) {
2978				throw new ParseError.SYNTAX ("only one of `abstract', `virtual', or `override' may be specified");
2979			}
2980		} else {
2981			if (ModifierFlags.ABSTRACT in flags
2982				|| ModifierFlags.VIRTUAL in flags
2983				|| ModifierFlags.OVERRIDE in flags) {
2984				throw new ParseError.SYNTAX ("the modifiers `abstract', `virtual', and `override' are not valid for static methods");
2985			}
2986		}
2987
2988		if (ModifierFlags.INLINE in flags) {
2989			method.is_inline = true;
2990		}
2991		if (ModifierFlags.EXTERN in flags) {
2992			method.is_extern = true;
2993		}
2994
2995		expect (TokenType.EOL);
2996
2997		var body_location = get_location ();
2998
2999
3000		/* "requires" and "ensures" if present will be at  start of the method body */
3001		if (accept (TokenType.INDENT)) {
3002			if (accept (TokenType.REQUIRES)) {
3003
3004				if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
3005					while (current() != TokenType.DEDENT) {
3006						method.add_precondition (parse_expression ());
3007						expect (TokenType.EOL);
3008					}
3009
3010					expect (TokenType.DEDENT);
3011					accept_terminator ();
3012				} else {
3013
3014					method.add_precondition (parse_expression ());
3015					expect_terminator ();
3016
3017				}
3018
3019			}
3020
3021			if (accept (TokenType.ENSURES)) {
3022				if (accept (TokenType.EOL) && accept (TokenType.INDENT)) {
3023					while (current() != TokenType.DEDENT) {
3024						method.add_postcondition (parse_expression ());
3025						expect (TokenType.EOL);
3026					}
3027
3028					expect (TokenType.DEDENT);
3029					accept_terminator ();
3030				} else {
3031					method.add_postcondition (parse_expression ());
3032					expect_terminator ();
3033				}
3034			}
3035		}
3036
3037		rollback (body_location);
3038
3039
3040		if (accept_block ()) {
3041			method.body = parse_block ();
3042			method.external = false;
3043		}
3044		return method;
3045	}
3046
3047	Property parse_property_declaration (List<Attribute>? attrs) throws ParseError {
3048		var begin = get_location ();
3049		var readonly = false;
3050
3051		expect (TokenType.PROP);
3052
3053		var flags = parse_member_declaration_modifiers ();
3054
3055		readonly =  accept (TokenType.READONLY);
3056
3057		string id = parse_identifier ();
3058		expect (TokenType.COLON);
3059
3060		var type = parse_type (true, true);
3061
3062		var prop = new Property (id, type, null, null, get_src (begin), comment);
3063		if (ModifierFlags.PRIVATE in flags) {
3064			prop.access = SymbolAccessibility.PRIVATE;
3065		} else if (ModifierFlags.PROTECTED in flags) {
3066			prop.access = SymbolAccessibility.PROTECTED;
3067		} else {
3068			prop.access = get_default_accessibility (id);
3069		}
3070
3071		set_attributes (prop, attrs);
3072
3073		if (ModifierFlags.STATIC in flags) {
3074			prop.binding = MemberBinding.STATIC;
3075		} else if (ModifierFlags.CLASS in flags) {
3076			prop.binding = MemberBinding.CLASS;
3077		}
3078		if (ModifierFlags.ABSTRACT in flags) {
3079			prop.is_abstract = true;
3080		}
3081		if (ModifierFlags.VIRTUAL in flags) {
3082			prop.is_virtual = true;
3083		}
3084		if (ModifierFlags.OVERRIDE in flags) {
3085			prop.overrides = true;
3086		}
3087
3088		if (ModifierFlags.NEW in flags) {
3089			prop.hides = true;
3090		}
3091		if (ModifierFlags.EXTERN in flags) {
3092			prop.is_extern = true;
3093		}
3094
3095		if (ModifierFlags.ASYNC in flags) {
3096			Report.error (prop.source_reference, "async properties are not supported yet");
3097		}
3098
3099		if (accept (TokenType.ASSIGN)) {
3100			prop.initializer = parse_expression ();
3101		}
3102
3103
3104		if (accept_block ()) {
3105			expect (TokenType.INDENT);
3106			while (current () != TokenType.DEDENT) {
3107				var accessor_begin = get_location ();
3108				var attribs = parse_attributes (false);
3109
3110				var value_type = type.copy ();
3111				value_type.value_owned = accept (TokenType.OWNED);
3112
3113				if (accept (TokenType.GET)) {
3114					if (prop.get_accessor != null) {
3115						throw new ParseError.SYNTAX ("property get accessor already defined");
3116					}
3117					Block block = null;
3118					if (accept_block ()) {
3119						block = parse_block ();
3120						prop.external = false;
3121					}
3122					prop.get_accessor = new PropertyAccessor (true, false, false, value_type, block, get_src (accessor_begin));
3123					set_attributes (prop.get_accessor, attribs);
3124					prop.get_accessor.access = SymbolAccessibility.PUBLIC;
3125				} else {
3126					bool _construct = false;
3127					if (accept (TokenType.SET)) {
3128						if (readonly) {
3129							throw new ParseError.SYNTAX ("set block not allowed for a read only property");
3130						}
3131						_construct = (context.profile == Profile.GOBJECT) && accept (TokenType.CONSTRUCT);
3132					} else if (context.profile == Profile.GOBJECT && accept (TokenType.CONSTRUCT)) {
3133						_construct = true;
3134					} else if (!accept (TokenType.EOL)) {
3135						throw new ParseError.SYNTAX ("expected get, set, or construct");
3136					}
3137
3138					if (prop.set_accessor != null) {
3139						throw new ParseError.SYNTAX ("property set accessor already defined");
3140					}
3141
3142					Block block = null;
3143					if (accept_block ()) {
3144						block = parse_block ();
3145						prop.external = false;
3146					}
3147					prop.set_accessor = new PropertyAccessor (false, !readonly, _construct, value_type, block, get_src (accessor_begin));
3148					set_attributes (prop.set_accessor, attribs);
3149					prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3150				}
3151			}
3152			accept (TokenType.EOL);
3153			expect (TokenType.DEDENT);
3154		} else {
3155			var value_type = type.copy ();
3156			value_type.value_owned = false;
3157
3158			prop.get_accessor = new PropertyAccessor (true, false, false, value_type, null, get_src (begin));
3159			prop.get_accessor.access = SymbolAccessibility.PUBLIC;
3160
3161			if (!readonly) {
3162				value_type = type.copy ();
3163				value_type.value_owned = false;
3164
3165				prop.set_accessor = new PropertyAccessor (false, true, false, value_type, null, get_src (begin));
3166				prop.set_accessor.access = SymbolAccessibility.PUBLIC;
3167
3168			}
3169
3170			expect_terminator ();
3171		}
3172
3173		return prop;
3174	}
3175
3176	Vala.Signal parse_signal_declaration (List<Attribute>? attrs) throws ParseError {
3177		var begin = get_location ();
3178		DataType type;
3179
3180		expect (TokenType.EVENT);
3181		var flags = parse_member_declaration_modifiers ();
3182		string id = parse_identifier ();
3183
3184
3185		var params = new ArrayList<Parameter> ();
3186
3187		expect (TokenType.OPEN_PARENS);
3188		if (current () != TokenType.CLOSE_PARENS) {
3189			do {
3190				var param = parse_parameter ();
3191				params.add (param);
3192			} while (accept (TokenType.COMMA));
3193		}
3194		expect (TokenType.CLOSE_PARENS);
3195
3196		if (accept (TokenType.COLON)) {
3197			type = parse_type (true, false);
3198		} else {
3199			type = new VoidType ();
3200		}
3201
3202		var sig = new Vala.Signal (id, type, get_src (begin), comment);
3203		if (ModifierFlags.PRIVATE in flags) {
3204			sig.access = SymbolAccessibility.PRIVATE;
3205		} else if (ModifierFlags.PROTECTED in flags) {
3206			sig.access = SymbolAccessibility.PROTECTED;
3207		} else {
3208			sig.access = get_default_accessibility (id);
3209		}
3210
3211		if (ModifierFlags.VIRTUAL in flags) {
3212			sig.is_virtual = true;
3213		}
3214		if (ModifierFlags.NEW in flags) {
3215			sig.hides = true;
3216		}
3217
3218		if (ModifierFlags.STATIC in flags) {
3219			throw new ParseError.SYNTAX ("`static' modifier not allowed on signals");
3220		} else if (ModifierFlags.CLASS in flags) {
3221			throw new ParseError.SYNTAX ("`class' modifier not allowed on signals");
3222		}
3223
3224		set_attributes (sig, attrs);
3225
3226		foreach (Parameter formal_param in params) {
3227			sig.add_parameter (formal_param);
3228		}
3229
3230		if (!accept_terminator ()) {
3231			sig.body = parse_block ();
3232		}
3233		return sig;
3234	}
3235
3236	Constructor parse_constructor_declaration (List<Attribute>? attrs) throws ParseError {
3237		var begin = get_location ();
3238
3239		expect (TokenType.INIT);
3240		var flags = parse_member_declaration_modifiers ();
3241
3242		var c = new Constructor (get_src (begin));
3243		if (ModifierFlags.STATIC in flags) {
3244			c.binding = MemberBinding.STATIC;
3245		} else if (ModifierFlags.CLASS in flags) {
3246			c.binding = MemberBinding.CLASS;
3247		}
3248
3249		accept_block ();
3250		c.body = parse_block ();
3251		return c;
3252	}
3253
3254	Destructor parse_destructor_declaration (List<Attribute>? attrs) throws ParseError {
3255		var begin = get_location ();
3256		expect (TokenType.FINAL);
3257		var d = new Destructor (get_src (begin));
3258		accept_block ();
3259		d.body = parse_block ();
3260		return d;
3261	}
3262
3263	Symbol parse_struct_declaration (List<Attribute>? attrs) throws ParseError {
3264		var begin = get_location ();
3265
3266		expect (TokenType.STRUCT);
3267		var flags = parse_type_declaration_modifiers ();
3268		var sym = parse_symbol_name ();
3269		var type_param_list = parse_type_parameter_list ();
3270		DataType base_type = null;
3271		if (accept (TokenType.COLON)) {
3272			base_type = parse_type (true, false);
3273		}
3274
3275		var st = new Struct (sym.name, get_src (begin), comment);
3276		if (ModifierFlags.PRIVATE in flags) {
3277			st.access = SymbolAccessibility.PRIVATE;
3278		} else if (ModifierFlags.PROTECTED in flags) {
3279			st.access = SymbolAccessibility.PROTECTED;
3280		} else {
3281			st.access = get_default_accessibility (sym.name);
3282		}
3283		set_attributes (st, attrs);
3284		foreach (TypeParameter type_param in type_param_list) {
3285			st.add_type_parameter (type_param);
3286		}
3287		if (base_type != null) {
3288			st.base_type = base_type;
3289		}
3290
3291		expect (TokenType.EOL);
3292
3293		class_name = st.name;
3294
3295		parse_declarations (st);
3296
3297		Symbol result = st;
3298		while (sym.inner != null) {
3299			sym = sym.inner;
3300			var ns = new Namespace (sym.name, st.source_reference);
3301			if (result is Namespace) {
3302				ns.add_namespace ((Namespace) result);
3303			} else {
3304				ns.add_struct ((Struct) result);
3305			}
3306			result = ns;
3307		}
3308		return result;
3309	}
3310
3311	void parse_struct_member (Struct st) throws ParseError {
3312		var sym = parse_declaration ();
3313		if (sym is Method) {
3314			st.add_method ((Method) sym);
3315		} else if (sym is Field) {
3316			st.add_field ((Field) sym);
3317		} else if (sym is Constant) {
3318			st.add_constant ((Constant) sym);
3319		} else if (sym is Property) {
3320			st.add_property ((Property) sym);
3321		} else {
3322			Report.error (sym.source_reference, "unexpected declaration in struct");
3323		}
3324	}
3325
3326	Symbol parse_interface_declaration (List<Attribute>? attrs) throws ParseError {
3327		var begin = get_location ();
3328
3329		expect (TokenType.INTERFACE);
3330		var flags = parse_type_declaration_modifiers ();
3331		var sym = parse_symbol_name ();
3332		var type_param_list = parse_type_parameter_list ();
3333		var base_types = new ArrayList<DataType> ();
3334		if (accept (TokenType.COLON)) {
3335			do {
3336				var type = parse_type (true, false);
3337				base_types.add (type);
3338			} while (accept (TokenType.COMMA));
3339		}
3340
3341		var iface = new Interface (sym.name, get_src (begin), comment);
3342		if (ModifierFlags.PRIVATE in flags) {
3343			iface.access = SymbolAccessibility.PRIVATE;
3344		} else if (ModifierFlags.PROTECTED in flags) {
3345			iface.access = SymbolAccessibility.PROTECTED;
3346		} else {
3347			iface.access = get_default_accessibility (sym.name);
3348		}
3349		if (ModifierFlags.EXTERN in flags) {
3350			iface.is_extern = true;
3351		}
3352		set_attributes (iface, attrs);
3353		foreach (TypeParameter type_param in type_param_list) {
3354			iface.add_type_parameter (type_param);
3355		}
3356		foreach (DataType base_type in base_types) {
3357			iface.add_prerequisite (base_type);
3358		}
3359
3360
3361		expect (TokenType.EOL);
3362
3363		parse_declarations (iface);
3364
3365
3366		Symbol result = iface;
3367		while (sym.inner != null) {
3368			sym = sym.inner;
3369			var ns = new Namespace (sym.name, iface.source_reference);
3370			if (result is Namespace) {
3371				ns.add_namespace ((Namespace) result);
3372			} else {
3373				ns.add_interface ((Interface) result);
3374			}
3375			result = ns;
3376		}
3377		return result;
3378	}
3379
3380	void parse_interface_member (Interface iface) throws ParseError {
3381		var sym = parse_declaration ();
3382		if (sym is Class) {
3383			iface.add_class ((Class) sym);
3384		} else if (sym is Struct) {
3385			iface.add_struct ((Struct) sym);
3386		} else if (sym is Enum) {
3387			iface.add_enum ((Enum) sym);
3388		} else if (sym is Delegate) {
3389			iface.add_delegate ((Delegate) sym);
3390		} else if (sym is Method) {
3391			iface.add_method ((Method) sym);
3392		} else if (sym is Vala.Signal) {
3393			iface.add_signal ((Vala.Signal) sym);
3394		} else if (sym is Field) {
3395			iface.add_field ((Field) sym);
3396		} else if (sym is Constant) {
3397			iface.add_constant ((Constant) sym);
3398		} else if (sym is Property) {
3399			iface.add_property ((Property) sym);
3400		} else {
3401			Report.error (sym.source_reference, "unexpected declaration in interface");
3402		}
3403	}
3404
3405	Symbol parse_enum_declaration (List<Attribute>? attrs) throws ParseError {
3406		var begin = get_location ();
3407		expect (TokenType.ENUM);
3408		var flags = parse_type_declaration_modifiers ();
3409
3410		var sym = parse_symbol_name ();
3411		var en = new Enum (sym.name, get_src (begin), comment);
3412		if (ModifierFlags.PRIVATE in flags) {
3413			en.access = SymbolAccessibility.PRIVATE;
3414		} else if (ModifierFlags.PROTECTED in flags) {
3415			en.access = SymbolAccessibility.PROTECTED;
3416		} else {
3417			en.access = get_default_accessibility (sym.name);
3418		}
3419		if (ModifierFlags.EXTERN in flags) {
3420			en.is_extern = true;
3421		}
3422		set_attributes (en, attrs);
3423
3424		expect (TokenType.EOL);
3425		expect (TokenType.INDENT);
3426		do {
3427			if (current () == TokenType.DEDENT && en.get_values ().size > 0) {
3428				// allow trailing comma
3429				break;
3430			}
3431			var value_attrs = parse_attributes (false);
3432			var value_begin = get_location ();
3433			string id = parse_identifier ();
3434			comment = scanner.pop_comment ();
3435
3436			Expression value = null;
3437			if (accept (TokenType.ASSIGN)) {
3438				value = parse_expression ();
3439			}
3440
3441			var ev = new EnumValue (id, value, get_src (value_begin), comment);
3442			ev.access = SymbolAccessibility.PUBLIC;
3443			set_attributes (ev, value_attrs);
3444
3445			en.add_value (ev);
3446			if (expect_separator ()) {
3447				accept (TokenType.EOL);
3448			}
3449		} while (true);
3450
3451		expect (TokenType.DEDENT);
3452
3453		Symbol result = en;
3454		while (sym.inner != null) {
3455			sym = sym.inner;
3456			var ns = new Namespace (sym.name, en.source_reference);
3457			if (result is Namespace) {
3458				ns.add_namespace ((Namespace) result);
3459			} else {
3460				ns.add_enum ((Enum) result);
3461			}
3462			result = ns;
3463		}
3464		return result;
3465	}
3466
3467	Symbol parse_errordomain_declaration (List<Attribute>? attrs) throws ParseError {
3468		var begin = get_location ();
3469		expect (TokenType.ERRORDOMAIN);
3470		var flags = parse_type_declaration_modifiers ();
3471
3472		var sym = parse_symbol_name ();
3473		var ed = new ErrorDomain (sym.name, get_src (begin), comment);
3474		if (ModifierFlags.PRIVATE in flags) {
3475			ed.access = SymbolAccessibility.PRIVATE;
3476		} else if (ModifierFlags.PROTECTED in flags) {
3477			ed.access = SymbolAccessibility.PROTECTED;
3478		} else {
3479			ed.access = get_default_accessibility (sym.name);
3480		}
3481
3482		set_attributes (ed, attrs);
3483
3484		expect (TokenType.EOL);
3485		expect (TokenType.INDENT);
3486
3487		do {
3488			if (current () == TokenType.DEDENT && ed.get_codes ().size > 0) {
3489				// allow trailing comma
3490				break;
3491			}
3492			var code_attrs = parse_attributes (false);
3493			var code_begin = get_location ();
3494			string id = parse_identifier ();
3495			comment = scanner.pop_comment ();
3496			var ec = new ErrorCode (id, get_src (code_begin), comment);
3497			set_attributes (ec, code_attrs);
3498			if (accept (TokenType.ASSIGN)) {
3499				ec.value = parse_expression ();
3500			}
3501			ed.add_code (ec);
3502			accept (TokenType.EOL);
3503		} while (true);
3504
3505
3506		expect (TokenType.DEDENT);
3507
3508		Symbol result = ed;
3509		while (sym.inner != null) {
3510			sym = sym.inner;
3511			var ns = new Namespace (sym.name, ed.source_reference);
3512
3513			if (result is Namespace) {
3514				ns.add_namespace ((Namespace) result);
3515			} else {
3516				ns.add_error_domain ((ErrorDomain) result);
3517			}
3518			result = ns;
3519		}
3520		return result;
3521	}
3522
3523	ModifierFlags parse_type_declaration_modifiers () {
3524		ModifierFlags flags = 0;
3525		while (true) {
3526			switch (current ()) {
3527			case TokenType.ABSTRACT:
3528				next ();
3529				flags |= ModifierFlags.ABSTRACT;
3530				break;
3531
3532			case TokenType.EXTERN:
3533				next ();
3534				flags |= ModifierFlags.EXTERN;
3535				break;
3536
3537			case TokenType.STATIC:
3538				next ();
3539				flags |= ModifierFlags.STATIC;
3540				break;
3541
3542			case TokenType.PRIVATE:
3543				next ();
3544				flags |= ModifierFlags.PRIVATE;
3545				break;
3546
3547			case TokenType.PUBLIC:
3548				next ();
3549				flags |= ModifierFlags.PUBLIC;
3550				break;
3551
3552			case TokenType.PROTECTED:
3553				next ();
3554				flags |= ModifierFlags.PROTECTED;
3555				break;
3556
3557			default:
3558				return flags;
3559			}
3560		}
3561	}
3562
3563	ModifierFlags parse_member_declaration_modifiers () {
3564		ModifierFlags flags = 0;
3565		while (true) {
3566			switch (current ()) {
3567			case TokenType.ABSTRACT:
3568				next ();
3569				flags |= ModifierFlags.ABSTRACT;
3570				break;
3571			case TokenType.ASYNC:
3572				next ();
3573				flags |= ModifierFlags.ASYNC;
3574				break;
3575			case TokenType.CLASS:
3576				next ();
3577				flags |= ModifierFlags.CLASS;
3578				break;
3579			case TokenType.EXTERN:
3580				next ();
3581				flags |= ModifierFlags.EXTERN;
3582				break;
3583			case TokenType.INLINE:
3584				next ();
3585				flags |= ModifierFlags.INLINE;
3586				break;
3587			case TokenType.NEW:
3588				next ();
3589				flags |= ModifierFlags.NEW;
3590				break;
3591			case TokenType.OVERRIDE:
3592				next ();
3593				flags |= ModifierFlags.OVERRIDE;
3594				break;
3595			case TokenType.SEALED:
3596				next ();
3597				flags |= ModifierFlags.SEALED;
3598				break;
3599			case TokenType.STATIC:
3600				next ();
3601				flags |= ModifierFlags.STATIC;
3602				break;
3603			case TokenType.VIRTUAL:
3604				next ();
3605				flags |= ModifierFlags.VIRTUAL;
3606				break;
3607			case TokenType.PRIVATE:
3608				next ();
3609				flags |= ModifierFlags.PRIVATE;
3610				break;
3611			case TokenType.PUBLIC:
3612				next ();
3613				flags |= ModifierFlags.PUBLIC;
3614				break;
3615			case TokenType.PROTECTED:
3616				next ();
3617				flags |= ModifierFlags.PROTECTED;
3618				break;
3619			default:
3620				return flags;
3621			}
3622		}
3623	}
3624
3625	Parameter parse_parameter () throws ParseError {
3626		var attrs = parse_attributes (true);
3627		var begin = get_location ();
3628		if (accept (TokenType.ELLIPSIS)) {
3629			// varargs
3630			return new Parameter.with_ellipsis (get_src (begin));
3631		}
3632		bool params_array = accept (TokenType.PARAMS);
3633		var direction = ParameterDirection.IN;
3634		if (accept (TokenType.OUT)) {
3635			direction = ParameterDirection.OUT;
3636		} else if (accept (TokenType.REF)) {
3637			direction = ParameterDirection.REF;
3638		}
3639
3640		string id = parse_identifier ();
3641
3642		expect (TokenType.COLON);
3643
3644		DataType type;
3645		if (direction == ParameterDirection.IN) {
3646			 type = parse_type (false, false);
3647		} else if (direction == ParameterDirection.REF) {
3648			// ref parameters own the value by default
3649			type = parse_type (true, true);
3650		} else {
3651			// out parameters own the value by default
3652			type = parse_type (true, false);
3653		}
3654
3655		var param = new Parameter (id, type, get_src (begin));
3656		set_attributes (param, attrs);
3657		param.direction = direction;
3658		param.params_array = params_array;
3659		if (accept (TokenType.ASSIGN)) {
3660			param.initializer = parse_expression ();
3661		}
3662		return param;
3663	}
3664
3665	CreationMethod parse_creation_method_declaration (List<Attribute>? attrs) throws ParseError {
3666		var begin = get_location ();
3667		CreationMethod method;
3668
3669		expect (TokenType.CONSTRUCT);
3670		parse_member_declaration_modifiers ();
3671
3672		if (accept (TokenType.OPEN_PARENS)) {
3673			/* create default name using class name */
3674			method = new CreationMethod (class_name, null, get_src (begin), comment);
3675		} else {
3676			var sym = parse_symbol_name ();
3677			if (sym.inner == null) {
3678
3679				if (sym.name != class_name) {
3680					method = new CreationMethod (class_name, sym.name, get_src (begin), comment);
3681				} else {
3682					method = new CreationMethod (sym.name, null, get_src (begin), comment);
3683				}
3684			} else {
3685				method = new CreationMethod (sym.inner.name, sym.name, get_src (begin), comment);
3686			}
3687			expect (TokenType.OPEN_PARENS);
3688		}
3689
3690		if (current () != TokenType.CLOSE_PARENS) {
3691			do {
3692				var param = parse_parameter ();
3693				method.add_parameter (param);
3694			} while (accept (TokenType.COMMA));
3695		}
3696		expect (TokenType.CLOSE_PARENS);
3697		if (accept (TokenType.RAISES)) {
3698			do {
3699				method.add_error_type (parse_type (true, false));
3700			} while (accept (TokenType.COMMA));
3701		}
3702		method.access = SymbolAccessibility.PUBLIC;
3703		set_attributes (method, attrs);
3704
3705		if (accept_block ()) {
3706			method.body = parse_block ();
3707			method.external = false;
3708		}
3709
3710		return method;
3711	}
3712
3713	Symbol parse_delegate_declaration (List<Attribute>? attrs) throws ParseError {
3714		var begin = get_location ();
3715		DataType type;
3716
3717		expect (TokenType.DELEGATE);
3718
3719		var flags = parse_member_declaration_modifiers ();
3720
3721		var sym = parse_symbol_name ();
3722
3723		var type_param_list = parse_type_parameter_list ();
3724
3725		if (ModifierFlags.NEW in flags) {
3726			throw new ParseError.SYNTAX ("`new' modifier not allowed on delegates");
3727		}
3728
3729		var params = new ArrayList<Parameter> ();
3730
3731		expect (TokenType.OPEN_PARENS);
3732		if (current () != TokenType.CLOSE_PARENS) {
3733			do {
3734				var param = parse_parameter ();
3735				params.add (param);
3736			} while (accept (TokenType.COMMA));
3737		}
3738		expect (TokenType.CLOSE_PARENS);
3739
3740		if (accept (TokenType.COLON)) {
3741			type = parse_type (true, false);
3742		} else {
3743			type = new VoidType ();
3744		}
3745
3746		var d = new Delegate (sym.name, type, get_src (begin), comment);
3747
3748		if (accept (TokenType.RAISES)) {
3749			do {
3750				d.add_error_type (parse_type (true, false));
3751			} while (accept (TokenType.COMMA));
3752		}
3753
3754		expect_terminator ();
3755
3756
3757		if (ModifierFlags.PRIVATE in flags) {
3758			d.access = SymbolAccessibility.PRIVATE;
3759		} else if (ModifierFlags.PROTECTED in flags) {
3760			d.access = SymbolAccessibility.PROTECTED;
3761		} else {
3762			d.access = get_default_accessibility (sym.name);
3763		}
3764
3765		if (ModifierFlags.STATIC in flags) {
3766			d.has_target = false;
3767		}
3768		if (ModifierFlags.EXTERN in flags) {
3769			d.is_extern = true;
3770		}
3771
3772		set_attributes (d, attrs);
3773
3774		foreach (TypeParameter type_param in type_param_list) {
3775			d.add_type_parameter (type_param);
3776		}
3777
3778		foreach (Parameter formal_param in params) {
3779			d.add_parameter (formal_param);
3780		}
3781
3782
3783
3784		Symbol result = d;
3785		while (sym.inner != null) {
3786			sym = sym.inner;
3787			var ns = new Namespace (sym.name, d.source_reference);
3788
3789			if (result is Namespace) {
3790				ns.add_namespace ((Namespace) result);
3791			} else {
3792				ns.add_delegate ((Delegate) result);
3793			}
3794			result = ns;
3795		}
3796		return result;
3797	}
3798
3799	List<TypeParameter> parse_type_parameter_list () throws ParseError {
3800		if (accept (TokenType.OF)) {
3801			var list = new ArrayList<TypeParameter> ();
3802			do {
3803				var begin = get_location ();
3804				string id = parse_identifier ();
3805				list.add (new TypeParameter (id, get_src (begin)));
3806			} while (accept (TokenType.COMMA));
3807			return list;
3808		} else {
3809			if (_empty_type_parameter_list == null) {
3810				_empty_type_parameter_list = new ArrayList<TypeParameter> ();
3811			}
3812			return _empty_type_parameter_list;
3813		}
3814	}
3815
3816	void skip_type_argument_list () throws ParseError {
3817		if (accept (TokenType.OF)) {
3818			if (accept (TokenType.OPEN_PARENS)) {
3819				do {
3820					skip_type ();
3821				} while (accept (TokenType.COMMA));
3822				expect (TokenType.CLOSE_PARENS);
3823			} else {
3824				do {
3825					skip_type ();
3826				} while (accept (TokenType.COMMA));
3827			}
3828		}
3829	}
3830
3831
3832	// try to parse type argument list
3833	List<DataType>? parse_type_argument_list (bool maybe_expression) throws ParseError {
3834		var begin = get_location ();
3835		if (accept (TokenType.OF)) {
3836			var list = new ArrayList<DataType> ();
3837			var inParens = false;
3838
3839			// Optional parens allow multi arg types in function signature: "dict of (int, string)"
3840			// See: https://bugzilla.gnome.org/show_bug.cgi?id=611191
3841			if (accept (TokenType.OPEN_PARENS)) {
3842				inParens = true;
3843			}
3844
3845			do {
3846				switch (current ()) {
3847				case TokenType.VOID:
3848				case TokenType.DYNAMIC:
3849				case TokenType.UNOWNED:
3850				case TokenType.WEAK:
3851				case TokenType.IDENTIFIER:
3852					var type = parse_type (true, true);
3853
3854					list.add (type);
3855					break;
3856				default:
3857					rollback (begin);
3858					return null;
3859				}
3860			} while (accept (TokenType.COMMA));
3861
3862			if (inParens) {
3863				expect (TokenType.CLOSE_PARENS);
3864			}
3865
3866			return list;
3867		}
3868		return null;
3869	}
3870
3871	MemberAccess parse_member_name (Expression? base_expr = null) throws ParseError {
3872		var begin = get_location ();
3873		MemberAccess expr = null;
3874		do {
3875			string id = parse_identifier ();
3876			List<DataType> type_arg_list = parse_type_argument_list (false);
3877			expr = new MemberAccess (expr != null ? expr : base_expr, id, get_src (begin));
3878			if (type_arg_list != null) {
3879				foreach (DataType type_arg in type_arg_list) {
3880					expr.add_type_argument (type_arg);
3881				}
3882			}
3883		} while (accept (TokenType.DOT));
3884		return expr;
3885	}
3886}
3887
3888