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