Skip to content

Commit

Permalink
lua: simplify and debug environments
Browse files Browse the repository at this point in the history
Use plain LUA strings as keys in environments.
Search outers environments with a loop.
Remove the now unneeded Env:find trick.
Let DEBUG-EVAL show the contents of all outer environments but repl_env.
  • Loading branch information
asarhaddon committed Aug 26, 2024
1 parent 5a35cb6 commit f64b53c
Show file tree
Hide file tree
Showing 9 changed files with 145 additions and 120 deletions.
43 changes: 27 additions & 16 deletions impls/lua/env.lua
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
local table = require('table')
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
Expand All @@ -22,27 +25,35 @@ function Env:new(outer, binds, exprs)
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
29 changes: 15 additions & 14 deletions impls/lua/step3_env.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,18 @@ end

function EVAL(ast, env)

local dbgeval_key = types.Symbol:new("DEBUG-EVAL")
local dbgeval_env = env:find(dbgeval_key)
if dbgeval_env then
local dbgeval = dbgeval_env:get(dbgeval_key)
if dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
end
local dbgeval = env:get("DEBUG-EVAL")
if dbgeval ~= nil and dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
env:debug()
end

if types._symbol_Q(ast) then
return env:get(ast)
local result = env:get(ast.val)
if result == nil then
types.throw("'" .. ast.val .. "' not found")
end
return result
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 @@ -45,11 +46,11 @@ function EVAL(ast, env)
local a0,a1,a2 = ast[1], ast[2],ast[3]
local a0sym = types._symbol_Q(a0) and a0.val or ""
if 'def!' == a0sym then
return env:set(a1, EVAL(a2, env))
return env:set(a1.val, EVAL(a2, env))
elseif 'let*' == a0sym then
local let_env = Env:new(env)
for i = 1,#a1,2 do
let_env:set(a1[i], EVAL(a1[i+1], let_env))
let_env:set(a1[i].val, EVAL(a1[i+1], let_env))
end
return EVAL(a2, let_env)
else
Expand All @@ -71,10 +72,10 @@ function rep(str)
return PRINT(EVAL(READ(str),repl_env))
end

repl_env:set(types.Symbol:new('+'), function(a,b) return a+b end)
repl_env:set(types.Symbol:new('-'), function(a,b) return a-b end)
repl_env:set(types.Symbol:new('*'), function(a,b) return a*b end)
repl_env:set(types.Symbol:new('/'), function(a,b) return math.floor(a/b) end)
repl_env:set('+', function(a,b) return a+b end)
repl_env:set('-', function(a,b) return a-b end)
repl_env:set('*', function(a,b) return a*b end)
repl_env:set('/', function(a,b) return math.floor(a/b) end)

if #arg > 0 and arg[1] == "--raw" then
readline.raw = true
Expand Down
23 changes: 12 additions & 11 deletions impls/lua/step4_if_fn_do.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,18 @@ end

function EVAL(ast, env)

local dbgeval_key = types.Symbol:new("DEBUG-EVAL")
local dbgeval_env = env:find(dbgeval_key)
if dbgeval_env then
local dbgeval = dbgeval_env:get(dbgeval_key)
if dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
end
local dbgeval = env:get("DEBUG-EVAL")
if dbgeval ~= nil and dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
env:debug()
end

if types._symbol_Q(ast) then
return env:get(ast)
local result = env:get(ast.val)
if result == nil then
types.throw("'" .. ast.val .. "' not found")
end
return result
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 @@ -46,11 +47,11 @@ function EVAL(ast, env)
local a0,a1,a2,a3 = ast[1], ast[2],ast[3],ast[4]
local a0sym = types._symbol_Q(a0) and a0.val or ""
if 'def!' == a0sym then
return env:set(a1, EVAL(a2, env))
return env:set(a1.val, EVAL(a2, env))
elseif 'let*' == a0sym then
local let_env = Env:new(env)
for i = 1,#a1,2 do
let_env:set(a1[i], EVAL(a1[i+1], let_env))
let_env:set(a1[i].val, EVAL(a1[i+1], let_env))
end
return EVAL(a2, let_env)
elseif 'do' == a0sym then
Expand Down Expand Up @@ -88,7 +89,7 @@ end

-- core.lua: defined using Lua
for k,v in pairs(core.ns) do
repl_env:set(types.Symbol:new(k), v)
repl_env:set(k, v)
end

-- core.mal: defined using mal
Expand Down
24 changes: 13 additions & 11 deletions impls/lua/step5_tco.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ end

function EVAL(ast, env)
while true do
local dbgeval_key = types.Symbol:new("DEBUG-EVAL")
local dbgeval_env = env:find(dbgeval_key)
if dbgeval_env then
local dbgeval = dbgeval_env:get(dbgeval_key)
if dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
end

local dbgeval = env:get("DEBUG-EVAL")
if dbgeval ~= nil and dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
env:debug()
end

if types._symbol_Q(ast) then
return env:get(ast)
local result = env:get(ast.val)
if result == nil then
types.throw("'" .. ast.val .. "' not found")
end
return result
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 @@ -46,11 +48,11 @@ function EVAL(ast, env)
local a0,a1,a2,a3 = ast[1], ast[2],ast[3],ast[4]
local a0sym = types._symbol_Q(a0) and a0.val or ""
if 'def!' == a0sym then
return env:set(a1, EVAL(a2, env))
return env:set(a1.val, EVAL(a2, env))
elseif 'let*' == a0sym then
local let_env = Env:new(env)
for i = 1,#a1,2 do
let_env:set(a1[i], EVAL(a1[i+1], let_env))
let_env:set(a1[i].val, EVAL(a1[i+1], let_env))
end
env = let_env
ast = a2 -- TCO
Expand Down Expand Up @@ -95,7 +97,7 @@ end

-- core.lua: defined using Lua
for k,v in pairs(core.ns) do
repl_env:set(types.Symbol:new(k), v)
repl_env:set(k, v)
end

-- core.mal: defined using mal
Expand Down
28 changes: 15 additions & 13 deletions impls/lua/step6_file.lua
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,19 @@ end

function EVAL(ast, env)
while true do
local dbgeval_key = types.Symbol:new("DEBUG-EVAL")
local dbgeval_env = env:find(dbgeval_key)
if dbgeval_env then
local dbgeval = dbgeval_env:get(dbgeval_key)
if dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
end

local dbgeval = env:get("DEBUG-EVAL")
if dbgeval ~= nil and dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
env:debug()
end

if types._symbol_Q(ast) then
return env:get(ast)
local result = env:get(ast.val)
if result == nil then
types.throw("'" .. ast.val .. "' not found")
end
return result
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 @@ -46,11 +48,11 @@ function EVAL(ast, env)
local a0,a1,a2,a3 = ast[1], ast[2],ast[3],ast[4]
local a0sym = types._symbol_Q(a0) and a0.val or ""
if 'def!' == a0sym then
return env:set(a1, EVAL(a2, env))
return env:set(a1.val, EVAL(a2, env))
elseif 'let*' == a0sym then
local let_env = Env:new(env)
for i = 1,#a1,2 do
let_env:set(a1[i], EVAL(a1[i+1], let_env))
let_env:set(a1[i].val, EVAL(a1[i+1], let_env))
end
env = let_env
ast = a2 -- TCO
Expand Down Expand Up @@ -95,11 +97,11 @@ end

-- core.lua: defined using Lua
for k,v in pairs(core.ns) do
repl_env:set(types.Symbol:new(k), v)
repl_env:set(k, v)
end
repl_env:set(types.Symbol:new('eval'),
repl_env:set('eval',
function(ast) return EVAL(ast, repl_env) end)
repl_env:set(types.Symbol:new('*ARGV*'), types.List:new(types.slice(arg,2)))
repl_env:set('*ARGV*', types.List:new(types.slice(arg,2)))

-- core.mal: defined using mal
rep("(def! not (fn* (a) (if a false true)))")
Expand Down
28 changes: 15 additions & 13 deletions impls/lua/step7_quote.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,19 @@ end

function EVAL(ast, env)
while true do
local dbgeval_key = types.Symbol:new("DEBUG-EVAL")
local dbgeval_env = env:find(dbgeval_key)
if dbgeval_env then
local dbgeval = dbgeval_env:get(dbgeval_key)
if dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
end

local dbgeval = env:get("DEBUG-EVAL")
if dbgeval ~= nil and dbgeval ~= types.Nil and dbgeval ~= false then
print("EVAL: " .. printer._pr_str(ast, true))
env:debug()
end

if types._symbol_Q(ast) then
return env:get(ast)
local result = env:get(ast.val)
if result == nil then
types.throw("'" .. ast.val .. "' not found")
end
return result
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 @@ -78,11 +80,11 @@ function EVAL(ast, env)
local a0,a1,a2,a3 = ast[1], ast[2],ast[3],ast[4]
local a0sym = types._symbol_Q(a0) and a0.val or ""
if 'def!' == a0sym then
return env:set(a1, EVAL(a2, env))
return env:set(a1.val, EVAL(a2, env))
elseif 'let*' == a0sym then
local let_env = Env:new(env)
for i = 1,#a1,2 do
let_env:set(a1[i], EVAL(a1[i+1], let_env))
let_env:set(a1[i].val, EVAL(a1[i+1], let_env))
end
env = let_env
ast = a2 -- TCO
Expand Down Expand Up @@ -131,11 +133,11 @@ end

-- core.lua: defined using Lua
for k,v in pairs(core.ns) do
repl_env:set(types.Symbol:new(k), v)
repl_env:set(k, v)
end
repl_env:set(types.Symbol:new('eval'),
repl_env:set('eval',
function(ast) return EVAL(ast, repl_env) end)
repl_env:set(types.Symbol:new('*ARGV*'), types.List:new(types.slice(arg,2)))
repl_env:set('*ARGV*', types.List:new(types.slice(arg,2)))

-- core.mal: defined using mal
rep("(def! not (fn* (a) (if a false true)))")
Expand Down
Loading

0 comments on commit f64b53c

Please sign in to comment.