package function.builtin.special; import static sexpression.Nil.NIL; import static testutil.TestUtilities.assertSExpressionsMatch; import static testutil.TestUtilities.evaluateString; import org.junit.Test; import function.ArgumentValidator.BadArgumentTypeException; import function.ArgumentValidator.DottedArgumentListException; import function.ArgumentValidator.TooFewArgumentsException; import function.ArgumentValidator.TooManyArgumentsException; import function.builtin.EVAL.UndefinedSymbolException; import sexpression.Cons; import sexpression.LispNumber; import testutil.SymbolAndFunctionCleaner; public class LET_STARTest extends SymbolAndFunctionCleaner { @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 letStarWithSetq_DoesNotAlterGlobalVariable() { String before = "(setq x 22)"; 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 letStarWithNestedSetq_DoesNotAlterGlobalVariable() { String before = "(setq x 22)"; String input = "(let* ((x 33)) (setq x 44) x)"; 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() { String before = "(setq x 92)"; 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() { String before = "(setq x 1)"; String input = "(let* ((y 1)) (setq x 2))"; 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() { String before = "(setq x 1)"; 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)); } }