From 04cb46e94da85f173d755acf0a36b51112f3df6c Mon Sep 17 00:00:00 2001 From: Mike Cifelli Date: Sun, 5 Mar 2017 10:20:31 -0500 Subject: [PATCH] Store the base directory for an interpreted files A bug was resolved where some functions were getting a null ErrorManager. A reset funtion was added to RuntimeEnvironment. Resolves #15 --- src/environment/RuntimeEnvironment.java | 52 ++++++++--- src/function/builtin/LOAD.java | 13 +-- src/function/builtin/special/Define.java | 8 +- .../InteractiveLispInterpreter.java | 12 +-- src/interpreter/LispInterpreter.java | 14 ++- .../LispInterpreterBuilderImpl.java | 14 ++- .../environment/RuntimeEnvironmentTester.java | 89 +++++++++++++++++-- test/error/ErrorManagerTester.java | 6 ++ test/function/builtin/EXITTester.java | 13 ++- test/function/builtin/LOADTester.java | 16 ++++ test/function/builtin/PRINTTester.java | 13 ++- .../builtin/special/DEFINE_MACROTester.java | 3 +- .../function/builtin/special/DEFUNTester.java | 3 +- 13 files changed, 206 insertions(+), 50 deletions(-) diff --git a/src/environment/RuntimeEnvironment.java b/src/environment/RuntimeEnvironment.java index eec0f9f..8e03352 100644 --- a/src/environment/RuntimeEnvironment.java +++ b/src/environment/RuntimeEnvironment.java @@ -17,17 +17,35 @@ public class RuntimeEnvironment { private InputStream input; private PrintStream output; private PrintStream errorOutput; - + private ErrorManager errorManager; + private String path; + private Runnable terminationFunction; + private Runnable errorTerminationFunction; private Function outputDecorator; private Function valueOutputDecorator; private Function warningOutputDecorator; private Function errorOutputDecorator; private Function criticalOutputDecorator; - private Runnable terminationFunction; - private Runnable errorTerminationFunction; - private ErrorManager errorManager; - private RuntimeEnvironment() {} + private RuntimeEnvironment() { + reset(); + } + + public void reset() { + inputName = null; + input = null; + output = null; + errorOutput = null; + errorManager = null; + path = null; + terminationFunction = null; + errorTerminationFunction = null; + outputDecorator = null; + valueOutputDecorator = null; + warningOutputDecorator = null; + errorOutputDecorator = null; + criticalOutputDecorator = null; + } public void setInputName(String inputName) { this.inputName = inputName; @@ -45,6 +63,14 @@ public class RuntimeEnvironment { this.errorOutput = errorOutput; } + public void setErrorManager(ErrorManager errorManager) { + this.errorManager = errorManager; + } + + public void setPath(String path) { + this.path = path; + } + public void setTerminationFunction(Runnable terminationFunction) { this.terminationFunction = terminationFunction; } @@ -53,10 +79,6 @@ public class RuntimeEnvironment { this.errorTerminationFunction = errorTerminationFunction; } - public void setErrorManager(ErrorManager errorManager) { - this.errorManager = errorManager; - } - public void setOutputDecorator(Function outputDecorator) { this.outputDecorator = outputDecorator; } @@ -93,6 +115,14 @@ public class RuntimeEnvironment { return errorOutput; } + public ErrorManager getErrorManager() { + return errorManager; + } + + public String getPath() { + return path; + } + public void terminateSuccessfully() { terminationFunction.run(); } @@ -101,10 +131,6 @@ public class RuntimeEnvironment { errorTerminationFunction.run(); } - public ErrorManager getErrorManager() { - return errorManager; - } - public String decorateOutput(String output) { return outputDecorator.apply(output); } diff --git a/src/function/builtin/LOAD.java b/src/function/builtin/LOAD.java index 063a63a..5c5d618 100644 --- a/src/function/builtin/LOAD.java +++ b/src/function/builtin/LOAD.java @@ -18,14 +18,14 @@ import sexpression.*; public class LOAD extends LispFunction { private ArgumentValidator argumentValidator; - private ErrorManager errorManager; + private RuntimeEnvironment environment; private Stack pathPrefixes; public LOAD() { this.argumentValidator = new ArgumentValidator("LOAD"); this.argumentValidator.setExactNumberOfArguments(1); this.argumentValidator.setEveryArgumentExpectedType(LispString.class); - this.errorManager = RuntimeEnvironment.getInstance().getErrorManager(); + this.environment = RuntimeEnvironment.getInstance(); this.pathPrefixes = new Stack<>(); } @@ -54,7 +54,10 @@ public class LOAD extends LispFunction { } private String prefixFileNameIfNecessary(String fileName) { - return pathPrefixes.empty() ? fileName : pathPrefixes.peek() + fileName; + if (pathPrefixes.isEmpty()) + return environment.getPath() + fileName; + + return pathPrefixes.peek() + fileName; } private LispParser attemptToCreateParserOnFile(String fileName) { @@ -63,7 +66,7 @@ public class LOAD extends LispFunction { try { parser = new LispParser(new FileInputStream(fileName), fileName); } catch (FileNotFoundException e) { - errorManager.handle(new CouldNotLoadFileWarning(fileName)); + this.environment.getErrorManager().handle(new CouldNotLoadFileWarning(fileName)); } return parser; @@ -86,7 +89,7 @@ public class LOAD extends LispFunction { try { eval(parser.getNextSExpression()); } catch (LispException e) { - errorManager.handle(e); + this.environment.getErrorManager().handle(e); return false; } } diff --git a/src/function/builtin/special/Define.java b/src/function/builtin/special/Define.java index d5c58fb..6575ba5 100644 --- a/src/function/builtin/special/Define.java +++ b/src/function/builtin/special/Define.java @@ -6,7 +6,7 @@ import static table.FunctionTable.*; import java.text.MessageFormat; import environment.RuntimeEnvironment; -import error.*; +import error.LispWarning; import function.*; import sexpression.*; @@ -15,7 +15,7 @@ public abstract class Define extends LispSpecialFunction { private ArgumentValidator argumentValidator; private ArgumentValidator lambdaListIsListValidator; private ArgumentValidator lambdaListValidator; - private ErrorManager errorManager; + private RuntimeEnvironment environment; public Define(String functionName) { this.argumentValidator = new ArgumentValidator(functionName); @@ -28,7 +28,7 @@ public abstract class Define extends LispSpecialFunction { this.lambdaListValidator = new ArgumentValidator(functionName + "|parameter|"); this.lambdaListValidator.setEveryArgumentExpectedType(Symbol.class); - this.errorManager = RuntimeEnvironment.getInstance().getErrorManager(); + this.environment = RuntimeEnvironment.getInstance(); } public SExpression call(Cons argumentList) { @@ -46,7 +46,7 @@ public abstract class Define extends LispSpecialFunction { UserDefinedFunction function = createFunction(functionName, lambdaList, functionBody); if (isAlreadyDefined(functionName.toString())) - errorManager.handle(new RedefiningFunctionWarning(functionName.toString())); + environment.getErrorManager().handle(new RedefiningFunctionWarning(functionName.toString())); defineFunction(functionName.toString(), function); diff --git a/src/interpreter/InteractiveLispInterpreter.java b/src/interpreter/InteractiveLispInterpreter.java index 95cd1f5..14080a0 100644 --- a/src/interpreter/InteractiveLispInterpreter.java +++ b/src/interpreter/InteractiveLispInterpreter.java @@ -7,26 +7,26 @@ public class InteractiveLispInterpreter extends LispInterpreter { @Override protected void printGreeting() { - output.println(GREETING); - output.println(); + environment.getOutput().println(GREETING); + environment.getOutput().println(); } @Override protected void displayPrompt() { - output.print(PROMPT); + environment.getOutput().print(PROMPT); } @Override protected void erasePrompt() { for (int i = 0; i < PROMPT.length(); i++) { - output.print("\b"); + environment.getOutput().print("\b"); } } @Override protected void printFarewell() { - output.println(); - output.println(); + environment.getOutput().println(); + environment.getOutput().println(); } } diff --git a/src/interpreter/LispInterpreter.java b/src/interpreter/LispInterpreter.java index 7449b06..b30fab0 100644 --- a/src/interpreter/LispInterpreter.java +++ b/src/interpreter/LispInterpreter.java @@ -2,24 +2,20 @@ package interpreter; import static function.builtin.EVAL.eval; -import java.io.*; +import java.io.InputStream; import environment.RuntimeEnvironment; -import error.*; +import error.LispException; import parser.LispParser; import sexpression.SExpression; public class LispInterpreter { protected RuntimeEnvironment environment; - protected ErrorManager errorManager; - protected PrintStream output; private LispParser parser; public LispInterpreter() { this.environment = RuntimeEnvironment.getInstance(); - this.errorManager = this.environment.getErrorManager(); - this.output = environment.getOutput(); } public void setInput(InputStream input, String inputName) { @@ -50,7 +46,7 @@ public class LispInterpreter { printValueOfNextSExpressionWithException(); } catch (LispException e) { erasePrompt(); - errorManager.handle(e); + environment.getErrorManager().handle(e); } } @@ -59,13 +55,13 @@ public class LispInterpreter { String result = environment.decorateValueOutput(String.valueOf(eval(sExpression))); erasePrompt(); - output.println(result); + environment.getOutput().println(result); } protected void erasePrompt() {} protected void printFarewell() { - output.println(); + environment.getOutput().println(); } } diff --git a/src/interpreter/LispInterpreterBuilderImpl.java b/src/interpreter/LispInterpreterBuilderImpl.java index 197f299..f2507dd 100644 --- a/src/interpreter/LispInterpreterBuilderImpl.java +++ b/src/interpreter/LispInterpreterBuilderImpl.java @@ -130,17 +130,29 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder { environment.setOutput(outputStream); environment.setErrorOutput(errorOutputStream); + environment.setErrorManager(errorManager); environment.setTerminationFunction(terminationFunction); environment.setErrorTerminationFunction(errorTerminationFunction); - environment.setErrorManager(errorManager); environment.setOutputDecorator(outputDecorator); environment.setValueOutputDecorator(valueOutputDecorator); environment.setWarningOutputDecorator(warningOutputDecorator); environment.setErrorOutputDecorator(errorOutputDecorator); environment.setCriticalOutputDecorator(criticalOutputDecorator); + configurePath(); configureInput(errorManager); } + private void configurePath() { + if (isFileBased) + environment.setPath(getPathPrefix(inputName)); + else + environment.setPath(""); + } + + private String getPathPrefix(String fileName) { + return fileName.substring(0, fileName.lastIndexOf(File.separator) + 1); + } + private void configureInput(ErrorManager errorManager) { environment.setInputName(inputName); diff --git a/test/environment/RuntimeEnvironmentTester.java b/test/environment/RuntimeEnvironmentTester.java index 1dbbe1a..7df140a 100644 --- a/test/environment/RuntimeEnvironmentTester.java +++ b/test/environment/RuntimeEnvironmentTester.java @@ -23,6 +23,12 @@ public class RuntimeEnvironmentTester { @Before public void setUp() { indicatorSet = new HashSet<>(); + environment.reset(); + } + + @After + public void tearDown() { + environment.reset(); } @Test @@ -53,6 +59,21 @@ public class RuntimeEnvironmentTester { assertEquals(System.err, environment.getErrorOutput()); } + @Test + public void assignErrorManager() { + ErrorManager errorManager = new ErrorManager(); + environment.setErrorManager(errorManager); + + assertEquals(errorManager, environment.getErrorManager()); + } + + @Test + public void assignPath() { + environment.setPath("testpath/"); + + assertEquals("testpath/", environment.getPath()); + } + @Test public void assignTerminationFunction() { environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED_SUCCESSFULLY)); @@ -69,14 +90,6 @@ public class RuntimeEnvironmentTester { assertTrue(indicatorSet.contains(TERMINATED_EXCEPTIONALLY)); } - @Test - public void assignErrorManager() { - ErrorManager errorManager = new ErrorManager(); - environment.setErrorManager(errorManager); - - assertEquals(errorManager, environment.getErrorManager()); - } - @Test public void assignOutputDecorator() { environment.setOutputDecorator(s -> "[" + s + "]"); @@ -112,4 +125,64 @@ public class RuntimeEnvironmentTester { assertEquals("/test/", environment.decorateCriticalOutput("test")); } + @Test + public void resetWorks() { + environment.setInputName("test"); + environment.setInput(System.in); + environment.setOutput(System.out); + environment.setErrorOutput(System.err); + environment.setErrorManager(new ErrorManager()); + environment.setPath("testpath/"); + environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED_SUCCESSFULLY)); + environment.setErrorTerminationFunction(() -> indicatorSet.add(TERMINATED_EXCEPTIONALLY)); + environment.setOutputDecorator(s -> "[" + s + "]"); + environment.setValueOutputDecorator(s -> "(" + s + ")"); + environment.setWarningOutputDecorator(s -> "|" + s + "|"); + environment.setErrorOutputDecorator(s -> "{" + s + "}"); + environment.setCriticalOutputDecorator(s -> "/" + s + "/"); + environment.reset(); + + assertNull(environment.getInputName()); + assertNull(environment.getInput()); + assertNull(environment.getOutput()); + assertNull(environment.getErrorOutput()); + assertNull(environment.getErrorManager()); + assertNull(environment.getPath()); + + try { + environment.terminateSuccessfully(); + fail("terminateSuccessfully"); + } catch (NullPointerException e) {} + + try { + environment.terminateExceptionally(); + fail("terminateExceptionally"); + } catch (NullPointerException e) {} + + try { + environment.decorateOutput(""); + fail("decorateOutput"); + } catch (NullPointerException e) {} + + try { + environment.decorateValueOutput(""); + fail("decorateValueOutput"); + } catch (NullPointerException e) {} + + try { + environment.decorateWarningOutput(""); + fail("decorateWarningOutput"); + } catch (NullPointerException e) {} + + try { + environment.decorateErrorOutput(""); + fail("decorateErrorOutput"); + } catch (NullPointerException e) {} + + try { + environment.decorateCriticalOutput(""); + fail("decorateCriticalOutput"); + } catch (NullPointerException e) {} + } + } diff --git a/test/error/ErrorManagerTester.java b/test/error/ErrorManagerTester.java index 5fa5519..62d3527 100644 --- a/test/error/ErrorManagerTester.java +++ b/test/error/ErrorManagerTester.java @@ -82,6 +82,12 @@ public class ErrorManagerTester { indicatorSet = new HashSet<>(); errorOutputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream(); + environment.reset(); + } + + @After + public void tearDown() { + environment.reset(); } @Test diff --git a/test/function/builtin/EXITTester.java b/test/function/builtin/EXITTester.java index 0c41e5d..140659d 100644 --- a/test/function/builtin/EXITTester.java +++ b/test/function/builtin/EXITTester.java @@ -13,8 +13,13 @@ import function.ArgumentValidator.TooManyArgumentsException; public class EXITTester { private static final String TERMINATED = "terminated"; + private RuntimeEnvironment environment; private Set indicatorSet; + public EXITTester() { + this.environment = RuntimeEnvironment.getInstance(); + } + private void assertTerminated() { assertTrue(indicatorSet.contains(TERMINATED)); } @@ -26,7 +31,13 @@ public class EXITTester { @Before public void setUp() { indicatorSet = new HashSet<>(); - RuntimeEnvironment.getInstance().setTerminationFunction(() -> indicatorSet.add(TERMINATED)); + environment.reset(); + environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED)); + } + + @After + public void tearDown() { + environment.reset(); } @Test diff --git a/test/function/builtin/LOADTester.java b/test/function/builtin/LOADTester.java index 483cb8e..b7a481b 100644 --- a/test/function/builtin/LOADTester.java +++ b/test/function/builtin/LOADTester.java @@ -42,14 +42,21 @@ public class LOADTester { outputStream = new ByteArrayOutputStream(); errorOutputStream = new ByteArrayOutputStream(); + environment.reset(); environment.setOutput(new PrintStream(outputStream)); environment.setErrorOutput(new PrintStream(errorOutputStream)); environment.setErrorManager(new ErrorManager()); + environment.setPath(""); environment.setOutputDecorator(s -> s); environment.setWarningOutputDecorator(s -> s); environment.setErrorOutputDecorator(s -> s); } + @After + public void tearDown() { + environment.reset(); + } + @Test public void loadGoodFile_ReturnsTAndPrintsNothing() { String input = "(load \"test/function/builtin/test-files/load-good.lisp\")"; @@ -105,4 +112,13 @@ public class LOADTester { evaluateString("(load)"); } + @Test + public void loadUsesRuntimePath() { + environment.setPath("test/function/builtin/test-files/nested/one/"); + String input = "(load \"load-one.lisp\")"; + + assertT(evaluateString(input)); + assertNothingPrinted(); + } + } diff --git a/test/function/builtin/PRINTTester.java b/test/function/builtin/PRINTTester.java index e802fcb..f5e2f24 100644 --- a/test/function/builtin/PRINTTester.java +++ b/test/function/builtin/PRINTTester.java @@ -13,8 +13,13 @@ import function.ArgumentValidator.*; public class PRINTTester { + private RuntimeEnvironment environment; private ByteArrayOutputStream outputStream; + public PRINTTester() { + this.environment = RuntimeEnvironment.getInstance(); + } + private void assertPrinted(String expected) { assertEquals(expected, outputStream.toString()); } @@ -22,7 +27,13 @@ public class PRINTTester { @Before public void setUp() { outputStream = new ByteArrayOutputStream(); - RuntimeEnvironment.getInstance().setOutput(new PrintStream(outputStream)); + environment.reset(); + environment.setOutput(new PrintStream(outputStream)); + } + + @After + public void tearDown() { + environment.reset(); } @Test diff --git a/test/function/builtin/special/DEFINE_MACROTester.java b/test/function/builtin/special/DEFINE_MACROTester.java index 82f5916..e8adb18 100644 --- a/test/function/builtin/special/DEFINE_MACROTester.java +++ b/test/function/builtin/special/DEFINE_MACROTester.java @@ -30,15 +30,16 @@ public class DEFINE_MACROTester { public void setUp() { outputStream = new ByteArrayOutputStream(); + environment.reset(); environment.setOutput(new PrintStream(outputStream)); environment.setErrorManager(new ErrorManager()); environment.setWarningOutputDecorator(s -> s); - resetFunctionTable(); } @After public void tearDown() { + environment.reset(); resetFunctionTable(); } diff --git a/test/function/builtin/special/DEFUNTester.java b/test/function/builtin/special/DEFUNTester.java index 5808f59..8423b2b 100644 --- a/test/function/builtin/special/DEFUNTester.java +++ b/test/function/builtin/special/DEFUNTester.java @@ -30,15 +30,16 @@ public class DEFUNTester { public void setUp() { outputStream = new ByteArrayOutputStream(); + environment.reset(); environment.setOutput(new PrintStream(outputStream)); environment.setErrorManager(new ErrorManager()); environment.setWarningOutputDecorator(s -> s); - resetFunctionTable(); } @After public void tearDown() { + environment.reset(); resetFunctionTable(); }