public ASTNode ParseBody() { do { if (Tokens.CurrentItem.StartPosition.Equals(Body.StartPos)) { break; } Tokens.Advance(); } while (!Tokens.AtEnd()); if (Tokens.AtEnd()) { return(Error("Could not find the code body for the current node, please contact the maintainers of this compiler!")); } var body = TryParseBody(false); if (body == null) { return(null); } Body.Statements = body.Statements; if (!Tokens.CurrentItem.StartPosition.Equals(Body.EndPos)) { return(Error("Could not parse a valid statement, even though the current code body has supposedly not ended yet.", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } return(Body); }
/// <summary> /// Skip tokens until we reach what we assume to be the end of a statement /// </summary> // TODO does this belong on a statement parser or something private void SkipToEndOfStatement() { while (!Tokens.AtEnd <ISemicolonToken>()) { Tokens.Next(); } // Consume the semicolon is we aren't at the end of the file. var _ = Tokens.Accept <ISemicolonToken>(); }
public FixedList <T> ParseMany <T, TTerminator>(Func <T> parseItem) where T : class where TTerminator : IToken { var items = new List <T>(); while (!Tokens.AtEnd <TTerminator>()) { items.Add(parseItem()); } return(items.ToFixedList()); }
/// <summary> /// Requires that the open paren has already been consumed /// </summary> /// <returns></returns> private FixedList <ParameterSyntax> ParseRestOfParameters() { var parameters = new List <ParameterSyntax>(); while (!Tokens.AtEnd <ICloseParenToken>()) { parameters.Add(ParseParameter()); if (Tokens.Current is ICommaToken) { Tokens.Expect <ICommaToken>(); } } Tokens.Expect <ICloseParenToken>(); return(parameters.ToFixedList()); }
private FixedList <EnumVariantSyntax> ParseEnumVariants() { var variants = new List <EnumVariantSyntax>(); while (Tokens.Current is IIdentifierToken) { variants.Add(ParseEnumVariant()); } // Semicolon is optional if there are no members if (!Tokens.AtEnd <ICloseBraceToken>()) { Tokens.Expect <ISemicolonToken>(); } return(variants.ToFixedList()); }
public Struct TryParseStruct() { Func <ASTNode> structParser = () => { if (Tokens.ConsumeToken(TokenType.Struct) == null) { return(null); } var specs = ParseSpecifiers(GlobalLists.StructSpecifiers); var name = Tokens.ConsumeToken(TokenType.Word); if (name == null) { return(Error("Expected struct name!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } var parent = TryParseParent(); if (Tokens.ConsumeToken(TokenType.LeftBracket) == null) { return(Error("Expected '{'!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } var vars = new List <VariableDeclaration>(); do { var variable = TryParseVarDecl(); if (variable == null) { return(Error("Malformed struct content!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } vars.Add(variable); } while (CurrentTokenType != TokenType.RightBracket && !Tokens.AtEnd()); if (Tokens.ConsumeToken(TokenType.RightBracket) == null) { return(Error("Expected '}'!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } return(new Struct(name.Value, specs, vars, name.StartPosition, name.EndPosition, parent)); }; return((Struct)Tokens.TryGetTree(structParser)); }
public FixedList <T> ParseMany <T, TSeparator, TTerminator>(Func <T> parseItem) where T : class where TSeparator : class, IToken where TTerminator : IToken { var items = new List <T>(); while (!Tokens.AtEnd <TTerminator>()) { items.Add(parseItem()); if (!Tokens.Accept <TSeparator>()) { break; } } return(items.ToFixedList()); }
public FixedList <DeclarationSyntax> ParseDeclarations() { var declarations = new List <DeclarationSyntax>(); // Stop at end of file or close brace that contains these declarations while (!Tokens.AtEnd <ICloseBraceToken>()) { try { declarations.AddRange(ParseDeclaration()); } catch (ParseFailedException) { // Ignore: we would have consumed something before failing, try to get the next declaration } } return(declarations.ToFixedList()); }
public FixedList <DeclarationSyntax> ParseTopLevelDeclarations() { var declarations = new List <DeclarationSyntax>(); // Keep going to the end of the file while (!Tokens.AtEnd <IEndOfFileToken>()) { try { declarations.AddRange(ParseDeclaration()); } catch (ParseFailedException) { // Ignore: we would have consumed something before failing, try to get the next declaration } } return(declarations.ToFixedList()); }
public FixedList <INonMemberDeclarationSyntax> ParseNonMemberDeclarations <T>() where T : IToken { var declarations = new List <INonMemberDeclarationSyntax>(); // Stop at end of file or some token that contains these declarations while (!Tokens.AtEnd <T>()) { try { declarations.Add(ParseNonMemberDeclaration()); } catch (ParseFailedException) { // Ignore: we would have consumed something before failing, try to get the next declaration } } return(declarations.ToFixedList()); }
public State TryParseState() { Func <ASTNode> stateSkeletonParser = () => { var specs = ParseSpecifiers(GlobalLists.StateSpecifiers); if (Tokens.ConsumeToken(TokenType.State) == null) { return(null); } var name = Tokens.ConsumeToken(TokenType.Word); if (name == null) { return(Error("Expected state name!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } var parent = TryParseParent(); if (Tokens.ConsumeToken(TokenType.LeftBracket) == null) { return(Error("Expected '{'!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } List <Function> ignores = new List <Function>(); if (Tokens.ConsumeToken(TokenType.Ignores) != null) { do { VariableIdentifier variable = TryParseVariable(); if (variable == null) { return(Error("Malformed ignore statement!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } ignores.Add(new Function(variable.Name, null, null, null, null, variable.StartPos, variable.EndPos)); } while (Tokens.ConsumeToken(TokenType.Comma) != null); if (Tokens.ConsumeToken(TokenType.SemiColon) == null) { return(Error("Expected semi-colon!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } } var funcs = new List <Function>(); Function func = TryParseFunction(); while (func != null) { funcs.Add(func); func = TryParseFunction(); } var bodyStart = Tokens.CurrentItem.StartPosition; while (Tokens.CurrentItem.Type != TokenType.RightBracket && !Tokens.AtEnd()) { Tokens.Advance(); } var bodyEnd = Tokens.CurrentItem.StartPosition; if (Tokens.ConsumeToken(TokenType.RightBracket) == null) { return(Error("Expected '}'!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } var body = new CodeBody(new List <Statement>(), bodyStart, bodyEnd); var parentState = parent != null ? new State(parent.Name, null, null, null, null, null, null, parent.StartPos, parent.EndPos) : null; return(new State(name.Value, body, specs, parentState, funcs, ignores, null, name.StartPosition, name.EndPosition)); }; return((State)Tokens.TryGetTree(stateSkeletonParser)); }
public Class TryParseClass() { Func <ASTNode> classParser = () => { if (Tokens.ConsumeToken(TokenType.Class) == null) { return(Error("Expected class declaration!")); } var name = Tokens.ConsumeToken(TokenType.Word); if (name == null) { return(Error("Expected class name!")); } var parentClass = TryParseParent(); if (parentClass == null) { Log.LogMessage("No parent class specified for " + name.Value + ", interiting from Object"); parentClass = new VariableType("Object", null, null); } var outerClass = TryParseOuter(); var specs = ParseSpecifiers(GlobalLists.ClassSpecifiers); if (Tokens.ConsumeToken(TokenType.SemiColon) == null) { return(Error("Expected semi-colon!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } var variables = new List <VariableDeclaration>(); var types = new List <VariableType>(); while (CurrentTokenType == TokenType.InstanceVariable || CurrentTokenType == TokenType.Struct || CurrentTokenType == TokenType.Enumeration) { if (CurrentTokenType == TokenType.InstanceVariable) { var variable = TryParseVarDecl(); if (variable == null) { return(Error("Malformed instance variable!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } variables.Add(variable); } else { var type = TryParseEnum() ?? TryParseStruct() ?? new VariableType("INVALID", null, null); if (type.Name == "INVALID") { return(Error("Malformed type declaration!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } types.Add(type); if (Tokens.ConsumeToken(TokenType.SemiColon) == null) { return(Error("Expected semi-colon!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } } } List <Function> funcs = new List <Function>(); List <State> states = new List <State>(); List <OperatorDeclaration> ops = new List <OperatorDeclaration>(); ASTNode declaration; do { declaration = (ASTNode)TryParseFunction() ?? (ASTNode)TryParseOperatorDecl() ?? (ASTNode)TryParseState() ?? (ASTNode)null; if (declaration == null && !Tokens.AtEnd()) { return(Error("Expected function/state/operator declaration!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1))); } if (declaration.Type == ASTNodeType.Function) { funcs.Add((Function)declaration); } else if (declaration.Type == ASTNodeType.State) { states.Add((State)declaration); } else { ops.Add((OperatorDeclaration)declaration); } } while (!Tokens.AtEnd()); // TODO: should AST-nodes accept null values? should they make sure they dont present any? return(new Class(name.Value, specs, variables, types, funcs, states, parentClass, outerClass, ops, name.StartPosition, name.EndPosition)); }; return((Class)Tokens.TryGetTree(classParser)); }