about summary refs log tree commit diff stats
path: root/read.lua
blob: 72bbd4da69d63ed11f19ec03415075246e116356 (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
--- lam.read

local read = {}

local types = require "types"
local util = require "util"

function read.tokenize (str)
	--[[ Convert a string of characters into a list of tokens ]]
	assert(str, "No program given")
	local tbl = {}
	local word = ""
	local push_word =
		function ()
			if word:len() > 0 then
				table.insert(tbl, word)
				word = ""
			end
		end

	for c = 1, #str do
		char = string.char(str:byte(c))
		if char == " " or char == "\t" or char == "\n" then
			push_word()
		elseif char == "(" then
			push_word()
			table.insert(tbl, "(")
		elseif char == ")" then
			push_word()
			table.insert(tbl, ")")
		else
			word = word .. char
		end
	end
	push_word()
	return tbl
end

function read.read (str)
	-- [[ Read a scheme expression from a string ]]

	local function Atom (token)
		local n = tonumber(token)
		if n then return n
		else return tostring(token)
		end
	end

	local function read_tokens (tokens)
		--[[ Read a list of tokens from `tokenize' ]]
		assert(next(tokens), "Unexpected EOF")
		token = util.pop(tokens)
		if token == "(" then
			local L = {}
			while tokens[1] ~= ")" do
				table.insert(L, read_tokens(tokens))
			end
			util.pop(tokens)		       --  remove ")"
			return L
		elseif token == ")" then
			error("Unexpected ')'")
		else
			return Atom(token)
		end
	end

	return read_tokens(read.tokenize(str))
end

return setmetatable(read, { __call =
				    function(_, str)
					    return read.read(str)
				    end,
})