Convert .falderal files to Markdown files.
--HG--
rename : dialect/crabwell.falderal => dialect/Crabwell.markdown
rename : dialect/p-normal.falderal => dialect/P-Normal.markdown
rename : dialect/pifxley.falderal => dialect/Pifxley.markdown
rename : dialect/dialects.markdown => dialect/README.markdown
rename : src/tests.falderal => src/tests.markdown
catseye
12 years ago
0 | Test suite for Crabwell. | |
1 | Chris Pressey, Cat's Eye Technologies. | |
2 | ||
3 | -> Tests for functionality "Interpret Crabwell Program" | |
4 | ||
5 | | (let* (((a b) (quote c))) (symbol (a b))) | |
6 | = c | |
7 | ||
8 | | (let* (((a b) (lambda (x) (cons x (quote ()))))) ((symbol (a b)) (quote r))) | |
9 | = (r) |
0 | P-Normal Pixley | |
1 | =============== | |
2 | ||
3 | P-Normalization is a technique for simplifying Pixley programs. It is | |
4 | related to [A-Normalization](http://matt.might.net/articles/a-normalization/), | |
5 | but quite a bit simpler. | |
6 | ||
7 | A Pixley program is in P-Normal form if and only if: | |
8 | ||
9 | * All `let*` forms bind a single expression to a single symbol; and | |
10 | * All `cond` forms have a single test branch and a single `else` branch. | |
11 | ||
12 | The Pixley 2.0 distribution contains a P-Normalizer, written in Pixley. | |
13 | It converts arbitrary Pixley programs into P-Normal form. | |
14 | ||
15 | Motivation | |
16 | ---------- | |
17 | ||
18 | There are several reasons why I wrote the P-Normalizer. | |
19 | ||
20 | One was simply to write a non-trivial program in Pixley besides the Pixley | |
21 | interpreter itself. | |
22 | ||
23 | Another is that an implementer might find it easier to write an interpreter | |
24 | or compiler for P-Normal Pixley; this gives them the option of P-Normalizing | |
25 | the Pixley source before input. Certainly, when I was implementing Pixley | |
26 | in C (for AmigaOS 1.3), I would have found the continuation code easier to | |
27 | formulate if the input program was in P-Normal form. | |
28 | ||
29 | Yet another is to effectively criticize the design choice of putting `let*` | |
30 | and `cond` in Pixley, instead of `let` and `if`. My belief is that, if only | |
31 | these simpler forms were included in Pixley, the Pixley interpreter would be | |
32 | larger. P-Normalizing the interpreter, then (as a trivial second step), | |
33 | converting the P-Normal `let*`s and `cond`s to `let`s and `if`s, would allow | |
34 | one to check this belief -- however, I have not gotten so far as to actually | |
35 | do that, yet. | |
36 | ||
37 | And the last reason I will mention here is that it is a step towards true | |
38 | A-Normalization of Pixley programs. This would be useful for my purposes, | |
39 | as one of my long-held goals for Pixley was to write a totality checker for | |
40 | Pixley programs, in Pixley, much as I have done in the past with Scheme. | |
41 | ||
42 | However, useful A-Normalization requires that non-trivial expressions | |
43 | (such as calls to defined functions) occur let-bound in other expressions. | |
44 | For example, the first element of a list which represents a function | |
45 | application must be a symbol which is bound to the lambda being applied, | |
46 | rather than a literal lambda. Pixley is not really capable of converting | |
47 | expressions to such a form, because it lacks the ability to create new | |
48 | symbols. | |
49 | ||
50 | There are a couple of ways around this, but they each have drawbacks. | |
51 | ||
52 | The normalizer could be supplied with a list of symbols to be used during | |
53 | bound-conversion, but the user would need to provide a sufficient supply | |
54 | of symbols, and ensure that they don't clash with symbols in the program. | |
55 | ||
56 | Or, a creative bending of the language could allow expressions to be bound | |
57 | to, not just symbols, but entire S-expressions, which we could generate in | |
58 | an infinite supply. While the resulting program could, e.g., be statically | |
59 | analyzed for totality, it would not be a Pixley program (because Scheme | |
60 | doesn't allow that kind of binding.) | |
61 | ||
62 | Or, instead of converting to normal form, the program could simply check | |
63 | the input Pixley program and evaluate to a boolean indicating whether the | |
64 | program is in normal form or not. However, this would offload the work of | |
65 | doing the actual conversion to programmer, which is less than ideal. | |
66 | ||
67 | Or, the normalizer could be written in some language besides Pixley, but | |
68 | given Pixley's "bootstrappability" roots, I'm not even going to consider | |
69 | that unless all else fails. | |
70 | ||
71 | The thing is, I haven't decided how to approach the problem yet, so I will | |
72 | save "P-Normalization 2.0" for a later date. (Although, now that I've | |
73 | wriiten them all out, option #2 seems most appealing.) | |
74 | ||
75 | Tests for the P-Normalizer | |
76 | -------------------------- | |
77 | ||
78 | -> Tests for functionality "P-Normalize Pixley Program" | |
79 | ||
80 | -> Functionality "P-Normalize Pixley Program" is implemented by | |
81 | -> shell command "script/tower.sh src/pixley.pix dialect/p-normal.pix %(test-file)" | |
82 | ||
83 | `let*` gets expanded into a series of nested, one-binding, `let*`s. | |
84 | ||
85 | | (let* ((a (quote a)) (b (quote b))) (cons a b)) | |
86 | = (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))) | |
87 | ||
88 | `cond` gets expanded into a series of nested, one-test, `cond`s. | |
89 | ||
90 | | (cond ((equal? a b) a) ((equal? b c) b) (else c)) | |
91 | = (cond ((equal? a b) a) (else (cond ((equal? b c) b) (else c)))) | |
92 | ||
93 | Expressions in a `let*` binding get P-Normalized. | |
94 | ||
95 | | (let* ((g (let* ((a (quote a)) (b (quote b))) (cons a b)))) g) | |
96 | = (let* ((g (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))))) g) | |
97 | ||
98 | Expressions in a `let*` body get P-Normalized. | |
99 | ||
100 | | (let* ((c (quote c))) | |
101 | | (car (let* ((a (quote a)) (b (quote b))) (cons a b)))) | |
102 | = (let* ((c (quote c))) (car (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))))) | |
103 | ||
104 | Expressions in a `cond` test get P-Normalized. | |
105 | ||
106 | | (cond | |
107 | | ((eq? (let* ((a (quote a)) (b (quote b))) a) (quote a)) | |
108 | | (quote yes)) | |
109 | | (else | |
110 | | (quote no))) | |
111 | = (cond ((eq? (let* ((a (quote a))) (let* ((b (quote b))) a)) (quote a)) (quote yes)) (else (quote no))) | |
112 | ||
113 | Expressions in a `cond` branch get P-Normalized. | |
114 | ||
115 | | (cond | |
116 | | ((eq? (quote a) (quote a)) | |
117 | | (let* ((a (quote a)) (yes (quote b))) yes)) | |
118 | | (else | |
119 | | (quote no))) | |
120 | = (cond ((eq? (quote a) (quote a)) (let* ((a (quote a))) (let* ((yes (quote b))) yes))) (else (quote no))) | |
121 | ||
122 | Expressions in a `cons` get P-Normalized. | |
123 | ||
124 | | (cons (quote x) (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
125 | = (cons (quote x) (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
126 | ||
127 | Expressions in a `car` get P-Normalized. | |
128 | ||
129 | | (car (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
130 | = (car (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
131 | ||
132 | Expressions in a `cdr` get P-Normalized. | |
133 | ||
134 | | (cdr (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
135 | = (cdr (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
136 | ||
137 | Expressions in a `list?` get P-Normalized. | |
138 | ||
139 | | (list? (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
140 | = (list? (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
141 | ||
142 | Expressions in a `quote` do *not* get P-Normalized. | |
143 | ||
144 | | (quote (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
145 | = (quote (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
146 | ||
147 | Expressions in a `lambda` body get P-Normalized. | |
148 | ||
149 | | (let* ((a (lambda (x) (let* ((r (quote r)) (p (quote p))) x)))) | |
150 | | (a (quote d))) | |
151 | = (let* ((a (lambda (x) (let* ((r (quote r))) (let* ((p (quote p))) x))))) (a (quote d))) | |
152 | ||
153 | Arguments of a function application get P-Normalized. | |
154 | ||
155 | | (let* ((f (lambda (x) x))) | |
156 | | (f (let* ((a (quote a)) (b (quote b))) (cons a b)))) | |
157 | = (let* ((f (lambda (x) x))) (f (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))))) |
0 | Test suite for the interpreter for Pifxley. | |
1 | Chris Pressey, Cat's Eye Technologies. | |
2 | ||
3 | -> Tests for functionality "Interpret Pifxley Program" | |
4 | ||
5 | Note: this file is just a copy of `src/tests.markdown` with the | |
6 | tests for `cond` replaced with tests for `if`. I should probably | |
7 | do something better than that someday (and that applies to the whole | |
8 | test system in the Pixley distribution.) | |
9 | ||
10 | Constructing and Manipulating Data | |
11 | ---------------------------------- | |
12 | ||
13 | `quote` evaluates to literally what is in the head of the tail of | |
14 | the cons cell whose head is `quote`. | |
15 | ||
16 | | (quote hello) | |
17 | = hello | |
18 | ||
19 | | (quote (foo bar)) | |
20 | = (foo bar) | |
21 | ||
22 | `cons` lets you create a list from some thing and another list. | |
23 | ||
24 | | (cons (quote thing) (quote (rest))) | |
25 | = (thing rest) | |
26 | ||
27 | `car` extracts the head of a list. | |
28 | ||
29 | | (car (quote (foo bar))) | |
30 | = foo | |
31 | ||
32 | `cdr` extracts the tail of a list. | |
33 | ||
34 | | (cdr (quote (foo bar))) | |
35 | = (bar) | |
36 | ||
37 | Predicates and Types | |
38 | -------------------- | |
39 | ||
40 | Because booleans don't actually have a defined representation in | |
41 | Pixley, the next few tests are cheating a bit, relying on Scheme's | |
42 | defined representation for booleans instead. This would be easy | |
43 | to fix up, but a bit tedious: just wrap each of these in | |
44 | ||
45 | (cond (... (quote true)) (else (quote false))) | |
46 | ||
47 | `equal?` works on symbols. | |
48 | ||
49 | | (equal? (quote a) (quote a)) | |
50 | = #t | |
51 | ||
52 | | (equal? (quote a) (quote b)) | |
53 | = #f | |
54 | ||
55 | `equal?` works on lists. | |
56 | ||
57 | | (equal? (quote (one (two three))) | |
58 | | (cons (quote one) (quote ((two three))))) | |
59 | = #t | |
60 | ||
61 | A symbol is not a list. | |
62 | ||
63 | | (list? (quote a)) | |
64 | = #f | |
65 | ||
66 | A list whose final cons cell's tail contains a null, is a list. | |
67 | ||
68 | | (list? (cons (quote a) (quote ()))) | |
69 | = #t | |
70 | ||
71 | | (list? (quote (a b c d e f))) | |
72 | = #t | |
73 | ||
74 | A pair is not a list. | |
75 | ||
76 | Actually, pairs aren't defined at all in Pixley, so I wouldn't | |
77 | blame an implementation for just freaking out at this one. | |
78 | ||
79 | | (list? (cons (quote a) (quote b))) | |
80 | = #f | |
81 | ||
82 | Booleans are not lists. | |
83 | ||
84 | | (list? (equal? (quote a) (quote b))) | |
85 | = #f | |
86 | ||
87 | Lambda functions are not lists. | |
88 | ||
89 | | (list? (lambda (x y) (y x))) | |
90 | = #f | |
91 | ||
92 | But the empty list is a list. | |
93 | ||
94 | | (list? (quote ())) | |
95 | = #t | |
96 | ||
97 | | (list? (cdr (quote (foo)))) | |
98 | = #t | |
99 | ||
100 | The empty list can be expressed as `(quote ())`. | |
101 | ||
102 | | (equal? (cdr (quote (foo))) (quote ())) | |
103 | = #t | |
104 | ||
105 | Binding to Names | |
106 | ---------------- | |
107 | ||
108 | `let*` lets you bind identifiers to values. An identifier can be bound | |
109 | to a symbol. | |
110 | ||
111 | | (let* ((a (quote hello))) a) | |
112 | = hello | |
113 | ||
114 | `let*` can appear in the binding expression in a `let*`. | |
115 | ||
116 | | (let* ((a (let* ((b (quote c))) b))) a) | |
117 | = c | |
118 | ||
119 | `let*` can bind a symbol to a function value. | |
120 | ||
121 | | (let* ((a (lambda (x y) (cons x y)))) | |
122 | | (a (quote foo) (quote ()))) | |
123 | = (foo) | |
124 | ||
125 | Bindings established in a binding in a `let*` can be seen in | |
126 | subsequent bindings in the same `let*`. | |
127 | ||
128 | | (let* ((a (quote hello)) (b (cons a (quote ())))) b) | |
129 | = (hello) | |
130 | ||
131 | Shadowing happens. | |
132 | ||
133 | | (let* ((a (quote hello))) (let* ((a (quote goodbye))) a)) | |
134 | = goodbye | |
135 | ||
136 | `let*` can have an empty list of bindings. | |
137 | ||
138 | | (let* () (quote hi)) | |
139 | = hi | |
140 | ||
141 | Decision-making | |
142 | --------------- | |
143 | ||
144 | `if` works. | |
145 | ||
146 | | (let* ((true (equal? (quote a) (quote a)))) | |
147 | | (if true (quote hi) (quote lo))) | |
148 | = hi | |
149 | ||
150 | | (let* ((false (equal? (quote a) (quote b)))) | |
151 | | (if false (quote hi) (quote lo))) | |
152 | = lo | |
153 | ||
154 | Functions | |
155 | --------- | |
156 | ||
157 | You can define functions with `lambda`. They can be anonymous. | |
158 | ||
159 | | ((lambda (a) a) (quote whee)) | |
160 | = whee | |
161 | ||
162 | Bindings in force when a function is defined will still be in force | |
163 | when the function is applied, even if they are not lexically in scope. | |
164 | ||
165 | | ((let* | |
166 | | ((a (quote (hi))) | |
167 | | (f (lambda (x) (cons x a)))) f) (quote oh)) | |
168 | = (oh hi) | |
169 | ||
170 | Functions can take functions. | |
171 | ||
172 | | (let* | |
173 | | ((apply (lambda (x) (x (quote a))))) | |
174 | | (apply (lambda (r) (cons r (quote ()))))) | |
175 | = (a) | |
176 | ||
177 | Functions can return functions. | |
178 | ||
179 | | (let* | |
180 | | ((mk (lambda (x) (lambda (y) (cons y x)))) | |
181 | | (mk2 (mk (quote (vindaloo))))) | |
182 | | (mk2 (quote chicken))) | |
183 | = (chicken vindaloo) |
0 | Dialects of Pixley | |
1 | ================== | |
2 | ||
3 | As is probably inevitable with a project like this, several minor | |
4 | variations on Pixley exist. This document aims to descibe the | |
5 | significant ones, and their relationships with each other. | |
6 | ||
7 | Pixley 1.x | |
8 | ---------- | |
9 | ||
10 | *Pixley 1.x* was the original version of Pixley. It supported two | |
11 | extra forms from Scheme that the current version (2.0) of Pixley does | |
12 | not support: `null?` and `cadr`. | |
13 | ||
14 | P-Normal Pixley | |
15 | --------------- | |
16 | ||
17 | *P-Normal Pixley* is a subset of Pixley where each `cond` can have | |
18 | only one test branch before the `else`, and where each `let*` can | |
19 | only bind one value to one identifier. | |
20 | ||
21 | P-Normal Pixley is a strict subset of Pixley. All P-Normal Pixley | |
22 | programs are Pixley programs; all P-Normal Pixley programs are also | |
23 | Scheme programs. | |
24 | ||
25 | Pifxley | |
26 | ------- | |
27 | ||
28 | *Pifxley* is a language trivially related to Pixley. The only | |
29 | difference between the two is that Pifxley does not have Scheme's | |
30 | `cond` form. Instead, it has Scheme's `if` form. | |
31 | ||
32 | Like Pixley, Pifxley is a strict subset of Scheme. Pifxley is | |
33 | not a subset of Pixley, nor is Pixley a subset of Pifxley (hello, | |
34 | lattice theory!) | |
35 | ||
36 | `pifxley.pifx` is the Pifxley reference interpreter; it is written | |
37 | in Pifxley. It consists of 386 instances of 52 unique symbols in | |
38 | 615 cons cells. This is actually somewhat smaller than the Pixley | |
39 | self-interpreter, which means that if I was going for purely small | |
40 | size in the self-interpreter, `if` would have made a better choice, | |
41 | as a langauge form to support, than `cond`. However, I find `cond` | |
42 | expressions generally easier to write, and the self-interpreter | |
43 | has one big `cond` expression in the evaluation dispatching section. | |
44 | In the Pifxley interpreter, this section is more awkwardly written | |
45 | and a litte harder to follow (you have to pay more attention to | |
46 | how many close parentheses there are.) | |
47 | ||
48 | `pixley.pifx` is a Pixley interpreter written in Pifxley. | |
49 | ||
50 | Pifxlety | |
51 | -------- | |
52 | ||
53 | *Pifxlety* is a language trivially related to Pifxley. The only | |
54 | difference between the two is that Pifxlety does not have Scheme's | |
55 | `let*` form. Instead, it has Scheme's `let` form. | |
56 | ||
57 | No Pifxlety self-interpreter has yet been written as part of the | |
58 | Pixley project, but I will hazard that it would not be significantly | |
59 | smaller than the Pifxley self-interpreter, for two reasons: | |
60 | ||
61 | 1. Some places in the Pifxley interpreter do rely on the fact that | |
62 | previous bindings in a `let*` are visible in subsequent bindings. | |
63 | These occurrences would have to be rewritten to use nested `let`s. | |
64 | 2. Implementing `let` is not significantly easier than implementing | |
65 | `let*`; it is mainly a matter of retrieving the bindings visible | |
66 | to the current binding from an expression which is unchanging over | |
67 | the whole form, rather than "folded in" after each binding. | |
68 | ||
69 | Of course, I may be wrong; I won't know until I implement it. | |
70 | ||
71 | Pifxlety is neither a strict subset of Pifxley nor of Pixley, and | |
72 | neither is either of those two languages a strict subset of it. | |
73 | But Pifxlety is a strict subset of Scheme. | |
74 | ||
75 | For completeness, there must also be a Pixlety: a language just like | |
76 | Pixley except with `let` instead of `let*`. It is not a particularly | |
77 | interesting variation to me, so I won't get into it, except to say | |
78 | that it, too, is not a subset of any of these other languages, except | |
79 | of course Scheme. | |
80 | ||
81 | Pixl_y | |
82 | ------ | |
83 | ||
84 | Now it is of course possible to remove `let` or `let*` _altogether_ | |
85 | from the language. The remaining language, which I'll call *Pixl_y*, | |
86 | does not suffer in computational power, only expressivity. | |
87 | ||
88 | Because expressions in Pixley do not have side-effects, there is no | |
89 | semantic difference between binding an expression to an identifier | |
90 | and then using the identifier twice, and just using the expression | |
91 | twice. So `let*` is completely unnecessary. | |
92 | ||
93 | Even in the absence of `let*`, you're not forced to repeat yourself; | |
94 | you can use `lambda` as a way to bind expressions to identifiers. | |
95 | For instance, | |
96 | ||
97 | (let* ((a (cons b c))) (cons a a)) | |
98 | ||
99 | can be rewritten | |
100 | ||
101 | ((lambda (a) (cons a a)) (cons b c)) | |
102 | ||
103 | Pixl_y is a strict subset of Pixley, and of Pixlety. It is not a | |
104 | subset of Pifxley, but of course there could be a Pifxl_y if you like. | |
105 | ||
106 | P_xl_y | |
107 | ------ | |
108 | ||
109 | If you remove `cond` from Pixl_y you get *P_xl_y*. | |
110 | ||
111 | Without decision-making, you might think P_xl_y isn't Turing-complete; | |
112 | but you do still have `lambda`, and you can thus write expressions | |
113 | directly in the (eager) lambda calculus. It's just that you'll have | |
114 | to come up with your own representations for truth-values -- one common | |
115 | way is to make truth-values functions which take two arguments, with | |
116 | the true truth-value returning the first argument, and false returning | |
117 | the second. And, of course, none of the existing machinery (`equal?` | |
118 | and so forth) supports this, so you'll have to roll your own. | |
119 | ||
120 | P_xl_y *is* a strict subset of every language listed so far -- Pixl_y, | |
121 | Pifxl_y, Pifxley, Pifxlety, Pixlety, Pixley, and Scheme. | |
122 | ||
123 | You could of course continue down this road, removing other stuff | |
124 | from the language (and letters from the name) until you just had one- | |
125 | argument `lambda` and symbols remaining -- and I guess, to match the | |
126 | lambda calculus, you could just call this language *l*. | |
127 | ||
128 | Crabwell | |
129 | -------- | |
130 | ||
131 | Unlike the previous languages, *Crabwell* is a version of Pixley with | |
132 | one extra feature. In Crabwell, an arbitrary S-expression may occur | |
133 | instead of a symbol as the identifier in a binding in a `let*` | |
134 | expression. In addition, the form `(symbol x)`, where _x_ is any | |
135 | S-expression, evaluates to whatever _x_ is currently bound to in the | |
136 | environment. This allows arbitrary S-expressions to be used as | |
137 | identifiers. | |
138 | ||
139 | This variation was invented to overcome a limitation of Pixley, | |
140 | namely, that it lacks any way to create new symbols. This is a | |
141 | significant limitation for implementing program transformations which | |
142 | create new `let*` bindings, such as A-normalization. | |
143 | ||
144 | Crabwell is not a subset of Scheme, and therefore not a subset of | |
145 | Pixley either. However, Pixley is a subset of Crabwell, and there is | |
146 | a trivial mapping between (finite) Crabwell programs and (finite) | |
147 | Pixley programs -- simply rename each S-expression-based identifier | |
148 | to a symbol-based identifier not used elsewhere in the scope in which | |
149 | it resides. Again, Pixley per se cannot do this, because it cannot | |
150 | create new symbols, but a program in a language which can generate a | |
151 | program source text character-by-character could do so. | |
152 | ||
153 | And, I should note, it's not really necessary to translate Crabwell | |
154 | to Pixley, or even to evaluate Crabwell, to reap some benefits from | |
155 | it in the realm of static analysis. If a program translates a Pixley | |
156 | program to an equivalent Crabwell program, perhaps with new bindings | |
157 | generated in it, then proves some property of the Crabwell program, | |
158 | we know that property is true of the original Pixley program as well. | |
159 | ||
160 | `crabwell.pix` is a Crabwell interpreter written in Pixley. |
0 | Test suite for Crabwell. | |
1 | Chris Pressey, Cat's Eye Technologies. | |
2 | ||
3 | -> Tests for functionality "Interpret Crabwell Program" | |
4 | ||
5 | | (let* (((a b) (quote c))) (symbol (a b))) | |
6 | = c | |
7 | ||
8 | | (let* (((a b) (lambda (x) (cons x (quote ()))))) ((symbol (a b)) (quote r))) | |
9 | = (r) |
0 | Dialects of Pixley | |
1 | ================== | |
2 | ||
3 | As is probably inevitable with a project like this, several minor | |
4 | variations on Pixley exist. This document aims to descibe the | |
5 | significant ones, and their relationships with each other. | |
6 | ||
7 | Pixley 1.x | |
8 | ---------- | |
9 | ||
10 | *Pixley 1.x* was the original version of Pixley. It supported two | |
11 | extra forms from Scheme that the current version (2.0) of Pixley does | |
12 | not support: `null?` and `cadr`. | |
13 | ||
14 | P-Normal Pixley | |
15 | --------------- | |
16 | ||
17 | *P-Normal Pixley* is a subset of Pixley where each `cond` can have | |
18 | only one test branch before the `else`, and where each `let*` can | |
19 | only bind one value to one identifier. | |
20 | ||
21 | P-Normal Pixley is a strict subset of Pixley. All P-Normal Pixley | |
22 | programs are Pixley programs; all P-Normal Pixley programs are also | |
23 | Scheme programs. | |
24 | ||
25 | Pifxley | |
26 | ------- | |
27 | ||
28 | *Pifxley* is a language trivially related to Pixley. The only | |
29 | difference between the two is that Pifxley does not have Scheme's | |
30 | `cond` form. Instead, it has Scheme's `if` form. | |
31 | ||
32 | Like Pixley, Pifxley is a strict subset of Scheme. Pifxley is | |
33 | not a subset of Pixley, nor is Pixley a subset of Pifxley (hello, | |
34 | lattice theory!) | |
35 | ||
36 | `pifxley.pifx` is the Pifxley reference interpreter; it is written | |
37 | in Pifxley. It consists of 386 instances of 52 unique symbols in | |
38 | 615 cons cells. This is actually somewhat smaller than the Pixley | |
39 | self-interpreter, which means that if I was going for purely small | |
40 | size in the self-interpreter, `if` would have made a better choice, | |
41 | as a langauge form to support, than `cond`. However, I find `cond` | |
42 | expressions generally easier to write, and the self-interpreter | |
43 | has one big `cond` expression in the evaluation dispatching section. | |
44 | In the Pifxley interpreter, this section is more awkwardly written | |
45 | and a litte harder to follow (you have to pay more attention to | |
46 | how many close parentheses there are.) | |
47 | ||
48 | `pixley.pifx` is a Pixley interpreter written in Pifxley. | |
49 | ||
50 | Pifxlety | |
51 | -------- | |
52 | ||
53 | *Pifxlety* is a language trivially related to Pifxley. The only | |
54 | difference between the two is that Pifxlety does not have Scheme's | |
55 | `let*` form. Instead, it has Scheme's `let` form. | |
56 | ||
57 | No Pifxlety self-interpreter has yet been written as part of the | |
58 | Pixley project, but I will hazard that it would not be significantly | |
59 | smaller than the Pifxley self-interpreter, for two reasons: | |
60 | ||
61 | 1. Some places in the Pifxley interpreter do rely on the fact that | |
62 | previous bindings in a `let*` are visible in subsequent bindings. | |
63 | These occurrences would have to be rewritten to use nested `let`s. | |
64 | 2. Implementing `let` is not significantly easier than implementing | |
65 | `let*`; it is mainly a matter of retrieving the bindings visible | |
66 | to the current binding from an expression which is unchanging over | |
67 | the whole form, rather than "folded in" after each binding. | |
68 | ||
69 | Of course, I may be wrong; I won't know until I implement it. | |
70 | ||
71 | Pifxlety is neither a strict subset of Pifxley nor of Pixley, and | |
72 | neither is either of those two languages a strict subset of it. | |
73 | But Pifxlety is a strict subset of Scheme. | |
74 | ||
75 | For completeness, there must also be a Pixlety: a language just like | |
76 | Pixley except with `let` instead of `let*`. It is not a particularly | |
77 | interesting variation to me, so I won't get into it, except to say | |
78 | that it, too, is not a subset of any of these other languages, except | |
79 | of course Scheme. | |
80 | ||
81 | Pixl_y | |
82 | ------ | |
83 | ||
84 | Now it is of course possible to remove `let` or `let*` _altogether_ | |
85 | from the language. The remaining language, which I'll call *Pixl_y*, | |
86 | does not suffer in computational power, only expressivity. | |
87 | ||
88 | Because expressions in Pixley do not have side-effects, there is no | |
89 | semantic difference between binding an expression to an identifier | |
90 | and then using the identifier twice, and just using the expression | |
91 | twice. So `let*` is completely unnecessary. | |
92 | ||
93 | Even in the absence of `let*`, you're not forced to repeat yourself; | |
94 | you can use `lambda` as a way to bind expressions to identifiers. | |
95 | For instance, | |
96 | ||
97 | (let* ((a (cons b c))) (cons a a)) | |
98 | ||
99 | can be rewritten | |
100 | ||
101 | ((lambda (a) (cons a a)) (cons b c)) | |
102 | ||
103 | Pixl_y is a strict subset of Pixley, and of Pixlety. It is not a | |
104 | subset of Pifxley, but of course there could be a Pifxl_y if you like. | |
105 | ||
106 | P_xl_y | |
107 | ------ | |
108 | ||
109 | If you remove `cond` from Pixl_y you get *P_xl_y*. | |
110 | ||
111 | Without decision-making, you might think P_xl_y isn't Turing-complete; | |
112 | but you do still have `lambda`, and you can thus write expressions | |
113 | directly in the (eager) lambda calculus. It's just that you'll have | |
114 | to come up with your own representations for truth-values -- one common | |
115 | way is to make truth-values functions which take two arguments, with | |
116 | the true truth-value returning the first argument, and false returning | |
117 | the second. And, of course, none of the existing machinery (`equal?` | |
118 | and so forth) supports this, so you'll have to roll your own. | |
119 | ||
120 | P_xl_y *is* a strict subset of every language listed so far -- Pixl_y, | |
121 | Pifxl_y, Pifxley, Pifxlety, Pixlety, Pixley, and Scheme. | |
122 | ||
123 | You could of course continue down this road, removing other stuff | |
124 | from the language (and letters from the name) until you just had one- | |
125 | argument `lambda` and symbols remaining -- and I guess, to match the | |
126 | lambda calculus, you could just call this language *l*. | |
127 | ||
128 | Crabwell | |
129 | -------- | |
130 | ||
131 | Unlike the previous languages, *Crabwell* is a version of Pixley with | |
132 | one extra feature. In Crabwell, an arbitrary S-expression may occur | |
133 | instead of a symbol as the identifier in a binding in a `let*` | |
134 | expression. In addition, the form `(symbol x)`, where _x_ is any | |
135 | S-expression, evaluates to whatever _x_ is currently bound to in the | |
136 | environment. This allows arbitrary S-expressions to be used as | |
137 | identifiers. | |
138 | ||
139 | This variation was invented to overcome a limitation of Pixley, | |
140 | namely, that it lacks any way to create new symbols. This is a | |
141 | significant limitation for implementing program transformations which | |
142 | create new `let*` bindings, such as A-normalization. | |
143 | ||
144 | Crabwell is not a subset of Scheme, and therefore not a subset of | |
145 | Pixley either. However, Pixley is a subset of Crabwell, and there is | |
146 | a trivial mapping between (finite) Crabwell programs and (finite) | |
147 | Pixley programs -- simply rename each S-expression-based identifier | |
148 | to a symbol-based identifier not used elsewhere in the scope in which | |
149 | it resides. Again, Pixley per se cannot do this, because it cannot | |
150 | create new symbols, but a program in a language which can generate a | |
151 | program source text character-by-character could do so. | |
152 | ||
153 | And, I should note, it's not really necessary to translate Crabwell | |
154 | to Pixley, or even to evaluate Crabwell, to reap some benefits from | |
155 | it in the realm of static analysis. If a program translates a Pixley | |
156 | program to an equivalent Crabwell program, perhaps with new bindings | |
157 | generated in it, then proves some property of the Crabwell program, | |
158 | we know that property is true of the original Pixley program as well. | |
159 | ||
160 | `crabwell.pix` is a Crabwell interpreter written in Pixley. |
0 | P-Normal Pixley | |
1 | =============== | |
2 | ||
3 | P-Normalization is a technique for simplifying Pixley programs. It is | |
4 | related to [A-Normalization](http://matt.might.net/articles/a-normalization/), | |
5 | but quite a bit simpler. | |
6 | ||
7 | A Pixley program is in P-Normal form if and only if: | |
8 | ||
9 | * All `let*` forms bind a single expression to a single symbol; and | |
10 | * All `cond` forms have a single test branch and a single `else` branch. | |
11 | ||
12 | The Pixley 2.0 distribution contains a P-Normalizer, written in Pixley. | |
13 | It converts arbitrary Pixley programs into P-Normal form. | |
14 | ||
15 | Motivation | |
16 | ---------- | |
17 | ||
18 | There are several reasons why I wrote the P-Normalizer. | |
19 | ||
20 | One was simply to write a non-trivial program in Pixley besides the Pixley | |
21 | interpreter itself. | |
22 | ||
23 | Another is that an implementer might find it easier to write an interpreter | |
24 | or compiler for P-Normal Pixley; this gives them the option of P-Normalizing | |
25 | the Pixley source before input. Certainly, when I was implementing Pixley | |
26 | in C (for AmigaOS 1.3), I would have found the continuation code easier to | |
27 | formulate if the input program was in P-Normal form. | |
28 | ||
29 | Yet another is to effectively criticize the design choice of putting `let*` | |
30 | and `cond` in Pixley, instead of `let` and `if`. My belief is that, if only | |
31 | these simpler forms were included in Pixley, the Pixley interpreter would be | |
32 | larger. P-Normalizing the interpreter, then (as a trivial second step), | |
33 | converting the P-Normal `let*`s and `cond`s to `let`s and `if`s, would allow | |
34 | one to check this belief -- however, I have not gotten so far as to actually | |
35 | do that, yet. | |
36 | ||
37 | And the last reason I will mention here is that it is a step towards true | |
38 | A-Normalization of Pixley programs. This would be useful for my purposes, | |
39 | as one of my long-held goals for Pixley was to write a totality checker for | |
40 | Pixley programs, in Pixley, much as I have done in the past with Scheme. | |
41 | ||
42 | However, useful A-Normalization requires that non-trivial expressions | |
43 | (such as calls to defined functions) occur let-bound in other expressions. | |
44 | For example, the first element of a list which represents a function | |
45 | application must be a symbol which is bound to the lambda being applied, | |
46 | rather than a literal lambda. Pixley is not really capable of converting | |
47 | expressions to such a form, because it lacks the ability to create new | |
48 | symbols. | |
49 | ||
50 | There are a couple of ways around this, but they each have drawbacks. | |
51 | ||
52 | The normalizer could be supplied with a list of symbols to be used during | |
53 | bound-conversion, but the user would need to provide a sufficient supply | |
54 | of symbols, and ensure that they don't clash with symbols in the program. | |
55 | ||
56 | Or, a creative bending of the language could allow expressions to be bound | |
57 | to, not just symbols, but entire S-expressions, which we could generate in | |
58 | an infinite supply. While the resulting program could, e.g., be statically | |
59 | analyzed for totality, it would not be a Pixley program (because Scheme | |
60 | doesn't allow that kind of binding.) | |
61 | ||
62 | Or, instead of converting to normal form, the program could simply check | |
63 | the input Pixley program and evaluate to a boolean indicating whether the | |
64 | program is in normal form or not. However, this would offload the work of | |
65 | doing the actual conversion to programmer, which is less than ideal. | |
66 | ||
67 | Or, the normalizer could be written in some language besides Pixley, but | |
68 | given Pixley's "bootstrappability" roots, I'm not even going to consider | |
69 | that unless all else fails. | |
70 | ||
71 | The thing is, I haven't decided how to approach the problem yet, so I will | |
72 | save "P-Normalization 2.0" for a later date. (Although, now that I've | |
73 | wriiten them all out, option #2 seems most appealing.) | |
74 | ||
75 | Tests for the P-Normalizer | |
76 | -------------------------- | |
77 | ||
78 | -> Tests for functionality "P-Normalize Pixley Program" | |
79 | ||
80 | -> Functionality "P-Normalize Pixley Program" is implemented by | |
81 | -> shell command "script/tower.sh src/pixley.pix dialect/p-normal.pix %(test-file)" | |
82 | ||
83 | `let*` gets expanded into a series of nested, one-binding, `let*`s. | |
84 | ||
85 | | (let* ((a (quote a)) (b (quote b))) (cons a b)) | |
86 | = (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))) | |
87 | ||
88 | `cond` gets expanded into a series of nested, one-test, `cond`s. | |
89 | ||
90 | | (cond ((equal? a b) a) ((equal? b c) b) (else c)) | |
91 | = (cond ((equal? a b) a) (else (cond ((equal? b c) b) (else c)))) | |
92 | ||
93 | Expressions in a `let*` binding get P-Normalized. | |
94 | ||
95 | | (let* ((g (let* ((a (quote a)) (b (quote b))) (cons a b)))) g) | |
96 | = (let* ((g (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))))) g) | |
97 | ||
98 | Expressions in a `let*` body get P-Normalized. | |
99 | ||
100 | | (let* ((c (quote c))) | |
101 | | (car (let* ((a (quote a)) (b (quote b))) (cons a b)))) | |
102 | = (let* ((c (quote c))) (car (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))))) | |
103 | ||
104 | Expressions in a `cond` test get P-Normalized. | |
105 | ||
106 | | (cond | |
107 | | ((eq? (let* ((a (quote a)) (b (quote b))) a) (quote a)) | |
108 | | (quote yes)) | |
109 | | (else | |
110 | | (quote no))) | |
111 | = (cond ((eq? (let* ((a (quote a))) (let* ((b (quote b))) a)) (quote a)) (quote yes)) (else (quote no))) | |
112 | ||
113 | Expressions in a `cond` branch get P-Normalized. | |
114 | ||
115 | | (cond | |
116 | | ((eq? (quote a) (quote a)) | |
117 | | (let* ((a (quote a)) (yes (quote b))) yes)) | |
118 | | (else | |
119 | | (quote no))) | |
120 | = (cond ((eq? (quote a) (quote a)) (let* ((a (quote a))) (let* ((yes (quote b))) yes))) (else (quote no))) | |
121 | ||
122 | Expressions in a `cons` get P-Normalized. | |
123 | ||
124 | | (cons (quote x) (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
125 | = (cons (quote x) (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
126 | ||
127 | Expressions in a `car` get P-Normalized. | |
128 | ||
129 | | (car (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
130 | = (car (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
131 | ||
132 | Expressions in a `cdr` get P-Normalized. | |
133 | ||
134 | | (cdr (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
135 | = (cdr (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
136 | ||
137 | Expressions in a `list?` get P-Normalized. | |
138 | ||
139 | | (list? (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
140 | = (list? (let* ((a (quote a))) (let* ((b (quote b))) (cons a b)))) | |
141 | ||
142 | Expressions in a `quote` do *not* get P-Normalized. | |
143 | ||
144 | | (quote (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
145 | = (quote (let* ((a (quote a)) (b (quote b))) (cons a b))) | |
146 | ||
147 | Expressions in a `lambda` body get P-Normalized. | |
148 | ||
149 | | (let* ((a (lambda (x) (let* ((r (quote r)) (p (quote p))) x)))) | |
150 | | (a (quote d))) | |
151 | = (let* ((a (lambda (x) (let* ((r (quote r))) (let* ((p (quote p))) x))))) (a (quote d))) | |
152 | ||
153 | Arguments of a function application get P-Normalized. | |
154 | ||
155 | | (let* ((f (lambda (x) x))) | |
156 | | (f (let* ((a (quote a)) (b (quote b))) (cons a b)))) | |
157 | = (let* ((f (lambda (x) x))) (f (let* ((a (quote a))) (let* ((b (quote b))) (cons a b))))) |
0 | Test suite for the interpreter for Pifxley. | |
1 | Chris Pressey, Cat's Eye Technologies. | |
2 | ||
3 | -> Tests for functionality "Interpret Pifxley Program" | |
4 | ||
5 | Note: this file is just a copy of `src/tests.falderal` with the | |
6 | tests for `cond` replaced with tests for `if`. I should probably | |
7 | do something better than that someday (and that applies to the whole | |
8 | test system in the Pixley distribution.) | |
9 | ||
10 | Constructing and Manipulating Data | |
11 | ---------------------------------- | |
12 | ||
13 | `quote` evaluates to literally what is in the head of the tail of | |
14 | the cons cell whose head is `quote`. | |
15 | ||
16 | | (quote hello) | |
17 | = hello | |
18 | ||
19 | | (quote (foo bar)) | |
20 | = (foo bar) | |
21 | ||
22 | `cons` lets you create a list from some thing and another list. | |
23 | ||
24 | | (cons (quote thing) (quote (rest))) | |
25 | = (thing rest) | |
26 | ||
27 | `car` extracts the head of a list. | |
28 | ||
29 | | (car (quote (foo bar))) | |
30 | = foo | |
31 | ||
32 | `cdr` extracts the tail of a list. | |
33 | ||
34 | | (cdr (quote (foo bar))) | |
35 | = (bar) | |
36 | ||
37 | Predicates and Types | |
38 | -------------------- | |
39 | ||
40 | Because booleans don't actually have a defined representation in | |
41 | Pixley, the next few tests are cheating a bit, relying on Scheme's | |
42 | defined representation for booleans instead. This would be easy | |
43 | to fix up, but a bit tedious: just wrap each of these in | |
44 | ||
45 | (cond (... (quote true)) (else (quote false))) | |
46 | ||
47 | `equal?` works on symbols. | |
48 | ||
49 | | (equal? (quote a) (quote a)) | |
50 | = #t | |
51 | ||
52 | | (equal? (quote a) (quote b)) | |
53 | = #f | |
54 | ||
55 | `equal?` works on lists. | |
56 | ||
57 | | (equal? (quote (one (two three))) | |
58 | | (cons (quote one) (quote ((two three))))) | |
59 | = #t | |
60 | ||
61 | A symbol is not a list. | |
62 | ||
63 | | (list? (quote a)) | |
64 | = #f | |
65 | ||
66 | A list whose final cons cell's tail contains a null, is a list. | |
67 | ||
68 | | (list? (cons (quote a) (quote ()))) | |
69 | = #t | |
70 | ||
71 | | (list? (quote (a b c d e f))) | |
72 | = #t | |
73 | ||
74 | A pair is not a list. | |
75 | ||
76 | Actually, pairs aren't define at all in Pixley, so I wouldn't | |
77 | blame an implementation for just freaking out at this one. | |
78 | ||
79 | | (list? (cons (quote a) (quote b))) | |
80 | = #f | |
81 | ||
82 | Booleans are not lists. | |
83 | ||
84 | | (list? (equal? (quote a) (quote b))) | |
85 | = #f | |
86 | ||
87 | Lambda functions are not lists. | |
88 | ||
89 | | (list? (lambda (x y) (y x))) | |
90 | = #f | |
91 | ||
92 | But the empty list is a list. | |
93 | ||
94 | | (list? (quote ())) | |
95 | = #t | |
96 | ||
97 | | (list? (cdr (quote (foo)))) | |
98 | = #t | |
99 | ||
100 | The empty list can be expressed as `(quote ())`. | |
101 | ||
102 | | (equal? (cdr (quote (foo))) (quote ())) | |
103 | = #t | |
104 | ||
105 | Binding to Names | |
106 | ---------------- | |
107 | ||
108 | `let*` lets you bind identifiers to values. An identifier can be bound | |
109 | to a symbol. | |
110 | ||
111 | | (let* ((a (quote hello))) a) | |
112 | = hello | |
113 | ||
114 | `let*` can appear in the binding expression in a `let*`. | |
115 | ||
116 | | (let* ((a (let* ((b (quote c))) b))) a) | |
117 | = c | |
118 | ||
119 | `let*` can bind a symbol to a function value. | |
120 | ||
121 | | (let* ((a (lambda (x y) (cons x y)))) | |
122 | | (a (quote foo) (quote ()))) | |
123 | = (foo) | |
124 | ||
125 | Bindings established in a binding in a `let*` can be seen in | |
126 | subsequent bindings in the same `let*`. | |
127 | ||
128 | | (let* ((a (quote hello)) (b (cons a (quote ())))) b) | |
129 | = (hello) | |
130 | ||
131 | Shadowing happens. | |
132 | ||
133 | | (let* ((a (quote hello))) (let* ((a (quote goodbye))) a)) | |
134 | = goodbye | |
135 | ||
136 | `let*` can have an empty list of bindings. | |
137 | ||
138 | | (let* () (quote hi)) | |
139 | = hi | |
140 | ||
141 | Decision-making | |
142 | --------------- | |
143 | ||
144 | `if` works. | |
145 | ||
146 | | (let* ((true (equal? (quote a) (quote a)))) | |
147 | | (if true (quote hi) (quote lo))) | |
148 | = hi | |
149 | ||
150 | | (let* ((false (equal? (quote a) (quote b)))) | |
151 | | (if false (quote hi) (quote lo))) | |
152 | = lo | |
153 | ||
154 | Functions | |
155 | --------- | |
156 | ||
157 | You can define functions with `lambda`. They can be anonymous. | |
158 | ||
159 | | ((lambda (a) a) (quote whee)) | |
160 | = whee | |
161 | ||
162 | Bindings in force when a function is defined will still be in force | |
163 | when the function is applied, even if they are not lexically in scope. | |
164 | ||
165 | | ((let* | |
166 | | ((a (quote (hi))) | |
167 | | (f (lambda (x) (cons x a)))) f) (quote oh)) | |
168 | = (oh hi) | |
169 | ||
170 | Functions can take functions. | |
171 | ||
172 | | (let* | |
173 | | ((apply (lambda (x) (x (quote a))))) | |
174 | | (apply (lambda (r) (cons r (quote ()))))) | |
175 | = (a) | |
176 | ||
177 | Functions can return functions. | |
178 | ||
179 | | (let* | |
180 | | ((mk (lambda (x) (lambda (y) (cons y x)))) | |
181 | | (mk2 (mk (quote (vindaloo))))) | |
182 | | (mk2 (quote chicken))) | |
183 | = (chicken vindaloo) |
220 | 220 | Pixley is a simplified version of Pixley where `let*` can only bind one |
221 | 221 | identifer to one value and `cond` can only make one test, like Scheme's |
222 | 222 | `if`. This form is described more fully in the [Falderal literate test |
223 | suite for the P-Normalizer](../eg/p-normal.falderal). | |
223 | suite for the P-Normalizer](../eg/P-Normal.markdown). | |
224 | 224 | * Test suites, written in Falderal, for both Pixley and the P-Normalizer. |
225 | 225 | The original test suite written in Scheme, which runs successively deeper |
226 | 226 | nested copies of the Pixley interpreter, is still included in the |
0 | Test suite for our R5RS Pixley interpreter. | |
1 | Chris Pressey, Cat's Eye Technologies. | |
2 | ||
3 | -> Tests for functionality "Interpret Pixley Program" | |
4 | ||
5 | Constructing and Manipulating Data | |
6 | ---------------------------------- | |
7 | ||
8 | `quote` evaluates to literally what is in the head of the tail of | |
9 | the cons cell whose head is `quote`. | |
10 | ||
11 | | (quote hello) | |
12 | = hello | |
13 | ||
14 | | (quote (foo bar)) | |
15 | = (foo bar) | |
16 | ||
17 | `cons` lets you create a list from some thing and another list. | |
18 | ||
19 | | (cons (quote thing) (quote (rest))) | |
20 | = (thing rest) | |
21 | ||
22 | `car` extracts the head of a list. | |
23 | ||
24 | | (car (quote (foo bar))) | |
25 | = foo | |
26 | ||
27 | `cdr` extracts the tail of a list. | |
28 | ||
29 | | (cdr (quote (foo bar))) | |
30 | = (bar) | |
31 | ||
32 | Predicates and Types | |
33 | -------------------- | |
34 | ||
35 | Because booleans don't actually have a defined representation in | |
36 | Pixley, the next few tests are cheating a bit, relying on Scheme's | |
37 | defined representation for booleans instead. This would be easy | |
38 | to fix up, but a bit tedious: just wrap each of these in | |
39 | ||
40 | (cond (... (quote true)) (else (quote false))) | |
41 | ||
42 | `equal?` works on symbols. | |
43 | ||
44 | | (equal? (quote a) (quote a)) | |
45 | = #t | |
46 | ||
47 | | (equal? (quote a) (quote b)) | |
48 | = #f | |
49 | ||
50 | `equal?` works on lists. | |
51 | ||
52 | | (equal? (quote (one (two three))) | |
53 | | (cons (quote one) (quote ((two three))))) | |
54 | = #t | |
55 | ||
56 | A symbol is not a list. | |
57 | ||
58 | | (list? (quote a)) | |
59 | = #f | |
60 | ||
61 | A list whose final cons cell's tail contains a null, is a list. | |
62 | ||
63 | | (list? (cons (quote a) (quote ()))) | |
64 | = #t | |
65 | ||
66 | | (list? (quote (a b c d e f))) | |
67 | = #t | |
68 | ||
69 | A pair is not a list. | |
70 | ||
71 | Actually, pairs aren't define at all in Pixley, so I wouldn't | |
72 | blame an implementation for just freaking out at this one. | |
73 | ||
74 | | (list? (cons (quote a) (quote b))) | |
75 | = #f | |
76 | ||
77 | Booleans are not lists. | |
78 | ||
79 | | (list? (equal? (quote a) (quote b))) | |
80 | = #f | |
81 | ||
82 | Lambda functions are not lists. | |
83 | ||
84 | | (list? (lambda (x y) (y x))) | |
85 | = #f | |
86 | ||
87 | But the empty list is a list. | |
88 | ||
89 | | (list? (quote ())) | |
90 | = #t | |
91 | ||
92 | | (list? (cdr (quote (foo)))) | |
93 | = #t | |
94 | ||
95 | The empty list can be expressed as `(quote ())`. | |
96 | ||
97 | | (equal? (cdr (quote (foo))) (quote ())) | |
98 | = #t | |
99 | ||
100 | Binding to Names | |
101 | ---------------- | |
102 | ||
103 | `let*` lets you bind identifiers to values. An identifier can be bound | |
104 | to a symbol. | |
105 | ||
106 | | (let* ((a (quote hello))) a) | |
107 | = hello | |
108 | ||
109 | `let*` can appear in the binding expression in a `let*`. | |
110 | ||
111 | | (let* ((a (let* ((b (quote c))) b))) a) | |
112 | = c | |
113 | ||
114 | `let*` can bind a symbol to a function value. | |
115 | ||
116 | | (let* ((a (lambda (x y) (cons x y)))) | |
117 | | (a (quote foo) (quote ()))) | |
118 | = (foo) | |
119 | ||
120 | Bindings established in a binding in a `let*` can be seen in | |
121 | subsequent bindings in the same `let*`. | |
122 | ||
123 | | (let* ((a (quote hello)) (b (cons a (quote ())))) b) | |
124 | = (hello) | |
125 | ||
126 | Shadowing happens. | |
127 | ||
128 | | (let* ((a (quote hello))) (let* ((a (quote goodbye))) a)) | |
129 | = goodbye | |
130 | ||
131 | `let*` can have an empty list of bindings. | |
132 | ||
133 | | (let* () (quote hi)) | |
134 | = hi | |
135 | ||
136 | Decision-making | |
137 | --------------- | |
138 | ||
139 | `cond` works. | |
140 | ||
141 | | (let* ((true (equal? (quote a) (quote a)))) | |
142 | | (cond (true (quote hi)) (else (quote lo)))) | |
143 | = hi | |
144 | ||
145 | | (let* ((true (equal? (quote a) (quote a))) | |
146 | | (false (equal? (quote a) (quote b)))) | |
147 | | (cond (false (quote hi)) (true (quote med)) (else (quote lo)))) | |
148 | = med | |
149 | ||
150 | | (let* ((true (equal? (quote a) (quote a))) | |
151 | | (false (equal? (quote a) (quote b)))) | |
152 | | (cond (false (quote hi)) (false (quote med)) (else (quote lo)))) | |
153 | = lo | |
154 | ||
155 | `cond` can have zero tests before the `else`. | |
156 | ||
157 | | (cond (else (quote woo))) | |
158 | = woo | |
159 | ||
160 | Functions | |
161 | --------- | |
162 | ||
163 | You can define functions with `lambda`. They can be anonymous. | |
164 | ||
165 | | ((lambda (a) a) (quote whee)) | |
166 | = whee | |
167 | ||
168 | Bindings in force when a function is defined will still be in force | |
169 | when the function is applied, even if they are not lexically in scope. | |
170 | ||
171 | | ((let* | |
172 | | ((a (quote (hi))) | |
173 | | (f (lambda (x) (cons x a)))) f) (quote oh)) | |
174 | = (oh hi) | |
175 | ||
176 | Functions can take functions. | |
177 | ||
178 | | (let* | |
179 | | ((apply (lambda (x) (x (quote a))))) | |
180 | | (apply (lambda (r) (cons r (quote ()))))) | |
181 | = (a) | |
182 | ||
183 | Functions can return functions. | |
184 | ||
185 | | (let* | |
186 | | ((mk (lambda (x) (lambda (y) (cons y x)))) | |
187 | | (mk2 (mk (quote (vindaloo))))) | |
188 | | (mk2 (quote chicken))) | |
189 | = (chicken vindaloo) |
0 | Test suite for our R5RS Pixley interpreter. | |
1 | Chris Pressey, Cat's Eye Technologies. | |
2 | ||
3 | -> Tests for functionality "Interpret Pixley Program" | |
4 | ||
5 | Constructing and Manipulating Data | |
6 | ---------------------------------- | |
7 | ||
8 | `quote` evaluates to literally what is in the head of the tail of | |
9 | the cons cell whose head is `quote`. | |
10 | ||
11 | | (quote hello) | |
12 | = hello | |
13 | ||
14 | | (quote (foo bar)) | |
15 | = (foo bar) | |
16 | ||
17 | `cons` lets you create a list from some thing and another list. | |
18 | ||
19 | | (cons (quote thing) (quote (rest))) | |
20 | = (thing rest) | |
21 | ||
22 | `car` extracts the head of a list. | |
23 | ||
24 | | (car (quote (foo bar))) | |
25 | = foo | |
26 | ||
27 | `cdr` extracts the tail of a list. | |
28 | ||
29 | | (cdr (quote (foo bar))) | |
30 | = (bar) | |
31 | ||
32 | Predicates and Types | |
33 | -------------------- | |
34 | ||
35 | Because booleans don't actually have a defined representation in | |
36 | Pixley, the next few tests are cheating a bit, relying on Scheme's | |
37 | defined representation for booleans instead. This would be easy | |
38 | to fix up, but a bit tedious: just wrap each of these in | |
39 | ||
40 | (cond (... (quote true)) (else (quote false))) | |
41 | ||
42 | `equal?` works on symbols. | |
43 | ||
44 | | (equal? (quote a) (quote a)) | |
45 | = #t | |
46 | ||
47 | | (equal? (quote a) (quote b)) | |
48 | = #f | |
49 | ||
50 | `equal?` works on lists. | |
51 | ||
52 | | (equal? (quote (one (two three))) | |
53 | | (cons (quote one) (quote ((two three))))) | |
54 | = #t | |
55 | ||
56 | A symbol is not a list. | |
57 | ||
58 | | (list? (quote a)) | |
59 | = #f | |
60 | ||
61 | A list whose final cons cell's tail contains a null, is a list. | |
62 | ||
63 | | (list? (cons (quote a) (quote ()))) | |
64 | = #t | |
65 | ||
66 | | (list? (quote (a b c d e f))) | |
67 | = #t | |
68 | ||
69 | A pair is not a list. | |
70 | ||
71 | Actually, pairs aren't defined at all in Pixley, so I wouldn't | |
72 | blame an implementation for just freaking out at this one. | |
73 | ||
74 | | (list? (cons (quote a) (quote b))) | |
75 | = #f | |
76 | ||
77 | Booleans are not lists. | |
78 | ||
79 | | (list? (equal? (quote a) (quote b))) | |
80 | = #f | |
81 | ||
82 | Lambda functions are not lists. | |
83 | ||
84 | | (list? (lambda (x y) (y x))) | |
85 | = #f | |
86 | ||
87 | But the empty list is a list. | |
88 | ||
89 | | (list? (quote ())) | |
90 | = #t | |
91 | ||
92 | | (list? (cdr (quote (foo)))) | |
93 | = #t | |
94 | ||
95 | The empty list can be expressed as `(quote ())`. | |
96 | ||
97 | | (equal? (cdr (quote (foo))) (quote ())) | |
98 | = #t | |
99 | ||
100 | Binding to Names | |
101 | ---------------- | |
102 | ||
103 | `let*` lets you bind identifiers to values. An identifier can be bound | |
104 | to a symbol. | |
105 | ||
106 | | (let* ((a (quote hello))) a) | |
107 | = hello | |
108 | ||
109 | `let*` can appear in the binding expression in a `let*`. | |
110 | ||
111 | | (let* ((a (let* ((b (quote c))) b))) a) | |
112 | = c | |
113 | ||
114 | `let*` can bind a symbol to a function value. | |
115 | ||
116 | | (let* ((a (lambda (x y) (cons x y)))) | |
117 | | (a (quote foo) (quote ()))) | |
118 | = (foo) | |
119 | ||
120 | Bindings established in a binding in a `let*` can be seen in | |
121 | subsequent bindings in the same `let*`. | |
122 | ||
123 | | (let* ((a (quote hello)) (b (cons a (quote ())))) b) | |
124 | = (hello) | |
125 | ||
126 | Shadowing happens. | |
127 | ||
128 | | (let* ((a (quote hello))) (let* ((a (quote goodbye))) a)) | |
129 | = goodbye | |
130 | ||
131 | `let*` can have an empty list of bindings. | |
132 | ||
133 | | (let* () (quote hi)) | |
134 | = hi | |
135 | ||
136 | Decision-making | |
137 | --------------- | |
138 | ||
139 | `cond` works. | |
140 | ||
141 | | (let* ((true (equal? (quote a) (quote a)))) | |
142 | | (cond (true (quote hi)) (else (quote lo)))) | |
143 | = hi | |
144 | ||
145 | | (let* ((true (equal? (quote a) (quote a))) | |
146 | | (false (equal? (quote a) (quote b)))) | |
147 | | (cond (false (quote hi)) (true (quote med)) (else (quote lo)))) | |
148 | = med | |
149 | ||
150 | | (let* ((true (equal? (quote a) (quote a))) | |
151 | | (false (equal? (quote a) (quote b)))) | |
152 | | (cond (false (quote hi)) (false (quote med)) (else (quote lo)))) | |
153 | = lo | |
154 | ||
155 | `cond` can have zero tests before the `else`. | |
156 | ||
157 | | (cond (else (quote woo))) | |
158 | = woo | |
159 | ||
160 | Functions | |
161 | --------- | |
162 | ||
163 | You can define functions with `lambda`. They can be anonymous. | |
164 | ||
165 | | ((lambda (a) a) (quote whee)) | |
166 | = whee | |
167 | ||
168 | Bindings in force when a function is defined will still be in force | |
169 | when the function is applied, even if they are not lexically in scope. | |
170 | ||
171 | | ((let* | |
172 | | ((a (quote (hi))) | |
173 | | (f (lambda (x) (cons x a)))) f) (quote oh)) | |
174 | = (oh hi) | |
175 | ||
176 | Functions can take functions. | |
177 | ||
178 | | (let* | |
179 | | ((apply (lambda (x) (x (quote a))))) | |
180 | | (apply (lambda (r) (cons r (quote ()))))) | |
181 | = (a) | |
182 | ||
183 | Functions can return functions. | |
184 | ||
185 | | (let* | |
186 | | ((mk (lambda (x) (lambda (y) (cons y x)))) | |
187 | | (mk2 (mk (quote (vindaloo))))) | |
188 | | (mk2 (quote chicken))) | |
189 | = (chicken vindaloo) |
24 | 24 | rm -f expected.sexp out.sexp |
25 | 25 | |
26 | 26 | echo "Testing Pixley programs as Scheme programs..." |
27 | falderal test tests/config/Pixley-as-Scheme.markdown src/tests.falderal | |
27 | falderal test tests/config/Pixley-as-Scheme.markdown src/tests.markdown | |
28 | 28 | |
29 | 29 | echo "Testing Pixley programs on Pixley reference interpreter..." |
30 | falderal test tests/config/Pixley-as-Pixley.markdown src/tests.falderal | |
30 | falderal test tests/config/Pixley-as-Pixley.markdown src/tests.markdown | |
31 | 31 | |
32 | 32 | echo "Testing Pixley programs on Pixley interpreter on Pixley interpreter..." |
33 | falderal test tests/config/Pixley-as-Pixley^2.markdown src/tests.falderal | |
33 | falderal test tests/config/Pixley-as-Pixley^2.markdown src/tests.markdown | |
34 | 34 | |
35 | 35 | # On my computer, the following test takes about 19 seconds on plt-r5rs, but |
36 | 36 | # about 32 minutes with tinyscheme -- possibly because of frequent GC? |
37 | 37 | # Meanwhile, it breaks miniscm completely. |
38 | 38 | |
39 | 39 | # echo "Testing Pixley programs on (Pixley reference interpreter)^3..." |
40 | # falderal test tests/config/Pixley-as-Pixley^3.markdown src/tests.falderal | |
40 | # falderal test tests/config/Pixley-as-Pixley^3.markdown src/tests.markdown | |
41 | 41 | |
42 | 42 | # And if you have an hour or so to kill, you can try the next level up! |
43 | 43 | # (That's with plt-r5rs; I imagine tinyscheme would take much longer) |
44 | 44 | |
45 | 45 | # echo "Testing Pixley programs on (Pixley reference interpreter)^4..." |
46 | # time falderal test tests/config/Pixley-as-Pixley^4.markdown src/tests.falderal | |
46 | # time falderal test tests/config/Pixley-as-Pixley^4.markdown src/tests.markdown | |
47 | 47 | |
48 | 48 | echo "Running Falderal tests for P-Normalizer..." |
49 | falderal test dialect/p-normal.falderal | |
49 | falderal test dialect/P-Normal.markdown | |
50 | 50 | |
51 | 51 | echo "P-Normalizing Pixley interpreter..." |
52 | 52 | script/tower.sh src/pixley.pix dialect/p-normal.pix src/pixley.pix > src/p-normal-pixley.pix |
53 | 53 | |
54 | 54 | echo "Testing Pixley programs on P-Normalized interpreter..." |
55 | falderal test tests/config/Pixley-on-P-Normal-Pixley.markdown src/tests.falderal | |
55 | falderal test tests/config/Pixley-on-P-Normal-Pixley.markdown src/tests.markdown | |
56 | 56 | |
57 | 57 | rm -f src/p-normal-pixley.pix |
58 | 58 | |
59 | 59 | echo "Testing Pixley programs on Pixley interpreter in Pifxley..." |
60 | falderal test tests/config/Pixley-on-Pifxley.markdown src/tests.falderal | |
60 | falderal test tests/config/Pixley-on-Pifxley.markdown src/tests.markdown | |
61 | 61 | |
62 | 62 | echo "Testing Pifxley programs as Scheme..." |
63 | falderal test tests/config/Pifxley-as-Scheme.markdown dialect/pifxley.falderal | |
63 | falderal test tests/config/Pifxley-as-Scheme.markdown dialect/Pifxley.markdown | |
64 | 64 | |
65 | 65 | echo "Testing Pifxley programs on Pifxley interpreter in Pifxley..." |
66 | falderal test tests/config/Pifxley-as-Pifxley.markdown dialect/pifxley.falderal | |
66 | falderal test tests/config/Pifxley-as-Pifxley.markdown dialect/Pifxley.markdown | |
67 | 67 | |
68 | 68 | echo "Testing Pixley programs on Crabwell interpreter..." |
69 | falderal test tests/config/Pixley-on-Crabwell.markdown src/tests.falderal | |
69 | falderal test tests/config/Pixley-on-Crabwell.markdown src/tests.markdown | |
70 | 70 | |
71 | 71 | echo "Testing Crabwell programs on Crabwell interpreter..." |
72 | falderal test tests/config/Crabwell-as-Crabwell.markdown dialect/crabwell.falderal | |
72 | falderal test tests/config/Crabwell-as-Crabwell.markdown dialect/Crabwell.markdown |