//TODO: unused? private List <Token <String> > ParseScopedTokens(TokenType scopeStart, TokenType scopeEnd) { var scopedTokens = new List <Token <String> >(); if (Tokens.ConsumeToken(scopeStart) == null) { Log.LogError("Expected '" + scopeStart.ToString() + "'!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1)); return(null); } int nestedLevel = 1; while (nestedLevel > 0) { if (CurrentTokenType == TokenType.EOF) { return(null); // ERROR: Scope ended prematurely, are your scopes unbalanced? } if (CurrentTokenType == scopeStart) { nestedLevel++; } else if (CurrentTokenType == scopeEnd) { nestedLevel--; } scopedTokens.Add(Tokens.CurrentItem); Tokens.Advance(); } // Remove the ending scope token: scopedTokens.RemoveAt(scopedTokens.Count - 1); return(scopedTokens); }
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> /// Creates a rule - metadata that allows invocation of a function on /// </summary> private void RuleDeclaration() { if (_EnclosingCompiler != null) { throw new CompilerException(Tokens.Peek(), "Rules must be globally scoped."); } Token triggerName = Tokens.Consume(IDENTIFIER, "Rule declarations must begin with a named trigger."); List <RuleCondition> conditions = new List <RuleCondition>(); // rule conditions while (!Tokens.Match(RIGHT_BRACKET)) { Token contextVariableName = Tokens.Consume(IDENTIFIER, "Rule must contain list of comparison expressions (missing identifier)."); Token comparisonOperation = Tokens.Advance(); // we will check validity of this token after consuming the value Token contextVariableValue = Tokens.Consume(NUMBER, "Rule must contain list of comparison expressions (missing value)"); switch (comparisonOperation.Type) { case BANG_EQUAL: // conditions.Add(RuleCondition.ConditionNotEquals(contextVariableName.Lexeme, contextVariableValue.LiteralAsNumber)); throw new CompilerException(Tokens.Peek(), "Rule must contain list of comparison expressions (can't use != operator)."); case EQUAL: case EQUAL_EQUAL: conditions.Add(RuleCondition.ConditionEquals(contextVariableName.Lexeme, contextVariableValue.LiteralAsNumber)); break; case GREATER: conditions.Add(RuleCondition.ConditionGreaterThan(contextVariableName.Lexeme, contextVariableValue.LiteralAsNumber)); break; case GREATER_EQUAL: conditions.Add(RuleCondition.ConditionGreaterThanOrEqual(contextVariableName.Lexeme, contextVariableValue.LiteralAsNumber)); break; case LESS: conditions.Add(RuleCondition.ConditionLessThan(contextVariableName.Lexeme, contextVariableValue.LiteralAsNumber)); break; case LESS_EQUAL: conditions.Add(RuleCondition.ConditionLessThanOrEqual(contextVariableName.Lexeme, contextVariableValue.LiteralAsNumber)); break; default: throw new CompilerException(Tokens.Peek(), "Rule must contain list of comparison expressions (missing operator)."); } } if (Tokens.Peek().Type == FUNCTION && Tokens.Peek(1).Type == IDENTIFIER) { string functionName = Tokens.Peek(1).Lexeme; _Rules.Add(new Rule(BitString.GetBitStr(triggerName.Lexeme), BitString.GetBitStr(functionName), conditions.ToArray())); } else { throw new CompilerException(Tokens.Peek(), "Rule declaration must be followed by function."); } }
private bool ParseScopeSpan(TokenType scopeStart, TokenType scopeEnd, out SourcePosition startPos, out SourcePosition endPos) { startPos = null; endPos = null; if (Tokens.ConsumeToken(scopeStart) == null) { Log.LogError("Expected '" + scopeStart.ToString() + "'!", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1)); return(false); } startPos = Tokens.CurrentItem.StartPosition; int nestedLevel = 1; while (nestedLevel > 0) { if (CurrentTokenType == TokenType.EOF) { Log.LogError("Scope ended prematurely, are your scopes unbalanced?", CurrentPosition, CurrentPosition.GetModifiedPosition(0, 1, 1)); return(false); } if (CurrentTokenType == scopeStart) { nestedLevel++; } else if (CurrentTokenType == scopeEnd) { nestedLevel--; } // If we're at the end token, don't advance so we can check the position properly. if (nestedLevel > 0) { Tokens.Advance(); } } endPos = Tokens.CurrentItem.StartPosition; Tokens.Advance(); return(true); }
// === Error Handling ======================================================================================== // =========================================================================================================== /// <summary> /// Discards tokens until it thinks it found a statement boundary. After catching a ParseError, we’ll call this /// and then we are hopefully back in sync. When it works well, we have discarded tokens that would have likely /// caused cascaded errors anyway and now we can parse the rest of the file starting at the next statement. /// </summary> protected override void Synchronize() { Tokens.Advance(); while (!Tokens.IsAtEnd()) { if (Tokens.Previous().Type == SEMICOLON) { return; } switch (Tokens.Peek().Type) { case CLASS: case FUNCTION: case VAR: case FOR: case IF: case WHILE: case RETURN: return; } Tokens.Advance(); } }
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)); }