Added unit tests and refactored the load function
This commit is contained in:
parent
919644d9c0
commit
25f73e6d2e
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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