% \iffalse meta-comment
%
%% File: l3luatex.dtx Copyright (C) 2010-2016 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the "l3kernel bundle" (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX3 Project.
%%
%% -----------------------------------------------------------------------
%
%<*driver>
\documentclass[full]{l3doc}
%</driver>
%<*driver|package&tex>
\GetIdInfo$Id: l3luatex.dtx 6679 2016-08-18 20:54:06Z bruno $
  {L3 Experimental LuaTeX-specific functions}
%</driver|package&tex>
%<*driver>
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3luatex} package\\LuaTeX-specific functions^^A
%   \thanks{This file describes v\ExplFileVersion,
%      last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
%
% \section{Breaking out to \Lua{}}
%
% The \LuaTeX{} engine provides access to the \Lua{} programming language,
% and with it access to the \enquote{internals} of \TeX{}. In order to use
% this within the framework provided here, a family of functions is
% available. When used with \pdfTeX{} or \XeTeX{} these will raise an
% error: use \cs{sys_if_engine_luatex:T} to avoid this. Details of coding
% the \LuaTeX{} engine are detailed in the \LuaTeX{} manual.
%
% \subsection{\TeX{} code interfaces}
%
% \begin{function}[EXP, added = 2015-06-29]{\lua_now_x:n, \lua_now:n}
%   \begin{syntax}
%     \cs{lua_now:n} \Arg{token list}
%   \end{syntax}
%   The \meta{token list} is first tokenized by \TeX{}, which will include
%   converting line ends to spaces in the usual \TeX{} manner and which
%   respects currently-applicable \TeX{} category codes. The resulting
%   \meta{\Lua{} input} is passed to the \Lua{} interpreter for processing.
%   Each \cs{lua_now:n} block is treated by \Lua{} as a separate chunk.
%   The \Lua{} interpreter will execute the \meta{\Lua{} input} immediately,
%   and in an expandable manner.
%
%   In the case of the \cs{lua_now_x:n} version the input is fully expanded
%   by \TeX{} in an \texttt{x}-type manner \emph{but} the function remains
%   fully expandable.
%   \begin{texnote}
%     \cs{lua_now_x:n} is a macro wrapper around \tn{directlua}: when
%     \LuaTeX{} is in use two expansions will be required to yield the
%     result of the \Lua{} code.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2015-06-30]{\lua_shipout_x:n, \lua_shipout:n}
%   \begin{syntax}
%     \cs{lua_shipout:n} \Arg{token list}
%   \end{syntax}
%   The \meta{token list} is first tokenized by \TeX{}, which will include
%   converting line ends to spaces in the usual \TeX{} manner and which
%   respects currently-applicable \TeX{} category codes.  The resulting
%   \meta{\Lua{} input} is passed to the \Lua{} interpreter when the
%   current page is finalised (\emph{i.e.}~at shipout).  Each
%   \cs{lua_shipout:n} block is treated by \Lua{} as a separate chunk.
%   The \Lua{} interpreter will execute the \meta{\Lua{} input} during the
%   page-building routine: no \TeX{} expansion of the \meta{\Lua{} input}
%   will occur at this stage.
%
%   In the case of the \cs{lua_shipout_x:n} version the input is fully
%   expanded by \TeX{} in an \texttt{x}-type manner during the shipout
%   operation.
%   \begin{texnote}
%     At a \TeX{} level, the \meta{\Lua{} input} is stored as a
%     \enquote{whatsit}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP, added = 2015-06-29]{\lua_escape_x:n, \lua_escape:n}
%   \begin{syntax}
%     \cs{lua_escape:n} \Arg{token list}
%   \end{syntax}
%   Converts the \meta{token list} such that it can safely be passed to
%   \Lua{}: embedded backslashes, double and single quotes, and newlines
%   and carriage returns are escaped. This is done by prepending an extra
%   token consisting of a backslash with category code~$12$, and for the line
%   endings, converting them to |\n| and |\r|, respectively.
%
%   In the case of the \cs{lua_escape_x:n} version the input is fully expanded
%   by \TeX{} in an \texttt{x}-type manner \emph{but} the function remains
%   fully expandable.
%   \begin{texnote}
%     \cs{lua_escape_x:n} is a macro wrapper around \tn{luaescapestring}:
%     when \LuaTeX{} is in use two expansions will be required to yield the
%     result of the \Lua{} code.
%   \end{texnote}
% \end{function}
%
% \subsection{Lua interfaces}
%
% As well as interfaces for \TeX{}, there are a small number of Lua functions
% provided here. Currently these are intended for internal use only.
%
% \begin{function}{l3kernel.strcmp}
%   \begin{syntax}
%     \cs{l3kernel.strcmp}|(|\meta{str one}, \meta{str two}|)|
%   \end{syntax}
%   Compares the two strings and returns |0| to \TeX{}
%   if the two are identical.
% \end{function}
%
% \begin{function}{l3kernel.charcat}
%   \begin{syntax}
%     \cs{l3kernel.charcat}|(|\meta{charcode}, \meta{catcode}|)|
%   \end{syntax}
%   Constructs a character of \meta{charcode} and \meta{catcode} and returns
%   the result to \TeX{}.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3luatex} implementation}
%
%    \begin{macrocode}
%<*initex|package>
%    \end{macrocode}
%
% \subsection{Breaking out to \Lua{}}
%
%    \begin{macrocode}
%<*tex>
%    \end{macrocode}
%
% \begin{macro}[EXP]{\lua_now_x:n, \lua_now:n}
% \begin{macro}{\lua_shipout_x:n, \lua_shipout:n}
% \begin{macro}[EXP]{\lua_escape_x:n, \lua_escape:n}
%   Wrappers around the primitives. As with engines other than \LuaTeX{}
%   these have to be macros, we give them the same status in all cases.
%   When \LuaTeX{} is not in use, simply give an error message/
%    \begin{macrocode}
\cs_new:Npn \lua_now_x:n #1 { \luatex_directlua:D {#1} }
\cs_new:Npn \lua_now:n #1   { \lua_now_x:n { \exp_not:n {#1} } }
\cs_new_protected:Npn \lua_shipout_x:n #1 { \luatex_latelua:D {#1} }
\cs_new_protected:Npn \lua_shipout:n #1
  { \lua_shipout_x:n { \exp_not:n {#1} } }
\cs_new:Npn \lua_escape_x:n #1 { \luatex_luaescapestring:D {#1} }
\cs_new:Npn \lua_escape:n #1 { \lua_escape_x:n { \exp_not:n {#1} } }
\sys_if_engine_luatex:F
  {
    \clist_map_inline:nn
      { \lua_now_x:n , \lua_now:n , \lua_escape_x:n , \lua_escape:n }
      {
        \cs_set:Npn #1 ##1
          {
            \__msg_kernel_expandable_error:nnn
              { kernel } { luatex-required } { #1 }
          }
      }
    \clist_map_inline:nn
      { \lua_shipout_x :n , \lua_shipout:n }
      {
        \cs_set_protected:Npn #1 ##1
          {
            \__msg_kernel_error:nnn
              { kernel } { luatex-required } { #1 }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Messages}
%
%    \begin{macrocode}
\__msg_kernel_new:nnnn { kernel } { luatex-required }
  { LuaTeX~engine~not~in~use!~Ignoring~#1. }
  {
    The~feature~you~are~using~is~only~available~
    with~the~LuaTeX~engine.~LaTeX3~ignored~'#1'.
  }
%    \end{macrocode}
%
%    \begin{macrocode}
%</tex>
%    \end{macrocode}
%
% \subsection{\Lua{} functions for internal use}
%
%    \begin{macrocode}
%<*lua>
%    \end{macrocode}
%
% \begin{macro}[int]{l3kernel}
%   Create a table for the kernel's own use.
%    \begin{macrocode}
l3kernel = l3kernel or { }
%    \end{macrocode}
% \end{macro}
%
%   Various local copies of standard functions: naming convention is to retain
%   the full text but replace all |.| by |_|. 
%    \begin{macrocode}
local tex_setcatcode    = tex.setcatcode
local tex_sprint        = tex.sprint
local tex_write         = tex.write
local unicode_utf8_char = unicode.utf8.char
%    \end{macrocode}
%
% \begin{macro}[int]{l3kernel.strcmp}
%   String comparison which gives the same results as \pdfTeX{}'s
%   \tn{pdfstrcmp}, although the ordering should likely not be relied upon!
%    \begin{macrocode}
local function strcmp (A, B)
  if A == B then
    tex_write("0")
  elseif A < B then
    tex_write("-1")
  else
    tex_write("1")
  end
end
l3kernel.strcmp = strcmp
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{l3kernel.charcat}
%   Creating arbitrary chars needs a category code table. As set up here,
%   one may have been assigned earlier (see \pkg{l3bootstrap}) or a hard-coded
%   one is used. The latter is intended for format mode and should be adjusted
%   to match an eventual allocator.
%    \begin{macrocode}
local charcat_table = l3kernel.charcat_table or 1
local function charcat (charcode, catcode)
  tex_setcatcode(charcat_table, charcode, catcode)
  tex_sprint(charcat_table, unicode_utf8_char(charcode))
end
l3kernel.charcat = charcat
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</lua>
%    \end{macrocode}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \subsection{Format mode code: font loader}
%
%    \begin{macrocode}
%<*fontloader>
%    \end{macrocode}
%
% In format mode, there needs to be a font loader available to let us
% use OpenType fonts. For testing, this is provided by
% \texttt{fontloader.lua} from the Speedata Publisher system
% (\url{https://github.com/speedata/publisher}). The code there is designed
% to be self-contained and has a certain number of build-in assumptions,
% so there is a small amount of compatibility required.
% 
% The code we load looks up \texttt{texmf} tree files using
% \texttt{kpse.filelist}, which isn't part of the standard \texttt{kpse}
% library. The interface is emulated using metatable.
%    \begin{macrocode}
kpse.filelist = setmetatable({}, {
  __index = function (t, key)
    return kpse.lookup(key)
  end
})
%    \end{macrocode}
% There is a built-in assumption in \texttt{fontloader.lua} that various
% environmental variables are set. We deal with that by intercepting the
% relevant names and returning something sane.
%    \begin{macrocode}
local os_getenv = os.getenv
function os.getenv (var)
  if var == "SP_FONT_PATH" then return "" end
  return os_getenv(var)
end
%    \end{macrocode}
% As detailed in
% \url{https://github.com/speedata/publisher/blob/develop/COPYING}, the current
% license for Speedata Publisher is \textsc{AGPLv3}. We therefore only
% load the file and use its public interfaces rather than copying/modifying
% the code itself. Note though that we do have permission to use
% \texttt{fontloader.lua} as a public domain work
% (\url{http://chat.stackexchange.com/transcript/message/27273687#27273687}):
% if we want to develop a richer loader we may want to take advantage of that
% (which also applies to the simple shaper in the related \texttt{fonts.lua}
% file).
%    \begin{macrocode}
local fontloader = require("fontloader.lua")
%    \end{macrocode}
% That done, register a callback which at present simply passes everything
% through. There's no attempt to pick up font settings (which presumably
% will be needed). Syntax is coerced to the same as for \XeTeX{}.
%    \begin{macrocode}
callback.register("define_font", 
  function (name, size, id)
    local opts, opttab, otfeatures = "", { }, { }
    if string.match(name, "^%[") then
      name, opts = string.match(name, "^%[([^%]]*)%][^:]*:?(.*)")
    end
    if opts ~= "" then
      for _,kv in ipairs(string.explode(opts,";")) do
        if string.match(kv, "=") then
          local k, v = string.match(kv, "([^=]*)=?(.*)")
          opttab[k] = v
        else
          if string.match(kv, "^+") then
            otfeatures[string.sub(kv,2,-1)] = "true"
          elseif string.match(kv, "^-") then
            otfeatures[string.sub(kv,2,-1)] = "false"
          else
            otfeatures[kv] = "true"
          end
        end
      end
    end
    if next(otfeatures) then
      opttab["otfeatures"] = otfeatures
    end
    return select(2, fontloader.define_font(name, size, opttab))
  end
)
%    \end{macrocode}
%
%    \begin{macrocode}
%</fontloader>
%    \end{macrocode}
%
%\end{implementation}
%
%\PrintIndex
