-
Notifications
You must be signed in to change notification settings - Fork 0
/
axio.py
186 lines (160 loc) · 4.54 KB
/
axio.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
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# axio
# PeckJ 20121206
#
from funcparserlib.lexer import make_tokenizer, Token, LexerError
from funcparserlib.parser import (some, many, finished, skip,
with_forward_decls, oneplus,
NoParseError)
from funcparserlib.util import pretty_tree
import sys, getopt
######################
## globals
axio_version = "20121206"
axio_symbol_lookup_table = {}
######################
## lexer
def tokenize(str):
'str -> Sequence(Token)'
specs = [
('comment', (r'//.*',)),
('newline', (r'[\r\n]+',)),
('space', (r'[ \t\r\n]+',)),
('number', (r'-?(\.[0-9]+)|([0-9]+(\.[0-9]*)?)',)),
('name', (r'([A-Za-z\200-\377_0-9]|!|\$|%|&|\*|\+|-|/|\?|=|\<|\>)+',)),
('kw_bind', (r'#bind',)),
('kw_halt', (r'#halt',)),
('op_lambda', (r'\\',)),
('op_map', (r'::',)),
('form_open', (r'\(',)),
('form_close', (r'\)',))
]
useless = ['comment', 'space', 'newline']
t = make_tokenizer(specs)
return [x for x in t(str) if x.type not in useless]
def tokenizefile(f):
try:
return tokenize(open(f, 'r').read())
except LexerError as e:
print e.__unicode__()
sys.exit()
######################
## parser
## grammar:
# prog ::= exp*
#
# lam ::= "(" "\" var+ "::" exp ")"
#
# exp ::= lam
# | var
# | prim_exp
# | "(" exp+ ")"
#
# prim_exp ::= "(" "#bind" var exp ")"
# | "(" "#halt" exp ")"
##
tokval = lambda tok: tok.value
toktype = lambda type: lambda tok: tok.type == type
make_number = lambda str: float(str)
def flatten(x):
result = []
for el in x:
if hasattr(el, "__iter__") and not isinstance(el, basestring):
result.extend(flatten(el))
else:
result.append(el)
return result
class Grouping(object):
def __init__(self, kids):
self.kids = list(flatten([kids]))
class Lambda(Grouping): pass
class Form(Grouping): pass
class Expression(Grouping): pass
class Program(Grouping): pass
def parse(tokens):
var = some(toktype("name")) | some(toktype("number"))
open_form = some(toktype("form_open"))
close_form = some(toktype("form_close"))
op_lambda = some(toktype("op_lambda"))
op_map = some(toktype("op_map"))
prim_bind = some(toktype("kw_bind"))
prim_halt = some(toktype("kw_halt"))
exp = with_forward_decls(lambda: lam | var | prim_exp | exprn) >> Expression
lam = open_form + op_lambda + many(var) + op_map + oneplus(exp) + close_form >> Lambda
bind_exp = open_form + prim_bind + var + lam + close_form
halt_exp = open_form + prim_halt + exp + close_form
prim_exp = bind_exp | halt_exp
exprn = open_form + oneplus(exp) + close_form >> Form
prog = many(exp) + skip(finished) >> Program
return prog.parse(tokens)
def pprint(tree):
def kids(x):
if isinstance(x, Grouping):
return x.kids
else:
return []
def show(x):
if isinstance(x, Lambda):
return '{Lambda}'
elif isinstance(x, Form):
return '{Form}'
elif isinstance(x, Expression):
return '{Expression}'
elif isinstance(x, Program):
return '{Program}'
else:
return tokval(x)
return pretty_tree(tree, kids, show)
######################
## interpreter
def usage():
print "usage: python axio.py [-p] <filename.axio>"
print " python axio.py -v"
print " python axio.py -h"
print " -p: pretty-print a parse tree and exit"
print " -v: display version info and exit"
print " -h: display this help text and exit"
def version():
global axio_version
print "axio version %s" % axio_version
print "Jacob Peck (suspended-chord)"
print "http://github.com/gatesphere/axio"
if __name__ == "__main__":
args = sys.argv[1:]
try:
opts, args = getopt.getopt(args, 'pvh')
except:
usage()
sys.exit()
ptree, pversion, phelp = False, False, False
for opt, a in opts:
if opt == '-p': ptree = True
elif opt == '-v': pversion = True
elif opt == '-h': phelp = True
if pversion:
version()
sys.exit()
if len(args) != 1 or phelp:
usage()
sys.exit()
filename = args[0]
if ptree:
try:
print pprint(parse(tokenizefile(filename)))
except NoParseError as e:
print "Could not parse file:"
print e.msg
sys.exit()
## actual logic
try:
tree = parse(tokenizefile(filename))
except NoParseError as e:
print "Could not parse file:"
print e.msg
sys.exit()
try:
# tree = CyprusProgram(tree)
# tree.run()
pass
except Exception as e:
print e.message
sys.exit()