コード例 #1
0
ファイル: Parser.cs プロジェクト: pipe01/LICC
        private Expression DoExpression(bool doOperator = true)
        {
            Expression ret = null;

            if (Take(LexemeKind.LeftParenthesis, out _))
            {
                ret = DoExpression();

                if (Take(LexemeKind.QuestionMark, out _))
                {
                    ret = DoTernaryOperator(ret);
                }

                Take(LexemeKind.RightParenthesis, "closing parentheses");
            }
            else if (Take(LexemeKind.String, out var str))
            {
                if (float.TryParse(str.Content, NumberStyles.Float, CultureInfo.InvariantCulture, out var f))
                {
                    ret = new NumberLiteralExpression(f);
                }
                else if (Current.Kind == LexemeKind.Exclamation)
                {
                    ret = DoFunctionCall(str.Content);
                }
                else
                {
                    if (Current.Kind == LexemeKind.LeftParenthesis)
                    {
                        ret = DoCommandExpression(str.Content);
                    }
                    else
                    {
                        Error($"unxpected string '{str.Content}' found");
                    }
                }
            }
            else if (Take(LexemeKind.QuotedString, out var quotedStr))
            {
                ret = new StringLiteralExpression(quotedStr.Content);
            }
            else if (Take(LexemeKind.Exclamation, out _))
            {
                ret = DoNegateOperator();
            }
            else if (Take(LexemeKind.Keyword, out var keyword))
            {
                if (keyword.Content == "null")
                {
                    ret = new NullExpression();
                }
                else if (keyword.Content == "true")
                {
                    ret = new BooleanLiteralExpression(true);
                }
                else if (keyword.Content == "false")
                {
                    ret = new BooleanLiteralExpression(false);
                }
                else
                {
                    Error($"unexpected keyword: '{keyword.Content}'");
                }
            }
            else if (Take(LexemeKind.Dollar, out _))
            {
                Push();

                if (Take(LexemeKind.String, out _) && Take(LexemeKind.EqualsAssign, out _))
                {
                    Pop();

                    ret = DoVariableAssign();
                }
                else
                {
                    Pop();

                    string name = Take(LexemeKind.String, "variable name").Content;

                    ret = new VariableAccessExpression(name);

                    if (Take(LexemeKind.Increment, out _))
                    {
                        ret = new UnaryOperatorExpression(Operator.IncrementByOne, ret);
                    }
                    else if (Take(LexemeKind.Decrement, out _))
                    {
                        ret = new UnaryOperatorExpression(Operator.DecrementByOne, ret);
                    }
                }
            }

            while (Take(LexemeKind.Dot, out _))
            {
                ret = new MemberAccessExpression(ret, Take(LexemeKind.String, "member name").Content);

                if (Take(LexemeKind.Exclamation, out _))
                {
                    ret = DoMemberCall(ret);
                }
            }

            if (ret != null && doOperator)
            {
                ret = Take(LexemeKind.QuestionMark, out _)
                    ? DoTernaryOperator(ret)
                    : (DoOperatorChain(ret) ?? ret);
            }

            return(ret);
        }
コード例 #2
0
        // Trying to parse an exception
        // When parsing an expression, any left markers like (, {, or [ must not be the first token
        // When returned, any right markers like ), }, ] and ; will still be in the token stream
        private static ExpressionSyntaxNode?ParseExpression(ref ReadOnlySpan <IToken> tokens, ISyntaxNode parent, ExpressionSyntaxNode?wouldBeLeft)
        {
            if (tokens.IsEmpty)
            {
                throw new InvalidOperationException("We need a token to do any attempt at parsing an expression");
            }

            var curToken   = tokens[0];
            var prevTokens = tokens;

            tokens = tokens.Slice(1);

            // We first need to special case any recursive expressions

            // First check if we are a supported operation
            if (curToken is ISupportedOperationToken op)
            {
                // A supported op requires something on the left
                if (wouldBeLeft == null)
                {
                    throw new InvalidTokenException("Left can't be null here");
                }

                // Grab the right side expressions
                var couldBeRight = ParseExpression(ref tokens, parent, null);

                // Right side expression can not be null either
                if (couldBeRight == null)
                {
                    throw new InvalidTokenException("Right can't be null either");
                }

                // We are an ExpOpExp, create with the left side, the right side, and the operation
                return(new ExpressionOpExpressionSyntaxNode(parent, wouldBeLeft, new OperationSyntaxNode(parent, op.Operation), couldBeRight));
            }
            else if (curToken is EqualsToken)
            {
                // Check if we are an assignment operation
                // Assignment must have a left as well
                if (wouldBeLeft == null)
                {
                    throw new InvalidTokenException("Left can't be null here");
                }

                // Parse the right, it must exist, can't assign nothing
                var couldBeRight = ParseExpression(ref tokens, parent, null);

                if (couldBeRight == null)
                {
                    throw new InvalidTokenException("Right can't be null either");
                }

                return(new ExpressionEqualsExpressionSyntaxNode(parent, wouldBeLeft, couldBeRight));
            }
            else if (curToken is LeftBracketToken)
            {
                // We are creating an array indexer
                // We must have an expression to attach the array indexer to
                if (tokens.Length < 2)
                {
                    throw new InvalidTokenException("Not enough tokens left");
                }

                if (wouldBeLeft == null)
                {
                    throw new InvalidTokenException("Left must not be null");
                }

                // There will be some expression to get the length
                var lengthExpression = ParseExpression(ref tokens, parent, null);
                if (lengthExpression == null)
                {
                    throw new InvalidTokenException("Must have an expression");
                }

                // There has to be a right bracket after parsing the inner expression
                // You also will need to have either a ; or some other expression on the right
                if (tokens.Length < 2)
                {
                    throw new InvalidTokenException("There must be a token");
                }

                if (!(tokens[0] is RightBracketToken))
                {
                    throw new InvalidTokenException("Must be a right bracket");
                }

                // Remove the ]
                tokens = tokens.Slice(1);

                // Create our array expression
                var arrIdxExp = new ArrayIndexExpression(parent, wouldBeLeft, lengthExpression);

                // TODO see if the same logic for detecting the end of a method train
                // works here. It should in theory. About 20 lines down

                // if there is a ;, this is the end of the expression
                // Don't remove the semi colon, but just return the array
                // indexing expression
                if (tokens[0] is SemiColonToken)
                {
                    return(arrIdxExp);
                }

                // Otherwise, parse the expression to the right of the indexer and return that
                return(ParseExpression(ref tokens, parent, arrIdxExp));
            }
            else if (curToken is DotToken)
            {
                // Method call or lots of fields
                // Next token must be an identifier
                if (tokens.Length < 3)
                {
                    throw new InvalidTokenException("Not enough tokens left");
                }

                if (!(tokens[0] is IdentifierToken id))
                {
                    throw new InvalidTokenException("An ID token must be next");
                }

                // Must be a left hand side if we have a .
                if (wouldBeLeft == null)
                {
                    throw new InvalidTokenException("Left can't be null");
                }

                // There are a few things that can happen after a ., lets try them
                if (tokens[1] is LeftParenthesisToken)
                {
                    // Left paranthesis means a method call
                    // Parse the call parameters
                    tokens = tokens.Slice(2);
                    var parameters = ParseCallParameters(ref tokens, parent);

                    // Create the method call expression
                    var methodExpression = new MethodCallExpression(parent, wouldBeLeft, id.Name, parameters);

                    // Try to parse an expression afterward
                    // If we could, return it
                    // Otherwise return the method expression as the end train
                    var continuingExpression = ParseExpression(ref tokens, parent, methodExpression);

                    if (continuingExpression != null)
                    {
                        return(continuingExpression);
                    }

                    return(methodExpression);
                }
                else if (tokens[1] is DotToken)
                {
                    // Nested field access
                    // Create a variable access, then parse everything to the right of that.
                    tokens = tokens.Slice(1);
                    return(ParseExpression(ref tokens, parent, new VariableAccessExpression(parent, wouldBeLeft, id.Name)));
                }
                else if (tokens[1] is RightParenthesisToken)
                {
                    // We might be inside a call parameter detector. If so,
                    // Just return a variable access since thats what we've done
                    tokens = tokens.Slice(1);
                    return(new VariableAccessExpression(parent, wouldBeLeft, id.Name));
                }
                else if (tokens[1] is EqualsToken)
                {
                    // Next is an equals, we currently have the left side as a variable
                    // Parse the right side
                    tokens = tokens.Slice(2);

                    var couldBeRight = ParseExpression(ref tokens, parent, null);

                    if (couldBeRight == null)
                    {
                        throw new InvalidTokenException("Right cannot be null here");
                    }

                    return(new ExpressionEqualsExpressionSyntaxNode(parent, new VariableAccessExpression(parent, wouldBeLeft, id.Name), couldBeRight));

                    ;
                }
                else if (tokens[1] is SemiColonToken)
                {
                    //End of an expression
                    // The slice slices off the next identifier, not the semi colon
                    tokens = tokens.Slice(1);
                    return(new MethodReferenceExpression(parent, wouldBeLeft, id.Name));
                }
                else if (tokens[1] is LeftBracketToken)
                {
                    // We are creating a nested array indexer
                    // Parse the index expression, then create the array expression
                    // Then return a Parsed expression
                    tokens = tokens.Slice(2);
                    var arrIdxExp = ParseExpression(ref tokens, parent, null);

                    if (arrIdxExp == null)
                    {
                        throw new InvalidOperationException("Must have an expression in the array indexer");
                    }

                    if (tokens.IsEmpty)
                    {
                        throw new InvalidOperationException("Must have more tokens");
                    }

                    if (!(tokens[0] is RightBracketToken))
                    {
                        throw new InvalidOperationException("Must have a right bracket");
                    }

                    tokens = tokens.Slice(1);

                    var arrAccessExp = new VariableAccessExpression(parent, wouldBeLeft, id.Name);

                    var arrExp = new ArrayIndexExpression(parent, arrAccessExp, arrIdxExp);

                    return(ParseExpression(ref tokens, parent, arrExp));
                }
                else
                {
                    throw new InvalidTokenException("A token must be handled here");
                }
            }

            if (wouldBeLeft != null)
            {
                tokens = prevTokens;
                return(null);
            }

            ExpressionSyntaxNode?variableNode;

            switch (curToken)
            {
            case IntegerConstantToken numericConstant:
                variableNode = new IntConstantSyntaxNode(parent, numericConstant.Value);
                break;

            case StringConstantToken stringConstant:
                variableNode = new StringConstantNode(parent, stringConstant.Value);
                break;

            case IdentifierToken {
                    Name: "this"
            } _:
                variableNode = new ThisConstantNode(parent);
                break;

            case IdentifierToken {
                    Name: "true"
            } _:
                variableNode = new TrueConstantNode(parent);
                break;

            case IdentifierToken {
                    Name: "false"
            } _:
                variableNode = new FalseConstantNode(parent);
                break;

            case IdentifierToken {
                    Name: "null"
            } _:
                variableNode = new NullConstantNode(parent);
                break;

            case NewToken _:
            {
                if (tokens.Length < 3)
                {
                    throw new InvalidTokenException("Need tokens to parse");
                }
                if (!(tokens[0] is IdentifierToken idToken))
                {
                    throw new InvalidTokenException("Next token must be an identifier");
                }
                if (!(tokens[1] is LeftParenthesisToken))
                {
                    throw new InvalidTokenException("Expected a left paranthesis");
                }

                tokens = tokens.Slice(2);

                var parameters = ParseCallParameters(ref tokens, parent);

                variableNode = new NewConstructorExpression(parent, idToken.Name, parameters);
                break;
            }

            case NewArrToken _:
            {
                if (tokens.Length < 3)
                {
                    throw new InvalidTokenException("Need tokens to parse");
                }
                if (!(tokens[0] is IdentifierToken idToken))
                {
                    throw new InvalidTokenException("Next token must be an identifier");
                }
                if (!(tokens[1] is LeftParenthesisToken))
                {
                    throw new InvalidTokenException("Expected a left paranthesis");
                }

                tokens = tokens.Slice(2);

                var expression = ParseExpression(ref tokens, parent, null);

                if (expression == null)
                {
                    throw new InvalidTokenException("Must have an expression for a newarr");
                }

                if (tokens.Length < 1)
                {
                    throw new InvalidTokenException("Need tokens to parse");
                }
                if (!(tokens[0] is RightParenthesisToken))
                {
                    throw new InvalidTokenException("Next token must be a right paranthesis");
                }
                tokens = tokens.Slice(1);


                variableNode = new NewArrExpression(parent, idToken.Name, expression);
                break;
            }

            case IdentifierToken id:
                variableNode = new VariableSyntaxNode(parent, id.Name);
                break;

            default:
                tokens = prevTokens;
                return(null);
            }

            // If its empty, we're done
            if (tokens.IsEmpty)
            {
                return(variableNode);
            }

            var attemptToParseLower = ParseExpression(ref tokens, parent, variableNode);

            return(attemptToParseLower ?? variableNode);
        }
コード例 #3
0
        private void Visit(VariableAccessExpression expr)
        {
            var local = Local(expr.Name);

            Generator.Ldloca(local);
        }