You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
472 lines
13 KiB
472 lines
13 KiB
TOK = {LPAREN = 1, RPAREN = 2, INT = 3, BOOL = 4, NAME = 5, QUOTE = 6, EOF = 7}
|
|
keys = []
|
|
for k in TOK do keys:insert(#keys, k) end
|
|
for k in keys do TOK[TOK[k]]=k end
|
|
|
|
token = {
|
|
new = func (type, value)
|
|
return {type = type, value = value, __index = token}
|
|
end,
|
|
pretty = func(self)
|
|
tname = TOK[self.type]
|
|
tval = tostring(self.value)
|
|
return '{'+tname+':'+tval+'}'
|
|
end
|
|
}
|
|
|
|
tokenizer = {
|
|
WS = " "+chr(8)+chr(9)+chr(10),
|
|
NAMESET = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ=+-*/.<>?!@$%^~",
|
|
DIGITS = "0123456789",
|
|
EOF = {},
|
|
new = func (str)
|
|
res = {str = str, pushed = None, __index = tokenizer}
|
|
res:init()
|
|
return res
|
|
end,
|
|
init = func(self)
|
|
--print('In init, self is', self)
|
|
res.cur = res:token()
|
|
res.next = res:token()
|
|
end,
|
|
next_char = func(self)
|
|
if self.pushed == None then
|
|
--print('In next_char, self is', self)
|
|
--print('In next_char, self.str is', self.str)
|
|
if self.str:eof() then return self.EOF end
|
|
res = self.str:read(1)
|
|
else
|
|
--print('Retrieving from pushback', self.pushed)
|
|
res = self.pushed[0]
|
|
self.pushed = self.pushed:sub(1)
|
|
if self.pushed == "" then self.pushed = None end
|
|
end
|
|
--print(res)
|
|
return res
|
|
end,
|
|
push_back = func(self, s)
|
|
--print('Pushing back', s)
|
|
if s == self.EOF then print('WARNING: Attempted to push_back EOF'); return end
|
|
if self.pushed == None then
|
|
self.pushed = s
|
|
else
|
|
self.pushed = s + self.pushed
|
|
end
|
|
--print('self.pushed:', self.pushed)
|
|
end,
|
|
token = func (self)
|
|
--print('In token, self is', self)
|
|
--print('In token, self.str is', self.str)
|
|
c = self:next_char()
|
|
while !(c == self.EOF) do
|
|
if c == "" then return token.new(TOK.EOF, None) end
|
|
if c == "(" then return token.new(TOK.LPAREN, c) end
|
|
if c == ")" then return token.new(TOK.RPAREN, c) end
|
|
if self.NAMESET:find(c) >= 0 then
|
|
--print('{NAME}')
|
|
name = c
|
|
c = self:next_char()
|
|
while 1 do
|
|
found = 0
|
|
if self.NAMESET:find(c) >= 0 then found = 1 end
|
|
if self.DIGITS:find(c) >= 0 then found = 1 end
|
|
if !found then break end
|
|
name += c
|
|
c = self:next_char()
|
|
if c == self.EOF then continue end
|
|
end
|
|
self:push_back(c)
|
|
return token.new(TOK.NAME, name)
|
|
end
|
|
if self.DIGITS:find(c) >= 0 then
|
|
val = c
|
|
c = self:next_char()
|
|
while self.DIGITS:find(c) >= 0 do
|
|
val += c
|
|
c = self:next_char()
|
|
if c == self.EOF then continue end
|
|
end
|
|
self:push_back(c)
|
|
return token.new(TOK.INT, toint(val))
|
|
end
|
|
if c == "#" then
|
|
c = self:next_char()
|
|
if c == "t" then return token.new(TOK.BOOL, 1) end
|
|
if c == "f" then return token.new(TOK.BOOL, 0) end
|
|
error("Invalid value for bool literal: "+c)
|
|
end
|
|
if c == "'" then return token.new(TOK.QUOTE, c) end
|
|
if self.WS:find(c) >= 0 then
|
|
c = self:next_char()
|
|
continue
|
|
end
|
|
if c == ";" then
|
|
c = self:next_char()
|
|
while 1 do
|
|
if c == chr(10) then break end
|
|
c = self:next_char()
|
|
end
|
|
c = self:next_char()
|
|
continue
|
|
end
|
|
error("Invalid character in token stream: "+c)
|
|
end
|
|
return token.new(TOK.EOF, None)
|
|
end,
|
|
advance = func(self)
|
|
self.cur = self.next
|
|
self.next = self:token()
|
|
end
|
|
}
|
|
|
|
|
|
|
|
ttreegen = {
|
|
new = func(tok)
|
|
return {tok = tok, __index = ttreegen}
|
|
end,
|
|
generate = func(self, consume)
|
|
res = self.TT_DISPATCH[self.tok.cur.type](self, self.tok.cur)
|
|
if None == consume then self.tok:advance() end
|
|
return res
|
|
end,
|
|
TT_DISPATCH = {
|
|
[TOK.LPAREN] = func(self, tok)
|
|
toklist = []
|
|
self.tok:advance()
|
|
tok = self.tok.cur
|
|
while 1 do
|
|
if tok.type == TOK.RPAREN then break end
|
|
if tok.type == TOK.EOF then error('Encountered EOF while matching delimiter') end
|
|
toklist:insert(#toklist, self.TT_DISPATCH[tok.type](self, tok))
|
|
self.tok:advance()
|
|
tok = self.tok.cur
|
|
end
|
|
return toklist
|
|
end,
|
|
[TOK.RPAREN] = func(self, tok)
|
|
error("Unexpected right parenthesis")
|
|
end,
|
|
[TOK.INT] = func(self, tok)
|
|
return tok
|
|
end,
|
|
[TOK.BOOL] = func(self, tok)
|
|
return tok
|
|
end,
|
|
[TOK.NAME] = func(self, tok)
|
|
return tok
|
|
end,
|
|
[TOK.QUOTE] = func(self, tok)
|
|
self.tok:advance()
|
|
tok.quoting = self:generate(0)
|
|
return tok
|
|
end,
|
|
[TOK.EOF] = func(self, tok)
|
|
return None
|
|
end
|
|
}
|
|
}
|
|
|
|
EX = {CALL=1, ASSIGN=2, FUNCDECL=3, SCOPE=4, IFELSE=5, DATUM=6, LIT=7, REF=8, LIST=9}
|
|
keys = []
|
|
for k in EX do keys:insert(#keys, k) end
|
|
for k in keys do EX[EX[k]]=k end
|
|
|
|
node = {
|
|
new = func(type, value)
|
|
return {type=type, value=value, __index=node}
|
|
end,
|
|
pretty = func(self) return self.PRETTY_DISPATCH[self.type](self) end
|
|
PRETTY_DISPATCH = {
|
|
[EX.CALL] = func(self)
|
|
return '<CALL NAME='+(self.value.name)+' ARGS='+tostring(self.value.args:copy():map(func(i) if !(None == i) then return i:pretty() else return tostring(i) end end))+'>'
|
|
end,
|
|
[EX.ASSIGN] = func(self)
|
|
return '<ASSIGN NAME='+(self.value.name)+' VALUE='+(self.value.value:pretty())+'>'
|
|
end,
|
|
[EX.FUNCDECL] = func(self)
|
|
return '<FUNCDECL PARAMS='+tostring(self.value.params)+' BODY='+(self.value.body:pretty())+'>'
|
|
end,
|
|
[EX.SCOPE] = func(self)
|
|
return '<SCOPE '+(self.value:copy():map(func(i) return i:pretty() end))+'>'
|
|
end,
|
|
[EX.IFELSE] = func(self)
|
|
return '<IFELSE COND='+(self.value.cond:pretty())+' IFT='+(self.value.ift:pretty())+' IFF='+(self.value.iff:pretty())+'>'
|
|
end,
|
|
[EX.DATUM] = func(self)
|
|
return '#'+tostring(self.value)
|
|
end,
|
|
[EX.LIT] = func(self)
|
|
if type(self.value) == 'list' then
|
|
return '/'+tostring(self.value:copy():map(func(i) return i:pretty() end))
|
|
end
|
|
return '/'+tostring(self.value)
|
|
end,
|
|
[EX.REF] = func(self)
|
|
--print('In EX.REF, self is', self)
|
|
res = '@'+tostring(self.value)
|
|
--print('In EX.REF, returning', res)
|
|
return res
|
|
end,
|
|
[EX.LIST] = func(self)
|
|
--print('In EX.LIST, self is', self)
|
|
return '<LIST '+(self.value:copy():map(func(i) return i:pretty() end))+'>'
|
|
end
|
|
}
|
|
}
|
|
|
|
parser = {
|
|
new = func(ttgen)
|
|
return {ttgen = ttgen, __index = parser}
|
|
end,
|
|
parse = func(self, tt)
|
|
if type(tt) == 'map' then
|
|
--print('In parse, self is', self)
|
|
--print('In parse, tt is', tt)
|
|
--print('In parse, dispatch to', self.TT_PARSE_DISPATCH[tt.type])
|
|
res = self.TT_PARSE_DISPATCH[tt.type](self, tt)
|
|
else
|
|
name = tt[0]
|
|
if !(name.type == TOK.NAME) then
|
|
error('Expected name as first element of expression-list')
|
|
end
|
|
rest = tt:copy()
|
|
rest:remove(0)
|
|
sc = self.SCALL_DISPATCH[name.value]
|
|
if !(None == sc) then
|
|
sc = None
|
|
res = self.SCALL_DISPATCH[name.value](self, rest)
|
|
else
|
|
res = node.new(EX.CALL, {name=name.value, args=rest:map(func(i) return self:parse(i) end)})
|
|
end
|
|
end
|
|
--print('In parse, returning', res:pretty())
|
|
return res
|
|
end,
|
|
TT_PARSE_DISPATCH = {
|
|
[TOK.INT] = func(self, tok)
|
|
return node.new(EX.LIT, tok.value)
|
|
end,
|
|
[TOK.BOOL] = func(self, tok)
|
|
return node.new(EX.LIT, tok.value)
|
|
end,
|
|
[TOK.NAME] = func(self, tok)
|
|
--print('In TOK.NAME, tok is', tok)
|
|
res = node.new(EX.REF, tok.value)
|
|
--print('In TOK.NAME, returning', res)
|
|
return res
|
|
end,
|
|
[TOK.QUOTE] = func(self, tok)
|
|
return self:parse_datum(tok.quoting)
|
|
end
|
|
},
|
|
SCALL_DISPATCH = {
|
|
define = func(self, args)
|
|
name = args[0]
|
|
if !(name.type == TOK.NAME) then error('Define: expected name as first argument') end
|
|
value = self:parse(args[1])
|
|
return node.new(EX.ASSIGN, {name=name.value, value=value})
|
|
end,
|
|
["if"] = func(self, args)
|
|
cond = self:parse(args[0])
|
|
ift = self:parse(args[1])
|
|
iff = self:parse(args[2])
|
|
return node.new(EX.IFELSE, {cond=cond, ift=ift, iff=iff})
|
|
end,
|
|
begin = func(self, args)
|
|
args:map(func(i) return self:parse(i) end)
|
|
return node.new(EX.LIST, args)
|
|
end,
|
|
lambda = func(self, args)
|
|
--print('Lambda args:', args)
|
|
params = args[0]
|
|
if !(type(params) == 'list') then error('Lambda: expected parameters as first argument (got '+tostring(params)+')') end
|
|
params:map(func(i)
|
|
if !(type(i) == 'map') then error('Lambda: expected name token in argument list (got sublist)') end
|
|
if !(i.type == TOK.NAME) then error('Lambda: expected name token in argument list (got '+(i:pretty())+')') end
|
|
return i.value
|
|
end)
|
|
body = args:copy()
|
|
body:remove(0)
|
|
--print('Lambda body:', body)
|
|
body:map(func(i) return self:parse(i) end)
|
|
return node.new(EX.FUNCDECL, {params=params, body=node.new(EX.LIST, body)})
|
|
end,
|
|
let = func(self, args)
|
|
defs = args[0]
|
|
if !(type(defs) == 'list') then error('Let: expected list of bindings are first argument') end
|
|
defs:map(func(i)
|
|
if !(type(i) == 'list') then error('Let: expected a binding entry') end
|
|
return self.SCALL_DISPATCH.define(self, i)
|
|
end)
|
|
body = args:copy()
|
|
body:remove(0)
|
|
body:map(func(i) return self:parse(i) end)
|
|
return node.new(EX.SCOPE, defs+body)
|
|
end,
|
|
letrec = func(self, args)
|
|
defs = args[0]
|
|
if !(type(defs) == 'list') then error('Let: expected list of bindings are first argument') end
|
|
defs:map(func(i)
|
|
if !(type(i) == 'list') then error('Let: expected a binding entry') end
|
|
return self.SCALL_DISPATCH.define(self, i)
|
|
end)
|
|
body = args:copy()
|
|
body:remove(0)
|
|
body:map(func(i) return self:parse(i) end)
|
|
return node.new(EX.LIST, defs+body)
|
|
end
|
|
}
|
|
parse_datum = func(self, tt)
|
|
if type(tt) == 'map' then
|
|
return self.TT_PARSE_DATUM_DISPATCH[tt.type](self, tt)
|
|
else
|
|
list = []
|
|
for tok in tt do
|
|
list:insert(#list, self:parse_datum(tok))
|
|
end
|
|
return node.new(EX.LIT, list)
|
|
end
|
|
end,
|
|
TT_PARSE_DATUM_DISPATCH = {
|
|
[TOK.INT] = func(self, tok)
|
|
return node.new(EX.LIT, tok.value)
|
|
end,
|
|
[TOK.BOOL] = func(self, tok)
|
|
return node.new(EX.LIT, tok.value)
|
|
end,
|
|
[TOK.NAME] = func(self, tok)
|
|
return node.new(EX.LIT, tok.value)
|
|
end,
|
|
[TOK.QUOTE] = func(self, tok)
|
|
return self:parse(tok.quoting)
|
|
end
|
|
},
|
|
run = func(self)
|
|
tt = self.ttgen:generate()
|
|
list = []
|
|
while 1 do
|
|
if None == tt then break end
|
|
--if type(tt) == 'list' then
|
|
list:insert(#list, self:parse(tt))
|
|
--end
|
|
tt = self.ttgen:generate()
|
|
end
|
|
--print('In run, list is', list)
|
|
return node.new(EX.LIST, list)
|
|
end
|
|
}
|
|
|
|
converter = {
|
|
new = func(p)
|
|
return {parser=p, __index = converter}
|
|
end,
|
|
make = func(self, node)
|
|
--print('In make, node is a', EX[node.type], 'of value', node)
|
|
res = self.MAKE_DISPATCH[node.type](self, node)
|
|
--print('In make, returning', res)
|
|
if type(res) == "astnode" then ast.print(res) end
|
|
return res
|
|
end,
|
|
MAKE_DISPATCH = {
|
|
[EX.CALL] = func(self, node)
|
|
e = parse('f()').stmtlist[0].expr
|
|
e.expr.ident = node.value.name
|
|
args = node.value.args:copy():map(func(i) return self:make(i) end)
|
|
--print('In EX.CALL, replacement args are', args)
|
|
e.args = args
|
|
--print('In EX.CALL, args are', e.args)
|
|
return e
|
|
end,
|
|
[EX.ASSIGN] = func(self, node)
|
|
e = parse('a = b').stmtlist[0].expr
|
|
e.ident = node.value.name
|
|
e.value = self:make(node.value.value)
|
|
return e
|
|
end,
|
|
[EX.FUNCDECL] = func(self, node)
|
|
e = parse('func() None None end').stmtlist[0].expr
|
|
params = node.value.params
|
|
--print('In EX.FUNCDECL, params are', params)
|
|
e.args = params
|
|
--print('In EX.FUNCDECL, args are', e.args)
|
|
e.body.stmtlist = self:make(node.value.body)
|
|
return e
|
|
end,
|
|
[EX.SCOPE] = func(self, node)
|
|
e = parse('(func() None None end)()').stmtlist[0].expr
|
|
node.type = EX.LIST
|
|
e.expr.body.stmtlist = self:make(node)
|
|
node.type = EX.SCOPE
|
|
return e
|
|
end,
|
|
[EX.IFELSE] = func(self, node)
|
|
e = parse('(func() if None then return None else return None end end)()').stmtlist[0].expr
|
|
e.expr.body.stmtlist[0].cond = self:make(node.value.cond)
|
|
e.expr.body.stmtlist[0].iftrue.stmtlist[0].ret = self:make(node.value.ift)
|
|
e.expr.body.stmtlist[0].iffalse.stmtlist[0].ret = self:make(node.value.iff)
|
|
return e
|
|
end,
|
|
[EX.DATUM] = func(self, node) error('EX.DATUM: Not implemented') end,
|
|
[EX.LIT] = func(self, node)
|
|
if type(node.value) == 'list' then
|
|
e = parse('[None]').stmtlist[0].expr
|
|
e.list = node.value:copy():map(func(i) return self:make(i) end)
|
|
else
|
|
e = parse('None').stmtlist[0].expr
|
|
if type(node.value) == "int" then
|
|
e.littype = ast.LIT_INT
|
|
e.ival = node.value
|
|
end
|
|
if type(node.value) == "string" then
|
|
e.littype = ast.LIT_STRING
|
|
e.str = node.value
|
|
end
|
|
end
|
|
return e
|
|
end,
|
|
[EX.REF] = func(self, node)
|
|
e = parse('a').stmtlist[0].expr
|
|
e.ident = node.value
|
|
return e
|
|
end,
|
|
[EX.LIST] = func(self, node)
|
|
e = parse('func() None end').stmtlist[0].expr
|
|
l = node.value:copy()
|
|
l:map(func(i)
|
|
s = parse('None').stmtlist[0]
|
|
s.expr = self:make(i)
|
|
return s
|
|
end)
|
|
lastidx = (#l) - 1
|
|
r = parse('return None').stmtlist[0]
|
|
r.ret = l[lastidx].expr
|
|
l[lastidx] = r
|
|
--print('In EX.LIST, e is now' e)
|
|
e.body.stmtlist = l
|
|
return e.body.stmtlist
|
|
end
|
|
},
|
|
run = func(self)
|
|
list = self:make(self.parser:run())
|
|
res = parse('(func() None None end)()')
|
|
--print('In run, list is', list)
|
|
--for i in list do ast.print(i) end
|
|
res.stmtlist[0].expr.expr.body.stmtlist = list
|
|
return res
|
|
end
|
|
}
|
|
|
|
_G = debug.globals()
|
|
_G['+'] = func(a, b) return a + b end
|
|
_G['-'] = func(a, b) return a - b end
|
|
_G['*'] = func(a, b) return a * b end
|
|
_G['/'] = func(a, b) return a / b end
|
|
_G['<'] = func(a, b) return a < b end
|
|
_G['>'] = func(a, b) return a > b end
|
|
_G['<='] = func(a, b) return a <= b end
|
|
_G['>='] = func(a, b) return a >= b end
|
|
_G['=='] = func(a, b) return a == b end
|
|
_G['eq'] = _G['==']
|
|
_G['or'] = func(a, b) return a || b end
|
|
_G['and'] = func(a, b) return a && b end
|