summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/lualatex/yamlvars/tinyyaml.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/lualatex/yamlvars/tinyyaml.lua')
-rw-r--r--Master/texmf-dist/tex/lualatex/yamlvars/tinyyaml.lua816
1 files changed, 0 insertions, 816 deletions
diff --git a/Master/texmf-dist/tex/lualatex/yamlvars/tinyyaml.lua b/Master/texmf-dist/tex/lualatex/yamlvars/tinyyaml.lua
deleted file mode 100644
index b1a64708635..00000000000
--- a/Master/texmf-dist/tex/lualatex/yamlvars/tinyyaml.lua
+++ /dev/null
@@ -1,816 +0,0 @@
--------------------------------------------------------------------------------
--- tinyyaml - YAML subset parser
--------------------------------------------------------------------------------
-
-local table = table
-local string = string
-local schar = string.char
-local ssub, gsub = string.sub, string.gsub
-local sfind, smatch = string.find, string.match
-local tinsert, tconcat, tremove = table.insert, table.concat, table.remove
-local setmetatable = setmetatable
-local pairs = pairs
-local type = type
-local tonumber = tonumber
-local math = math
-local getmetatable = getmetatable
-local error = error
-
-local UNESCAPES = {
- ['0'] = "\x00", z = "\x00", N = "\x85",
- a = "\x07", b = "\x08", t = "\x09",
- n = "\x0a", v = "\x0b", f = "\x0c",
- r = "\x0d", e = "\x1b", ['\\'] = '\\',
-};
-
--------------------------------------------------------------------------------
--- utils
-local function select(list, pred)
- local selected = {}
- for i = 0, #list do
- local v = list[i]
- if v and pred(v, i) then
- tinsert(selected, v)
- end
- end
- return selected
-end
-
-local function startswith(haystack, needle)
- return ssub(haystack, 1, #needle) == needle
-end
-
-local function ltrim(str)
- return smatch(str, "^%s*(.-)$")
-end
-
-local function rtrim(str)
- return smatch(str, "^(.-)%s*$")
-end
-
-local function trim(str)
- return smatch(str, "^%s*(.-)%s*$")
-end
-
--------------------------------------------------------------------------------
--- Implementation.
---
-local class = {__meta={}}
-function class.__meta.__call(cls, ...)
- local self = setmetatable({}, cls)
- if cls.__init then
- cls.__init(self, ...)
- end
- return self
-end
-
-function class.def(base, typ, cls)
- base = base or class
- local mt = {__metatable=base, __index=base}
- for k, v in pairs(base.__meta) do mt[k] = v end
- cls = setmetatable(cls or {}, mt)
- cls.__index = cls
- cls.__metatable = cls
- cls.__type = typ
- cls.__meta = mt
- return cls
-end
-
-
-local types = {
- null = class:def('null'),
- map = class:def('map'),
- omap = class:def('omap'),
- pairs = class:def('pairs'),
- set = class:def('set'),
- seq = class:def('seq'),
- timestamp = class:def('timestamp'),
-}
-
-local Null = types.null
-function Null.__tostring() return 'yaml.null' end
-function Null.isnull(v)
- if v == nil then return true end
- if type(v) == 'table' and getmetatable(v) == Null then return true end
- return false
-end
-local null = Null()
-
-function types.timestamp:__init(y, m, d, h, i, s, f, z)
- self.year = tonumber(y)
- self.month = tonumber(m)
- self.day = tonumber(d)
- self.hour = tonumber(h or 0)
- self.minute = tonumber(i or 0)
- self.second = tonumber(s or 0)
- if type(f) == 'string' and sfind(f, '^%d+$') then
- self.fraction = tonumber(f) * math.pow(10, 3 - #f)
- elseif f then
- self.fraction = f
- else
- self.fraction = 0
- end
- self.timezone = z
-end
-
-function types.timestamp:__tostring()
- return string.format(
- '%04d-%02d-%02dT%02d:%02d:%02d.%03d%s',
- self.year, self.month, self.day,
- self.hour, self.minute, self.second, self.fraction,
- self:gettz())
-end
-
-function types.timestamp:gettz()
- if not self.timezone then
- return ''
- end
- if self.timezone == 0 then
- return 'Z'
- end
- local sign = self.timezone > 0
- local z = sign and self.timezone or -self.timezone
- local zh = math.floor(z)
- local zi = (z - zh) * 60
- return string.format(
- '%s%02d:%02d', sign and '+' or '-', zh, zi)
-end
-
-
-local function countindent(line)
- local _, j = sfind(line, '^%s+')
- if not j then
- return 0, line
- end
- return j, ssub(line, j+1)
-end
-
-local function parsestring(line, stopper)
- stopper = stopper or ''
- local q = ssub(line, 1, 1)
- if q == ' ' or q == '\t' then
- return parsestring(ssub(line, 2))
- end
- if q == "'" then
- local i = sfind(line, "'", 2, true)
- if not i then
- return nil, line
- end
- return ssub(line, 2, i-1), ssub(line, i+1)
- end
- if q == '"' then
- local i, buf = 2, ''
- while i < #line do
- local c = ssub(line, i, i)
- if c == '\\' then
- local n = ssub(line, i+1, i+1)
- if UNESCAPES[n] ~= nil then
- buf = buf..UNESCAPES[n]
- elseif n == 'x' then
- local h = ssub(i+2,i+3)
- if sfind(h, '^[0-9a-fA-F]$') then
- buf = buf..schar(tonumber(h, 16))
- i = i + 2
- else
- buf = buf..'x'
- end
- else
- buf = buf..n
- end
- i = i + 1
- elseif c == q then
- break
- else
- buf = buf..c
- end
- i = i + 1
- end
- return buf, ssub(line, i+1)
- end
- if q == '{' or q == '[' then -- flow style
- return nil, line
- end
- if q == '|' or q == '>' then -- block
- return nil, line
- end
- if q == '-' or q == ':' then
- if ssub(line, 2, 2) == ' ' or ssub(line, 2, 2) == '\n' or #line == 1 then
- return nil, line
- end
- end
- local buf = ''
- while #line > 0 do
- local c = ssub(line, 1, 1)
- if sfind(stopper, c, 1, true) then
- break
- elseif c == ':' and (ssub(line, 2, 2) == ' ' or ssub(line, 2, 2) == '\n' or #line == 1) then
- break
- elseif c == '#' and (ssub(buf, #buf, #buf) == ' ') then
- break
- else
- buf = buf..c
- end
- line = ssub(line, 2)
- end
- return rtrim(buf), line
-end
-
-local function isemptyline(line)
- return line == '' or sfind(line, '^%s*$') or sfind(line, '^%s*#')
-end
-
-local function equalsline(line, needle)
- return startswith(line, needle) and isemptyline(ssub(line, #needle+1))
-end
-
-local function compactifyemptylines(lines)
- -- Appends empty lines as "\n" to the end of the nearest preceding non-empty line
- local compactified = {}
- local lastline = {}
- for i = 1, #lines do
- local line = lines[i]
- if isemptyline(line) then
- if #compactified > 0 and i < #lines then
- tinsert(lastline, "\n")
- end
- else
- if #lastline > 0 then
- tinsert(compactified, tconcat(lastline, ""))
- end
- lastline = {line}
- end
- end
- if #lastline > 0 then
- tinsert(compactified, tconcat(lastline, ""))
- end
- return compactified
-end
-
-local function checkdupekey(map, key)
- if map[key] ~= nil then
- -- print("found a duplicate key '"..key.."' in line: "..line)
- local suffix = 1
- while map[key..'_'..suffix] do
- suffix = suffix + 1
- end
- key = key ..'_'..suffix
- end
- return key
-end
-
-local function parseflowstyle(line, lines)
- local stack = {}
- while true do
- if #line == 0 then
- if #lines == 0 then
- break
- else
- line = tremove(lines, 1)
- end
- end
- local c = ssub(line, 1, 1)
- if c == '#' then
- line = ''
- elseif c == ' ' or c == '\t' or c == '\r' or c == '\n' then
- line = ssub(line, 2)
- elseif c == '{' or c == '[' then
- tinsert(stack, {v={},t=c})
- line = ssub(line, 2)
- elseif c == ':' then
- local s = tremove(stack)
- tinsert(stack, {v=s.v, t=':'})
- line = ssub(line, 2)
- elseif c == ',' then
- local value = tremove(stack)
- if value.t == ':' or value.t == '{' or value.t == '[' then error() end
- if stack[#stack].t == ':' then
- -- map
- local key = tremove(stack)
- key.v = checkdupekey(stack[#stack].v, key.v)
- stack[#stack].v[key.v] = value.v
- elseif stack[#stack].t == '{' then
- -- set
- stack[#stack].v[value.v] = true
- elseif stack[#stack].t == '[' then
- -- seq
- tinsert(stack[#stack].v, value.v)
- end
- line = ssub(line, 2)
- elseif c == '}' then
- if stack[#stack].t == '{' then
- if #stack == 1 then break end
- stack[#stack].t = '}'
- line = ssub(line, 2)
- else
- line = ','..line
- end
- elseif c == ']' then
- if stack[#stack].t == '[' then
- if #stack == 1 then break end
- stack[#stack].t = ']'
- line = ssub(line, 2)
- else
- line = ','..line
- end
- else
- local s, rest = parsestring(line, ',{}[]')
- if not s then
- error('invalid flowstyle line: '..line)
- end
- tinsert(stack, {v=s, t='s'})
- line = rest
- end
- end
- return stack[1].v, line
-end
-
-local function parseblockstylestring(line, lines, indent)
- if #lines == 0 then
- error("failed to find multi-line scalar content")
- end
- local s = {}
- local firstindent = -1
- local endline = -1
- for i = 1, #lines do
- local ln = lines[i]
- local idt = countindent(ln)
- if idt <= indent then
- break
- end
- if ln == '' then
- tinsert(s, '')
- else
- if firstindent == -1 then
- firstindent = idt
- elseif idt < firstindent then
- break
- end
- tinsert(s, ssub(ln, firstindent + 1))
- end
- endline = i
- end
-
- local striptrailing = true
- local sep = '\n'
- local newlineatend = true
- if line == '|' then
- striptrailing = true
- sep = '\n'
- newlineatend = true
- elseif line == '|+' then
- striptrailing = false
- sep = '\n'
- newlineatend = true
- elseif line == '|-' then
- striptrailing = true
- sep = '\n'
- newlineatend = false
- elseif line == '>' then
- striptrailing = true
- sep = ' '
- newlineatend = true
- elseif line == '>+' then
- striptrailing = false
- sep = ' '
- newlineatend = true
- elseif line == '>-' then
- striptrailing = true
- sep = ' '
- newlineatend = false
- else
- error('invalid blockstyle string:'..line)
- end
- local _, eonl = s[#s]:gsub('\n', '\n')
- s[#s] = rtrim(s[#s])
- if striptrailing then
- eonl = 0
- end
- if newlineatend then
- eonl = eonl + 1
- end
- for i = endline, 1, -1 do
- tremove(lines, i)
- end
- return tconcat(s, sep)..string.rep('\n', eonl)
-end
-
-local function parsetimestamp(line)
- local _, p1, y, m, d = sfind(line, '^(%d%d%d%d)%-(%d%d)%-(%d%d)')
- if not p1 then
- return nil, line
- end
- if p1 == #line then
- return types.timestamp(y, m, d), ''
- end
- local _, p2, h, i, s = sfind(line, '^[Tt ](%d+):(%d+):(%d+)', p1+1)
- if not p2 then
- return types.timestamp(y, m, d), ssub(line, p1+1)
- end
- if p2 == #line then
- return types.timestamp(y, m, d, h, i, s), ''
- end
- local _, p3, f = sfind(line, '^%.(%d+)', p2+1)
- if not p3 then
- p3 = p2
- f = 0
- end
- local zc = ssub(line, p3+1, p3+1)
- local _, p4, zs, z = sfind(line, '^ ?([%+%-])(%d+)', p3+1)
- if p4 then
- z = tonumber(z)
- local _, p5, zi = sfind(line, '^:(%d+)', p4+1)
- if p5 then
- z = z + tonumber(zi) / 60
- end
- z = zs == '-' and -tonumber(z) or tonumber(z)
- elseif zc == 'Z' then
- p4 = p3 + 1
- z = 0
- else
- p4 = p3
- z = false
- end
- return types.timestamp(y, m, d, h, i, s, f, z), ssub(line, p4+1)
-end
-
-local function parsescalar(line, lines, indent)
- line = trim(line)
- line = gsub(line, '^%s*#.*$', '') -- comment only -> ''
- line = gsub(line, '^%s*', '') -- trim head spaces
-
- if line == '' or line == '~' then
- return null
- end
-
- local ts, _ = parsetimestamp(line)
- if ts then
- return ts
- end
-
- local s, _ = parsestring(line)
- -- startswith quote ... string
- -- not startswith quote ... maybe string
- if s and (startswith(line, '"') or startswith(line, "'")) then
- return s
- end
-
- if startswith('!', line) then -- unexpected tagchar
- error('unsupported line: '..line)
- end
-
- if equalsline(line, '{}') then
- return {}
- end
- if equalsline(line, '[]') then
- return {}
- end
-
- if startswith(line, '{') or startswith(line, '[') then
- return parseflowstyle(line, lines)
- end
-
- if startswith(line, '|') or startswith(line, '>') then
- return parseblockstylestring(line, lines, indent)
- end
-
- -- Regular unquoted string
- line = gsub(line, '%s*#.*$', '') -- trim tail comment
- local v = line
- if v == 'null' or v == 'Null' or v == 'NULL'then
- return null
- elseif v == 'true' or v == 'True' or v == 'TRUE' then
- return true
- elseif v == 'false' or v == 'False' or v == 'FALSE' then
- return false
- elseif v == '.inf' or v == '.Inf' or v == '.INF' then
- return math.huge
- elseif v == '+.inf' or v == '+.Inf' or v == '+.INF' then
- return math.huge
- elseif v == '-.inf' or v == '-.Inf' or v == '-.INF' then
- return -math.huge
- elseif v == '.nan' or v == '.NaN' or v == '.NAN' then
- return 0 / 0
- elseif sfind(v, '^[%+%-]?[0-9]+$') or sfind(v, '^[%+%-]?[0-9]+%.$')then
- return tonumber(v) -- : int
- elseif sfind(v, '^[%+%-]?[0-9]+%.[0-9]+$') then
- return tonumber(v)
- end
- return s or v
-end
-
-local parsemap; -- : func
-
-local function parseseq(line, lines, indent)
- local seq = setmetatable({}, types.seq)
- if line ~= '' then
- error()
- end
- while #lines > 0 do
- -- Check for a new document
- line = lines[1]
- if startswith(line, '---') then
- while #lines > 0 and not startswith(lines, '---') do
- tremove(lines, 1)
- end
- return seq
- end
-
- -- Check the indent level
- local level = countindent(line)
- if level < indent then
- return seq
- elseif level > indent then
- error("found bad indenting in line: ".. line)
- end
-
- local i, j = sfind(line, '%-%s+')
- if not i then
- i, j = sfind(line, '%-$')
- if not i then
- return seq
- end
- end
- local rest = ssub(line, j+1)
-
- if sfind(rest, '^[^\'\"%s]*:%s*$') or sfind(rest, '^[^\'\"%s]*:%s+.') then
- -- Inline nested hash
- -- There are two patterns need to match as inline nested hash
- -- first one should have no other characters except whitespace after `:`
- -- and the second one should have characters besides whitespace after `:`
- --
- -- value:
- -- - foo:
- -- bar: 1
- --
- -- and
- --
- -- value:
- -- - foo: bar
- --
- -- And there is one pattern should not be matched, where there is no space after `:`
- -- in below, `foo:bar` should be parsed into a single string
- --
- -- value:
- -- - foo:bar
- local indent2 = j
- lines[1] = string.rep(' ', indent2)..rest
- tinsert(seq, parsemap('', lines, indent2))
- elseif sfind(rest, '^%-%s+') then
- -- Inline nested seq
- local indent2 = j
- lines[1] = string.rep(' ', indent2)..rest
- tinsert(seq, parseseq('', lines, indent2))
- elseif isemptyline(rest) then
- tremove(lines, 1)
- if #lines == 0 then
- tinsert(seq, null)
- return seq
- end
- if sfind(lines[1], '^%s*%-') then
- local nextline = lines[1]
- local indent2 = countindent(nextline)
- if indent2 == indent then
- -- Null seqay entry
- tinsert(seq, null)
- else
- tinsert(seq, parseseq('', lines, indent2))
- end
- else
- -- - # comment
- -- key: value
- local nextline = lines[1]
- local indent2 = countindent(nextline)
- tinsert(seq, parsemap('', lines, indent2))
- end
- elseif rest then
- -- Array entry with a value
- tremove(lines, 1)
- tinsert(seq, parsescalar(rest, lines))
- end
- end
- return seq
-end
-
-local function parseset(line, lines, indent)
- if not isemptyline(line) then
- error('not seq line: '..line)
- end
- local set = setmetatable({}, types.set)
- while #lines > 0 do
- -- Check for a new document
- line = lines[1]
- if startswith(line, '---') then
- while #lines > 0 and not startswith(lines, '---') do
- tremove(lines, 1)
- end
- return set
- end
-
- -- Check the indent level
- local level = countindent(line)
- if level < indent then
- return set
- elseif level > indent then
- error("found bad indenting in line: ".. line)
- end
-
- local i, j = sfind(line, '%?%s+')
- if not i then
- i, j = sfind(line, '%?$')
- if not i then
- return set
- end
- end
- local rest = ssub(line, j+1)
-
- if sfind(rest, '^[^\'\"%s]*:') then
- -- Inline nested hash
- local indent2 = j
- lines[1] = string.rep(' ', indent2)..rest
- set[parsemap('', lines, indent2)] = true
- elseif sfind(rest, '^%s+$') then
- tremove(lines, 1)
- if #lines == 0 then
- tinsert(set, null)
- return set
- end
- if sfind(lines[1], '^%s*%?') then
- local indent2 = countindent(lines[1])
- if indent2 == indent then
- -- Null array entry
- set[null] = true
- else
- set[parseseq('', lines, indent2)] = true
- end
- end
-
- elseif rest then
- tremove(lines, 1)
- set[parsescalar(rest, lines)] = true
- else
- error("failed to classify line: "..line)
- end
- end
- return set
-end
-
-function parsemap(line, lines, indent)
- if not isemptyline(line) then
- error('not map line: '..line)
- end
- local map = setmetatable({}, types.map)
- while #lines > 0 do
- -- Check for a new document
- line = lines[1]
- if startswith(line, '---') then
- while #lines > 0 and not startswith(lines, '---') do
- tremove(lines, 1)
- end
- return map
- end
-
- -- Check the indent level
- local level, _ = countindent(line)
- if level < indent then
- return map
- elseif level > indent then
- error("found bad indenting in line: ".. line)
- end
-
- -- Find the key
- local key
- local s, rest = parsestring(line)
-
- -- Quoted keys
- if s and startswith(rest, ':') then
- local sc = parsescalar(s, {}, 0)
- if sc and type(sc) ~= 'string' then
- key = sc
- else
- key = s
- end
- line = ssub(rest, 2)
- else
- error("failed to classify line: "..line)
- end
-
- key = checkdupekey(map, key)
- line = ltrim(line)
-
- if ssub(line, 1, 1) == '!' then
- -- ignore type
- local rh = ltrim(ssub(line, 3))
- local typename = smatch(rh, '^!?[^%s]+')
- line = ltrim(ssub(rh, #typename+1))
- end
-
- if not isemptyline(line) then
- tremove(lines, 1)
- line = ltrim(line)
- map[key] = parsescalar(line, lines, indent)
- else
- -- An indent
- tremove(lines, 1)
- if #lines == 0 then
- map[key] = null
- return map;
- end
- if sfind(lines[1], '^%s*%-') then
- local indent2 = countindent(lines[1])
- map[key] = parseseq('', lines, indent2)
- elseif sfind(lines[1], '^%s*%?') then
- local indent2 = countindent(lines[1])
- map[key] = parseset('', lines, indent2)
- else
- local indent2 = countindent(lines[1])
- if indent >= indent2 then
- -- Null hash entry
- map[key] = null
- else
- map[key] = parsemap('', lines, indent2)
- end
- end
- end
- end
- return map
-end
-
-
--- : (list<str>)->dict
-local function parsedocuments(lines)
- lines = compactifyemptylines(lines)
-
- if sfind(lines[1], '^%%YAML') then tremove(lines, 1) end
-
- local root = {}
- local in_document = false
- while #lines > 0 do
- local line = lines[1]
- -- Do we have a document header?
- local docright;
- if sfind(line, '^%-%-%-') then
- -- Handle scalar documents
- docright = ssub(line, 4)
- tremove(lines, 1)
- in_document = true
- end
- if docright then
- if (not sfind(docright, '^%s+$') and
- not sfind(docright, '^%s+#')) then
- tinsert(root, parsescalar(docright, lines))
- end
- elseif #lines == 0 or startswith(line, '---') then
- -- A naked document
- tinsert(root, null)
- while #lines > 0 and not sfind(lines[1], '---') do
- tremove(lines, 1)
- end
- in_document = false
- -- XXX The final '-+$' is to look for -- which ends up being an
- -- error later.
- elseif not in_document and #root > 0 then
- -- only the first document can be explicit
- error('parse error: '..line)
- elseif sfind(line, '^%s*%-') then
- -- An array at the root
- tinsert(root, parseseq('', lines, 0))
- elseif sfind(line, '^%s*[^%s]') then
- -- A hash at the root
- local level = countindent(line)
- tinsert(root, parsemap('', lines, level))
- else
- -- Shouldn't get here. @lines have whitespace-only lines
- -- stripped, and previous match is a line with any
- -- non-whitespace. So this clause should only be reachable via
- -- a perlbug where \s is not symmetric with \S
-
- -- uncoverable statement
- error('parse error: '..line)
- end
- end
- if #root > 1 and Null.isnull(root[1]) then
- tremove(root, 1)
- return root
- end
- return root
-end
-
---- Parse yaml string into table.
-local function parse(source)
- local lines = {}
- for line in string.gmatch(source .. '\n', '(.-)\r?\n') do
- tinsert(lines, line)
- end
-
- local docs = parsedocuments(lines)
- if #docs == 1 then
- return docs[1]
- end
-
- return docs
-end
-
-return {
- version = 0.1,
- parse = parse,
-}