fc3b83d8f6235906fdb0c0ef0699b6ffab6bcf75
[lambda.git] / code / parse.js
1 // Parser for lambda with let written in Simplified JavaScript
2 //      by Jim Pryor 2010-09-22
3 //      Stripped down from Top Down Operator Precedence : parse.js
4 //      http://javascript.crockford.com/tdop/index.html
5 //      Douglas Crockford 2010-06-26
6
7 /*jslint onevar: false
8  */
9
10 /*   members create, error, message, name, prototype, stringify, toSource,
11     toString, write
12 */
13
14 /*global make_var, make_app, make_lam, Lambda_var */
15
16 var make_parse = function () {
17     var symbol_table = {};
18     var token;
19     var tokens;
20     var token_nr;
21
22     var advance = function (id) {
23         var a, o, t, v;
24         if (id && token.id !== id) {
25             token.error("Expected '" + id + "'.");
26         }
27         if (token_nr >= tokens.length) {
28             token = symbol_table["(end)"];
29             return;
30         }
31         t = tokens[token_nr];
32         token_nr += 1;
33         v = t.value;
34         a = t.type;
35         if (a === "name") {
36             o = symbol_table[v];
37             if (!o || typeof o === 'function') {
38                 o = symbol_table["(name)"];
39             } else {
40                 a = o.arity || "keyword";
41             }
42         } else if (a ===  "number") {
43             o = symbol_table["(literal)"];
44             a = "literal";
45         } else if (a === "operator") {
46             o = symbol_table[v];
47             if (!o) {
48                 t.error("Unknown operator.");
49             }
50             a = "keyword";
51         } else {
52             t.error("Unexpected token.");
53         }
54         token = Object.create(o);
55         token.from  = t.from;
56         token.to    = t.to;
57         token.value = v;
58         token.arity = a; // will be: name, keyword, literal
59         return token;
60     };
61
62     var original_symbol = {
63         handler: function () {
64             this.error("Undefined.");
65         }
66     };
67
68         try {
69                 if (console && console.debug) {
70                         function print() {
71                                 console.debug.apply(this, arguments);
72                         }
73                 }
74         } catch (e) {}
75
76     var symbol = function (id) {
77         var s = symbol_table[id];
78         if (!s) {
79             s = Object.create(original_symbol);
80             s.id = s.value = id;
81             symbol_table[id] = s;
82                         print(s, s.arity);
83         }
84         return s;
85     };
86
87     var var_table;
88     var name_table;
89
90     var name_handler = function () {
91         var n = name_table[this.value];
92         if (!n) {
93             n = make_var(this.value);
94             var_table[this.value] = n;
95             n = new Lambda_var(n);
96             name_table[this.value] = n;
97         }
98         if (this.first) {
99             return make_app(this.first.handler(), n);
100         } else {
101             return n;
102         }
103     };
104
105     var branch_handler = function () {
106         var n = this.second.handler();
107         if (this.first) {
108             return make_app(this.first.handler(), n);
109         } else {
110             return n;
111         }
112     };
113
114     var lambda_handler = function () {
115         var body = this.second.handler();
116         var n, v;
117         while (this.first.length) {
118             n = this.first.pop().value;
119             v = var_table[n];
120             if (!v) {
121                 v = make_var(n);
122                 var_table[n] = v;
123                 name_table[n] = new Lambda_var(v);
124             }
125             body = make_lam(v, body);
126         }
127         return body;
128     };
129
130
131     var itself = function () {
132         return this;
133     };
134
135     symbol("(end)");
136     symbol("(name)").handler = name_handler;
137     symbol("(literal)").handler = itself;
138     symbol("let").handler = lambda_handler;
139     symbol("=").handler = branch_handler;
140     symbol("in");
141     symbol(")").handler = branch_handler;
142     symbol("(");
143     symbol("\\").handler = lambda_handler;
144     symbol("lambda").handler = lambda_handler;
145     symbol(".");
146
147         function make_constants() {
148
149                 var constant = function (s, v) {
150                         var x = symbol(s);
151                         x.handler = function () {
152                                 this.value = symbol_table[this.id].value;
153                                 return this;
154                         };
155                         x.value = v;
156                         x.arity = "literal";
157                         return x;
158                 };
159
160                 function make_lam2(a, b, aa) {
161                         return make_lam(a, make_lam(b, aa));
162                 }
163                 function make_lam3(a, b, c, aa) {
164                         return make_lam(a, make_lam(b, make_lam(c, aa)));
165                 }
166                 function make_app3(aa, bb, cc) {
167                         return make_app(make_app(aa, bb), cc);
168                 }
169                 var u = make_var("u");
170                 var v = make_var("v");
171                 var x = make_var("x");
172                 var s = make_var("s");
173                 var z = make_var("z");
174                 var uu = new Lambda_var(u);
175                 var vv = new Lambda_var(v);
176                 var xx = new Lambda_var(x);
177                 var ss = new Lambda_var(s);
178                 var zz = new Lambda_var(z);
179                 var_table = { u: u, v: v, x: x, s: s, z: z};
180                 name_table = {u: uu, v: vv, x: xx, s: ss, z: zz};
181
182                 constant("S", make_lam3(u, v, x, make_app3(uu, xx, make_app(vv, xx))));
183                 constant("K", make_lam2(u, v, uu));
184                 constant("I", make_lam(x, xx));
185                 constant("B", make_lam3(u, v, x, make_app(uu, make_app(vv, xx))));
186                 constant("C", make_lam3(u, v, x, make_app3(uu, xx, vv)));
187                 constant("W", make_lam2(u, v, make_app3(uu, vv, vv)));
188                 constant("T", make_lam2(u, v, make_app(vv, uu)));
189         }
190         make_constants();
191
192     var expression = function (in_let) {
193         var t, n;
194         if (token.id === "\\" || token.id === "lambda") {
195             token.value = "lambda";
196             t = token;
197             advance();
198             n = token;
199             if (n.arity !== "name") {
200                 n.error("Expected a variable name.");
201             }
202             advance();
203             if (token.id === "(") {
204                 t.first = [n];
205                 advance();
206                 t.second = expression(false);
207                 advance(")");
208                 return t;
209             } else {
210                 t.first = [];
211                 while (token.arity === "name") {
212                     t.first.push(n);
213                     n = token;
214                     advance();
215                 }
216                                 if (token.arity === "literal" && t.first.length === 0) {
217                                         t.first.push(n);
218                                         t.second = token;
219                                         advance();
220                                 } else if (token.id === ".") {
221                     t.first.push(n);
222                     advance();
223                     t.second = expression(in_let);
224                 } else if (t.first.length === 1) {
225                     t.second = n;
226                 } else {
227                     t.first.push(n);
228                     t.error("Can't parse lambda abstract.");
229                 }
230                 return t;
231             }
232         } else {
233             n = null;
234             while (token.id === "(") {
235                 advance();
236                 t = expression(false);
237                 token.first = n;
238                 token.second = t;
239                 n = token;
240                 advance(")");
241                 if (in_let && token.id === "let" || token.id === "(end)" || token.id === ")") {
242                     return n;
243                 }
244             }
245             while (true) {
246                                 if (n && (in_let && token.id === "in" || token.id === "(end)" || token.id === ")")) {
247                     return n;
248                 } else if (token.id === "(") {
249                     advance();
250                     t = expression(false);
251                     token.first = n;
252                     token.second = t;
253                     n = token;
254                     advance(")");
255                 } else {
256                     if (token.arity !== "name" && token.arity !== "literal") {
257                         token.error("Expected a variable name or literal.");
258                     }
259                     token.first = n;
260                     n = token;
261                     advance();
262                 }
263             }
264         }
265         };
266
267     return function (source) {
268         tokens = source.tokens();
269         token_nr = 0;
270         advance();
271         
272         // let n = c in b
273         // (\n. b) c
274
275         var t = null, eq, c, base = {};
276         var target = base;
277
278         while (token.id === "let") {
279             t = token;
280             advance();
281             if (token.arity !== "name") {
282                 token.error("Expected a variable name.");
283             }
284             t.first = [token];
285             advance();
286             eq = token; // token.id === "="
287             advance("=");
288             c = expression(true);
289
290                         eq.first = t;
291                         eq.second = c;
292                         target.second = eq;
293
294 //             c.first = eq;
295 //             eq.second = t;
296 //             target.second = c;
297
298             target = t;
299             advance("in");
300         }
301     
302         target.second = expression(false);
303
304         advance("(end)");
305         return base.second;
306     };
307
308 };
309