Test suite for the interpreter for Pifxley.
Chris Pressey, Cat's Eye Technologies.
-> Tests for functionality "Interpret Pifxley Program"
Note: this file is just a copy of `src/tests.markdown` with the
tests for `cond` replaced with tests for `if`. I should probably
do something better than that someday (and that applies to the whole
test system in the Pixley distribution.)
Constructing and Manipulating Data
----------------------------------
`quote` evaluates to literally what is in the head of the tail of
the cons cell whose head is `quote`.
| (quote hello)
= hello
| (quote (foo bar))
= (foo bar)
`cons` lets you create a list from some thing and another list.
| (cons (quote thing) (quote (rest)))
= (thing rest)
`car` extracts the head of a list.
| (car (quote (foo bar)))
= foo
`cdr` extracts the tail of a list.
| (cdr (quote (foo bar)))
= (bar)
Predicates and Types
--------------------
Because booleans don't actually have a defined representation in
Pixley, the next few tests are cheating a bit, relying on Scheme's
defined representation for booleans instead. This would be easy
to fix up, but a bit tedious: just wrap each of these in
(cond (... (quote true)) (else (quote false)))
`equal?` works on symbols.
| (equal? (quote a) (quote a))
= #t
| (equal? (quote a) (quote b))
= #f
`equal?` works on lists.
| (equal? (quote (one (two three)))
| (cons (quote one) (quote ((two three)))))
= #t
A symbol is not a list.
| (list? (quote a))
= #f
A list whose final cons cell's tail contains a null, is a list.
| (list? (cons (quote a) (quote ())))
= #t
| (list? (quote (a b c d e f)))
= #t
A pair is not a list.
Actually, pairs aren't defined at all in Pixley, so I wouldn't
blame an implementation for just freaking out at this one.
| (list? (cons (quote a) (quote b)))
= #f
Booleans are not lists.
| (list? (equal? (quote a) (quote b)))
= #f
Lambda functions are not lists.
| (list? (lambda (x y) (y x)))
= #f
But the empty list is a list.
| (list? (quote ()))
= #t
| (list? (cdr (quote (foo))))
= #t
The empty list can be expressed as `(quote ())`.
| (equal? (cdr (quote (foo))) (quote ()))
= #t
Binding to Names
----------------
`let*` lets you bind identifiers to values. An identifier can be bound
to a symbol.
| (let* ((a (quote hello))) a)
= hello
`let*` can appear in the binding expression in a `let*`.
| (let* ((a (let* ((b (quote c))) b))) a)
= c
`let*` can bind a symbol to a function value.
| (let* ((a (lambda (x y) (cons x y))))
| (a (quote foo) (quote ())))
= (foo)
Bindings established in a binding in a `let*` can be seen in
subsequent bindings in the same `let*`.
| (let* ((a (quote hello)) (b (cons a (quote ())))) b)
= (hello)
Shadowing happens.
| (let* ((a (quote hello))) (let* ((a (quote goodbye))) a))
= goodbye
`let*` can have an empty list of bindings.
| (let* () (quote hi))
= hi
Decision-making
---------------
`if` works.
| (let* ((true (equal? (quote a) (quote a))))
| (if true (quote hi) (quote lo)))
= hi
| (let* ((false (equal? (quote a) (quote b))))
| (if false (quote hi) (quote lo)))
= lo
Functions
---------
You can define functions with `lambda`. They can be anonymous.
| ((lambda (a) a) (quote whee))
= whee
Bindings in force when a function is defined will still be in force
when the function is applied, even if they are not lexically in scope.
| ((let*
| ((a (quote (hi)))
| (f (lambda (x) (cons x a)))) f) (quote oh))
= (oh hi)
Functions can take functions.
| (let*
| ((apply (lambda (x) (x (quote a)))))
| (apply (lambda (r) (cons r (quote ())))))
= (a)
Functions can return functions.
| (let*
| ((mk (lambda (x) (lambda (y) (cons y x))))
| (mk2 (mk (quote (vindaloo)))))
| (mk2 (quote chicken)))
= (chicken vindaloo)