public ResolveContextLambda(CsSimpleLambdaExpression lambda) { Lambda = lambda; }
private static CsExpression parseExpressionIdentifierOrKeyword(TokenJar tok, ref int i) { var startIndex = tok[i].StartIndex; if (tok[i].IsIdentifier("from") && tok[i + 1].Type == TokenType.Identifier) { var linq = new CsLinqExpression { StartIndex = startIndex }; parseLinqQueryExpression(linq, tok, ref i); linq.EndIndex = tok[i - 1].EndIndex; return linq; } if (tok[i].IsBuiltin("{")) { try { var exprs = parseArrayLiteral(tok, ref i); return new CsArrayLiteralExpression { StartIndex = startIndex, EndIndex = tok[i - 1].EndIndex, Expressions = exprs }; } catch (ParseException e) { if (e.IncompleteResult is List<CsExpression>) throw new ParseException(e.Message, e.Index, new CsArrayLiteralExpression { StartIndex = startIndex, Expressions = (List<CsExpression>) e.IncompleteResult }, e); throw; } } if (tok[i].Type == TokenType.CharacterLiteral) return new CsCharacterLiteralExpression { StartIndex = startIndex, EndIndex = tok[i].EndIndex, Literal = tok[i++].TokenStr[0] }; if (tok[i].Type == TokenType.StringLiteral) return new CsStringLiteralExpression { StartIndex = startIndex, EndIndex = tok[i].EndIndex, Literal = tok[i++].TokenStr }; if (tok[i].Type == TokenType.NumberLiteral) return new CsNumberLiteralExpression { StartIndex = startIndex, EndIndex = tok[i].EndIndex, Literal = tok[i++].TokenStr }; if (tok[i].IsBuiltin("true")) { i++; return new CsBooleanLiteralExpression { StartIndex = tok[i - 1].StartIndex, EndIndex = tok[i - 1].EndIndex, Literal = true }; } if (tok[i].IsBuiltin("false")) { i++; return new CsBooleanLiteralExpression { StartIndex = tok[i - 1].StartIndex, EndIndex = tok[i - 1].EndIndex, Literal = false }; } if (tok[i].IsBuiltin("null")) { i++; return new CsNullExpression { StartIndex = tok[i - 1].StartIndex, EndIndex = tok[i - 1].EndIndex }; } if (tok[i].IsBuiltin("this")) { i++; return new CsThisExpression { StartIndex = tok[i - 1].StartIndex, EndIndex = tok[i - 1].EndIndex }; } if (tok[i].IsBuiltin("base")) { i++; return new CsBaseExpression { StartIndex = tok[i - 1].StartIndex, EndIndex = tok[i - 1].EndIndex }; } if (tok[i].IsBuiltin("typeof") || tok[i].IsBuiltin("default") || tok[i].IsBuiltin("sizeof")) { var typof = tok[i].IsBuiltin("typeof"); var expr = typof ? new CsTypeofExpression() : tok[i].IsBuiltin("default") ? (CsTypeOperatorExpression) new CsDefaultExpression() : new CsSizeofExpression(); expr.StartIndex = startIndex; i++; if (!tok[i].IsBuiltin("(")) throw new ParseException("'(' expected after 'typeof' or 'default'.", tok[i].StartIndex); i++; CsTypeName ty; var tif = typeIdentifierFlags.AllowKeywords | typeIdentifierFlags.AllowNullablesAndPointers | typeIdentifierFlags.AllowArrays; try { ty = parseTypeName(tok, ref i, typof ? tif | typeIdentifierFlags.AllowEmptyGenerics : tif).Item1; } catch (ParseException e) { if (e.IncompleteResult is CsTypeName) expr.Type = (CsTypeName) e.IncompleteResult; throw new ParseException(e.Message, e.Index, expr, e); } expr.Type = ty; if (!tok[i].IsBuiltin(")")) throw new ParseException("')' expected.", tok[i].StartIndex, expr); expr.EndIndex = tok[i].EndIndex; i++; return expr; } if (tok[i].IsBuiltin("checked") || tok[i].IsBuiltin("unchecked")) { var expr = tok[i].IsBuiltin("checked") ? (CsCheckedUncheckedExpression) new CsCheckedExpression() : new CsUncheckedExpression(); expr.StartIndex = startIndex; i++; if (!tok[i].IsBuiltin("(")) throw new ParseException("'(' expected after 'checked' or 'unchecked'.", tok[i].StartIndex); i++; expr.Subexpression = parseExpression(tok, ref i); if (!tok[i].IsBuiltin(")")) throw new ParseException("')' expected.", tok[i].StartIndex, expr); expr.EndIndex = tok[i].EndIndex; i++; return expr; } if (tok[i].IsBuiltin("new")) { i++; if (tok[i].IsBuiltin("{")) { var anon = new CsNewAnonymousTypeExpression { StartIndex = startIndex }; try { anon.Initializers = parseArrayLiteral(tok, ref i); } catch (ParseException e) { if (e.IncompleteResult is List<CsExpression>) anon.Initializers = (List<CsExpression>) e.IncompleteResult; throw new ParseException(e.Message, e.Index, anon, e); } anon.EndIndex = tok[i - 1].EndIndex; return anon; } else if (tok[i].IsBuiltin("[") && tok[i + 1].IsBuiltin("]")) { i += 2; // Implicitly-typed array if (!tok[i].IsBuiltin("{")) throw new ParseException("'{' expected.", tok[i].StartIndex); try { var items = parseArrayLiteral(tok, ref i); return new CsNewImplicitlyTypedArrayExpression { StartIndex = startIndex, EndIndex = tok[i - 1].EndIndex, Items = items }; } catch (ParseException e) { if (e.IncompleteResult is List<CsExpression>) throw new ParseException(e.Message, e.Index, new CsNewImplicitlyTypedArrayExpression { StartIndex = startIndex, Items = (List<CsExpression>) e.IncompleteResult }, e); throw; } } else if (tok[i].Type != TokenType.Identifier && tok[i].Type != TokenType.Builtin) throw new ParseException("'{', '[' or type expected.", tok[i].StartIndex); else { var ty = parseTypeName(tok, ref i, typeIdentifierFlags.AllowKeywords | typeIdentifierFlags.AllowNullablesAndPointers | typeIdentifierFlags.AllowArrays | typeIdentifierFlags.Lenient).Item1; if (tok[i].IsBuiltin("(")) { // Constructor call with parameters var constructor = new CsNewConstructorExpression { StartIndex = startIndex, Type = ty }; try { bool dummy; constructor.Arguments = parseArgumentList(tok, ref i, out dummy); if (tok[i].IsBuiltin("{")) constructor.Initializers = parseArrayLiteral(tok, ref i); } catch (ParseException e) { if (e.IncompleteResult is List<CsArgument>) constructor.Arguments = (List<CsArgument>) e.IncompleteResult; else if (e.IncompleteResult is List<CsExpression>) constructor.Initializers = (List<CsExpression>) e.IncompleteResult; throw new ParseException(e.Message, e.Index, constructor, e); } constructor.EndIndex = tok[i - 1].EndIndex; return constructor; } else if (tok[i].IsBuiltin("{")) { // Constructor call without parameters var constructor = new CsNewConstructorExpression { StartIndex = startIndex, Type = ty }; try { constructor.Initializers = parseArrayLiteral(tok, ref i); } catch (ParseException e) { if (e.IncompleteResult is List<CsExpression>) constructor.Initializers = (List<CsExpression>) e.IncompleteResult; throw new ParseException(e.Message, e.Index, constructor, e); } constructor.EndIndex = tok[i - 1].EndIndex; return constructor; } else if (tok[i].IsBuiltin("[")) { // Array construction bool dummy; var k = i; var ret = new CsNewArrayExpression { StartIndex = startIndex, Type = ty }; ret.SizeExpressions.AddRange(parseArgumentList(tok, ref i, out dummy).Select(p => { if (p.Mode != ArgumentMode.In) throw new ParseException("'out' and 'ref' parameters are not allowed in an array constructor.", tok[k].StartIndex); return p.Expression; })); while (tok[i].IsBuiltin("[")) { i++; int num = 1; while (tok[i].IsBuiltin(",")) { num++; i++; } if (!tok[i].IsBuiltin("]")) throw new ParseException("',' or ']' expected.", tok[i].StartIndex, ret); i++; ret.AdditionalRanks.Add(num); } if (tok[i].IsBuiltin("{")) { try { ret.Items = parseArrayLiteral(tok, ref i); } catch (ParseException e) { if (e.IncompleteResult is List<CsExpression>) ret.Items = (List<CsExpression>) e.IncompleteResult; throw new ParseException(e.Message, e.Index, ret, e); } } ret.EndIndex = tok[i - 1].EndIndex; return ret; } else throw new ParseException("'(', '[' or '{' expected.", tok[i].StartIndex); } } if (tok[i].IsBuiltin("delegate")) { i++; var delegateParams = tok[i].IsBuiltin("(") ? parseParameterList(tok, ref i) : null; var block = parseBlock(tok, ref i); return new CsAnonymousMethodExpression { StartIndex = startIndex, EndIndex = tok[i - 1].EndIndex, Body = block, Parameters = delegateParams }; } // See if this could be a lambda expression. If it is, set 'parameters' to something non-null and move 'i' to behind the '=>'. Otherwise, keep 'i' unchanged. List<CsParameter> parameters = null; if (tok[i].Type == TokenType.Identifier && tok[i + 1].IsBuiltin("=>")) { // p => ... parameters = new List<CsParameter> { new CsParameter { StartIndex = startIndex, EndIndex = tok[i].EndIndex, Name = tok[i].TokenStr } }; i += 2; } else if (tok[i].IsBuiltin("(")) { // () => ... if (tok[i + 1].IsBuiltin(")") && tok[i + 2].IsBuiltin("=>")) { parameters = new List<CsParameter>(); i += 3; } else { // Try (Type p1, Type p2) => ... try { var j = i; var tried = parseParameterList(tok, ref j, tryNotToThrow: true); if (tried != null && tok[j].IsBuiltin("=>")) { i = j + 1; parameters = tried; } } catch { } } // If (Type p1, Type p2) => ... still didn't work, try (p1, p2) => ... if (parameters == null && tok[i + 1].Type == TokenType.Identifier) { var ps = new List<CsParameter> { new CsParameter { StartIndex = tok[i + 1].StartIndex, EndIndex = tok[i + 1].EndIndex, Name = tok[i + 1].TokenStr } }; var j = i + 2; while (tok[j].IsBuiltin(",") && tok[j + 1].Type == TokenType.Identifier) { ps.Add(new CsParameter { StartIndex = tok[j + 1].StartIndex, EndIndex = tok[j + 1].EndIndex, Name = tok[j + 1].TokenStr }); j += 2; } if (tok[j].IsBuiltin(")") && tok[j + 1].IsBuiltin("=>")) { parameters = ps; i = j + 2; } } } // If 'parameters' is non-null, we found a lambda expression and 'i' is pointing behind the '=>'. if (parameters != null) { if (tok[i].IsBuiltin("{")) { var lambda = new CsBlockLambdaExpression { StartIndex = startIndex, Parameters = parameters }; try { lambda.Body = parseBlock(tok, ref i); } catch (ParseException e) { if (e.IncompleteResult is CsBlock) { lambda.Body = (CsBlock) e.IncompleteResult; throw new ParseException(e.Message, e.Index, lambda, e); } throw; } lambda.EndIndex = lambda.Body.EndIndex; return lambda; } else { var lambda = new CsSimpleLambdaExpression { StartIndex = startIndex, Parameters = parameters }; try { lambda.Body = parseExpression(tok, ref i); } catch (ParseException e) { if (e.IncompleteResult is CsExpression) { lambda.Body = (CsExpression) e.IncompleteResult; throw new ParseException(e.Message, e.Index, lambda, e); } throw; } lambda.EndIndex = lambda.Body.EndIndex; return lambda; } } // If we get to here, then there is an open-parenthesis that is not the beginning of a lambda expression parameter list. if (tok[i].IsBuiltin("(")) { i++; // Every time we encounter an open-parenthesis, we don't know in advance whether it's a cast, a sub-expression, or a lambda expression. // We've already checked for lambda expression above, so we can rule that one out, but to check whether it's a cast, we need to tentatively // parse it, see if it is followed by ')', and then follow a heuristic specified in the C# standard. CsTypeName typeName = null; CsExpression expression = null; int afterType = i; int afterExpression = i; // Does it parse as a type? try { var result = parseTypeName(tok, ref afterType, typeIdentifierFlags.AllowKeywords | typeIdentifierFlags.AllowNullablesAndPointers | typeIdentifierFlags.AllowArrays, true); if (result != null && tok[afterType].IsBuiltin(")")) { typeName = result.Item1; afterType++; } } catch { } // Does it parse as a parenthesised expression? try { expression = parseExpression(tok, ref afterExpression, true); if (!tok[afterExpression].IsBuiltin(")")) throw new ParseException("')' expected after parenthesised expression.", tok[afterExpression].StartIndex); afterExpression++; } catch (ParseException) { // It’s neither an expression nor a valid type name. if (typeName == null) throw; } // According to the Standard, we are supposed to interpret this as a cast if: // • it definitely doesn’t parse as an expression; OR // • the next token is one of a special set if (expression == null || (typeName != null && ( tok[afterType].IsBuiltin("~") || tok[afterType].IsBuiltin("!") || tok[afterType].IsBuiltin("(") || tok[afterType].Type == TokenType.Identifier || tok[afterType].Type == TokenType.CharacterLiteral || tok[afterType].Type == TokenType.NumberLiteral || tok[afterType].Type == TokenType.StringLiteral || (tok[afterType].Type == TokenType.Builtin && tok[afterType].TokenStr != "is" && tok[afterType].TokenStr != "as" && Lexer.Keywords.Contains(tok[afterType].TokenStr))))) { // It’s a cast! try { i = afterType; var operand = parseExpressionUnary(tok, ref i); return new CsCastExpression { StartIndex = startIndex, EndIndex = operand.EndIndex, Operand = operand, Type = typeName }; } catch (ParseException e) { if (e.IncompleteResult is CsExpression) throw new ParseException(e.Message, e.Index, new CsCastExpression { StartIndex = startIndex, Operand = (CsExpression) e.IncompleteResult, Type = typeName }, e); throw; } } // It’s a subexpression! i = afterExpression; return new CsParenthesizedExpression { StartIndex = startIndex, EndIndex = tok[i - 1].EndIndex, Subexpression = expression }; } var simpleName = parseExpressionIdentifier(tok, ref i); return new CsIdentifierExpression { StartIndex = startIndex, EndIndex = tok[i - 1].EndIndex, Identifier = simpleName }; }