--- 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, })