Beispiel #1
0
        /// <summary>
        /// The current token is unexpected, report an error and consume it.
        /// </summary>
        public static TextSpan UnexpectedToken(this ITokenIterator tokens)
        {
            // TODO shouldn't we ignore or combine unexpected token errors until we parse something successfully?
            var span = tokens.Current.Span;

            tokens.Context.Diagnostics.Add(ParseError.UnexpectedToken(tokens.Context.File, span));
            tokens.Next();
            return(span);
        }
        internal IMemberDeclarationSyntax ParseMemberFunction(
            IClassDeclarationSyntax declaringType,
            ModifierParser modifiers)
        {
            var accessModifer = modifiers.ParseAccessModifier();

            modifiers.ParseEndOfModifiers();
            var  fn         = Tokens.Expect <IFunctionKeywordToken>();
            var  identifier = Tokens.RequiredToken <IIdentifierToken>();
            Name name       = identifier.Value;
            var  bodyParser = BodyParser();
            var  parameters = bodyParser.ParseParameters(bodyParser.ParseMethodParameter);

            var(returnType, reachabilityAnnotations) = ParseReturn();

            var selfParameter   = parameters.OfType <ISelfParameterSyntax>().FirstOrDefault();
            var namedParameters = parameters.Except(parameters.OfType <ISelfParameterSyntax>())
                                  .Cast <INamedParameterSyntax>().ToFixedList();

            // if no self parameter, it is an associated function
            if (selfParameter is null)
            {
                var body = bodyParser.ParseFunctionBody();
                var span = TextSpan.Covering(fn, body.Span);
                return(new AssociatedFunctionDeclarationSyntax(declaringType, span, File, accessModifer, identifier.Span, name, namedParameters, returnType, reachabilityAnnotations, body));
            }

            if (!(parameters[0] is ISelfParameterSyntax))
            {
                Add(ParseError.SelfParameterMustBeFirst(File, selfParameter.Span));
            }

            foreach (var extraSelfParameter in parameters.OfType <ISelfParameterSyntax>().Skip(1))
            {
                Add(ParseError.ExtraSelfParameter(File, extraSelfParameter.Span));
            }

            // It is a method that may or may not have a body
            if (Tokens.Current is IOpenBraceToken)
            {
                var body = bodyParser.ParseFunctionBody();
                var span = TextSpan.Covering(fn, body.Span);
                return(new ConcreteMethodDeclarationSyntax(declaringType, span, File, accessModifer,
                                                           identifier.Span, name, selfParameter, namedParameters, returnType, reachabilityAnnotations, body));
            }
            else
            {
                var semicolon = bodyParser.Tokens.Expect <ISemicolonToken>();
                var span      = TextSpan.Covering(fn, semicolon);
                return(new AbstractMethodDeclarationSyntax(declaringType, span, File, accessModifer,
                                                           identifier.Span, name, selfParameter, namedParameters, returnType, reachabilityAnnotations));
            }
        }
Beispiel #3
0
        public static (TextSpan, IIdentifierToken) ExpectIdentifier(this ITokenIterator tokens)
        {
            if (tokens.Current is IIdentifierToken identifier)
            {
                tokens.Next();
                return(identifier.Span, identifier);
            }

            tokens.Context.Diagnostics.Add(
                ParseError.MissingToken(tokens.Context.File, typeof(IIdentifierToken), tokens.Current));
            return(new TextSpan(tokens.Current.Span.Start, 0), null);
        }
Beispiel #4
0
        public static T RequiredToken <T>(this ITokenIterator <IToken> tokens)
            where T : IToken
        {
            if (tokens.Current is T token)
            {
                tokens.Next();
                return(token);
            }

            tokens.Context.Diagnostics.Add(
                ParseError.MissingToken(tokens.Context.File, typeof(T), tokens.Current));
            throw new ParseFailedException($"Requires {typeof(T).GetFriendlyName()}, found {tokens.Current.GetType().GetFriendlyName()}");
        }
        private IBodySyntax ParseFunctionBody()
        {
            var openBrace  = Tokens.Expect <IOpenBraceToken>();
            var statements = ParseMany <IStatementSyntax, ICloseBraceToken>(ParseStatement);

            foreach (var resultStatement in statements.OfType <IResultStatementSyntax>())
            {
                Add(ParseError.ResultStatementInBody(File, resultStatement.Span));
            }
            var closeBrace = Tokens.Expect <ICloseBraceToken>();
            var span       = TextSpan.Covering(openBrace, closeBrace);

            return(new BodySyntax(span, statements.OfType <IBodyStatementSyntax>().ToFixedList()));
        }
Beispiel #6
0
        public static TextSpan Expect <T>(this ITokenIterator <IToken> tokens)
            where T : IToken
        {
            if (tokens.Current is T token)
            {
                tokens.Next();
                return(token.Span);
            }

            tokens.Context.Diagnostics.Add(
                ParseError.MissingToken(tokens.Context.File, typeof(T), tokens.Current));
            // An empty span at the current location
            return(new TextSpan(tokens.Current.Span.Start, 0));
        }
Beispiel #7
0
 private FixedList <NamedFunctionDeclarationSyntax> ParseExternalBlock(
     FixedList <AttributeSyntax> attributes,
     FixedList <IModiferToken> modifiers)
 {
     // TODO error on attributes and modifiers
     Tokens.Expect <IExternalKeywordToken>();
     return(ParseTypeBody().Select(d =>
     {
         if (d is NamedFunctionDeclarationSyntax function)
         {
             function.IsExternalFunction = true;
             return function;
         }
         Add(ParseError.DeclarationNotAllowedInExternal(File, d.NameSpan));
         return null;
     }).Where(d => d != null).ToFixedList());
 }
        public GenericParameterSyntax ParseGenericParameter()
        {
            Name name;
            var  dollar = Tokens.AcceptToken <IDollarToken>();

            if (dollar != null)
            {
                var lifetime = Tokens.RequiredToken <ILifetimeNameToken>();
                var span     = TextSpan.Covering(dollar.Span, lifetime.Span);

                switch (lifetime)
                {
                case IIdentifierToken lifetimeIdentifier:
                    name = nameContext.Qualify(lifetimeIdentifier.Value);
                    break;

                case IRefKeywordToken _:
                    name = nameContext.Qualify(SpecialName.Ref);
                    break;

                case IOwnedKeywordToken _:
                    Add(ParseError.OwnedNotValidAsGenericLifetimeParameter(File, span));
                    // We just treat it as if they had written `$\owned`
                    name = nameContext.Qualify("owned");
                    break;

                default:
                    throw NonExhaustiveMatchException.For(lifetime);
                }

                return(new GenericParameterSyntax(true, false, name, null));
            }

            var isParams   = Tokens.Accept <IParamsKeywordToken>();
            var identifier = Tokens.RequiredToken <IIdentifierToken>();

            name = nameContext.Qualify(identifier.Value);
            ExpressionSyntax typeExpression = null;

            if (Tokens.Accept <IColonToken>())
            {
                typeExpression = ParseExpression();
            }
            return(new GenericParameterSyntax(false, isParams, name, typeExpression));
        }
        /// <summary>
        /// For expressions, we switch to a precedence climbing parser.
        /// </summary>
        public IExpressionSyntax ParseExpression(OperatorPrecedence minPrecedence)
        {
            var expression = ParseAtom();

            for (; ;)
            {
                IBinaryOperatorToken? @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)
                    {
                        var assignmentOperator = BuildAssignmentOperator(Tokens.RequiredToken <IAssignmentToken>());
                        var rightOperand       = ParseExpression();
                        if (expression is IAssignableExpressionSyntax assignableExpression)
                        {
                            expression = new AssignmentExpressionSyntax(assignableExpression, assignmentOperator, rightOperand);
                        }
                        else
                        {
                            // Don't assign expression, so it is just the right hand side of the assignment
                            Add(ParseError.CantAssignIntoExpression(File, expression.Span));
                        }
                        continue;
                    }
                    break;

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

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

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

                case IEqualsEqualsToken _:
                case INotEqualToken _:
                    if (minPrecedence <= OperatorPrecedence.Equality)
                    {
                        precedence = OperatorPrecedence.Equality;
                        @operator  = Tokens.RequiredToken <IBinaryOperatorToken>();
                    }
                    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 <IBinaryOperatorToken>();
                    }
                    break;

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

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

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

                case IDotToken _:
                case IQuestionDotToken _:
                    if (minPrecedence <= OperatorPrecedence.Primary)
                    {
                        // Member Access
                        var accessOperator = BuildAccessOperator(Tokens.RequiredToken <IAccessOperatorToken>());
                        var nameSyntax     = ParseName();
                        if (!(Tokens.Current is IOpenParenToken))
                        {
                            var memberAccessSpan = TextSpan.Covering(expression.Span, nameSyntax.Span);
                            expression = new QualifiedNameExpressionSyntax(memberAccessSpan, expression, accessOperator, nameSyntax.ToExpression());
                        }
                        else
                        {
                            Tokens.RequiredToken <IOpenParenToken>();
                            var arguments      = ParseArguments();
                            var closeParenSpan = Tokens.Expect <ICloseParenToken>();
                            var invocationSpan = TextSpan.Covering(expression.Span, closeParenSpan);
                            expression = new QualifiedInvocationExpressionSyntax(invocationSpan, expression, nameSyntax.Name, nameSyntax.Span, arguments);
                        }
                        continue;
                    }
                    break;

                default:
                    return(expression);
                }

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

                    var rightOperand = ParseExpression(operatorPrecedence);
                    expression = BuildBinaryOperatorExpression(expression, @operator, rightOperand);
                }