Exemplo n.º 1
0
 public ResolveContextLambda(CsSimpleLambdaExpression lambda)
 {
     Lambda = lambda;
 }
Exemplo n.º 2
0
        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 };
        }