From 822a74f6dc7b1056eccb9f7d070457bb0994f9a2 Mon Sep 17 00:00:00 2001 From: Caleb Maclennan Date: Thu, 3 Oct 2024 17:43:07 +0300 Subject: [PATCH] feat(outputters): Promote pseudo AST backend to full-blow outputter This also comes with the ability for *any* outputter to pre-process the AST tree if it wanted to (e.g. for remove leaf types it would not be able to output. If the outputter doesn't do anything to the AST it is just a pass-through step. Note this does *not* yet walk the AST and do any AST munging that functions might engage in, it only catches the top level tree as parsed by the inputter. Additionally it is not a full serialization of the AST that could be read back in with an input driver. We'd need a new dependency on something like serpent for that, which would be a lovely next step. --- core/sile.lua | 12 +++++------- inputters/base.lua | 3 --- outputters/ast.lua | 27 +++++++++++++++++++++++++++ outputters/base.lua | 4 ++++ 4 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 outputters/ast.lua diff --git a/core/sile.lua b/core/sile.lua index 1c8bf90a4..85f2eb424 100644 --- a/core/sile.lua +++ b/core/sile.lua @@ -208,10 +208,6 @@ function SILE.init () if not SILE.backend then SILE.backend = "libtexpdf" end - if SILE.backend == "ast" then - runEvals(SILE.input.evaluates, "evaluate") - return -- Short circuit for AST processing only - end if SILE.backend == "libtexpdf" then SILE.shaper = SILE.shapers.harfbuzz() SILE.outputter = SILE.outputters.libtexpdf() @@ -227,6 +223,9 @@ function SILE.init () elseif SILE.backend == "dummy" then SILE.shaper = SILE.shapers.dummy() SILE.outputter = SILE.outputters.dummy() + elseif SILE.backend == "ast" then + SILE.shaper = SILE.shapers.dummy() + SILE.outputter = SILE.outputters.ast() end SILE.pagebuilder = SILE.pagebuilders.base() io.stdout:setvbuf("no") @@ -399,6 +398,7 @@ end -- iterate through the tree handling each item in the order encountered. -- @tparam table ast SILE content in abstract syntax tree format (a table of strings, functions, or more AST trees). function SILE.process (ast) + ast = SILE.outputter:preProcess(ast) if not ast then return end @@ -699,9 +699,7 @@ end -- 5. Close out the Lua profiler if it was running. -- 6. Output version information if versions debug flag is set. function SILE.finish () - if SILE.documentState.documentClass then - SILE.documentState.documentClass:finish() - end + SILE.documentState.documentClass:finish() SILE.font.finish() runEvals(SILE.input.evaluateAfters, "evaluate-after") if SILE.makeDeps then diff --git a/inputters/base.lua b/inputters/base.lua index 012172fcb..2a076f244 100644 --- a/inputters/base.lua +++ b/inputters/base.lua @@ -49,9 +49,6 @@ end function inputter:process (doc) -- Input parsers can already return multiple ASTs, but so far we only process one local tree = self:parse(doc)[1] - if not SILE.outputter then - return pl.pretty.dump(tree) - end self:requireClass(tree) return SILE.process(tree) end diff --git a/outputters/ast.lua b/outputters/ast.lua new file mode 100644 index 000000000..047f53bf0 --- /dev/null +++ b/outputters/ast.lua @@ -0,0 +1,27 @@ +local base = require("outputters.base") + +local outputter = pl.class(base) +outputter._name = "ast" +outputter.extension = "ast" + +local outfile + +function outputter:_ensureInit () + if not outfile then + local fname = self:getOutputFilename() + outfile = fname == "-" and io.stdout or io.open(fname, "w+") + end +end + +function outputter:preProcess (ast) + self:_ensureInit() + local prettyprinted = pl.pretty.write(ast, " ") + outfile:write(prettyprinted) +end + +function outputter:finish () + self:runHooks("prefinish") + outfile:close() +end + +return outputter diff --git a/outputters/base.lua b/outputters/base.lua index 3ea3335e1..32ef11d3b 100644 --- a/outputters/base.lua +++ b/outputters/base.lua @@ -27,6 +27,10 @@ function outputter:runHooks (category, data) return data end +function outputter:preProcess (ast) + return ast +end + function outputter.newPage () end function outputter:finish ()