Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lua: merge evalAST and fix remaining tests #664

Merged
merged 12 commits into from
Aug 26, 2024
31 changes: 9 additions & 22 deletions impls/lua/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM ubuntu:18.04
FROM ubuntu:24.04
MAINTAINER Joel Martin <github@martintribe.org>

##########################################################
Expand All @@ -9,10 +9,8 @@ MAINTAINER Joel Martin <github@martintribe.org>
RUN apt-get -y update

# Required for running tests
RUN apt-get -y install make python

# Some typical implementation and test requirements
RUN apt-get -y install curl libreadline-dev libedit-dev
RUN apt-get -y install make python3
RUN ln -fs /usr/bin/python3 /usr/local/bin/python

RUN mkdir -p /mal
WORKDIR /mal
Expand All @@ -21,23 +19,12 @@ WORKDIR /mal
# Specific implementation requirements
##########################################################

# Lua
RUN apt-get -y install gcc wget unzip libpcre3-dev

RUN \
curl -R -O http://www.lua.org/ftp/lua-5.3.5.tar.gz && \
tar -zxf lua-5.3.5.tar.gz && \
cd lua-5.3.5 && \
make linux test && \
make install

RUN \
wget https://luarocks.org/releases/luarocks-3.3.1.tar.gz && \
tar zxpf luarocks-3.3.1.tar.gz && \
cd luarocks-3.3.1 && \
./configure && \
make && \
make install
# luarocks 3.8.0+dfsg1-1 only supports 5.1 5.2 5.3,
# and its dependencies default on 5.1 if no version is available.
# Explicitly install the desired version before luarocks.
RUN apt-get -y install liblua5.3-dev lua5.3

RUN apt-get -y install gcc libpcre3-dev luarocks

# luarocks .cache directory is relative to HOME
ENV HOME /mal
23 changes: 9 additions & 14 deletions impls/lua/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@ SOURCES_BASE = utils.lua types.lua reader.lua printer.lua
SOURCES_LISP = env.lua core.lua stepA_mal.lua
SOURCES = $(SOURCES_BASE) $(SOURCES_LISP)

all: libs
libraries := linenoise.so rex_pcre.so
linenoise.so_package := linenoise
rex_pcre.so_package := lrexlib-pcre

all: $(libraries)

dist: mal.lua mal

Expand All @@ -21,19 +25,10 @@ mal: mal.lua
cat $< >> $@
chmod +x $@


clean:
rm -f linenoise.so rex_pcre.so mal.lua mal
rm -f $(libraries) mal.lua mal
rm -rf lib

.PHONY: libs
libs: linenoise.so rex_pcre.so

linenoise.so:
luarocks install --tree=./ linenoise
ln -sf $$(find . -name linenoise.so) $@

rex_pcre.so:
luarocks install --tree=./ lrexlib-pcre
ln -sf $$(find . -name rex_pcre.so) $@

$(libraries):
luarocks install --tree=./ $($@_package)
find . -name $@ | xargs ln -s
22 changes: 7 additions & 15 deletions impls/lua/core.lua
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,21 @@ local M = {}
-- string functions

function pr_str(...)
return table.concat(
utils.map(function(e) return _pr_str(e, true) end,
table.pack(...)), " ")
return printer._pr_seq(table.pack(...), true, " ")
end

function str(...)
return table.concat(
utils.map(function(e) return _pr_str(e, false) end,
table.pack(...)), "")
return printer._pr_seq(table.pack(...), false, "")
end

function prn(...)
print(table.concat(
utils.map(function(e) return _pr_str(e, true) end,
table.pack(...)), " "))
print(printer._pr_seq(table.pack(...), true, " "))
io.flush()
return Nil
end

function println(...)
print(table.concat(
utils.map(function(e) return _pr_str(e, false) end,
table.pack(...)), " "))
print(printer._pr_seq(table.pack(...), false, " "))
io.flush()
return Nil
end
Expand Down Expand Up @@ -107,7 +99,7 @@ function concat(...)
end

function vec(a)
return types.Vector:new(a)
return types.Vector:new(types.copy(a))
end

function nth(seq, idx)
Expand Down Expand Up @@ -253,12 +245,12 @@ M.ns = {
['number?'] = function(a) return types._number_Q(a) end,
symbol = function(a) return types.Symbol:new(a) end,
['symbol?'] = function(a) return types._symbol_Q(a) end,
['string?'] = function(a) return types._string_Q(a) and "\u{029e}" ~= string.sub(a,1,2) end,
['string?'] = function(a) return types._string_Q(a) end,
keyword = function(a)
if types._keyword_Q(a) then
return a
else
return "\u{029e}"..a
return types._keyword_from_lua_string(a)
end
end,
['keyword?'] = function(a) return types._keyword_Q(a) end,
Expand Down
53 changes: 28 additions & 25 deletions impls/lua/env.lua
Original file line number Diff line number Diff line change
@@ -1,52 +1,55 @@
local rex = require('rex_pcre')
local string = require('string')
local table = require('table')
local utils = require('utils')
local types = require('types')
local printer = require('printer')

local Env = {}

function Env:new(outer, binds, exprs)
-- binds is a MAL sequence of MAL symbols
-- exprs is an LUA table of MAL forms
local data = {}
local newObj = {outer = outer, data = data}
self.__index = self
if binds then
for i, b in ipairs(binds) do
if binds[i].val == '&' then
local new_exprs = types.List:new()
for j = i, #exprs do
table.insert(new_exprs, exprs[j])
end
table.remove(exprs, 1)
data[binds[i+1].val] = new_exprs
data[binds[i+1].val] = types.List.slice(exprs, i)
break
end
data[binds[i].val] = exprs[i]
end
end
return setmetatable(newObj, self)
end
function Env:find(sym)
if self.data[sym.val] ~= nil then
return self
else
if self.outer ~= nil then
return self.outer:find(sym)
else
return nil
end

function Env:get(sym)
-- sym is an LUA string
-- returns nil if the key is not found
local env = self
local result
while true do
result = env.data[sym]
if result ~= nil then return result end
env = env.outer
if env == nil then return nil end
end
end

function Env:set(sym,val)
self.data[sym.val] = val
-- sym is an LUA string
self.data[sym] = val
return val
end
function Env:get(sym)
local env = self:find(sym)
if env then
return env.data[sym.val]
else
types.throw("'"..sym.val.."' not found")

function Env:debug()
local env = self
while env.outer ~=nil do
line = ' ENV:'
for k, v in pairs(env.data) do
line = line .. ' ' .. k .. '=' .. printer._pr_str(v)
end
print(line)
env = env.outer
end
end

Expand Down
28 changes: 15 additions & 13 deletions impls/lua/printer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,30 @@ local utils = require('utils')
local M = {}

function M._pr_str(obj, print_readably)
local _r = print_readably
if utils.instanceOf(obj, types.Symbol) then
return obj.val
elseif types._list_Q(obj) then
return "(" .. table.concat(utils.map(function(e)
return M._pr_str(e,_r) end, obj), " ") .. ")"
return "(" .. M._pr_seq(obj, print_readably, " ") .. ")"
elseif types._vector_Q(obj) then
return "[" .. table.concat(utils.map(function(e)
return M._pr_str(e,_r) end, obj), " ") .. "]"
return "[" .. M._pr_seq(obj, print_readably, " ") .. "]"
elseif types._hash_map_Q(obj) then
local res = {}
for k,v in pairs(obj) do
res[#res+1] = M._pr_str(k, _r)
res[#res+1] = M._pr_str(v, _r)
res[#res+1] = M._pr_str(k, print_readably)
res[#res+1] = M._pr_str(v, print_readably)
end
return "{".. table.concat(res, " ").."}"
elseif type(obj) == 'string' then
if string.sub(obj,1,2) == "\u{029e}" then
return ':' .. string.sub(obj,3)
else
if _r then
elseif types._keyword_Q(obj) then
return ':' .. types._lua_string_from_keyword(obj)
elseif types._string_Q(obj) then
if print_readably then
local sval = obj:gsub('\\', '\\\\')
sval = sval:gsub('"', '\\"')
sval = sval:gsub('\n', '\\n')
return '"' .. sval .. '"'
else
return obj
end
end
elseif obj == types.Nil then
return "nil"
elseif obj == true then
Expand All @@ -52,4 +47,11 @@ function M._pr_str(obj, print_readably)
end
end

function M._pr_seq(obj, print_readably, separator)
return table.concat(
utils.map(function(e) return M._pr_str(e,print_readably) end,
obj),
separator)
end

return M
4 changes: 2 additions & 2 deletions impls/lua/reader.lua
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function M.read_atom(rdr)
elseif string.sub(token,1,1) == '"' then
throw("expected '\"', got EOF")
elseif string.sub(token,1,1) == ':' then
return "\u{029e}" .. string.sub(token,2)
return types._keyword_from_lua_string(string.sub(token,2))
elseif token == "nil" then return Nil
elseif token == "true" then return true
elseif token == "false" then return false
Expand Down Expand Up @@ -87,7 +87,7 @@ end

function M.read_hash_map(rdr)
local seq = M.read_sequence(rdr, '{', '}')
return types._assoc_BANG(types.HashMap:new(), table.unpack(seq))
return types.hash_map(table.unpack(seq))
end

function M.read_form(rdr)
Expand Down
1 change: 0 additions & 1 deletion impls/lua/step1_read_print.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#!/usr/bin/env lua

local readline = require('readline')
local utils = require('utils')
local types = require('types')
local reader = require('reader')
local printer = require('printer')
Expand Down
20 changes: 9 additions & 11 deletions impls/lua/step2_eval.lua
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,16 @@ function READ(str)
end

-- eval
function eval_ast(ast, env)

function EVAL(ast, env)

-- print("EVAL: " .. printer._pr_str(ast, true))

if types._symbol_Q(ast) then
if env[ast.val] == nil then
types.throw("'"..ast.val.."' not found")
end
return env[ast.val]
elseif types._list_Q(ast) then
return List:new(utils.map(function(x) return EVAL(x,env) end,ast))
elseif types._vector_Q(ast) then
return Vector:new(utils.map(function(x) return EVAL(x,env) end,ast))
elseif types._hash_map_Q(ast) then
Expand All @@ -31,17 +33,13 @@ function eval_ast(ast, env)
new_hm[k] = EVAL(v, env)
end
return HashMap:new(new_hm)
else
elseif not types._list_Q(ast) or #ast == 0 then
return ast
end
end

function EVAL(ast, env)
--print("EVAL: "..printer._pr_str(ast,true))
if not types._list_Q(ast) then return eval_ast(ast, env) end
if #ast == 0 then return ast end
local args = eval_ast(ast, env)
local f = table.remove(args, 1)
local f = EVAL(ast[1], env)
local args = types.slice(ast, 2)
args = utils.map(function(x) return EVAL(x,env) end, args)
return f(table.unpack(args))
end

Expand Down
Loading
Loading