Woodchuck/Implementation

From Esolang
Jump to navigation Jump to search
Back to Woodchuck

This is a simple Woodchuck interpreter written in Lua, along with a function to translate brainfuck to Woodchuck through the method described in the main article.

return {
	run = function (wc)
		local wc = wc:gsub("[^%^%<%>%%%[%]%+%.]", "")
		
		local root = {}
		local node = root
		local accumulator = 0
		local stack = {}
		
		local i = 1
		while i <= #wc do
			local char = wc:sub(i, i)
			
			-- Movement
			if char == "^" then
				node = node.up
			elseif char == "<" then
				node.left = node.left or {up = node}
				node = node.left
			elseif char == ">" then
				node.right = node.right or {up = node}
				node = node.right
			elseif char == "%" then
				if node.up.left == node then node.up.left = nil
				elseif node.up.right == node then node.up.right = nil end
				node = node.up
			
			-- Control
			elseif char == "[" then
				if node.left and node.right then
					table.insert(stack, {type = "while", ip = i})
				else
					local depth = 1

					i = i + 1
					while depth > 0 do
						local char = wc:sub(i, i)
						if char == "[" then depth = depth + 1
						elseif char == "]" then depth = depth - 1 end

						i = i + 1
					end
					i = i - 1
				end
			elseif char == "]" then
				if node.left and node.right then
					i = stack[#stack].ip
				else
					table.remove(stack)
				end
			
			-- Output
			elseif char == "+" then
				accumulator = accumulator + 1
			elseif char == "." then
				io.write(string.char(accumulator))
				accumulator = 0
			end

			i = i + 1
		end

		return root
	end,
	frombf = function (bf)
		return bf
			:gsub("[^%+%-%<%>%.%[%]]", "")
			:gsub("%+", "%$inc")
			:gsub("%-", "%$dec")
			:gsub("%<", "%$left")
			:gsub("%>", "%$right")
			:gsub("%.", "%$out")
			:gsub("%[", "%$while")
			:gsub("%]", "%$end")
			:gsub("%$inc", function () return ">>[>]>^<^[^]^" end)
			:gsub("%$dec", function () return ">>[>]%<%^[^]^" end)
			:gsub("%$left", function () return "^" end)
			:gsub("%$right", function () return "<" end)
			:gsub("%$out", function () return ">>[>+].^[^]^" end)
			:gsub("%$while", function () return ">>[^^" end)
			:gsub("%$end", function () return ">>]^^" end)
	end
}