public static void Interpret(AstNode program, Environment env) { if (program.Type != AstNodeType.Program) { throw new InterpreterException("Expected a program."); } InterpretStatementList(program.Children, env); }
private static AstNode LeftAssocCombiner( string[] operators, ParseFunction termParser, TokenStream tokenStream) { AstNode leftTerm = termParser(tokenStream); while (tokenStream.HasMoreTokens && OneOf(tokenStream.Current.Content, operators)) { AstNode tokenNode = new AstNode(AstNodeType.Identifier, tokenStream.Current); tokenStream.Next(); AstNode rightTerm = termParser(tokenStream); leftTerm = new AstNode( AstNodeType.BinaryExpression, new AstNode[] { tokenNode, leftTerm, rightTerm }); } return leftTerm; }
private static object EvaluateExpression(AstNode astNode, Environment env) { switch (astNode.Type) { case AstNodeType.BinaryExpression: return EvaluateBinaryExpression(astNode, env); case AstNodeType.UnaryExpression: return EvaluateUnaryExpression(astNode, env); case AstNodeType.FunctionCall: return EvaluateFunctionCall(astNode, env); case AstNodeType.Number: return Int32.Parse(astNode.Token.Content); case AstNodeType.FunctionDeclaration: return EvaluateFunctionDeclaration(astNode, env); case AstNodeType.Identifier: return EvaluateIdentifier(astNode, env); default: throw new InterpreterException(String.Format( "Unknown kind of Expression '{0}'.", astNode.Type)); } }
private static object EvaluateBinaryExpression(AstNode astNode, Environment env) { string binaryOp = astNode.Children[0].Token.Content; object rawOperand1 = EvaluateExpression(astNode.Children[1], env); object rawOperand2 = EvaluateExpression(astNode.Children[2], env); int operand1 = EvaluateInt(rawOperand1); int operand2 = EvaluateInt(rawOperand2); switch (binaryOp) { case "+": return operand1 + operand2; case "-": return operand1 - operand2; case "*": return operand1 * operand2; case "/": return operand1 / operand2; case "<": return (operand1 < operand2) ? 1 : 0; case "<=": return (operand1 <= operand2) ? 1 : 0; case "==": return (object.Equals(rawOperand1, rawOperand2)) ? 1 : 0; case "!=": return !(object.Equals(rawOperand1, rawOperand2)) ? 1 : 0; case ">=": return (operand1 >= operand2) ? 1 : 0; case ">": return (operand1 > operand2) ? 1 : 0; case "||": return (TruthFunction(rawOperand1) || TruthFunction(rawOperand2)) ? 1 : 0; case "&&": return (TruthFunction(rawOperand1) && TruthFunction(rawOperand2)) ? 1 : 0; } throw new InterpreterException(String.Format( "Unknown binary operator '{0}'.", binaryOp)); }
private static object EvaluateFunctionCall(AstNode functionCallNode, Environment env) { AstNode functionNode = functionCallNode.Children[0]; if (functionNode.Type == AstNodeType.Identifier) { string functionName = functionNode.Token.Content; if (functionName == "print") { // execute our only built-in :-) object valueToPrint = EvaluateExpression(functionCallNode.Children[1], env); if (valueToPrint != null) { Console.WriteLine(valueToPrint.ToString()); } else { Console.WriteLine("<null>"); } return null; } } FunctionValue function = EvaluateExpression(functionNode, env) as FunctionValue; if (function == null) { throw new InterpreterException("Object is not a function."); } List<object> argumentValues = new List<object>(); for (int i = 1; i < functionCallNode.Children.Count; i++) { AstNode argExpression = functionCallNode.Children[i]; argumentValues.Add(EvaluateExpression(argExpression, env)); } return function.Call(argumentValues); }
private static Pair<bool, object> InterpretStatement(AstNode statement, Environment env) { switch (statement.Type) { case AstNodeType.FunctionCall: return new Pair<bool, object>( true, EvaluateFunctionCall(statement, env)); case AstNodeType.AssignmentStatement: env.AssignLocal( statement.Children[0].Token.Content, EvaluateExpression(statement.Children[1], env)); return new Pair<bool, object>(true, null); case AstNodeType.IfStatement: return InterpretIfStatement(statement, env); case AstNodeType.CompoundStatement: return InterpretStatementList(statement.Children, env); case AstNodeType.ReturnStatement: return new Pair<bool, object>( false, EvaluateExpression(statement.Children[0], env)); default: throw new InterpreterException(String.Format( "Invalid statement {0}.", statement.Type)); } }
private static Pair<bool, object> InterpretIfStatement(AstNode statement, Environment env) { if (TruthFunction(EvaluateExpression(statement.Children[0], env))) { return InterpretStatement(statement.Children[1], env); } else if (statement.Children.Count == 3) { return InterpretStatement(statement.Children[2], env); } return new Pair<bool, object>(true, null); }
private static object EvaluateUnaryExpression(AstNode astNode, Environment env) { string unaryOp = astNode.Children[0].Token.Content; switch (unaryOp) { case "-": return -EvaluateInt(EvaluateExpression(astNode.Children[1], env)); case "!": return !TruthFunction(EvaluateExpression(astNode.Children[1], env)) ? 1 : 0; } throw new InterpreterException(String.Format( "Unknown unary operator '{0}'.", unaryOp)); }
private static object EvaluateIdentifier(AstNode astNode, Environment env) { string varName = astNode.Token.Content; if (varName == "null") { return null; } Pair<bool, object> result = env.LookUp(varName); if (result.First) { return result.Second; } else { throw new InterpreterException(String.Format( "Cannot find variable '{0}'.", varName)); } }
private static object EvaluateFunctionDeclaration(AstNode astNode, Environment env) { List<string> argList = new List<string>(); foreach (AstNode argNode in astNode.Children[0].Children) { argList.Add(argNode.Token.Content); } return new FunctionValue(astNode.Children[1].Children, env, argList); }
private static AstNode ParseFunctionCallExpression(AstNode function, TokenStream tokenStream) { MatchToken(TokenType.OpenParen, "(", tokenStream); List<AstNode> arguments = ParseExpressionList(tokenStream); MatchToken(TokenType.CloseParen, ")", tokenStream); arguments.Insert(0, function); return new AstNode(AstNodeType.FunctionCall, arguments); }
private static AstNode ParseExprUnary(TokenStream tokenStream) { CheckEnd(tokenStream); AstNode result; if (tokenStream.Current.Type == TokenType.OpenParen) { result = ParseParenExpression(tokenStream); } else if (tokenStream.Current.Type == TokenType.Minus || tokenStream.Current.Type == TokenType.LogicalNot) { AstNode tokenNode = new AstNode(AstNodeType.Identifier, tokenStream.Current); tokenStream.Next(); AstNode negatedExpression = ParseExprUnary(tokenStream); result = new AstNode(AstNodeType.UnaryExpression, new AstNode[] { tokenNode, negatedExpression }); } else if (tokenStream.Current.Type == TokenType.Identifier) { AstNode tokenNode = new AstNode(AstNodeType.Identifier, tokenStream.Current); tokenStream.Next(); if (tokenStream.HasMoreTokens && tokenStream.Current.Type == TokenType.OpenParen) { result = ParseFunctionCallExpression(tokenNode, tokenStream); } else { result = tokenNode; } } else if (tokenStream.Current.Type == TokenType.Number) { result = new AstNode(AstNodeType.Number, tokenStream.Current); tokenStream.Next(); } else { throw new ParserException(String.Format( "Expecting an unary expression at {0}.", tokenStream.Current.Start)); } while (tokenStream.HasMoreTokens && tokenStream.Current.Type == TokenType.OpenParen) { result = ParseFunctionCallExpression(result, tokenStream); } return result; }
private static AstNode ParseAssignmentStatement(AstNode tok, TokenStream tokenStream) { MatchToken(TokenType.Equal, "=", tokenStream); AstNode value = ParseExpression(tokenStream); MatchToken(TokenType.Semicolon, ";", tokenStream); return new AstNode(AstNodeType.AssignmentStatement, new AstNode[] { tok, value }); }
private static AstNode ParseAssignmentOrFunctionCallStatement(TokenStream tokenStream) { CheckEnd(tokenStream); AstNode tokenNode = new AstNode(AstNodeType.Identifier, tokenStream.Current); tokenStream.Next(); CheckEnd(tokenStream); if (tokenStream.Current.Type == TokenType.Equal) { return ParseAssignmentStatement(tokenNode, tokenStream); } else if (tokenStream.Current.Type == TokenType.OpenParen) { AstNode result = ParseFunctionCallExpression(tokenNode, tokenStream); MatchToken(TokenType.Semicolon, ";", tokenStream); return result; } else { throw new ParserException(String.Format( "Expected an assignment or function call at {0}.", tokenNode.Token.Start)); } }