local lib = ...
local tree = {}

local let let = lib.class {
	__index = {
		get = function(self, v)
			if self.bind[v] ~= nil then
				return self.bind[v]
			elseif self.import ~= nil then
				for i=#self.import, 1, -1 do
					local g = self.import[i]:get(v)
					if g then return g end
				end
			end
			if self.parent ~= nil then
				return self.parent:get(v)
			else return nil end
		end;
		put = function(self, v, val)
			self.bind[v] = val
		end;
		unify = function(self, v, val)
			local x = self:get(v)
			if     x == nil then self:put(v, val)
		                        return true
			elseif x == val then return true
			else                 return false end
		end;
		newBinds = function(self)
			return pairs(self.bind)
		end;
		binds = function(self)
			local k
			return function()
				k = next(self.bind, k)
				if k == nil then
					self = self.parent
					if not self then return nil end
					k = next(self.bind, k)
				end
				return k, self.bind[k]
			end
		end;
		compile = function(self, into)
			-- assemble the entire tree into a single unified list,
			-- suitable for returning from a completed query. uses
			-- tail recursion for optimal performance
			into = into or {}
			for k,v in pairs(self.bind) do
				into[k]=into[k] or v
			end
			if self.parent then -- branch node
				return self.parent:compile(into)
			else -- root node in let tree
				return into
			end
		end;
		branch = function(self, ref) return let(self,ref) end;
		import = function(i)
			if self.import == nil then self.import = {i}
			else table.insert(self.import, i) end
		end;
	};
	construct = function(parent, ref)
		return {
			bind = {};
			parent = parent;
			import = nil;
			ref = ref; -- used to store e.g. a position in a program
		}
	end;
}
tree.let = let

return tree