Skip to content

Commit

Permalink
refactor(core): Promote Lua input detection to first class
Browse files Browse the repository at this point in the history
  • Loading branch information
alerque committed Jun 30, 2022
1 parent 50c73f9 commit 684dd78
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 27 deletions.
30 changes: 17 additions & 13 deletions core/sile.lua
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ SILE.baseClass = setmetatable({}, {
__index = nobaseclass
})

local defaultinputters = { "xml", "lua", "sil" }

SILE.init = function ()
-- Set by def
if not SILE.backend then
Expand Down Expand Up @@ -134,10 +136,6 @@ SILE.init = function ()
local _, err = pcall(func)
if err then error(err) end
end
-- Preload default reader types so content detection has something to work with
for _, inputter in ipairs({ "sil", "xml" }) do
local _ = SILE.inputters[inputter]
end
end

SILE.require = function (dependency, pathprefix, deprecation_ack)
Expand Down Expand Up @@ -196,6 +194,10 @@ SILE.process = function (input)
end

function SILE.readFile (filename)
-- Preload default reader types so content detection has something to work with
for _, inputter in ipairs(defaultinputters) do
local _ = SILE.inputters[inputter]
end
SILE.currentlyProcessingFile = filename
local doc
if filename == "-" then
Expand All @@ -218,25 +220,27 @@ function SILE.readFile (filename)
print("Could not open "..filename..": "..err)
return
end
io.stderr:write("<"..filename..">\n")
io.stderr:write("<"..filename..">")
doc = file:read("*a")
end
local sniff = doc:sub(1, 100):gsub("begin.*", "") or ""
local contentDetectionOrder = {}
for _, inputter in pairs(SILE.inputters) do
if inputter.order then table.insert(contentDetectionOrder, inputter) end
end
table.sort(contentDetectionOrder, function (a, b) return a.order < b.order end)
for _, inputter in ipairs(contentDetectionOrder) do
if inputter.appropriate(filename, sniff) then
SILE.inputter = inputter()
local pId = SILE.traceStack:pushDocument(filename, sniff, doc)
SILE.inputter:process(doc)
SILE.traceStack:pop(pId)
return
for round = 1, 3 do
if inputter.appropriate(round, filename, doc) then
io.stderr:write(" as " .. inputter._name .. "\n")
SILE.inputter = inputter()
local pId = SILE.traceStack:pushDocument(filename, doc)
SILE.inputter:process(doc)
SILE.traceStack:pop(pId)
return
end
end
end
SU.error("No input processor available for "..filename.." (should never happen)", true)
SU.error(("Unable to pick inputter to process input from '%s'"):format(filename))
end

-- Sort through possible places files could be
Expand Down
11 changes: 6 additions & 5 deletions core/tracestack.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ traceStack.defaultFrame = pl.class({

traceStack.documentFrame = pl.class(traceStack.defaultFrame)

function traceStack.documentFrame:_init (file, sniff)
function traceStack.documentFrame:_init (file, snippet)
self.command = "document"
self.file = file
self.sniff = sniff
self.snippet = snippet
end

function traceStack.documentFrame:__tostring ()
return "<file> (" .. self.sniff .. ")"
return "<file> (" .. self.snippet .. ")"
end

traceStack.commandFrame = pl.class(traceStack.defaultFrame)
Expand Down Expand Up @@ -89,8 +89,9 @@ local function formatTraceLine (string)
end

-- Push a document processing run (input method) onto the stack
function traceStack:pushDocument(file, sniff, _)
local frame = traceStack.documentFrame(file, sniff)
function traceStack:pushDocument(file, doc)
local snippet = doc:sub(1, 100)
local frame = traceStack.documentFrame(file, snippet)
return self:pushFrame(frame)
end

Expand Down
26 changes: 26 additions & 0 deletions inputters/lua.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
local base = require("inputters.base")

local lua = pl.class(base)
lua._name = "lua"

lua.order = 99

function lua.appropriate (round, filename, doc)
if round == 1 then
return filename:match("lua$")
elseif round == 2 then
local sniff = doc:sub(1, 100)
return sniff:match("^--") or sniff:match("^local") or sniff:match("^return")
elseif round == 3 then
local _, err = pcall(function () assert(load(doc)) end)
return not err
end
end

function lua:process (doc)
local root = SILE.documentState.documentClass == nil
local tree = load(doc)()
if root then self:classInit(tree) end
end

return lua
21 changes: 16 additions & 5 deletions inputters/sil.lua
Original file line number Diff line number Diff line change
@@ -1,12 +1,25 @@
local base = require("inputters.base")

local lpeg = require("lpeg")
local epnf = require("epnf")

local base = require("inputters.base")
local sil = pl.class(base)
sil._name = "sil"

sil.order = 99
sil.appropriate = function () return true end
sil.order = 50

sil.appropriate = function (round, filename, doc)
if round == 1 then
return filename:match("sil$")
elseif round == 2 then
local sniff = doc:sub(1, 100)
return sniff:match("\\begin") or sniff:match("\\document")
elseif round == 3 then
local _parser = sil:rebuildParser()
local _, err = pcall(function () assert(epnf.parsestring(_parser, doc)) end)
return not err
end
end

local ID = lpeg.C(SILE.parserBits.letter * (SILE.parserBits.letter + SILE.parserBits.digit)^0)
sil.identifier = (ID + lpeg.S":-")^1
Expand Down Expand Up @@ -189,8 +202,6 @@ function sil:process (doc)
self:classInit(tree)
end
SILE.process(tree)
elseif not pcall(function () assert(load(doc))() end) then
SU.error("Input not recognized as Lua or SILE content")
end
if root and not SILE.preamble then
SILE.documentState.documentClass:finish()
Expand Down
18 changes: 14 additions & 4 deletions inputters/xml.lua
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
local base = require("inputters.base")

local lom = require("lomwithpos")

local xml = pl.class(base)
xml._name = "xml"

xml.order = 1
xml.order = 2

function xml.appropriate (filename, sniff)
return filename:match("xml$") or sniff:match("<")
function xml.appropriate (round, filename, doc)
if round == 1 then
return filename:match("xml$")
elseif round == 2 then
local sniff = doc:sub(1, 100):gsub("begin.*", "") or ""
return sniff:match("<")
elseif round == 3 then
local _, err = lom.parse(doc)
return not err
end
end

function xml:process (doc)
local lom = require("lomwithpos")
local content, err = lom.parse(doc)
if content == nil then
error(err)
Expand Down

0 comments on commit 684dd78

Please sign in to comment.