git @ Cat's Eye Technologies Exanoke / 78ecde6
Allow it to compile under RPython (segfaults, though) Chris Pressey 7 years ago
1 changed file(s) with 199 addition(s) and 51 deletion(s). Raw diff Collapse all Expand all
33 # ... implemented in a Questionable Manner
44
55 from optparse import OptionParser
6 import re
76 import sys
87
98
109 class AST(object):
11 def __init__(self, type, children=None, value=None):
10 def __init__(self, type, children=[], value=None, index=0, formals=[]):
1211 self.type = type
1312 self.value = value
14 if children is not None:
15 self.children = children
16 else:
17 self.children = []
13 self.index = index
14 self.formals = formals
15 self.children = []
16 for child in children:
17 self.add_child(child)
1818
1919 def add_child(self, item):
20 assert isinstance(item, AST)
2021 self.children.append(item)
2122
2223 def __repr__(self):
3435 self.type = None
3536 self.scan()
3637
37 def scan_pattern(self, pattern, type, token_group=1, rest_group=2):
38 pattern = r'^(' + pattern + r')(.*?)$'
39 match = re.match(pattern, self.text, re.DOTALL)
40 if not match:
41 return False
42 else:
38 def scan_single_char(self, chars, type):
39 text = self.text
40 token = ''
41
42 if len(text) == 0:
43 return False
44 for char in chars:
45 if text.startswith(char):
46 token += char
47 text = text[1:]
48 break
49 if token:
50 self.text = text
51 self.token = token
4352 self.type = type
44 self.token = match.group(token_group)
45 self.text = match.group(rest_group)
46 #print >>sys.stderr, "(%r/%s->%r)" % (self.token, self.type, self.text)
4753 return True
54 else:
55 return False
56
57 def scan_multi_char(self, chars, type):
58 text = self.text
59 token = ''
60 while True:
61 if len(text) == 0:
62 return False
63 found = False
64 for char in chars:
65 if text.startswith(char):
66 token += char
67 text = text[1:]
68 found = True
69 break
70 if not found:
71 if token:
72 self.text = text
73 self.token = token
74 self.type = type
75 return True
76 else:
77 return False
78
79 def scan_atom(self):
80 text = self.text
81 token = ''
82 if len(text) == 0:
83 return False
84 if text.startswith(':'):
85 token += ':'
86 text = text[1:]
87 else:
88 return False
89 while len(text) != 0 and text[0].isalpha():
90 token += text[0]
91 text = text[1:]
92 self.text = text
93 self.token = token
94 self.type = 'atom'
95 return True
96
97 def scan_smallifier(self):
98 text = self.text
99 token = ''
100 if len(text) == 0:
101 return False
102 if text.startswith('<'):
103 token += '<'
104 text = text[1:]
105 else:
106 return False
107 while len(text) != 0 and text[0].isalpha():
108 token += text[0]
109 text = text[1:]
110 self.text = text
111 self.token = token
112 self.type = 'smallifier'
113 return True
114
115 def scan_identifier(self):
116 text = self.text
117 token = ''
118 if len(text) == 0:
119 return False
120 while len(text) != 0 and (text[0].isalpha() or text[0] == '?'):
121 token += text[0]
122 text = text[1:]
123 if not token:
124 return False
125 self.text = text
126 self.token = token
127 self.type = 'identifier'
128 return True
48129
49130 def scan(self):
50 self.scan_pattern(r'[ \t\r\n]*', 'whitespace')
131 self.scan_multi_char(' \t\r\n', 'whitespace')
51132 if not self.text:
52133 self.token = None
53134 self.type = 'EOF'
54135 return
55 if self.scan_pattern(r'\(|\)|\,|\#', 'goose egg'):
136 if self.scan_single_char('(),#', 'goose egg'):
56137 return
57 if self.scan_pattern(r':[a-zA-Z]+', 'atom'):
138 if self.scan_atom():
58139 return
59 if self.scan_pattern(r'[a-zA-Z]+\??', 'identifier'):
140 if self.scan_identifier():
60141 return
61 if self.scan_pattern(r'\<[a-z]+', 'smallifier'):
142 if self.scan_smallifier():
62143 return
63 if self.scan_pattern(r'.', 'unknown character'):
64 return
65 else:
66 raise ValueError, "this should never happen, self.text=(%s)" % self.text
144 self.token = self.text[0]
145 self.text = self.text[1:]
146 self.type = 'unknown character'
67147
68148 def expect(self, token):
69149 if self.token == token:
99179 def __init__(self, text):
100180 self.scanner = Scanner(text)
101181 self.defining = None
102 self.self_arity = None
103182 self.defined = {}
104183 self.formals = None
105184
137216 self.self_arity = len(args) + 1
138217 expr = self.expr()
139218 self.defining = None
140 self.self_arity = None
141219 self.formals = None
142220 self.defined[name] = len(args) + 1
143 return AST('FunDef', [expr] + args, value=name)
221 return AST('FunDef', [expr], formals=args, value=name)
144222
145223 def expr(self):
146224 if self.scanner.consume("cons"):
201279 elif self.scanner.consume("#"):
202280 if self.defining is None:
203281 raise SyntaxError('Use of "#" outside of a function body')
204 return AST('ArgRef', value=0)
282 return AST('ArgRef', index=0)
205283 elif self.scanner.on_type("atom"):
206284 atom = self.scanner.token
207285 self.scanner.scan()
227305 'outside of a function body' % ident)
228306 if ident not in self.formals:
229307 raise SyntaxError('Undefined argument "%s"' % ident)
230 return AST('ArgRef', value=self.formals[ident])
308 return AST('ArgRef', index=self.formals[ident])
231309 else:
232310 return self.smaller()
233311
251329
252330 def smallerterm(self):
253331 if self.scanner.consume("#"):
254 return AST('ArgRef', value=0)
332 return AST('ArgRef', index=0)
255333 else:
256334 return self.smaller()
257335
258336
259337 ### Runtime ###
260338
261 class Cons(object):
339
340 class SExpr(object):
341 pass
342
343
344 class Atom(SExpr):
345 def __init__(self, text):
346 self.text = text
347
348 def __str__(self):
349 return self.text
350
351 def __repr__(self):
352 return "Atom(%r)" % self.text
353
354 def __eq__(self, other):
355 return isinstance(other, Atom) and self.text == other.text
356
357
358 class Cons(SExpr):
262359 def __init__(self, head, tail):
263360 self.head = head
264361 self.tail = tail
267364 return "(%s %s)" % (self.head, self.tail)
268365
269366 def __repr__(self):
270 return "Cons(%r,%r)" % (self.head, self.tail)
367 return "Cons(%r, %r)" % (self.head, self.tail)
368
369 def __eq__(self, other):
370 return False # isinstance(other, Cons) and self.head == other.head and self.tail == other.tail
371
372
373 class FunDef(object):
374 def __init__(self, expr, args):
375 self.expr = expr
376 self.args = args
377
378
379 TRUE = Atom(':true')
380 FALSE = Atom(':false')
271381
272382
273383 class Evaluator(object):
274384 def __init__(self, ast):
275385 self.fundefs = {}
276386 for fundef in ast.children[1:]:
277 self.fundefs[fundef.value] = {
278 'expr': fundef.children[0],
279 'args': fundef.children[1:],
280 }
387 self.fundefs[fundef.value] = FunDef(
388 fundef.children[0], fundef.children[1:]
389 )
281390 self.bindings = []
282391
283392 def eval(self, ast):
284393 if ast.type == 'Atom':
285 return ast.value
394 return Atom(ast.value)
286395 elif ast.type == 'Cons':
287396 v1 = self.eval(ast.children[0])
288397 v2 = self.eval(ast.children[1])
289398 return Cons(v1, v2)
290399 elif ast.type == 'Head':
291400 v1 = self.eval(ast.children[0])
292 try:
293 return v1.head
294 except AttributeError:
401 if not isinstance(v1, Cons):
295402 raise TypeError("head: Not a cons cell")
403 return v1.head
296404 elif ast.type == 'Tail':
297405 v1 = self.eval(ast.children[0])
298406 try:
301409 raise TypeError("tail: Not a cons cell")
302410 elif ast.type == 'If':
303411 v1 = self.eval(ast.children[0])
304 if v1 == ':true':
412 if v1 == TRUE:
305413 return self.eval(ast.children[1])
306414 else:
307415 return self.eval(ast.children[2])
309417 v1 = self.eval(ast.children[0])
310418 v2 = self.eval(ast.children[1])
311419 if v1 == v2:
312 return ':true'
420 return TRUE
313421 else:
314 return ':false'
422 return FALSE
315423 elif ast.type == 'Cons?':
316424 v1 = self.eval(ast.children[0])
317425 if isinstance(v1, Cons):
318 return ':true'
426 return TRUE
319427 else:
320 return ':false'
428 return FALSE
321429 elif ast.type == 'Not':
322430 v1 = self.eval(ast.children[0])
323 if v1 == ':true':
324 return ':false'
431 if v1 == TRUE:
432 return FALSE
325433 else:
326 return ':true'
434 return TRUE
327435 elif ast.type == 'Call':
328 fun = self.fundefs[ast.value]
436 fundef = self.fundefs[ast.value]
329437 bindings = self.bindings
330438 self.bindings = [self.eval(expr) for expr in ast.children]
331 result = self.eval(fun['expr'])
439 result = self.eval(fundef.expr)
332440 self.bindings = bindings
333441 return result
334442 elif ast.type == 'ArgRef':
335 return self.bindings[ast.value]
443 return self.bindings[ast.index]
336444 elif ast.type == 'Program':
337445 return self.eval(ast.children[0])
338446 else:
378486 sys.exit(0)
379487
380488
489 def target(*args):
490 import os
491
492 def rpython_load(filename):
493 fd = os.open(filename, os.O_RDONLY, 0644)
494 text = ''
495 chunk = os.read(fd, 1024)
496 text += chunk
497 while len(chunk) == 1024:
498 chunk = os.read(fd, 1024)
499 text += chunk
500 os.close(fd)
501 return text
502
503 def rpython_input():
504 accum = ''
505 done = False
506 while not done:
507 s = os.read(1, 1)
508 if not s:
509 done = True
510 accum += s
511 return accum
512
513 def rpython_main(argv):
514 #inp = rpython_input()
515 #if not inp:
516 # inp = 'ifeq'
517 text = rpython_load(argv[1])
518 p = Parser(text)
519 prog = p.program()
520 print "%r" % prog
521 ev = Evaluator(prog)
522 result = ev.eval(prog)
523 print "%r" % result
524 return 0
525
526 return rpython_main, None
527
528
381529 if __name__ == "__main__":
382530 main(sys.argv)