Added unit tests and refactored the load function
This commit is contained in:
parent
919644d9c0
commit
25f73e6d2e
|
@ -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;
|
||||
|
||||
throw new RuntimeException(errMsg);
|
||||
public LOAD() {
|
||||
this.argumentValidator = new ArgumentValidator("LOAD");
|
||||
this.argumentValidator.setExactNumberOfArguments(1);
|
||||
this.argumentValidator.setEveryArgumentExpectedType(LispString.class);
|
||||
this.environment = Environment.getInstance();
|
||||
}
|
||||
|
||||
SExpression argCar = argList.getCar();
|
||||
public SExpression call(Cons argumentList) {
|
||||
argumentValidator.validate(argumentList);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)");
|
||||
}
|
||||
|
||||
}
|
|
@ -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)))
|
||||
)
|
||||
)
|
||||
|
|
@ -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)))
|
||||
)
|
||||
)
|
||||
|
Loading…
Reference in New Issue