2017-03-07 13:26:24 -05:00
|
|
|
package function.builtin.special;
|
|
|
|
|
|
|
|
import static sexpression.Nil.NIL;
|
|
|
|
import static testutil.TestUtilities.*;
|
|
|
|
|
2017-07-19 15:23:15 -04:00
|
|
|
import org.junit.Test;
|
2017-03-07 13:26:24 -05:00
|
|
|
|
|
|
|
import function.ArgumentValidator.*;
|
|
|
|
import function.builtin.EVAL.UndefinedSymbolException;
|
|
|
|
import sexpression.*;
|
2017-07-19 15:23:15 -04:00
|
|
|
import testutil.SymbolAndFunctionCleaner;
|
2017-03-07 13:26:24 -05:00
|
|
|
|
2017-07-19 15:23:15 -04:00
|
|
|
public class LET_STARTest extends SymbolAndFunctionCleaner {
|
2017-03-07 13:26:24 -05:00
|
|
|
|
|
|
|
@Test
|
|
|
|
public void simpleLet() {
|
|
|
|
String input = "(let* ((x 1)) x)";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("1"), evaluateString(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void emptyLet_ReturnsNil() {
|
|
|
|
String input = "(let* ())";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(NIL, evaluateString(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void letStarWithSymbolsOnly_SetsValuesToNil() {
|
|
|
|
String input = "(let* ((x) (y)) (list x y))";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new Cons(NIL, new Cons(NIL, NIL)), evaluateString(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void letStarWithSetf_DoesNotAlterGlobalVariable() {
|
2017-03-07 16:41:26 -05:00
|
|
|
String before = "(setq x 22)";
|
2017-03-07 13:26:24 -05:00
|
|
|
String input = "(let* ((x 1)) x)";
|
|
|
|
String after = "x";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("22"), evaluateString(before));
|
|
|
|
assertSExpressionsMatch(new LispNumber("1"), evaluateString(input));
|
|
|
|
assertSExpressionsMatch(new LispNumber("22"), evaluateString(after));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void letStarWithNestedSetf_DoesNotAlterGlobalVariable() {
|
2017-03-07 16:41:26 -05:00
|
|
|
String before = "(setq x 22)";
|
|
|
|
String input = "(let* ((x 33)) (setq x 44) x)";
|
2017-03-07 13:26:24 -05:00
|
|
|
String after = "x";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("22"), evaluateString(before));
|
|
|
|
assertSExpressionsMatch(new LispNumber("44"), evaluateString(input));
|
|
|
|
assertSExpressionsMatch(new LispNumber("22"), evaluateString(after));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void nestedLet() {
|
|
|
|
String input = "(let* ((x 1)) (let* ((y (+ 1 x))) y))";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void nestedLetWithGlobals() {
|
2017-03-07 16:41:26 -05:00
|
|
|
String before = "(setq x 92)";
|
2017-03-07 13:26:24 -05:00
|
|
|
String input = "(let* ((x 1)) (let* ((y (+ 1 x))) y))";
|
|
|
|
String after = "x";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("92"), evaluateString(before));
|
|
|
|
assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
|
|
|
|
assertSExpressionsMatch(new LispNumber("92"), evaluateString(after));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void alterGlobalVariableFromLet() {
|
2017-03-07 16:41:26 -05:00
|
|
|
String before = "(setq x 1)";
|
|
|
|
String input = "(let* ((y 1)) (setq x 2))";
|
2017-03-07 13:26:24 -05:00
|
|
|
String after = "x";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("1"), evaluateString(before));
|
|
|
|
assertSExpressionsMatch(new LispNumber("2"), evaluateString(input));
|
|
|
|
assertSExpressionsMatch(new LispNumber("2"), evaluateString(after));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void accessGlobalVariableFromLet() {
|
2017-03-07 16:41:26 -05:00
|
|
|
String before = "(setq x 1)";
|
2017-03-07 13:26:24 -05:00
|
|
|
String input = "(let* () x)";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("1"), evaluateString(before));
|
|
|
|
assertSExpressionsMatch(new LispNumber("1"), evaluateString(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = UndefinedSymbolException.class)
|
|
|
|
public void letStarDoesNotSetGlobalVariable() {
|
|
|
|
String input = "(let* ((x 1)) nil)";
|
|
|
|
|
|
|
|
evaluateString(input);
|
|
|
|
evaluateString("x");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = BadArgumentTypeException.class)
|
|
|
|
public void letStarWithNonList() {
|
|
|
|
evaluateString("(let* a)");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = BadArgumentTypeException.class)
|
|
|
|
public void letStarWithNoPairs() {
|
|
|
|
evaluateString("(let* (a))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = TooFewArgumentsException.class)
|
|
|
|
public void letStarWithTooFewItemsInPair() {
|
|
|
|
evaluateString("(let* (()))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = TooManyArgumentsException.class)
|
|
|
|
public void letStarWithTooManyItemsInPair() {
|
|
|
|
evaluateString("(let* ((a b c)))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = BadArgumentTypeException.class)
|
|
|
|
public void letStarWithNonSymbolInPair() {
|
|
|
|
evaluateString("(let* ((1 b)))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = TooFewArgumentsException.class)
|
|
|
|
public void letStarWithTooFewArguments() {
|
|
|
|
evaluateString("(let*)");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = DottedArgumentListException.class)
|
|
|
|
public void letStarWithDottedArgumentList() {
|
|
|
|
evaluateString("(apply 'let* (cons 'a 'b))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = DottedArgumentListException.class)
|
|
|
|
public void letStarWithDottedPairList() {
|
|
|
|
evaluateString("(apply 'let* (cons (cons 'a 'b) nil))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test(expected = DottedArgumentListException.class)
|
|
|
|
public void letStarWithDottedPair() {
|
|
|
|
evaluateString("(apply 'let* (cons (cons (cons 'a 'b) nil) nil))");
|
|
|
|
}
|
|
|
|
|
|
|
|
@Test
|
|
|
|
public void letStarEvaluatesSymbolsInSequence() {
|
|
|
|
String input = "(let* ((x 1) (y (+ x 1))) (+ x y))";
|
|
|
|
|
|
|
|
assertSExpressionsMatch(new LispNumber("3"), evaluateString(input));
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|