git @ Cat's Eye Technologies Exanoke / f27b8e8
Aesthetics. catseye 12 years ago
2 changed file(s) with 134 addition(s) and 119 deletion(s). Raw diff Collapse all Expand all
9898 ----------
9999
100100 Let's just go with pairs and atoms for now, although natural numbers would
101 be easy to add too. Atoms are all-uppercase, and `TRUE` is the only truthy
102 atom. Lists are by convention only (and by convention, lists compose via
103 the second element of each pair, and `NIL` is the agreed-upon list-terminating
104 atom, much love to it.)
101 be easy to add too. Following Ruby, atoms are preceded by a colon; while I
102 find this syntax somewhat obnoxious, it is less obnoxious than requiring that
103 atoms are in ALL CAPS, which is what Exanoke originally had. In truth, there
104 would be no real problem with allowing atoms, parameters, and function names
105 to all be arbitrarily alphanumeric, but it would require more static context
106 checking to sort them all out, and we're trying to be heavily syntactic here.
107
108 `:true` is the only truthy atom. Lists are by convention only, and, by
109 convention, lists compose via the second element of each pair, and `:nil` is
110 the agreed-upon list-terminating atom, much love to it.
105111
106112 Grammar
107113 -------
117123 | "cons?" "(" Expr ")"
118124 | "not" "(" Expr ")"
119125 | "#"
120 | Atom
126 | ":" Ident
121127 | Ident ["(" Expr {"," Expr} ")"]
122128 | Smaller.
123129 Smaller ::= "<head" SmallerTerm
125131 | "<if" Expr "then" Smaller "else" Smaller.
126132 SmallerTerm ::= "#"
127133 | Smaller.
128 Ident ::= name<lowercase>.
129 Atom ::= name<uppercase>.
134 Ident ::= name.
130135
131136 The first argument to a function does not have a user-defined name; it is
132 simply referred to as `#`.
137 simply referred to as `#`. Again, there would be no real problem if we were
138 to allow the programmer to give it a better name, but more static context
139 checking would be involved.
133140
134141 Note that `<if` does not seem to be truly necessary. Its only use is to embed
135142 a conditional into the first argument being passed to a recursive call. You
136143 could also use a regular `if` and make the recursive call in both branches,
137 one with `TRUE` as the first argument and the other with `FALSE`.
144 one with `:true` as the first argument and the other with `:false`.
138145
139146 Examples
140147 --------
146153
147154 Basic examples.
148155
149 | cons(HI, THERE)
150 = (HI THERE)
156 | cons(:hi, :there)
157 = (:hi :there)
151158
152 | cons(HI, cons(THERE, NIL))
153 = (HI (THERE NIL))
154
155 | head(cons(HI, THERE))
156 = HI
157
158 | tail(cons(HI, THERE))
159 = THERE
160
161 | tail(tail(cons(HI, cons(THERE, NIL))))
162 = NIL
163
164 | tail(FOO)
159 | cons(:hi, cons(:there, :nil))
160 = (:hi (:there :nil))
161
162 | head(cons(:hi, :there))
163 = :hi
164
165 | tail(cons(:hi, :there))
166 = :there
167
168 | tail(tail(cons(:hi, cons(:there, :nil))))
169 = :nil
170
171 | tail(:foo)
165172 ? tail: Not a cons cell
166173
167 | head(BAR)
174 | head(:bar)
168175 ? head: Not a cons cell
169176
170 | <head cons(HI, THERE)
177 | <head cons(:hi, :there)
171178 ? Expected <smaller>, found "cons"
172179
173 | <tail HI
174 ? Expected <smaller>, found "HI"
175
176 | if TRUE then HI else THERE
177 = HI
178
179 | if HI then HERE else THERE
180 = THERE
181
182 | eq?(HI, THERE)
183 = FALSE
184
185 | eq?(HI, HI)
186 = TRUE
187
188 | cons?(HI)
189 = FALSE
190
191 | cons?(cons(WAGGA, NIL))
192 = TRUE
193
194 | not(TRUE)
195 = FALSE
196
197 | not(FALSE)
198 = TRUE
199
200 | not(cons(WANGA, NIL))
201 = TRUE
180 | <tail :hi
181 ? Expected <smaller>, found ":hi"
182
183 | if :true then :hi else :there
184 = :hi
185
186 | if :hi then :here else :there
187 = :there
188
189 | eq?(:hi, :there)
190 = :false
191
192 | eq?(:hi, :hi)
193 = :true
194
195 | cons?(:hi)
196 = :false
197
198 | cons?(cons(:wagga, :nil))
199 = :true
200
201 | not(:true)
202 = :false
203
204 | not(:false)
205 = :true
206
207 Cons cells are falsey.
208
209 | not(cons(:wanga, :nil))
210 = :true
211
212 `self` and `#` can only be used inside function definitions.
202213
203214 | #
204215 ? Use of "#" outside of a function body
205216
206 | self(FOO)
217 | self(:foo)
207218 ? Use of "self" outside of a function body
208219
209220 | def id(#)
210221 | #
211 | id(WOO)
212 = WOO
222 | id(:woo)
223 = :woo
213224
214225 | def id(#)
215226 | #
216 | id(FOO, BAR)
227 | id(:foo, :bar)
217228 ? Arity mismatch (expected 1, got 2)
218229
219230 | def id(#)
220231 | woo
221 | id(WOO)
232 | id(:woo)
222233 ? Undefined argument "woo"
223234
224235 | def wat(#, woo)
225236 | woo(#)
226 | wat(WOO)
237 | wat(:woo)
227238 ? Undefined function "woo"
228239
229240 | def wat(#)
230 | THERE
241 | :there
231242 | def wat(#)
232 | HI
233 | wat(WOO)
243 | :hi
244 | wat(:woo)
234245 ? Function "wat" already defined
235246
236 | def WAT(#)
247 | def :wat(#)
237248 | #
238 | WAT(WOO)
239 ? Expected identifier, but found atom ('WAT')
249 | :wat(:woo)
250 ? Expected identifier, but found atom (':wat')
240251
241252 | def wat(meow)
242253 | meow
243 | wat(WOO)
254 | wat(:woo)
244255 ? Expected '#', but found 'meow'
245256
246257 | def snd(#, another)
247258 | another
248 | snd(FOO, BAR)
249 = BAR
259 | snd(:foo, :bar)
260 = :bar
250261
251262 | def snd(#, another)
252263 | another
253 | snd(FOO)
264 | snd(:foo)
254265 ? Arity mismatch (expected 2, got 1)
255266
256267 | def snoc(#, another)
257268 | cons(another, #)
258 | snoc(THERE, HI)
259 = (HI THERE)
269 | snoc(:there, :hi)
270 = (:hi :there)
260271
261272 | def count(#)
262273 | self(<tail #)
263 | count(cons(A, cons(B, NIL)))
274 | count(cons(:alpha, cons(:beta, :nil)))
264275 ? tail: Not a cons cell
265276
266277 | def count(#)
267 | if eq?(#, NIL) then NIL else self(<tail #)
268 | count(cons(A, cons(B, NIL)))
269 = NIL
278 | if eq?(#, :nil) then :nil else self(<tail #)
279 | count(cons(:alpha, cons(:beta, :nil)))
280 = :nil
270281
271282 | def last(#)
272283 | if not(cons?(#)) then # else self(<tail #)
273 | last(cons(A, cons(B, GRAAAP)))
274 = GRAAAP
284 | last(cons(:alpha, cons(:beta, :graaap)))
285 = :graaap
275286
276287 | def count(#, acc)
277 | if eq?(#, NIL) then acc else self(<tail #, cons(ONE, acc))
278 | count(cons(A, cons(B, NIL)), NIL)
279 = (ONE (ONE NIL))
288 | if eq?(#, :nil) then acc else self(<tail #, cons(:one, acc))
289 | count(cons(:A, cons(:B, :nil)), :nil)
290 = (:one (:one :nil))
291
292 Functions can call other user-defined functions.
280293
281294 | def double(#)
282295 | cons(#, #)
283296 | def quadruple(#)
284297 | double(double(#))
285 | quadruple(MEOW)
286 = ((MEOW MEOW) (MEOW MEOW))
298 | quadruple(:meow)
299 = ((:meow :meow) (:meow :meow))
300
301 Functions must be defined before they are called.
287302
288303 | def quadruple(#)
289304 | double(double(#))
290305 | def double(#)
291306 | cons(#, #)
292 | MEOW
307 | :meow
293308 ? Undefined function "double"
294309
295310 Argument names may shadow previously-defined functions, because we
299314 | cons(other, #)
300315 | def snocsnoc(#, snoc)
301316 | snoc(snoc(snoc, #), #)
302 | snocsnoc(BLARCH, GLAMCH)
303 = (BLARCH (BLARCH GLAMCH))
317 | snocsnoc(:blarch, :glamch)
318 = (:blarch (:blarch :glamch))
304319
305320 | def urff(#)
306321 | self(<tail #, <head #)
307 | urff(WOOF)
322 | urff(:woof)
308323 ? Arity mismatch on self (expected 1, got 2)
309324
310325 | def urff(#, other)
311326 | self(<tail #)
312 | urff(WOOF, MOO)
327 | urff(:woof, :moo)
313328 ? Arity mismatch on self (expected 2, got 1)
314329
315330 | def urff(#)
316331 | self(cons(#, #))
317 | urff(WOOF)
332 | urff(:woof)
318333 ? Expected <smaller>, found "cons"
319334
320335 | def urff(#)
321336 | self(#)
322 | urff(GRAAAAP)
337 | urff(:graaap)
323338 ? Expected <smaller>, found "#"
324339
325340 | def urff(#, boof)
326341 | self(boof)
327 | urff(GRAAAAP, SKOOOORP)
342 | urff(:graaap, :skooorp)
328343 ? Expected <smaller>, found "boof"
329344
330345 | def urff(#, boof)
331346 | self(<tail boof)
332 | urff(GRAAAAP, SKOOOORP)
347 | urff(:graaap, :skooorp)
333348 ? Expected <smaller>, found "boof"
334349
335350 | def urff(#)
336 | self(WANGA)
337 | urff(GRAAAAP)
338 ? Expected <smaller>, found "WANGA"
339
340 | def urff(#)
341 | self(if eq?(A, A) then <head # else <tail #)
342 | urff(GRAAAAP)
351 | self(:wanga)
352 | urff(:graaap)
353 ? Expected <smaller>, found ":wanga"
354
355 | def urff(#)
356 | self(if eq?(:alpha, :alpha) then <head # else <tail #)
357 | urff(:graaap)
343358 ? Expected <smaller>, found "if"
344359
345360 | def urff(#)
346 | self(<if eq?(A, A) then <head # else <tail #)
347 | urff(GRAAAAP)
361 | self(<if eq?(:alpha, :alpha) then <head # else <tail #)
362 | urff(:graaap)
348363 ? head: Not a cons cell
349364
350365 | def urff(#)
351 | self(<if eq?(self(<head #), A) then <head # else <tail #)
352 | urff(GRAAAAP)
366 | self(<if eq?(self(<head #), :alpha) then <head # else <tail #)
367 | urff(:graaap)
353368 ? head: Not a cons cell
354369
355370 | def urff(#)
356371 | self(<if self(<tail #) then <head # else <tail #)
357 | urff(cons(GRAAAAP, FARRRRP))
372 | urff(cons(:graaap, :skooorp))
358373 ? tail: Not a cons cell
359374
360375 TODO
5454 return
5555 if self.scan_pattern(r'\(|\)|\,|\#', 'goose egg'):
5656 return
57 if self.scan_pattern(r'[A-Z]+', 'atom'):
58 return
59 if self.scan_pattern(r'[a-z]+\??', 'identifier'):
57 if self.scan_pattern(r':[a-zA-Z]+', 'atom'):
58 return
59 if self.scan_pattern(r'[a-zA-Z]+\??', 'identifier'):
6060 return
6161 if self.scan_pattern(r'\<[a-z]+', 'smallifier'):
6262 return
298298 raise TypeError("tail: Not a cons cell")
299299 elif ast.type == 'If':
300300 v1 = self.eval(ast.children[0])
301 if v1 == 'TRUE':
301 if v1 == ':true':
302302 return self.eval(ast.children[1])
303303 else:
304304 return self.eval(ast.children[2])
306306 v1 = self.eval(ast.children[0])
307307 v2 = self.eval(ast.children[1])
308308 if v1 == v2:
309 return 'TRUE'
310 else:
311 return 'FALSE'
309 return ':true'
310 else:
311 return ':false'
312312 elif ast.type == 'Cons?':
313313 v1 = self.eval(ast.children[0])
314314 if isinstance(v1, Cons):
315 return 'TRUE'
316 else:
317 return 'FALSE'
315 return ':true'
316 else:
317 return ':false'
318318 elif ast.type == 'Not':
319319 v1 = self.eval(ast.children[0])
320 if v1 == 'TRUE':
321 return 'FALSE'
322 else:
323 return 'TRUE'
320 if v1 == ':true':
321 return ':false'
322 else:
323 return ':true'
324324 elif ast.type == 'Call':
325325 fun = self.fundefs[ast.value]
326326 bindings = self.bindings