Added unit tests and refactored the load function

This commit is contained in:
Mike Cifelli 2017-01-26 15:58:15 -05:00
parent 919644d9c0
commit 25f73e6d2e
5 changed files with 218 additions and 55 deletions

View File

@ -1,82 +1,84 @@
package function.builtin; package function.builtin;
import java.io.FileInputStream; import java.io.*;
import java.io.FileNotFoundException; import java.text.MessageFormat;
import function.LispFunction; import environment.Environment;
import function.builtin.cons.LENGTH; import function.*;
import parser.LispParser; import parser.LispParser;
import sexpression.*; import sexpression.*;
/**
* <code>LOAD</code> represents the LOAD function in Lisp.
*/
public class LOAD extends LispFunction { public class LOAD extends LispFunction {
// The number of arguments that LOAD takes.
private static final int NUM_ARGS = 1;
public SExpression call(Cons argList) { private ArgumentValidator argumentValidator;
// retrieve the number of arguments passed to LOAD private Environment environment;
int argListLength = LENGTH.getLength(argList);
// make sure we have received the proper number of arguments public LOAD() {
if (argListLength != NUM_ARGS) { this.argumentValidator = new ArgumentValidator("LOAD");
Cons originalSExpr = new Cons(new Symbol("LOAD"), argList); this.argumentValidator.setExactNumberOfArguments(1);
String errMsg = "too " + this.argumentValidator.setEveryArgumentExpectedType(LispString.class);
((argListLength > NUM_ARGS) ? "many" : "few") + this.environment = Environment.getInstance();
" arguments given to LOAD: " + originalSExpr;
throw new RuntimeException(errMsg);
} }
SExpression argCar = argList.getCar(); public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
// make sure the argument is a string LispString quotedName = (LispString) argumentList.getCar();
if (! argCar.stringp()) { String fileName = removeSurroundingQuotes(quotedName.toString());
throw new RuntimeException("LOAD: " + argCar + " is not a string");
}
LispString quotedName = (LispString) argCar;
String fileName = quotedName.toString();
// remove the surrounding quotes from the file name
fileName = fileName.substring(1, (fileName.length() - 1));
return processFile(fileName); return processFile(fileName);
} }
// Evaluate all the S-expressions found in the file with the specified private String removeSurroundingQuotes(String fileName) {
// name. return fileName.substring(1, (fileName.length() - 1));
// }
// Parameters: fileName - the name of the file to be evaluated
// Returns: 'T' if the file was processed successfully; 'NIL' otherwise
private SExpression processFile(String fileName) { private SExpression processFile(String fileName) {
boolean wasSuccessful = false;
LispParser parser = attemptToCreateParserOnFile(fileName);
if (parser != null)
wasSuccessful = isSuccessfulEvaluation(parser);
return wasSuccessful ? Symbol.T : Nil.getInstance();
}
private LispParser attemptToCreateParserOnFile(String fileName) {
LispParser parser = null; LispParser parser = null;
// attempt to create a new 'LispParser' on the specified file
try { try {
parser = new LispParser(new FileInputStream(fileName), fileName); parser = new LispParser(new FileInputStream(fileName), fileName);
} catch (FileNotFoundException e) { } catch (FileNotFoundException e) {
System.out.println("LOAD: could not open " + fileName); printCouldNotOpenFileMessage(fileName);
return Nil.getInstance();
} }
// attempt to evaluate all the S-expressions contained in the file return parser;
}
private boolean isSuccessfulEvaluation(LispParser parser) {
while (!parser.isEof()) { while (!parser.isEof()) {
try { try {
SExpression sexpr = parser.getNextSExpression(); SExpression sexpr = parser.getNextSExpression();
EVAL.eval(sexpr); EVAL.eval(sexpr);
} catch (RuntimeException e) { } catch (RuntimeException e) {
System.out.println("LOAD: " + e.getMessage()); printErrorMessage(e.getMessage());
return Nil.getInstance(); return false;
} }
} }
// success! return true;
return Symbol.T; }
private void printCouldNotOpenFileMessage(String fileName) {
String message = MessageFormat.format("could not open ''{0}''", fileName);
printErrorMessage(message);
}
private void printErrorMessage(String errorMessage) {
String message = MessageFormat.format("LOAD: {0}", errorMessage);
environment.getErrorOutput().println(message);
} }
} }

View File

@ -5,9 +5,6 @@ import function.builtin.EVAL;
import sexpression.*; import sexpression.*;
import table.SymbolTable; import table.SymbolTable;
/**
* <code>LET</code> represents the LET form in Lisp.
*/
public class LET extends LispFunction { public class LET extends LispFunction {
public SExpression call(Cons argList) { public SExpression call(Cons argList) {
@ -93,11 +90,6 @@ public class LET extends LispFunction {
} }
} }
/**
* Determine if the arguments passed to this Lisp function should be evaluated.
*
* @return <code>false</code>
*/
public boolean evaluateArguments() { public boolean evaluateArguments() {
return false; return false;
} }

View File

@ -0,0 +1,69 @@
package function.builtin;
import static org.junit.Assert.assertEquals;
import static testutil.TestUtilities.*;
import java.io.*;
import org.junit.*;
import environment.Environment;
import function.ArgumentValidator.*;
public class LOADTester {
private ByteArrayOutputStream outputStream;
private void assertPrinted(String expected) {
assertEquals(expected, outputStream.toString());
}
private void assertNothingPrinted() {
assertPrinted("");
}
@Before
public void setUp() {
this.outputStream = new ByteArrayOutputStream();
Environment.getInstance().setErrorOutput(new PrintStream(outputStream));
}
@Test
public void loadGoodFile_ReturnsTAndPrintsNothing() {
String input = "(load \"test/function/builtin/test-files/load-good.lisp\")";
assertSExpressionsMatch(parseString("T"), evaluateString(input));
assertNothingPrinted();
}
@Test
public void loadBadFile_ReturnsNilAndPrintsError() {
String input = "(load \"test/function/builtin/test-files/load-bad.lisp\")";
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
assertPrinted("LOAD: expression begins with ')' - line 1, column 1\n");
}
@Test
public void loadNonExistentFile_ReturnsNilAndPrintsError() {
String input = "(load \"doesNotExist.lisp\")";
assertSExpressionsMatch(parseString("nil"), evaluateString(input));
assertPrinted("LOAD: could not open 'doesNotExist.lisp'\n");
}
@Test(expected = BadArgumentTypeException.class)
public void testLoadWithBadArgumentType() {
evaluateString("(load '1)");
}
@Test(expected = TooManyArgumentsException.class)
public void testLoadWithTooManyArguments() {
evaluateString("(load \"1\" \"2\")");
}
@Test(expected = TooFewArgumentsException.class)
public void testLoadWithTooFewArguments() {
evaluateString("(load)");
}
}

View File

@ -0,0 +1,50 @@
)(defun extend-null (the-list)
(cond
((equal (length the-list) 0) t)
(t nil)
)
)
(defun mapcar (function-name the-list)
(cond
((null the-list) nil)
(t (cons (funcall function-name (first the-list))
(mapcar function-name (rest the-list))))
)
)
(defun maplist (function-name the-list)
(cond
((null the-list) nil)
(t (cons (funcall function-name the-list)
(maplist function-name (rest the-list))))
)
)
(defun extend-apply (function-name param-list)
(eval (cons function-name param-list)))
(defun append (listA listB)
(cond
((null listA) listB)
(t (cons (first listA) (append (rest listA) listB)))
)
)
(defun second (listA) (first (rest listA)))
(defun third (listA) (first (rest (rest listA))))
(defun fourth (listA) (first (rest (rest (rest listA)))))
(defun fifth (listA) (first (rest (rest (rest (rest listA))))))
(defun sixth (listA) (first (rest (rest (rest (rest (rest listA)))))))
(defun seventh (listA) (first (rest (rest (rest (rest (rest (rest listA))))))))
(defun eighth (listA) (first (rest (rest (rest (rest (rest (rest (rest listA)))))))))
(defun ninth (listA) (first (rest (rest (rest (rest (rest (rest (rest (rest listA))))))))))
(defun tenth (listA) (first (rest (rest (rest (rest (rest (rest (rest (rest (rest listA)))))))))))
(defun nth (n listA)
(cond
((equal 0 n) (first listA))
(t (nth (- n 1) (rest listA)))
)
)

View File

@ -0,0 +1,50 @@
(defun extend-null (the-list)
(cond
((equal (length the-list) 0) t)
(t nil)
)
)
(defun mapcar (function-name the-list)
(cond
((null the-list) nil)
(t (cons (funcall function-name (first the-list))
(mapcar function-name (rest the-list))))
)
)
(defun maplist (function-name the-list)
(cond
((null the-list) nil)
(t (cons (funcall function-name the-list)
(maplist function-name (rest the-list))))
)
)
(defun extend-apply (function-name param-list)
(eval (cons function-name param-list)))
(defun append (listA listB)
(cond
((null listA) listB)
(t (cons (first listA) (append (rest listA) listB)))
)
)
(defun second (listA) (first (rest listA)))
(defun third (listA) (first (rest (rest listA))))
(defun fourth (listA) (first (rest (rest (rest listA)))))
(defun fifth (listA) (first (rest (rest (rest (rest listA))))))
(defun sixth (listA) (first (rest (rest (rest (rest (rest listA)))))))
(defun seventh (listA) (first (rest (rest (rest (rest (rest (rest listA))))))))
(defun eighth (listA) (first (rest (rest (rest (rest (rest (rest (rest listA)))))))))
(defun ninth (listA) (first (rest (rest (rest (rest (rest (rest (rest (rest listA))))))))))
(defun tenth (listA) (first (rest (rest (rest (rest (rest (rest (rest (rest (rest listA)))))))))))
(defun nth (n listA)
(cond
((equal 0 n) (first listA))
(t (nth (- n 1) (rest listA)))
)
)