package org.zwobble.couscous.interpreter; import java.util.List; import java.util.Optional; import java.util.stream.Stream; import org.zwobble.couscous.ast.ExpressionStatementNode; import org.zwobble.couscous.ast.LocalVariableDeclarationNode; import org.zwobble.couscous.ast.MethodNode; import org.zwobble.couscous.ast.ReturnNode; import org.zwobble.couscous.ast.StatementNode; import org.zwobble.couscous.ast.VariableNode; import org.zwobble.couscous.ast.visitors.StatementNodeVisitor; import org.zwobble.couscous.values.InterpreterValue; import org.zwobble.couscous.values.UnitValue; import static org.zwobble.couscous.interpreter.Evaluator.eval; import lombok.val; public class Executor implements StatementNodeVisitor> { public static InterpreterValue callMethod(Environment environment, MethodNode method, Arguments arguments) { val innerEnvironment = buildEnvironment(environment, method, arguments); for (val statement : method.getBody()) { val result = exec(innerEnvironment, statement); if (result.isPresent()) { return result.get(); } } return UnitValue.UNIT; } private static Environment buildEnvironment( final Environment environment, final MethodNode method, Arguments arguments) { val stackFrame = new StackFrameBuilder(); for (int index = 0; index < method.getArguments().size(); index++) { stackFrame.declare(method.getArguments().get(index), arguments.get(index)); } findDeclarations(method.getBody()).forEach(declaration -> stackFrame.declare(declaration)); return environment.withStackFrame(stackFrame.build()); } private static Stream findDeclarations(List body) { return body.stream() .flatMap(statement -> statement.accept(new StatementNodeVisitor>() { @Override public Stream visit(ReturnNode returnNode) { return Stream.empty(); } @Override public Stream visit(ExpressionStatementNode expressionStatement) { return Stream.empty(); } @Override public Stream visit(LocalVariableDeclarationNode localVariableDeclaration) { return Stream.of(localVariableDeclaration); } })); } public static Optional exec(Environment environment, StatementNode statement) { return statement.accept(new Executor(environment)); } private final Environment environment; private Executor(Environment environment) { this.environment = environment; } @Override public Optional visit(ReturnNode returnNode) { return Optional.of(eval(environment, returnNode.getValue())); } @Override public Optional visit(ExpressionStatementNode expressionStatement) { eval(environment, expressionStatement.getExpression()); return Optional.empty(); } @Override public Optional visit(LocalVariableDeclarationNode localVariableDeclaration) { val value = eval(environment, localVariableDeclaration.getInitialValue()); environment.put(localVariableDeclaration, value); return Optional.empty(); } }