package function.builtin; import static function.builtin.EVAL.eval; import static sexpression.Nil.NIL; import static sexpression.Symbol.T; import java.io.*; import java.text.MessageFormat; import java.util.Stack; import environment.RuntimeEnvironment; import error.*; import function.*; import parser.LispParser; import sexpression.*; @FunctionNames({ "LOAD" }) public class LOAD extends LispFunction { private ArgumentValidator argumentValidator; private ErrorManager errorManager; 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.pathPrefixes = new Stack<>(); } 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) { return pathPrefixes.empty() ? fileName : pathPrefixes.peek() + fileName; } private LispParser attemptToCreateParserOnFile(String fileName) { LispParser parser = null; try { parser = new LispParser(new FileInputStream(fileName), fileName); } catch (FileNotFoundException e) { errorManager.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 String getPathPrefix(String fileName) { return fileName.substring(0, fileName.lastIndexOf(File.separator) + 1); } private boolean isSuccessfulEvaluation(LispParser parser) { while (!parser.isEof()) { try { eval(parser.getNextSExpression()); } catch (LispException e) { errorManager.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 MessageFormat.format("could not load ''{0}''", fileName); } } }