package function.builtin; import environment.RuntimeEnvironment; import error.LispException; import error.LispWarning; import function.ArgumentValidator; import function.FunctionNames; import function.LispFunction; import parser.LispParser; import sexpression.Cons; import sexpression.LispString; import sexpression.SExpression; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.util.Stack; import static function.builtin.EVAL.eval; import static java.text.MessageFormat.format; import static sexpression.Nil.NIL; import static sexpression.Symbol.T; import static util.Path.getPathPrefix; @FunctionNames({ "LOAD" }) public class LOAD extends LispFunction { private static Stack pathPrefixes = new Stack<>(); private ArgumentValidator argumentValidator; private RuntimeEnvironment environment; public LOAD(String name) { this.argumentValidator = new ArgumentValidator(name); this.argumentValidator.setExactNumberOfArguments(1); this.argumentValidator.setEveryArgumentExpectedType(LispString.class); this.environment = RuntimeEnvironment.getInstance(); } @Override public SExpression call(Cons argumentList) { argumentValidator.validate(argumentList); LispString quotedName = (LispString) argumentList.getFirst(); String fileName = removeSurroundingQuotes(quotedName.toString()); return processFile(fileName); } private String removeSurroundingQuotes(String fileName) { return fileName.substring(1, (fileName.length() - 1)); } private SExpression processFile(String fileName) { boolean isSuccessful = false; String prefixedFileName = prefixFileNameIfNecessary(fileName); LispParser parser = attemptToCreateParserOnFile(prefixedFileName); if (parser != null) isSuccessful = isSuccessfulEvaluationWithPathPrefix(prefixedFileName, parser); return isSuccessful ? T : NIL; } private String prefixFileNameIfNecessary(String fileName) { if (pathPrefixes.isEmpty()) return environment.getPath() + fileName; return pathPrefixes.peek() + fileName; } private LispParser attemptToCreateParserOnFile(String fileName) { LispParser parser = null; try { parser = new LispParser(new FileInputStream(fileName), fileName); } catch (FileNotFoundException e) { environment.getErrorManager().handle(new CouldNotLoadFileWarning(fileName)); } return parser; } private boolean isSuccessfulEvaluationWithPathPrefix(String prefixedFileName, LispParser parser) { pathPrefixes.push(getPathPrefix(prefixedFileName)); boolean isSuccessful = isSuccessfulEvaluation(parser); pathPrefixes.pop(); return isSuccessful; } private boolean isSuccessfulEvaluation(LispParser parser) { while (!parser.isEof()) { try { eval(parser.getNextSExpression()); } catch (LispException e) { environment.getErrorManager().handle(e); return false; } } return true; } public static class CouldNotLoadFileWarning extends LispWarning { private static final long serialVersionUID = 1L; private String fileName; public CouldNotLoadFileWarning(String fileName) { this.fileName = fileName; } @Override public String getMessage() { return format("could not load ''{0}''", fileName); } } }