- // Tests whether '(' is beggining of lambda parameters
- //
- bool IsLambdaOpenParens ()
- {
- int ntoken;
- while ((ntoken = xtoken ()) != Token.EOF) {
- switch (ntoken) {
- case Token.CLOSE_PARENS:
- return xtoken () == Token.ARROW;
-
- case Token.STAR:
- case Token.SEMICOLON:
- case Token.OPEN_BRACE:
- case Token.OPEN_PARENS:
- case Token.LITERAL_STRING:
- case Token.LITERAL_INTEGER:
- case Token.LITERAL_FLOAT:
- case Token.LITERAL_DOUBLE:
- case Token.LITERAL_DECIMAL:
- case Token.LITERAL_CHARACTER:
- case Token.NULL:
- case Token.FALSE:
- case Token.TRUE:
- case Token.OP_INC:
- case Token.OP_DEC:
- case Token.OP_SHIFT_LEFT:
- case Token.OP_SHIFT_RIGHT:
- case Token.OP_LE:
- case Token.OP_GE:
- case Token.OP_EQ:
- case Token.OP_NE:
- case Token.OP_AND:
- case Token.OP_OR:
- case Token.BITWISE_AND:
- case Token.BITWISE_OR:
- case Token.PLUS:
- case Token.MINUS:
- case Token.DIV:
- case Token.NEW:
- case Token.THIS:
- case Token.BASE:
- case Token.TYPEOF:
- return false;
+ // Open parens micro parser. Detects both lambda and cast ambiguity.
+ //
+
+ int TokenizeOpenParens ()
+ {
+ int ptoken;
+ current_token = -1;
+
+ int bracket_level = 0;
+ bool is_type = false;
+ bool can_be_type = false;
+
+ while (true) {
+ ptoken = current_token;
+ token ();
+
+ switch (current_token) {
+ case Token.CLOSE_PARENS:
+ token ();
+
+ //
+ // Expression inside parens is lambda, (int i) =>
+ //
+ if (current_token == Token.ARROW) {
+ if (RootContext.Version <= LanguageVersion.ISO_2)
+ Report.FeatureIsNotAvailable (Location, "lambda expressions");
+
+ return Token.OPEN_PARENS_LAMBDA;
+ }
+
+ //
+ // Expression inside parens is single type, (int[])
+ //
+ if (is_type)
+ return Token.OPEN_PARENS_CAST;
+
+ //
+ // Expression is possible cast, look at next token, (T)null
+ //
+ if (can_be_type) {
+ switch (current_token) {
+ case Token.OPEN_PARENS:
+ case Token.BANG:
+ case Token.TILDE:
+ case Token.IDENTIFIER:
+ case Token.LITERAL_INTEGER:
+ case Token.LITERAL_FLOAT:
+ case Token.LITERAL_DOUBLE:
+ case Token.LITERAL_DECIMAL:
+ case Token.LITERAL_CHARACTER:
+ case Token.LITERAL_STRING:
+ case Token.BASE:
+ case Token.CHECKED:
+ case Token.DELEGATE:
+ case Token.FALSE:
+ case Token.FIXED:
+ case Token.NEW:
+ case Token.NULL:
+ case Token.SIZEOF:
+ case Token.THIS:
+ case Token.THROW:
+ case Token.TRUE:
+ case Token.TYPEOF:
+ case Token.UNCHECKED:
+ case Token.UNSAFE:
+ case Token.DEFAULT:
+
+ //
+ // These can be part of a member access
+ //
+ case Token.INT:
+ case Token.UINT:
+ case Token.SHORT:
+ case Token.USHORT:
+ case Token.LONG:
+ case Token.ULONG:
+ case Token.DOUBLE:
+ case Token.FLOAT:
+ case Token.CHAR:
+ case Token.BYTE:
+ case Token.DECIMAL:
+ case Token.BOOL:
+ return Token.OPEN_PARENS_CAST;
+ }
+ }
+ return Token.OPEN_PARENS;
+
+ case Token.DOT:
+ case Token.DOUBLE_COLON:
+ if (ptoken != Token.IDENTIFIER && ptoken != Token.OP_GENERICS_GT)
+ goto default;
+
+ continue;
+
+ case Token.IDENTIFIER:
+ switch (ptoken) {
+ case Token.DOT:
+ case Token.OP_GENERICS_LT:
+ case Token.COMMA:
+ case Token.DOUBLE_COLON:
+ case -1:
+ if (bracket_level == 0)
+ can_be_type = true;
+ continue;
+ default:
+ can_be_type = is_type = false;
+ continue;
+ }
+
+ case Token.OBJECT:
+ case Token.STRING:
+ case Token.BOOL:
+ case Token.DECIMAL:
+ case Token.FLOAT:
+ case Token.DOUBLE:
+ case Token.SBYTE:
+ case Token.BYTE:
+ case Token.SHORT:
+ case Token.USHORT:
+ case Token.INT:
+ case Token.UINT:
+ case Token.LONG:
+ case Token.ULONG:
+ case Token.CHAR:
+ case Token.VOID:
+ if (bracket_level == 0)
+ is_type = true;
+ continue;
+
+ case Token.COMMA:
+ if (bracket_level == 0) {
+ bracket_level = 100;
+ can_be_type = is_type = false;
+ }
+ continue;
+
+ case Token.OP_GENERICS_LT:
+ case Token.OPEN_BRACKET:
+ if (bracket_level++ == 0)
+ is_type = true;
+ continue;
+
+ case Token.OP_GENERICS_GT:
+ case Token.CLOSE_BRACKET:
+ --bracket_level;
+ continue;
+
+ case Token.INTERR_NULLABLE:
+ case Token.STAR:
+ if (bracket_level == 0)
+ is_type = true;
+ continue;
+
+ case Token.REF:
+ case Token.OUT:
+ can_be_type = is_type = false;
+ continue;
+
+ default:
+ return Token.OPEN_PARENS;