Resolves #1 - Added the IF Special Form

This commit is contained in:
Mike Cifelli 2017-02-21 12:35:47 -05:00
parent 35550c46ac
commit 0c3d3ae024
4 changed files with 151 additions and 0 deletions

View File

@ -0,0 +1,52 @@
package function.builtin.special;
import static function.builtin.EVAL.eval;
import function.*;
import sexpression.*;
public class IF extends LispFunction {
private ArgumentValidator argumentValidator;
public IF() {
this.argumentValidator = new ArgumentValidator("IF");
this.argumentValidator.setMinimumNumberOfArguments(2);
this.argumentValidator.setMaximumNumberOfArguments(3);
}
public SExpression call(Cons argumentList) {
argumentValidator.validate(argumentList);
SExpression test = eval(argumentList.getCar());
SExpression thenForm = getThenForm(argumentList);
SExpression elseForm = getElseForm(argumentList);
return isNil(test) ? eval(elseForm) : eval(thenForm);
}
private boolean isNil(SExpression test) {
return test.nullp();
}
private SExpression getThenForm(Cons argumentList) {
Cons expressions = getRestOfList(argumentList);
return expressions.getCar();
}
private Cons getRestOfList(Cons argumentList) {
return (Cons) argumentList.getCdr();
}
private SExpression getElseForm(Cons argumentList) {
Cons expressions = getRestOfList(argumentList);
return getRestOfList(expressions).getCar();
}
public boolean evaluateArguments() {
return false;
}
}

View File

@ -60,6 +60,7 @@ public class FunctionTable {
functionTable.put("FIRST", new CAR());
functionTable.put("FUNCALL", new FUNCALL());
functionTable.put("GREATERP", new GREATERP());
functionTable.put("IF", new IF());
functionTable.put("LAMBDA", new LAMBDA());
functionTable.put("LENGTH", new LENGTH());
functionTable.put("LET", new LET());

View File

@ -22,6 +22,13 @@ public class CONDTester {
assertSExpressionsMatch(parseString("T"), evaluateString(input));
}
@Test
public void testCondWithNumber() {
String input = "(cond ((+ 1 2)))";
assertSExpressionsMatch(parseString("3"), evaluateString(input));
}
@Test
public void testCondWithSingleExpression() {
String input = "(cond (T \"true\"))";

View File

@ -0,0 +1,91 @@
package function.builtin.special;
import static testutil.TestUtilities.evaluateString;
import static testutil.TypeAssertions.*;
import org.junit.*;
import function.ArgumentValidator.*;
import function.builtin.EVAL.UndefinedSymbolException;
import table.ExecutionContext;
public class IFTester {
private ExecutionContext executionContext;
public IFTester() {
this.executionContext = ExecutionContext.getInstance();
}
@Before
public void setUp() {
executionContext.clearContext();
}
@After
public void tearDown() {
executionContext.clearContext();
}
@Test
public void ifWithOneExpression_ReturnsExpression() {
String input = "(if t t)";
assertT(evaluateString(input));
}
@Test
public void ifWithOneExpression_ReturnsNil() {
String input = "(if nil t)";
assertNil(evaluateString(input));
}
@Test
public void ifWithTwoExpressions_ReturnsFirst() {
String input = "(if t t nil)";
assertT(evaluateString(input));
}
@Test
public void ifWithTwoExpressions_ReturnsSecond() {
String input = "(if nil nil t)";
assertT(evaluateString(input));
}
@Test
public void ifWithNumericConditional() {
String input = "(if 23 t nil)";
assertT(evaluateString(input));
}
@Test(expected = UndefinedSymbolException.class)
public void ifWithNilCondition_DoesNotEvaluateThenForm() {
String input = "(if nil (setf x 22))";
assertNil(evaluateString(input));
evaluateString("x");
}
@Test(expected = UndefinedSymbolException.class)
public void ifWithTrueCondition_DoesNotEvaluateElseForm() {
String input = "(if t nil (setf x 22))";
assertNil(evaluateString(input));
evaluateString("x");
}
@Test(expected = TooFewArgumentsException.class)
public void ifWithTooFewArguments() {
evaluateString("(if t)");
}
@Test(expected = TooManyArgumentsException.class)
public void ifWithTooManyArguments() {
evaluateString("(if t t t t)");
}
}