public bool ExecuteNext() { if (_statement == null) { return(false); } if (_statement.Type != ASTNodeType.STATEMENT) { throw new RunTimeError(_statement, "Invalid script"); } var node = _statement.FirstChild(); if (node == null) { throw new RunTimeError(_statement, "Invalid statement"); } int depth = 0; switch (node.Type) { case ASTNodeType.IF: { PushScope(node); var expr = node.FirstChild(); var result = EvaluateExpression(ref expr); // Advance to next statement _statement = _statement.Next(); // Evaluated true. Jump right into execution. if (result) { break; } // The expression evaluated false, so keep advancing until // we hit an elseif, else, or endif statement that matches // and try again. depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.IF) { depth++; } else if (node.Type == ASTNodeType.ELSEIF) { if (depth == 0) { expr = node.FirstChild(); result = EvaluateExpression(ref expr); // Evaluated true. Jump right into execution if (result) { _statement = _statement.Next(); break; } } } else if (node.Type == ASTNodeType.ELSE) { if (depth == 0) { // Jump into the else clause _statement = _statement.Next(); break; } } else if (node.Type == ASTNodeType.ENDIF) { if (depth == 0) { break; } depth--; } _statement = _statement.Next(); } if (_statement == null) { throw new RunTimeError(node, "If with no matching endif"); } break; } case ASTNodeType.ELSEIF: // If we hit the elseif statement during normal advancing, skip over it. The only way // to execute an elseif clause is to jump directly in from an if statement. depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.IF) { depth++; } else if (node.Type == ASTNodeType.ENDIF) { if (depth == 0) { break; } depth--; } _statement = _statement.Next(); } if (_statement == null) { throw new RunTimeError(node, "If with no matching endif"); } break; case ASTNodeType.ENDIF: PopScope(); _statement = _statement.Next(); break; case ASTNodeType.ELSE: // If we hit the else statement during normal advancing, skip over it. The only way // to execute an else clause is to jump directly in from an if statement. depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.IF) { depth++; } else if (node.Type == ASTNodeType.ENDIF) { if (depth == 0) { break; } depth--; } _statement = _statement.Next(); } if (_statement == null) { throw new RunTimeError(node, "If with no matching endif"); } break; case ASTNodeType.WHILE: { // When we first enter the loop, push a new scope if (_scope.StartNode != node) { PushScope(node); } var expr = node.FirstChild(); var result = EvaluateExpression(ref expr); // Advance to next statement _statement = _statement.Next(); // The expression evaluated false, so keep advancing until // we hit an endwhile statement. if (!result) { depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.WHILE) { depth++; } else if (node.Type == ASTNodeType.ENDWHILE) { if (depth == 0) { PopScope(); // Go one past the endwhile so the loop doesn't repeat _statement = _statement.Next(); break; } depth--; } _statement = _statement.Next(); } } break; } case ASTNodeType.ENDWHILE: // Walk backward to the while statement _statement = _statement.Prev(); depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.ENDWHILE) { depth++; } else if (node.Type == ASTNodeType.WHILE) { if (depth == 0) { break; } depth--; } _statement = _statement.Prev(); } if (_statement == null) { throw new RunTimeError(node, "Unexpected endwhile"); } break; case ASTNodeType.FOR: { // The iterator variable's name is the hash code of the for loop's ASTNode. var iterName = node.GetHashCode().ToString(); // When we first enter the loop, push a new scope if (_scope.StartNode != node) { PushScope(node); // Grab the arguments var max = node.FirstChild(); if (max.Type != ASTNodeType.INTEGER) { throw new RunTimeError(max, "Invalid for loop syntax"); } // Create a dummy argument that acts as our loop variable var iter = new ASTNode(ASTNodeType.INTEGER, "0", node, 0); _scope.SetVar(iterName, new Argument(this, iter)); } else { // Increment the iterator argument var arg = _scope.GetVar(iterName); var iter = new ASTNode(ASTNodeType.INTEGER, (arg.AsUInt() + 1).ToString(), node, 0); _scope.SetVar(iterName, new Argument(this, iter)); } // Check loop condition var i = _scope.GetVar(iterName); // Grab the max value to iterate to node = node.FirstChild(); var end = new Argument(this, node); if (i.AsUInt() < end.AsUInt()) { // enter the loop _statement = _statement.Next(); } else { // Walk until the end of the loop _statement = _statement.Next(); depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.FOR || node.Type == ASTNodeType.FOREACH) { depth++; } else if (node.Type == ASTNodeType.ENDFOR) { if (depth == 0) { PopScope(); // Go one past the end so the loop doesn't repeat _statement = _statement.Next(); break; } depth--; } _statement = _statement.Next(); } } } break; case ASTNodeType.FOREACH: { // foreach VAR in LIST // The iterator's name is the hash code of the for loop's ASTNode. var varName = node.FirstChild().Lexeme; var listName = node.FirstChild().Next().Lexeme; var iterName = node.GetHashCode().ToString(); // When we first enter the loop, push a new scope if (_scope.StartNode != node) { PushScope(node); // Create a dummy argument that acts as our iterator object var iter = new ASTNode(ASTNodeType.INTEGER, "0", node, 0); _scope.SetVar(iterName, new Argument(this, iter)); // Make the user-chosen variable have the value for the front of the list var arg = Interpreter.GetListValue(listName, 0); if (arg != null) { _scope.SetVar(varName, arg); } else { _scope.ClearVar(varName); } } else { // Increment the iterator argument var idx = _scope.GetVar(iterName).AsInt() + 1; var iter = new ASTNode(ASTNodeType.INTEGER, idx.ToString(), node, 0); _scope.SetVar(iterName, new Argument(this, iter)); // Update the user-chosen variable var arg = Interpreter.GetListValue(listName, idx); if (arg != null) { _scope.SetVar(varName, arg); } else { _scope.ClearVar(varName); } } // Check loop condition var i = _scope.GetVar(varName); if (i != null) { // enter the loop _statement = _statement.Next(); } else { // Walk until the end of the loop _statement = _statement.Next(); depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.FOR || node.Type == ASTNodeType.FOREACH) { depth++; } else if (node.Type == ASTNodeType.ENDFOR) { if (depth == 0) { PopScope(); // Go one past the end so the loop doesn't repeat _statement = _statement.Next(); break; } depth--; } _statement = _statement.Next(); } } break; } case ASTNodeType.ENDFOR: // Walk backward to the for statement _statement = _statement.Prev(); while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.FOR || node.Type == ASTNodeType.FOREACH) { break; } _statement = _statement.Prev(); } if (_statement == null) { throw new RunTimeError(node, "Unexpected endfor"); } break; case ASTNodeType.BREAK: // Walk until the end of the loop _statement = _statement.Next(); depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.WHILE || node.Type == ASTNodeType.FOR || node.Type == ASTNodeType.FOREACH) { depth++; } else if (node.Type == ASTNodeType.ENDWHILE || node.Type == ASTNodeType.ENDFOR) { if (depth == 0) { PopScope(); // Go one past the end so the loop doesn't repeat _statement = _statement.Next(); break; } depth--; } _statement = _statement.Next(); } PopScope(); break; case ASTNodeType.CONTINUE: // Walk backward to the loop statement _statement = _statement.Prev(); depth = 0; while (_statement != null) { node = _statement.FirstChild(); if (node.Type == ASTNodeType.ENDWHILE || node.Type == ASTNodeType.ENDFOR) { depth++; } else if (node.Type == ASTNodeType.WHILE || node.Type == ASTNodeType.FOR || node.Type == ASTNodeType.FOREACH) { if (depth == 0) { break; } depth--; } _statement = _statement.Prev(); } if (_statement == null) { throw new RunTimeError(node, "Unexpected continue"); } break; case ASTNodeType.STOP: _statement = null; break; case ASTNodeType.REPLAY: _statement = _statement.Parent.FirstChild(); break; case ASTNodeType.QUIET: case ASTNodeType.FORCE: case ASTNodeType.COMMAND: if (ExecuteCommand(node)) { _statement = _statement.Next(); } break; } return((_statement != null) ? true : false); }
public void SetVar(string name, Argument val) { _namespace[name] = val; }