transcendental-lisp/src/main/java/interpreter/LispInterpreterBuilderImpl.java

218 lines
6.7 KiB
Java

package interpreter;
import environment.RuntimeEnvironment;
import error.CriticalLispException;
import error.ErrorManager;
import interpreter.LispInterpreter.LanguageFile;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
import static util.Path.getPathPrefix;
public class LispInterpreterBuilderImpl implements LispInterpreterBuilder {
private static LispInterpreterBuilder uniqueInstance = new LispInterpreterBuilderImpl();
public static LispInterpreterBuilder getInstance() {
return uniqueInstance;
}
private String inputName;
private InputStream inputStream;
private PrintStream outputStream;
private PrintStream errorOutputStream;
private Runnable terminationFunction;
private Runnable errorTerminationFunction;
private List<LanguageFile> languageFiles;
private Function<String, String> promptDecorator;
private Function<String, String> valueOutputDecorator;
private Function<String, String> warningOutputDecorator;
private Function<String, String> errorOutputDecorator;
private Function<String, String> criticalOutputDecorator;
private RuntimeEnvironment environment;
private boolean isInteractive;
private boolean isFileBased;
protected boolean isBuilt;
protected LispInterpreterBuilderImpl() {
this.environment = RuntimeEnvironment.getInstance();
this.inputName = "";
this.isInteractive = true;
this.isFileBased = false;
this.isBuilt = false;
this.languageFiles = new ArrayList<>();
this.promptDecorator = s -> s;
this.valueOutputDecorator = s -> s;
this.warningOutputDecorator = s -> s;
this.errorOutputDecorator = s -> s;
this.criticalOutputDecorator = s -> s;
}
@Override
public void setInput(InputStream inputStream, String inputName) {
this.inputStream = inputStream;
this.inputName = inputName;
}
@Override
public void setOutput(PrintStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void setErrorOutput(PrintStream errorOutputStream) {
this.errorOutputStream = errorOutputStream;
}
@Override
public void setTerminationFunction(Runnable terminationFunction) {
this.terminationFunction = terminationFunction;
}
@Override
public void setErrorTerminationFunction(Runnable errorTerminationFunction) {
this.errorTerminationFunction = errorTerminationFunction;
}
@Override
public void setNotInteractive() {
this.isInteractive = false;
}
@Override
public void useFile(String fileName) {
this.isFileBased = true;
this.inputName = fileName;
this.setNotInteractive();
}
@Override
public void setLanguageFileNames(String... languageFileNames) {
ClassLoader classLoader = getClass().getClassLoader();
languageFiles = new ArrayList<>();
for (String fileName : languageFileNames)
languageFiles.add(new LanguageFile(classLoader.getResourceAsStream(fileName), fileName));
}
@Override
public void setPromptDecorator(Function<String, String> decorator) {
this.promptDecorator = decorator;
}
@Override
public void setValueOutputDecorator(Function<String, String> decorator) {
this.valueOutputDecorator = decorator;
}
@Override
public void setWarningOutputDecorator(Function<String, String> decorator) {
this.warningOutputDecorator = decorator;
}
@Override
public void setErrorOutputDecorator(Function<String, String> decorator) {
this.errorOutputDecorator = decorator;
}
@Override
public void setCriticalOutputDecorator(Function<String, String> decorator) {
this.criticalOutputDecorator = decorator;
}
@Override
public LispInterpreter build() {
if (!isBuilt)
return buildInterpreter();
else
throw new InterpreterAlreadyBuiltException();
}
private LispInterpreter buildInterpreter() {
configureRuntimeEnvironment();
LispInterpreter lispInterpreter = createInterpreter();
lispInterpreter.interpretLanguageFiles(languageFiles);
isBuilt = true;
return lispInterpreter;
}
private void configureRuntimeEnvironment() {
ErrorManager errorManager = new ErrorManager();
environment.setOutput(outputStream);
environment.setErrorOutput(errorOutputStream);
environment.setErrorManager(errorManager);
environment.setTerminationFunction(terminationFunction);
environment.setErrorTerminationFunction(errorTerminationFunction);
environment.setPromptDecorator(promptDecorator);
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 void configureInput(ErrorManager errorManager) {
environment.setInputName(inputName);
try {
environment.setInput(getInputStream());
} catch (FileNotFoundException e) {
errorManager.handle(new LispFileNotFoundException(e));
}
}
private InputStream getInputStream() throws FileNotFoundException {
return isFileBased ? new FileInputStream(inputName) : inputStream;
}
private LispInterpreter createInterpreter() {
if (isFileBased)
return new FileLispInterpreter();
else if (isInteractive)
return new InteractiveLispInterpreter();
return new LispInterpreter();
}
public static class InterpreterAlreadyBuiltException extends CriticalLispException {
private static final long serialVersionUID = 1L;
@Override
public String getMessage() {
return "Refusing to build more than one interpreter.";
}
}
public static class LispFileNotFoundException extends CriticalLispException {
private static final long serialVersionUID = 1L;
private String message;
public LispFileNotFoundException(FileNotFoundException e) {
this.message = e.getMessage();
}
@Override
public String getMessage() {
return message;
}
}
}