namespace Mono.CSharp
{
+ //
+ // This class has to be used by parser only, it reuses token
+ // details once a file is parsed
+ //
+ public class LocatedToken
+ {
+ public int row, column;
+ public string value;
+ public SourceFile file;
+
+ public LocatedToken ()
+ {
+ }
+
+ public LocatedToken (string value, Location loc)
+ {
+ this.value = value;
+ file = loc.SourceFile;
+ row = loc.Row;
+ column = loc.Column;
+ }
+
+ public override string ToString ()
+ {
+ return string.Format ("Token '{0}' at {1},{2}", Value, row, column);
+ }
+
+ public Location Location
+ {
+ get { return new Location (file, row, column); }
+ }
+
+ public string Value
+ {
+ get { return value; }
+ }
+ }
+
/// <summary>
/// Tokenizer for C# source code.
/// </summary>
-
public class Tokenizer : yyParser.yyInput
{
class KeywordEntry<T>
}
}
- //
- // This class has to be used by parser only, it reuses token
- // details after each file parse completion
- //
- public class LocatedToken
- {
- public int row, column;
- public string value;
- public SourceFile file;
-
- public LocatedToken ()
- {
- }
-
- public LocatedToken (string value, Location loc)
- {
- this.value = value;
- file = loc.SourceFile;
- row = loc.Row;
- column = loc.Column;
- }
-
- public override string ToString ()
- {
- return string.Format ("Token '{0}' at {1},{2}", Value, row, column);
- }
-
- public Location Location {
- get { return new Location (file, row, column); }
- }
-
- public string Value {
- get { return value; }
- }
- }
-
public class LocatedTokenBuffer
{
readonly LocatedToken[] buffer;
readonly int tab_size;
bool handle_get_set = false;
bool handle_remove_add = false;
- bool handle_where = false;
+ bool handle_where;
bool handle_typeof = false;
bool lambda_arguments_parsing;
List<Location> escaped_identifiers;
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
}
break;
case Token.WHERE:
- if (!handle_where && !query_parsing)
+ if (!(handle_where && current_token != Token.COLON) && !query_parsing)
res = -1;
break;
case Token.FROM:
// followed by any token except ; , =
//
if (!query_parsing) {
- if (lambda_arguments_parsing) {
+ if (lambda_arguments_parsing || parsing_block == 0) {
res = -1;
break;
}
case Token.UINT:
case Token.ULONG:
next_token = xtoken ();
- if (next_token == Token.SEMICOLON || next_token == Token.COMMA || next_token == Token.EQUALS)
+ if (next_token == Token.SEMICOLON || next_token == Token.COMMA || next_token == Token.EQUALS || next_token == Token.ASSIGN)
goto default;
res = Token.FROM_FIRST;
case Token.NAMESPACE:
// TODO: some explanation needed
check_incorrect_doc_comment ();
+ parsing_modifiers = false;
break;
case Token.PARTIAL:
Report.Error (267, Location,
"The `partial' modifier can be used only immediately before `class', `struct', `interface', or `void' keyword");
return token ();
- }
+ }
+ // HACK: A token is not a keyword so we need to restore identifiers buffer
+ // which has been overwritten before we grabbed the identifier
+ id_builder[0] = 'p';
+ id_builder[1] = 'a';
+ id_builder[2] = 'r';
+ id_builder[3] = 't';
+ id_builder[4] = 'i';
+ id_builder[5] = 'a';
+ id_builder[6] = 'l';
res = -1;
break;
case Token.IDENTIFIER:
PushPosition ();
xtoken ();
- if (xtoken () != Token.ARROW)
+ if (xtoken () != Token.ARROW) {
+ PopPosition ();
goto default;
+ }
PopPosition ();
break;
//
// Expression inside parens is single type, (int[])
//
- if (is_type)
+ if (is_type) {
+ if (current_token == Token.SEMICOLON)
+ return Token.OPEN_PARENS;
+
return Token.OPEN_PARENS_CAST;
+ }
//
// Expression is possible cast, look at next token, (T)null
continue;
case Token.IDENTIFIER:
+ case Token.AWAIT:
switch (ptoken) {
case Token.DOT:
if (bracket_level == 0) {
case Token.OPEN_BRACKET:
case Token.OP_GENERICS_GT:
case Token.INTERR:
+ case Token.OP_COALESCING:
+ case Token.COLON:
next_token = Token.INTERR_NULLABLE;
break;
// if we have not seen anything in between
// report this error
//
- Report.Warning (78, 4, Location, "The 'l' suffix is easily confused with the digit '1' (use 'L' for clarity)");
+ Report.Warning (78, 4, Location, "The `l' suffix is easily confused with the digit `1' (use `L' for clarity)");
}
goto case 'L';
//
// Invoked if we know we have .digits or digits
//
- int is_number (int c)
+ int is_number (int c, bool dotLead)
{
ILiteralConstant res;
#if FULL_AST
int read_start = reader.Position - 1;
- if (c == '.') {
+ if (dotLead) {
//
// Caller did peek_char
//
number_pos = 0;
var loc = Location;
- if (c >= '0' && c <= '9'){
+ if (!dotLead){
if (c == '0'){
int peek = peek_char ();
}
}
decimal_digits (c);
- c = get_char ();
+ c = peek_char ();
}
//
//
bool is_real = false;
if (c == '.'){
+ if (!dotLead)
+ get_char ();
+
if (decimal_digits ('.')){
is_real = true;
- c = get_char ();
+ c = peek_char ();
} else {
putback ('.');
number_pos--;
if (c == 'e' || c == 'E'){
is_real = true;
+ get_char ();
if (number_pos == MaxNumberLength)
Error_NumericConstantTooLong ();
number_builder [number_pos++] = (char) c;
}
decimal_digits (c);
- c = get_char ();
+ c = peek_char ();
}
var type = real_type_suffix (c);
if (type == TypeCode.Empty && !is_real) {
- putback (c);
res = adjust_int (c, loc);
} else {
is_real = true;
- if (type == TypeCode.Empty) {
- putback (c);
+ if (type != TypeCode.Empty) {
+ get_char ();
}
res = adjust_real (type, loc);
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>
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;
}
}
case PreprocessorDirective.Define:
if (any_token_seen){
- Error_TokensSeen ();
+ if (caller_is_taking)
+ Error_TokensSeen ();
return caller_is_taking;
}
PreProcessDefinition (true, arg, caller_is_taking);
case PreprocessorDirective.Undef:
if (any_token_seen){
- Error_TokensSeen ();
+ if (caller_is_taking)
+ Error_TokensSeen ();
return caller_is_taking;
}
PreProcessDefinition (false, arg, caller_is_taking);
return Token.LITERAL;
}
- if (c == '\n') {
+ if (c == '\n' || c == UnicodeLS || c == UnicodePS) {
if (!quoted) {
Report.Error (1010, Location, "Newline in constant");
advance_line ();
} else if (c == '\\' && !quoted) {
+ ++col;
int surrogate;
c = escape (c, out surrogate);
if (c == -1)
case '\v':
case '\r':
case '\n':
+ case UnicodeLS:
+ case UnicodePS:
case '/':
next = peek_token ();
if (next == Token.COMMA || next == Token.CLOSE_BRACKET)
case Token.FOREACH:
case Token.TYPEOF:
case Token.WHILE:
+ case Token.SWITCH:
case Token.USING:
case Token.DEFAULT:
case Token.DELEGATE:
}
}
- 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;
//
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
tokens_seen = true;
- return is_number (c);
+ return is_number (c, false);
case '\n': // white space
+ case UnicodeLS:
+ case UnicodePS:
any_token_seen |= tokens_seen;
tokens_seen = false;
comments_seen = false;
tokens_seen = true;
d = peek_char ();
if (d >= '0' && d <= '9')
- return is_number (c);
+ return is_number (c, true);
ltb.CreateOptional (current_source, ref_line, col, ref val);
return Token.DOT;
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;
}
}