-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.py
59 lines (48 loc) · 1.59 KB
/
parse.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
'''
From Peter Novrig's "Lispy"
http://norvig.com/lispy.html
(I've written my own parsers, but it's a pain
in the ass and this one is at least as good
as any of mine.)
'''
# pylint: skip-file
# because I didn't write this!
# primary functions
def parse(program):
"Read a Scheme expression from a string."
return read_from_tokens(tokenize(program))
def schemify(exp):
"Convert a Python object back into a Scheme-readable string."
if isinstance(exp, List):
return '(' + ' '.join(map(schemify, exp)) + ')'
else:
return str(exp)
# helpers
def tokenize(chars):
"Convert a string of characters into a list of tokens."
return chars.replace('(', ' ( ').replace(')', ' ) ').split()
def read_from_tokens(tokens):
"Read an expression from a sequence of tokens."
if len(tokens) == 0:
raise SyntaxError('unexpected EOF while reading')
token = tokens.pop(0)
if '(' == token:
L = []
while tokens[0] != ')':
L.append(read_from_tokens(tokens))
tokens.pop(0) # pop off ')'
return L
elif ')' == token:
raise SyntaxError('unexpected )')
else:
return atom(token)
def atom(token):
"Numbers become numbers; every other token is a symbol."
try: return int(token)
except ValueError:
try: return float(token)
except ValueError:
return Symbol(token)
Symbol = str # A Scheme Symbol is implemented as a Python str
List = list # A Scheme List is implemented as a Python list
Number = (int, float) # A Scheme Number is implemented as a Python int or float