honeylisp/vendor/jeejah/jeejah/fenneleval.lua

81 lines
2.4 KiB
Lua

local fennel = require("fennel")
local fennelview_ok, fennelview = pcall(require, "fennelview")
if not fennelview_ok then fennelview = fennel.dofile("fennelview.fnl") end
local d = os.getenv("DEBUG") and print or function(_) end
local repls = {}
local print_for = function(write)
return function(...)
local args = {...}
for i,x in ipairs(args) do args[i] = tostring(x) end
table.insert(args, "\n")
write(table.concat(args, " "))
end
end
local make_repl = function(session, repls)
local on_values = function(xs)
session.values(xs)
session.done({status={"done"}})
end
local read = function()
-- If we skip empty input, it confuses the client.
local input = coroutine.yield()
if(input:find("^%s*$")) then return "nil\n" else return input end
end
local err = function(errtype, msg)
session.write(table.concat({errtype, msg}, ": ")) session.done()
end
local env = session.sandbox
if not env then
env = {}
for k, v in pairs(_G) do env[k] = v end
env.io = {}
end
env.print = print_for(session.write)
env.io.write = function(...) return session.io_write(...) end
env.io.read = function()
session.needinput()
local input, done = coroutine.yield()
done()
return input
end
local f = function()
return fennel.repl({readChunk = read,
onValues = on_values,
onError = err,
env = env,
pp = fennelview})
end
repls[session.id] = coroutine.wrap(f)
repls[session.id]()
return repls[session.id]
end
return function(conn, msg, session, send, response_for)
d("Evaluating", msg.code)
local repl = repls[session.id] or make_repl(session, repls)
if msg.op == "eval" then
session.values = function(xs)
send(conn, response_for(msg, {value=table.concat(xs, "\n") .. "\n"}))
end
session.io_write = function(...)
send(conn, response_for(msg, {out=table.concat({...})}))
end
session.done = function()
send(conn, response_for(msg, {status={"done"}}))
end
session.needinput = function()
send(conn, response_for(msg, {status={"need-input"}}))
end
repl(msg.code .. "\n")
elseif msg.op == "stdin" then
repl(msg.stdin,
function() send(conn, response_for(msg, {status={"done"}})) end)
end
end