Warning: this is an htmlized version!
The original is here, and
the conversion rules are here.
-- This file:
-- http://angg.twu.net/dednat6/dednat6/output.lua
-- http://angg.twu.net/dednat6/dednat6/output.lua.html
--         (find-angg "dednat6/dednat6/output.lua")
-- By Eduardo Ochs <eduardoochs@gmail.com>
-- Version: 2021jun06
--
-- Sending (Lua-produced) TeX code back to the TeX interpreter requires
-- some preprocessing... see:
--   (find-es "luatex" "comments-in-tex.print")
--   (find-es "luatex" "spurious-omega")
--
-- Usage:
--   \catcode`\^^J=10                     % (find-es "luatex" "spurious-omega")
--   \directlua{output = mytexprint}
--   \directlua{output =  printboth}
-- or: (...)

-- «.deletecomments_2015»	(to "deletecomments_2015")
-- «.deletecomments_2019»	(to "deletecomments_2019")
-- «.deletecomments_2019-tests»	(to "deletecomments_2019-tests")
-- «.DeleteComments»		(to "DeleteComments")
-- «.Deletecomments-class»	(to "Deletecomments-class")
-- «.DeleteComments-tests»	(to "DeleteComments-tests")
-- «.deletecomments_2021»	(to "deletecomments_2021")
-- «.deletecomments»		(to "deletecomments")
-- «.output»			(to "output")
-- «.output_dnt»		(to "output_dnt")
-- «.write_dnt_file»		(to "write_dnt_file")
-- «.write_single_tex_file»	(to "write_single_tex_file")
-- «.formatt»			(to "formatt")
-- «.bprintt»			(to "bprintt")



--      _      _      _                                                _       
--   __| | ___| | ___| |_ ___  ___ ___  _ __ ___  _ __ ___   ___ _ __ | |_ ___ 
--  / _` |/ _ \ |/ _ \ __/ _ \/ __/ _ \| '_ ` _ \| '_ ` _ \ / _ \ '_ \| __/ __|
-- | (_| |  __/ |  __/ ||  __/ (_| (_) | | | | | | | | | | |  __/ | | | |_\__ \
--  \__,_|\___|_|\___|\__\___|\___\___/|_| |_| |_|_| |_| |_|\___|_| |_|\__|___/
--                                                                             
-- «deletecomments_2015»  (to ".deletecomments_2015")
-- See: (find-es "luatex" "comments-in-tex.print")
deletecomments_2015 = function (str)
    return (str:gsub("%%[^%%\n]*\n[ \t]*", ""))
  end

-- «deletecomments_2019»  (to ".deletecomments_2019")
-- The version below (from 2019apr29) is a bit better than
-- deletecomments_2015 but still not very smart. It converts each
-- line made of blank spaces followed by something like "%this" to a
-- line made of just the blank spaces, and it treats the "%bar" in a
-- line like "foo\%bar" as comment, and converts that to "foo\".
--
deletecomments1 = function (line)
    return line:match"^([^%%]*)"
  end
deletecomments_2019 = function (bigstr)
    return (bigstr:gsub("([^\n]+)", deletecomments1))
  end

-- «deletecomments_2019-tests»  (to ".deletecomments_2019-tests")
--[[
 (eepitch-lua51)
 (eepitch-kill)
 (eepitch-lua51)
dofile "output.lua"
-- Good:
= deletecomments_2019 "a % b % c"
= deletecomments_2019 "a % b % c\nd \\% e % f"
-- Bad:
= deletecomments_2019 "foo\\%bar"
= deletecomments_2019 "foo\n %bar\n %plic\n bletch"

--]]



-- «DeleteComments»  (to ".DeleteComments")
-- «Deletecomments-class»  (to ".Deletecomments-class")
-- New (2021jun05): the class DeleteComments implements a way to
-- delete comments that TRIES to simulate what TeX does. The TeXBook
-- explains in its pages 46-47 that the "eyes" and "mouth" of TeX
-- enter the "State S" (for "skipping blanks") after a "%"; we
-- simulate that by splitting bigstr in a certain way, and then after
-- each "%" we delete the "%..." part of that line plus the
-- whitespaces and newlines in (hopefully) the right places.
--
-- This version doesn't treat backslashes followed by "%"s in the
-- right way. This is still to be done.
--
-- See: (find-es "tex" "comments")
--      (find-es "tex" "comments" "Skipping blanks")
--
DeleteComments = Class {
  type  = "DeleteComments",
  split = function (bigstr)
      local A = {}
      for _,li in ipairs(splitlines(bigstr)) do
        local a,b = li:match("^([^%%]*)(.*)")
        table.insert(A, {a, b, "\n"})
      end
      return DeleteComments(A)
    end,
  from = function (bigstr)
      return DeleteComments.split(bigstr):delcomments():concat()
    end,
  __tostring = function (dc) return mytabletostring(dc) end,
  __index = {
      hascomment = function (dc, k) return dc[k][2] ~= "" end,
      endswithcmd = function (dc, k)
          return dc[k][1]:reverse():match("^[A-Za-z]+\\")
        end,
      addspaceaftercmd = function (dc, k)
          dc[k][1] = dc[k][1].." "
        end,
      valid = function (dc, k) return 1 <= k and k <= #dc end,
      ltrim = function (dc, k)
          dc[k][1] = dc[k][1]:match("^[ \t]*(.*)")
        end,
      delcomment = function (dc, k)
          if dc:endswithcmd(k) then dc:addspaceaftercmd(k) end
          dc[k][2] = ""		-- delete the "%..."
          dc[k][3] = ""		-- delete the newline
          if dc:valid(k+1) then dc:ltrim(k+1) end
        end,
      delcomments = function (dc)
          for k=1,#dc do if dc:hascomment(k) then dc:delcomment(k) end end
	  return dc
        end,
      concat = function (dc)
          local bigstr = ""
          for k=1,#dc-1 do bigstr = bigstr..dc[k][1]..dc[k][2]..dc[k][3] end
          if #dc > 0 then bigstr = bigstr..dc[#dc][1]..dc[#dc][2] end
          return bigstr
        end,
  },
}

-- «DeleteComments-tests»  (to ".DeleteComments-tests")
-- (find-es "dednat" "deletecomments-2021")
--[==[
 (eepitch-lua51)
 (eepitch-kill)
 (eepitch-lua51)
dofile "output.lua"

bigstr = [[
foo%12
  bar\plic%34
  qoo%56
  blep
  bletch
  %
  woo
]]

dc = DeleteComments.split(bigstr)
= dc
= dc:delcomments()
= dc:concat()

= bigstr
= deletecomments_2019(bigstr)
= deletecomments_2021(bigstr)

--]==]

-- «deletecomments_2021»  (to ".deletecomments_2021")
deletecomments_2021 = function (bigstr)
    return DeleteComments.from(bigstr)
  end


-- «deletecomments» (to ".deletecomments")
-- The default is to use deletecomments_2021.
deletecomments = deletecomments_2021






-- See: (to "write_dnt_file")
dnt_log = ""




--              _               _   
--   ___  _   _| |_ _ __  _   _| |_ 
--  / _ \| | | | __| '_ \| | | | __|
-- | (_) | |_| | |_| |_) | |_| | |_ 
--  \___/ \__,_|\__| .__/ \__,_|\__|
--                 |_|              
--
-- «output»  (to ".output")
-- `output(str)' is the main way to send TeX code from dednat6 to TeX.
-- The TUGBoat article explains this briefly in sec.3.1. See:
--
--   https://tug.org/TUGboat/tb39-3/tb123ochs-dednat.pdf
--   http://angg.twu.net/dednat6/tugboat-rev2.pdf
--
-- The article says:
-- 
--   We saw in sections 1 and 2.2 that the "output" of
--   a %:-block is a series of `\defded's and the "output"
--   of a %D-block is a series of `\defdiags's. We can
--   generalize this. For example, the "output" of
-- 
--     %L output [[\def\Foo{FOO}]]
--     %L output [[\def\Bar{BAR}]]
-- 
--   is:
-- 
--     \def\Foo{FOO}
--     \def\Bar{BAR}
--
-- The default behavior of `output(str)' is `output_verbose(str)',
-- that:
--
--   1) runs tex.print(deletecomments(str)),
--   2) appends str (with comments!) to dnt_log,
--   3) prints the current value of tf.nline to stdout,
--   4) prints str (with comments!) to stdout.
--
-- I always check the output of running `lualatex foo.tex' to see if
-- there were any errors. If there weren't any errors, one of the last
-- lines of the output will be something like
--
--   Output written on foo.pdf (42 pages, 1234567 bytes).
--
-- Making `output(str)' print to stdout means that all TeX code that
-- dednat6 produces is shown in the output of `lualatex foo.tex'; I
-- find that this helps debugging.

-- «output_dnt»  (to ".output_dnt")
-- (find-es "dednat" "output_dnt")
output_dnt = function (str)
    dnt_log = dnt_log..str.."\n"
  end

output_quiet = function (str)
    tex.print(deletecomments(str))
    output_dnt(str)
  end
output_verbose = function (str)
    print("% Running the \\pu at line "..tf.nline)
    output_quiet(str)
    print(str)
  end
output  = output_verbose
quiet   = function () output = output_quiet   end
verbose = function () output = output_verbose end




--                _ _              _       _        __ _ _      
-- __      ___ __(_) |_ ___     __| |_ __ | |_     / _(_) | ___ 
-- \ \ /\ / / '__| | __/ _ \   / _` | '_ \| __|   | |_| | |/ _ \
--  \ V  V /| |  | | ||  __/  | (_| | | | | |_    |  _| | |  __/
--   \_/\_/ |_|  |_|\__\___|___\__,_|_| |_|\__|___|_| |_|_|\___|
--                        |_____|            |_____|            
--
-- «write_dnt_file» (to ".write_dnt_file")
-- Use this to _sort of_ emulate the behavior of dednat4.
-- See: http://angg.twu.net/dednat6.html#no-lua
--      (find-LATEX "dednat6load.lua")
--      (find-dn6 "options6.lua")
--      (find-dn6file "options6.lua" "dooptions_t =")
-- The name of the current .tex file is stored in texlines.name:
--   (find-dn6 "block.lua" "texfile0")
--   (find-dn6 "block.lua" "TexLines")
--   (find-dn6 "block.lua" "TexLines" "read =")
--
write_dnt_file  = function (fname)
    fname = fname or texlines.name:gsub("%.tex$", "")..".dnt"
    print("% Writing: "..fname)
    writefile(fname, dnt_log)
  end

--                _ _               _             _      
-- __      ___ __(_) |_ ___     ___(_)_ __   __ _| | ___ 
-- \ \ /\ / / '__| | __/ _ \   / __| | '_ \ / _` | |/ _ \
--  \ V  V /| |  | | ||  __/   \__ \ | | | | (_| | |  __/
--   \_/\_/ |_|  |_|\__\___|___|___/_|_| |_|\__, |_|\___|
--                        |_____|           |___/        
--
-- «write_single_tex_file»  (to ".write_single_tex_file")
-- Experimental, 2019aug16
write_single_tex_file__pat = "^(.-\n)(%s*)(\\input\\jobname.dnt[^\n]*\n)(.*)$"
write_single_tex_file = function (fname_out)
    local fname_in = status.filename
    local bigstr_in = ee_readfile(fname_in)
    local a,spaces,inputdnt,b = bigstr_in:match(write_single_tex_file__pat)
    local header = format("%% Generated from %s\n"..
            "%% using write_single_tex_file(\"%s\")\n%%\n",
            fname_in, fname_out)
    local bigstr_out = header..a..spaces.."% "..inputdnt..dnt_log.."\n"..b
    print("% Writing: "..fname_out)
    ee_writefile(fname_out, bigstr_out)
  end




-- I don't use the functions below this point much...
-- I only use them to generate code for pict2e.

-- «formatt» (to ".formatt")
-- (find-es "lua5" "formatt-and-printt")
formatt = function (...)
    local A = {...}
    for i=1,#A do if type(A[i]=="table") then A[i] = tostring(A[i]) end end
    return format(unpack(A))
  end
printt  = function (...) print(formatt(...)) end
outputt = function (...) output(formatt(...)) end

--[[
 (eepitch-lua51)
 (eepitch-kill)
 (eepitch-lua51)
dofile "output.lua"
dofile "picture.lua"
p, q = v(3,4), v(5,6)
= formatt("%s--%s", p, q)  --> (3,4)--(5,6)

--]]




-- «bprintt» (to ".bprintt")
-- Usage in the REPL:
--   bprint, out = makebprint("verbose")
--   bprint("%s--%s", v(2,3), v(4,5))
--   bprint("%s--%s", v(20,30), v(40,50))
--   = out()
-- Usage in a function:
--   local bprint, out = makebprint()
--   bprint("%s--%s", v(2,3), v(4,5))
--   bprint("%s--%s", v(20,30), v(40,50))
--   return out()
makebprint = function (verbose)
    local buffer = {}
    local bprint = function (...) table.insert(buffer, formatt(...)) end
    local out    = function () return table.concat(buffer, "\n") end
    if verbose then
      local bprint0 = bprint
      bprint = function (...) printt(...); bprint0(...) end
    end
    return bprint, out, buffer
  end





-- Local Variables:
-- coding: utf-8-unix
-- End: