~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to contrib/ICSharpCode.NRefactory.CSharp/Parser/mcs/cs-tokenizer.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
//
2
 
// cs-tokenizer.cs: The Tokenizer for the C# compiler
3
 
//                  This also implements the preprocessor
4
 
//
5
 
// Author: Miguel de Icaza (miguel@gnu.org)
6
 
//         Marek Safar (marek.safar@gmail.com)
7
 
//
8
 
// Dual licensed under the terms of the MIT X11 or GNU GPL
9
 
//
10
 
// Copyright 2001, 2002 Ximian, Inc (http://www.ximian.com)
11
 
// Copyright 2004-2008 Novell, Inc
12
 
// Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
13
 
//
14
 
using System;
15
 
using System.Text;
16
 
using System.Collections.Generic;
17
 
using System.Globalization;
18
 
using System.Diagnostics;
19
 
 
20
 
namespace Mono.CSharp
21
 
{
22
 
        /// <summary>
23
 
        ///    Tokenizer for C# source code. 
24
 
        /// </summary>
25
 
        public class Tokenizer : yyParser.yyInput
26
 
        {
27
 
                class KeywordEntry<T>
28
 
                {
29
 
                        public readonly T Token;
30
 
                        public KeywordEntry<T> Next;
31
 
                        public readonly char[] Value;
32
 
 
33
 
                        public KeywordEntry (string value,T token)
34
 
                        {
35
 
                                this.Value = value.ToCharArray ();
36
 
                                this.Token = token;
37
 
                        }
38
 
                }
39
 
 
40
 
                sealed class IdentifiersComparer : IEqualityComparer<char[]>
41
 
                {
42
 
                        readonly int length;
43
 
 
44
 
                        public IdentifiersComparer (int length)
45
 
                        {
46
 
                                this.length = length;
47
 
                        }
48
 
 
49
 
                        public bool Equals (char[] x, char[] y)
50
 
                        {
51
 
                                for (int i = 0; i < length; ++i)
52
 
                                        if (x [i] != y [i])
53
 
                                                return false;
54
 
 
55
 
                                return true;
56
 
                        }
57
 
 
58
 
                        public int GetHashCode (char[] obj)
59
 
                        {
60
 
                                int h = 0;
61
 
                                for (int i = 0; i < length; ++i)
62
 
                                        h = (h << 5) - h + obj [i];
63
 
 
64
 
                                return h;
65
 
                        }
66
 
                }
67
 
 
68
 
                //
69
 
                // This class has to be used in the parser only, it reuses token
70
 
                // details after each parse
71
 
                //
72
 
                public class LocatedToken
73
 
                {
74
 
                        int row, column;
75
 
                        string value;
76
 
 
77
 
                        static LocatedToken[] buffer = new LocatedToken[0];
78
 
                        static int pos;
79
 
 
80
 
                        private LocatedToken ()
81
 
                        {
82
 
                        }
83
 
 
84
 
                        public static LocatedToken Create (int row, int column)
85
 
                        {
86
 
                                return Create (null, row, column);
87
 
                        }
88
 
 
89
 
                        public static LocatedToken Create (string value, Location loc)
90
 
                        {
91
 
                                return Create (value, loc.Row, loc.Column);
92
 
                        }
93
 
                        
94
 
                        public static LocatedToken Create (string value, int row, int column)
95
 
                        {
96
 
                                //
97
 
                                // TODO: I am not very happy about the logic but it's the best
98
 
                                // what I could come up with for now.
99
 
                                // Ideally we should be using just tiny buffer (256 elements) which
100
 
                                // is enough to hold all details for currect stack and recycle elements
101
 
                                // poped from the stack but there is a trick needed to recycle
102
 
                                // them properly.
103
 
                                //
104
 
                                LocatedToken entry;
105
 
                                if (pos >= buffer.Length) {
106
 
                                        entry = new LocatedToken ();
107
 
                                } else {
108
 
                                        entry = buffer [pos];
109
 
                                        if (entry == null) {
110
 
                                                entry = new LocatedToken ();
111
 
                                                buffer [pos] = entry;
112
 
                                        }
113
 
 
114
 
                                        ++pos;
115
 
                                }
116
 
                                entry.value = value;
117
 
                                entry.row = row;
118
 
                                entry.column = column;
119
 
                                return entry;
120
 
                        }
121
 
 
122
 
                        //
123
 
                        // Used for token not required by expression evaluator
124
 
                        //
125
 
                        [Conditional ("FULL_AST")]
126
 
                        public static void CreateOptional (int row, int col, ref object token)
127
 
                        {
128
 
                                token = Create (row, col);
129
 
                        }
130
 
 
131
 
                        public static void Initialize ()
132
 
                        {
133
 
#if !FULL_AST
134
 
                                if (buffer.Length == 0)
135
 
                                        buffer = new LocatedToken [15000];
136
 
#endif
137
 
                                pos = 0;
138
 
                        }
139
 
 
140
 
                        public override string ToString ()
141
 
                        {
142
 
                                return string.Format ("Token '{0}' at {1},{2}", Value, row, column);
143
 
                        }
144
 
                        
145
 
                        public Location Location {
146
 
                                get { return new Location (row, column); }
147
 
                        }
148
 
 
149
 
                        public string Value {
150
 
                                get { return value; }
151
 
                        }
152
 
                }
153
 
 
154
 
                public enum PreprocessorDirective
155
 
                {
156
 
                        Invalid = 0,
157
 
 
158
 
                        Region = 1,
159
 
                        Endregion = 2,
160
 
                        If = 3 | RequiresArgument,
161
 
                        Endif = 4,
162
 
                        Elif = 5 | RequiresArgument,
163
 
                        Else = 6,
164
 
                        Define = 7 | RequiresArgument,
165
 
                        Undef = 8 | RequiresArgument,
166
 
                        Error = 9,
167
 
                        Warning = 10,
168
 
                        Pragma = 11 | CustomArgumentsParsing,
169
 
                        Line = 12 | CustomArgumentsParsing,
170
 
 
171
 
                        CustomArgumentsParsing = 1 << 10,
172
 
                        RequiresArgument = 1 << 11
173
 
                }
174
 
 
175
 
                readonly SeekableStreamReader reader;
176
 
                readonly CompilationSourceFile source_file;
177
 
                readonly CompilerContext context;
178
 
 
179
 
                SourceFile current_source;
180
 
                Location hidden_block_start;
181
 
                int ref_line = 1;
182
 
                int line = 1;
183
 
                int col = 0;
184
 
                int previous_col;
185
 
                int current_token;
186
 
                readonly int tab_size;
187
 
                bool handle_get_set = false;
188
 
                bool handle_remove_add = false;
189
 
                bool handle_where = false;
190
 
                bool handle_typeof = false;
191
 
                bool lambda_arguments_parsing;
192
 
                List<Location> escaped_identifiers;
193
 
                int parsing_generic_less_than;
194
 
                readonly bool doc_processing;
195
 
                
196
 
                //
197
 
                // Used mainly for parser optimizations. Some expressions for instance
198
 
                // can appear only in block (including initializer, base initializer)
199
 
                // scope only
200
 
                //
201
 
                public int parsing_block;
202
 
                internal bool query_parsing;
203
 
                
204
 
                // 
205
 
                // When parsing type only, useful for ambiguous nullable types
206
 
                //
207
 
                public int parsing_type;
208
 
                
209
 
                //
210
 
                // Set when parsing generic declaration (type or method header)
211
 
                //
212
 
                public bool parsing_generic_declaration;
213
 
                public bool parsing_generic_declaration_doc;
214
 
                
215
 
                //
216
 
                // The value indicates that we have not reach any declaration or
217
 
                // namespace yet
218
 
                //
219
 
                public int parsing_declaration;
220
 
                public bool parsing_attribute_section;
221
 
 
222
 
                public bool parsing_modifiers;
223
 
 
224
 
                //
225
 
                // The special characters to inject on streams to run the unit parser
226
 
                // in the special expression mode. Using private characters from
227
 
                // Plane Sixteen (U+100000 to U+10FFFD)
228
 
                //
229
 
                // This character is only tested just before the tokenizer is about to report
230
 
                // an error;   So on the regular operation mode, this addition will have no
231
 
                // impact on the tokenizer's performance.
232
 
                //
233
 
                
234
 
                public const int EvalStatementParserCharacter = 0x100000;
235
 
                public const int EvalCompilationUnitParserCharacter = 0x100001;
236
 
                public const int EvalUsingDeclarationsParserCharacter = 0x100002;
237
 
                public const int DocumentationXref = 0x100003;
238
 
                
239
 
                //
240
 
                // XML documentation buffer. The save point is used to divide
241
 
                // comments on types and comments on members.
242
 
                //
243
 
                StringBuilder xml_comment_buffer;
244
 
 
245
 
                //
246
 
                // See comment on XmlCommentState enumeration.
247
 
                //
248
 
                XmlCommentState xml_doc_state = XmlCommentState.Allowed;
249
 
 
250
 
                //
251
 
                // Whether tokens have been seen on this line
252
 
                //
253
 
                bool tokens_seen = false;
254
 
 
255
 
                //
256
 
                // Set to true once the GENERATE_COMPLETION token has bee
257
 
                // returned.   This helps produce one GENERATE_COMPLETION,
258
 
                // as many COMPLETE_COMPLETION as necessary to complete the
259
 
                // AST tree and one final EOF.
260
 
                //
261
 
                bool generated;
262
 
                
263
 
                //
264
 
                // Whether a token has been seen on the file
265
 
                // This is needed because `define' is not allowed to be used
266
 
                // after a token has been seen.
267
 
                //
268
 
                bool any_token_seen;
269
 
 
270
 
                //
271
 
                // Class variables
272
 
                // 
273
 
                static readonly KeywordEntry<int>[][] keywords;
274
 
                static readonly KeywordEntry<PreprocessorDirective>[][] keywords_preprocessor;
275
 
                static readonly HashSet<string> keyword_strings;
276
 
                static readonly NumberStyles styles;
277
 
                static readonly NumberFormatInfo csharp_format_info;
278
 
 
279
 
                // Pragma arguments
280
 
                static readonly char[] pragma_warning = "warning".ToCharArray ();
281
 
                static readonly char[] pragma_warning_disable = "disable".ToCharArray ();
282
 
                static readonly char[] pragma_warning_restore = "restore".ToCharArray ();
283
 
                static readonly char[] pragma_checksum = "checksum".ToCharArray ();
284
 
                static readonly char[] line_hidden = "hidden".ToCharArray ();
285
 
                static readonly char[] line_default = "default".ToCharArray ();
286
 
 
287
 
                static readonly char[] simple_whitespaces = new char[] { ' ', '\t' };
288
 
                bool startsLine = true;
289
 
                internal SpecialsBag sbag;
290
 
 
291
 
                public bool PropertyParsing {
292
 
                        get { return handle_get_set; }
293
 
                        set { handle_get_set = value; }
294
 
                }
295
 
 
296
 
                public bool EventParsing {
297
 
                        get { return handle_remove_add; }
298
 
                        set { handle_remove_add = value; }
299
 
                }
300
 
 
301
 
                public bool ConstraintsParsing {
302
 
                        get { return handle_where; }
303
 
                        set { handle_where = value; }
304
 
                }
305
 
 
306
 
                public bool TypeOfParsing {
307
 
                        get { return handle_typeof; }
308
 
                        set { handle_typeof = value; }
309
 
                }
310
 
        
311
 
                public XmlCommentState doc_state {
312
 
                        get { return xml_doc_state; }
313
 
                        set {
314
 
                                if (value == XmlCommentState.Allowed) {
315
 
                                        check_incorrect_doc_comment ();
316
 
                                        reset_doc_comment ();
317
 
                                }
318
 
                                xml_doc_state = value;
319
 
                        }
320
 
                }
321
 
 
322
 
                //
323
 
                // This is used to trigger completion generation on the parser
324
 
                public bool CompleteOnEOF;
325
 
 
326
 
                void AddEscapedIdentifier (Location loc)
327
 
                {
328
 
                        if (escaped_identifiers == null)
329
 
                                escaped_identifiers = new List<Location> ();
330
 
 
331
 
                        escaped_identifiers.Add (loc);
332
 
                }
333
 
 
334
 
                public bool IsEscapedIdentifier (ATypeNameExpression name)
335
 
                {
336
 
                        return escaped_identifiers != null && escaped_identifiers.Contains (name.Location);
337
 
                }
338
 
 
339
 
                //
340
 
                // Values for the associated token returned
341
 
                //
342
 
                internal int putback_char;      // Used by repl only
343
 
                object val;
344
 
 
345
 
                //
346
 
                // Pre-processor
347
 
                //
348
 
                const int TAKING        = 1;
349
 
                const int ELSE_SEEN = 4;
350
 
                const int PARENT_TAKING = 8;
351
 
                const int REGION = 16;          
352
 
 
353
 
                //
354
 
                // pre-processor if stack state:
355
 
                //
356
 
                Stack<int> ifstack;
357
 
 
358
 
                const int max_id_size = 512;
359
 
                const int max_number_size = 512;
360
 
 
361
 
#if FULL_AST
362
 
                readonly char [] id_builder = new char [max_id_size];
363
 
 
364
 
                Dictionary<char[], string>[] identifiers = new Dictionary<char[], string>[max_id_size + 1];
365
 
 
366
 
                char [] number_builder = new char [max_number_size];
367
 
                int number_pos;
368
 
 
369
 
                char[] value_builder = new char[256];
370
 
#else
371
 
                static readonly char [] id_builder = new char [max_id_size];
372
 
 
373
 
                static Dictionary<char[], string>[] identifiers = new Dictionary<char[], string>[max_id_size + 1];
374
 
 
375
 
                static char [] number_builder = new char [max_number_size];
376
 
                static int number_pos;
377
 
                static char[] value_builder = new char[256];
378
 
#endif
379
 
 
380
 
                public int Line {
381
 
                        get {
382
 
                                return ref_line;
383
 
                        }
384
 
                        set {
385
 
                                ref_line = value;
386
 
                        }
387
 
                }
388
 
 
389
 
                //
390
 
                // This is used when the tokenizer needs to save
391
 
                // the current position as it needs to do some parsing
392
 
                // on its own to deamiguate a token in behalf of the
393
 
                // parser.
394
 
                //
395
 
                Stack<Position> position_stack = new Stack<Position> (2);
396
 
 
397
 
                class Position
398
 
                {
399
 
                        public int position;
400
 
                        public int line;
401
 
                        public int ref_line;
402
 
                        public int col;
403
 
                        public Location hidden;
404
 
                        public int putback_char;
405
 
                        public int previous_col;
406
 
                        public Stack<int> ifstack;
407
 
                        public int parsing_generic_less_than;
408
 
                        public int current_token;
409
 
                        public object val;
410
 
 
411
 
                        public Position (Tokenizer t)
412
 
                        {
413
 
                                position = t.reader.Position;
414
 
                                line = t.line;
415
 
                                ref_line = t.ref_line;
416
 
                                col = t.col;
417
 
                                hidden = t.hidden_block_start;
418
 
                                putback_char = t.putback_char;
419
 
                                previous_col = t.previous_col;
420
 
                                if (t.ifstack != null && t.ifstack.Count != 0) {
421
 
                                        // There is no simple way to clone Stack<T> all
422
 
                                        // methods reverse the order
423
 
                                        var clone = t.ifstack.ToArray ();
424
 
                                        Array.Reverse (clone);
425
 
                                        ifstack = new Stack<int> (clone);
426
 
                                }
427
 
                                parsing_generic_less_than = t.parsing_generic_less_than;
428
 
                                current_token = t.current_token;
429
 
                                val = t.val;
430
 
                        }
431
 
                }
432
 
 
433
 
                public Tokenizer (SeekableStreamReader input, CompilationSourceFile file)
434
 
                {
435
 
                        this.source_file = file;
436
 
                        this.context = file.Compiler;
437
 
                        this.current_source = file.SourceFile;
438
 
 
439
 
                        reader = input;
440
 
 
441
 
                        putback_char = -1;
442
 
 
443
 
                        xml_comment_buffer = new StringBuilder ();
444
 
                        doc_processing = context.Settings.DocumentationFile != null;
445
 
 
446
 
                        tab_size = context.Settings.TabSize;
447
 
 
448
 
                        Mono.CSharp.Location.Push (current_source);
449
 
                }
450
 
                
451
 
                public void PushPosition ()
452
 
                {
453
 
                        position_stack.Push (new Position (this));
454
 
                }
455
 
 
456
 
                public void PopPosition ()
457
 
                {
458
 
                        Position p = position_stack.Pop ();
459
 
 
460
 
                        reader.Position = p.position;
461
 
                        ref_line = p.ref_line;
462
 
                        line = p.line;
463
 
                        col = p.col;
464
 
                        hidden_block_start = p.hidden;
465
 
                        putback_char = p.putback_char;
466
 
                        previous_col = p.previous_col;
467
 
                        ifstack = p.ifstack;
468
 
                        parsing_generic_less_than = p.parsing_generic_less_than;
469
 
                        current_token = p.current_token;
470
 
                        val = p.val;
471
 
                }
472
 
 
473
 
                // Do not reset the position, ignore it.
474
 
                public void DiscardPosition ()
475
 
                {
476
 
                        position_stack.Pop ();
477
 
        }
478
 
                
479
 
                static void AddKeyword (string kw, int token)
480
 
                {
481
 
                        keyword_strings.Add (kw);
482
 
 
483
 
                        AddKeyword (keywords, kw, token);
484
 
}
485
 
 
486
 
                static void AddPreprocessorKeyword (string kw, PreprocessorDirective directive)
487
 
                {
488
 
                        AddKeyword (keywords_preprocessor, kw, directive);
489
 
                }
490
 
 
491
 
                static void AddKeyword<T> (KeywordEntry<T>[][] keywords, string kw, T token)
492
 
                {
493
 
                        int length = kw.Length;
494
 
                        if (keywords[length] == null) {
495
 
                                keywords[length] = new KeywordEntry<T>['z' - '_' + 1];
496
 
                        }
497
 
 
498
 
                        int char_index = kw[0] - '_';
499
 
                        var kwe = keywords[length][char_index];
500
 
                        if (kwe == null) {
501
 
                                keywords[length][char_index] = new KeywordEntry<T> (kw, token);
502
 
                                return;
503
 
                        }
504
 
 
505
 
                        while (kwe.Next != null) {
506
 
                                kwe = kwe.Next;
507
 
                        }
508
 
 
509
 
                        kwe.Next = new KeywordEntry<T> (kw, token);
510
 
                }
511
 
 
512
 
                //
513
 
                // Class initializer
514
 
                // 
515
 
                static Tokenizer ()
516
 
                {
517
 
                        keyword_strings = new HashSet<string> ();
518
 
 
519
 
                        // 11 is the length of the longest keyword for now
520
 
                        keywords = new KeywordEntry<int>[11][];
521
 
 
522
 
                        AddKeyword ("__arglist", Token.ARGLIST);
523
 
                        AddKeyword ("__makeref", Token.MAKEREF);
524
 
                        AddKeyword ("__reftype", Token.REFTYPE);
525
 
                        AddKeyword ("__refvalue", Token.REFVALUE);
526
 
                        AddKeyword ("abstract", Token.ABSTRACT);
527
 
                        AddKeyword ("as", Token.AS);
528
 
                        AddKeyword ("add", Token.ADD);
529
 
                        AddKeyword ("base", Token.BASE);
530
 
                        AddKeyword ("bool", Token.BOOL);
531
 
                        AddKeyword ("break", Token.BREAK);
532
 
                        AddKeyword ("byte", Token.BYTE);
533
 
                        AddKeyword ("case", Token.CASE);
534
 
                        AddKeyword ("catch", Token.CATCH);
535
 
                        AddKeyword ("char", Token.CHAR);
536
 
                        AddKeyword ("checked", Token.CHECKED);
537
 
                        AddKeyword ("class", Token.CLASS);
538
 
                        AddKeyword ("const", Token.CONST);
539
 
                        AddKeyword ("continue", Token.CONTINUE);
540
 
                        AddKeyword ("decimal", Token.DECIMAL);
541
 
                        AddKeyword ("default", Token.DEFAULT);
542
 
                        AddKeyword ("delegate", Token.DELEGATE);
543
 
                        AddKeyword ("do", Token.DO);
544
 
                        AddKeyword ("double", Token.DOUBLE);
545
 
                        AddKeyword ("else", Token.ELSE);
546
 
                        AddKeyword ("enum", Token.ENUM);
547
 
                        AddKeyword ("event", Token.EVENT);
548
 
                        AddKeyword ("explicit", Token.EXPLICIT);
549
 
                        AddKeyword ("extern", Token.EXTERN);
550
 
                        AddKeyword ("false", Token.FALSE);
551
 
                        AddKeyword ("finally", Token.FINALLY);
552
 
                        AddKeyword ("fixed", Token.FIXED);
553
 
                        AddKeyword ("float", Token.FLOAT);
554
 
                        AddKeyword ("for", Token.FOR);
555
 
                        AddKeyword ("foreach", Token.FOREACH);
556
 
                        AddKeyword ("goto", Token.GOTO);
557
 
                        AddKeyword ("get", Token.GET);
558
 
                        AddKeyword ("if", Token.IF);
559
 
                        AddKeyword ("implicit", Token.IMPLICIT);
560
 
                        AddKeyword ("in", Token.IN);
561
 
                        AddKeyword ("int", Token.INT);
562
 
                        AddKeyword ("interface", Token.INTERFACE);
563
 
                        AddKeyword ("internal", Token.INTERNAL);
564
 
                        AddKeyword ("is", Token.IS);
565
 
                        AddKeyword ("lock", Token.LOCK);
566
 
                        AddKeyword ("long", Token.LONG);
567
 
                        AddKeyword ("namespace", Token.NAMESPACE);
568
 
                        AddKeyword ("new", Token.NEW);
569
 
                        AddKeyword ("null", Token.NULL);
570
 
                        AddKeyword ("object", Token.OBJECT);
571
 
                        AddKeyword ("operator", Token.OPERATOR);
572
 
                        AddKeyword ("out", Token.OUT);
573
 
                        AddKeyword ("override", Token.OVERRIDE);
574
 
                        AddKeyword ("params", Token.PARAMS);
575
 
                        AddKeyword ("private", Token.PRIVATE);
576
 
                        AddKeyword ("protected", Token.PROTECTED);
577
 
                        AddKeyword ("public", Token.PUBLIC);
578
 
                        AddKeyword ("readonly", Token.READONLY);
579
 
                        AddKeyword ("ref", Token.REF);
580
 
                        AddKeyword ("remove", Token.REMOVE);
581
 
                        AddKeyword ("return", Token.RETURN);
582
 
                        AddKeyword ("sbyte", Token.SBYTE);
583
 
                        AddKeyword ("sealed", Token.SEALED);
584
 
                        AddKeyword ("set", Token.SET);
585
 
                        AddKeyword ("short", Token.SHORT);
586
 
                        AddKeyword ("sizeof", Token.SIZEOF);
587
 
                        AddKeyword ("stackalloc", Token.STACKALLOC);
588
 
                        AddKeyword ("static", Token.STATIC);
589
 
                        AddKeyword ("string", Token.STRING);
590
 
                        AddKeyword ("struct", Token.STRUCT);
591
 
                        AddKeyword ("switch", Token.SWITCH);
592
 
                        AddKeyword ("this", Token.THIS);
593
 
                        AddKeyword ("throw", Token.THROW);
594
 
                        AddKeyword ("true", Token.TRUE);
595
 
                        AddKeyword ("try", Token.TRY);
596
 
                        AddKeyword ("typeof", Token.TYPEOF);
597
 
                        AddKeyword ("uint", Token.UINT);
598
 
                        AddKeyword ("ulong", Token.ULONG);
599
 
                        AddKeyword ("unchecked", Token.UNCHECKED);
600
 
                        AddKeyword ("unsafe", Token.UNSAFE);
601
 
                        AddKeyword ("ushort", Token.USHORT);
602
 
                        AddKeyword ("using", Token.USING);
603
 
                        AddKeyword ("virtual", Token.VIRTUAL);
604
 
                        AddKeyword ("void", Token.VOID);
605
 
                        AddKeyword ("volatile", Token.VOLATILE);
606
 
                        AddKeyword ("while", Token.WHILE);
607
 
                        AddKeyword ("partial", Token.PARTIAL);
608
 
                        AddKeyword ("where", Token.WHERE);
609
 
 
610
 
                        // LINQ keywords
611
 
                        AddKeyword ("from", Token.FROM);
612
 
                        AddKeyword ("join", Token.JOIN);
613
 
                        AddKeyword ("on", Token.ON);
614
 
                        AddKeyword ("equals", Token.EQUALS);
615
 
                        AddKeyword ("select", Token.SELECT);
616
 
                        AddKeyword ("group", Token.GROUP);
617
 
                        AddKeyword ("by", Token.BY);
618
 
                        AddKeyword ("let", Token.LET);
619
 
                        AddKeyword ("orderby", Token.ORDERBY);
620
 
                        AddKeyword ("ascending", Token.ASCENDING);
621
 
                        AddKeyword ("descending", Token.DESCENDING);
622
 
                        AddKeyword ("into", Token.INTO);
623
 
 
624
 
                        // Contextual async keywords
625
 
                        AddKeyword ("async", Token.ASYNC);
626
 
                        AddKeyword ("await", Token.AWAIT);
627
 
 
628
 
                        keywords_preprocessor = new KeywordEntry<PreprocessorDirective>[10][];
629
 
 
630
 
                        AddPreprocessorKeyword ("region", PreprocessorDirective.Region);
631
 
                        AddPreprocessorKeyword ("endregion", PreprocessorDirective.Endregion);
632
 
                        AddPreprocessorKeyword ("if", PreprocessorDirective.If);
633
 
                        AddPreprocessorKeyword ("endif", PreprocessorDirective.Endif);
634
 
                        AddPreprocessorKeyword ("elif", PreprocessorDirective.Elif);
635
 
                        AddPreprocessorKeyword ("else", PreprocessorDirective.Else);
636
 
                        AddPreprocessorKeyword ("define", PreprocessorDirective.Define);
637
 
                        AddPreprocessorKeyword ("undef", PreprocessorDirective.Undef);
638
 
                        AddPreprocessorKeyword ("error", PreprocessorDirective.Error);
639
 
                        AddPreprocessorKeyword ("warning", PreprocessorDirective.Warning);
640
 
                        AddPreprocessorKeyword ("pragma", PreprocessorDirective.Pragma);
641
 
                        AddPreprocessorKeyword ("line", PreprocessorDirective.Line);
642
 
 
643
 
                        csharp_format_info = NumberFormatInfo.InvariantInfo;
644
 
                        styles = NumberStyles.Float;
645
 
                }
646
 
 
647
 
                int GetKeyword (char[] id, int id_len)
648
 
                {
649
 
                        //
650
 
                        // Keywords are stored in an array of arrays grouped by their
651
 
                        // length and then by the first character
652
 
                        //
653
 
                        if (id_len >= keywords.Length || keywords [id_len] == null)
654
 
                                return -1;
655
 
 
656
 
                        int first_index = id [0] - '_';
657
 
                        if (first_index > 'z' - '_')
658
 
                                return -1;
659
 
 
660
 
                        var kwe = keywords [id_len] [first_index];
661
 
                        if (kwe == null)
662
 
                                return -1;
663
 
 
664
 
                        int res;
665
 
                        do {
666
 
                                res = kwe.Token;
667
 
                                for (int i = 1; i < id_len; ++i) {
668
 
                                        if (id [i] != kwe.Value [i]) {
669
 
                                                res = 0;
670
 
                                                kwe = kwe.Next;
671
 
                                                break;
672
 
                                        }
673
 
                                }
674
 
                        } while (res == 0 && kwe != null);
675
 
 
676
 
                        if (res == 0)
677
 
                                return -1;
678
 
 
679
 
                        int next_token;
680
 
                        switch (res) {
681
 
                        case Token.GET:
682
 
                        case Token.SET:
683
 
                                if (!handle_get_set)
684
 
                                        res = -1;
685
 
                                break;
686
 
                        case Token.REMOVE:
687
 
                        case Token.ADD:
688
 
                                if (!handle_remove_add)
689
 
                                        res = -1;
690
 
                                break;
691
 
                        case Token.EXTERN:
692
 
                                if (parsing_declaration == 0)
693
 
                                        res = Token.EXTERN_ALIAS;
694
 
                                break;
695
 
                        case Token.DEFAULT:
696
 
                                if (peek_token () == Token.COLON) {
697
 
                                        token ();
698
 
                                        res = Token.DEFAULT_COLON;
699
 
                                }
700
 
                                break;
701
 
                        case Token.WHERE:
702
 
                                if (!handle_where && !query_parsing)
703
 
                                        res = -1;
704
 
                                break;
705
 
                        case Token.FROM:
706
 
                                //
707
 
                                // A query expression is any expression that starts with `from identifier'
708
 
                                // followed by any token except ; , =
709
 
                                // 
710
 
                                if (!query_parsing) {
711
 
                                        if (lambda_arguments_parsing) {
712
 
                                                res = -1;
713
 
                                                break;
714
 
                                        }
715
 
 
716
 
                                        PushPosition ();
717
 
                                        // HACK: to disable generics micro-parser, because PushPosition does not
718
 
                                        // store identifiers array
719
 
                                        parsing_generic_less_than = 1;
720
 
                                        switch (xtoken ()) {
721
 
                                        case Token.IDENTIFIER:
722
 
                                        case Token.INT:
723
 
                                        case Token.BOOL:
724
 
                                        case Token.BYTE:
725
 
                                        case Token.CHAR:
726
 
                                        case Token.DECIMAL:
727
 
                                        case Token.FLOAT:
728
 
                                        case Token.LONG:
729
 
                                        case Token.OBJECT:
730
 
                                        case Token.STRING:
731
 
                                        case Token.UINT:
732
 
                                        case Token.ULONG:
733
 
                                                next_token = xtoken ();
734
 
                                                if (next_token == Token.SEMICOLON || next_token == Token.COMMA || next_token == Token.EQUALS)
735
 
                                                        goto default;
736
 
                                                
737
 
                                                res = Token.FROM_FIRST;
738
 
                                                query_parsing = true;
739
 
                                                if (context.Settings.Version <= LanguageVersion.ISO_2)
740
 
                                                        Report.FeatureIsNotAvailable (context, Location, "query expressions");
741
 
                                                break;
742
 
                                        case Token.VOID:
743
 
                                                Expression.Error_VoidInvalidInTheContext (Location, Report);
744
 
                                                break;
745
 
                                        default:
746
 
                                                PopPosition ();
747
 
                                                // HACK: A token is not a keyword so we need to restore identifiers buffer
748
 
                                                // which has been overwritten before we grabbed the identifier
749
 
                                                id_builder [0] = 'f'; id_builder [1] = 'r'; id_builder [2] = 'o'; id_builder [3] = 'm';
750
 
                                                return -1;
751
 
                                        }
752
 
                                        PopPosition ();
753
 
                                }
754
 
                                break;
755
 
                        case Token.JOIN:
756
 
                        case Token.ON:
757
 
                        case Token.EQUALS:
758
 
                        case Token.SELECT:
759
 
                        case Token.GROUP:
760
 
                        case Token.BY:
761
 
                        case Token.LET:
762
 
                        case Token.ORDERBY:
763
 
                        case Token.ASCENDING:
764
 
                        case Token.DESCENDING:
765
 
                        case Token.INTO:
766
 
                                if (!query_parsing)
767
 
                                        res = -1;
768
 
                                break;
769
 
                                
770
 
                        case Token.USING:
771
 
                        case Token.NAMESPACE:
772
 
                                // TODO: some explanation needed
773
 
                                check_incorrect_doc_comment ();
774
 
                                break;
775
 
                                
776
 
                        case Token.PARTIAL:
777
 
                                if (parsing_block > 0) {
778
 
                                        res = -1;
779
 
                                        break;
780
 
                                }
781
 
 
782
 
                                // Save current position and parse next token.
783
 
                                PushPosition ();
784
 
 
785
 
                                next_token = token ();
786
 
                                bool ok = (next_token == Token.CLASS) ||
787
 
                                        (next_token == Token.STRUCT) ||
788
 
                                        (next_token == Token.INTERFACE) ||
789
 
                                        (next_token == Token.VOID);
790
 
 
791
 
                                PopPosition ();
792
 
 
793
 
                                if (ok) {
794
 
                                        if (next_token == Token.VOID) {
795
 
                                                if (context.Settings.Version <= LanguageVersion.ISO_2)
796
 
                                                        Report.FeatureIsNotAvailable (context, Location, "partial methods");
797
 
                                        } else if (context.Settings.Version == LanguageVersion.ISO_1)
798
 
                                                Report.FeatureIsNotAvailable (context, Location, "partial types");
799
 
 
800
 
                                        return res;
801
 
                                }
802
 
 
803
 
                                if (next_token < Token.LAST_KEYWORD) {
804
 
                                        Report.Error (267, Location,
805
 
                                                "The `partial' modifier can be used only immediately before `class', `struct', `interface', or `void' keyword");
806
 
                                        return token ();
807
 
                                }                                       
808
 
 
809
 
                                res = -1;
810
 
                                break;
811
 
 
812
 
                        case Token.ASYNC:
813
 
                                if (parsing_modifiers) {
814
 
                                        //
815
 
                                        // Skip attributes section or constructor called async
816
 
                                        //
817
 
                                        if (parsing_attribute_section || peek_token () == Token.OPEN_PARENS) {
818
 
                                                res = -1;
819
 
                                        } else {
820
 
                                                // async is keyword
821
 
                                        }
822
 
                                } else if (parsing_block > 0) {
823
 
                                        switch (peek_token ()) {
824
 
                                        case Token.DELEGATE:
825
 
                                        case Token.OPEN_PARENS_LAMBDA:
826
 
                                                // async is keyword
827
 
                                                break;
828
 
                                        case Token.IDENTIFIER:
829
 
                                                PushPosition ();
830
 
                                                xtoken ();
831
 
                                                if (xtoken () != Token.ARROW)
832
 
                                                        res = -1;
833
 
 
834
 
                                                PopPosition ();
835
 
                                                break;
836
 
                                        default:
837
 
                                                res = -1;
838
 
                                                break;
839
 
                                        }
840
 
                                } else {
841
 
                                        res = -1;
842
 
                                }
843
 
 
844
 
                                if (res == Token.ASYNC && context.Settings.Version <= LanguageVersion.V_4) {
845
 
                                        Report.FeatureIsNotAvailable (context, Location, "asynchronous functions");
846
 
                                }
847
 
                                
848
 
                                break;
849
 
 
850
 
                        case Token.AWAIT:
851
 
                                if (parsing_block == 0)
852
 
                                        res = -1;
853
 
 
854
 
                                break;
855
 
                        }
856
 
 
857
 
                        return res;
858
 
                }
859
 
 
860
 
                static PreprocessorDirective GetPreprocessorDirective (char[] id, int id_len)
861
 
                {
862
 
                        //
863
 
                        // Keywords are stored in an array of arrays grouped by their
864
 
                        // length and then by the first character
865
 
                        //
866
 
                        if (id_len >= keywords_preprocessor.Length || keywords_preprocessor[id_len] == null)
867
 
                                return PreprocessorDirective.Invalid;
868
 
 
869
 
                        int first_index = id[0] - '_';
870
 
                        if (first_index > 'z' - '_')
871
 
                                return PreprocessorDirective.Invalid;
872
 
 
873
 
                        var kwe = keywords_preprocessor[id_len][first_index];
874
 
                        if (kwe == null)
875
 
                                return PreprocessorDirective.Invalid;
876
 
 
877
 
                        PreprocessorDirective res = PreprocessorDirective.Invalid;
878
 
                        do {
879
 
                                res = kwe.Token;
880
 
                                for (int i = 1; i < id_len; ++i) {
881
 
                                        if (id[i] != kwe.Value[i]) {
882
 
                                                res = 0;
883
 
                                                kwe = kwe.Next;
884
 
                                                break;
885
 
                                        }
886
 
                                }
887
 
                        } while (res == PreprocessorDirective.Invalid && kwe != null);
888
 
 
889
 
                        return res;
890
 
                }
891
 
 
892
 
                public Location Location {
893
 
                        get {
894
 
                                return new Location (ref_line, col);
895
 
                        }
896
 
                }
897
 
 
898
 
                static bool is_identifier_start_character (int c)
899
 
                {
900
 
                        return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || Char.IsLetter ((char)c);
901
 
                }
902
 
 
903
 
                static bool is_identifier_part_character (char c)
904
 
                {
905
 
                        if (c >= 'a' && c <= 'z')
906
 
                                return true;
907
 
 
908
 
                        if (c >= 'A' && c <= 'Z')
909
 
                                return true;
910
 
 
911
 
                        if (c == '_' || (c >= '0' && c <= '9'))
912
 
                                return true;
913
 
 
914
 
                        if (c < 0x80)
915
 
                                return false;
916
 
 
917
 
                        return Char.IsLetter (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
918
 
                }
919
 
 
920
 
                public static bool IsKeyword (string s)
921
 
                {
922
 
                        return keyword_strings.Contains (s);
923
 
                }
924
 
 
925
 
                //
926
 
                // Open parens micro parser. Detects both lambda and cast ambiguity.
927
 
                //      
928
 
                int TokenizeOpenParens ()
929
 
                {
930
 
                        int ptoken;
931
 
                        current_token = -1;
932
 
 
933
 
                        int bracket_level = 0;
934
 
                        bool is_type = false;
935
 
                        bool can_be_type = false;
936
 
                        
937
 
                        while (true) {
938
 
                                ptoken = current_token;
939
 
                                token ();
940
 
 
941
 
                                switch (current_token) {
942
 
                                case Token.CLOSE_PARENS:
943
 
                                        token ();
944
 
                                        
945
 
                                        //
946
 
                                        // Expression inside parens is lambda, (int i) => 
947
 
                                        //
948
 
                                        if (current_token == Token.ARROW)
949
 
                                                return Token.OPEN_PARENS_LAMBDA;
950
 
 
951
 
                                        //
952
 
                                        // Expression inside parens is single type, (int[])
953
 
                                        //
954
 
                                        if (is_type)
955
 
                                                return Token.OPEN_PARENS_CAST;
956
 
 
957
 
                                        //
958
 
                                        // Expression is possible cast, look at next token, (T)null
959
 
                                        //
960
 
                                        if (can_be_type) {
961
 
                                                switch (current_token) {
962
 
                                                case Token.OPEN_PARENS:
963
 
                                                case Token.BANG:
964
 
                                                case Token.TILDE:
965
 
                                                case Token.IDENTIFIER:
966
 
                                                case Token.LITERAL:
967
 
                                                case Token.BASE:
968
 
                                                case Token.CHECKED:
969
 
                                                case Token.DELEGATE:
970
 
                                                case Token.FALSE:
971
 
                                                case Token.FIXED:
972
 
                                                case Token.NEW:
973
 
                                                case Token.NULL:
974
 
                                                case Token.SIZEOF:
975
 
                                                case Token.THIS:
976
 
                                                case Token.THROW:
977
 
                                                case Token.TRUE:
978
 
                                                case Token.TYPEOF:
979
 
                                                case Token.UNCHECKED:
980
 
                                                case Token.UNSAFE:
981
 
                                                case Token.DEFAULT:
982
 
                                                case Token.AWAIT:
983
 
 
984
 
                                                //
985
 
                                                // These can be part of a member access
986
 
                                                //
987
 
                                                case Token.INT:
988
 
                                                case Token.UINT:
989
 
                                                case Token.SHORT:
990
 
                                                case Token.USHORT:
991
 
                                                case Token.LONG:
992
 
                                                case Token.ULONG:
993
 
                                                case Token.DOUBLE:
994
 
                                                case Token.FLOAT:
995
 
                                                case Token.CHAR:
996
 
                                                case Token.BYTE:
997
 
                                                case Token.DECIMAL:
998
 
                                                case Token.BOOL:
999
 
                                                        return Token.OPEN_PARENS_CAST;
1000
 
                                                }
1001
 
                                        }
1002
 
                                        return Token.OPEN_PARENS;
1003
 
                                        
1004
 
                                case Token.DOT:
1005
 
                                case Token.DOUBLE_COLON:
1006
 
                                        if (ptoken != Token.IDENTIFIER && ptoken != Token.OP_GENERICS_GT)
1007
 
                                                goto default;
1008
 
 
1009
 
                                        continue;
1010
 
 
1011
 
                                case Token.IDENTIFIER:
1012
 
                                        switch (ptoken) {
1013
 
                                        case Token.DOT:
1014
 
                                                if (bracket_level == 0) {
1015
 
                                                        is_type = false;
1016
 
                                                        can_be_type = true;
1017
 
                                                }
1018
 
 
1019
 
                                                continue;
1020
 
                                        case Token.OP_GENERICS_LT:
1021
 
                                        case Token.COMMA:
1022
 
                                        case Token.DOUBLE_COLON:
1023
 
                                        case -1:
1024
 
                                                if (bracket_level == 0)
1025
 
                                                        can_be_type = true;
1026
 
                                                continue;
1027
 
                                        default:
1028
 
                                                can_be_type = is_type = false;
1029
 
                                                continue;
1030
 
                                        }
1031
 
 
1032
 
                                case Token.OBJECT:
1033
 
                                case Token.STRING:
1034
 
                                case Token.BOOL:
1035
 
                                case Token.DECIMAL:
1036
 
                                case Token.FLOAT:
1037
 
                                case Token.DOUBLE:
1038
 
                                case Token.SBYTE:
1039
 
                                case Token.BYTE:
1040
 
                                case Token.SHORT:
1041
 
                                case Token.USHORT:
1042
 
                                case Token.INT:
1043
 
                                case Token.UINT:
1044
 
                                case Token.LONG:
1045
 
                                case Token.ULONG:
1046
 
                                case Token.CHAR:
1047
 
                                case Token.VOID:
1048
 
                                        if (bracket_level == 0)
1049
 
                                                is_type = true;
1050
 
                                        continue;
1051
 
 
1052
 
                                case Token.COMMA:
1053
 
                                        if (bracket_level == 0) {
1054
 
                                                bracket_level = 100;
1055
 
                                                can_be_type = is_type = false;
1056
 
                                        }
1057
 
                                        continue;
1058
 
 
1059
 
                                case Token.OP_GENERICS_LT:
1060
 
                                case Token.OPEN_BRACKET:
1061
 
                                        if (bracket_level++ == 0)
1062
 
                                                is_type = true;
1063
 
                                        continue;
1064
 
 
1065
 
                                case Token.OP_GENERICS_GT:
1066
 
                                case Token.CLOSE_BRACKET:
1067
 
                                        --bracket_level;
1068
 
                                        continue;
1069
 
 
1070
 
                                case Token.INTERR_NULLABLE:
1071
 
                                case Token.STAR:
1072
 
                                        if (bracket_level == 0)
1073
 
                                                is_type = true;
1074
 
                                        continue;
1075
 
 
1076
 
                                case Token.REF:
1077
 
                                case Token.OUT:
1078
 
                                        can_be_type = is_type = false;
1079
 
                                        continue;
1080
 
 
1081
 
                                default:
1082
 
                                        return Token.OPEN_PARENS;
1083
 
                                }
1084
 
                        }
1085
 
                }
1086
 
 
1087
 
                public static bool IsValidIdentifier (string s)
1088
 
                {
1089
 
                        if (s == null || s.Length == 0)
1090
 
                                return false;
1091
 
 
1092
 
                        if (!is_identifier_start_character (s [0]))
1093
 
                                return false;
1094
 
                        
1095
 
                        for (int i = 1; i < s.Length; i ++)
1096
 
                                if (! is_identifier_part_character (s [i]))
1097
 
                                        return false;
1098
 
                        
1099
 
                        return true;
1100
 
                }
1101
 
 
1102
 
                bool parse_less_than ()
1103
 
                {
1104
 
                start:
1105
 
                        int the_token = token ();
1106
 
                        if (the_token == Token.OPEN_BRACKET) {
1107
 
                                do {
1108
 
                                        the_token = token ();
1109
 
                                } while (the_token != Token.CLOSE_BRACKET);
1110
 
                                the_token = token ();
1111
 
                        } else if (the_token == Token.IN || the_token == Token.OUT) {
1112
 
                                the_token = token ();
1113
 
                        }
1114
 
                        switch (the_token) {
1115
 
                        case Token.IDENTIFIER:
1116
 
                        case Token.OBJECT:
1117
 
                        case Token.STRING:
1118
 
                        case Token.BOOL:
1119
 
                        case Token.DECIMAL:
1120
 
                        case Token.FLOAT:
1121
 
                        case Token.DOUBLE:
1122
 
                        case Token.SBYTE:
1123
 
                        case Token.BYTE:
1124
 
                        case Token.SHORT:
1125
 
                        case Token.USHORT:
1126
 
                        case Token.INT:
1127
 
                        case Token.UINT:
1128
 
                        case Token.LONG:
1129
 
                        case Token.ULONG:
1130
 
                        case Token.CHAR:
1131
 
                        case Token.VOID:
1132
 
                                break;
1133
 
                        case Token.OP_GENERICS_GT:
1134
 
                        case Token.IN:
1135
 
                        case Token.OUT:
1136
 
                                return true;
1137
 
 
1138
 
                        default:
1139
 
                                return false;
1140
 
                        }
1141
 
                again:
1142
 
                        the_token = token ();
1143
 
 
1144
 
                        if (the_token == Token.OP_GENERICS_GT)
1145
 
                                return true;
1146
 
                        else if (the_token == Token.COMMA || the_token == Token.DOT || the_token == Token.DOUBLE_COLON)
1147
 
                                goto start;
1148
 
                        else if (the_token == Token.INTERR_NULLABLE || the_token == Token.STAR)
1149
 
                                goto again;
1150
 
                        else if (the_token == Token.OP_GENERICS_LT) {
1151
 
                                if (!parse_less_than ())
1152
 
                                        return false;
1153
 
                                goto again;
1154
 
                        } else if (the_token == Token.OPEN_BRACKET) {
1155
 
                        rank_specifiers:
1156
 
                                the_token = token ();
1157
 
                                if (the_token == Token.CLOSE_BRACKET)
1158
 
                                        goto again;
1159
 
                                else if (the_token == Token.COMMA)
1160
 
                                        goto rank_specifiers;
1161
 
                                return false;
1162
 
                        }
1163
 
 
1164
 
                        return false;
1165
 
                }
1166
 
 
1167
 
                bool parse_generic_dimension (out int dimension)
1168
 
                {
1169
 
                        dimension = 1;
1170
 
 
1171
 
                again:
1172
 
                        int the_token = token ();
1173
 
                        if (the_token == Token.OP_GENERICS_GT)
1174
 
                                return true;
1175
 
                        else if (the_token == Token.COMMA) {
1176
 
                                dimension++;
1177
 
                                goto again;
1178
 
                        }
1179
 
 
1180
 
                        return false;
1181
 
                }
1182
 
                
1183
 
                public int peek_token ()
1184
 
                {
1185
 
                        int the_token;
1186
 
 
1187
 
                        PushPosition ();
1188
 
                        the_token = token ();
1189
 
                        PopPosition ();
1190
 
                        
1191
 
                        return the_token;
1192
 
                }
1193
 
                                        
1194
 
                //
1195
 
                // Tonizes `?' using custom disambiguous rules to return one
1196
 
                // of following tokens: INTERR_NULLABLE, OP_COALESCING, INTERR
1197
 
                //
1198
 
                // Tricky expression look like:
1199
 
                //
1200
 
                // Foo ? a = x ? b : c;
1201
 
                //
1202
 
                int TokenizePossibleNullableType ()
1203
 
                {
1204
 
                        if (parsing_block == 0 || parsing_type > 0)
1205
 
                                return Token.INTERR_NULLABLE;
1206
 
 
1207
 
                        int d = peek_char ();
1208
 
                        if (d == '?') {
1209
 
                                get_char ();
1210
 
                                return Token.OP_COALESCING;
1211
 
                        }
1212
 
 
1213
 
                        switch (current_token) {
1214
 
                        case Token.CLOSE_PARENS:
1215
 
                        case Token.TRUE:
1216
 
                        case Token.FALSE:
1217
 
                        case Token.NULL:
1218
 
                        case Token.LITERAL:
1219
 
                                return Token.INTERR;
1220
 
                        }
1221
 
 
1222
 
                        if (d != ' ') {
1223
 
                                if (d == ',' || d == ';' || d == '>')
1224
 
                                        return Token.INTERR_NULLABLE;
1225
 
                                if (d == '*' || (d >= '0' && d <= '9'))
1226
 
                                        return Token.INTERR;
1227
 
                        }
1228
 
 
1229
 
                        PushPosition ();
1230
 
                        current_token = Token.NONE;
1231
 
                        int next_token;
1232
 
                        switch (xtoken ()) {
1233
 
                        case Token.LITERAL:
1234
 
                        case Token.TRUE:
1235
 
                        case Token.FALSE:
1236
 
                        case Token.NULL:
1237
 
                        case Token.THIS:
1238
 
                        case Token.NEW:
1239
 
                                next_token = Token.INTERR;
1240
 
                                break;
1241
 
                                
1242
 
                        case Token.SEMICOLON:
1243
 
                        case Token.COMMA:
1244
 
                        case Token.CLOSE_PARENS:
1245
 
                        case Token.OPEN_BRACKET:
1246
 
                        case Token.OP_GENERICS_GT:
1247
 
                        case Token.INTERR:
1248
 
                                next_token = Token.INTERR_NULLABLE;
1249
 
                                break;
1250
 
                                
1251
 
                        default:
1252
 
                                next_token = -1;
1253
 
                                break;
1254
 
                        }
1255
 
 
1256
 
                        if (next_token == -1) {
1257
 
                                switch (xtoken ()) {
1258
 
                                case Token.COMMA:
1259
 
                                case Token.SEMICOLON:
1260
 
                                case Token.OPEN_BRACE:
1261
 
                                case Token.CLOSE_PARENS:
1262
 
                                case Token.IN:
1263
 
                                        next_token = Token.INTERR_NULLABLE;
1264
 
                                        break;
1265
 
                                        
1266
 
                                case Token.COLON:
1267
 
                                        next_token = Token.INTERR;
1268
 
                                        break;                                                  
1269
 
                                        
1270
 
                                default:
1271
 
                                        int ntoken;
1272
 
                                        int interrs = 1;
1273
 
                                        int colons = 0;
1274
 
                                        int braces = 0;
1275
 
                                        //
1276
 
                                        // All shorcuts failed, do it hard way
1277
 
                                        //
1278
 
                                        while ((ntoken = xtoken ()) != Token.EOF) {
1279
 
                                                if (ntoken == Token.OPEN_BRACE) {
1280
 
                                                        ++braces;
1281
 
                                                        continue;
1282
 
                                                }
1283
 
 
1284
 
                                                if (ntoken == Token.CLOSE_BRACE) {
1285
 
                                                        --braces;
1286
 
                                                        continue;
1287
 
                                                }
1288
 
 
1289
 
                                                if (braces != 0)
1290
 
                                                        continue;
1291
 
 
1292
 
                                                if (ntoken == Token.SEMICOLON)
1293
 
                                                        break;
1294
 
                                                
1295
 
                                                if (ntoken == Token.COLON) {
1296
 
                                                        if (++colons == interrs)
1297
 
                                                                break;
1298
 
                                                        continue;
1299
 
                                                }
1300
 
                                                
1301
 
                                                if (ntoken == Token.INTERR) {
1302
 
                                                        ++interrs;
1303
 
                                                        continue;
1304
 
                                                }
1305
 
                                        }
1306
 
                                        
1307
 
                                        next_token = colons != interrs && braces == 0 ? Token.INTERR_NULLABLE : Token.INTERR;
1308
 
                                        break;
1309
 
                                }
1310
 
                        }
1311
 
                        
1312
 
                        PopPosition ();
1313
 
                        return next_token;
1314
 
                }
1315
 
 
1316
 
                bool decimal_digits (int c)
1317
 
                {
1318
 
                        int d;
1319
 
                        bool seen_digits = false;
1320
 
                        
1321
 
                        if (c != -1){
1322
 
                                if (number_pos == max_number_size)
1323
 
                                        Error_NumericConstantTooLong ();
1324
 
                                number_builder [number_pos++] = (char) c;
1325
 
                        }
1326
 
                        
1327
 
                        //
1328
 
                        // We use peek_char2, because decimal_digits needs to do a 
1329
 
                        // 2-character look-ahead (5.ToString for example).
1330
 
                        //
1331
 
                        while ((d = peek_char2 ()) != -1){
1332
 
                                if (d >= '0' && d <= '9'){
1333
 
                                        if (number_pos == max_number_size)
1334
 
                                                Error_NumericConstantTooLong ();
1335
 
                                        number_builder [number_pos++] = (char) d;
1336
 
                                        get_char ();
1337
 
                                        seen_digits = true;
1338
 
                                } else
1339
 
                                        break;
1340
 
                        }
1341
 
                        
1342
 
                        return seen_digits;
1343
 
                }
1344
 
 
1345
 
                static bool is_hex (int e)
1346
 
                {
1347
 
                        return (e >= '0' && e <= '9') || (e >= 'A' && e <= 'F') || (e >= 'a' && e <= 'f');
1348
 
                }
1349
 
 
1350
 
                static TypeCode real_type_suffix (int c)
1351
 
                {
1352
 
                        switch (c){
1353
 
                        case 'F': case 'f':
1354
 
                                return TypeCode.Single;
1355
 
                        case 'D': case 'd':
1356
 
                                return TypeCode.Double;
1357
 
                        case 'M': case 'm':
1358
 
                                return TypeCode.Decimal;
1359
 
                        default:
1360
 
                                return TypeCode.Empty;
1361
 
                        }
1362
 
                }
1363
 
 
1364
 
                ILiteralConstant integer_type_suffix (ulong ul, int c, Location loc)
1365
 
                {
1366
 
                        bool is_unsigned = false;
1367
 
                        bool is_long = false;
1368
 
 
1369
 
                        if (c != -1){
1370
 
                                bool scanning = true;
1371
 
                                do {
1372
 
                                        switch (c){
1373
 
                                        case 'U': case 'u':
1374
 
                                                if (is_unsigned)
1375
 
                                                        scanning = false;
1376
 
                                                is_unsigned = true;
1377
 
                                                get_char ();
1378
 
                                                break;
1379
 
 
1380
 
                                        case 'l':
1381
 
                                                if (!is_unsigned){
1382
 
                                                        //
1383
 
                                                        // if we have not seen anything in between
1384
 
                                                        // report this error
1385
 
                                                        //
1386
 
                                                        Report.Warning (78, 4, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
1387
 
                                                }
1388
 
 
1389
 
                                                goto case 'L';
1390
 
 
1391
 
                                        case 'L': 
1392
 
                                                if (is_long)
1393
 
                                                        scanning = false;
1394
 
                                                is_long = true;
1395
 
                                                get_char ();
1396
 
                                                break;
1397
 
                                                
1398
 
                                        default:
1399
 
                                                scanning = false;
1400
 
                                                break;
1401
 
                                        }
1402
 
                                        c = peek_char ();
1403
 
                                } while (scanning);
1404
 
                        }
1405
 
 
1406
 
                        if (is_long && is_unsigned){
1407
 
                                return new ULongLiteral (context.BuiltinTypes, ul, loc);
1408
 
                        }
1409
 
                        
1410
 
                        if (is_unsigned){
1411
 
                                // uint if possible, or ulong else.
1412
 
 
1413
 
                                if ((ul & 0xffffffff00000000) == 0)
1414
 
                                        return new UIntLiteral (context.BuiltinTypes, (uint) ul, loc);
1415
 
                                else
1416
 
                                        return new ULongLiteral (context.BuiltinTypes, ul, loc);
1417
 
                        } else if (is_long){
1418
 
                                // long if possible, ulong otherwise
1419
 
                                if ((ul & 0x8000000000000000) != 0)
1420
 
                                        return new ULongLiteral (context.BuiltinTypes, ul, loc);
1421
 
                                else
1422
 
                                        return new LongLiteral (context.BuiltinTypes, (long) ul, loc);
1423
 
                        } else {
1424
 
                                // int, uint, long or ulong in that order
1425
 
                                if ((ul & 0xffffffff00000000) == 0){
1426
 
                                        uint ui = (uint) ul;
1427
 
                                        
1428
 
                                        if ((ui & 0x80000000) != 0)
1429
 
                                                return new UIntLiteral (context.BuiltinTypes, ui, loc);
1430
 
                                        else
1431
 
                                                return new IntLiteral (context.BuiltinTypes, (int) ui, loc);
1432
 
                                } else {
1433
 
                                        if ((ul & 0x8000000000000000) != 0)
1434
 
                                                return new ULongLiteral (context.BuiltinTypes, ul, loc);
1435
 
                                        else
1436
 
                                                return new LongLiteral (context.BuiltinTypes, (long) ul, loc);
1437
 
                                }
1438
 
                        }
1439
 
                }
1440
 
                                
1441
 
                //
1442
 
                // given `c' as the next char in the input decide whether
1443
 
                // we need to convert to a special type, and then choose
1444
 
                // the best representation for the integer
1445
 
                //
1446
 
                ILiteralConstant adjust_int (int c, Location loc)
1447
 
                {
1448
 
                        try {
1449
 
                                if (number_pos > 9){
1450
 
                                        ulong ul = (uint) (number_builder [0] - '0');
1451
 
 
1452
 
                                        for (int i = 1; i < number_pos; i++){
1453
 
                                                ul = checked ((ul * 10) + ((uint)(number_builder [i] - '0')));
1454
 
                                        }
1455
 
 
1456
 
                                        return integer_type_suffix (ul, c, loc);
1457
 
                                } else {
1458
 
                                        uint ui = (uint) (number_builder [0] - '0');
1459
 
 
1460
 
                                        for (int i = 1; i < number_pos; i++){
1461
 
                                                ui = checked ((ui * 10) + ((uint)(number_builder [i] - '0')));
1462
 
                                        }
1463
 
 
1464
 
                                        return integer_type_suffix (ui, c, loc);
1465
 
                                }
1466
 
                        } catch (OverflowException) {
1467
 
                                Error_NumericConstantTooLong ();
1468
 
                                return new IntLiteral (context.BuiltinTypes, 0, loc);
1469
 
                        }
1470
 
                        catch (FormatException) {
1471
 
                                Report.Error (1013, Location, "Invalid number");
1472
 
                                return new IntLiteral (context.BuiltinTypes, 0, loc);
1473
 
                        }
1474
 
                }
1475
 
                
1476
 
                ILiteralConstant adjust_real (TypeCode t, Location loc)
1477
 
                {
1478
 
                        string s = new string (number_builder, 0, number_pos);
1479
 
                        const string error_details = "Floating-point constant is outside the range of type `{0}'";
1480
 
 
1481
 
                        switch (t){
1482
 
                        case TypeCode.Decimal:
1483
 
                                try {
1484
 
                                        return new DecimalLiteral (context.BuiltinTypes, decimal.Parse (s, styles, csharp_format_info), loc);
1485
 
                                } catch (OverflowException) {
1486
 
                                        Report.Error (594, Location, error_details, "decimal");
1487
 
                                        return new DecimalLiteral (context.BuiltinTypes, 0, loc);
1488
 
                                }
1489
 
                        case TypeCode.Single:
1490
 
                                try {
1491
 
                                        return new FloatLiteral (context.BuiltinTypes, float.Parse (s, styles, csharp_format_info), loc);
1492
 
                                } catch (OverflowException) {
1493
 
                                        Report.Error (594, Location, error_details, "float");
1494
 
                                        return new FloatLiteral (context.BuiltinTypes, 0, loc);
1495
 
                                }
1496
 
                        default:
1497
 
                                try {
1498
 
                                        return new DoubleLiteral (context.BuiltinTypes, double.Parse (s, styles, csharp_format_info), loc);
1499
 
                                } catch (OverflowException) {
1500
 
                                        Report.Error (594, loc, error_details, "double");
1501
 
                                        return new DoubleLiteral (context.BuiltinTypes, 0, loc);
1502
 
                                }
1503
 
                        }
1504
 
                }
1505
 
 
1506
 
                ILiteralConstant handle_hex (Location loc)
1507
 
                {
1508
 
                        int d;
1509
 
                        ulong ul;
1510
 
                        
1511
 
                        get_char ();
1512
 
                        while ((d = peek_char ()) != -1){
1513
 
                                if (is_hex (d)){
1514
 
                                        number_builder [number_pos++] = (char) d;
1515
 
                                        get_char ();
1516
 
                                } else
1517
 
                                        break;
1518
 
                        }
1519
 
                        
1520
 
                        string s = new String (number_builder, 0, number_pos);
1521
 
 
1522
 
                        try {
1523
 
                                if (number_pos <= 8)
1524
 
                                        ul = System.UInt32.Parse (s, NumberStyles.HexNumber);
1525
 
                                else
1526
 
                                        ul = System.UInt64.Parse (s, NumberStyles.HexNumber);
1527
 
 
1528
 
                                return integer_type_suffix (ul, peek_char (), loc);
1529
 
                        } catch (OverflowException){
1530
 
                                Error_NumericConstantTooLong ();
1531
 
                                return new IntLiteral (context.BuiltinTypes, 0, loc);
1532
 
                        }
1533
 
                        catch (FormatException) {
1534
 
                                Report.Error (1013, Location, "Invalid number");
1535
 
                                return new IntLiteral (context.BuiltinTypes, 0, loc);
1536
 
                        }
1537
 
                }
1538
 
 
1539
 
                //
1540
 
                // Invoked if we know we have .digits or digits
1541
 
                //
1542
 
                int is_number (int c)
1543
 
                {
1544
 
                        ILiteralConstant res;
1545
 
 
1546
 
#if FULL_AST
1547
 
                        int read_start = reader.Position - 1;
1548
 
                        if (c == '.') {
1549
 
                                //
1550
 
                                // Caller did peek_char
1551
 
                                //
1552
 
                                --read_start;
1553
 
                        }
1554
 
#endif
1555
 
                        number_pos = 0;
1556
 
                        var loc = Location;
1557
 
                        bool hasLeadingDot = c == '.';
1558
 
 
1559
 
                        if (c >= '0' && c <= '9'){
1560
 
                                if (c == '0'){
1561
 
                                        int peek = peek_char ();
1562
 
 
1563
 
                                        if (peek == 'x' || peek == 'X') {
1564
 
                                                val = res = handle_hex (loc);
1565
 
#if FULL_AST
1566
 
                                                res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1);
1567
 
#endif
1568
 
 
1569
 
                                                return Token.LITERAL;
1570
 
                                        }
1571
 
                                }
1572
 
                                decimal_digits (c);
1573
 
                                c = get_char ();
1574
 
                        }
1575
 
 
1576
 
                        //
1577
 
                        // We need to handle the case of
1578
 
                        // "1.1" vs "1.string" (LITERAL_FLOAT vs NUMBER DOT IDENTIFIER)
1579
 
                        //
1580
 
                        bool is_real = false;
1581
 
                        if (c == '.'){
1582
 
                                if (decimal_digits ('.')){
1583
 
                                        is_real = true;
1584
 
                                        c = get_char ();
1585
 
                                } else {
1586
 
                                        putback ('.');
1587
 
                                        number_pos--;
1588
 
                                        val = res = adjust_int (-1, loc);
1589
 
#if FULL_AST
1590
 
                                        res.ParsedValue = reader.ReadChars (read_start, reader.Position - 1);
1591
 
#endif
1592
 
                                        return Token.LITERAL;
1593
 
                                }
1594
 
                        }
1595
 
                        
1596
 
                        if (c == 'e' || c == 'E'){
1597
 
                                is_real = true;
1598
 
                                if (number_pos == max_number_size)
1599
 
                                        Error_NumericConstantTooLong ();
1600
 
                                number_builder [number_pos++] = (char) c;
1601
 
                                c = get_char ();
1602
 
                                
1603
 
                                if (c == '+'){
1604
 
                                        if (number_pos == max_number_size)
1605
 
                                                Error_NumericConstantTooLong ();
1606
 
                                        number_builder [number_pos++] = '+';
1607
 
                                        c = -1;
1608
 
                                } else if (c == '-') {
1609
 
                                        if (number_pos == max_number_size)
1610
 
                                                Error_NumericConstantTooLong ();
1611
 
                                        number_builder [number_pos++] = '-';
1612
 
                                        c = -1;
1613
 
                                } else {
1614
 
                                        if (number_pos == max_number_size)
1615
 
                                                Error_NumericConstantTooLong ();
1616
 
                                        number_builder [number_pos++] = '+';
1617
 
                                }
1618
 
                                        
1619
 
                                decimal_digits (c);
1620
 
                                c = get_char ();
1621
 
                        }
1622
 
 
1623
 
                        var type = real_type_suffix (c);
1624
 
                        if (type == TypeCode.Empty && !is_real) {
1625
 
                                putback (c);
1626
 
                                res = adjust_int (c, loc);
1627
 
                        } else {
1628
 
                                is_real = true;
1629
 
 
1630
 
                                if (type == TypeCode.Empty) {
1631
 
                                        putback (c);
1632
 
                                }
1633
 
 
1634
 
                                res = adjust_real (type, loc);
1635
 
                        }
1636
 
 
1637
 
                        val = res;
1638
 
#if FULL_AST
1639
 
                        var chars = reader.ReadChars (read_start, reader.Position - (type == TypeCode.Empty && c > 0 ? 1 : 0));
1640
 
                        if (chars[chars.Length - 1] == '\r')
1641
 
                                Array.Resize (ref chars, chars.Length - 1);
1642
 
                        res.ParsedValue = chars;
1643
 
#endif
1644
 
 
1645
 
                        return Token.LITERAL;
1646
 
                }
1647
 
 
1648
 
                //
1649
 
                // Accepts exactly count (4 or 8) hex, no more no less
1650
 
                //
1651
 
                int getHex (int count, out int surrogate, out bool error)
1652
 
                {
1653
 
                        int i;
1654
 
                        int total = 0;
1655
 
                        int c;
1656
 
                        int top = count != -1 ? count : 4;
1657
 
                        
1658
 
                        get_char ();
1659
 
                        error = false;
1660
 
                        surrogate = 0;
1661
 
                        for (i = 0; i < top; i++){
1662
 
                                c = get_char ();
1663
 
 
1664
 
                                if (c >= '0' && c <= '9')
1665
 
                                        c = (int) c - (int) '0';
1666
 
                                else if (c >= 'A' && c <= 'F')
1667
 
                                        c = (int) c - (int) 'A' + 10;
1668
 
                                else if (c >= 'a' && c <= 'f')
1669
 
                                        c = (int) c - (int) 'a' + 10;
1670
 
                                else {
1671
 
                                        error = true;
1672
 
                                        return 0;
1673
 
                                }
1674
 
                                
1675
 
                                total = (total * 16) + c;
1676
 
                                if (count == -1){
1677
 
                                        int p = peek_char ();
1678
 
                                        if (p == -1)
1679
 
                                                break;
1680
 
                                        if (!is_hex ((char)p))
1681
 
                                                break;
1682
 
                                }
1683
 
                        }
1684
 
 
1685
 
                        if (top == 8) {
1686
 
                                if (total > 0x0010FFFF) {
1687
 
                                        error = true;
1688
 
                                        return 0;
1689
 
                                }
1690
 
 
1691
 
                                if (total >= 0x00010000) {
1692
 
                                        surrogate = ((total - 0x00010000) % 0x0400 + 0xDC00);                                   
1693
 
                                        total = ((total - 0x00010000) / 0x0400 + 0xD800);
1694
 
                                }
1695
 
                        }
1696
 
 
1697
 
                        return total;
1698
 
                }
1699
 
 
1700
 
                int escape (int c, out int surrogate)
1701
 
                {
1702
 
                        bool error;
1703
 
                        int d;
1704
 
                        int v;
1705
 
 
1706
 
                        d = peek_char ();
1707
 
                        if (c != '\\') {
1708
 
                                surrogate = 0;
1709
 
                                return c;
1710
 
                        }
1711
 
                        
1712
 
                        switch (d){
1713
 
                        case 'a':
1714
 
                                v = '\a'; break;
1715
 
                        case 'b':
1716
 
                                v = '\b'; break;
1717
 
                        case 'n':
1718
 
                                v = '\n'; break;
1719
 
                        case 't':
1720
 
                                v = '\t'; break;
1721
 
                        case 'v':
1722
 
                                v = '\v'; break;
1723
 
                        case 'r':
1724
 
                                v = '\r'; break;
1725
 
                        case '\\':
1726
 
                                v = '\\'; break;
1727
 
                        case 'f':
1728
 
                                v = '\f'; break;
1729
 
                        case '0':
1730
 
                                v = 0; break;
1731
 
                        case '"':
1732
 
                                v = '"'; break;
1733
 
                        case '\'':
1734
 
                                v = '\''; break;
1735
 
                        case 'x':
1736
 
                                v = getHex (-1, out surrogate, out error);
1737
 
                                if (error)
1738
 
                                        goto default;
1739
 
                                return v;
1740
 
                        case 'u':
1741
 
                        case 'U':
1742
 
                                return EscapeUnicode (d, out surrogate);
1743
 
                        default:
1744
 
                                surrogate = 0;
1745
 
                                Report.Error (1009, Location, "Unrecognized escape sequence `\\{0}'", ((char)d).ToString ());
1746
 
                                return d;
1747
 
                        }
1748
 
 
1749
 
                        get_char ();
1750
 
                        surrogate = 0;
1751
 
                        return v;
1752
 
                }
1753
 
 
1754
 
                int EscapeUnicode (int ch, out int surrogate)
1755
 
                {
1756
 
                        bool error;
1757
 
                        if (ch == 'U') {
1758
 
                                ch = getHex (8, out surrogate, out error);
1759
 
                        } else {
1760
 
                                ch = getHex (4, out surrogate, out error);
1761
 
                        }
1762
 
 
1763
 
                        if (error)
1764
 
                                Report.Error (1009, Location, "Unrecognized escape sequence");
1765
 
 
1766
 
                        return ch;
1767
 
                }
1768
 
 
1769
 
                int get_char ()
1770
 
                {
1771
 
                        int x;
1772
 
                        if (putback_char != -1) {
1773
 
                                x = putback_char;
1774
 
                                putback_char = -1;
1775
 
                        } else {
1776
 
                                x = reader.Read ();
1777
 
                        }
1778
 
                        
1779
 
                        if (x == '\r') {
1780
 
                                if (peek_char () == '\n') {
1781
 
                                        putback_char = -1;
1782
 
                                }
1783
 
 
1784
 
                                x = '\n';
1785
 
                                advance_line ();
1786
 
                        } else if (x == '\n') {
1787
 
                                advance_line ();
1788
 
                        } else {
1789
 
                                col++;
1790
 
                        }
1791
 
                        return x;
1792
 
                }
1793
 
 
1794
 
                void advance_line ()
1795
 
                {
1796
 
                        line++;
1797
 
                        ref_line++;
1798
 
                        previous_col = col;
1799
 
                        col = 0;
1800
 
                        startsLine = true;
1801
 
                }
1802
 
 
1803
 
                int peek_char ()
1804
 
                {
1805
 
                        if (putback_char == -1)
1806
 
                                putback_char = reader.Read ();
1807
 
                        return putback_char;
1808
 
                }
1809
 
 
1810
 
                int peek_char2 ()
1811
 
                {
1812
 
                        if (putback_char != -1)
1813
 
                                return putback_char;
1814
 
                        return reader.Peek ();
1815
 
                }
1816
 
                
1817
 
                public void putback (int c)
1818
 
                {
1819
 
                        if (putback_char != -1) {
1820
 
                                throw new InternalErrorException (string.Format ("Secondary putback [{0}] putting back [{1}] is not allowed", (char)putback_char, (char) c), Location);
1821
 
                        }
1822
 
 
1823
 
                        if (c == '\n' || col == 0) {
1824
 
                                // It won't happen though.
1825
 
                                line--;
1826
 
                                ref_line--;
1827
 
                                col = previous_col;
1828
 
                        }
1829
 
                        else
1830
 
                                col--;
1831
 
                        putback_char = c;
1832
 
                }
1833
 
 
1834
 
                public bool advance ()
1835
 
                {
1836
 
                        return peek_char () != -1 || CompleteOnEOF;
1837
 
                }
1838
 
 
1839
 
                public Object Value {
1840
 
                        get {
1841
 
                                return val;
1842
 
                        }
1843
 
                }
1844
 
 
1845
 
                public Object value ()
1846
 
                {
1847
 
                        return val;
1848
 
                }
1849
 
 
1850
 
                public int token ()
1851
 
                {
1852
 
                        current_token = xtoken ();
1853
 
                        return current_token;
1854
 
                }
1855
 
 
1856
 
                int TokenizePreprocessorIdentifier (out int c)
1857
 
                {
1858
 
                        int endLine, endCol;
1859
 
                        return TokenizePreprocessorIdentifier (out c, out endLine, out endCol);
1860
 
                }
1861
 
 
1862
 
                int TokenizePreprocessorIdentifier (out int c, out int endLine, out int endCol)
1863
 
                {
1864
 
                        // skip over white space
1865
 
                        do {
1866
 
                                endLine = line;
1867
 
                                endCol = col;
1868
 
                                c = get_char ();
1869
 
                        } while (c == ' ' || c == '\t');
1870
 
                        
1871
 
                        int pos = 0;
1872
 
                        while (c != -1 && c >= 'a' && c <= 'z') {
1873
 
                                id_builder[pos++] = (char) c;
1874
 
                                endCol = col + 1;
1875
 
                                c = get_char ();
1876
 
                                if (c == '\\') {
1877
 
                                        int peek = peek_char ();
1878
 
                                        if (peek == 'U' || peek == 'u') {
1879
 
                                                int surrogate;
1880
 
                                                c = EscapeUnicode (c, out surrogate);
1881
 
                                                if (surrogate != 0) {
1882
 
                                                        if (is_identifier_part_character ((char) c)) {
1883
 
                                                                id_builder[pos++] = (char) c;
1884
 
                                                        }
1885
 
                                                        c = surrogate;
1886
 
                                                }
1887
 
                                        }
1888
 
                                }
1889
 
                        }
1890
 
 
1891
 
                        return pos;
1892
 
                }
1893
 
 
1894
 
                PreprocessorDirective get_cmd_arg (out string arg)
1895
 
                {
1896
 
                        int c;
1897
 
                        int startLine = line, startCol = col;
1898
 
 
1899
 
                        tokens_seen = false;
1900
 
                        arg = "";
1901
 
                        
1902
 
                        int endLine, endCol;
1903
 
                        var cmd = GetPreprocessorDirective (id_builder, TokenizePreprocessorIdentifier (out c, out endLine, out endCol));
1904
 
                        
1905
 
                        if ((cmd & PreprocessorDirective.CustomArgumentsParsing) != 0) {
1906
 
                                if (position_stack.Count == 0)
1907
 
                                        sbag.AddPreProcessorDirective (startLine, startCol, line, col, cmd, null);
1908
 
                                return cmd;
1909
 
                        }
1910
 
                        
1911
 
                        // skip over white space
1912
 
                        while (c == ' ' || c == '\t') {
1913
 
                                c = get_char ();
1914
 
                        }
1915
 
                        int has_identifier_argument = (int)(cmd & PreprocessorDirective.RequiresArgument);
1916
 
 
1917
 
                        int pos = 0;
1918
 
                        while (c != -1 && c != '\n' && c != '\r') {
1919
 
                                if (c == '\\' && has_identifier_argument >= 0) {
1920
 
                                        if (has_identifier_argument != 0) {
1921
 
                                                has_identifier_argument = 1;
1922
 
 
1923
 
                                                int peek = peek_char ();
1924
 
                                                if (peek == 'U' || peek == 'u') {
1925
 
                                                        int surrogate;
1926
 
                                                        c = EscapeUnicode (c, out surrogate);
1927
 
                                                        if (surrogate != 0) {
1928
 
                                                                if (is_identifier_part_character ((char)c)) {
1929
 
                                                                        if (pos == value_builder.Length)
1930
 
                                                                                Array.Resize (ref value_builder, pos * 2);
1931
 
 
1932
 
                                                                        value_builder [pos++] = (char)c;
1933
 
                                                                }
1934
 
                                                                c = surrogate;
1935
 
                                                        }
1936
 
                                                }
1937
 
                                        } else {
1938
 
                                                has_identifier_argument = -1;
1939
 
                                        }
1940
 
                                } else if (c == '/' && peek_char () == '/') {
1941
 
                                        //
1942
 
                                        // Eat single-line comments
1943
 
                                        //
1944
 
                                        get_char ();
1945
 
                                        do {
1946
 
                                                c = get_char ();
1947
 
                                        } while (c != -1 && c != '\n');
1948
 
 
1949
 
                                        break;
1950
 
                                }
1951
 
                                
1952
 
                                endLine = line;
1953
 
                                endCol = col + 1;
1954
 
                                
1955
 
                                if (pos == value_builder.Length)
1956
 
                                        Array.Resize (ref value_builder, pos * 2);
1957
 
 
1958
 
                                value_builder[pos++] = (char) c;
1959
 
                                c = get_char ();
1960
 
                        }
1961
 
 
1962
 
                        if (pos != 0) {
1963
 
                                if (pos > max_id_size)
1964
 
                                        arg = new string (value_builder, 0, pos);
1965
 
                                else
1966
 
                                        arg = InternIdentifier (value_builder, pos);
1967
 
 
1968
 
                                // Eat any trailing whitespaces
1969
 
                                arg = arg.Trim (simple_whitespaces);
1970
 
                        }
1971
 
                        if (position_stack.Count == 0)
1972
 
                                sbag.AddPreProcessorDirective (startLine, startCol, endLine, endCol, cmd, arg);
1973
 
 
1974
 
                        return cmd;
1975
 
                }
1976
 
 
1977
 
                //
1978
 
                // Handles the #line directive
1979
 
                //
1980
 
                bool PreProcessLine ()
1981
 
                {
1982
 
                        Location loc = Location;
1983
 
 
1984
 
                        int c;
1985
 
 
1986
 
                        int length = TokenizePreprocessorIdentifier (out c);
1987
 
                        if (length == line_default.Length) {
1988
 
                                if (!IsTokenIdentifierEqual (line_default))
1989
 
                                        return false;
1990
 
 
1991
 
                                current_source = source_file.SourceFile;
1992
 
                                if (!hidden_block_start.IsNull) {
1993
 
                                        current_source.RegisterHiddenScope (hidden_block_start, loc);
1994
 
                                        hidden_block_start = Location.Null;
1995
 
                                }
1996
 
 
1997
 
                                //ref_line = line;
1998
 
                                Location.Push (current_source);
1999
 
                                return true;
2000
 
                        }
2001
 
 
2002
 
                        if (length == line_hidden.Length) {
2003
 
                                if (!IsTokenIdentifierEqual (line_hidden))
2004
 
                                        return false;
2005
 
 
2006
 
                                if (hidden_block_start.IsNull)
2007
 
                                        hidden_block_start = loc;
2008
 
 
2009
 
                                return true;
2010
 
                        }
2011
 
 
2012
 
                        if (length != 0 || c < '0' || c > '9') {
2013
 
                                //
2014
 
                                // Eat any remaining characters to continue parsing on next line
2015
 
                                //
2016
 
                                while (c != -1 && c != '\n') {
2017
 
                                        c = get_char ();
2018
 
                                }
2019
 
 
2020
 
                                return false;
2021
 
                        }
2022
 
 
2023
 
                        int new_line = TokenizeNumber (c);
2024
 
                        if (new_line < 1) {
2025
 
                                //
2026
 
                                // Eat any remaining characters to continue parsing on next line
2027
 
                                //
2028
 
                                while (c != -1 && c != '\n') {
2029
 
                                        c = get_char ();
2030
 
                                }
2031
 
 
2032
 
                                return new_line != 0;
2033
 
                        }
2034
 
 
2035
 
                        c = get_char ();
2036
 
                        if (c == ' ') {
2037
 
                                // skip over white space
2038
 
                                do {
2039
 
                                        c = get_char ();
2040
 
                                } while (c == ' ' || c == '\t');
2041
 
                        } else if (c == '"') {
2042
 
                                c = 0;
2043
 
                        }
2044
 
 
2045
 
                        if (c != '\n' && c != '/' && c != '"') {
2046
 
                                //
2047
 
                                // Eat any remaining characters to continue parsing on next line
2048
 
                                //
2049
 
                                while (c != -1 && c != '\n') {
2050
 
                                        c = get_char ();
2051
 
                                }
2052
 
 
2053
 
                                Report.Error (1578, loc, "Filename, single-line comment or end-of-line expected");
2054
 
                                return true;
2055
 
                        }
2056
 
 
2057
 
                        string new_file_name = null;
2058
 
                        if (c == '"') {
2059
 
                                new_file_name = TokenizeFileName (ref c);
2060
 
 
2061
 
                                // skip over white space
2062
 
                                while (c == ' ' || c == '\t') {
2063
 
                                        c = get_char ();
2064
 
                                }
2065
 
                        }
2066
 
 
2067
 
                        if (c == '\n') {
2068
 
                        } else if (c == '/') {
2069
 
                                ReadSingleLineComment ();
2070
 
                        } else {
2071
 
                                //
2072
 
                                // Eat any remaining characters to continue parsing on next line
2073
 
                                //
2074
 
                                while (c != -1 && c != '\n') {
2075
 
                                        c = get_char ();
2076
 
                                }
2077
 
 
2078
 
                                Error_EndLineExpected ();
2079
 
                                return true;
2080
 
                        }
2081
 
 
2082
 
                        if (new_file_name != null) {
2083
 
                                current_source = context.LookupFile (source_file, new_file_name);
2084
 
                                source_file.AddIncludeFile (current_source);
2085
 
                                Location.Push (current_source);
2086
 
                        }
2087
 
 
2088
 
                        if (!hidden_block_start.IsNull) {
2089
 
                                current_source.RegisterHiddenScope (hidden_block_start, loc);
2090
 
                                hidden_block_start = Location.Null;
2091
 
                        }
2092
 
 
2093
 
                        //ref_line = new_line;
2094
 
                        return true;
2095
 
                }
2096
 
 
2097
 
                //
2098
 
                // Handles #define and #undef
2099
 
                //
2100
 
                void PreProcessDefinition (bool is_define, string ident, bool caller_is_taking)
2101
 
                {
2102
 
                        if (ident.Length == 0 || ident == "true" || ident == "false"){
2103
 
                                Report.Error (1001, Location, "Missing identifier to pre-processor directive");
2104
 
                                return;
2105
 
                        }
2106
 
 
2107
 
                        if (ident.IndexOfAny (simple_whitespaces) != -1){
2108
 
                                Error_EndLineExpected ();
2109
 
                                return;
2110
 
                        }
2111
 
 
2112
 
                        if (!is_identifier_start_character (ident [0]))
2113
 
                                Report.Error (1001, Location, "Identifier expected: {0}", ident);
2114
 
                        
2115
 
                        foreach (char c in ident.Substring (1)){
2116
 
                                if (!is_identifier_part_character (c)){
2117
 
                                        Report.Error (1001, Location, "Identifier expected: {0}",  ident);
2118
 
                                        return;
2119
 
                                }
2120
 
                        }
2121
 
 
2122
 
                        if (!caller_is_taking)
2123
 
                                return;
2124
 
 
2125
 
                        if (is_define) {
2126
 
                                //
2127
 
                                // #define ident
2128
 
                                //
2129
 
                                if (context.Settings.IsConditionalSymbolDefined (ident))
2130
 
                                        return;
2131
 
 
2132
 
                                source_file.AddDefine (ident);
2133
 
                        } else {
2134
 
                                //
2135
 
                                // #undef ident
2136
 
                                //
2137
 
                                source_file.AddUndefine (ident);
2138
 
                        }
2139
 
                }
2140
 
 
2141
 
                byte read_hex (out bool error)
2142
 
                {
2143
 
                        int total;
2144
 
                        int c = get_char ();
2145
 
 
2146
 
                        if ((c >= '0') && (c <= '9'))
2147
 
                                total = (int) c - (int) '0';
2148
 
                        else if ((c >= 'A') && (c <= 'F'))
2149
 
                                total = (int) c - (int) 'A' + 10;
2150
 
                        else if ((c >= 'a') && (c <= 'f'))
2151
 
                                total = (int) c - (int) 'a' + 10;
2152
 
                        else {
2153
 
                                error = true;
2154
 
                                return 0;
2155
 
                        }
2156
 
 
2157
 
                        total *= 16;
2158
 
                        c = get_char ();
2159
 
 
2160
 
                        if ((c >= '0') && (c <= '9'))
2161
 
                                total += (int) c - (int) '0';
2162
 
                        else if ((c >= 'A') && (c <= 'F'))
2163
 
                                total += (int) c - (int) 'A' + 10;
2164
 
                        else if ((c >= 'a') && (c <= 'f'))
2165
 
                                total += (int) c - (int) 'a' + 10;
2166
 
                        else {
2167
 
                                error = true;
2168
 
                                return 0;
2169
 
                        }
2170
 
 
2171
 
                        error = false;
2172
 
                        return (byte) total;
2173
 
                }
2174
 
 
2175
 
                //
2176
 
                // Parses #pragma checksum
2177
 
                //
2178
 
                bool ParsePragmaChecksum ()
2179
 
                {
2180
 
                        //
2181
 
                        // The syntax is ` "foo.txt" "{guid}" "hash"'
2182
 
                        //
2183
 
                        int c = get_char ();
2184
 
 
2185
 
                        if (c != '"')
2186
 
                                return false;
2187
 
 
2188
 
                        string file_name = TokenizeFileName (ref c);
2189
 
 
2190
 
                        // TODO: Any white-spaces count
2191
 
                        if (c != ' ')
2192
 
                                return false;
2193
 
 
2194
 
                        SourceFile file = context.LookupFile (source_file, file_name);
2195
 
 
2196
 
                        if (get_char () != '"' || get_char () != '{')
2197
 
                                return false;
2198
 
 
2199
 
                        bool error;
2200
 
                        byte[] guid_bytes = new byte [16];
2201
 
                        int i = 0;
2202
 
 
2203
 
                        for (; i < 4; i++) {
2204
 
                                guid_bytes [i] = read_hex (out error);
2205
 
                                if (error)
2206
 
                                        return false;
2207
 
                        }
2208
 
 
2209
 
                        if (get_char () != '-')
2210
 
                                return false;
2211
 
 
2212
 
                        for (; i < 10; i++) {
2213
 
                                guid_bytes [i] = read_hex (out error);
2214
 
                                if (error)
2215
 
                                        return false;
2216
 
 
2217
 
                                guid_bytes [i++] = read_hex (out error);
2218
 
                                if (error)
2219
 
                                        return false;
2220
 
 
2221
 
                                if (get_char () != '-')
2222
 
                                        return false;
2223
 
                        }
2224
 
 
2225
 
                        for (; i < 16; i++) {
2226
 
                                guid_bytes [i] = read_hex (out error);
2227
 
                                if (error)
2228
 
                                        return false;
2229
 
                        }
2230
 
 
2231
 
                        if (get_char () != '}' || get_char () != '"')
2232
 
                                return false;
2233
 
 
2234
 
                        // TODO: Any white-spaces count
2235
 
                        c = get_char ();
2236
 
                        if (c != ' ')
2237
 
                                return false;
2238
 
 
2239
 
                        if (get_char () != '"')
2240
 
                                return false;
2241
 
 
2242
 
                        // Any length of checksum
2243
 
                        List<byte> checksum_bytes = new List<byte> (16);
2244
 
 
2245
 
                        c = peek_char ();
2246
 
                        while (c != '"' && c != -1) {
2247
 
                                checksum_bytes.Add (read_hex (out error));
2248
 
                                if (error)
2249
 
                                        return false;
2250
 
 
2251
 
                                c = peek_char ();
2252
 
                        }
2253
 
 
2254
 
                        if (c == '/') {
2255
 
                                ReadSingleLineComment ();
2256
 
                        } else if (get_char () != '"') {
2257
 
                                return false;
2258
 
                        }
2259
 
 
2260
 
                        file.SetChecksum (guid_bytes, checksum_bytes.ToArray ());
2261
 
                        current_source.AutoGenerated = true;
2262
 
                        return true;
2263
 
                }
2264
 
 
2265
 
#if !FULL_AST
2266
 
                static
2267
 
#endif
2268
 
                bool IsTokenIdentifierEqual (char[] identifier)
2269
 
                {
2270
 
                        for (int i = 0; i < identifier.Length; ++i) {
2271
 
                                if (identifier[i] != id_builder[i])
2272
 
                                        return false;
2273
 
                        }
2274
 
 
2275
 
                        return true;
2276
 
                }
2277
 
 
2278
 
                int TokenizeNumber (int value)
2279
 
                {
2280
 
                        number_pos = 0;
2281
 
 
2282
 
                        decimal_digits (value);
2283
 
                        uint ui = (uint) (number_builder[0] - '0');
2284
 
 
2285
 
                        try {
2286
 
                                for (int i = 1; i < number_pos; i++) {
2287
 
                                        ui = checked ((ui * 10) + ((uint) (number_builder[i] - '0')));
2288
 
                                }
2289
 
 
2290
 
                                return (int) ui;
2291
 
                        } catch (OverflowException) {
2292
 
                                Error_NumericConstantTooLong ();
2293
 
                                return -1;
2294
 
                        }
2295
 
                }
2296
 
 
2297
 
                string TokenizeFileName (ref int c)
2298
 
                {
2299
 
                        var string_builder = new StringBuilder ();
2300
 
                        while (c != -1 && c != '\n') {
2301
 
                                c = get_char ();
2302
 
                                if (c == '"') {
2303
 
                                        c = get_char ();
2304
 
                                        break;
2305
 
                                }
2306
 
 
2307
 
                                string_builder.Append ((char) c);
2308
 
                        }
2309
 
 
2310
 
                        if (string_builder.Length == 0) {
2311
 
                                Report.Warning (1709, 1, Location, "Filename specified for preprocessor directive is empty");
2312
 
                        }
2313
 
 
2314
 
                
2315
 
                        return string_builder.ToString ();
2316
 
                }
2317
 
 
2318
 
                int TokenizePragmaNumber (ref int c)
2319
 
                {
2320
 
                        number_pos = 0;
2321
 
 
2322
 
                        int number;
2323
 
 
2324
 
                        if (c >= '0' && c <= '9') {
2325
 
                                number = TokenizeNumber (c);
2326
 
 
2327
 
                                c = get_char ();
2328
 
 
2329
 
                                // skip over white space
2330
 
                                while (c == ' ' || c == '\t')
2331
 
                                        c = get_char ();
2332
 
 
2333
 
                                if (c == ',') {
2334
 
                                        c = get_char ();
2335
 
                                }
2336
 
 
2337
 
                                // skip over white space
2338
 
                                while (c == ' ' || c == '\t')
2339
 
                                        c = get_char ();
2340
 
                        } else {
2341
 
                                number = -1;
2342
 
                                if (c == '/') {
2343
 
                                        ReadSingleLineComment ();
2344
 
                                } else {
2345
 
                                        Report.Warning (1692, 1, Location, "Invalid number");
2346
 
 
2347
 
                                        // Read everything till the end of the line or file
2348
 
                                        do {
2349
 
                                                c = get_char ();
2350
 
                                        } while (c != -1 && c != '\n');
2351
 
                                }
2352
 
                        }
2353
 
 
2354
 
                        return number;
2355
 
                }
2356
 
                
2357
 
                
2358
 
                void ReadSingleLineComment ()
2359
 
                {
2360
 
                        if (peek_char () != '/')
2361
 
                                Report.Warning (1696, 1, Location, "Single-line comment or end-of-line expected");
2362
 
                        if (position_stack.Count == 0)
2363
 
                                sbag.StartComment (SpecialsBag.CommentType.Single, startsLine, line, col - 1);
2364
 
                        // Read everything till the end of the line or file
2365
 
                        int c;
2366
 
                        do {
2367
 
                                c = get_char ();
2368
 
                                if (position_stack.Count == 0)
2369
 
                                        sbag.PushCommentChar (c);
2370
 
                                var pc = peek_char ();
2371
 
                                if ((pc == '\n' || pc == -1) && position_stack.Count == 0) 
2372
 
                                        sbag.EndComment (line, col + 1);
2373
 
                        } while (c != -1 && c != '\n');
2374
 
                }
2375
 
 
2376
 
                /// <summary>
2377
 
                /// Handles #pragma directive
2378
 
                /// </summary>
2379
 
                void ParsePragmaDirective (string arg)
2380
 
                {
2381
 
                        int c;
2382
 
                        int length = TokenizePreprocessorIdentifier (out c);
2383
 
                        if (length == pragma_warning.Length && IsTokenIdentifierEqual (pragma_warning)) {
2384
 
                                length = TokenizePreprocessorIdentifier (out c);
2385
 
 
2386
 
                                //
2387
 
                                // #pragma warning disable
2388
 
                                // #pragma warning restore
2389
 
                                //
2390
 
                                if (length == pragma_warning_disable.Length) {
2391
 
                                        bool disable = IsTokenIdentifierEqual (pragma_warning_disable);
2392
 
                                        if (disable || IsTokenIdentifierEqual (pragma_warning_restore)) {
2393
 
                                                // skip over white space
2394
 
                                                while (c == ' ' || c == '\t')
2395
 
                                                        c = get_char ();
2396
 
 
2397
 
                                                var loc = Location;
2398
 
 
2399
 
                                                if (c == '\n' || c == '/') {
2400
 
                                                        if (c == '/')
2401
 
                                                                ReadSingleLineComment ();
2402
 
 
2403
 
                                                        //
2404
 
                                                        // Disable/Restore all warnings
2405
 
                                                        //
2406
 
                                                        if (disable) {
2407
 
                                                                Report.RegisterWarningRegion (loc).WarningDisable (loc.Row);
2408
 
                                                        } else {
2409
 
                                                                Report.RegisterWarningRegion (loc).WarningEnable (loc.Row);
2410
 
                                                        }
2411
 
                                                } else {
2412
 
                                                        //
2413
 
                                                        // Disable/Restore a warning or group of warnings
2414
 
                                                        //
2415
 
                                                        int code;
2416
 
                                                        do {
2417
 
                                                                code = TokenizePragmaNumber (ref c);
2418
 
                                                                if (code > 0) {
2419
 
                                                                        if (disable) {
2420
 
                                                                                Report.RegisterWarningRegion (loc).WarningDisable (loc, code, context.Report);
2421
 
                                                                        } else {
2422
 
                                                                                Report.RegisterWarningRegion (loc).WarningEnable (loc, code, context);
2423
 
                                                                        }
2424
 
                                                                }
2425
 
                                                        } while (code >= 0 && c != '\n' && c != -1);
2426
 
                                                }
2427
 
 
2428
 
                                                return;
2429
 
                                        }
2430
 
                                }
2431
 
 
2432
 
                                Report.Warning (1634, 1, Location, "Expected disable or restore");
2433
 
                                return;
2434
 
                        }
2435
 
 
2436
 
                        //
2437
 
                        // #pragma checksum
2438
 
                        //
2439
 
                        if (length == pragma_checksum.Length && IsTokenIdentifierEqual (pragma_checksum)) {
2440
 
                                if (c != ' ' || !ParsePragmaChecksum ()) {
2441
 
                                        Report.Warning (1695, 1, Location,
2442
 
                                                "Invalid #pragma checksum syntax. Expected \"filename\" \"{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}\" \"XXXX...\"");
2443
 
                                }
2444
 
 
2445
 
                                return;
2446
 
                        }
2447
 
 
2448
 
                        Report.Warning (1633, 1, Location, "Unrecognized #pragma directive");
2449
 
                }
2450
 
 
2451
 
                bool eval_val (string s)
2452
 
                {
2453
 
                        if (s == "true")
2454
 
                                return true;
2455
 
                        if (s == "false")
2456
 
                                return false;
2457
 
 
2458
 
                        return source_file.IsConditionalDefined (s);
2459
 
                }
2460
 
 
2461
 
                bool pp_primary (ref string s)
2462
 
                {
2463
 
                        s = s.Trim ();
2464
 
                        int len = s.Length;
2465
 
 
2466
 
                        if (len > 0){
2467
 
                                char c = s [0];
2468
 
                                
2469
 
                                if (c == '('){
2470
 
                                        s = s.Substring (1);
2471
 
                                        bool val = pp_expr (ref s, false);
2472
 
                                        if (s.Length > 0 && s [0] == ')'){
2473
 
                                                s = s.Substring (1);
2474
 
                                                return val;
2475
 
                                        }
2476
 
                                        Error_InvalidDirective ();
2477
 
                                        return false;
2478
 
                                }
2479
 
                                
2480
 
                                if (is_identifier_start_character (c)){
2481
 
                                        int j = 1;
2482
 
 
2483
 
                                        while (j < len){
2484
 
                                                c = s [j];
2485
 
                                                
2486
 
                                                if (is_identifier_part_character (c)){
2487
 
                                                        j++;
2488
 
                                                        continue;
2489
 
                                                }
2490
 
                                                bool v = eval_val (s.Substring (0, j));
2491
 
                                                s = s.Substring (j);
2492
 
                                                return v;
2493
 
                                        }
2494
 
                                        bool vv = eval_val (s);
2495
 
                                        s = "";
2496
 
                                        return vv;
2497
 
                                }
2498
 
                        }
2499
 
                        Error_InvalidDirective ();
2500
 
                        return false;
2501
 
                }
2502
 
                
2503
 
                bool pp_unary (ref string s)
2504
 
                {
2505
 
                        s = s.Trim ();
2506
 
                        int len = s.Length;
2507
 
 
2508
 
                        if (len > 0){
2509
 
                                if (s [0] == '!'){
2510
 
                                        if (len > 1 && s [1] == '='){
2511
 
                                                Error_InvalidDirective ();
2512
 
                                                return false;
2513
 
                                        }
2514
 
                                        s = s.Substring (1);
2515
 
                                        return ! pp_primary (ref s);
2516
 
                                } else
2517
 
                                        return pp_primary (ref s);
2518
 
                        } else {
2519
 
                                Error_InvalidDirective ();
2520
 
                                return false;
2521
 
                        }
2522
 
                }
2523
 
                
2524
 
                bool pp_eq (ref string s)
2525
 
                {
2526
 
                        bool va = pp_unary (ref s);
2527
 
 
2528
 
                        s = s.Trim ();
2529
 
                        int len = s.Length;
2530
 
                        if (len > 0){
2531
 
                                if (s [0] == '='){
2532
 
                                        if (len > 2 && s [1] == '='){
2533
 
                                                s = s.Substring (2);
2534
 
                                                return va == pp_unary (ref s);
2535
 
                                        } else {
2536
 
                                                Error_InvalidDirective ();
2537
 
                                                return false;
2538
 
                                        }
2539
 
                                } else if (s [0] == '!' && len > 1 && s [1] == '='){
2540
 
                                        s = s.Substring (2);
2541
 
 
2542
 
                                        return va != pp_unary (ref s);
2543
 
 
2544
 
                                } 
2545
 
                        }
2546
 
 
2547
 
                        return va;
2548
 
                                
2549
 
                }
2550
 
                
2551
 
                bool pp_and (ref string s)
2552
 
                {
2553
 
                        bool va = pp_eq (ref s);
2554
 
 
2555
 
                        s = s.Trim ();
2556
 
                        int len = s.Length;
2557
 
                        if (len > 0){
2558
 
                                if (s [0] == '&'){
2559
 
                                        if (len > 2 && s [1] == '&'){
2560
 
                                                s = s.Substring (2);
2561
 
                                                return (va & pp_and (ref s));
2562
 
                                        } else {
2563
 
                                                Error_InvalidDirective ();
2564
 
                                                return false;
2565
 
                                        }
2566
 
                                } 
2567
 
                        }
2568
 
                        return va;
2569
 
                }
2570
 
                
2571
 
                //
2572
 
                // Evaluates an expression for `#if' or `#elif'
2573
 
                //
2574
 
                bool pp_expr (ref string s, bool isTerm)
2575
 
                {
2576
 
                        bool va = pp_and (ref s);
2577
 
                        s = s.Trim ();
2578
 
                        int len = s.Length;
2579
 
                        if (len > 0){
2580
 
                                char c = s [0];
2581
 
                                
2582
 
                                if (c == '|'){
2583
 
                                        if (len > 2 && s [1] == '|'){
2584
 
                                                s = s.Substring (2);
2585
 
                                                return va | pp_expr (ref s, isTerm);
2586
 
                                        } else {
2587
 
                                                Error_InvalidDirective ();
2588
 
                                                return false;
2589
 
                                        }
2590
 
                                }
2591
 
                                if (isTerm) {
2592
 
                                        Error_EndLineExpected ();
2593
 
                                        return false;
2594
 
                                }
2595
 
                        }
2596
 
                        
2597
 
                        return va;
2598
 
                }
2599
 
 
2600
 
                bool eval (string s)
2601
 
                {
2602
 
                        bool v = pp_expr (ref s, true);
2603
 
                        s = s.Trim ();
2604
 
                        if (s.Length != 0){
2605
 
                                return false;
2606
 
                        }
2607
 
 
2608
 
                        return v;
2609
 
                }
2610
 
 
2611
 
                void Error_NumericConstantTooLong ()
2612
 
                {
2613
 
                        Report.Error (1021, Location, "Integral constant is too large");                        
2614
 
                }
2615
 
                
2616
 
                void Error_InvalidDirective ()
2617
 
                {
2618
 
                        Report.Error (1517, Location, "Invalid preprocessor directive");
2619
 
                }
2620
 
 
2621
 
                void Error_UnexpectedDirective (string extra)
2622
 
                {
2623
 
                        Report.Error (
2624
 
                                1028, Location,
2625
 
                                "Unexpected processor directive ({0})", extra);
2626
 
                }
2627
 
 
2628
 
                void Error_TokensSeen ()
2629
 
                {
2630
 
                        Report.Error (1032, Location,
2631
 
                                "Cannot define or undefine preprocessor symbols after first token in file");
2632
 
                }
2633
 
 
2634
 
                void Eror_WrongPreprocessorLocation ()
2635
 
                {
2636
 
                        Report.Error (1040, Location,
2637
 
                                "Preprocessor directives must appear as the first non-whitespace character on a line");
2638
 
                }
2639
 
 
2640
 
                void Error_EndLineExpected ()
2641
 
                {
2642
 
                        Report.Error (1025, Location, "Single-line comment or end-of-line expected");
2643
 
                }
2644
 
 
2645
 
                //
2646
 
                // Raises a warning when tokenizer found documentation comment
2647
 
                // on unexpected place
2648
 
                //
2649
 
                void WarningMisplacedComment (Location loc)
2650
 
                {
2651
 
                        if (doc_state != XmlCommentState.Error) {
2652
 
                                doc_state = XmlCommentState.Error;
2653
 
                                Report.Warning (1587, 2, loc, "XML comment is not placed on a valid language element");
2654
 
                        }
2655
 
                }
2656
 
                
2657
 
                //
2658
 
                // if true, then the code continues processing the code
2659
 
                // if false, the code stays in a loop until another directive is
2660
 
                // reached.
2661
 
                // When caller_is_taking is false we ignore all directives except the ones
2662
 
                // which can help us to identify where the #if block ends
2663
 
                bool ParsePreprocessingDirective (bool caller_is_taking)
2664
 
                {
2665
 
                        string arg;
2666
 
                        bool region_directive = false;
2667
 
 
2668
 
                        var directive = get_cmd_arg (out arg);
2669
 
 
2670
 
                        //
2671
 
                        // The first group of pre-processing instructions is always processed
2672
 
                        //
2673
 
                        switch (directive) {
2674
 
                        case PreprocessorDirective.Region:
2675
 
                                region_directive = true;
2676
 
                                arg = "true";
2677
 
                                goto case PreprocessorDirective.If;
2678
 
 
2679
 
                        case PreprocessorDirective.Endregion:
2680
 
                                if (ifstack == null || ifstack.Count == 0){
2681
 
                                        Error_UnexpectedDirective ("no #region for this #endregion");
2682
 
                                        return true;
2683
 
                                }
2684
 
                                int pop = ifstack.Pop ();
2685
 
                                        
2686
 
                                if ((pop & REGION) == 0)
2687
 
                                        Report.Error (1027, Location, "Expected `#endif' directive");
2688
 
                                        
2689
 
                                return caller_is_taking;
2690
 
                                
2691
 
                        case PreprocessorDirective.If:
2692
 
                                if (ifstack == null)
2693
 
                                        ifstack = new Stack<int> (2);
2694
 
 
2695
 
                                int flags = region_directive ? REGION : 0;
2696
 
                                if (ifstack.Count == 0){
2697
 
                                        flags |= PARENT_TAKING;
2698
 
                                } else {
2699
 
                                        int state = ifstack.Peek ();
2700
 
                                        if ((state & TAKING) != 0) {
2701
 
                                                flags |= PARENT_TAKING;
2702
 
                                        }
2703
 
                                }
2704
 
 
2705
 
                                if (eval (arg) && caller_is_taking) {
2706
 
                                        ifstack.Push (flags | TAKING);
2707
 
                                        return true;
2708
 
                                }
2709
 
                                sbag.SkipIf ();
2710
 
                                ifstack.Push (flags);
2711
 
                                return false;
2712
 
 
2713
 
                        case PreprocessorDirective.Endif:
2714
 
                                if (ifstack == null || ifstack.Count == 0){
2715
 
                                        Error_UnexpectedDirective ("no #if for this #endif");
2716
 
                                        return true;
2717
 
                                } else {
2718
 
                                        pop = ifstack.Pop ();
2719
 
                                        
2720
 
                                        if ((pop & REGION) != 0)
2721
 
                                                Report.Error (1038, Location, "#endregion directive expected");
2722
 
                                        
2723
 
                                        if (arg.Length != 0) {
2724
 
                                                Error_EndLineExpected ();
2725
 
                                        }
2726
 
                                        
2727
 
                                        if (ifstack.Count == 0)
2728
 
                                                return true;
2729
 
 
2730
 
                                        int state = ifstack.Peek ();
2731
 
                                        return (state & TAKING) != 0;
2732
 
                                }
2733
 
 
2734
 
                        case PreprocessorDirective.Elif:
2735
 
                                if (ifstack == null || ifstack.Count == 0){
2736
 
                                        Error_UnexpectedDirective ("no #if for this #elif");
2737
 
                                        return true;
2738
 
                                } else {
2739
 
                                        int state = ifstack.Pop ();
2740
 
 
2741
 
                                        if ((state & REGION) != 0) {
2742
 
                                                Report.Error (1038, Location, "#endregion directive expected");
2743
 
                                                return true;
2744
 
                                        }
2745
 
 
2746
 
                                        if ((state & ELSE_SEEN) != 0){
2747
 
                                                Error_UnexpectedDirective ("#elif not valid after #else");
2748
 
                                                return true;
2749
 
                                        }
2750
 
 
2751
 
                                        if ((state & TAKING) != 0) {
2752
 
                                                ifstack.Push (0);
2753
 
                                                return false;
2754
 
                                        }
2755
 
 
2756
 
                                        if (eval (arg) && ((state & PARENT_TAKING) != 0)){
2757
 
                                                ifstack.Push (state | TAKING);
2758
 
                                                return true;
2759
 
                                        }
2760
 
 
2761
 
                                        ifstack.Push (state);
2762
 
                                        return false;
2763
 
                                }
2764
 
 
2765
 
                        case PreprocessorDirective.Else:
2766
 
                                if (ifstack == null || ifstack.Count == 0){
2767
 
                                        Error_UnexpectedDirective ("no #if for this #else");
2768
 
                                        return true;
2769
 
                                } else {
2770
 
                                        int state = ifstack.Peek ();
2771
 
 
2772
 
                                        if ((state & REGION) != 0) {
2773
 
                                                Report.Error (1038, Location, "#endregion directive expected");
2774
 
                                                return true;
2775
 
                                        }
2776
 
 
2777
 
                                        if ((state & ELSE_SEEN) != 0){
2778
 
                                                Error_UnexpectedDirective ("#else within #else");
2779
 
                                                return true;
2780
 
                                        }
2781
 
 
2782
 
                                        ifstack.Pop ();
2783
 
 
2784
 
                                        if (arg.Length != 0) {
2785
 
                                                Error_EndLineExpected ();
2786
 
                                                return true;
2787
 
                                        }
2788
 
 
2789
 
                                        bool ret = false;
2790
 
                                        if ((state & PARENT_TAKING) != 0) {
2791
 
                                                ret = (state & TAKING) == 0;
2792
 
                                        
2793
 
                                                if (ret)
2794
 
                                                        state |= TAKING;
2795
 
                                                else
2796
 
                                                        state &= ~TAKING;
2797
 
                                        }
2798
 
        
2799
 
                                        ifstack.Push (state | ELSE_SEEN);
2800
 
                                        
2801
 
                                        return ret;
2802
 
                                }
2803
 
                        case PreprocessorDirective.Define:
2804
 
                                if (any_token_seen){
2805
 
                                        Error_TokensSeen ();
2806
 
                                        return caller_is_taking;
2807
 
                                }
2808
 
                                PreProcessDefinition (true, arg, caller_is_taking);
2809
 
                                return caller_is_taking;
2810
 
 
2811
 
                        case PreprocessorDirective.Undef:
2812
 
                                if (any_token_seen){
2813
 
                                        Error_TokensSeen ();
2814
 
                                        return caller_is_taking;
2815
 
                                }
2816
 
                                PreProcessDefinition (false, arg, caller_is_taking);
2817
 
                                return caller_is_taking;
2818
 
 
2819
 
                        case PreprocessorDirective.Invalid:
2820
 
                                Report.Error (1024, Location, "Wrong preprocessor directive");
2821
 
                                return true;
2822
 
                        }
2823
 
 
2824
 
                        //
2825
 
                        // These are only processed if we are in a `taking' block
2826
 
                        //
2827
 
                        if (!caller_is_taking)
2828
 
                                return false;
2829
 
                                        
2830
 
                        switch (directive){
2831
 
                        case PreprocessorDirective.Error:
2832
 
                                Report.Error (1029, Location, "#error: '{0}'", arg);
2833
 
                                return true;
2834
 
 
2835
 
                        case PreprocessorDirective.Warning:
2836
 
                                Report.Warning (1030, 1, Location, "#warning: `{0}'", arg);
2837
 
                                return true;
2838
 
 
2839
 
                        case PreprocessorDirective.Pragma:
2840
 
                                if (context.Settings.Version == LanguageVersion.ISO_1) {
2841
 
                                        Report.FeatureIsNotAvailable (context, Location, "#pragma");
2842
 
                                }
2843
 
 
2844
 
                                ParsePragmaDirective (arg);
2845
 
                                return true;
2846
 
 
2847
 
                        case PreprocessorDirective.Line:
2848
 
                                Location loc = Location;
2849
 
                                if (!PreProcessLine ())
2850
 
                                        Report.Error (1576, loc, "The line number specified for #line directive is missing or invalid");
2851
 
 
2852
 
                                return caller_is_taking;
2853
 
                        }
2854
 
 
2855
 
                        throw new NotImplementedException (directive.ToString ());
2856
 
                }
2857
 
 
2858
 
                private int consume_string (bool quoted)
2859
 
                {
2860
 
                        int c;
2861
 
                        int pos = 0;
2862
 
                        Location start_location = Location;
2863
 
                        if (quoted)
2864
 
                                start_location = start_location - 1;
2865
 
 
2866
 
#if FULL_AST
2867
 
                        int reader_pos = reader.Position;
2868
 
#endif
2869
 
 
2870
 
                        while (true){
2871
 
                                c = get_char ();
2872
 
                                if (c == '"') {
2873
 
                                        if (quoted && peek_char () == '"') {
2874
 
                                                if (pos == value_builder.Length)
2875
 
                                                        Array.Resize (ref value_builder, pos * 2);
2876
 
 
2877
 
                                                value_builder[pos++] = (char) c;
2878
 
                                                get_char ();
2879
 
                                                continue;
2880
 
                                        }
2881
 
 
2882
 
                                        string s;
2883
 
                                        if (pos == 0)
2884
 
                                                s = string.Empty;
2885
 
                                        else if (pos <= 4)
2886
 
                                                s = InternIdentifier (value_builder, pos);
2887
 
                                        else
2888
 
                                                s = new string (value_builder, 0, pos);
2889
 
 
2890
 
                                        ILiteralConstant res = new StringLiteral (context.BuiltinTypes, s, start_location);
2891
 
                                        val = res;
2892
 
#if FULL_AST
2893
 
                                        res.ParsedValue = quoted ?
2894
 
                                                reader.ReadChars (reader_pos - 2, reader.Position - 1) :
2895
 
                                                reader.ReadChars (reader_pos - 1, reader.Position);
2896
 
#endif
2897
 
 
2898
 
                                        return Token.LITERAL;
2899
 
                                }
2900
 
 
2901
 
                                if (c == '\n') {
2902
 
                                        if (!quoted) {
2903
 
                                                Report.Error (1010, Location, "Newline in constant");
2904
 
                                                val = new StringLiteral (context.BuiltinTypes, new string (value_builder, 0, pos), start_location);
2905
 
                                                return Token.LITERAL;
2906
 
                                        }
2907
 
                                } else if (c == '\\' && !quoted) {
2908
 
                                        int surrogate;
2909
 
                                        c = escape (c, out surrogate);
2910
 
                                        if (c == -1)
2911
 
                                                return Token.ERROR;
2912
 
                                        if (surrogate != 0) {
2913
 
                                                if (pos == value_builder.Length)
2914
 
                                                        Array.Resize (ref value_builder, pos * 2);
2915
 
 
2916
 
                                                value_builder[pos++] = (char) c;
2917
 
                                                c = surrogate;
2918
 
                                        }
2919
 
                                } else if (c == -1) {
2920
 
                                        Report.Error (1039, Location, "Unterminated string literal");
2921
 
                                        return Token.EOF;
2922
 
                                }
2923
 
 
2924
 
                                if (pos == value_builder.Length)
2925
 
                                        Array.Resize (ref value_builder, pos * 2);
2926
 
 
2927
 
                                value_builder[pos++] = (char) c;
2928
 
                        }
2929
 
                }
2930
 
 
2931
 
                private int consume_identifier (int s)
2932
 
                {
2933
 
                        int res = consume_identifier (s, false);
2934
 
 
2935
 
                        if (doc_state == XmlCommentState.Allowed)
2936
 
                                doc_state = XmlCommentState.NotAllowed;
2937
 
                        startsLine = false;
2938
 
                        return res;
2939
 
                }
2940
 
 
2941
 
                int consume_identifier (int c, bool quoted) 
2942
 
                {
2943
 
                        //
2944
 
                        // This method is very performance sensitive. It accounts
2945
 
                        // for approximately 25% of all parser time
2946
 
                        //
2947
 
 
2948
 
                        int pos = 0;
2949
 
                        int column = col;
2950
 
                        if (quoted)
2951
 
                                --column;
2952
 
 
2953
 
                        if (c == '\\') {
2954
 
                                int surrogate;
2955
 
                                c = escape (c, out surrogate);
2956
 
                                if (surrogate != 0) {
2957
 
                                        id_builder [pos++] = (char) c;
2958
 
                                        c = surrogate;
2959
 
                                }
2960
 
                        }
2961
 
 
2962
 
                        id_builder [pos++] = (char) c;
2963
 
 
2964
 
                        try {
2965
 
                                while (true) {
2966
 
                                        c = reader.Read ();
2967
 
 
2968
 
                                        if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_' || (c >= '0' && c <= '9')) {
2969
 
                                                id_builder [pos++] = (char) c;
2970
 
                                                continue;
2971
 
                                        }
2972
 
 
2973
 
                                        if (c < 0x80) {
2974
 
                                                if (c == '\\') {
2975
 
                                                        int surrogate;
2976
 
                                                        c = escape (c, out surrogate);
2977
 
                                                        if (is_identifier_part_character ((char) c))
2978
 
                                                                id_builder[pos++] = (char) c;
2979
 
 
2980
 
                                                        if (surrogate != 0) {
2981
 
                                                                c = surrogate;
2982
 
                                                        }
2983
 
 
2984
 
                                                        continue;
2985
 
                                                }
2986
 
                                        } else if (Char.IsLetter ((char) c) || Char.GetUnicodeCategory ((char) c) == UnicodeCategory.ConnectorPunctuation) {
2987
 
                                                id_builder [pos++] = (char) c;
2988
 
                                                continue;
2989
 
                                        }
2990
 
 
2991
 
                                        putback_char = c;
2992
 
                                        break;
2993
 
                                }
2994
 
                        } catch (IndexOutOfRangeException) {
2995
 
                                Report.Error (645, Location, "Identifier too long (limit is 512 chars)");
2996
 
                                --pos;
2997
 
                                col += pos;
2998
 
                        }
2999
 
 
3000
 
                        col += pos - 1;
3001
 
 
3002
 
                        //
3003
 
                        // Optimization: avoids doing the keyword lookup
3004
 
                        // on uppercase letters
3005
 
                        //
3006
 
                        if (id_builder [0] >= '_' && !quoted) {
3007
 
                                int keyword = GetKeyword (id_builder, pos);
3008
 
                                if (keyword != -1) {
3009
 
                                        val = LocatedToken.Create (keyword == Token.AWAIT ? "await" : null, ref_line, column);
3010
 
                                        return keyword;
3011
 
                                }
3012
 
                        }
3013
 
 
3014
 
                        string s = InternIdentifier (id_builder, pos);
3015
 
#if FULL_AST
3016
 
                        if (quoted) {
3017
 
                                val = LocatedToken.Create ("@" + s, ref_line, column - 1);
3018
 
                        } else {
3019
 
                                val = LocatedToken.Create (s, ref_line, column);
3020
 
                        }
3021
 
#else
3022
 
                        val = LocatedToken.Create (s, ref_line, column);
3023
 
#endif
3024
 
                        if (quoted && parsing_attribute_section)
3025
 
                                AddEscapedIdentifier (((LocatedToken) val).Location);
3026
 
 
3027
 
                        return Token.IDENTIFIER;
3028
 
                }
3029
 
 
3030
 
#if !FULL_AST
3031
 
                static
3032
 
#endif
3033
 
                string InternIdentifier (char[] charBuffer, int length)
3034
 
                {
3035
 
                        //
3036
 
                        // Keep identifiers in an array of hashtables to avoid needless
3037
 
                        // allocations
3038
 
                        //
3039
 
                        var identifiers_group = identifiers [length];
3040
 
                        string s;
3041
 
                        if (identifiers_group != null) {
3042
 
                                if (identifiers_group.TryGetValue (charBuffer, out s)) {
3043
 
                                        return s;
3044
 
                                }
3045
 
                        } else {
3046
 
                                // TODO: this should be number of files dependant
3047
 
                                // corlib compilation peaks at 1000 and System.Core at 150
3048
 
                                int capacity = length > 20 ? 10 : 100;
3049
 
                                identifiers_group = new Dictionary<char[], string> (capacity, new IdentifiersComparer (length));
3050
 
                                identifiers [length] = identifiers_group;
3051
 
                        }
3052
 
 
3053
 
                        char[] chars = new char[length];
3054
 
                        Array.Copy (charBuffer, chars, length);
3055
 
 
3056
 
                        s = new string (charBuffer, 0, length);
3057
 
                        identifiers_group.Add (chars, s);
3058
 
 
3059
 
                        return s;
3060
 
                }
3061
 
                
3062
 
                public int xtoken ()
3063
 
                {
3064
 
                        int d, c;
3065
 
 
3066
 
                        // Whether we have seen comments on the current line
3067
 
                        bool comments_seen = false;
3068
 
                        while ((c = get_char ()) != -1) {
3069
 
                                switch (c) {
3070
 
                                case '\t':
3071
 
                                        col = ((col - 1 + tab_size) / tab_size) * tab_size;
3072
 
                                        continue;
3073
 
 
3074
 
                                case ' ':
3075
 
                                case '\f':
3076
 
                                case '\v':
3077
 
                                case 0xa0:
3078
 
                                case 0:
3079
 
                                case 0xFEFF:    // Ignore BOM anywhere in the file
3080
 
                                        continue;
3081
 
 
3082
 
/*                              This is required for compatibility with .NET
3083
 
                                case 0xEF:
3084
 
                                        if (peek_char () == 0xBB) {
3085
 
                                                PushPosition ();
3086
 
                                                get_char ();
3087
 
                                                if (get_char () == 0xBF)
3088
 
                                                        continue;
3089
 
                                                PopPosition ();
3090
 
                                        }
3091
 
                                        break;
3092
 
*/
3093
 
                                case '\\':
3094
 
                                        tokens_seen = true;
3095
 
                                        return consume_identifier (c);
3096
 
 
3097
 
                                case '{':
3098
 
                                        val = LocatedToken.Create (ref_line, col);
3099
 
                                        return Token.OPEN_BRACE;
3100
 
                                case '}':
3101
 
                                        val = LocatedToken.Create (ref_line, col);
3102
 
                                        return Token.CLOSE_BRACE;
3103
 
                                case '[':
3104
 
                                        // To block doccomment inside attribute declaration.
3105
 
                                        if (doc_state == XmlCommentState.Allowed)
3106
 
                                                doc_state = XmlCommentState.NotAllowed;
3107
 
 
3108
 
                                        val = LocatedToken.Create (ref_line, col);
3109
 
 
3110
 
                                        if (parsing_block == 0 || lambda_arguments_parsing)
3111
 
                                                return Token.OPEN_BRACKET;
3112
 
 
3113
 
                                        int next = peek_char ();
3114
 
                                        switch (next) {
3115
 
                                        case ']':
3116
 
                                        case ',':
3117
 
                                                return Token.OPEN_BRACKET;
3118
 
 
3119
 
                                        case ' ':
3120
 
                                        case '\f':
3121
 
                                        case '\v':
3122
 
                                        case '\r':
3123
 
                                        case '\n':
3124
 
                                        case '/':
3125
 
                                                next = peek_token ();
3126
 
                                                if (next == Token.COMMA || next == Token.CLOSE_BRACKET)
3127
 
                                                        return Token.OPEN_BRACKET;
3128
 
 
3129
 
                                                return Token.OPEN_BRACKET_EXPR;
3130
 
                                        default:
3131
 
                                                return Token.OPEN_BRACKET_EXPR;
3132
 
                                        }
3133
 
                                case ']':
3134
 
                                        LocatedToken.CreateOptional (ref_line, col, ref val);
3135
 
                                        return Token.CLOSE_BRACKET;
3136
 
                                case '(':
3137
 
                                        val = LocatedToken.Create (ref_line, col);
3138
 
                                        //
3139
 
                                        // An expression versions of parens can appear in block context only
3140
 
                                        //
3141
 
                                        if (parsing_block != 0 && !lambda_arguments_parsing) {
3142
 
                                                
3143
 
                                                //
3144
 
                                                // Optmize most common case where we know that parens
3145
 
                                                // is not special
3146
 
                                                //
3147
 
                                                switch (current_token) {
3148
 
                                                case Token.IDENTIFIER:
3149
 
                                                case Token.IF:
3150
 
                                                case Token.FOR:
3151
 
                                                case Token.FOREACH:
3152
 
                                                case Token.TYPEOF:
3153
 
                                                case Token.WHILE:
3154
 
                                                case Token.USING:
3155
 
                                                case Token.DEFAULT:
3156
 
                                                case Token.DELEGATE:
3157
 
                                                case Token.OP_GENERICS_GT:
3158
 
                                                        return Token.OPEN_PARENS;
3159
 
                                                }
3160
 
 
3161
 
                                                // Optimize using peek
3162
 
                                                int xx = peek_char ();
3163
 
                                                switch (xx) {
3164
 
                                                case '(':
3165
 
                                                case '\'':
3166
 
                                                case '"':
3167
 
                                                case '0':
3168
 
                                                case '1':
3169
 
                                                        return Token.OPEN_PARENS;
3170
 
                                                }
3171
 
 
3172
 
                                                lambda_arguments_parsing = true;
3173
 
                                                PushPosition ();
3174
 
                                                d = TokenizeOpenParens ();
3175
 
                                                PopPosition ();
3176
 
                                                lambda_arguments_parsing = false;
3177
 
                                                return d;
3178
 
                                        }
3179
 
 
3180
 
                                        return Token.OPEN_PARENS;
3181
 
                                case ')':
3182
 
                                        LocatedToken.CreateOptional (ref_line, col, ref val);
3183
 
                                        return Token.CLOSE_PARENS;
3184
 
                                case ',':
3185
 
                                        LocatedToken.CreateOptional (ref_line, col, ref val);
3186
 
                                        return Token.COMMA;
3187
 
                                case ';':
3188
 
                                        LocatedToken.CreateOptional (ref_line, col, ref val);
3189
 
                                        return Token.SEMICOLON;
3190
 
                                case '~':
3191
 
                                        val = LocatedToken.Create (ref_line, col);
3192
 
                                        return Token.TILDE;
3193
 
                                case '?':
3194
 
                                        val = LocatedToken.Create (ref_line, col);
3195
 
                                        return TokenizePossibleNullableType ();
3196
 
                                case '<':
3197
 
                                        val = LocatedToken.Create (ref_line, col);
3198
 
                                        if (parsing_generic_less_than++ > 0)
3199
 
                                                return Token.OP_GENERICS_LT;
3200
 
 
3201
 
                                        return TokenizeLessThan ();
3202
 
 
3203
 
                                case '>':
3204
 
                                        val = LocatedToken.Create (ref_line, col);
3205
 
                                        d = peek_char ();
3206
 
 
3207
 
                                        if (d == '=') {
3208
 
                                                get_char ();
3209
 
                                                return Token.OP_GE;
3210
 
                                        }
3211
 
 
3212
 
                                        if (parsing_generic_less_than > 1 || (parsing_generic_less_than == 1 && d != '>')) {
3213
 
                                                parsing_generic_less_than--;
3214
 
                                                return Token.OP_GENERICS_GT;
3215
 
                                        }
3216
 
 
3217
 
                                        if (d == '>') {
3218
 
                                                get_char ();
3219
 
                                                d = peek_char ();
3220
 
 
3221
 
                                                if (d == '=') {
3222
 
                                                        get_char ();
3223
 
                                                        return Token.OP_SHIFT_RIGHT_ASSIGN;
3224
 
                                                }
3225
 
                                                return Token.OP_SHIFT_RIGHT;
3226
 
                                        }
3227
 
 
3228
 
                                        return Token.OP_GT;
3229
 
 
3230
 
                                case '+':
3231
 
                                        val = LocatedToken.Create (ref_line, col);
3232
 
                                        d = peek_char ();
3233
 
                                        if (d == '+') {
3234
 
                                                d = Token.OP_INC;
3235
 
                                        } else if (d == '=') {
3236
 
                                                d = Token.OP_ADD_ASSIGN;
3237
 
                                        } else {
3238
 
                                                return Token.PLUS;
3239
 
                                        }
3240
 
                                        get_char ();
3241
 
                                        return d;
3242
 
 
3243
 
                                case '-':
3244
 
                                        val = LocatedToken.Create (ref_line, col);
3245
 
                                        d = peek_char ();
3246
 
                                        if (d == '-') {
3247
 
                                                d = Token.OP_DEC;
3248
 
                                        } else if (d == '=')
3249
 
                                                d = Token.OP_SUB_ASSIGN;
3250
 
                                        else if (d == '>')
3251
 
                                                d = Token.OP_PTR;
3252
 
                                        else {
3253
 
                                                return Token.MINUS;
3254
 
                                        }
3255
 
                                        get_char ();
3256
 
                                        return d;
3257
 
 
3258
 
                                case '!':
3259
 
                                        val = LocatedToken.Create (ref_line, col);
3260
 
                                        if (peek_char () == '=') {
3261
 
                                                get_char ();
3262
 
                                                return Token.OP_NE;
3263
 
                                        }
3264
 
                                        return Token.BANG;
3265
 
 
3266
 
                                case '=':
3267
 
                                        val = LocatedToken.Create (ref_line, col);
3268
 
                                        d = peek_char ();
3269
 
                                        if (d == '=') {
3270
 
                                                get_char ();
3271
 
                                                return Token.OP_EQ;
3272
 
                                        }
3273
 
                                        if (d == '>') {
3274
 
                                                get_char ();
3275
 
                                                return Token.ARROW;
3276
 
                                        }
3277
 
 
3278
 
                                        return Token.ASSIGN;
3279
 
 
3280
 
                                case '&':
3281
 
                                        val = LocatedToken.Create (ref_line, col);
3282
 
                                        d = peek_char ();
3283
 
                                        if (d == '&') {
3284
 
                                                get_char ();
3285
 
                                                return Token.OP_AND;
3286
 
                                        }
3287
 
                                        if (d == '=') {
3288
 
                                                get_char ();
3289
 
                                                return Token.OP_AND_ASSIGN;
3290
 
                                        }
3291
 
                                        return Token.BITWISE_AND;
3292
 
 
3293
 
                                case '|':
3294
 
                                        val = LocatedToken.Create (ref_line, col);
3295
 
                                        d = peek_char ();
3296
 
                                        if (d == '|') {
3297
 
                                                get_char ();
3298
 
                                                return Token.OP_OR;
3299
 
                                        }
3300
 
                                        if (d == '=') {
3301
 
                                                get_char ();
3302
 
                                                return Token.OP_OR_ASSIGN;
3303
 
                                        }
3304
 
                                        return Token.BITWISE_OR;
3305
 
 
3306
 
                                case '*':
3307
 
                                        val = LocatedToken.Create (ref_line, col);
3308
 
                                        if (peek_char () == '=') {
3309
 
                                                get_char ();
3310
 
                                                return Token.OP_MULT_ASSIGN;
3311
 
                                        }
3312
 
                                        return Token.STAR;
3313
 
 
3314
 
                                case '/':
3315
 
                                        d = peek_char ();
3316
 
                                        if (d == '=') {
3317
 
                                                val = LocatedToken.Create (ref_line, col);
3318
 
                                                get_char ();
3319
 
                                                return Token.OP_DIV_ASSIGN;
3320
 
                                        }
3321
 
                                        // Handle double-slash comments.
3322
 
                                        if (d == '/') {
3323
 
                                                get_char ();
3324
 
                                                if (doc_processing) {
3325
 
                                                        if (peek_char () == '/') {
3326
 
                                                                get_char ();
3327
 
                                                                // Don't allow ////.
3328
 
                                                                if ((d = peek_char ()) != '/') {
3329
 
                                                                        if (position_stack.Count == 0)
3330
 
                                                                                sbag.PushCommentChar (d);
3331
 
                                                                        if (doc_state == XmlCommentState.Allowed)
3332
 
                                                                                handle_one_line_xml_comment ();
3333
 
                                                                        else if (doc_state == XmlCommentState.NotAllowed)
3334
 
                                                                                WarningMisplacedComment (Location - 3);
3335
 
                                                                }
3336
 
                                                        } else {
3337
 
                                                                if (xml_comment_buffer.Length > 0)
3338
 
                                                                        doc_state = XmlCommentState.NotAllowed;
3339
 
                                                        }
3340
 
                                                } else {
3341
 
                                                        bool isDoc = peek_char () == '/';
3342
 
                                                        if (position_stack.Count == 0)
3343
 
                                                                sbag.StartComment (isDoc ? SpecialsBag.CommentType.Documentation : SpecialsBag.CommentType.Single, startsLine, line, col - 1);
3344
 
                                                        if (isDoc)
3345
 
                                                                get_char ();
3346
 
                                                }
3347
 
                                                
3348
 
                                                d = peek_char ();
3349
 
                                                int endLine = line, endCol = col;
3350
 
                                                while ((d = get_char ()) != -1 && (d != '\n') && d != '\r') {
3351
 
                                                        if (position_stack.Count == 0)
3352
 
                                                                sbag.PushCommentChar (d);
3353
 
                                                        endLine = line;
3354
 
                                                        endCol = col;
3355
 
                                                }
3356
 
                                                if (position_stack.Count == 0)
3357
 
                                                        sbag.EndComment (endLine, endCol + 1);
3358
 
                                                                                                
3359
 
                                                any_token_seen |= tokens_seen;
3360
 
                                                tokens_seen = false;
3361
 
                                                comments_seen = false;
3362
 
                                                continue;
3363
 
                                        } else if (d == '*'){
3364
 
                                                if (position_stack.Count == 0)
3365
 
                                                        sbag.StartComment (SpecialsBag.CommentType.Multi, startsLine, line, col);
3366
 
                                                get_char ();
3367
 
                                                bool docAppend = false;
3368
 
                                                if (doc_processing && peek_char () == '*') {
3369
 
                                                        int ch = get_char ();
3370
 
                                                        // But when it is /**/, just do nothing.
3371
 
                                                        if (peek_char () == '/') {
3372
 
                                                                ch = get_char ();
3373
 
                                                                if (position_stack.Count == 0) {
3374
 
                                                                        sbag.EndComment (line, col + 1);
3375
 
                                                                }
3376
 
                                                                continue;
3377
 
                                                        } else {
3378
 
                                                                if (position_stack.Count == 0)
3379
 
                                                                        sbag.PushCommentChar (ch);
3380
 
                                                        }
3381
 
                                                        if (doc_state == XmlCommentState.Allowed)
3382
 
                                                                docAppend = true;
3383
 
                                                        else if (doc_state == XmlCommentState.NotAllowed) {
3384
 
                                                                WarningMisplacedComment (Location - 2);
3385
 
                                                        }
3386
 
                                                }
3387
 
 
3388
 
                                                int current_comment_start = 0;
3389
 
                                                if (docAppend) {
3390
 
                                                        current_comment_start = xml_comment_buffer.Length;
3391
 
                                                        xml_comment_buffer.Append (Environment.NewLine);
3392
 
                                                }
3393
 
 
3394
 
                                                while ((d = get_char ()) != -1){
3395
 
                                                        if (d == '*' && peek_char () == '/'){
3396
 
                                                                get_char ();
3397
 
                                                                if (position_stack.Count == 0)
3398
 
                                                                        sbag.EndComment (line, col + 1);
3399
 
                                                                comments_seen = true;
3400
 
                                                                break;
3401
 
                                                        } else {
3402
 
                                                                if (position_stack.Count == 0)
3403
 
                                                                        sbag.PushCommentChar (d);
3404
 
                                                        }
3405
 
                                                        if (docAppend)
3406
 
                                                                xml_comment_buffer.Append ((char) d);
3407
 
                                                        
3408
 
                                                        if (d == '\n'){
3409
 
                                                                any_token_seen |= tokens_seen;
3410
 
                                                                tokens_seen = false;
3411
 
                                                                // 
3412
 
                                                                // Reset 'comments_seen' just to be consistent.
3413
 
                                                                // It doesn't matter either way, here.
3414
 
                                                                //
3415
 
                                                                comments_seen = false;
3416
 
                                                        }
3417
 
                                                }
3418
 
                                                
3419
 
                                                if (!comments_seen)
3420
 
                                                        Report.Error (1035, Location, "End-of-file found, '*/' expected");
3421
 
 
3422
 
                                                if (docAppend)
3423
 
                                                        update_formatted_doc_comment (current_comment_start);
3424
 
                                                continue;
3425
 
                                        }
3426
 
                                        val = LocatedToken.Create (ref_line, col);
3427
 
                                        return Token.DIV;
3428
 
 
3429
 
                                case '%':
3430
 
                                        val = LocatedToken.Create (ref_line, col);
3431
 
                                        if (peek_char () == '='){
3432
 
                                                get_char ();
3433
 
                                                return Token.OP_MOD_ASSIGN;
3434
 
                                        }
3435
 
                                        return Token.PERCENT;
3436
 
 
3437
 
                                case '^':
3438
 
                                        val = LocatedToken.Create (ref_line, col);
3439
 
                                        if (peek_char () == '='){
3440
 
                                                get_char ();
3441
 
                                                return Token.OP_XOR_ASSIGN;
3442
 
                                        }
3443
 
                                        return Token.CARRET;
3444
 
 
3445
 
                                case ':':
3446
 
                                        val = LocatedToken.Create (ref_line, col);
3447
 
                                        if (peek_char () == ':') {
3448
 
                                                get_char ();
3449
 
                                                return Token.DOUBLE_COLON;
3450
 
                                        }
3451
 
                                        return Token.COLON;
3452
 
 
3453
 
                                case '0': case '1': case '2': case '3': case '4':
3454
 
                                case '5': case '6': case '7': case '8': case '9':
3455
 
                                        tokens_seen = true;
3456
 
                                        return is_number (c);
3457
 
 
3458
 
                                case '\n': // white space
3459
 
                                        any_token_seen |= tokens_seen;
3460
 
                                        tokens_seen = false;
3461
 
                                        comments_seen = false;
3462
 
                                        continue;
3463
 
 
3464
 
                                case '.':
3465
 
                                        tokens_seen = true;
3466
 
                                        d = peek_char ();
3467
 
                                        if (d >= '0' && d <= '9')
3468
 
                                                return is_number (c);
3469
 
 
3470
 
                                        LocatedToken.CreateOptional (ref_line, col, ref val);
3471
 
                                        return Token.DOT;
3472
 
                                
3473
 
                                case '#':
3474
 
                                        if (tokens_seen || comments_seen) {
3475
 
                                                Eror_WrongPreprocessorLocation ();
3476
 
                                                return Token.ERROR;
3477
 
                                        }
3478
 
                                        
3479
 
                                        if (ParsePreprocessingDirective (true))
3480
 
                                                continue;
3481
 
                                        sbag.StartComment (SpecialsBag.CommentType.InactiveCode, false, line, 1);
3482
 
                                        bool directive_expected = false;
3483
 
                                        while ((c = get_char ()) != -1) {
3484
 
                                                if (col == 1) {
3485
 
                                                        directive_expected = true;
3486
 
                                                } else if (!directive_expected) {
3487
 
                                                        // TODO: Implement comment support for disabled code and uncomment this code
3488
 
//                                                      if (c == '#') {
3489
 
//                                                              Eror_WrongPreprocessorLocation ();
3490
 
//                                                              return Token.ERROR;
3491
 
//                                                      }
3492
 
                                                        sbag.PushCommentChar (c);
3493
 
                                                        continue;
3494
 
                                                }
3495
 
 
3496
 
                                                if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' ) {
3497
 
                                                        sbag.PushCommentChar (c);
3498
 
                                                        continue;
3499
 
                                                }
3500
 
 
3501
 
                                                if (c == '#') {
3502
 
                                                        if (ParsePreprocessingDirective (false))
3503
 
                                                                break;
3504
 
                                                }
3505
 
                                                sbag.PushCommentChar (c);
3506
 
                                                directive_expected = false;
3507
 
                                        }
3508
 
                                        sbag.EndComment (line, col);
3509
 
                                        if (c != -1) {
3510
 
                                                tokens_seen = false;
3511
 
                                                continue;
3512
 
                                        }
3513
 
 
3514
 
                                        return Token.EOF;
3515
 
                                                                
3516
 
                                case '"':
3517
 
                                        return consume_string (false);
3518
 
 
3519
 
                                case '\'':
3520
 
                                        return TokenizeBackslash ();
3521
 
                                
3522
 
                                case '@':
3523
 
                                        c = get_char ();
3524
 
                                        if (c == '"') {
3525
 
                                                tokens_seen = true;
3526
 
                                                return consume_string (true);
3527
 
                                        }
3528
 
 
3529
 
                                        if (is_identifier_start_character (c)){
3530
 
                                                return consume_identifier (c, true);
3531
 
                                        }
3532
 
 
3533
 
                                        Report.Error (1646, Location, "Keyword, identifier, or string expected after verbatim specifier: @");
3534
 
                                        return Token.ERROR;
3535
 
 
3536
 
                                case EvalStatementParserCharacter:
3537
 
                                        return Token.EVAL_STATEMENT_PARSER;
3538
 
                                case EvalCompilationUnitParserCharacter:
3539
 
                                        return Token.EVAL_COMPILATION_UNIT_PARSER;
3540
 
                                case EvalUsingDeclarationsParserCharacter:
3541
 
                                        return Token.EVAL_USING_DECLARATIONS_UNIT_PARSER;
3542
 
                                case DocumentationXref:
3543
 
                                        return Token.DOC_SEE;
3544
 
                                }
3545
 
 
3546
 
                                if (is_identifier_start_character (c)) {
3547
 
                                        tokens_seen = true;
3548
 
                                        return consume_identifier (c);
3549
 
                                }
3550
 
 
3551
 
                                if (char.IsWhiteSpace ((char) c))
3552
 
                                        continue;
3553
 
 
3554
 
                                Report.Error (1056, Location, "Unexpected character `{0}'", ((char) c).ToString ());
3555
 
                        }
3556
 
 
3557
 
                        if (CompleteOnEOF){
3558
 
                                if (generated)
3559
 
                                        return Token.COMPLETE_COMPLETION;
3560
 
                                
3561
 
                                generated = true;
3562
 
                                return Token.GENERATE_COMPLETION;
3563
 
                        }
3564
 
                        
3565
 
 
3566
 
                        return Token.EOF;
3567
 
                }
3568
 
 
3569
 
                int TokenizeBackslash ()
3570
 
                {
3571
 
#if FULL_AST
3572
 
                        int read_start = reader.Position;
3573
 
#endif
3574
 
                        Location start_location = Location;
3575
 
                        int c = get_char ();
3576
 
                        tokens_seen = true;
3577
 
                        if (c == '\'') {
3578
 
                                val = new CharLiteral (context.BuiltinTypes, (char) c, start_location);
3579
 
                                Report.Error (1011, start_location, "Empty character literal");
3580
 
                                return Token.LITERAL;
3581
 
                        }
3582
 
 
3583
 
                        if (c == '\n') {
3584
 
                                Report.Error (1010, start_location, "Newline in constant");
3585
 
                                return Token.ERROR;
3586
 
                        }
3587
 
 
3588
 
                        int d;
3589
 
                        c = escape (c, out d);
3590
 
                        if (c == -1)
3591
 
                                return Token.ERROR;
3592
 
                        if (d != 0)
3593
 
                                throw new NotImplementedException ();
3594
 
 
3595
 
                        ILiteralConstant res = new CharLiteral (context.BuiltinTypes, (char) c, start_location);
3596
 
                        val = res;
3597
 
                        c = get_char ();
3598
 
 
3599
 
                        if (c != '\'') {
3600
 
                                Report.Error (1012, start_location, "Too many characters in character literal");
3601
 
 
3602
 
                                // Try to recover, read until newline or next "'"
3603
 
                                while ((c = get_char ()) != -1) {
3604
 
                                        if (c == '\n' || c == '\'')
3605
 
                                                break;
3606
 
                                }
3607
 
                        }
3608
 
 
3609
 
#if FULL_AST
3610
 
                        res.ParsedValue = reader.ReadChars (read_start - 1, reader.Position);
3611
 
#endif
3612
 
 
3613
 
                        return Token.LITERAL;
3614
 
                }
3615
 
 
3616
 
                int TokenizeLessThan ()
3617
 
                {
3618
 
                        int d;
3619
 
                        if (handle_typeof) {
3620
 
                                PushPosition ();
3621
 
                                if (parse_generic_dimension (out d)) {
3622
 
                                        val = d;
3623
 
                                        DiscardPosition ();
3624
 
                                        return Token.GENERIC_DIMENSION;
3625
 
                                }
3626
 
                                PopPosition ();
3627
 
                        }
3628
 
 
3629
 
                        // Save current position and parse next token.
3630
 
                        PushPosition ();
3631
 
                        if (parse_less_than ()) {
3632
 
                                if (parsing_generic_declaration && (parsing_generic_declaration_doc || token () != Token.DOT)) {
3633
 
                                        d = Token.OP_GENERICS_LT_DECL;
3634
 
                                } else {
3635
 
                                        d = Token.OP_GENERICS_LT;
3636
 
                                }
3637
 
                                PopPosition ();
3638
 
                                return d;
3639
 
                        }
3640
 
 
3641
 
                        PopPosition ();
3642
 
                        parsing_generic_less_than = 0;
3643
 
 
3644
 
                        d = peek_char ();
3645
 
                        if (d == '<') {
3646
 
                                get_char ();
3647
 
                                d = peek_char ();
3648
 
 
3649
 
                                if (d == '=') {
3650
 
                                        get_char ();
3651
 
                                        return Token.OP_SHIFT_LEFT_ASSIGN;
3652
 
                                }
3653
 
                                return Token.OP_SHIFT_LEFT;
3654
 
                        }
3655
 
 
3656
 
                        if (d == '=') {
3657
 
                                get_char ();
3658
 
                                return Token.OP_LE;
3659
 
                        }
3660
 
                        return Token.OP_LT;
3661
 
                }
3662
 
 
3663
 
                //
3664
 
                // Handles one line xml comment
3665
 
                //
3666
 
                private void handle_one_line_xml_comment ()
3667
 
                {
3668
 
                        int c;
3669
 
                        while ((c = peek_char ()) == ' ') {
3670
 
                                if (position_stack.Count == 0)
3671
 
                                        sbag.PushCommentChar (c);
3672
 
                                get_char (); // skip heading whitespaces.
3673
 
                        }
3674
 
                        while ((c = peek_char ()) != -1 && c != '\n' && c != '\r') {
3675
 
                                if (position_stack.Count == 0)
3676
 
                                        sbag.PushCommentChar (c);
3677
 
                                xml_comment_buffer.Append ((char) get_char ());
3678
 
                        }
3679
 
                        if (c == '\r' || c == '\n')
3680
 
                                xml_comment_buffer.Append (Environment.NewLine);
3681
 
                }
3682
 
 
3683
 
                //
3684
 
                // Remove heading "*" in Javadoc-like xml documentation.
3685
 
                //
3686
 
                private void update_formatted_doc_comment (int current_comment_start)
3687
 
                {
3688
 
                        int length = xml_comment_buffer.Length - current_comment_start;
3689
 
                        string [] lines = xml_comment_buffer.ToString (
3690
 
                                current_comment_start,
3691
 
                                length).Replace ("\r", "").Split ('\n');
3692
 
                        
3693
 
                        // The first line starts with /**, thus it is not target
3694
 
                        // for the format check.
3695
 
                        for (int i = 1; i < lines.Length; i++) {
3696
 
                                string s = lines [i];
3697
 
                                int idx = s.IndexOf ('*');
3698
 
                                string head = null;
3699
 
                                if (idx < 0) {
3700
 
                                        if (i < lines.Length - 1)
3701
 
                                                return;
3702
 
                                        head = s;
3703
 
                                } else
3704
 
                                        head = s.Substring (0, idx);
3705
 
                                foreach (char c in head)
3706
 
                                        if (c != ' ')
3707
 
                                                return;
3708
 
                                lines [i] = s.Substring (idx + 1);
3709
 
                        }
3710
 
                        xml_comment_buffer.Remove (current_comment_start, length);
3711
 
                        xml_comment_buffer.Insert (current_comment_start, String.Join (Environment.NewLine, lines));
3712
 
                }
3713
 
 
3714
 
                //
3715
 
                // Checks if there was incorrect doc comments and raise
3716
 
                // warnings.
3717
 
                //
3718
 
                public void check_incorrect_doc_comment ()
3719
 
                {
3720
 
                        if (xml_comment_buffer.Length > 0)
3721
 
                                WarningMisplacedComment (Location);
3722
 
                }
3723
 
 
3724
 
                //
3725
 
                // Consumes the saved xml comment lines (if any)
3726
 
                // as for current target member or type.
3727
 
                //
3728
 
                public string consume_doc_comment ()
3729
 
                {
3730
 
                        if (xml_comment_buffer.Length > 0) {
3731
 
                                string ret = xml_comment_buffer.ToString ();
3732
 
                                reset_doc_comment ();
3733
 
                                return ret;
3734
 
                        }
3735
 
                        return null;
3736
 
                }
3737
 
 
3738
 
                Report Report {
3739
 
                        get { return context.Report; }
3740
 
                }
3741
 
 
3742
 
                void reset_doc_comment ()
3743
 
                {
3744
 
                        xml_comment_buffer.Length = 0;
3745
 
                }
3746
 
 
3747
 
                public void cleanup ()
3748
 
                {
3749
 
                        if (ifstack != null && ifstack.Count >= 1) {
3750
 
                                int state = ifstack.Pop ();
3751
 
                                if ((state & REGION) != 0)
3752
 
                                        Report.Error (1038, Location, "#endregion directive expected");
3753
 
                                else 
3754
 
                                        Report.Error (1027, Location, "Expected `#endif' directive");
3755
 
                        }
3756
 
                }
3757
 
        }
3758
 
 
3759
 
        //
3760
 
        // Indicates whether it accepts XML documentation or not.
3761
 
        //
3762
 
        public enum XmlCommentState {
3763
 
                // comment is allowed in this state.
3764
 
                Allowed,
3765
 
                // comment is not allowed in this state.
3766
 
                NotAllowed,
3767
 
                // once comments appeared when it is NotAllowed, then the
3768
 
                // state is changed to it, until the state is changed to
3769
 
                // .Allowed.
3770
 
                Error
3771
 
        }
3772
 
}
3773