local function table_stream(t) return coroutine.wrap(function() for _, v in ipairs(t) do coroutine.yield(v) end end) end local function push(t, v) table.insert(t, v) end local function show_tree(tree) local buffer = {} for node in table_stream(tree) do if type(node) == "table" then local subtree = ("(%s)"):format(show_tree(node)) push(buffer, subtree) else push(buffer, tostring(node)) end end return table.concat(buffer, " ") end local function build_symbol(bits) local symbol = table.concat(bits) if tonumber(symbol) then return tonumber(symbol) elseif symbol == "true" then return true elseif symbol == "false" then return false else return symbol end end local function build_tree(stream) local tree = {} local symbol = {} for char in stream do if char == "(" then push(tree, build_tree(stream)) elseif char == ")" then break elseif char == " " and #symbol ~= 0 then push(tree, build_symbol(symbol)) symbol = {} elseif char:match("%s") then -- no op else push(symbol, char) end end if #symbol ~= 0 then push(tree, build_symbol(symbol)) end return tree end local function parse(string) return build_tree(string:gmatch(".")) end local objects = {} objects.Nowhere = { objects = {}, create = function(self, stream) local name = table.concat(stream(), " ") self.objects[name] = { lookAt = function(self, stream) print("You see " .. name) return self end } return self.objects[name] end } local function reduce(tree) if type(tree) ~= "table" then return tree end local index = 1 local target = nil local node_stream = coroutine.wrap(function() for _, node in ipairs(tree) do coroutine.yield(node) end end) for node in node_stream do if not target then target = reduce(node) if objects[target] then target = objects[target] end elseif type(target) == "table" then if target[node] then target = target[node](target, node_stream) else error("Object does not respond to " .. node) end elseif type(target) == "number" then local next = reduce(node_stream()) if node == "+" then target = target + next elseif node == "-" then target = target - next elseif node == "*" then target = target * next elseif node == "/" then target = target / next else error("Object does not respond to " .. node) end end end return target end print(show_tree(parse(arg[1]))) print(reduce(parse(arg[1])))