Пример #1
0
        protected override void VisitUnaryExpressionSyntax(UnaryExpressionSyntax pNode)
        {
            base.VisitUnaryExpressionSyntax(pNode);

            switch (pNode.Operator)
            {
            case UnaryExpressionOperator.Not:
                TrySetImplicitCastType(pNode.Value, SmallTypeCache.Boolean);
                pNode.SetType(SmallTypeCache.Boolean);
                break;

            case UnaryExpressionOperator.Length:
                pNode.SetType(SmallTypeCache.Int);
                break;

            case UnaryExpressionOperator.Negative:
            case UnaryExpressionOperator.PreDecrement:
            case UnaryExpressionOperator.PreIncrement:
            case UnaryExpressionOperator.PostDecrement:
            case UnaryExpressionOperator.PostIncrement:
                TrySetImplicitCastType(pNode.Value, pNode.Value.Type);
                pNode.SetType(pNode.Value.Type);
                break;
            }
        }
Пример #2
0
        protected override void VisitUnaryExpressionSyntax(UnaryExpressionSyntax pNode)
        {
            switch (pNode.Operator)
            {
            case UnaryExpressionOperator.Not:
                if (!CanCast(pNode.Value.Type, SmallTypeCache.Boolean))
                {
                    CompilerErrors.TypeCastError(pNode.Value.Type, SmallTypeCache.Boolean, pNode.Value.Span);
                }
                break;

            case UnaryExpressionOperator.Length:
                if (!pNode.Value.Type.IsArray)
                {
                    CompilerErrors.TypeCastError(pNode.Value.Type.ToString(), "array", pNode.Span);
                }
                break;

            case UnaryExpressionOperator.PreDecrement:
            case UnaryExpressionOperator.PreIncrement:
            case UnaryExpressionOperator.PostDecrement:
            case UnaryExpressionOperator.PostIncrement:
            case UnaryExpressionOperator.Negative:
                if (!TypeHelper.IsInt(pNode.Value.Type))
                {
                    CompilerErrors.TypeCastError(pNode.Value.Type, SmallTypeCache.Int, pNode.Span);
                }
                break;
            }
            base.VisitUnaryExpressionSyntax(pNode);
        }
Пример #3
0
        /// <summary>
        /// Building the expression tree based on precedence of operators
        /// "High precedence" roughly means "should be calculated first", e.g. * operator VS + operator
        /// Syntax nodes with a high precedence will be placed first (lower) in the syntax tree, as syntax trees are evaluated from bottom up
        /// </summary>
        private ExpressionSyntax ParseExpression(int inParentPrecedence = 0)
        {
            ExpressionSyntax left;
            var unaryOperatorPrecedence = CurrentToken.Kind.GetUnaryOperatorPrecedence();

            // If current token is a unary operator (i.e. UnaryOperatorPrecedenc != 0) and it is more than parent precedence, we put it first (i.e. lower) in the syntax tree
            if (unaryOperatorPrecedence != 0 && unaryOperatorPrecedence >= inParentPrecedence)
            {
                var operatorToken     = NextToken();
                var operandExpression = ParseExpression(unaryOperatorPrecedence);
                left = new UnaryExpressionSyntax(operatorToken, operandExpression);
            }
            else             // The left expression must be a primary expression
            {
                left = ParsePrimaryExpression();
            }

            // After settling the unary expression, if there exists more tokens after it (i.e. an operator and right expression), we shall parse this "binary expression"
            while (true)
            {
                var precedence = CurrentToken.Kind.GetBinaryOperatorPrecedence();                 // Getting the precedence of the current token
                if (precedence == 0 || precedence < inParentPrecedence)
                {
                    break;                                                     // If precedence = 0 (i.e. no tokens), or if it is less than the parent (not part of current expression, but the next one), we shall break
                }
                var operatorToken = NextToken();                               // Get current token and proceed to the next one
                var right         = ParseExpression(precedence);               // Recursively parse the "right-side" of the binary expression
                left = new BinaryExpressionSyntax(left, operatorToken, right); // Now with the left, operator, and right sides of the expression, we shall group (or "collapse") them all together as the same "node" (i.e. left) as a BinaryExpressionSyntax
            }

            return(left);
        }
Пример #4
0
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax syntax)
        {
            var boundOperand      = BindExpression(syntax.Operand);
            var boundOperatorKind = BoundUnaryOperator.Bind(syntax.OperatorToken.Kind, boundOperand.Type);

            return(new BoundUnaryExpression(boundOperatorKind, boundOperand));
        }
Пример #5
0
 private static int EvaluateUnaryExpression(UnaryExpressionSyntax unary)
 {
     return(unary.OperatorToken.Kind switch
     {
         SyntaxKind.PlusToken => Evaluate(unary.Operand),
         SyntaxKind.MinusToken => - Evaluate(unary.Operand),
         _ => throw new InvalidOperationException($"Unexpected operator token '{unary.OperatorToken.Kind}'")
     });
Пример #6
0
 public override void VisitUnaryExpression(UnaryExpressionSyntax node)
 {
     if (!_featureStatisticsBuilder.HasCBooleanOperators && node.OperatorToken.Kind is SyntaxKind.BangToken)
     {
         _featureStatisticsBuilder.HasCBooleanOperators = true;
     }
     base.VisitUnaryExpression(node);
 }
Пример #7
0
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax syntax)
        {
            var boundOperand  = BindExpression(syntax.Operand);
            var boundOperator = BoundUnaryOperator.Bind(syntax.OperatorToken.Kind, boundOperand.Type);

            if (boundOperator == null)
            {
                _diagnostics.ReportUndefinedUnaryOperator(syntax.OperatorToken.Span, syntax.OperatorToken.Text, boundOperand.Type);
                return(boundOperand);
            }
            return(new BoundUnaryExpression(boundOperator, boundOperand));
        }
Пример #8
0
        public AnnotatedExpression AnnotateUnaryExpression(UnaryExpressionSyntax syntax)
        {
            var annotateOperand      = AnnotateExpression(syntax.Operand);
            var annotateOperatorKind = AnnotatedUnaryOperator.Annotate(syntax.OperatorToken.Kind, annotateOperand.Type);

            if (annotateOperatorKind == null)
            {
                _diagnostics.ReportUndefinedUnaryOperator(syntax.OperatorToken.Span, syntax.OperatorToken.Text, annotateOperand.Type);
                return(annotateOperand);
            }
            return(new AnnotatedUnaryExpression(annotateOperatorKind, annotateOperand));
        }
 private static async Task<Document> ChangeToIsNotAsync(Document document, UnaryExpressionSyntax unary, BinaryExpressionSyntax isExpression,
     CancellationToken cancellationToken)
 {
     var root = await document.GetSyntaxRootAsync(cancellationToken);
     var newRoot = root.ReplaceNode(
         unary,
         SyntaxFactory.BinaryExpression(
             SyntaxKind.IsNotExpression,
             isExpression.Left,
             SyntaxFactory.Token(SyntaxKind.IsNotKeyword).WithTriviaFrom(isExpression.OperatorToken),
             isExpression.Right));
     return document.WithSyntaxRoot(newRoot);
 }
Пример #10
0
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax syntax)
        {
            var boundOperand  = BindExpression(syntax.Operand);
            var boundOperator = BoundUnaryOperator.Bind(syntax.OperatorToken.Kind, boundOperand.Type);

            if (boundOperator == null)
            {
                _diagnostics.Add($"Unary operator '{syntax.OperatorToken.Text}' is not defined for type {boundOperand.Type}");
                return(boundOperand);
            }

            return(new BoundUnaryExpression(boundOperator, boundOperand));
        }
Пример #11
0
        /// <summary>
        /// Binding a unary expression. Binds operand recursively while evaluating the unary operator kind of each bound expression
        /// </summary>
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax inSyntax)
        {
            var boundOperand      = BindExpression(inSyntax.OperandExpression);
            var boundOperatorKind = BindUnaryOperatorKind(inSyntax.OperatorToken.Kind, boundOperand.Type);

            if (boundOperatorKind == null)
            {
                _diagnostics.Add("Unary operator " + inSyntax.OperatorToken.Text + " is not defined for type " + boundOperand.Type);
                return(boundOperand);
            }

            return(new BoundUnaryExpression(boundOperatorKind.Value, boundOperand));
        }
Пример #12
0
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax syntax)
        {
            var boundExpresion = BindExpression(syntax.Expression);

            var op = BoundUnaryOperator.Bind(syntax.OperatorToken.Kind, boundExpresion.ReturnType);

            if (op == null)
            {
                _diagnostics.Add(Diagnostic.Create(DiagnosticDescriptors.UndefinedUnaryOperator, syntax.OperatorToken.Location, syntax.OperatorToken.ValueText, boundExpresion.ReturnType));
                return(boundExpresion);
            }

            return(new BoundUnaryExpresion(op, boundExpresion));
        }
Пример #13
0
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax syntax)
        {
            var operand = BindExpression(syntax.Operand);
            var op      = BoundUnaryOperator.Bind(syntax.OperatorToken.Kind, operand.Type);

            if (op == null)
            {
                Diagnostics.ReportUndefinedUnaryOperator(syntax.OperatorToken, operand.Type);
                return(operand);
            }


            return(new BoundUnaryExpression(op, operand));
        }
        private static async Task <Document> ChangeToIsNotAsync(Document document, UnaryExpressionSyntax unary, BinaryExpressionSyntax isExpression,
                                                                CancellationToken cancellationToken)
        {
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var newRoot = root.ReplaceNode(
                unary,
                SyntaxFactory.BinaryExpression(
                    SyntaxKind.IsNotExpression,
                    isExpression.Left,
                    SyntaxFactory.Token(SyntaxKind.IsNotKeyword).WithTriviaFrom(isExpression.OperatorToken),
                    isExpression.Right));

            return(document.WithSyntaxRoot(newRoot));
        }
Пример #15
0
        public override SyntaxNode?VisitUnaryExpression(UnaryExpressionSyntax node)
        {
            var operand      = (ExpressionSyntax)Visit(node.Operand);
            var operandFlags = GetFlags(operand);

            return(node.Kind() switch
            {
                SyntaxKind.UnaryMinusExpression when HasEFlag(operandFlags, ExpressionFlags.IsNum) =>
                LiteralExpression(SyntaxKind.NumericalLiteralExpression, Literal(-GetValue <double>(operand))),
                SyntaxKind.LogicalNotExpression when TryConvertToBool(operand, out var value) =>
                LiteralExpression(value ? SyntaxKind.TrueLiteralExpression : SyntaxKind.FalseLiteralExpression),
                SyntaxKind.BitwiseNotExpression when HasEFlag(operandFlags, ExpressionFlags.IsNum) &&
                TryGetInt64(operand, out var value) &&
                TryConvertToDouble(~value, out var result) =>
                LiteralExpression(SyntaxKind.NumericalLiteralExpression, Literal(result)),
                _ => node.Update(node.OperatorToken, operand),
            });
        private Value ConvertUnaryExpressionToValue(
            BlockBuilder currentBlock,
            UnaryExpressionSyntax expression)
        {
            switch (expression.Operator)
            {
            case UnaryOperator.Not:
                var operand = ConvertToOperand(currentBlock, expression.Operand);
                return(new UnaryOperation(expression.Operator, operand, expression.Span));

            case UnaryOperator.Plus:
                // This is a no-op
                return(ConvertToValue(currentBlock, expression.Operand));

            default:
                throw NonExhaustiveMatchException.ForEnum(expression.Operator);
            }
        }
Пример #17
0
        private void OutputUnaryExpression(UnaryExpressionSyntax node, string prefix)
        {
            bool expressionIsBinary = node.Expression is BinaryExpressionSyntax;

            builder.AddFragment(new OutputFragment(prefix, DefaultColour));
            builder.AddFragment(new OutputFragment(node.OpToken.ToString(), DefaultColour));

            if (expressionIsBinary)
            {
                builder.AddFragment(new OutputFragment("(", DefaultColour));
            }

            Output(node.Expression, string.Empty);

            if (expressionIsBinary)
            {
                builder.AddFragment(new OutputFragment(")", DefaultColour));
            }
        }
Пример #18
0
 public void Render(UnaryExpressionSyntax unaryExpression)
 {
     Render(unaryExpression.UnaryOperatorNode);
     Render(unaryExpression.ExpressionNode);
 }
Пример #19
0
 public virtual TResult VisitUnaryExpression(UnaryExpressionSyntax node)
 {
     return(DefaultVisit(node));
 }
Пример #20
0
        private BoundExpression BindUnaryExpression(UnaryExpressionSyntax node)
        {
            var operatorKind = node.Kind.ToUnaryOperatorKind();

            return(BindUnaryExpression(node.Span, operatorKind, node.Expression));
        }
Пример #21
0
 public virtual void VisitUnaryExpression(UnaryExpressionSyntax node) =>
 this.DefaultVisit(node);
 public virtual TResult Visit(UnaryExpressionSyntax syntax) => default(TResult);
Пример #23
0
        protected override SyntaxNode VisitForSyntax(ForSyntax pNode)
        {
            //Rewrite for statements with iterator arrays to normal for statements
            if (pNode.Iterator != null)
            {
                var i = SyntaxFactory.Identifier("!i");
                i.SetType(SmallTypeCache.Int);

                var postOp = pNode.Reverse ? UnaryExpressionOperator.PostDecrement : UnaryExpressionOperator.PostIncrement;
                UnaryExpressionSyntax finalizer = SyntaxFactory.UnaryExpression(i, postOp);

                SyntaxNode        end  = null;
                DeclarationSyntax decl = null;

                //Save itvar in case we are looping in a case body
                var rw = _rewrite;
                var it = _itVar;

                //Declare our iterator outside the for loop
                //This will help if our iterator is complex like a function call
                var iterVar = SyntaxFactory.Identifier("!iter");
                iterVar.SetType(pNode.Iterator.Type);
                var iterDecl = SyntaxFactory.SingleDeclaration(iterVar, pNode.Iterator);

                if (pNode.Iterator.Type.IsArray)
                {
                    //We are iterating over an array
                    //Reverse loops will start at Array.Length and decrement to 0
                    //Normal loops will start at 0 and increment to Array.Length
                    if (pNode.Reverse)
                    {
                        var length = SyntaxFactory.UnaryExpression(iterVar, UnaryExpressionOperator.Length);
                        length.SetType(SmallTypeCache.Int);
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.BinaryExpression(length, BinaryExpressionOperator.Subtraction, SyntaxFactory.NumericLiteral(1)));
                        end  = SyntaxFactory.NumericLiteral(0);
                    }
                    else
                    {
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.NumericLiteral(0));
                        end  = SyntaxFactory.UnaryExpression(iterVar, UnaryExpressionOperator.Length);
                        ((UnaryExpressionSyntax)end).SetType(SmallTypeCache.Int);
                    }

                    _itVar = SyntaxFactory.ArrayAccess(iterVar, i);
                    ((ArrayAccessSyntax)_itVar).SetType(iterVar.Type);
                }
                else if (pNode.Iterator.Type.IsAssignableFrom(_enumerable))
                {
                    //We are iterating over an enumerable
                    //Reverse loops will start at Count and decrement to 0
                    //Normal loops will start at 0 and increment to Count
                    if (pNode.Reverse)
                    {
                        var count = SyntaxFactory.MemberAccess(iterVar, SyntaxFactory.Identifier("Count"));
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.BinaryExpression(count, BinaryExpressionOperator.Subtraction, SyntaxFactory.NumericLiteral(1)));
                        end  = SyntaxFactory.NumericLiteral(0);
                    }
                    else
                    {
                        decl = SyntaxFactory.SingleDeclaration(i, SyntaxFactory.NumericLiteral(0));
                        end  = SyntaxFactory.MemberAccess(iterVar, SyntaxFactory.Identifier("Count"));
                    }

                    _itVar = SyntaxFactory.MemberAccess(iterVar, SyntaxFactory.MethodCall("ItemAt", new List <SyntaxNode>()
                    {
                        SyntaxFactory.Identifier("!i")
                    }));
                }
                else
                {
                    //Some bad type. We can't rewrite if it isn't array or enumerable
                    return(base.VisitForSyntax(pNode));
                }

                var op        = pNode.Reverse ? BinaryExpressionOperator.GreaterThanOrEqual : BinaryExpressionOperator.LessThan;
                var condition = SyntaxFactory.BinaryExpression(i, op, end);
                condition.SetType(SmallTypeCache.Boolean);

                var body         = (BlockSyntax)Visit(pNode.Body);
                var forStatement = SyntaxFactory.For(new List <DeclarationSyntax>()
                {
                    decl
                }, condition, new List <SyntaxNode>()
                {
                    finalizer
                }, body);

                //Restore our it for any other nested loops
                _itVar   = it;
                _rewrite = rw;

                //Return our iterator declaration and for rewrite
                return(SyntaxFactory.Block(new List <SyntaxNode>()
                {
                    iterDecl, forStatement
                }));
            }

            return(base.VisitForSyntax(pNode));
        }
 public virtual void VisitUnaryExpression(UnaryExpressionSyntax unaryExpression, A args)
 {
     VisitExpression(unaryExpression.Operand, args);
 }
Пример #25
0
 private static bool TryCompileUnary(UnaryExpressionSyntax expression, in Temporary innerValue,
Пример #26
0
        private DataType InferUnaryExpressionType(UnaryExpressionSyntax unaryExpression)
        {
            var operandType = InferExpressionType(unaryExpression.Operand);
            var @operator   = unaryExpression.Operator;

            // If either is unknown, then we can't know whether there is a a problem
            // (technically not true, for example, we could know that one arg should
            // be a bool and isn't)
            if (operandType == DataType.Unknown)
            {
                return(unaryExpression.Type = DataType.Unknown);
            }

            bool typeError;

            switch (@operator)
            {
            case UnaryOperator.Not:
                typeError            = operandType != DataType.Bool;
                unaryExpression.Type = DataType.Bool;
                break;

            case UnaryOperator.At:
                typeError = false;     // TODO check that the expression can have a pointer taken
                if (operandType is Metatype)
                {
                    unaryExpression.Type = DataType.Type;     // constructing a type
                }
                else
                {
                    unaryExpression.Type = new PointerType(operandType);     // taking the address of something
                }
                break;

            case UnaryOperator.Question:
                typeError            = false; // TODO check that the expression can have a pointer taken
                unaryExpression.Type = new PointerType(operandType);
                break;

            case UnaryOperator.Caret:
                switch (operandType)
                {
                case PointerType pointerType:
                    unaryExpression.Type = pointerType.Referent;
                    typeError            = false;
                    break;

                default:
                    unaryExpression.Type = DataType.Unknown;
                    typeError            = true;
                    break;
                }
                break;

            case UnaryOperator.Minus:
                switch (operandType)
                {
                case IntegerConstantType integerType:
                    typeError            = false;
                    unaryExpression.Type = integerType;
                    break;

                case SizedIntegerType sizedIntegerType:
                    typeError            = false;
                    unaryExpression.Type = sizedIntegerType;
                    break;

                default:
                    unaryExpression.Type = DataType.Unknown;
                    typeError            = true;
                    break;
                }
                break;

            default:
                throw NonExhaustiveMatchException.ForEnum(@operator);
            }
            if (typeError)
            {
                diagnostics.Add(TypeError.OperatorCannotBeAppliedToOperandOfType(file,
                                                                                 unaryExpression.Span, @operator, operandType));
            }

            return(unaryExpression.Type);
        }
Пример #27
0
 protected virtual void VisitUnaryExpressionSyntax(UnaryExpressionSyntax pNode)
 {
     Visit(pNode.Value);
 }
Пример #28
0
 protected virtual SyntaxNode VisitUnaryExpressionSyntax(UnaryExpressionSyntax pNode)
 {
     return(SyntaxFactory.UnaryExpression(Visit(pNode.Value), pNode.Operator));
 }
        /// <summary>
        /// For expressions, we switch to a precedence climbing parser.
        /// </summary>
        public ExpressionSyntax ParseExpression(OperatorPrecedence minPrecedence)
        {
            var expression = ParseAtom();

            for (; ;)
            {
                IOperatorToken     @operator  = null;
                OperatorPrecedence?precedence = null;
                var leftAssociative           = true;
                switch (Tokens.Current)
                {
                case IEqualsToken _:
                case IPlusEqualsToken _:
                case IMinusEqualsToken _:
                case IAsteriskEqualsToken _:
                case ISlashEqualsToken _:
                    if (minPrecedence <= OperatorPrecedence.Assignment)
                    {
                        precedence      = OperatorPrecedence.Assignment;
                        leftAssociative = false;
                        @operator       = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IQuestionQuestionToken _:
                    if (minPrecedence <= OperatorPrecedence.Coalesce)
                    {
                        precedence = OperatorPrecedence.Coalesce;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IOrKeywordToken _:
                    if (minPrecedence <= OperatorPrecedence.LogicalOr)
                    {
                        precedence = OperatorPrecedence.LogicalOr;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IAndKeywordToken _:
                    if (minPrecedence <= OperatorPrecedence.LogicalAnd)
                    {
                        precedence = OperatorPrecedence.LogicalAnd;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IEqualsEqualsToken _:
                case INotEqualToken _:
                    if (minPrecedence <= OperatorPrecedence.Equality)
                    {
                        precedence = OperatorPrecedence.Equality;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case ILessThanToken _:
                case ILessThanOrEqualToken _:
                case IGreaterThanToken _:
                case IGreaterThanOrEqualToken _:
                case ILessThanColonToken _:     // Subtype operator
                case IAsKeywordToken _:
                    if (minPrecedence <= OperatorPrecedence.Relational)
                    {
                        precedence = OperatorPrecedence.Relational;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IColonToken _:     // type kind
                    if (minPrecedence <= OperatorPrecedence.Relational)
                    {
                        var      colon = Tokens.Expect <IColonToken>();
                        TypeKind typeKind;
                        switch (Tokens.Current)
                        {
                        case IClassKeywordToken _:
                            typeKind = TypeKind.Class;
                            break;

                        case IStructKeywordToken _:
                            typeKind = TypeKind.Struct;
                            break;

                        default:
                            Tokens.Expect <ITypeKindKeywordToken>();
                            // We saw a colon without what we expected after, just assume it is missing
                            continue;
                        }
                        var typeKindSpan = Tokens.Expect <ITypeKindKeywordToken>();
                        var span         = TextSpan.Covering(colon, typeKindSpan);
                        expression = new TypeKindExpressionSyntax(span, typeKind);
                        continue;
                    }
                    break;

                case IDotDotToken _:
                case ILessThanDotDotToken _:
                case IDotDotLessThanToken _:
                case ILessThanDotDotLessThanToken _:
                    if (minPrecedence <= OperatorPrecedence.Range)
                    {
                        precedence = OperatorPrecedence.Range;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IPlusToken _:
                case IMinusToken _:
                    if (minPrecedence <= OperatorPrecedence.Additive)
                    {
                        precedence = OperatorPrecedence.Additive;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IAsteriskToken _:
                case ISlashToken _:
                    if (minPrecedence <= OperatorPrecedence.Multiplicative)
                    {
                        precedence = OperatorPrecedence.Multiplicative;
                        @operator  = Tokens.RequiredToken <IOperatorToken>();
                    }
                    break;

                case IDollarToken _:
                    if (minPrecedence <= OperatorPrecedence.Lifetime)
                    {
                        Tokens.Expect <IDollarToken>();
                        var(nameSpan, lifetime) = ParseLifetimeName();
                        expression = new ReferenceLifetimeSyntax(expression, nameSpan, lifetime);
                        continue;
                    }
                    break;

                case IQuestionToken _:
                    if (minPrecedence <= OperatorPrecedence.Unary)
                    {
                        var question = Tokens.Required <IQuestionToken>();
                        var span     = TextSpan.Covering(expression.Span, question);
                        expression = new UnaryExpressionSyntax(span, UnaryOperatorFixity.Postfix, UnaryOperator.Question, expression);
                        continue;
                    }
                    break;

                case IOpenParenToken _:
                    if (minPrecedence <= OperatorPrecedence.Primary)
                    {
                        var callee = expression;
                        Tokens.Expect <IOpenParenToken>();
                        var arguments      = ParseArguments();
                        var closeParenSpan = Tokens.Expect <ICloseParenToken>();
                        var span           = TextSpan.Covering(callee.Span, closeParenSpan);
                        expression = new InvocationSyntax(span, callee, arguments);
                        continue;
                    }
                    break;

                case IDotToken _:
                case ICaretDotToken _:
                case IQuestionDotToken _:
                    if (minPrecedence <= OperatorPrecedence.Primary)
                    {
                        // Member Access
                        var accessOperator = BuildAccessOperator(Tokens.RequiredToken <IAccessOperatorToken>());
                        var member         = ParseSimpleName();
                        var span           = TextSpan.Covering(expression.Span, member.Span);
                        expression = new MemberAccessExpressionSyntax(span, expression, accessOperator, member);
                        continue;
                    }
                    break;

                default:
                    return(expression);
                }

                if (@operator is IOperatorToken operatorToken &&
                    precedence is OperatorPrecedence operatorPrecedence)
                {
                    if (leftAssociative)
                    {
                        operatorPrecedence += 1;
                    }

                    var rightOperand = ParseExpression(operatorPrecedence);
                    expression = BuildOperatorExpression(expression, operatorToken, rightOperand);
                }
Пример #30
0
        private bool TryParseFactor([NotNullWhen(true)] out ExpressionSyntax?expressionSyntax)
        {
            // Factor := Identifier | Number | Boolean literal | ( Expression ) | -Factor | !Factor | ~Factor

            expressionSyntax = null;

            switch (_lexer.PeekTokenType())
            {
            case TokenType.Minus:
                return(ParseUnary(UnaryOperation.Minus, out expressionSyntax));

            case TokenType.Exclamation:
                return(ParseUnary(UnaryOperation.Negation, out expressionSyntax));

            case TokenType.Tilde:
                return(ParseUnary(UnaryOperation.Complement, out expressionSyntax));

            case TokenType.OpenParen:
                // Eat the '('
                _lexer.GetToken();

                // Parse the expression.
                // The inner expression is returned as is, with no enclosing 'parens' node.
                // The modified precedence/associativity is already reflected in the syntax tree.
                if (!TryParseExpression(out expressionSyntax))
                {
                    return(false);
                }

                // Eat the ')'
                if (!ExpectToken(TokenType.CloseParen, DiagnosticCode.ExpectedClosingParen))
                {
                    return(false);
                }
                return(true);

            case TokenType.False:
                // Eat the token
                _lexer.GetToken();

                expressionSyntax = new BooleanLiteralSyntax(false, _lexer.LastPosition);
                return(true);

            case TokenType.True:
                // Eat the token
                _lexer.GetToken();

                expressionSyntax = new BooleanLiteralSyntax(true, _lexer.LastPosition);
                return(true);

            case TokenType.StringLiteral:
                return(TryParseStringLiteral(out expressionSyntax));

            case TokenType.Identifier:
                if (!TryReadAndValidateIdentifier(out var identifier, allowReservedTypeNames: false))
                {
                    return(false);
                }

                // This may be either a function call or a variable reference
                if (_lexer.PeekTokenType() == TokenType.OpenParen)
                {
                    // Function call
                    if (!TryParseFunctionCall(identifier, out var callSyntax))
                    {
                        return(false);
                    }
                    else
                    {
                        Debug.Assert(callSyntax != null);
                        expressionSyntax = callSyntax;
                        return(true);
                    }
                }
                else
                {
                    // Variable reference
                    expressionSyntax = identifier;
                    return(true);
                }

            default:
                return(TryParseNumber(out expressionSyntax));
            }

            // Local helper method for sharing code between the various unary paths
            bool ParseUnary(UnaryOperation op, out ExpressionSyntax?syntax)
            {
                // Eat the operator
                var opPosition = _lexer.Position;

                _lexer.GetToken();

                // Recurse into the inner expression, which is a factor too
                if (TryParseFactor(out var innerFactor))
                {
                    Debug.Assert(innerFactor != null);
                    syntax = new UnaryExpressionSyntax(op, innerFactor, opPosition);
                    return(true);
                }
                else
                {
                    syntax = null;
                    return(false);
                }
            }
        }