diff options
-rw-r--r-- | data/pandoc.lua | 134 |
1 files changed, 83 insertions, 51 deletions
diff --git a/data/pandoc.lua b/data/pandoc.lua index f6484f05e..ebe14cb0c 100644 --- a/data/pandoc.lua +++ b/data/pandoc.lua @@ -29,39 +29,54 @@ local M = { local List = require 'pandoc.List' ------------------------------------------------------------------------ --- The base class for pandoc's AST elements. --- @type AstElement +-- The base class for types +-- @type Type -- @local -local AstElement = {} -AstElement.__index = AstElement +local Type = {} +Type.name = 'Type' +Type.__index = Type +Type.behavior = { + __type = Type, + new = function (obj) + obj = obj or {} + setmetatable(obj, self) + return obj + end +} +Type.behavior.__index = Type.behavior ---- Create a new element subtype +--- Set a new behavior for the type, inheriting that of the parent type if none +--- is specified explicitely +-- @param behavior the behavior object for this type. -- @local -function AstElement:make_subtype(o) - o = o or {} - setmetatable(o, self) - -- Make subtype usable as a metatable - o.__index = o - return o +function Type:set_behavior (behavior) + behavior = behavior or {} + behavior.__index = rawget(behavior, '__index') or behavior + behavior.__type = self + if not getmetatable(behavior) and getmetatable(self) then + setmetatable(behavior, getmetatable(self).behavior) + end + self.behavior = behavior end ---- Create a new element given its tag and arguments +--- Create a new subtype, using the given table as base. +-- @param obj type object -- @local -function AstElement:new(tag, ...) - local element = { t = tag } - local content = {...} - -- special case for unary constructors - if #content == 1 then - element.c = content[1] - -- Don't set 'c' field if no further arguments were given. This is important - -- for nullary constructors like `Space` and `HorizontalRule`. - elseif #content > 0 then - element.c = content - end - setmetatable(element, self) - return element +function Type:make_subtype(name, behavior) + local newtype = setmetatable({}, self) + newtype.name = name + newtype.__index = newtype + newtype:set_behavior(behavior) + return newtype end + +------------------------------------------------------------------------ +-- The base class for pandoc's AST elements. +-- @type AstElement +-- @local +local AstElement = Type:make_subtype 'AstElement' + --- Create a new constructor -- @local -- @param tag Tag used to identify the constructor @@ -69,31 +84,48 @@ end -- @param accessors names to use as accessors for numerical fields -- @return function that constructs a new element function AstElement:create_constructor(tag, fn, accessors) - local constr = self:make_subtype({tag = tag, getters = {}, setters = {}}) + local constr = self:make_subtype(tag, {tag = tag, getters = {}, setters = {}}) + behavior = constr.behavior + behavior.__index = function(t, k) + if getmetatable(t).getters[k] then + return getmetatable(t).getters[k](t) + elseif k == "t" then + return getmetatable(t)["tag"] + else + return getmetatable(t)[k] + end + end + behavior.__newindex = function(t, k, v) + if getmetatable(t).setters[k] then + getmetatable(t).setters[k](t, v) + else + rawset(t, k, v) + end + end -- Add accessors to the metatable if type(accessors) == "string" then - constr.getters[accessors] = function(elem) + behavior.getters[accessors] = function(elem) return elem.c end - constr.setters[accessors] = function(elem, v) + behavior.setters[accessors] = function(elem, v) elem.c = v end else for i = 1, #(accessors or {}) do if type(accessors[i]) == "string" then - constr.getters[accessors[i]] = function(elem) + behavior.getters[accessors[i]] = function(elem) return elem.c[i] end - constr.setters[accessors[i]] = function(elem, v) + behavior.setters[accessors[i]] = function(elem, v) elem.c[i] = v end else -- only two levels of nesting are supported for k, v in ipairs(accessors[i]) do - constr.getters[v] = function(elem) + behavior.getters[v] = function(elem) return elem.c[i][k] end - constr.setters[v] = function(elem, v) + behavior.setters[v] = function(elem, v) elem.c[i][k] = v end end @@ -102,31 +134,31 @@ function AstElement:create_constructor(tag, fn, accessors) end function constr:new(...) - local obj = fn(...) - setmetatable(obj, self) - self.__index = function(t, k) - if getmetatable(t).getters[k] then - return getmetatable(t).getters[k](t) - elseif k == "t" then - return getmetatable(t)["tag"] - else - return getmetatable(t)[k] - end - end - self.__newindex = function(t, k, v) - if getmetatable(t).setters[k] then - getmetatable(t).setters[k](t, v) - else - rawset(t, k, v) - end - end - return obj + return setmetatable(fn(...), self.behavior) end self.constructor = self.constructor or {} self.constructor[tag] = constr return constr end +--- Create a new element given its tag and arguments +-- @local +function AstElement.new(constr, ...) + local element = { t = constr.__type.name } + local content = {...} + -- special case for unary constructors + if #content == 1 then + element.c = content[1] + -- Don't set 'c' field if no further arguments were given. This is important + -- for nullary constructors like `Space` and `HorizontalRule`. + elseif #content > 0 then + element.c = content + end + setmetatable(element, constr) + element.__index = element + return element +end + ------------------------------------------------------------------------ --- Pandoc Document -- @section document |