private static IStatement ParseStatement(Context context, ParserState state) { IStatement statement; if (_parseRules.TryGetValue(state.Current().Kind, out var parseRule)) { state.Advance(); statement = parseRule.ParserFunction.Invoke(context, state); if (parseRule.EndsWithSemicolon) { state.ConsumeOrError(TokenKind.Semicolon); } ConsumeUnnecessarySemicolons(context, state); return(statement); } var nodeId = state.NodeIdGenerator.GetNextId(); var expression = ExpressionParser.ParseExpression(state); if (state.Consume(TokenKind.ColonEqual)) { var value = ExpressionParser.ParseExpression(state); var span = SourceSpan.Merge(expression.Span, value.Span); statement = new AssignmentStatement(nodeId, span, expression, value); } else { statement = new ExpressionStatement(nodeId, expression.Span, expression); } state.ConsumeOrError(TokenKind.Semicolon); ConsumeUnnecessarySemicolons(context, state); return(statement); }
private static List <Spanned <FunctionParameter> > ParseFunctionParameters( Context context, ParserState state) { var parameters = new List <Spanned <FunctionParameter> >(); state.ConsumeOrError(TokenKind.LeftParenthesis); if (state.Consume(TokenKind.RightParenthesis)) { return(parameters); } do { var identifier = state.ConsumeOrError(TokenKind.Identifier); state.ConsumeOrError(TokenKind.Colon); var typeSignature = TypeSignatureParser.ParseTypeSignature(state); var span = SourceSpan.Merge(identifier.Span, typeSignature.Span); parameters.Add( new Spanned <FunctionParameter>( new FunctionParameter( state.NodeIdGenerator.GetNextId(), identifier, typeSignature), span)); } while (!state.IsAtEnd() && state.Consume(TokenKind.Comma)); state.ConsumeOrError(TokenKind.RightParenthesis); return(parameters); }
private static IExpression ParseArrayLiteral(ParserState state) { var nodeId = state.NodeIdGenerator.GetNextId(); SourceSpan span; var spanStart = state.Previous().Span; var elements = new List <IExpression>(); if (state.Consume(TokenKind.RightBracket)) { throw new ParseException( state.Previous().Span, "empty array literals are not allowed"); } do { elements.Add(ParseExpression(state)); } while (state.Consume(TokenKind.Comma)); state.ConsumeOrError(TokenKind.RightBracket); var spanEnd = state.Previous().Span; span = SourceSpan.Merge(spanStart, spanEnd); return(new ArrayLiteral(nodeId, span, elements)); }
public InfixOperation( int nodeId, Token @operator, IExpression leftOperand, IExpression rightOperand) { NodeId = nodeId; Span = SourceSpan.Merge(leftOperand.Span, rightOperand.Span); Operator = new Spanned <InfixOperator>( @operator.Kind switch { TokenKind.Ampersand => InfixOperator.BinaryAnd, TokenKind.AmpersandAmpersand => InfixOperator.LogicalAnd, TokenKind.Asterisk => InfixOperator.Multiply, TokenKind.Caret => InfixOperator.BinaryXor, TokenKind.Equal => InfixOperator.Equal, TokenKind.EqualEqual => InfixOperator.Equal, TokenKind.Greater => InfixOperator.Greater, TokenKind.GreaterEqual => InfixOperator.GreaterOrEqual, TokenKind.GreaterGreater => InfixOperator.ShiftRight, TokenKind.Less => InfixOperator.Less, TokenKind.LessEqual => InfixOperator.LessOrEqual, TokenKind.LessGreater => InfixOperator.NotEqual, TokenKind.LessLess => InfixOperator.ShiftLeft, TokenKind.Minus => InfixOperator.Subtract, TokenKind.Percent => InfixOperator.Modulo, TokenKind.Pipe => InfixOperator.BinaryOr, TokenKind.PipePipe => InfixOperator.LogicalOr, TokenKind.Plus => InfixOperator.Add, TokenKind.Slash => InfixOperator.Divide, _ => throw new ArgumentException( $"Cannot create an infix operator from a token {@operator.Kind}"), },
public Block(Token openingBrace, Token closingBrace, List <IStatement> statements) { Span = SourceSpan.Merge(openingBrace.Span, closingBrace.Span); OpeningBrace = openingBrace; ClosingBrace = closingBrace; Statements = statements; }
private static ITypeSignature ParsePointerSignature(ParserState state) { var spanStart = state.Previous().Span; var underlyingType = ParseTypeSignature(state); var span = SourceSpan.Merge(spanStart, underlyingType.Span); return(new PointerSignature(span, underlyingType)); }
private static IExpression ParseDereferenceExpression(ParserState state) { var startSpan = state.Previous().Span; var expression = ParsePrefixOperation(state); var nodeId = state.NodeIdGenerator.GetNextId(); var span = SourceSpan.Merge(startSpan, expression.Span); return(new Dereference(nodeId, span, expression)); }
private static IStatement ParseWhileStatement(Context context, ParserState state) { var startSpan = state.Previous().Span; var condition = ExpressionParser.ParseExpression(state); var body = ParseBlock(context, state); var nodeId = state.NodeIdGenerator.GetNextId(); var span = SourceSpan.Merge(startSpan, body.Span); return(new WhileStatement(nodeId, span, condition, body)); }
private static IExpression ParseSubscriptOperator(ParserState state, IExpression operand) { var index = ParseExpression(state); state.ConsumeOrError(TokenKind.RightBracket); var nodeId = state.NodeIdGenerator.GetNextId(); var span = SourceSpan.Merge(operand.Span, state.Previous().Span); return(new SubscriptExpression(nodeId, span, operand, index)); }
private static IExpression ParseParenthesizedExpression(ParserState state) { var startSpan = state.Previous().Span; var expression = ParseExpression(state); state.ConsumeOrError(TokenKind.RightParenthesis); var endSpan = state.Previous().Span; return(new ParenthesizedExpression( state.NodeIdGenerator.GetNextId(), SourceSpan.Merge(startSpan, endSpan), expression)); }
public PrefixOperation(int nodeId, Token @operator, IExpression operand) { NodeId = nodeId; Span = SourceSpan.Merge(@operator.Span, operand.Span); Operator = new Spanned <PrefixOperator>( @operator.Kind switch { TokenKind.Bang => PrefixOperator.Not, TokenKind.Plus => PrefixOperator.Identity, TokenKind.Minus => PrefixOperator.Negate, TokenKind.Tilde => PrefixOperator.BinaryNot, _ => throw new ArgumentException(nameof(@operator)), },
private static IStatement ParseReturnStatement(Context context, ParserState state) { var startSpan = state.Previous().Span; if (state.Current().Kind == TokenKind.Semicolon) { return(new ReturnStatement(state.NodeIdGenerator.GetNextId(), startSpan, null)); } var expression = ExpressionParser.ParseExpression(state); var endSpan = state.Previous().Span; var span = SourceSpan.Merge(startSpan, endSpan); return(new ReturnStatement(state.NodeIdGenerator.GetNextId(), span, expression)); }
private static IStatement ParseAssertStatement(Context context, ParserState state) { var startSpan = state.Previous().Span; state.ConsumeOrError(TokenKind.LeftParenthesis); var condition = ExpressionParser.ParseExpression(state); state.ConsumeOrError(TokenKind.RightParenthesis); var endSpan = state.Previous().Span; return(new AssertStatement( state.NodeIdGenerator.GetNextId(), SourceSpan.Merge(startSpan, endSpan), condition)); }
private static IStatement ParseIfStatement(Context context, ParserState state) { var startSpan = state.Previous().Span; var condition = ExpressionParser.ParseExpression(state); var thenBlock = ParseBlock(context, state); var elifs = ParseElifs(context, state); var elseBlock = state.Consume(TokenKind.Else) ? ParseBlock(context, state) : null; return(new IfStatement( state.NodeIdGenerator.GetNextId(), SourceSpan.Merge(startSpan, elseBlock != null ? elseBlock.Span : thenBlock.Span), condition, thenBlock, elifs, elseBlock)); }
private static void ConsumeUnnecessarySemicolons(Context context, ParserState state) { while (!state.IsAtEnd() && state.Consume(TokenKind.Semicolon)) { var firstSemicolon = state.Previous(); var lastSemicolon = firstSemicolon; while (state.Consume(TokenKind.Semicolon)) { lastSemicolon = state.Previous(); } var semicolonsSpan = SourceSpan.Merge(firstSemicolon.Span, lastSemicolon.Span); var message = firstSemicolon.Span.Start == lastSemicolon.Span.Start ? "unnecessary trailing semicolon" : "unnecessary trailing semicolons"; context.Warning(semicolonsSpan, message); } }
private static IStatement ParseFunctionDefinition(Context context, ParserState state) { var startSpan = state.Previous().Span; var identifier = state.ConsumeOrError(TokenKind.Identifier); var parameters = ParseFunctionParameters(context, state); var returnTypeSignature = state.Consume(TokenKind.Colon) ? TypeSignatureParser.ParseTypeSignature(state) : null; var body = ParseBlock(context, state); var endSpan = state.Previous().Span; var span = SourceSpan.Merge(startSpan, endSpan); return(new FunctionDefinition( state.NodeIdGenerator.GetNextId(), span, identifier, parameters, body, returnTypeSignature)); }
private static ITypeSignature ParseArraySignature(ParserState state) { var spanStart = state.Previous().Span; var underlyingType = ParseTypeSignature(state); state.ConsumeOrError(TokenKind.Semicolon); var length = int.Parse(state.ConsumeOrError(TokenKind.Integer).Lexeme); if (length <= 0) { throw new ParseException( state.Previous().Span, "array length must be a positive integer"); } state.ConsumeOrError(TokenKind.RightBracket); var spanEnd = state.Previous().Span; var span = SourceSpan.Merge(spanStart, spanEnd); return(new ArraySignature(span, underlyingType, length)); }
private static IStatement ParseVariableDefinition(Context context, ParserState state) { var startSpan = state.Previous().Span; var identifier = state.ConsumeOrError(TokenKind.Identifier); var typeSignature = state.Consume(TokenKind.Colon) ? TypeSignatureParser.ParseTypeSignature(state) : null; SourceSpan endSpan; SourceSpan span; if (state.Consume(TokenKind.Equal)) { var initializer = ExpressionParser.ParseExpression(state); endSpan = state.Previous().Span; span = SourceSpan.Merge(startSpan, endSpan); return(new VariableDefinition( state.NodeIdGenerator.GetNextId(), span, identifier, typeSignature, initializer)); } if (typeSignature == null) { throw new ParseException(identifier.Span, "type signature needed"); } endSpan = state.Previous().Span; span = SourceSpan.Merge(startSpan, endSpan); return(new VariableDefinition( state.NodeIdGenerator.GetNextId(), span, identifier, typeSignature, null)); }
private static IExpression ParseFunctionCall(ParserState state, IExpression callee) { var arguments = new List <IExpression>(); if (state.Consume(TokenKind.RightParenthesis)) { return(new FunctionCall( state.NodeIdGenerator.GetNextId(), SourceSpan.Merge(callee.Span, state.Previous().Span), callee, arguments)); } do { arguments.Add(ParseExpression(state)); } while (!state.IsAtEnd() && state.Consume(TokenKind.Comma)); state.ConsumeOrError(TokenKind.RightParenthesis); var span = SourceSpan.Merge(callee.Span, state.Previous().Span); return(new FunctionCall(state.NodeIdGenerator.GetNextId(), span, callee, arguments)); }