Module:parser: Difference between revisions

From Linguifex
Jump to navigation Jump to search
(Created page with "local m_table local concat = table.concat local getmetatable = getmetatable local insert = table.insert local next = next local rawget = rawget local rawset = rawset local remove = table.remove local select = select local setmetatable = setmetatable local type = type local unpack = unpack local classes = {} local metamethods = mw.loadData("Module:parser/data").metamethods ------------------------------------------------------------------------------------ -- -- Helper...")
 
No edit summary
Line 1: Line 1:
local m_table
local export = {}
 
local metamethods_data_module = "Module:data/metamethods"
local table_module = "Module:table"


local concat = table.concat
local concat = table.concat
Line 8: Line 11:
local rawset = rawset
local rawset = rawset
local remove = table.remove
local remove = table.remove
local select = select
local require = require
local setmetatable = setmetatable
local setmetatable = setmetatable
local type = type
local type = type
Line 14: Line 17:


local classes = {}
local classes = {}
local metamethods = mw.loadData("Module:parser/data").metamethods
 
--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==]
local function deep_copy(...)
deep_copy = require(table_module).deepCopy
return deep_copy(...)
end
 
--[==[
Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==]
local metamethods
local function get_metamethods()
-- Use require, since lookup times are much slower with mw.loadData.
metamethods, get_metamethods = require(metamethods_data_module), nil
return metamethods
end


------------------------------------------------------------------------------------
------------------------------------------------------------------------------------
Line 22: Line 40:
------------------------------------------------------------------------------------
------------------------------------------------------------------------------------


local function get_nested(a, b, ...)
local function get_nested(t, k, ...)
if not a then
if t == nil then
return nil
return nil
elseif ... then
elseif ... == nil then
return get_nested(a[b], ...)
return t[k]
end
end
return a[b]
return get_nested(t[k], ...)
end
end


local function set_nested(a, b, c, ...)
local function set_nested(t, k, v, ...)
if not (a and b) then
if ... ~= nil then
return
local t_next = t[k]
elseif c and ... then
if t_next == nil then
a[b] = a[b] or {}
t_next = {}
return set_nested(a[b], c, ...)
t[k] = t_next
end
return set_nested(t_next, v, ...)
end
end
a[b] = c
t[k] = v
end
end


Line 44: Line 64:
if parent then
if parent then
for method, value in next, parent do
for method, value in next, parent do
if metamethods[method] then
if child[method] == nil and (metamethods or get_metamethods())[method] ~= nil then
child[method] = value
child[method] = value
end
end
Line 57: Line 77:


local function is_node(value)
local function is_node(value)
return classes[getmetatable(value)] and true or false
if value == nil then
return false
end
local mt = getmetatable(value)
return not (mt == nil or classes[mt] == nil)
end
end


-- Recursively calling tostring() adds to the C stack (limit: 200), whereas calling __tostring metamethods directly does not. Occasionally relevant when dealing with very deep nesting.
-- Recursively calling tostring() adds to the C stack (limit: 200), whereas
-- calling __tostring metamethods directly does not. Occasionally relevant when
-- dealing with very deep nesting.
local tostring
local tostring
do
do
Line 73: Line 99:
end
end


local function type_or_class(value)
local function class_else_type(value)
return classes[getmetatable(value)] or type(value)
if value == nil then
return type(value)
end
local mt = getmetatable(value)
if mt == nil then
return type(value)
end
local class = classes[mt]
return class == nil and type(value) or class
end
end


Line 88: Line 122:
function Node:next(i)
function Node:next(i)
i = i + 1
i = i + 1
return self[i], i
return self[i], self, i
end
end


function Node:next_node(i)
--[==[
local v
Implements recursive iteration over a node tree.
repeat
v, i = self:next(i)
until v == nil or is_node(v)
return v, i
end


-- Implements recursive iteration over a node tree, using functors to maintain state (which uses a lot less memory than closures). Iterator1 exists only to return the calling node on the first iteration, while Iterator2 uses a stack to store the state of each layer in the tree.
By default, when a node is encountered (which may contain other nodes), it is returned on the first iteration, and then any child nodes are returned on each subsequent iteration; the same process is then followed if any of those children contain nodes themselves. Once a particular node has been fully traversed, the iterator then continues with any sibling nodes. The iterator will use the `next` method of each node to traverse it, which may differ depending on the node class.


-- When a node is encountered (which may contain other nodes), it is returned on the first iteration, and then any child nodes are returned on each subsequent iteration; the same process is followed if any of those children contain nodes themselves. Once a particular node has been fully traversed, the iterator moves back up one layer and continues with any sibling nodes.
Each iteration returns three values: `value`, `node` and `key`. Together, these can be used to manipulate the node tree at any given point without needing to know the full structure. Note that when the input node is returned on the first iteration, `node` and `key` will be nil.


-- Each iteration returns three values: `value`, `node` and `key`. Together, these can be used to manipulate the node tree at any given point without needing to know the full structure. Note that when the input node is returned on the first iteration, `node` and `key` will be nil.
The optional argument `test` can be used to limit the return values. This should be a function that returns a boolean value, where a return value of true means that the child will be returned by the iterator. If a node is not returned by the iterator, it will still be traversed, as it may contain children that should be returned.


-- By default, the iterator will use the `next` method of each node, but this can be changed with the `next_func` parameter, which accepts a string argument with the name of a next method. This is because trees might consist of several different classes of node, and each might have different next methods that are tailored to their particular structures. In addition, each class of node might have multiple different next methods, which can be named according to their purposes. `next_func` ensures that the iterator uses equivalent next methods between different types of node.
The method `iterate_nodes` is provided as a special instance of iterate which uses `is_node` as the test.]==]
 
function Node:iterate(test)
-- Currently, two next methods are available: `next`, which simply iterates over the node conventionally, and `next_node`, which only returns children that are themselves nodes. Custom next methods can be declared by any calling module.
local node, k, n, nodes, keys, returned_self = self, 0, 0
do
-- Special case if `test` is `is_node`.
local Iterator1, Iterator2 = {}, {}
local is_node_is_test = test == is_node
Iterator1.__index = Iterator2 -- Not a typo.
Iterator2.__index = Iterator2
function Iterator1:__call()
setmetatable(self, Iterator2)
return self[1].node
end
function Iterator2:push(node)
local layer = {
k = 0,
node = node
}
self[#self + 1] = layer
self[-1] = layer
return self
end
function Iterator2:pop()
return function()
local len = #self
if not returned_self then
self[len] = nil
returned_self = true
self[-1] = self[len - 1]
if test == nil or test(self) then
end
return self
function Iterator2:catch_values(node, ...)
local v, k = ...
if v == nil then
self:pop()
if self[-1] then
return self:__call()
end
end
return
end
end
self[-1].k = k
-- Get `v`, which is the value at the last-returned key of the current node; if `v` is a node, it will be iterated over (i.e. recursive iteration). By default, `v` will be the last-returned value, but looking it up here means that any modifications made to the node during the loop will be taken into account. This makes it possible to swap one node out for something else (e.g. another node), or to remove it entirely, without being locked into recursively iterating over the old node; instead, the new node (if any) will be iterated over. This means node trees can be modified on-the-fly during the course of a single loop.
if is_node(v) then
local v, node_check = node[k], true
self:push(v)
while true do
-- If `v` is a node, memoize the current node and key, then iterate over it.
if node_check and is_node(v) then
-- `n` is the current memo level.
n = n + 1
if nodes then
nodes[n], keys[n] = node, k
else
nodes, keys = {node}, {k}
end
node, k = v, 0
end
v, node, k = node:next(k)
-- If `v` is nil, move down one level, then continue iterating the node on that level (if any), or otherwise terminate the loop.
if v == nil then
if n == 0 then
return nil
end
node, k, n = nodes[n], keys[n], n - 1
elseif test == nil or test(v) then
return v, node, k
-- If `test` is `is_node`, there's no point checking it again on the next loop.
elseif node_check and is_node_is_test then
node_check = false
end
end
end
return v, node, select(2, ...)
end
function Iterator2:__call()
local layer = self[-1]
local node = layer.node
return self:catch_values(node, node[self.next_func](node, layer.k))
end
function Node:__pairs(next_func)
return setmetatable({
next_func = next_func or "next"
}, Iterator1):push(self)
end
end
end
end


function Node:rawpairs()
function Node:iterate_nodes()
return next, self
return self:iterate(is_node)
end
end


Line 176: Line 191:


function Node:clone()
function Node:clone()
return require("Module:table").deepcopy(self, "keep", true)
return deep_copy(self, "keep", true)
end
end


function Node:new_class(class)
function Node:new_class(class)
local t = inherit_metamethods({type = class}, self)
local t = {type = class}
t.__index = t
t.__index = t
t = inherit_metamethods(t, self)
classes[t] = class
classes[t] = class
return setmetatable(t, self)
return setmetatable(t, self)
end
end
Node.keys_to_remove = {"fail", "handler", "head", "override", "route"}


function Node:new(t)
function Node:new(t)
setmetatable(t, nil)
setmetatable(t, nil)
t.handler = nil
local keys_to_remove = self.keys_to_remove
t.override = nil
for i = 1, #keys_to_remove do
t.route = nil
t[keys_to_remove[i]] = nil
end
return setmetatable(t, self)
return setmetatable(t, self)
end
end
Line 198: Line 217:


function Proxy:__index(k)
function Proxy:__index(k)
return Proxy[k] or self.__chars[k]
local v = Proxy[k]
if v ~= nil then
return v
end
return self.__chars[k]
end
end


Line 224: Line 247:
i = i + 1
i = i + 1
local char = self.__chars[i]
local char = self.__chars[i]
if char then
if char ~= nil then
return i, self[i], self, self.__parents[i], self.__keys[i]
return i, self[i], self, self.__parents[i], self.__keys[i]
end
end
Line 250: Line 273:


function Parser:read(delta)
function Parser:read(delta)
return self.text[self.head + (delta or 0)] or ""
local v = self.text[self.head + (delta or 0)]
return v == nil and "" or v
end
end


function Parser:advance(n)
function Parser:advance(n)
self.head = self.head + (n or 1)
self.head = self.head + (n == nil and 1 or n)
end
end


function Parser:layer(n)
function Parser:layer(n)
if n then
if n ~= nil then
return rawget(self, #self + n)
return rawget(self, #self + n)
end
end
Line 266: Line 290:
function Parser:emit(a, b)
function Parser:emit(a, b)
local layer = self[-1]
local layer = self[-1]
if b then
if b ~= nil then
insert(layer, signed_index(layer, a), b)
insert(layer, signed_index(layer, a), b)
else
else
Line 275: Line 299:
function Parser:emit_tokens(a, b)
function Parser:emit_tokens(a, b)
local layer = self[-1]
local layer = self[-1]
if b then
if b ~= nil then
a = signed_index(layer, a)
a = signed_index(layer, a)
for i = 1, #b do
for i = 1, #b do
Line 291: Line 315:
function Parser:remove(n)
function Parser:remove(n)
local layer = self[-1]
local layer = self[-1]
if n then
if n ~= nil then
return remove(layer, signed_index(layer, n))
return remove(layer, signed_index(layer, n))
end
end
Line 307: Line 331:
-- Unlike default table.concat, this respects __tostring metamethods.
-- Unlike default table.concat, this respects __tostring metamethods.
function Parser:concat(a, b, c)
function Parser:concat(a, b, c)
if not a or a > 0 then
if a == nil or a > 0 then
return self:concat(0, a, b)
return self:concat(0, a, b)
end
end
local layer = self:layer(a)
local layer, ret, n = self:layer(a), {}, 0
local ret = {}
for i = b and signed_index(layer, b) or 1, c and signed_index(layer, c) or #layer do
for i = signed_index(layer, b) or 1, signed_index(layer, c) or #layer do
n = n + 1
insert(ret, tostring(layer[i]))
ret[n] = tostring(layer[i])
end
end
return concat(ret)
return concat(ret)
Line 319: Line 343:


function Parser:emitted(delta)
function Parser:emitted(delta)
delta = delta or -1
if delta == nil then
delta = -1
end
local i = 0
local i = 0
while true do
while true do
local layer = self:layer(i)
local layer = self:layer(i)
if not layer then
if layer == nil then
return nil
return nil
end
end
Line 366: Line 392:
self[len] = nil
self[len] = nil
len = len - 1
len = len - 1
self[-1] = self[len] or self
local new = self[len]
if not layer.sublayer then
self[-1] = new == nil and self or new
if layer.sublayer == nil then
break
break
end
end
Line 378: Line 405:
local len, layer = #self, self[-1]
local len, layer = #self, self[-1]
self[len] = nil
self[len] = nil
self[-1] = self[len - 1] or self
local new = self[len - 1]
return setmetatable(layer, nil)
self[-1] = new == nil and self or new
setmetatable(layer, nil)
layer.sublayer = nil
return layer
end
end


function Parser:get(route, ...)
function Parser:get(route, ...)
local failed_route = get_nested(self.failed_routes, self.head, route)
if failed_route then
return false, failed_route
end
self:push(route)
self:push(route)
local layer = self[route](self, ...)
local layer = route(self, ...)
if layer == nil then
if layer == nil then
layer = self:traverse()
layer = self:traverse()
end
end
if layer.fail then
return layer
return false, layer
end
 
function Parser:try(route, ...)
local failed_layer = get_nested(self.failed_routes, route, self.head)
if failed_layer ~= nil then
return false, failed_layer
end
end
return true, layer
local layer = self:get(route, ...)
return not layer.fail, layer
end
end


function Parser:consume(this, ...)
function Parser:consume(this, ...)
local layer = self[-1]
local layer = self[-1]
return (layer.override or layer.handler)(self, this or self:read(), ...)
if this == nil then
this = self:read()
end
return (layer.override or layer.handler)(self, this, ...)
end
end


Line 406: Line 441:
local layer = self:pop()
local layer = self:pop()
layer.fail = true
layer.fail = true
set_nested(self, "failed_routes", layer.head, layer.route, layer)
set_nested(self, "failed_routes", layer.route, layer.head, layer)
self.head = layer.head
self.head = layer.head
return layer
return layer
Line 414: Line 449:
while true do
while true do
local layer = self:consume()
local layer = self:consume()
if layer then
if layer ~= nil then
return layer
return layer
end
end
Line 442: Line 477:
-- Generate a new parser class object, which is used as the template for any parser objects. These should be customized with additional/modified methods as needed.
-- Generate a new parser class object, which is used as the template for any parser objects. These should be customized with additional/modified methods as needed.
function Parser:new_class()
function Parser:new_class()
local t = inherit_metamethods({}, self)
local t = {}
t.__index = t
t.__index = t
return setmetatable(t, self)
return setmetatable(inherit_metamethods(t, self), self)
end
end


Line 457: Line 492:
function Parser:parse(data)
function Parser:parse(data)
local parser = self:new(data.text)
local parser = self:new(data.text)
local success, tokens = parser:get(unpack(data.route))
local success, tokens = parser:try(unpack(data.route))
if #parser > 0 then
if #parser > 0 then
-- This shouldn't happen.
-- This shouldn't happen.
Line 467: Line 502:
return false, nil, parser
return false, nil, parser
end
end
error("Parser exited with bad route.")
error("Parser exited with failed route.")
end
end


local export = {}
export.class_else_type = class_else_type
 
export.is_node = is_node
export.is_node = is_node
export.tostring = tostring
export.tostring = tostring
export.type_or_class = type_or_class


function export.new()
function export.new()

Revision as of 12:29, 8 January 2025

Documentation for this module may be created at Module:parser/doc

local export = {}

local metamethods_data_module = "Module:data/metamethods"
local table_module = "Module:table"

local concat = table.concat
local getmetatable = getmetatable
local insert = table.insert
local next = next
local rawget = rawget
local rawset = rawset
local remove = table.remove
local require = require
local setmetatable = setmetatable
local type = type
local unpack = unpack

local classes = {}

--[==[
Loaders for functions in other modules, which overwrite themselves with the target function when called. This ensures modules are only loaded when needed, retains the speed/convenience of locally-declared pre-loaded functions, and has no overhead after the first call, since the target functions are called directly in any subsequent calls.]==]
	local function deep_copy(...)
		deep_copy = require(table_module).deepCopy
		return deep_copy(...)
	end

--[==[
Loaders for objects, which load data (or some other object) into some variable, which can then be accessed as "foo or get_foo()", where the function get_foo sets the object to "foo" and then returns it. This ensures they are only loaded when needed, and avoids the need to check for the existence of the object each time, since once "foo" has been set, "get_foo" will not be called again.]==]
	local metamethods
	local function get_metamethods()
		-- Use require, since lookup times are much slower with mw.loadData.
		metamethods, get_metamethods = require(metamethods_data_module), nil
		return metamethods
	end

------------------------------------------------------------------------------------
--
-- Helper functions
--
------------------------------------------------------------------------------------

local function get_nested(t, k, ...)
	if t == nil then
		return nil
	elseif ... == nil then
		return t[k]
	end
	return get_nested(t[k], ...)
end

local function set_nested(t, k, v, ...)
	if ... ~= nil then
		local t_next = t[k]
		if t_next == nil then
			t_next = {}
			t[k] = t_next
		end
		return set_nested(t_next, v, ...)
	end
	t[k] = v
end

local function inherit_metamethods(child, parent)
	if parent then
		for method, value in next, parent do
			if child[method] == nil and (metamethods or get_metamethods())[method] ~= nil then
				child[method] = value
			end
		end
	end
	return child
end

local function signed_index(t, n)
	return n and n <= 0 and #t + 1 + n or n
end

local function is_node(value)
	if value == nil then
		return false
	end
	local mt = getmetatable(value)
	return not (mt == nil or classes[mt] == nil)
end

-- Recursively calling tostring() adds to the C stack (limit: 200), whereas
-- calling __tostring metamethods directly does not. Occasionally relevant when
-- dealing with very deep nesting.
local tostring
do
	local _tostring = _G.tostring
	
	function tostring(value)
		if is_node(value) then
			return value:__tostring(value)
		end
		return _tostring(value)
	end
end

local function class_else_type(value)
	if value == nil then
		return type(value)
	end
	local mt = getmetatable(value)
	if mt == nil then
		return type(value)
	end
	local class = classes[mt]
	return class == nil and type(value) or class
end

------------------------------------------------------------------------------------
--
-- Nodes
--
------------------------------------------------------------------------------------

local Node = {}
Node.__index = Node

function Node:next(i)
	i = i + 1
	return self[i], self, i
end

--[==[
Implements recursive iteration over a node tree.

By default, when a node is encountered (which may contain other nodes), it is returned on the first iteration, and then any child nodes are returned on each subsequent iteration; the same process is then followed if any of those children contain nodes themselves. Once a particular node has been fully traversed, the iterator then continues with any sibling nodes. The iterator will use the `next` method of each node to traverse it, which may differ depending on the node class.

Each iteration returns three values: `value`, `node` and `key`. Together, these can be used to manipulate the node tree at any given point without needing to know the full structure. Note that when the input node is returned on the first iteration, `node` and `key` will be nil.

The optional argument `test` can be used to limit the return values. This should be a function that returns a boolean value, where a return value of true means that the child will be returned by the iterator. If a node is not returned by the iterator, it will still be traversed, as it may contain children that should be returned.

The method `iterate_nodes` is provided as a special instance of iterate which uses `is_node` as the test.]==]
function Node:iterate(test)
	local node, k, n, nodes, keys, returned_self = self, 0, 0
	-- Special case if `test` is `is_node`.
	local is_node_is_test = test == is_node
	
	return function()
		if not returned_self then
			returned_self = true
			if test == nil or test(self) then
				return self
			end
		end
		-- Get `v`, which is the value at the last-returned key of the current node; if `v` is a node, it will be iterated over (i.e. recursive iteration). By default, `v` will be the last-returned value, but looking it up here means that any modifications made to the node during the loop will be taken into account. This makes it possible to swap one node out for something else (e.g. another node), or to remove it entirely, without being locked into recursively iterating over the old node; instead, the new node (if any) will be iterated over. This means node trees can be modified on-the-fly during the course of a single loop.
		local v, node_check = node[k], true
		while true do
			-- If `v` is a node, memoize the current node and key, then iterate over it.
			if node_check and is_node(v) then
				-- `n` is the current memo level.
				n = n + 1
				if nodes then
					nodes[n], keys[n] = node, k
				else
					nodes, keys = {node}, {k}
				end
				node, k = v, 0
			end
			v, node, k = node:next(k)
			-- If `v` is nil, move down one level, then continue iterating the node on that level (if any), or otherwise terminate the loop.
			if v == nil then
				if n == 0 then
					return nil
				end
				node, k, n = nodes[n], keys[n], n - 1
			elseif test == nil or test(v) then
				return v, node, k
			-- If `test` is `is_node`, there's no point checking it again on the next loop.
			elseif node_check and is_node_is_test then
				node_check = false
			end
		end
	end
end

function Node:iterate_nodes()
	return self:iterate(is_node)
end

function Node:__tostring()
	local output = {}
	for i = 1, #self do
		insert(output, tostring(self[i]))
	end
	return concat(output)
end

function Node:clone()
	return deep_copy(self, "keep", true)
end

function Node:new_class(class)
	local t = {type = class}
	t.__index = t
	t = inherit_metamethods(t, self)
	classes[t] = class
	return setmetatable(t, self)
end

Node.keys_to_remove = {"fail", "handler", "head", "override", "route"}

function Node:new(t)
	setmetatable(t, nil)
	local keys_to_remove = self.keys_to_remove
	for i = 1, #keys_to_remove do
		t[keys_to_remove[i]] = nil
	end
	return setmetatable(t, self)
end

do
	local Proxy = {}

	function Proxy:__index(k)
		local v = Proxy[k]
		if v ~= nil then
			return v
		end
		return self.__chars[k]
	end

	function Proxy:__newindex(k, v)
		local key = self.__keys[k]
		if key then
			self.__chars[k] = v
			self.__parents[key] = v
		elseif key == false then
			error("Character is immutable.")
		else
			error("Invalid key.")
		end
	end

	function Proxy:build(a, b, c)
		local len = self.__len + 1
		self.__chars[len] = a
		self.__parents[len] = b
		self.__keys[len] = c
		self.__len = len
	end

	function Proxy:iter(i)
		i = i + 1
		local char = self.__chars[i]
		if char ~= nil then
			return i, self[i], self, self.__parents[i], self.__keys[i]
		end
	end
	
	function Node:new_proxy()
		return setmetatable({
			__node = self,
			__chars = {},
			__parents = {},
			__keys = {},
			__len = 0
		}, Proxy)
	end
end

------------------------------------------------------------------------------------
--
-- Parser
--
------------------------------------------------------------------------------------

local Parser = {}
Parser.__index = Parser

function Parser:read(delta)
	local v = self.text[self.head + (delta or 0)]
	return v == nil and "" or v
end

function Parser:advance(n)
	self.head = self.head + (n == nil and 1 or n)
end

function Parser:layer(n)
	if n ~= nil then
		return rawget(self, #self + n)
	end
	return self[-1]
end

function Parser:emit(a, b)
	local layer = self[-1]
	if b ~= nil then
		insert(layer, signed_index(layer, a), b)
	else
		rawset(layer, #layer + 1, a)
	end
end

function Parser:emit_tokens(a, b)
	local layer = self[-1]
	if b ~= nil then
		a = signed_index(layer, a)
		for i = 1, #b do
			insert(layer, a + i - 1, b[i])
		end
	else
		local len = #layer
		for i = 1, #a do
			len = len + 1
			rawset(layer, len, a[i])
		end
	end
end

function Parser:remove(n)
	local layer = self[-1]
	if n ~= nil then
		return remove(layer, signed_index(layer, n))
	end
	local len = #layer
	local token = layer[len]
	layer[len] = nil
	return token
end

function Parser:replace(a, b)
	local layer = self[-1]
	layer[signed_index(layer, a)] = b
end

-- Unlike default table.concat, this respects __tostring metamethods.
function Parser:concat(a, b, c)
	if a == nil or a > 0 then
		return self:concat(0, a, b)
	end
	local layer, ret, n = self:layer(a), {}, 0
	for i = b and signed_index(layer, b) or 1, c and signed_index(layer, c) or #layer do
		n = n + 1
		ret[n] = tostring(layer[i])
	end
	return concat(ret)
end

function Parser:emitted(delta)
	if delta == nil then
		delta = -1
	end
	local i = 0
	while true do
		local layer = self:layer(i)
		if layer == nil then
			return nil
		end
		local layer_len = #layer
		if -delta <= layer_len then
			return rawget(layer, layer_len + delta + 1)
		end
		delta = delta + layer_len
		i = i - 1
	end
end

function Parser:push(route)
	local layer = {
		head = self.head,
		route = route
	}
	self[#self + 1] = layer
	self[-1] = layer
end

function Parser:push_sublayer(handler, inherit)
	local sublayer = {
		handler = handler,
		sublayer = true
	}
	if inherit then
		local layer = self[-1]
		setmetatable(sublayer, inherit_metamethods({
			__index = layer,
			__newindex = layer
		}, getmetatable(layer)))
	end
	self[#self + 1] = sublayer
	self[-1] = sublayer
end

function Parser:pop()
	local len, layer = #self
	while true do
		layer = self[len]
		self[len] = nil
		len = len - 1
		local new = self[len]
		self[-1] = new == nil and self or new
		if layer.sublayer == nil then
			break
		end
		self:emit_tokens(layer)
	end
	return layer
end

function Parser:pop_sublayer()
	local len, layer = #self, self[-1]
	self[len] = nil
	local new = self[len - 1]
	self[-1] = new == nil and self or new
	setmetatable(layer, nil)
	layer.sublayer = nil
	return layer
end

function Parser:get(route, ...)
	self:push(route)
	local layer = route(self, ...)
	if layer == nil then
		layer = self:traverse()
	end
	return layer
end

function Parser:try(route, ...)
	local failed_layer = get_nested(self.failed_routes, route, self.head)
	if failed_layer ~= nil then
		return false, failed_layer
	end
	local layer = self:get(route, ...)
	return not layer.fail, layer
end

function Parser:consume(this, ...)
	local layer = self[-1]
	if this == nil then
		this = self:read()
	end
	return (layer.override or layer.handler)(self, this, ...)
end

function Parser:fail_route()
	local layer = self:pop()
	layer.fail = true
	set_nested(self, "failed_routes", layer.route, layer.head, layer)
	self.head = layer.head
	return layer
end

function Parser:traverse()
	while true do
		local layer = self:consume()
		if layer ~= nil then
			return layer
		end
		self:advance()
	end
end

-- Converts a handler into a switch table the first time it's called, which avoids creating unnecessary objects, and prevents any scoping issues caused by parser methods being assigned to table keys before they've been declared.
-- false is used as the default key.
do
	local Switch = {}
	
	function Switch:__call(parser, this)
		return (self[this] or self[false])(parser, this)
	end
	
	function Parser:switch(func, t)
		local layer = self[-1]
		-- Point handler to the new switch table if the calling function is the current handler.
		if layer.handler == func then
			layer.handler = t
		end
		return setmetatable(t, Switch)
	end
end

-- Generate a new parser class object, which is used as the template for any parser objects. These should be customized with additional/modified methods as needed.
function Parser:new_class()
	local t = {}
	t.__index = t
	return setmetatable(inherit_metamethods(t, self), self)
end

-- Generate a new parser object, which is used for a specific parse.
function Parser:new(text)
	return setmetatable({
		text = text,
		head = 1
	}, self)
end

function Parser:parse(data)
	local parser = self:new(data.text)
	local success, tokens = parser:try(unpack(data.route))
	if #parser > 0 then
		-- This shouldn't happen.
		error("Parser exited with non-empty stack.")
	elseif success then
		local node = data.node
		return true, node[1]:new(tokens, unpack(node, 2)), parser
	elseif data.allow_fail then
		return false, nil, parser
	end
	error("Parser exited with failed route.")
end

export.class_else_type = class_else_type
export.is_node = is_node
export.tostring = tostring

function export.new()
	return Parser:new_class(), Node:new_class("node")
end

return export