/// <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)); } }
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); }
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())); }
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)); }
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); }