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
This commit is contained in:
Mike Cifelli 2017-03-05 10:20:31 -05:00
parent c20bb682f2
commit 04cb46e94d
13 changed files with 206 additions and 50 deletions

View File

@ -17,17 +17,35 @@ public class RuntimeEnvironment {
private InputStream input; private InputStream input;
private PrintStream output; private PrintStream output;
private PrintStream errorOutput; private PrintStream errorOutput;
private ErrorManager errorManager;
private String path;
private Runnable terminationFunction;
private Runnable errorTerminationFunction;
private Function<String, String> outputDecorator; private Function<String, String> outputDecorator;
private Function<String, String> valueOutputDecorator; private Function<String, String> valueOutputDecorator;
private Function<String, String> warningOutputDecorator; private Function<String, String> warningOutputDecorator;
private Function<String, String> errorOutputDecorator; private Function<String, String> errorOutputDecorator;
private Function<String, String> criticalOutputDecorator; private Function<String, String> 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) { public void setInputName(String inputName) {
this.inputName = inputName; this.inputName = inputName;
@ -45,6 +63,14 @@ public class RuntimeEnvironment {
this.errorOutput = errorOutput; this.errorOutput = errorOutput;
} }
public void setErrorManager(ErrorManager errorManager) {
this.errorManager = errorManager;
}
public void setPath(String path) {
this.path = path;
}
public void setTerminationFunction(Runnable terminationFunction) { public void setTerminationFunction(Runnable terminationFunction) {
this.terminationFunction = terminationFunction; this.terminationFunction = terminationFunction;
} }
@ -53,10 +79,6 @@ public class RuntimeEnvironment {
this.errorTerminationFunction = errorTerminationFunction; this.errorTerminationFunction = errorTerminationFunction;
} }
public void setErrorManager(ErrorManager errorManager) {
this.errorManager = errorManager;
}
public void setOutputDecorator(Function<String, String> outputDecorator) { public void setOutputDecorator(Function<String, String> outputDecorator) {
this.outputDecorator = outputDecorator; this.outputDecorator = outputDecorator;
} }
@ -93,6 +115,14 @@ public class RuntimeEnvironment {
return errorOutput; return errorOutput;
} }
public ErrorManager getErrorManager() {
return errorManager;
}
public String getPath() {
return path;
}
public void terminateSuccessfully() { public void terminateSuccessfully() {
terminationFunction.run(); terminationFunction.run();
} }
@ -101,10 +131,6 @@ public class RuntimeEnvironment {
errorTerminationFunction.run(); errorTerminationFunction.run();
} }
public ErrorManager getErrorManager() {
return errorManager;
}
public String decorateOutput(String output) { public String decorateOutput(String output) {
return outputDecorator.apply(output); return outputDecorator.apply(output);
} }

View File

@ -18,14 +18,14 @@ import sexpression.*;
public class LOAD extends LispFunction { public class LOAD extends LispFunction {
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private ErrorManager errorManager; private RuntimeEnvironment environment;
private Stack<String> pathPrefixes; private Stack<String> pathPrefixes;
public LOAD() { public LOAD() {
this.argumentValidator = new ArgumentValidator("LOAD"); this.argumentValidator = new ArgumentValidator("LOAD");
this.argumentValidator.setExactNumberOfArguments(1); this.argumentValidator.setExactNumberOfArguments(1);
this.argumentValidator.setEveryArgumentExpectedType(LispString.class); this.argumentValidator.setEveryArgumentExpectedType(LispString.class);
this.errorManager = RuntimeEnvironment.getInstance().getErrorManager(); this.environment = RuntimeEnvironment.getInstance();
this.pathPrefixes = new Stack<>(); this.pathPrefixes = new Stack<>();
} }
@ -54,7 +54,10 @@ public class LOAD extends LispFunction {
} }
private String prefixFileNameIfNecessary(String fileName) { 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) { private LispParser attemptToCreateParserOnFile(String fileName) {
@ -63,7 +66,7 @@ public class LOAD extends LispFunction {
try { try {
parser = new LispParser(new FileInputStream(fileName), fileName); parser = new LispParser(new FileInputStream(fileName), fileName);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
errorManager.handle(new CouldNotLoadFileWarning(fileName)); this.environment.getErrorManager().handle(new CouldNotLoadFileWarning(fileName));
} }
return parser; return parser;
@ -86,7 +89,7 @@ public class LOAD extends LispFunction {
try { try {
eval(parser.getNextSExpression()); eval(parser.getNextSExpression());
} catch (LispException e) { } catch (LispException e) {
errorManager.handle(e); this.environment.getErrorManager().handle(e);
return false; return false;
} }
} }

View File

@ -6,7 +6,7 @@ import static table.FunctionTable.*;
import java.text.MessageFormat; import java.text.MessageFormat;
import environment.RuntimeEnvironment; import environment.RuntimeEnvironment;
import error.*; import error.LispWarning;
import function.*; import function.*;
import sexpression.*; import sexpression.*;
@ -15,7 +15,7 @@ public abstract class Define extends LispSpecialFunction {
private ArgumentValidator argumentValidator; private ArgumentValidator argumentValidator;
private ArgumentValidator lambdaListIsListValidator; private ArgumentValidator lambdaListIsListValidator;
private ArgumentValidator lambdaListValidator; private ArgumentValidator lambdaListValidator;
private ErrorManager errorManager; private RuntimeEnvironment environment;
public Define(String functionName) { public Define(String functionName) {
this.argumentValidator = new ArgumentValidator(functionName); this.argumentValidator = new ArgumentValidator(functionName);
@ -28,7 +28,7 @@ public abstract class Define extends LispSpecialFunction {
this.lambdaListValidator = new ArgumentValidator(functionName + "|parameter|"); this.lambdaListValidator = new ArgumentValidator(functionName + "|parameter|");
this.lambdaListValidator.setEveryArgumentExpectedType(Symbol.class); this.lambdaListValidator.setEveryArgumentExpectedType(Symbol.class);
this.errorManager = RuntimeEnvironment.getInstance().getErrorManager(); this.environment = RuntimeEnvironment.getInstance();
} }
public SExpression call(Cons argumentList) { public SExpression call(Cons argumentList) {
@ -46,7 +46,7 @@ public abstract class Define extends LispSpecialFunction {
UserDefinedFunction function = createFunction(functionName, lambdaList, functionBody); UserDefinedFunction function = createFunction(functionName, lambdaList, functionBody);
if (isAlreadyDefined(functionName.toString())) if (isAlreadyDefined(functionName.toString()))
errorManager.handle(new RedefiningFunctionWarning(functionName.toString())); environment.getErrorManager().handle(new RedefiningFunctionWarning(functionName.toString()));
defineFunction(functionName.toString(), function); defineFunction(functionName.toString(), function);

View File

@ -7,26 +7,26 @@ public class InteractiveLispInterpreter extends LispInterpreter {
@Override @Override
protected void printGreeting() { protected void printGreeting() {
output.println(GREETING); environment.getOutput().println(GREETING);
output.println(); environment.getOutput().println();
} }
@Override @Override
protected void displayPrompt() { protected void displayPrompt() {
output.print(PROMPT); environment.getOutput().print(PROMPT);
} }
@Override @Override
protected void erasePrompt() { protected void erasePrompt() {
for (int i = 0; i < PROMPT.length(); i++) { for (int i = 0; i < PROMPT.length(); i++) {
output.print("\b"); environment.getOutput().print("\b");
} }
} }
@Override @Override
protected void printFarewell() { protected void printFarewell() {
output.println(); environment.getOutput().println();
output.println(); environment.getOutput().println();
} }
} }

View File

@ -2,24 +2,20 @@ package interpreter;
import static function.builtin.EVAL.eval; import static function.builtin.EVAL.eval;
import java.io.*; import java.io.InputStream;
import environment.RuntimeEnvironment; import environment.RuntimeEnvironment;
import error.*; import error.LispException;
import parser.LispParser; import parser.LispParser;
import sexpression.SExpression; import sexpression.SExpression;
public class LispInterpreter { public class LispInterpreter {
protected RuntimeEnvironment environment; protected RuntimeEnvironment environment;
protected ErrorManager errorManager;
protected PrintStream output;
private LispParser parser; private LispParser parser;
public LispInterpreter() { public LispInterpreter() {
this.environment = RuntimeEnvironment.getInstance(); this.environment = RuntimeEnvironment.getInstance();
this.errorManager = this.environment.getErrorManager();
this.output = environment.getOutput();
} }
public void setInput(InputStream input, String inputName) { public void setInput(InputStream input, String inputName) {
@ -50,7 +46,7 @@ public class LispInterpreter {
printValueOfNextSExpressionWithException(); printValueOfNextSExpressionWithException();
} catch (LispException e) { } catch (LispException e) {
erasePrompt(); erasePrompt();
errorManager.handle(e); environment.getErrorManager().handle(e);
} }
} }
@ -59,13 +55,13 @@ public class LispInterpreter {
String result = environment.decorateValueOutput(String.valueOf(eval(sExpression))); String result = environment.decorateValueOutput(String.valueOf(eval(sExpression)));
erasePrompt(); erasePrompt();
output.println(result); environment.getOutput().println(result);
} }
protected void erasePrompt() {} protected void erasePrompt() {}
protected void printFarewell() { protected void printFarewell() {
output.println(); environment.getOutput().println();
} }
} }

View File

@ -130,17 +130,29 @@ public class LispInterpreterBuilderImpl implements LispInterpreterBuilder {
environment.setOutput(outputStream); environment.setOutput(outputStream);
environment.setErrorOutput(errorOutputStream); environment.setErrorOutput(errorOutputStream);
environment.setErrorManager(errorManager);
environment.setTerminationFunction(terminationFunction); environment.setTerminationFunction(terminationFunction);
environment.setErrorTerminationFunction(errorTerminationFunction); environment.setErrorTerminationFunction(errorTerminationFunction);
environment.setErrorManager(errorManager);
environment.setOutputDecorator(outputDecorator); environment.setOutputDecorator(outputDecorator);
environment.setValueOutputDecorator(valueOutputDecorator); environment.setValueOutputDecorator(valueOutputDecorator);
environment.setWarningOutputDecorator(warningOutputDecorator); environment.setWarningOutputDecorator(warningOutputDecorator);
environment.setErrorOutputDecorator(errorOutputDecorator); environment.setErrorOutputDecorator(errorOutputDecorator);
environment.setCriticalOutputDecorator(criticalOutputDecorator); environment.setCriticalOutputDecorator(criticalOutputDecorator);
configurePath();
configureInput(errorManager); 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) { private void configureInput(ErrorManager errorManager) {
environment.setInputName(inputName); environment.setInputName(inputName);

View File

@ -23,6 +23,12 @@ public class RuntimeEnvironmentTester {
@Before @Before
public void setUp() { public void setUp() {
indicatorSet = new HashSet<>(); indicatorSet = new HashSet<>();
environment.reset();
}
@After
public void tearDown() {
environment.reset();
} }
@Test @Test
@ -53,6 +59,21 @@ public class RuntimeEnvironmentTester {
assertEquals(System.err, environment.getErrorOutput()); 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 @Test
public void assignTerminationFunction() { public void assignTerminationFunction() {
environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED_SUCCESSFULLY)); environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED_SUCCESSFULLY));
@ -69,14 +90,6 @@ public class RuntimeEnvironmentTester {
assertTrue(indicatorSet.contains(TERMINATED_EXCEPTIONALLY)); assertTrue(indicatorSet.contains(TERMINATED_EXCEPTIONALLY));
} }
@Test
public void assignErrorManager() {
ErrorManager errorManager = new ErrorManager();
environment.setErrorManager(errorManager);
assertEquals(errorManager, environment.getErrorManager());
}
@Test @Test
public void assignOutputDecorator() { public void assignOutputDecorator() {
environment.setOutputDecorator(s -> "[" + s + "]"); environment.setOutputDecorator(s -> "[" + s + "]");
@ -112,4 +125,64 @@ public class RuntimeEnvironmentTester {
assertEquals("/test/", environment.decorateCriticalOutput("test")); 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) {}
}
} }

View File

@ -82,6 +82,12 @@ public class ErrorManagerTester {
indicatorSet = new HashSet<>(); indicatorSet = new HashSet<>();
errorOutputStream = new ByteArrayOutputStream(); errorOutputStream = new ByteArrayOutputStream();
outputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream();
environment.reset();
}
@After
public void tearDown() {
environment.reset();
} }
@Test @Test

View File

@ -13,8 +13,13 @@ import function.ArgumentValidator.TooManyArgumentsException;
public class EXITTester { public class EXITTester {
private static final String TERMINATED = "terminated"; private static final String TERMINATED = "terminated";
private RuntimeEnvironment environment;
private Set<String> indicatorSet; private Set<String> indicatorSet;
public EXITTester() {
this.environment = RuntimeEnvironment.getInstance();
}
private void assertTerminated() { private void assertTerminated() {
assertTrue(indicatorSet.contains(TERMINATED)); assertTrue(indicatorSet.contains(TERMINATED));
} }
@ -26,7 +31,13 @@ public class EXITTester {
@Before @Before
public void setUp() { public void setUp() {
indicatorSet = new HashSet<>(); indicatorSet = new HashSet<>();
RuntimeEnvironment.getInstance().setTerminationFunction(() -> indicatorSet.add(TERMINATED)); environment.reset();
environment.setTerminationFunction(() -> indicatorSet.add(TERMINATED));
}
@After
public void tearDown() {
environment.reset();
} }
@Test @Test

View File

@ -42,14 +42,21 @@ public class LOADTester {
outputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream();
errorOutputStream = new ByteArrayOutputStream(); errorOutputStream = new ByteArrayOutputStream();
environment.reset();
environment.setOutput(new PrintStream(outputStream)); environment.setOutput(new PrintStream(outputStream));
environment.setErrorOutput(new PrintStream(errorOutputStream)); environment.setErrorOutput(new PrintStream(errorOutputStream));
environment.setErrorManager(new ErrorManager()); environment.setErrorManager(new ErrorManager());
environment.setPath("");
environment.setOutputDecorator(s -> s); environment.setOutputDecorator(s -> s);
environment.setWarningOutputDecorator(s -> s); environment.setWarningOutputDecorator(s -> s);
environment.setErrorOutputDecorator(s -> s); environment.setErrorOutputDecorator(s -> s);
} }
@After
public void tearDown() {
environment.reset();
}
@Test @Test
public void loadGoodFile_ReturnsTAndPrintsNothing() { public void loadGoodFile_ReturnsTAndPrintsNothing() {
String input = "(load \"test/function/builtin/test-files/load-good.lisp\")"; String input = "(load \"test/function/builtin/test-files/load-good.lisp\")";
@ -105,4 +112,13 @@ public class LOADTester {
evaluateString("(load)"); 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();
}
} }

View File

@ -13,8 +13,13 @@ import function.ArgumentValidator.*;
public class PRINTTester { public class PRINTTester {
private RuntimeEnvironment environment;
private ByteArrayOutputStream outputStream; private ByteArrayOutputStream outputStream;
public PRINTTester() {
this.environment = RuntimeEnvironment.getInstance();
}
private void assertPrinted(String expected) { private void assertPrinted(String expected) {
assertEquals(expected, outputStream.toString()); assertEquals(expected, outputStream.toString());
} }
@ -22,7 +27,13 @@ public class PRINTTester {
@Before @Before
public void setUp() { public void setUp() {
outputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream();
RuntimeEnvironment.getInstance().setOutput(new PrintStream(outputStream)); environment.reset();
environment.setOutput(new PrintStream(outputStream));
}
@After
public void tearDown() {
environment.reset();
} }
@Test @Test

View File

@ -30,15 +30,16 @@ public class DEFINE_MACROTester {
public void setUp() { public void setUp() {
outputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream();
environment.reset();
environment.setOutput(new PrintStream(outputStream)); environment.setOutput(new PrintStream(outputStream));
environment.setErrorManager(new ErrorManager()); environment.setErrorManager(new ErrorManager());
environment.setWarningOutputDecorator(s -> s); environment.setWarningOutputDecorator(s -> s);
resetFunctionTable(); resetFunctionTable();
} }
@After @After
public void tearDown() { public void tearDown() {
environment.reset();
resetFunctionTable(); resetFunctionTable();
} }

View File

@ -30,15 +30,16 @@ public class DEFUNTester {
public void setUp() { public void setUp() {
outputStream = new ByteArrayOutputStream(); outputStream = new ByteArrayOutputStream();
environment.reset();
environment.setOutput(new PrintStream(outputStream)); environment.setOutput(new PrintStream(outputStream));
environment.setErrorManager(new ErrorManager()); environment.setErrorManager(new ErrorManager());
environment.setWarningOutputDecorator(s -> s); environment.setWarningOutputDecorator(s -> s);
resetFunctionTable(); resetFunctionTable();
} }
@After @After
public void tearDown() { public void tearDown() {
environment.reset();
resetFunctionTable(); resetFunctionTable();
} }