about summary refs log tree commit diff stats
path: root/load.lua
blob: db2651ff2f8c03ce8a10e1459cbaf2b0fdf16cc1 (plain)
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
--- lam.load

local m = {}
local core = require("core")
local eval = require("eval")
local read = require("read")
local type = require("type")

local function schemeprint (x)
	-- possibly a candidate to put in a `write' library
	if x == true then print("#t")
	elseif x == false then print("#f")
	elseif x == nil then return -- print("#<nil>")
	else print(x)
	end
end

function core.environment.read (r)
	type.assert_arity(r,1,1)
	error("unimplemented")
end

function core.environment.eval (r)
	type.assert_arity(r,1,2)
	local form = r[1]
	local env = r[2][1] or core.environment
	return eval.eval(form, env)
end

function core.environment.load (r)
	type.assert_arity(r,1,1)
	return m.load(tostring(r[1]))
end

function m.load (filename, interactive)
	-- interactive = { out = file/handle, prompt = string, }
	local inport = type.input_port(filename)
	if interactive then
		io.output(interactive.out)
		io.output():setvbuf("line")
	else
		io.output():setvbuf("no")
	end

	local function handle_error (e)
		local start = e:find(": ")
		return e:sub(start + 2)
	end

	repeat
		if interactive then
			io.stderr:write(interactive.prompt or "")
			io.stderr:flush()
		end
		-- read
		local read_ok, form = xpcall(
			function () return read.read(inport) end,
			handle_error)
		if form == type.eof then break end
		if not read_ok then
			io.stderr:write("error (read): ", form, "\n")
			-- when interactive, errors should not be fatal, but
			-- they should be in batch mode
			inport:flush() -- avoid endless loop
			if not interactive then return nil end
		else
			-- eval
			local eval_ok, value = xpcall(
				function ()
					return eval.eval(form, core.environment)
				end,
				handle_error)
			if not eval_ok then
				io.stderr:write("error (eval): ", value, "\n")
				if not interactive then return nil end
			else
				-- print
				if interactive then schemeprint(value) end
			end
		end
	until value == type.eof -- loop
end

--------
return m