-
Notifications
You must be signed in to change notification settings - Fork 0
/
lithon.py
executable file
·136 lines (104 loc) · 3.58 KB
/
lithon.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
#!/usr/bin/env python
from codetalker.pgm import Grammar, Translator
from codetalker.pgm.special import star, plus, _or, commas
from codetalker.pgm.tokens import STRING, NUMBER, EOF, NEWLINE, WHITE, ReToken, re, CharToken, StringToken
import os,sys
import re
import nodes
'''
A simple lisp that compiles to Python.
Mainly for educational purposes
'''
# special tokens
class SYMBOL(CharToken):
chars = '\'()[]'
num = 5
class ID(ReToken):
rx = re.compile("[a-zA-Z\_\+\-\*\/\=\<\>]*")
class BOOL(StringToken):
strings = ['#t','#f']
# rules
def program(rule):
rule | (star(_or(expression,NEWLINE)),EOF)
rule.astAttrs = {'body': [expression]}
program.astName = 'Program'
def expression(rule):
rule | quote | define | defvar | anon | if_ | sexp | ID | STRING | NUMBER | BOOL
rule.pass_single = True
def quote(rule):
rule | ('\'','(',star(expression),')')
rule.astAttrs = {'values':[expression]}
quote.astName = 'Quote'
def define(rule):
rule | ('(','define','(',ID,star(ID),')',plus(expression),')')
rule.astAttrs = {'args': [ID], 'body': [expression]}
define.astName = 'Define'
def defvar(rule):
rule | ('(','define',ID,expression,')')
rule.astAttrs = {'ident': [ID], 'val': expression}
defvar.astName = 'Defvar'
def anon(rule):
rule | ('(','lambda','(',star(ID),')',expression,')')
rule.astAttrs = {'args': [ID], 'body': expression}
anon.astName = 'Anon'
def if_(rule):
rule | ('(','if',expression,expression,expression,')')
rule.astAttrs = {'expressions':[expression]}
if_.astName = 'If'
def sexp(rule):
rule | ('(',ID,star(expression),')') | ('(',star(expression),')')
rule.astAttrs = {'function': ID, 'args': [expression]}
sexp.astName = 'Sexp'
grammar = Grammar(start=program,
tokens=[SYMBOL],
ignore=[WHITE, NEWLINE],
ast_tokens=[ID, STRING, NUMBER, BOOL])
# translation
Lithon = Translator(grammar)
ast = grammar.ast_classes
elements = []
@Lithon.translates(ast.Program)
def t_program(node):
for exp in node.body: elements.append(Lithon.translate(exp))
@Lithon.translates(ast.Quote)
def t_quote(node):
return nodes.Quote([Lithon.translate(v) for v in node.values])
@Lithon.translates(ast.Define)
def t_define(node):
return nodes.Define(node.args[1],node.args[2:],[Lithon.translate(exp) for exp in node.body])
@Lithon.translates(ast.Defvar)
def t_defvar(node):
return nodes.Defvar(node.ident[1],Lithon.translate(node.val))
@Lithon.translates(ast.Anon)
def t_anon(node):
return nodes.Anon(node.args[1:],Lithon.translate(node.body))
@Lithon.translates(ast.If)
def t_if(node):
return nodes.If([Lithon.translate(e) for e in node.expressions])
@Lithon.translates(ast.Sexp)
def t_sexp(node):
return nodes.Sexp(node.function,[Lithon.translate(arg) for arg in node.args])
@Lithon.translates(ID)
def t_id(node):
return nodes.Id(node.value)
@Lithon.translates(STRING)
def t_string(node):
return nodes.String(node.value)
@Lithon.translates(NUMBER)
def t_number(node):
return nodes.Number(node.value)
@Lithon.translates(BOOL)
def t_bool(node):
return nodes.Bool(node.value)
input_file = sys.argv[1]
output_file = re.match("(.+)\.",sys.argv[1]).group()+"py"
Lithon.from_string(open(input_file,'r').read())
f = open(output_file,'w')
f.write("from fractions import Fraction # Might eventually be optional\n\n")
for e in elements:
print "VISITING: %s" % e.__class__
f.write("print %s\n" % e) if (e.__class__ == nodes.Sexp or e.__class__ == nodes.Id) else f.write("%s\n" % e)
f.close()
print "Compiled!"
print "Executing %s ..." % output_file
os.system("python %s" % output_file)