readonly SeekableStreamReader reader;
readonly CompilationSourceFile source_file;
readonly CompilerContext context;
+ readonly Report Report;
+
SourceFile current_source;
Location hidden_block_start;
bool handle_get_set = false;
bool handle_remove_add = false;
bool handle_where;
- bool handle_typeof = false;
bool lambda_arguments_parsing;
List<Location> escaped_identifiers;
int parsing_generic_less_than;
public const int EvalCompilationUnitParserCharacter = 0x100001;
public const int EvalUsingDeclarationsParserCharacter = 0x100002;
public const int DocumentationXref = 0x100003;
+
+ const int UnicodeLS = 0x2028;
+ const int UnicodePS = 0x2029;
//
// XML documentation buffer. The save point is used to divide
get { return handle_where; }
set { handle_where = value; }
}
-
- public bool TypeOfParsing {
- get { return handle_typeof; }
- set { handle_typeof = value; }
- }
public XmlCommentState doc_state {
get { return xml_doc_state; }
}
}
- public Tokenizer (SeekableStreamReader input, CompilationSourceFile file, ParserSession session)
+ public Tokenizer (SeekableStreamReader input, CompilationSourceFile file, ParserSession session, Report report)
{
this.source_file = file;
this.context = file.Compiler;
this.id_builder = session.IDBuilder;
this.number_builder = session.NumberBuilder;
this.ltb = new LocatedTokenBuffer (session.LocatedTokens);
+ this.Report = report;
reader = input;
case Token.BYTE:
case Token.CHAR:
case Token.DECIMAL:
+ case Token.DOUBLE:
case Token.FLOAT:
case Token.LONG:
case Token.OBJECT:
if (c < 0x80)
return false;
- return Char.IsLetter (c) || Char.GetUnicodeCategory (c) == UnicodeCategory.ConnectorPunctuation;
+ return is_identifier_part_character_slow_part (c);
+ }
+
+ static bool is_identifier_part_character_slow_part (char c)
+ {
+ if (Char.IsLetter (c))
+ return true;
+
+ switch (Char.GetUnicodeCategory (c)) {
+ case UnicodeCategory.ConnectorPunctuation:
+
+ // combining-character: A Unicode character of classes Mn or Mc
+ case UnicodeCategory.NonSpacingMark:
+ case UnicodeCategory.SpacingCombiningMark:
+
+ // decimal-digit-character: A Unicode character of the class Nd
+ case UnicodeCategory.DecimalDigitNumber:
+ return true;
+ }
+
+ return false;
}
public static bool IsKeyword (string s)
return true;
}
- bool parse_less_than ()
+ bool parse_less_than (ref int genericDimension)
{
start:
int the_token = token ();
case Token.VOID:
break;
case Token.OP_GENERICS_GT:
+ genericDimension = 1;
+ return true;
case Token.IN:
case Token.OUT:
return true;
+ case Token.COMMA:
+ do {
+ ++genericDimension;
+ the_token = token ();
+ } while (the_token == Token.COMMA);
+
+ if (the_token == Token.OP_GENERICS_GT) {
+ ++genericDimension;
+ return true;
+ }
+ return false;
default:
return false;
}
else if (the_token == Token.INTERR_NULLABLE || the_token == Token.STAR)
goto again;
else if (the_token == Token.OP_GENERICS_LT) {
- if (!parse_less_than ())
+ if (!parse_less_than (ref genericDimension))
return false;
goto again;
} else if (the_token == Token.OPEN_BRACKET) {
return false;
}
- bool parse_generic_dimension (out int dimension)
- {
- dimension = 1;
-
- again:
- int the_token = token ();
- if (the_token == Token.OP_GENERICS_GT)
- return true;
- else if (the_token == Token.COMMA) {
- dimension++;
- goto again;
- }
-
- return false;
- }
-
public int peek_token ()
{
int the_token;
// Tonizes `?' using custom disambiguous rules to return one
// of following tokens: INTERR_NULLABLE, OP_COALESCING, INTERR
//
- // Tricky expression look like:
+ // Tricky expression looks like:
//
// Foo ? a = x ? b : c;
//
return Token.OP_COALESCING;
}
- switch (current_token) {
- case Token.CLOSE_PARENS:
- case Token.TRUE:
- case Token.FALSE:
- case Token.NULL:
- case Token.LITERAL:
- return Token.INTERR;
+ if (d == '.') {
+ return Token.INTERR_OPERATOR;
}
if (d != ' ') {
PushPosition ();
current_token = Token.NONE;
int next_token;
- switch (xtoken ()) {
+ int parens = 0;
+ int generics = 0;
+
+ var nt = xtoken ();
+ switch (nt) {
+ case Token.DOT:
+ case Token.OPEN_BRACKET_EXPR:
+ next_token = Token.INTERR_OPERATOR;
+ break;
case Token.LITERAL:
case Token.TRUE:
case Token.FALSE:
case Token.COLON:
next_token = Token.INTERR_NULLABLE;
break;
-
+
+ case Token.OPEN_PARENS:
+ case Token.OPEN_PARENS_CAST:
+ case Token.OPEN_PARENS_LAMBDA:
+ next_token = -1;
+ ++parens;
+ break;
+
+ case Token.OP_GENERICS_LT:
+ case Token.OP_GENERICS_LT_DECL:
+ case Token.GENERIC_DIMENSION:
+ next_token = -1;
+ ++generics;
+ break;
+
default:
next_token = -1;
break;
case Token.COMMA:
case Token.SEMICOLON:
case Token.OPEN_BRACE:
- case Token.CLOSE_PARENS:
case Token.IN:
next_token = Token.INTERR_NULLABLE;
break;
case Token.COLON:
next_token = Token.INTERR;
- break;
-
+ break;
+
+ case Token.OPEN_PARENS:
+ case Token.OPEN_PARENS_CAST:
+ case Token.OPEN_PARENS_LAMBDA:
+ ++parens;
+ goto default;
+
+ case Token.CLOSE_PARENS:
+ --parens;
+ goto default;
+
+ case Token.OP_GENERICS_LT:
+ case Token.OP_GENERICS_LT_DECL:
+ case Token.GENERIC_DIMENSION:
+ ++generics;
+ goto default;
+
default:
int ntoken;
int interrs = 1;
int colons = 0;
int braces = 0;
+ int brackets = 0;
//
// All shorcuts failed, do it hard way
//
while ((ntoken = xtoken ()) != Token.EOF) {
- if (ntoken == Token.OPEN_BRACE) {
+ switch (ntoken) {
+ case Token.OPEN_BRACE:
++braces;
continue;
- }
-
- if (ntoken == Token.CLOSE_BRACE) {
+ case Token.OPEN_PARENS:
+ case Token.OPEN_PARENS_CAST:
+ case Token.OPEN_PARENS_LAMBDA:
+ ++parens;
+ continue;
+ case Token.CLOSE_BRACE:
--braces;
continue;
+ case Token.OP_GENERICS_LT:
+ case Token.OP_GENERICS_LT_DECL:
+ case Token.GENERIC_DIMENSION:
+ ++generics;
+ continue;
+ case Token.OPEN_BRACKET:
+ case Token.OPEN_BRACKET_EXPR:
+ ++brackets;
+ continue;
+ case Token.CLOSE_BRACKET:
+ --brackets;
+ continue;
+ case Token.CLOSE_PARENS:
+ if (parens > 0) {
+ --parens;
+ continue;
+ }
+
+ PopPosition ();
+ return Token.INTERR_NULLABLE;
+
+ case Token.OP_GENERICS_GT:
+ if (generics > 0) {
+ --generics;
+ continue;
+ }
+
+ PopPosition ();
+ return Token.INTERR_NULLABLE;
}
if (braces != 0)
if (ntoken == Token.SEMICOLON)
break;
+
+ if (parens != 0)
+ continue;
+
+ if (ntoken == Token.COMMA) {
+ if (generics != 0 || brackets != 0)
+ continue;
+
+ PopPosition ();
+ return Token.INTERR_NULLABLE;
+ }
if (ntoken == Token.COLON) {
if (++colons == interrs)
x = reader.Read ();
}
- if (x == '\r') {
- if (peek_char () == '\n') {
- putback_char = -1;
- }
+ if (x <= 13) {
+ if (x == '\r') {
+ if (peek_char () == '\n') {
+ putback_char = -1;
+ }
- x = '\n';
- advance_line ();
- } else if (x == '\n') {
+ x = '\n';
+ advance_line ();
+ } else if (x == '\n') {
+ advance_line ();
+ } else {
+ col++;
+ }
+ } else if (x >= UnicodeLS && x <= UnicodePS) {
advance_line ();
} else {
col++;
}
+
return x;
}
throw new InternalErrorException (string.Format ("Secondary putback [{0}] putting back [{1}] is not allowed", (char)putback_char, (char) c), Location);
}
- if (c == '\n' || col == 0) {
+ if (c == '\n' || col == 0 || (c >= UnicodeLS && c <= UnicodePS)) {
// It won't happen though.
line--;
ref_line--;
int has_identifier_argument = (int)(cmd & PreprocessorDirective.RequiresArgument);
int pos = 0;
- while (c != -1 && c != '\n') {
+ while (c != -1 && c != '\n' && c != UnicodeLS && c != UnicodePS) {
if (c == '\\' && has_identifier_argument >= 0) {
if (has_identifier_argument != 0) {
has_identifier_argument = 1;
// Eat single-line comments
//
get_char ();
- do {
- c = get_char ();
- } while (c != -1 && c != '\n');
-
+ ReadToEndOfLine ();
break;
}
//
// Eat any remaining characters to continue parsing on next line
//
- while (c != -1 && c != '\n') {
- c = get_char ();
- }
-
+ ReadToEndOfLine ();
return false;
}
//
// Eat any remaining characters to continue parsing on next line
//
- while (c != -1 && c != '\n') {
- c = get_char ();
- }
-
+ ReadToEndOfLine ();
return new_line != 0;
}
c = 0;
}
- if (c != '\n' && c != '/' && c != '"') {
+ if (c != '\n' && c != '/' && c != '"' && c != UnicodeLS && c != UnicodePS) {
//
// Eat any remaining characters to continue parsing on next line
//
- while (c != -1 && c != '\n') {
- c = get_char ();
- }
+ ReadToEndOfLine ();
Report.Error (1578, loc, "Filename, single-line comment or end-of-line expected");
return true;
}
}
- if (c == '\n') {
+ if (c == '\n' || c == UnicodeLS || c == UnicodePS) {
+
} else if (c == '/') {
ReadSingleLineComment ();
} else {
//
// Eat any remaining characters to continue parsing on next line
//
- while (c != -1 && c != '\n') {
- c = get_char ();
- }
+ ReadToEndOfLine ();
Error_EndLineExpected ();
return true;
string TokenizeFileName (ref int c)
{
var string_builder = new StringBuilder ();
- while (c != -1 && c != '\n') {
+ while (c != -1 && c != '\n' && c != UnicodeLS && c != UnicodePS) {
c = get_char ();
if (c == '"') {
c = get_char ();
Report.Warning (1692, 1, Location, "Invalid number");
// Read everything till the end of the line or file
- do {
- c = get_char ();
- } while (c != -1 && c != '\n');
+ ReadToEndOfLine ();
}
}
return number;
}
+ void ReadToEndOfLine ()
+ {
+ int c;
+ do {
+ c = get_char ();
+ } while (c != -1 && c != '\n' && c != UnicodeLS && c != UnicodePS);
+ }
+
void ReadSingleLineComment ()
{
if (peek_char () != '/')
Report.Warning (1696, 1, Location, "Single-line comment or end-of-line expected");
// Read everything till the end of the line or file
- int c;
- do {
- c = get_char ();
- } while (c != -1 && c != '\n');
+ ReadToEndOfLine ();
}
/// <summary>
/// Handles #pragma directive
/// </summary>
- void ParsePragmaDirective (string arg)
+ void ParsePragmaDirective ()
{
int c;
int length = TokenizePreprocessorIdentifier (out c);
var loc = Location;
- if (c == '\n' || c == '/') {
+ if (c == '\n' || c == '/' || c == UnicodeLS || c == UnicodePS) {
if (c == '/')
ReadSingleLineComment ();
Report.RegisterWarningRegion (loc).WarningEnable (loc, code, context);
}
}
- } while (code >= 0 && c != '\n' && c != -1);
+ } while (code >= 0 && c != '\n' && c != -1 && c != UnicodeLS && c != UnicodePS);
}
return;
Report.Warning (1634, 1, Location, "Expected disable or restore");
// Eat any remaining characters on the line
- while (c != '\n' && c != -1)
- c = get_char ();
+ ReadToEndOfLine ();
return;
}
Report.FeatureIsNotAvailable (context, Location, "#pragma");
}
- ParsePragmaDirective (arg);
+ ParsePragmaDirective ();
return true;
case PreprocessorDirective.Line:
return Token.LITERAL;
}
- if (c == '\n') {
+ if (c == '\n' || c == UnicodeLS || c == UnicodePS) {
if (!quoted) {
Report.Error (1010, Location, "Newline in constant");
continue;
}
- } else if (Char.IsLetter ((char) c) || Char.GetUnicodeCategory ((char) c) == UnicodeCategory.ConnectorPunctuation) {
+ } else if (is_identifier_part_character_slow_part ((char) c)) {
id_builder [pos++] = (char) c;
continue;
}
case '\v':
case '\r':
case '\n':
+ case UnicodeLS:
+ case UnicodePS:
case '/':
next = peek_token ();
if (next == Token.COMMA || next == Token.CLOSE_BRACKET)
}
}
- while ((d = get_char ()) != -1 && d != '\n');
+ ReadToEndOfLine ();
any_token_seen |= tokens_seen;
tokens_seen = false;
if (docAppend)
xml_comment_buffer.Append ((char) d);
- if (d == '\n'){
+ if (d == '\n' || d == UnicodeLS || d == UnicodePS){
any_token_seen |= tokens_seen;
tokens_seen = false;
//
return is_number (c, false);
case '\n': // white space
+ case UnicodeLS:
+ case UnicodePS:
any_token_seen |= tokens_seen;
tokens_seen = false;
comments_seen = false;
continue;
}
- if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' )
+ if (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == UnicodeLS || c == UnicodePS)
continue;
if (c == '#') {
return Token.LITERAL;
}
- if (c == '\n') {
+ if (c == '\n' || c == UnicodeLS || c == UnicodePS) {
Report.Error (1010, start_location, "Newline in constant");
return Token.ERROR;
}
// Try to recover, read until newline or next "'"
while ((c = get_char ()) != -1) {
- if (c == '\n' || c == '\'')
+ if (c == '\n' || c == '\'' || c == UnicodeLS || c == UnicodePS)
break;
}
}
int TokenizeLessThan ()
{
int d;
- if (handle_typeof) {
- PushPosition ();
- if (parse_generic_dimension (out d)) {
- val = d;
- DiscardPosition ();
- return Token.GENERIC_DIMENSION;
- }
- PopPosition ();
- }
// Save current position and parse next token.
PushPosition ();
- if (parse_less_than ()) {
+ int generic_dimension = 0;
+ if (parse_less_than (ref generic_dimension)) {
if (parsing_generic_declaration && (parsing_generic_declaration_doc || token () != Token.DOT)) {
d = Token.OP_GENERICS_LT_DECL;
} else {
+ if (generic_dimension > 0) {
+ val = generic_dimension;
+ DiscardPosition ();
+ return Token.GENERIC_DIMENSION;
+ }
+
d = Token.OP_GENERICS_LT;
}
PopPosition ();
return null;
}
- Report Report {
- get { return context.Report; }
- }
-
void reset_doc_comment ()
{
xml_comment_buffer.Length = 0;