diff options
-rw-r--r-- | Master/texmf-dist/doc/latex/unravel/README | 34 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/unravel/README.md | 36 | ||||
-rw-r--r-- | Master/texmf-dist/doc/latex/unravel/unravel.pdf | bin | 674252 -> 692725 bytes | |||
-rw-r--r-- | Master/texmf-dist/source/latex/unravel/unravel.dtx | 1929 | ||||
-rw-r--r-- | Master/texmf-dist/tex/latex/unravel/unravel.sty | 1030 |
5 files changed, 1841 insertions, 1188 deletions
diff --git a/Master/texmf-dist/doc/latex/unravel/README b/Master/texmf-dist/doc/latex/unravel/README deleted file mode 100644 index b2dce6d2cc1..00000000000 --- a/Master/texmf-dist/doc/latex/unravel/README +++ /dev/null @@ -1,34 +0,0 @@ ----------------------------------------------------------------- -unravel --- Watching TeX digest tokens -E-mail: blflatex@gmail.com -Released under the LaTeX Project Public License v1.3c or later -See http://www.latex-project.org/lppl.txt ----------------------------------------------------------------- - -The unravel LaTeX package provides tools to explore TeX code, -performing expansion and assignments step by step. - -TeX is a strange beast. Its eyes read files, making characters -into tokens. Its mouth then chews tokens, expanding them if -possible, namely, expanding user-defined macros, or conditionals, -etc. When meeting a so called ``unexpandable'' token, TeX's -stomach comes into play, performing assignments, or moving boxes -around, eventually typesetting the result thanks to its great -line- and page-breaking algorithms. - -All of this is interleaved, and difficult to follow. Of course, -one can always use \tracingall, but the result is... messy. -This package is an attempt to replicate how TeX digests tokens, -and to make the process easier to follow. Namely, -\unravel{\some\tokens} will let you go through expansions and -assignments performed by TeX upon seeing of ``\some\tokens'', -step by step. - -Some parts of TeX are not covered. In particular, category codes -are fixed for the whole argument of \unravel when it is read. - -This package requires up-to-date versions of the l3kernel, -l3packages, and l3experimental bundles. - -The package is extracted by running "pdflatex unravel.ins". -For documentation, run "pdflatex unravel.dtx" twice.
\ No newline at end of file diff --git a/Master/texmf-dist/doc/latex/unravel/README.md b/Master/texmf-dist/doc/latex/unravel/README.md new file mode 100644 index 00000000000..bc25d285c38 --- /dev/null +++ b/Master/texmf-dist/doc/latex/unravel/README.md @@ -0,0 +1,36 @@ +unravel: Watching TeX digest tokens +==================================================== +* E-mail: blflatex@gmail.com +* Released under the LaTeX Project Public License v1.3c or later + See http://www.latex-project.org/lppl.txt + +The `unravel` LaTeX package provides tools to explore TeX code, +performing expansion and assignments step by step. + +TeX is a strange beast. Its eyes read files, making characters +into tokens. Its mouth then chews tokens, expanding them if +possible, namely, expanding user-defined macros, or conditionals, +etc. When meeting a so called 'unexpandable' token, TeX's +stomach comes into play, performing assignments, or moving boxes +around, eventually typesetting the result thanks to its great +line- and page-breaking algorithms. + +All of this is interleaved, and difficult to follow. Of course, +one can always use `\tracingall`, but the result is... messy. +This package is an attempt to replicate how TeX digests tokens, +and to make the process easier to follow. Namely, +`\unravel{\some\tokens}` will let you go through expansions and +assignments performed by TeX upon seeing of `\some\tokens`, +step by step. + +Some parts of TeX are not covered. In particular, category codes +are fixed for the whole argument of `\unravel` when it is read. + +This package requires up-to-date versions of the `l3kernel`, +`l3packages` and `l3experimental` bundles. + +The package is extracted by running `pdflatex unravel.ins`. +For the documentation, run `pdflatex unravel.dtx` twice. + +This is work in progress, all suggestions/comments/bug reports +are welcome! See https://github.com/blefloch/latex-unravel/ diff --git a/Master/texmf-dist/doc/latex/unravel/unravel.pdf b/Master/texmf-dist/doc/latex/unravel/unravel.pdf Binary files differindex 19a0e4fe3f1..a8af7eaff51 100644 --- a/Master/texmf-dist/doc/latex/unravel/unravel.pdf +++ b/Master/texmf-dist/doc/latex/unravel/unravel.pdf diff --git a/Master/texmf-dist/source/latex/unravel/unravel.dtx b/Master/texmf-dist/source/latex/unravel/unravel.dtx index 1cd40dc4382..87170f4286c 100644 --- a/Master/texmf-dist/source/latex/unravel/unravel.dtx +++ b/Master/texmf-dist/source/latex/unravel/unravel.dtx @@ -1,5 +1,5 @@ % \iffalse -%% File: unravel.dtx Copyright (C) 2013 Bruno Le Floch +%% File: unravel.dtx Copyright (C) 2013, 2015 Bruno Le Floch %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -23,9 +23,9 @@ % % \title{The \textsf{unravel} package: \\ % watching TeX digest tokens\thanks{This -% file has version number 0.0a, last revised 2013/07/28.}} +% file has version number 0.1, last revised 2015/09/22.}} % \author{Bruno Le Floch} -% \date{2013/07/28} +% \date{2015/09/22} % % \maketitle % \tableofcontents @@ -38,18 +38,53 @@ % This is done by letting the user step through the execution of some % \TeX{} code, going through the details of nested expansions, % performing assignments, as well as some simple typesetting commands. +% To use this package, one should normally run \TeX{} in a terminal. +% +% \begin{function}{\unravel} +% \begin{syntax} +% \cs{unravel} \oarg{key-value list} \marg{code} +% \end{syntax} +% This command shows in the terminal the steps performed by \TeX{} +% when running the \meta{code}. By default, it pauses to let the +% user read the description of every step: simply press |<return>| to +% proceed. Typing |s|\meta{integer} instead will go forward +% \meta{integer} steps somewhat silently. In the future it will be +% possible to use a negative \meta{integer} to go back a few steps. +% Typing |h| gives a list of various other possibilities. +% The available \meta{key-value} options are described in +% Section~\ref{sec:options}. +% \end{function} +% +% \begin{function}{\unravelsetup} +% \begin{syntax} +% \cs{unravelsetup} \marg{options} +% \end{syntax} +% Sets \meta{options} that apply to all subsequent \cs{unravel}. See +% options in Section~\ref{sec:options}. +% \end{function} +% +% \begin{function}{\unravel:nn} +% \begin{syntax} +% \cs{unravel:nn} \Arg{options} \Arg{code} +% \end{syntax} +% See \cs{unravel}. +% \end{function} +% +% \begin{function}{\unravel_setup:n} +% \begin{syntax} +% \cs{unravel_setup:n} \Arg{options} +% \end{syntax} +% See \cs{unravelsetup}. +% \end{function} +% % The \pkg{unravel} package is currently based on the behaviour of -% \pdfTeX{}, but it should work in the \XeTeX{} and \LuaTeX{} engines as -% long as none of the primitives specific to those engines is used. Any +% \pdfTeX{}, but it should work in all engines supported by \pkg{expl3} +% (\pdfTeX{}, \XeTeX{}, \LuaTeX{}, ep\TeX{}, eup\TeX{}) as long as none +% of the primitives specific to those engines is used. Any % difference between how \pkg{unravel} and (pdf)\TeX{} process a given % piece of code, unless described in the section~\ref{sec:differences}, -% should be reported to Bruno Le Floch \texttt{<blflatex@gmail.com>}. -% -% The only public command is \cs{unravel}, used as \cs{unravel} -% \Arg{some tokens}. It will show on the terminal the various steps -% that \TeX{} performs, waiting for input from the user at each step. -% As a result, \pkg{unravel} can only be used meaningfully when \TeX{} -% is run in a terminal. +% should be reported on the issue tracker +% (\url{https://github.com/blefloch/latex-unravel/issues}). % % As a simple example, one can run \LaTeX{} on the following file. % \begin{verbatim} @@ -120,34 +155,76 @@ % |\unravel{\lipsum[1-30]}|, which also takes $20000$ step, takes % $8$~minutes to complete. % +% \subsection{Options} +% \label{sec:options} +% +% \begin{function}{explicit-prompt} +% Boolean option (default \texttt{false}) determining whether to give +% an explicit prompt. If \texttt{true}, the text ``|Your input=|'' +% will appear at the beginning of lines where user input is expected. +% \end{function} +% +% \begin{function}{internal-debug} +% Boolean option (default \texttt{false}) used to debug \pkg{unravel} +% itself. +% \end{function} +% +% \begin{function}{machine} +% Option which takes no value and makes \pkg{unravel} produce an +% output that is somewhat more suitable for automatic processing. In +% particular, it sets |max-action|, |max-output|, |max-input| to very +% large values, and |number-steps| to \texttt{false}. +% \end{function} +% +% \begin{function}{max-action, max-output, max-input} +% Integer options (defaults $50$, $300$, $300$) determining the +% maximum number of characters displayed for the action, the output +% part, and the input part. +% \end{function} +% +% \begin{function}{number-steps} +% Boolean option (default \texttt{true}) determining whether to +% number steps. +% \end{function} +% +% \begin{function}{welcome-message} +% Boolean option (default \texttt{true}) determining whether to +% display the welcome message. +% \end{function} +% % \subsection{Differences between \pkg{unravel} and \TeX{}'s processing} % \label{sec:differences} % +% Bugs are listed at \url{https://github.com/blefloch/latex-unravel/issues}. +% +% Differences. % \begin{itemize} -% \item Alignments (\tn{halign}, \tn{valign}, \tn{noalign}, \tn{omit}, -% \tn{span}, \tn{cr}, \tn{crcr},~|&|) are not implemented. -% \item Math mode is not implemented, but might be. -% \item Some other primitives are not implemented (but they should claim -% so). -% \item For \pkg{unravel}, category codes are fixed when a file is read, +% \item Some primitives are not implemented yet: alignments +% (\tn{halign}, \tn{valign}, \tn{noalign}, \tn{omit}, \tn{span}, +% \tn{cr}, \tn{crcr},~|&|), many math mode primitives, and +% \cs{pdfprimitive}, \cs{aftergroup}, \cs{discretionary}, as well as +% all primitives specific to engines other than \pdfTeX{}. +% This list is sadly incomplete! +% \item For \pkg{unravel}, category codes are fixed when a file is read +% using \tn{input}, % while \TeX{} only fixes category codes when the corresponding % characters are converted to tokens. Similarly, the argument of % \tn{scantokens} is converted to the new category code r\'egime in % one go, and the result must be balanced. % \item Explicit begin-group and end-group characters other than the -% usual left and right braces will either make \pkg{unravel} choke or -% will be replaced by the usual left and right braces. -% \item \tn{endinput} is ignored, as it is not possible to implement it -% in a way similar to \TeX{}'s, and as it is most often used at the -% very end of files, in a redundant way. -% \item Negative signs and glue probably mix in wrong ways (this is a -% fixable bug, please tell me if it affects you). +% usual left and right braces may make \pkg{unravel} choke, or may be +% silently replaced by the usual left and right braces. +% \item \tn{endinput} is ignored with a warning, as it is very difficult +% to implement it in a way similar to \TeX{}'s, and as it is most +% often used at the very end of files, in a redundant way. +% \item \tn{outer} is not supported. % \end{itemize} % % \subsection{Future perhaps} % % \begin{itemize} -% \item Allow users to change some settings. +% \item Allow users to change some settings globally/for one |\unravel|. +% \item Allow to replay steps that have already been run. % \item Fix the display for \tn{if} and \tn{ifcat} (remove extraneous % \cs{exp_not:N}). % \end{itemize} @@ -166,26 +243,495 @@ % \end{macrocode} % % \begin{macrocode} -\RequirePackage{expl3}[2013/07/01] -\RequirePackage{l3str}[2013/04/24] -\RequirePackage{gtl}[2013/07/28] +\RequirePackage{expl3,xparse}[2015/09/11] +\RequirePackage{gtl}[2015/09/21] \ProvidesExplPackage - {unravel} {2013/07/28} {0.0a} {Watching TeX digest tokens} + {unravel} {2015/09/22} {0.1} {Watching TeX digest tokens} +% \end{macrocode} +% +% Load \pkg{l3str} if \pkg{expl3} is too old and does not define +% \cs{str_range:nnn}. Otherwise loading \pkg{l3str} would give +% an error. +% \begin{macrocode} +\cs_if_exist:NF \str_range:nnn { \RequirePackage{l3str} } % \end{macrocode} % % \begin{macrocode} %<@@=unravel> % \end{macrocode} % +% \subsection{Primitives, variants, and helpers} +% +% \subsubsection{Renamed primitives} +% +% \begin{macro} +% { +% \@@_currentgrouptype:, \@@_everyeof:w, \@@_everypar:w, +% \@@_set_escapechar:n, \@@_nullfont:, +% \@@_hbox:w, \@@_the:w, +% } +% Copy primitives which are used multiple times, to avoid littering +% the code with |:D| commands. Primitives are left as |:D| in the +% code when that is clearer (typically when testing the meaning of +% a token against that of a primitive). +% \begin{macrocode} +\cs_new_eq:NN \@@_currentgrouptype: \etex_currentgrouptype:D +\cs_new_protected_nopar:Npn \@@_set_escapechar:n + { \int_set:Nn \tex_escapechar:D } +\cs_new_eq:NN \@@_everyeof:w \etex_everyeof:D +\cs_new_eq:NN \@@_everypar:w \tex_everypar:D +\cs_new_eq:NN \@@_hbox:w \tex_hbox:D +\cs_new_eq:NN \@@_nullfont: \tex_nullfont:D +\cs_new_eq:NN \@@_the:w \tex_the:D +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\c_@@_prompt_ior, \c_@@_noprompt_ior} +% These are not quite primitives, but are very low-level +% |ior| streams to prompt the user explicitly or not. +% \begin{macrocode} +\cs_new_eq:NN \c_@@_prompt_ior \c_sixteen +\cs_new_eq:NN \c_@@_noprompt_ior \c_minus_one +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Variants} +% +% Variants that we need. +% \begin{macrocode} +\cs_if_exist:NF \exp_last_unbraced:NNn + { \cs_new_eq:NN \exp_last_unbraced:NNn \use:nnn } +\cs_generate_variant:Nn \exp_last_unbraced:NNn { NNv } +\cs_generate_variant:Nn \str_head:n { f } +\cs_generate_variant:Nn \tl_to_str:n { o } +\cs_generate_variant:Nn \tl_if_head_eq_meaning:nNT { V } +\cs_generate_variant:Nn \tl_if_head_is_space:nTF { o } +\cs_generate_variant:Nn \tl_if_head_is_space:nT { V } +\cs_generate_variant:Nn \tl_if_head_is_N_type:nTF { o } +\cs_generate_variant:Nn \tl_if_in:nnF { nV } +\cs_generate_variant:Nn \tl_if_in:nnTF { nV } +\cs_generate_variant:Nn \tl_if_eq:nnT { V } +\cs_generate_variant:Nn \tl_if_in:NnTF { No , NV } +\cs_generate_variant:Nn \tl_if_single_token:nT { V } +\cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nnx } +\cs_generate_variant:Nn \gtl_gput_left:Nn { Nx , NV , No } +\cs_generate_variant:Nn \gtl_gput_right:Nn { Nx , NV } +\cs_generate_variant:Nn \gtl_put_right:Nn { NV } +\cs_generate_variant:Nn \ior_get_str:NN { Nc } +\cs_generate_variant:Nn \gtl_if_empty:NTF { c } +\cs_generate_variant:Nn \gtl_to_str:N { c } +\cs_generate_variant:Nn \gtl_gpop_left:NN { c } +\cs_generate_variant:Nn \gtl_get_left:NN { c } +\cs_generate_variant:Nn \gtl_gset:Nn { c } +\cs_generate_variant:Nn \gtl_gconcat:NNN { ccc , cNc } +\cs_generate_variant:Nn \gtl_gclear:N { c } +\cs_generate_variant:Nn \gtl_gclear_new:N { c } +% \end{macrocode} +% +% \subsubsection{Miscellanous helpers} +% +% \begin{macro}[aux]{\@@_tmp:w} +% Temporary function used to define other functions. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_tmp:w { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_tl_gset_input:Nnn, \@@_tl_gset_input:Nno} +% \begin{macro}[aux]{\@@_tl_gset_input_aux:wN} +% \begin{macrocode} +\cs_new_protected:Npn \@@_tl_gset_input:Nnn #1#2#3 + { + \group_begin: + \@@_everyeof:w \exp_after:wN { \token_to_str:N @ @ #1 } + #2 + \tl_gclear:N #1 + \exp_after:wN \@@_tl_gset_input_aux:wN + \exp_after:wN \prg_do_nothing: + \tex_input:D \tl_to_str:n {#3} \scan_stop: + \group_end: + \tl_gput_right:NV #1 \@@_everyeof:w + } +\cs_generate_variant:Nn \@@_tl_gset_input:Nnn { Nno } +\use:x + { + \cs_new_protected:Npn \exp_not:N \@@_tl_gset_input_aux:wN + ##1 \token_to_str:N @ @ ##2 + } { \tl_gset:No #2 {#1} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{String helpers} +% +% \begin{macro}[int]{\@@_strip_escape:w} +% \begin{macro}[aux]{\@@_strip_escape_aux:N, \@@_strip_escape_aux:w} +% This is based on the 2013-07-19 (and earlier) version of +% \cs{cs_to_str:N}. There are three cases. If the escape character +% is printable, the charcode test is false, and +% \cs{@@_strip_escape_aux:N} removes one character. If the escape +% character is a space, the charcode test is true, and if there is no +% escape charcter, the test is unfinished after |\token_to_str:N \ |. +% In both of those cases, \cs{@@_strip_escape_aux:w} inserts +% |-\__int_value:w \fi: \c_zero|. If the escape character was a +% space, the test was true, and \cs{__int_value:w} converts +% \cs{c_zero} to~|0|, hence the leading roman numeral expansion +% removes a space from what follows (it is important that what follows +% cannot start with a digit). Otherwise, the test takes~|-| as its +% second operand, is false, and the roman numeral expansion only sees +% \cs{c_zero}, thus does not remove anything from what follows. +% \begin{macrocode} +\cs_new_nopar:Npn \@@_strip_escape:w + { + \tex_romannumeral:D + \if_charcode:w \token_to_str:N \ \@@_strip_escape_aux:w \fi: + \@@_strip_escape_aux:N + } +\cs_new:Npn \@@_strip_escape_aux:N #1 { \c_zero } +\cs_new:Npn \@@_strip_escape_aux:w #1#2 + { - \__int_value:w #1 \c_zero } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% ^^A todo: change approach: this abuses future l3obj. +% \begin{macro}[int,EXP]{\@@_to_str:n} +% \begin{macro}[aux,EXP] +% {\@@_to_str_auxi:w, \@@_to_str_auxii:w, \@@_gtl_to_str:n} +% Use the type-appropriate conversion to string. +% This unavoidably uses an internal function of \pkg{gtl}. +% \begin{macrocode} +\cs_new:Npn \@@_to_str:n #1 + { + \tl_if_head_eq_meaning:nNTF {#1} \scan_stop: + { \@@_to_str_auxi:w #1 ? \q_stop } + { \tl_to_str:n } + {#1} + } +\cs_set:Npn \@@_tmp:w #1 + { + \cs_new:Npn \@@_to_str_auxi:w ##1##2 \q_stop + { + \exp_after:wN \@@_to_str_auxii:w \token_to_str:N ##1 \q_mark + #1 tl \q_mark \q_stop + } + \cs_new:Npn \@@_to_str_auxii:w ##1 #1 ##2 \q_mark ##3 \q_stop + { \cs_if_exist_use:cF { @@_ ##2 _to_str:n } { \tl_to_str:n } } + } +\exp_args:No \@@_tmp:w { \tl_to_str:n { s__ } } +\cs_new:Npn \@@_gtl_to_str:n #1 { \__gtl_to_str:w #1 } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_str_truncate_left:nn} +% \begin{macro}[aux]{\@@_str_truncate_left_aux:nnn} +% Truncate the string |#1| to a maximum of |#2| characters. If it is +% longer, replace some characters on the left of the string by +% |(123~more~chars)~| with the appropriate number instead of~|123|. +% In any reasonable case, $25$ is big enough to fit this extra text. +% \begin{macrocode} +\cs_new:Npn \@@_str_truncate_left:nn #1#2 + { + \exp_args:Nf \@@_str_truncate_left_aux:nnn + { \str_count:n {#1} } {#1} {#2} + } +\cs_new:Npn \@@_str_truncate_left_aux:nnn #1#2#3 + { + \int_compare:nNnTF {#1} > {#3} + { + ( \int_eval:n { #1 - #3 + 25 } ~ more~chars ) ~ + \str_range:nnn {#2} { #1 - #3 + 26 } {#1} + } + { \tl_to_str:n {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_str_truncate_right:nn} +% \begin{macro}[aux]{\@@_str_truncate_right_aux:nnn} +% Truncate the string |#1| to a maximum of |#2| characters. If it is +% longer, replace some characters on the right of the string by +% |~(123~more~chars)| with the appropriate number instead of~|123|. +% In any reasonable case, $25$ is big enough to fit this extra text. +% \begin{macrocode} +\cs_new:Npn \@@_str_truncate_right:nn #1#2 + { + \exp_args:Nf \@@_str_truncate_right_aux:nnn + { \str_count:n {#1} } {#1} {#2} + } +\cs_new:Npn \@@_str_truncate_right_aux:nnn #1#2#3 + { + \int_compare:nNnTF {#1} > {#3} + { + \str_range:nnn {#2} { 1 } { #3 - 25 } ~ + ( \int_eval:n { #1 - #3 + 25 } ~ more~chars ) + } + { \tl_to_str:n {#2} } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Helpers for control flow} +% +% \begin{macro}[int,EXP]{\@@_exit:w, \@@_exit_point:} +% Jump to the very end of this instance of \cs{unravel}. +% \begin{macrocode} +\cs_new_eq:NN \@@_exit_point: \prg_do_nothing: +\cs_new:Npn \@@_exit:w #1 \@@_exit_point: { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int,EXP]{\@@_break:w, \@@_break_point:} +% Useful to jump out of complicated conditionals. +% \begin{macrocode} +\cs_new_eq:NN \@@_break_point: \prg_do_nothing: +\cs_new:Npn \@@_break:w #1 \@@_break_point: { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_cmd_if_internal:TF} +% Test whether the \cs{l_@@_head_cmd_int} denotes an ``internal'' +% command, between |min_internal| and |max_internal| (see +% Section~\ref{sec:numeric-codes}). +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_cmd_if_internal: { TF } + { + \int_compare:nNnTF + \l_@@_head_cmd_int < { \@@_tex_use:n { min_internal } } + { \prg_return_false: } + { + \int_compare:nNnTF + \l_@@_head_cmd_int + > { \@@_tex_use:n { max_internal } } + { \prg_return_false: } + { \prg_return_true: } + } + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Helpers concerning tokens} +% +% \begin{macro}[int]{\@@_token_to_char:N} +% \begin{macro}[int]{\@@_meaning_to_char:n, \@@_meaning_to_char:o} +% \begin{macro}[aux] +% {\@@_meaning_to_char_auxi:w, \@@_meaning_to_char_auxii:w} +% From the meaning of a character token (with arbitrary character +% code, except active), extract the character itself (with string +% category codes). This is somewhat robust against wrong input. +% \begin{macrocode} +\cs_new:Npn \@@_meaning_to_char:n #1 + { \@@_meaning_to_char_auxi:w #1 \q_mark ~ {} ~ \q_mark \q_stop } +\cs_new:Npn \@@_meaning_to_char_auxi:w #1 ~ #2 ~ #3 \q_mark #4 \q_stop + { \@@_meaning_to_char_auxii:w #3 ~ #3 ~ \q_stop } +\cs_new:Npn \@@_meaning_to_char_auxii:w #1 ~ #2 ~ #3 \q_stop + { \tl_if_empty:nTF {#2} { ~ } {#2} } +\cs_generate_variant:Nn \@@_meaning_to_char:n { o } +\cs_new:Npn \@@_token_to_char:N #1 + { \@@_meaning_to_char:o { \token_to_meaning:N #1 } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int,EXP,pTF]{\@@_token_if_expandable:N} +% We need to cook up our own version of \cs{token_if_expandable:NTF} +% because the \pkg{expl3} one does not think that |undefined| is +% expandable. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_token_if_expandable:N #1 + { p , T , F , TF } + { + \exp_after:wN \if_meaning:w \exp_not:N #1 #1 + \prg_return_false: + \else: + \prg_return_true: + \fi: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int,EXP,pTF]{\@@_token_if_protected:N} +% Returns \texttt{true} if the token is either not expandable or is a +% protected macro. +% \begin{macrocode} +\prg_new_conditional:Npnn \@@_token_if_protected:N #1 + { p , T , F , TF } + { + \@@_token_if_expandable:NTF #1 + { + \token_if_protected_macro:NTF #1 + { \prg_return_true: } + { + \token_if_protected_long_macro:NTF #1 + { \prg_return_true: } + { \prg_return_false: } + } + } + { \prg_return_true: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int,TF]{\@@_token_if_definable:N} +% Within a group, set the escape character to a non-space value +% (backslash). Convert the token to a string with +% \cs{token_to_str:N}. The result is multiple characters if the +% token is a control sequence, and a single character otherwise (even +% for explicit catcode~$6$ character tokens which would be doubled if +% we used \cs{tl_to_str:n} instead of \cs{token_to_str:N}). Thus +% \cs{str_tail:n} gives a non-empty result exactly for control +% sequences. Those are definable (technically, not always: +% |\expandafter\font\csname\endcsname=cmr10| +% |\expandafter\def\the\csname\endcsname{}|). For characters, there +% remains to determine if |#1| is an active character. One option +% would be to build the active character with that character code and +% compare them using a delimited-argument test, but that needlessly +% pollutes the hash table in \XeTeX{} (and \LuaTeX{}?) if the +% character was in fact not active. Instead, use the \tn{lowercase} +% primitive to convert the character to a fixed character code~|Z|. +% Compare with an active~|Z|. In all cases, remember to end the +% group. +% \begin{macrocode} +\group_begin: + \char_set_catcode_active:n { `Z } + \prg_new_protected_conditional:Npnn \@@_token_if_definable:N #1 + { TF } + { + \group_begin: + \@@_set_escapechar:n { 92 } + \tl_set:Nx \l_@@_tmpa_tl + { \exp_args:No \str_tail:n { \token_to_str:N #1 } } + \tl_if_empty:NTF \l_@@_tmpa_tl + { + \exp_args:Nx \char_set_lccode:nn + { ` \str_head:n {#1} } { `Z } + \tex_lowercase:D { \tl_if_eq:nnTF {#1} } { Z } + { \group_end: \prg_return_true: } + { \group_end: \prg_return_false: } + } + { \group_end: \prg_return_true: } + } +\group_end: +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int,TF]{\@@_gtl_if_head_is_definable:N} +% Tests if a generalized token list is a single control sequence or a +% single active character. First test that it is single, then filter +% out the case of (explicit) begin-group, end-group, and blank space +% characters: those are neither control sequences nor active. Then +% feed the single normal token to a first auxiliary. +% \begin{macrocode} +\prg_new_protected_conditional:Npnn \@@_gtl_if_head_is_definable:N #1 + { TF , F } + { + \gtl_if_single_token:NTF #1 + { + \gtl_if_head_is_N_type:NTF #1 + { + \exp_last_unbraced:Nx \@@_token_if_definable:NTF + { \gtl_head:N #1 } + { \prg_return_true: } + { \prg_return_false: } + } + { \prg_return_false: } + } + { \prg_return_false: } + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Helpers for previous input} +% +% \begin{macro}[int] +% { +% \@@_prev_input_silent:n, +% \@@_prev_input_silent:V, +% \@@_prev_input_silent:x +% } +% \begin{macro}[int] +% { +% \@@_prev_input:n, +% \@@_prev_input:V, +% \@@_prev_input:x +% } +% \begin{macrocode} +\cs_new_protected:Npn \@@_prev_input_silent:n #1 + { + \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_prev_input_tl + \tl_put_right:Nn \l_@@_prev_input_tl {#1} + \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_prev_input_tl + } +\cs_generate_variant:Nn \@@_prev_input_silent:n { V , x } +\cs_new_protected:Npn \@@_prev_input:n #1 + { + \@@_prev_input_silent:n {#1} + \@@_print_action:x { \tl_to_str:n {#1} } + } +\cs_generate_variant:Nn \@@_prev_input:n { V , x } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_prev_input_gtl:N} +% \begin{macrocode} +\cs_new_protected:Npn \@@_prev_input_gtl:N #1 + { + \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_prev_input_gtl + \gtl_concat:NNN \l_@@_prev_input_gtl \l_@@_prev_input_gtl #1 + \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_prev_input_gtl + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_prev_input_join_get:nN} +% \begin{macro}[aux]{\@@_join_get_aux:NNN} +% Pops \cs{g_@@_prev_input_seq} twice to get some value in +% \cs{l_@@_head_tl} and some sign or decimal number in +% \cs{l_@@_tmpa_tl}. Combines them into a value, using +% the appropriate evaluation function, determined based +% on~|#1|. +% \begin{macrocode} +\cs_new_protected:Npn \@@_prev_input_join_get:nN #1 + { + \int_case:nnF {#1} + { + { 2 } { \@@_join_get_aux:NNN \skip_eval:n \etex_glueexpr:D } + { 3 } { \@@_join_get_aux:NNN \muskip_eval:n \etex_muexpr:D } + } + { + \msg_error:nnn { unravel } { internal } { join-factor } + \@@_join_get_aux:NNN \use:n \prg_do_nothing: + } + } +\cs_new_protected:Npn \@@_join_get_aux:NNN #1#2#3 + { + \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl + \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_tmpa_tl + \tl_set:Nx #3 { #1 { \l_@@_tmpa_tl #2 \l_@@_head_tl } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% % \subsection{Variables} % % \subsubsection{User interaction} % -% \begin{variable} -% {\g_@@_prompt_ior, \g_@@_prompt_before_tl, \l_@@_prompt_tmpa_int} +% \begin{variable}{\g_@@_before_print_state_tl, \g_@@_before_prompt_tl} +% Code to run before printing the state or before the prompt. +% \begin{macrocode} +\tl_new:N \g_@@_before_print_state_tl +\tl_new:N \g_@@_before_prompt_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_prompt_tmpa_int} % \begin{macrocode} -\ior_new:N \g_@@_prompt_ior -\tl_new:N \g_@@_prompt_before_tl \int_new:N \l_@@_prompt_tmpa_int % \end{macrocode} % \end{variable} @@ -199,10 +745,29 @@ % \end{macrocode} % \end{variable} % -% \begin{variable}{\l_@@_debug_bool} -% If true, debug-mode. Activated by \cs{UnravelDebug} -% \begin{macrocode} -\bool_new:N \l_@@_debug_bool +% \begin{variable} +% { +% \g_@@_default_explicit_prompt_bool , \g_@@_explicit_prompt_bool , +% \g_@@_default_internal_debug_bool , \g_@@_internal_debug_bool , +% \g_@@_default_number_steps_bool , \g_@@_number_steps_bool , +% \g_@@_default_welcome_message_bool , \g_@@_welcome_message_bool , +% } +% Variables for the options |explicit-prompt|, +% |internal-debug|, |number-steps|. The +% \texttt{default_} booleans store the default value of these +% options, and are affected by \cs{unravelsetup} or +% \cs{unravel_setup:n}. +% \begin{macrocode} +\bool_new:N \g_@@_default_explicit_prompt_bool +\bool_new:N \g_@@_default_internal_debug_bool +\bool_new:N \g_@@_default_number_steps_bool +\bool_gset_true:N \g_@@_default_number_steps_bool +\bool_new:N \g_@@_default_welcome_message_bool +\bool_gset_true:N \g_@@_default_welcome_message_bool +\bool_new:N \g_@@_explicit_prompt_bool +\bool_new:N \g_@@_internal_debug_bool +\bool_new:N \g_@@_number_steps_bool +\bool_new:N \g_@@_welcome_message_bool % \end{macrocode} % \end{variable} % @@ -223,28 +788,29 @@ % \end{macrocode} % \end{variable} % -% ^^A todo: let the user fix those numbers. % \begin{variable} % { +% \g_@@_default_max_action_int, +% \g_@@_default_max_output_int, +% \g_@@_default_max_input_int, % \g_@@_max_action_int, % \g_@@_max_output_int, -% \g_@@_max_prev_int, % \g_@@_max_input_int % } % Maximum length of various pieces of what is shown on the terminal. % \begin{macrocode} +\int_new:N \g_@@_default_max_action_int +\int_new:N \g_@@_default_max_output_int +\int_new:N \g_@@_default_max_input_int +\int_gset:Nn \g_@@_default_max_action_int { 50 } +\int_gset:Nn \g_@@_default_max_output_int { 300 } +\int_gset:Nn \g_@@_default_max_input_int { 300 } \int_new:N \g_@@_max_action_int \int_new:N \g_@@_max_output_int -\int_new:N \g_@@_max_prev_int \int_new:N \g_@@_max_input_int -\int_gset:Nn \g_@@_max_action_int { 50 } -\int_gset:Nn \g_@@_max_output_int { 300 } -\int_gset:Nn \g_@@_max_prev_int { 300 } -\int_gset:Nn \g_@@_max_input_int { 300 } % \end{macrocode} % \end{variable} % -% ^^A todo: doc, and let user decide % \begin{variable}{\g_@@_speedup_macros_bool} % If this boolean is true, speed up macros which have a simple % parameter text. This may not be safe if very weird macros appear. @@ -287,7 +853,12 @@ % % \begin{variable} % {\g_@@_prev_input_seq, \l_@@_prev_input_tl, \l_@@_prev_input_gtl} -% ^^A todo: comment +% The different levels of expansion are stored in +% \cs{g_@@_prev_input_seq}, with the innermost at the end of the +% sequence (otherwise the sequence would have to be reversed for +% display). When adding material to the last level of expansion, +% \cs{l_@@_prev_input_tl} or \cs{l_@@_prev_input_gtl} are used to +% temporarily store the last level of expansion. % \begin{macrocode} \seq_new:N \g_@@_prev_input_seq \tl_new:N \l_@@_prev_input_tl @@ -331,10 +902,12 @@ % \end{variable} % % \begin{variable} -% {\l_@@_tmpa_tl, \l_@@_tmpb_gtl, \g_@@_tmpc_tl, \l_@@_tmpa_seq} -% Temporary storage. +% {\l_@@_tmpa_tl, \l_@@_tmpb_gtl, \g_@@_tmpc_tl, \l_@@_tmpa_seq, \l_@@_unused_gtl} +% Temporary storage. The \cs{l_@@_unused_gtl} is only used once, +% to ignore some unwanted tokens. % \begin{macrocode} \tl_new:N \l_@@_tmpa_tl +\gtl_new:N \l_@@_unused_gtl \gtl_new:N \l_@@_tmpb_gtl \tl_new:N \g_@@_tmpc_tl \seq_new:N \l_@@_tmpa_seq @@ -382,9 +955,9 @@ % Used to determine if a macro has simple parameters or not. % \begin{macrocode} \group_begin: - \char_set_lccode:nn { `* } { `# } - \tex_lowercase:D - { \tl_const:Nn \c_@@_parameters_tl { ^*1*2*3*4*5*6*7*8*9 } } + \cs_set:Npx \@@_tmp:w #1 { \c_hash_str #1 } + \tl_const:Nx \c_@@_parameters_tl + { ^ \tl_map_function:nN { 123456789 } \@@_tmp:w } \group_end: % \end{macrocode} % \end{variable} @@ -407,28 +980,6 @@ % \end{macrocode} % \end{variable} % -% \begin{variable} -% { -% \c_@@_plus_tl, \c_@@_minus_tl, \c_@@_times_tl, \c_@@_over_tl, -% \c_@@_lq_tl, \c_@@_rq_tl, \c_@@_dq_tl, \c_@@_lp_tl, \c_@@_rp_tl, -% \c_@@_eq_tl, \c_@@_comma_tl, \c_@@_point_tl, -% } -% \begin{macrocode} -\tl_const:Nn \c_@@_plus_tl { + } -\tl_const:Nn \c_@@_minus_tl { - } -\tl_const:Nn \c_@@_times_tl { * } -\tl_const:Nn \c_@@_over_tl { / } -\tl_const:Nn \c_@@_lq_tl { ` } -\tl_const:Nn \c_@@_rq_tl { ' } -\tl_const:Nn \c_@@_dq_tl { " } -\tl_const:Nn \c_@@_lp_tl { ( } -\tl_const:Nn \c_@@_rp_tl { ) } -\tl_const:Nn \c_@@_eq_tl { = } -\tl_const:Nn \c_@@_comma_tl { , } -\tl_const:Nn \c_@@_point_tl { . } -% \end{macrocode} -% \end{variable} -% % \begin{variable}{\g_@@_if_limit_tl} % \begin{variable}{\g_@@_if_limit_int} % \begin{variable}{\g_@@_if_depth_int} @@ -472,317 +1023,37 @@ % % \subsubsection{Constants} % -% \begin{variable}{\c_@@_frozen_relax_gtl} -% \TeX{}'s |frozen_relax|, inserted by \cs{@@_insert_relax:}. -% \begin{macrocode} -\gtl_const:Nx \c_@@_frozen_relax_gtl { \if_int_compare:w 0 = 0 \fi: } -% \end{macrocode} -% \end{variable} -% -% \subsection{Variants and helper functions} -% -% Variants that we need. -% \begin{macrocode} -\cs_if_exist:NF \exp_last_unbraced:NNn - { \cs_new_eq:NN \exp_last_unbraced:NNn \use:nnn } -\cs_generate_variant:Nn \exp_last_unbraced:NNn { NNv } -\cs_generate_variant:Nn \str_head:n { f } -\cs_generate_variant:Nn \tl_to_str:n { o } -\cs_generate_variant:Nn \tl_if_head_eq_meaning:nNT { V } -\cs_generate_variant:Nn \tl_if_head_is_space:nTF { o } -\cs_generate_variant:Nn \tl_if_head_is_space:nT { V } -\cs_generate_variant:Nn \tl_if_head_is_N_type:nTF { o } -\cs_generate_variant:Nn \tl_if_in:nnF { nV } -\cs_generate_variant:Nn \tl_if_in:nnTF { nV } -\cs_generate_variant:Nn \tl_if_eq:nnT { V } -\cs_generate_variant:Nn \tl_if_in:NnTF { No , NV } -\cs_generate_variant:Nn \tl_if_single_token:nT { V } -\cs_generate_variant:Nn \tl_gset_rescan:Nnn { Nnx } -\cs_generate_variant:Nn \gtl_gput_left:Nn { Nx , NV , No } -\cs_generate_variant:Nn \gtl_gput_right:Nn { Nx , NV } -\cs_generate_variant:Nn \gtl_put_right:Nn { NV } -\cs_generate_variant:Nn \ior_get_str:NN { Nc } -\cs_generate_variant:Nn \gtl_if_empty:NTF { c } -\cs_generate_variant:Nn \gtl_to_str:N { c } -\cs_generate_variant:Nn \gtl_gpop_left:NN { c } -\cs_generate_variant:Nn \gtl_get_left:NN { c } -\cs_generate_variant:Nn \gtl_gset:Nn { c } -\cs_generate_variant:Nn \gtl_gconcat:NNN { ccc , cNc } -\cs_generate_variant:Nn \gtl_gclear:N { c } -% \end{macrocode} -% -% \begin{macro}[aux]{\@@_tl_gset_input:Nnn, \@@_tl_gset_input:Nno} -% \begin{macro}[aux]{\@@_tl_gset_input_aux:wN} -% \begin{macrocode} -\cs_new_protected:Npn \@@_tl_gset_input:Nnn #1#2#3 - { - \group_begin: - \etex_everyeof:D \exp_after:wN { \token_to_str:N @ @ #1 } - #2 - \tl_gclear:N #1 - \str_if_eq_x:nnF - { \token_to_meaning:N \tex_input:D } - { \token_to_str:N \input } - { \msg_unravel:nnx { unravel } { internal } { input-prim } } - \exp_after:wN \@@_tl_gset_input_aux:wN - \exp_after:wN \prg_do_nothing: - \tex_input:D \tl_to_str:n {#3} \scan_stop: - \group_end: - \tl_gput_right:NV #1 \etex_everyeof:D - } -\cs_generate_variant:Nn \@@_tl_gset_input:Nnn { Nno } -\use:x - { - \cs_new_protected:Npn \exp_not:N \@@_tl_gset_input_aux:wN - ##1 \token_to_str:N @ @ ##2 - } { \tl_gset:No #2 {#1} } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[EXP]{\@@_cs_case:NnF} -% Currently, \texttt{expl3} does not provide a case statement for the -% meaning of control sequences. However, \cs{tl_case:NnF} in fact -% does precisely this. -% \begin{macrocode} -\cs_new_eq:NN \@@_cs_case:NnF \tl_case:NnF -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[int]{\@@_strip_escape:w} -% \begin{macro}[aux]{\@@_strip_escape_aux:N, \@@_strip_escape_aux:w} -% This is based on the 2013-07-19 (and earlier) version of -% \cs{cs_to_str:N}. There are three cases. If the escape character -% is printable, the charcode test is false, and -% \cs{@@_strip_escape_aux:N} removes one character. If the escape -% character is a space, the charcode test is true, and if there is no -% escape charcter, the test is unfinished after |\token_to_str:N \ |. -% In both of those cases, \cs{@@_strip_escape_aux:w} inserts -% |-\__int_value:w \fi: \c_zero|. If the escape character was a -% space, the test was true, and \cs{__int_value:w} converts -% \cs{c_zero} to~|0|, hence the leading roman numeral expansion -% removes a space from what follows (it is important that what follows -% cannot start with a digit). Otherwise, the test takes~|-| as its -% second operand, is false, and the roman numeral expansion only sees -% \cs{c_zero}, thus does not remove anything from what follows. -% \begin{macrocode} -\cs_new_nopar:Npn \@@_strip_escape:w - { - \tex_romannumeral:D - \if_charcode:w \token_to_str:N \ \@@_strip_escape_aux:w \fi: - \@@_strip_escape_aux:N - } -\cs_new:Npn \@@_strip_escape_aux:N #1 { \c_zero } -\cs_new:Npn \@@_strip_escape_aux:w #1#2 - { - \__int_value:w #1 \c_zero } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[int]{\@@_token_to_char:N} -% \begin{macro}[int]{\@@_meaning_to_char:n, \@@_meaning_to_char:o} -% \begin{macro}[aux] -% {\@@_meaning_to_char_auxi:w, \@@_meaning_to_char_auxii:w} -% From the meaning of a character token (with arbitrary character -% code, except active), extract the character itself (with string -% category codes). This is somewhat robust against wrong input. -% \begin{macrocode} -\cs_new:Npn \@@_meaning_to_char:n #1 - { \@@_meaning_to_char_auxi:w #1 \q_mark ~ {} ~ \q_mark \q_stop } -\cs_new:Npn \@@_meaning_to_char_auxi:w #1 ~ #2 ~ #3 \q_mark #4 \q_stop - { \@@_meaning_to_char_auxii:w #3 ~ #3 ~ \q_stop } -\cs_new:Npn \@@_meaning_to_char_auxii:w #1 ~ #2 ~ #3 \q_stop - { \tl_if_empty:nTF {#2} { ~ } {#2} } -\cs_generate_variant:Nn \@@_meaning_to_char:n { o } -\cs_new:Npn \@@_token_to_char:N #1 - { \@@_meaning_to_char:o { \token_to_meaning:N #1 } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% \end{macro} -% -% ^^A this abuses future l3obj. -% \begin{macro}[int,EXP]{\@@_to_str:n} -% \begin{macro}[aux,EXP]{\@@_to_str_auxi:w, \@@_to_str_auxii:w} -% Use the type-appropriate conversion to string. -% \begin{macrocode} -\cs_new:Npn \@@_to_str:n #1 - { - \tl_if_head_eq_meaning:nNTF {#1} \scan_stop: - { \@@_to_str_auxi:w #1 ? \q_stop } - { \tl_to_str:n } - {#1} - } -\cs_set:Npn \@@_tmp:w #1 - { - \cs_new:Npn \@@_to_str_auxi:w ##1##2 \q_stop - { - \exp_after:wN \@@_to_str_auxii:w \token_to_str:N ##1 \q_mark - #1 tl \q_mark \q_stop - } - \cs_new:Npn \@@_to_str_auxii:w ##1 #1 ##2 \q_mark ##3 \q_stop - { \cs_if_exist_use:cF { ##2 _to_str:n } { \tl_to_str:n } } - } -\exp_args:No \@@_tmp:w { \tl_to_str:n { s__ } } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[int] -% { -% \@@_prev_input_silent:n, -% \@@_prev_input_silent:V, -% \@@_prev_input_silent:x -% } -% \begin{macro}[int] +% \begin{variable} % { -% \@@_prev_input:n, -% \@@_prev_input:V, -% \@@_prev_input:x +% \c_@@_plus_tl, \c_@@_minus_tl, \c_@@_times_tl, \c_@@_over_tl, +% \c_@@_lq_tl, \c_@@_rq_tl, \c_@@_dq_tl, \c_@@_lp_tl, \c_@@_rp_tl, +% \c_@@_eq_tl, \c_@@_comma_tl, \c_@@_point_tl, % } % \begin{macrocode} -\cs_new_protected:Npn \@@_prev_input_silent:n #1 - { - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_prev_input_tl - \tl_put_right:Nn \l_@@_prev_input_tl {#1} - \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_prev_input_tl - } -\cs_generate_variant:Nn \@@_prev_input_silent:n { V , x } -\cs_new_protected:Npn \@@_prev_input:n #1 - { - \@@_prev_input_silent:n {#1} - \@@_print_action:x { \tl_to_str:n {#1} } - } -\cs_generate_variant:Nn \@@_prev_input:n { V , x } -% \end{macrocode} -% \end{macro} -% \end{macro} -% -% \begin{macro}[int]{\@@_prev_input_gtl:N} -% \begin{macrocode} -\cs_new_protected:Npn \@@_prev_input_gtl:N #1 - { - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_prev_input_gtl - \gtl_concat:NNN \l_@@_prev_input_gtl \l_@@_prev_input_gtl #1 - \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_prev_input_gtl - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[int,EXP,pTF]{\@@_token_if_expandable:N} -% We need to cook up our own version of \cs{token_if_expandable:NTF} -% because the \texttt{expl3} one does not think that |undefined| is -% expandable. -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_token_if_expandable:N #1 - { p , T , F , TF } - { - \exp_after:wN \if_meaning:w \exp_not:N #1 #1 - \prg_return_false: - \else: - \prg_return_true: - \fi: - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[int,EXP,pTF]{\@@_token_if_protected:N} -% Returns \texttt{true} if the token is either not expandable or is a -% protected macro. -% \begin{macrocode} -\prg_new_conditional:Npnn \@@_token_if_protected:N #1 - { p , T , F , TF } - { - \@@_token_if_expandable:NTF #1 - { - \token_if_protected_macro:NTF #1 - { \prg_return_true: } - { - \token_if_protected_long_macro:NTF #1 - { \prg_return_true: } - { \prg_return_false: } - } - } - { \prg_return_true: } - } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[int,EXP]{\@@_exit:w, \@@_exit_point:} -% Jump to the very end of this instance of \cs{unravel}. -% \begin{macrocode} -\cs_new_eq:NN \@@_exit_point: \prg_do_nothing: -\cs_new:Npn \@@_exit:w #1 \@@_exit_point: { } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[int,EXP]{\@@_break:w, \@@_break_point:} -% Useful to jump out of complicated conditionals. -% \begin{macrocode} -\cs_new_eq:NN \@@_break_point: \prg_do_nothing: -\cs_new:Npn \@@_break:w #1 \@@_break_point: { } -% \end{macrocode} -% \end{macro} -% -% \begin{macro}[int,TF]{\@@_token_if_definable:N} -% Within a group, set the escape character to a non-zero non-space -% value (backslash): if the result of converting the token to a string -% is longer than a single token (false branch), the token was a -% control sequence and the test is \texttt{true} (note that we did not -% use \cs{tl_to_str:n}, as this would fail on explicit macro parameter -% characters). Otherwise, the token was an explicit character, active -% or not. Use \tn{lowercase} to convert the character to a fixed -% character code~|Z|. Compare with an active~|Z|. In all three -% outcomes, remember to end the group. -% \begin{macrocode} -\group_begin: - \char_set_catcode_active:n { `Z } - \prg_new_protected_conditional:Npnn \@@_token_if_definable:N #1 - { TF } - { - \group_begin: - \int_set:Nn \tex_escapechar:D { 92 } - \exp_args:No \tl_if_single:nTF { \token_to_str:N #1 } - { - \exp_args:Nx \char_set_lccode:nn - { ` \str_head:n {#1} } { `Z } - \tex_lowercase:D { \tl_if_eq:nnTF {#1} } { Z } - { \group_end: \prg_return_true: } - { \group_end: \prg_return_false: } - } - { \group_end: \prg_return_true: } - } -\group_end: +\tl_const:Nn \c_@@_plus_tl { + } +\tl_const:Nn \c_@@_minus_tl { - } +\tl_const:Nn \c_@@_times_tl { * } +\tl_const:Nn \c_@@_over_tl { / } +\tl_const:Nn \c_@@_lq_tl { ` } +\tl_const:Nn \c_@@_rq_tl { ' } +\tl_const:Nn \c_@@_dq_tl { " } +\tl_const:Nn \c_@@_lp_tl { ( } +\tl_const:Nn \c_@@_rp_tl { ) } +\tl_const:Nn \c_@@_eq_tl { = } +\tl_const:Nn \c_@@_comma_tl { , } +\tl_const:Nn \c_@@_point_tl { . } % \end{macrocode} -% \end{macro} +% \end{variable} % -% \begin{macro}[int,TF]{\@@_gtl_if_head_is_definable:N} -% Tests if a generalized token list is a single control sequence or a -% single active character. First test that it is single, then filter -% out the case of (explicit) begin-group, end-group, and blank space -% characters: those are neither control sequences nor active. Then -% feed the single normal token to a first auxiliary. +% \begin{variable}{\c_@@_frozen_relax_gtl} +% \TeX{}'s |frozen_relax|, inserted by \cs{@@_insert_relax:}. % \begin{macrocode} -\prg_new_protected_conditional:Npnn \@@_gtl_if_head_is_definable:N #1 - { TF , F } - { - \gtl_if_single_token:NTF #1 - { - \gtl_if_head_is_N_type:NTF #1 - { - \exp_last_unbraced:Nx \@@_token_if_definable:NTF - { \gtl_head:N #1 } - { \prg_return_true: } - { \prg_return_false: } - } - { \prg_return_false: } - } - { \prg_return_false: } - } +\gtl_const:Nx \c_@@_frozen_relax_gtl { \if_int_compare:w 0 = 0 \fi: } % \end{macrocode} -% \end{macro} +% \end{variable} % % \subsection{Numeric codes} +% \label{sec:numeric-codes} % % First we define some numeric codes, following Section~15 of the \TeX{} % web code, then we associate a command code to each \TeX{} primitive, @@ -1253,7 +1524,7 @@ \@@_tex_primitive:nnn { lefthyphenmin } { assign_int } { 51 } \@@_tex_primitive:nnn { righthyphenmin } { assign_int } { 52 } \@@_tex_primitive:nnn { holdinginserts } { assign_int } { 53 } -\@@_tex_primitive:nnn { errorcontegtlines } { assign_int } { 54 } +\@@_tex_primitive:nnn { errorcontextlines } { assign_int } { 54 } \@@_tex_primitive:nnn { pdfoutput } { assign_int } { 55 } \@@_tex_primitive:nnn { pdfcompresslevel } { assign_int } { 56 } \@@_tex_primitive:nnn { pdfdecimaldigits } { assign_int } { 57 } @@ -1662,10 +1933,9 @@ % \end{macro} % \end{macro} % -% ^^A todo: should we worry about call vs long_call etc.? % \begin{macro}[aux]{\@@_set_cmd_aux_macro:} -% The token is a macro. For now we do not test if the macro is -% long/outer. +% The token is a macro. There is no need to determine whether the +% macro is long/outer. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_set_cmd_aux_macro: { @@ -1847,7 +2117,7 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: "timeit" to know if \@@_input_split: is beneficial. +% ^^A todo: profiling to know if \@@_input_split: is beneficial. % % \begin{macro}[int]{\@@_input_split:} % If the input is completely flat, and is a token list starting with @@ -1894,6 +2164,8 @@ \cs_new_protected:Npn \@@_input_split_auxiii:w #1 \@@_input_split_end: { + \gtl_gclear_new:c + { g_@@_input_ \int_use:N \g_@@_input_tmpa_int _gtl } \gtl_gset:cn { g_@@_input_ \int_use:N \g_@@_input_tmpa_int _gtl } {#1} \int_gdecr:N \g_@@_input_tmpa_int @@ -1906,8 +2178,8 @@ % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_input_gset:n { - \int_gset_eq:NN \g_@@_input_int \c_one - \gtl_gset:cn { g_@@_input_1_gtl } + \int_gzero:N \g_@@_input_int + \@@_back_input:n } % \end{macrocode} % \end{macro} @@ -2043,11 +2315,14 @@ % \end{macro} % % \begin{macro}[int]{\@@_back_input:n, \@@_back_input:x} -% Insert a token list back into the input. +% Insert a token list back into the input. Use \cs{gtl_gclear_new:c} +% to define the gtl variable if necessary: this happens whenever a +% new largest value of \cs{g_@@_input_int} is reached. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_back_input:n { \int_gincr:N \g_@@_input_int + \gtl_gclear_new:c { g_@@_input_ \int_use:N \g_@@_input_int _gtl } \gtl_gset:cn { g_@@_input_ \int_use:N \g_@@_input_int _gtl } } \cs_generate_variant:Nn \@@_back_input:n { x , V , o } @@ -2147,21 +2422,20 @@ % \@@_macro_replacement:N % } % \begin{macrocode} -\group_begin: - \char_set_lccode:nn { `. } { `: } - \tex_lowercase:D - { - \cs_new:Npn \@@_macro_split_do:NN #1 - { - \exp_after:wN \@@_macro_split_do:wN - \token_to_meaning:N #1 \q_mark { } . -> \q_mark \use_none:nnnn - \q_stop - } - \cs_new:Npn \@@_macro_split_do:wN - #1 . #2 -> #3 \q_mark #4 #5 \q_stop #6 - { #4 #6 {#1} {#2} {#3} } - } -\group_end: +\use:x + { + \exp_not:n { \cs_new:Npn \@@_macro_split_do:NN #1 } + { + \exp_not:n { \exp_after:wN \@@_macro_split_do:wN } + \exp_not:n { \token_to_meaning:N #1 \q_mark { } } + \tl_to_str:n { : } \exp_not:n { -> \q_mark \use_none:nnnn } + \exp_not:N \q_stop + } + \exp_not:n { \cs_new:Npn \@@_macro_split_do:wN } + \exp_not:n {#1} \tl_to_str:n { : } \exp_not:n { #2 -> } + \exp_not:n { #3 \q_mark #4 #5 \q_stop #6 } + { \exp_not:n { #4 #6 {#1} {#2} {#3} } } + } \cs_new:Npn \@@_macro_prefix:N #1 { \@@_macro_split_do:NN #1 \use_i:nnn } \cs_new:Npn \@@_macro_parameter:N #1 @@ -2172,13 +2446,13 @@ % \end{macro} % % ^^A todo: redoc -% ^^A todo: estimate how far the macro has touched the input. % \begin{macro}[int]{\@@_macro_call:} % \begin{macro}[aux] % { % \@@_macro_call_safe:, % \@@_macro_call_quick:, -% \@@_macro_call_quick_loop:NN +% \@@_macro_call_quick_loop:NNN, +% \@@_macro_call_quick_runaway:Nw, % } % Macros are simply expanded once. We cannot determine precisely % which tokens a macro will need for its parameters, but we know that @@ -2206,17 +2480,23 @@ } \cs_new_protected_nopar:Npn \@@_macro_call_quick: { - \exp_after:wN \@@_macro_call_quick_loop:NN \l_@@_tmpa_tl + \exp_after:wN \@@_macro_call_quick_loop:NNN \l_@@_tmpa_tl { ? \use_none_delimit_by_q_stop:w } \q_stop } -\cs_new_protected_nopar:Npn \@@_macro_call_quick_loop:NN #1#2 +\cs_new_protected:Npn \@@_macro_call_quick_loop:NNN #1#2#3 { \use_none:n #2 \@@_input_gpop_item:NF \l_@@_tmpa_tl - { \msg_error:nn { unravel } { runaway-macro-parameter } } + { \@@_macro_call_quick_runaway:Nw #3 } \tl_put_right:Nx \l_@@_head_tl { { \exp_not:V \l_@@_tmpa_tl } } - \@@_macro_call_quick_loop:NN + \@@_macro_call_quick_loop:NNN + #3 + } +\cs_new_protected:Npn \@@_macro_call_quick_runaway:Nw #1#2 \q_stop + { + \msg_error:nnxx { unravel } { runaway-macro-parameter } + { \tl_to_str:N \l_@@_head_tl } { \tl_to_str:n {#1} } } % \end{macrocode} % \end{macro} @@ -2233,7 +2513,7 @@ \cs_new_protected_nopar:Npn \@@_expand: { \@@_set_action_text: - \bool_if:NT \l_@@_debug_bool + \bool_if:NT \g_@@_internal_debug_bool { \@@_set_cmd: \iow_term:x { Exp:~\int_use:N \l_@@_head_cmd_int } @@ -2250,7 +2530,8 @@ % and call the function implementing that expansion. If we do not % recognize the meaning then it is probably an unknown primitive. If % we recognize the meaning but there is no corresponding function, -% then we probably have not implemented it yet. +% then we probably have not implemented it yet, so dump it in the +% output as is. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_expand_nonmacro: { @@ -2513,7 +2794,7 @@ } { \msg_error:nn { unravel } { missing-font-id } - \@@_prev_input:n { \tex_nullfont:D } + \@@_prev_input:n { \@@_nullfont: } \@@_back_error: } } @@ -2549,7 +2830,7 @@ % \end{macro} % % ^^A todo: redoc -% ^^A todo: rename: all other scan functions do get_x_next themselves. +% ^^A todo: rename this function because all other scan functions do get_x_next themselves. % \begin{macro}[aux]{\@@_scan_something_internal:n} % \begin{macro}[aux]{\@@_scan_something_aux:nwn} % Receives an (explicit) \enquote{level} argument: @@ -2582,7 +2863,10 @@ % may complain about a missing number or incompatible glue units), and % place the result in |prev_input|. Finally, tell the user the tokens % that have been found and their value (and, if there was a single -% token, its meaning). +% token, its meaning). Use |=>| rather than |=| because the value +% displayed is the value used, not the actual value (this matters in +% constructions such as |\parindent=\parskip| where a skip or a dimen +% is downgraded to a dimen or an int). % \begin{macrocode} \cs_new_protected:Npn \@@_scan_something_internal:n #1 { @@ -2611,7 +2895,7 @@ \@@_prev_input_silent:V \l_@@_tmpa_tl \@@_set_action_text: \@@_set_action_text:x - { \g_@@_action_text_str = ~ \tl_to_str:N \l_@@_tmpa_tl } + { \g_@@_action_text_str \use:n { ~ => ~ } \tl_to_str:N \l_@@_tmpa_tl } \int_compare:nNnF {#3} > { 3 } { \@@_print_action: } \int_gset:Nn \g_@@_val_level_int {#1} } @@ -2624,7 +2908,7 @@ % This expands to a digit (the level generated by whatever token is % the current |head|), followed by some code to fetch necessary % operands. In most cases, this can be done by simply looking at the -% |cmd| integer, but for |last_item| and |register|, the level of the +% |cmd| integer, but for |last_item|, |set_aux| and |register|, the level of the % token depends on the |char| integer. When the token is not allowed % after \tn{the} (or at any other position where % \cs{@@_scan_something_internal:n} is called), the resulting level @@ -2646,7 +2930,7 @@ { 76 } { 3 } % assign_mu_glue { 77 } { 1 \@@_scan_font_dimen: } % assign_font_dimen { 78 } { 0 \@@_scan_font_int: } % assign_font_int - { 79 } { 0 } % set_aux + { 79 } { \@@_thing_set_aux: } % set_aux { 80 } { 0 } % set_prev_graf { 81 } { 1 } % set_page_dimen { 82 } { 0 } % set_page_int @@ -2660,6 +2944,8 @@ } { 8 } } +\cs_new_nopar:Npn \@@_thing_set_aux: + { \int_compare:nNnTF \l_@@_head_char_int = { 1 } { 1 } { 0 } } \cs_new_nopar:Npn \@@_thing_last_item: { \int_compare:nNnTF \l_@@_head_char_int < { 26 } @@ -2737,7 +3023,7 @@ { 2 } \skip_eval:n { 3 } \muskip_eval:n } - { \tex_the:D } + { \@@_the:w } } % \end{macrocode} % \end{macro} @@ -2842,7 +3128,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: |\let\a b \ifnum`\a=`b wrong!\fi| % \begin{macro}[aux]{\@@_scan_int:} % \begin{macro}[aux] % {\@@_scan_int_char:, \@@_scan_int_lq:, \@@_scan_int_explicit:n} @@ -2851,16 +3136,9 @@ { \@@_scan_signs: \@@_set_cmd: - \int_compare:nNnTF - \l_@@_head_cmd_int < { \@@_tex_use:n { min_internal } } + \@@_cmd_if_internal:TF + { \@@_scan_something_internal:n { 0 } } { \@@_scan_int_char: } - { - \int_compare:nNnTF - \l_@@_head_cmd_int - > { \@@_tex_use:n { max_internal } } - { \@@_scan_int_char: } - { \@@_scan_something_internal:n { 0 } } - } } \cs_new_protected_nopar:Npn \@@_scan_int_char: { @@ -2922,61 +3200,56 @@ % \begin{macro}[int]{\@@_scan_normal_dimen:} % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_scan_normal_dimen: - { \@@_scan_dimen:NN \c_false_bool \c_false_bool } + { \@@_scan_dimen:nN { 2 } \c_false_bool } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\@@_scan_dimen:NN} -% Quoth |tex.web|. ``\emph{|mu| is |true| if the finite units must be -% `mu', while |mu| is |false| if `mu' units are disallowed; |inf| is -% |true| if the infinite units `fil', `fill', `filll' are -% permitted.}'' The function here has the same first two parameters -% as \TeX{}'s |scan_dimen|, but omits the third, as the shortcut is -% provided as a separate function, \cs{@@_scan_dimen_unit:NN}. +% \begin{macro}[int]{\@@_scan_dimen:nN} +% The first argument is $2$ if the unit may not be |mu| and $3$ if +% the unit must be |mu| (or |fil|). The second argument is +% \cs{c_true_bool} if |fil|, |fill|, |filll| are permitted, and is +% otherwise |false|. These arguments are similar to those of +% \TeX{}'s own |scan_dimen| procedure, in which |mu| is |bool(#1=3)| +% and |inf| is |#2|. The third argument of this procedure is omitted +% here, as the corresponding shortcut is provided as a separate +% function, \cs{@@_scan_dimen_unit:nN}. % \begin{macrocode} -\cs_new_protected:Npn \@@_scan_dimen:NN #1#2 +\cs_new_protected:Npn \@@_scan_dimen:nN #1#2 { \@@_scan_signs: \seq_gput_right:Nn \g_@@_prev_input_seq { } \@@_set_cmd: - \int_compare:nNnTF - \l_@@_head_cmd_int < { \@@_tex_use:n { min_internal } } - { \@@_scan_dimen_char:NN #1#2 } + \@@_cmd_if_internal:TF { - \int_compare:nNnTF - \l_@@_head_cmd_int - > { \@@_tex_use:n { max_internal } } - { \@@_scan_dimen_char:NN #1#2 } + \int_compare:nNnTF {#1} = { 3 } { - \bool_if:NTF #1 + \@@_scan_something_internal:n { 3 } + \int_case:nnF \g_@@_val_level_int { - \@@_scan_something_internal:n { 3 } - \int_case:nnF \g_@@_val_level_int - { - { 0 } { \@@_scan_dim_unit:NN #1 #2 } - { 3 } { } - } - { - \msg_error:nn { unravel } { incompatible-units } - % ^^A todo: error recovery - } + { 0 } { \@@_scan_dim_unit:nN {#1} #2 } + { 3 } { } } { - \@@_scan_something_internal:n { 2 } - \int_case:nnF \g_@@_val_level_int - { - { 0 } { \@@_scan_dim_unit:NN #1#2 } - { 3 } % ^^A todo: error recovery - { \msg_error:nn { unravel } { incompatible-units } } - } - { } + \msg_error:nn { unravel } { incompatible-units } + % ^^A todo: error recovery + } + } + { + \@@_scan_something_internal:n { 1 } + \int_case:nnF \g_@@_val_level_int + { + { 0 } { \@@_scan_dim_unit:nN {#1} #2 } + { 3 } % ^^A todo: error recovery + { \msg_error:nn { unravel } { incompatible-units } } } + { } } } + { \@@_scan_dimen_char:nN {#1} #2 } \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl \@@_prev_input_silent:V \l_@@_head_tl } -\cs_new_protected:Npn \@@_scan_dimen_char:NN #1#2 +\cs_new_protected:Npn \@@_scan_dimen_char:nN #1#2 { \tl_if_eq:NNT \l_@@_head_tl \c_@@_comma_tl { \tl_set_eq:NN \l_@@_head_tl \c_@@_point_tl } @@ -3004,9 +3277,9 @@ \@@_scan_int: } } - \@@_scan_dim_unit:NN #1#2 + \@@_scan_dim_unit:nN {#1} #2 } -\cs_new_protected:Npn \@@_scan_dim_unit:NN #1#2 +\cs_new_protected:Npn \@@_scan_dim_unit:nN #1#2 { \bool_if:NT #2 { @@ -3018,35 +3291,16 @@ } \@@_get_x_non_blank: \@@_set_cmd: - \int_compare:nNnTF - \l_@@_head_cmd_int < { \@@_tex_use:n { min_internal } } - { \@@_back_input: } + \@@_cmd_if_internal:TF { - \int_compare:nNnTF - \l_@@_head_cmd_int - > { \@@_tex_use:n { max_internal } } - { \@@_back_input: } - { - \seq_gput_right:Nn \g_@@_prev_input_seq { } - \bool_if:NTF #1 - { \@@_scan_something_internal:n { 3 } } - { \@@_scan_something_internal:n { 2 } } - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_tmpa_tl - \tl_set:Nx \l_@@_tmpa_tl - { - \bool_if:NTF #1 \muskip_eval:n \skip_eval:n - { - \l_@@_tmpa_tl - \bool_if:NTF #1 \etex_muexpr:D \etex_glueexpr:D - \l_@@_head_tl - } - } - \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_tmpa_tl - \@@_break:w - } + \seq_gput_right:Nn \g_@@_prev_input_seq { } + \@@_scan_something_internal:n {#1} + \@@_prev_input_join_get:nN {#1} \l_@@_tmpa_tl + \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_tmpa_tl + \@@_break:w } - \bool_if:NT #1 + { \@@_back_input: } + \int_compare:nNnT {#1} = { 3 } { \@@_scan_keyword:nT { mM uU } { \@@_break:w } \msg_error:nn { unravel } { missing-mudim } @@ -3099,52 +3353,38 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: this is wrong for signs. % \begin{macro}[int]{\@@_scan_glue:n} % \begin{macrocode} \cs_new_protected:Npn \@@_scan_glue:n #1 { - \int_compare:nNnTF {#1} = { 2 } - { \@@_scan_glue_aux:nN {#1} \c_false_bool } - { \@@_scan_glue_aux:nN {#1} \c_true_bool } - } -\cs_new_protected:Npn \@@_scan_glue_aux:nN #1#2 - { + \seq_gput_right:Nn \g_@@_prev_input_seq { } \@@_scan_signs: \seq_gput_right:Nn \g_@@_prev_input_seq { } \@@_set_cmd: - \int_compare:nNnTF - \l_@@_head_cmd_int < { \@@_tex_use:n { min_internal } } - { \@@_back_input: \@@_scan_dimen:NN #2 \c_false_bool } + \@@_cmd_if_internal:TF { - \int_compare:nNnTF - \l_@@_head_cmd_int - > { \@@_tex_use:n { max_internal } } + \@@_scan_something_internal:n {#1} + \int_case:nnF \g_@@_val_level_int { - \@@_back_input: - \@@_scan_dimen:NN #2 \c_false_bool + { 0 } { \@@_scan_dimen:nN {#1} \c_false_bool } + {#1} { \@@_break:w } } { - \@@_scan_something_internal:n {#1} - \int_case:nnF \g_@@_val_level_int - { - { 0 } { \@@_scan_dimen:NN #2 \c_false_bool } - { 1 } { \bool_if:NT #2 { \msg_error: } } % ^^A todo: ?? - } - { - \int_compare:nNnF \g_@@_val_level_int = {#1} - { \msg_error:nn { unravel } { incompatible-units } } - \@@_break:w - } + \int_compare:nNnF { \g_@@_val_level_int + #1 } = 3 + { \msg_error:nn { unravel } { incompatible-units } } } } + { \@@_back_input: \@@_scan_dimen:nN {#1} \c_false_bool } + \@@_prev_input_join_get:nN {#1} \l_@@_tmpa_tl + \seq_gput_right:Nn \g_@@_prev_input_seq { } + \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_tmpa_tl \@@_scan_keyword:nT { pP lL uU sS } - { \@@_scan_dimen:NN #2 \c_true_bool } + { \@@_scan_dimen:nN {#1} \c_true_bool } \@@_scan_keyword:nT { mM iI nN uU sS } - { \@@_scan_dimen:NN #2 \c_true_bool } + { \@@_scan_dimen:nN {#1} \c_true_bool } \@@_break_point: - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl - \@@_prev_input_silent:V \l_@@_head_tl + \@@_prev_input_join_get:nN {#1} \l_@@_tmpa_tl + \@@_prev_input_silent:V \l_@@_tmpa_tl } % \end{macrocode} % \end{macro} @@ -3379,7 +3619,7 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: catch runaway expand/get_x_next. +% ^^A todo: catch runaway expand/get_x_next. (get_next too, probably) % % \begin{macro}[aux]{\@@_scan_alt_rule:} % \begin{macrocode} @@ -3452,11 +3692,12 @@ { \bool_if:NTF #1 { - \@@_cs_case:NnF \l_@@_head_token + \int_case:nnTF \l_@@_head_cmd_int { - \tex_hrule:D { \@@_do_leaders_rule: } - \tex_vrule:D { \@@_do_leaders_rule: } + { \@@_tex_use:n { hrule } } { } + { \@@_tex_use:n { vrule } } { } } + { \@@_do_leaders_rule: } { \@@_do_box_error: } } { \@@_do_box_error: } @@ -3576,7 +3817,7 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_do_box_explicit:N #1 { - \token_if_eq_meaning:NNTF \l_@@_head_token \tex_hbox:D + \token_if_eq_meaning:NNTF \l_@@_head_token \@@_hbox:w { \@@_box_hook:N \tex_everyhbox:D } { \@@_box_hook:N \tex_everyvbox:D } % ^^A todo: TeX calls |normal_paragraph| here. @@ -3617,7 +3858,7 @@ \@@_print_action: \@@_back_input:o {##1} \@@_set_action_text:x - { \token_to_meaning:N #1 \tl_to_str:o {##1} } + { \token_to_meaning:N #1 = \tl_to_str:o {##1} } \tl_if_empty:oF {##1} { \@@_print_action: } } } @@ -3662,26 +3903,18 @@ % % \begin{macro}[aux]{\@@_char:n, \@@_char:V, \@@_char:x} % \begin{macrocode} -\group_begin: - \char_set_catcode_other:n { 0 } - \cs_new_protected:Npn \@@_char:n #1 - { - \tex_char:D #1 \scan_stop: - \@@_charcode_if_safe:nTF {#1} - { - \group_begin: - \char_set_lccode:nn { 0 } {#1} - \tex_lowercase:D - { \group_end: \tl_set:Nn \l_@@_tmpa_tl { ^^@ } } - } - { - \tl_set:Nx \l_@@_tmpa_tl - { \exp_not:N \char \int_eval:n {#1} ~ } - } - \gtl_gput_right:NV \g_@@_output_gtl \l_@@_tmpa_tl - \@@_print_action:x { \tl_to_str:N \l_@@_tmpa_tl } - } -\group_end: +\cs_new_protected:Npn \@@_char:n #1 + { + \tex_char:D #1 \scan_stop: + \@@_charcode_if_safe:nTF {#1} + { \tl_set:Nx \l_@@_tmpa_tl { \char_generate:nn {#1} { 12 } } } + { + \tl_set:Nx \l_@@_tmpa_tl + { \exp_not:N \char \int_eval:n {#1} ~ } + } + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_tmpa_tl + \@@_print_action:x { \tl_to_str:N \l_@@_tmpa_tl } + } \cs_generate_variant:Nn \@@_char:n { V , x } % \end{macrocode} % \end{macro} @@ -3689,21 +3922,16 @@ % \begin{macro}[aux] % {\@@_char_in_mmode:n, \@@_char_in_mmode:V, \@@_char_in_mmode:x} % \begin{macrocode} -\group_begin: - \char_set_catcode_other:n { 0 } - \cs_new_protected:Npn \@@_char_in_mmode:n #1 - { - \int_compare:nNnTF { \tex_mathcode:D #1 } = { "8000 } - { % math active - \group_begin: - \char_set_lccode:nn { 0 } { \l_@@_tmpa_tl } - \tex_lowercase:D - { \group_end: \gtl_set:Nn \l_@@_head_gtl { ^^@ } } - \@@_back_input: - } - { \@@_char:n {#1} } - } -\group_end: +\cs_new_protected:Npn \@@_char_in_mmode:n #1 + { + \int_compare:nNnTF { \tex_mathcode:D #1 } = { "8000 } + { % math active + \gtl_set:Nx \l_@@_head_gtl + { \char_generate:nn {#1} { 12 } } + \@@_back_input: + } + { \@@_char:n {#1} } + } \cs_generate_variant:Nn \@@_char_in_mmode:n { V , x } % \end{macrocode} % \end{macro} @@ -3731,10 +3959,10 @@ % \begin{macrocode} \cs_new_protected:Npn \@@_new_graf:N #1 { - \tl_set:NV \l_@@_tmpa_tl \tex_everypar:D - \tex_everypar:D { } + \tl_set:NV \l_@@_tmpa_tl \@@_everypar:w + \@@_everypar:w { } \bool_if:NTF #1 { \tex_indent:D } { \tex_noindent:D } - \exp_args:NV \tex_everypar:D \l_@@_tmpa_tl + \exp_args:NV \@@_everypar:w \l_@@_tmpa_tl \@@_back_input:V \l_@@_tmpa_tl \@@_print_action:x { @@ -3778,7 +4006,6 @@ % ^^A todo: implement \@@_end_align_group: % ^^A todo: implement \@@_end_no_align_group: (start = \@@_end_graf:) % ^^A todo: implement \@@_end_output_group: -% ^^A todo: implement \@@_end_math_group: % ^^A todo: implement \@@_end_disc_group: % ^^A todo: implement \@@_end_math_choice_group: % @@ -3788,7 +4015,7 @@ % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_handle_left_brace: { - \int_case:nnF \etex_currentgrouptype:D + \int_case:nnF \@@_currentgrouptype: { { 1 } { \@@_end_simple_group: } % simple { 2 } { \@@_end_box_group: } % hbox @@ -3798,7 +4025,7 @@ { 6 } { \@@_end_align_group: } % align { 7 } { \@@_end_no_align_group: } % no_align { 8 } { \@@_end_output_group: } % output - { 9 } { \@@_end_math_group: } % math + { 9 } { \@@_end_simple_group: } % math { 10 } { \@@_end_disc_group: } % disc { 11 } { \@@_end_graf: \@@_end_simple_group: } % insert { 12 } { \@@_end_graf: \@@_end_simple_group: } % vcenter @@ -3860,14 +4087,14 @@ % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_off_save: { - \int_compare:nNnTF \etex_currentgrouptype:D = { 0 } + \int_compare:nNnTF \@@_currentgrouptype: = { 0 } { % bottom-level \msg_error:nnx { unravel } { extra-close } { \token_to_meaning:N \l_@@_head_token } } { \@@_back_input: - \int_case:nnF \etex_currentgrouptype:D + \int_case:nnF \@@_currentgrouptype: { { 14 } % semi_simple_group { \gtl_set:Nn \l_@@_head_gtl { \group_end: } } @@ -3887,9 +4114,6 @@ % % \subsection{Modes} % ^^A todo: implement \aftergroup and things happening at end-group -% ^^A todo: implement \@@_after_math: -% ^^A todo: implement \@@_goto_inner_math: -% ^^A todo: implement \@@_goto_display_math: % ^^A todo: implement \@@_scan_math: % % \begin{macro}[int] @@ -3937,6 +4161,56 @@ % \end{macrocode} % \end{macro} % +% ^^A todo: should push_math be provided? +% \begin{macro}[aux]{\@@_goto_inner_math:} +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_goto_inner_math: + { + \@@_box_hook:N \tex_everymath:D + $ % $ + \@@_box_hook_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_goto_display_math:} +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_goto_display_math: + { + \@@_box_hook:N \tex_everydisplay:D + $ $ + \@@_box_hook_end: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_after_math:} +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_after_math: + { + \mode_if_inner:TF + { + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl + $ % $ + } + { + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl + \@@_get_x_next: + \token_if_eq_catcode:NNF + \l_@@_head_token \c_math_toggle_token + { + \@@_back_input: + \tl_set:Nn \l_@@_head_tl { $ } % $ + \msg_error:nn { unravel } { missing-dollar } + } + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl + $ $ + } + \@@_print_action: + } +% \end{macrocode} +% \end{macro} +% % \subsection{One step} % % \begin{macro}[int]{\@@_do_step:} @@ -3946,7 +4220,7 @@ \cs_new_protected_nopar:Npn \@@_do_step: { \@@_set_action_text: - \bool_if:NT \l_@@_debug_bool + \bool_if:NT \g_@@_internal_debug_bool { \iow_term:x { Cmd:~\int_use:N \l_@@_head_cmd_int } } \cs_if_exist_use:cF { @@_cmd_ \int_use:N \l_@@_head_cmd_int : } @@ -3968,7 +4242,7 @@ % \item |relax=0| for \tn{relax}. % \item |begin-group_char=1| for begin-group characters (catcode~$1$). % \item |end-group_char=2| for end-group characters (catcode~$2$). -% \item |math_char=3| for math shift (math toggle in \texttt{expl3}) +% \item |math_char=3| for math shift (math toggle in \pkg{expl3}) % characters (catcode~$3$). % \item |tab_mark=4| for \tn{span} % \item |alignment_char=4| for alignment tab characters (catcode~$4$). @@ -4019,18 +4293,23 @@ \mode_if_math:TF { \int_compare:nNnTF - \etex_currentgrouplevel:D = { 15 } % math_shift_group + \@@_currentgrouptype: = { 15 } % math_shift_group { \@@_after_math: } { \@@_off_save: } } { + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl \@@_get_next: \token_if_eq_catcode:NNTF \l_@@_head_token \c_math_toggle_token { \mode_if_inner:TF { \@@_back_input: \@@_goto_inner_math: } - { \@@_goto_display_math: } + { + \gtl_gput_right:NV + \g_@@_output_gtl \l_@@_head_tl + \@@_goto_display_math: + } } { \@@_back_input: \@@_goto_inner_math: } } @@ -4050,6 +4329,8 @@ { \l_@@_head_token \@@_print_action: } % \end{macrocode} % +% ^^A todo: wrong: needs to collect subsup before output (otherwise b{}^2{}_3) +% ^^A todo: wrong: mathcode "8000 is not recognized. % \begin{macrocode} \@@_new_tex_cmd:nn { superscript_char } % 7 { \@@_mode_math:n { \@@_sub_sup: } } @@ -4059,10 +4340,45 @@ { \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_head_tl \@@_print_action: - \@@_scan_math: - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl - \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl - \tl_use:N \l_@@_head_tl \scan_stop: + \@@_get_x_non_relax: + \@@_set_cmd: + \int_case:nnTF \l_@@_head_cmd_int + { + { \@@_tex_use:n { the_char } } + { \@@_prev_input:V \l_@@_head_tl } + { \@@_tex_use:n { other_char } } + { \@@_prev_input:V \l_@@_head_tl } + { \@@_tex_use:n { char_given } } + { \@@_prev_input:V \l_@@_head_tl } + { \@@_tex_use:n { char_num } } + { + \@@_prev_input:V \l_@@_head_tl + \@@_scan_int: + } + { \@@_tex_use:n { math_char_num } } + { + \@@_prev_input:V \l_@@_head_tl + \@@_scan_int: + } + { \@@_tex_use:n { math_given } } + { \@@_prev_input:V \l_@@_head_tl } + { \@@_tex_use:n { delim_num } } + { \@@_prev_input:V \l_@@_head_tl \@@_scan_int: } + } + { + \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl + \tl_use:N \l_@@_head_tl \scan_stop: + } + { + \@@_back_input: + \@@_scan_left_brace: + \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl + \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl + \gtl_gconcat:NNN \g_@@_output_gtl + \g_@@_output_gtl \c_group_begin_gtl + \tl_use:N \l_@@_head_tl \c_group_begin_token + } \@@_print_action:x { \tl_to_str:N \l_@@_head_tl } } % \end{macrocode} @@ -4135,7 +4451,7 @@ \@@_back_input: \@@_back_input:n { - \tex_hbox:D to \tex_hsize:D { } + \@@_hbox:w to \tex_hsize:D { } \tex_vfill:D \tex_penalty:D - '10000000000 ~ } @@ -4431,8 +4747,8 @@ \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_head_tl \@@_print_action: \token_if_eq_meaning:NNTF \l_@@_head_token \tex_kern:D - { \@@_scan_dimen:NN \c_true_bool \c_false_bool } - { \@@_scan_dimen:NN \c_false_bool \c_false_bool } + { \@@_scan_dimen:nN { 2 } \c_false_bool } + { \@@_scan_dimen:nN { 3 } \c_false_bool } \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl \tl_use:N \l_@@_head_tl \scan_stop: \@@_print_action:x { \tl_to_str:N \l_@@_head_tl } @@ -4579,7 +4895,7 @@ { \int_compare:nNnT \l_@@_head_char_int = { 1 } % indent { - \tex_hbox:D width \tex_parindent:D { } + \@@_hbox:w width \tex_parindent:D { } \gtl_gput_right:NV \g_@@_output_gtl \l_@@_head_tl } \@@_print_action: @@ -5267,7 +5583,6 @@ % % \subsubsection{Assignments} % -% ^^A todo: introduce \@@_tmp:w % Quoting \texttt{tex.web}: ``Every prefix, and every command code that % might or might not be prefixed, calls the action procedure % |prefixed_command|. This routine accumulates a sequence of prefixes @@ -5351,7 +5666,6 @@ % \end{macro} % % \begin{macro}[int]{\@@_assign_token:n} -% ^^A todo: wrong printed value for \count123=123\count\count123=987. % \begin{macrocode} \cs_new_protected:Npn \@@_assign_token:n #1 { @@ -5364,7 +5678,6 @@ % \end{macro} % % \begin{macro}[int]{\@@_assign_register:} -% ^^A todo: wrong printed value for \count123=123\count\count123=987. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_assign_register: { @@ -5460,7 +5773,7 @@ { \@@_scan_font_int: } { \@@_scan_int: } } \@@_prefixed_new:nn { set_aux } % 79 - { % prevdepth = 1, spacefactor = 0 + { % prevdepth = 1, spacefactor = 102 \int_compare:nNnTF \l_@@_head_char_int = \c_one { \@@_assign_value:nn { } { \@@_scan_normal_dimen: } } { \@@_assign_value:nn { } { \@@_scan_int: } } @@ -5669,33 +5982,46 @@ } % \end{macrocode} % -% ^^A todo: the implementation of |set_interaction| looks fishy % \begin{macrocode} \@@_prefixed_new:nn { set_interaction } % 100 { \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_tmpa_tl - \tl_put_right:NV \l_@@_head_tl \l_@@_tmpa_tl + \tl_put_left:NV \l_@@_head_tl \l_@@_tmpa_tl \tl_use:N \l_@@_head_tl \scan_stop: \@@_print_action:x { \tl_to_str:N \l_@@_head_tl } } % \end{macrocode} % +% ^^A todo: print the temporary nullfont assignment? % \begin{macrocode} \@@_prefixed_new:nn { letterspace_font } % 101 { - % ^^A todo... - % new_letterspaced_font(a); - \msg_error:nnx { unravel } { not-implemented } { letterspace-font } - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl - \@@_omit_after_assignment:w + \@@_prev_input_silent:V \l_@@_head_tl + \@@_set_action_text:x { \tl_to_str:N \l_@@_head_tl } + \@@_scan_r_token: + \@@_print_action:x + { \g_@@_action_text_str \tl_to_str:N \l_@@_defined_tl } + \exp_after:wN \cs_set_eq:NN \l_@@_defined_tl \@@_nullfont: + \@@_scan_optional_equals: + \@@_scan_font_ident: + \@@_scan_int: + \@@_assign_token:n { } } +% \end{macrocode} +% +% ^^A todo: print the temporary nullfont assignment? +% \begin{macrocode} \@@_prefixed_new:nn { pdf_copy_font } % 102 { - % ^^A todo... - % make_font_copy(a); - \msg_error:nnx { unravel } { not-implemented } { pdf-copy-font } - \seq_gpop_right:NN \g_@@_prev_input_seq \l_@@_head_tl - \@@_omit_after_assignment:w + \@@_prev_input_silent:V \l_@@_head_tl + \@@_set_action_text:x { \tl_to_str:N \l_@@_head_tl } + \@@_scan_r_token: + \@@_print_action:x + { \g_@@_action_text_str \tl_to_str:N \l_@@_defined_tl } + \exp_after:wN \cs_set_eq:NN \l_@@_defined_tl \@@_nullfont: + \@@_scan_optional_equals: + \@@_scan_font_ident: + \@@_assign_token:n { } } % \end{macrocode} % @@ -5952,15 +6278,13 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: document that this often fails. -% ^^A todo: better \endinput? Document current behaviour (ignored). -% \begin{macro}[aux]{\@@_scantokens:, \@@_input:} +% \begin{macro}[aux]{\@@_endinput:, \@@_scantokens:, \@@_input:} % \begin{macrocode} \@@_new_tex_expandable:nn { input } % 106 { \int_case:nnF \l_@@_head_char_int { - { 1 } { \@@_print_action: } % \endinput + { 1 } { \@@_endinput: } % \endinput { 2 } { \@@_scantokens: } % \scantokens } { % 0=\input @@ -5968,6 +6292,11 @@ { \@@_insert_relax: } { \@@_input: } } } +\cs_new_protected_nopar:Npn \@@_endinput: + { + \msg_warning:nn { unravel } { endinput-ignored } + \@@_print_action: + } \cs_new_protected_nopar:Npn \@@_scantokens: { \seq_gput_right:Nn \g_@@_prev_input_seq { } @@ -5990,7 +6319,6 @@ % \end{macrocode} % \end{macro} % -% ^^A todo: this wrongly accepts things let to characters. % \begin{macro}[aux]{\@@_csname_loop:} % \begin{macrocode} \@@_new_tex_expandable:nn { cs_name } % 109 @@ -6215,7 +6543,7 @@ \fi: \int_incr:N \l_@@_if_nesting_int \fi: - \@@_input_gpop:N \l_@@_tmpa_gtl + \@@_input_gpop:N \l_@@_unused_gtl \int_compare:nNnTF \l_@@_if_nesting_int = \c_zero { \@@_pass_text: } { \@@_pass_text_nested: } @@ -6463,7 +6791,7 @@ { \seq_gput_right:NV \g_@@_prev_input_seq \l_@@_head_tl \@@_print_action: - \bool_if:NT \l_@@_debug_bool { \iow_term:n { {\ifcase level~#1} } } + \bool_if:NT \g_@@_internal_debug_bool { \iow_term:n { {\ifcase level~#1} } } \@@_scan_int: \seq_get_right:NN \g_@@_prev_input_seq \l_@@_head_tl \tl_set:Nx \l_@@_head_tl { \tl_tail:N \l_@@_head_tl } @@ -6602,7 +6930,7 @@ \cs_new_protected:Npn \@@_set_action_text:x #1 { \group_begin: - \int_set:Nn \tex_escapechar:D { 92 } + \@@_set_escapechar:n { 92 } \str_gset:Nx \g_@@_action_text_str {#1} \group_end: } @@ -6628,7 +6956,8 @@ \cs_new_protected:Npn \@@_print_state: { \group_begin: - \int_set:Nn \tex_escapechar:D { 92 } + \@@_set_escapechar:n { 92 } + \tl_use:N \g_@@_before_print_state_tl \int_compare:nNnT \g_@@_noise_int > \c_zero { \exp_args:Nx \@@_print_state_output:n @@ -6647,83 +6976,39 @@ % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\@@_print_state_output:n} +% \begin{macro}[aux]{\@@_print_state_output:n} +% Unless empty, print |#1| with each line starting with \verb*+<|~+. +% The \cs{@@_str_truncate_left:nn} function trims |#1| if needed, to +% fit in a maximum of \cs{g_@@_max_output_int} characters. % \begin{macrocode} \cs_new_protected:Npn \@@_print_state_output:n #1 { \tl_if_empty:nF {#1} { - \int_set:Nn \l_@@_print_int { \str_count:n {#1} } \@@_print_message:nn { <| ~ } - { - \int_compare:nNnTF - \l_@@_print_int > \g_@@_max_output_int - { - ( - \int_eval:n - { - \l_@@_print_int - - \g_@@_max_output_int + 14 - } ~ - chars - )~ - ... - \str_substr:nnn {#1} - { \l_@@_print_int - \g_@@_max_output_int + 15 } - { \l_@@_print_int } - } - {#1} - } + { \@@_str_truncate_left:nn {#1} { \g_@@_max_output_int } } } } % \end{macrocode} % \end{macro} % -% ^^A todo: use \cs{g_@@_max_prev_int} % \begin{macro}[aux]{\@@_print_state_prev:n} +% Never trim~|#1|. % \begin{macrocode} \cs_new_protected:Npn \@@_print_state_prev:n #1 - { - % \int_set:Nn \l_@@_print_int { \str_count:n {#1} } - \@@_print_message:nn { || ~ } {#1} - % { - % \int_compare:nNnTF \l_@@_print_int > \g_@@_max_prev_int - % { - % ( - % \int_eval:n - % { \l_@@_print_int - \g_@@_max_prev_int + 14 } ~ - % chars - % )~ - % ... - % \str_substr:nnn {#1} - % { \l_@@_print_int - \g_@@_max_prev_int + 15 } - % { \l_@@_print_int } - % } - % {#1} - % } - } + { \@@_print_message:nn { || ~ } {#1} } % \end{macrocode} % \end{macro} % % \begin{macro}[aux]{\@@_print_state_input:n} +% Print |#1| with each line starting with \verb*+|>~+. The +% \cs{@@_str_truncate_right:nn} function trims |#1| if needed, to fit +% in a maximum of \cs{g_@@_max_input_int} characters. % \begin{macrocode} \cs_new_protected:Npn \@@_print_state_input:n #1 { - \int_set:Nn \l_@@_print_int { \str_count:n {#1} } \@@_print_message:nn { |> ~ } - { - \int_compare:nNnTF \l_@@_print_int > \g_@@_max_input_int - { - \str_substr:nnn {#1} { 1 } { \g_@@_max_input_int - 14 } - ...~ - ( - \int_eval:n - { \l_@@_print_int - \g_@@_max_input_int + 14 } ~ - chars - ) - } - {#1} - } + { \@@_str_truncate_right:nn {#1} { \g_@@_max_input_int } } } % \end{macrocode} % \end{macro} @@ -6751,21 +7036,20 @@ \cs_new_protected:Npn \@@_print_action: { \int_gincr:N \g_@@_step_int - \@@_print_message:nn { } + \@@_print:x { - % \\ - [=====~ Step~ \int_use:N \g_@@_step_int \ =====]~ + [===== + \bool_if:NT \g_@@_number_steps_bool + { ~ Step ~ \int_use:N \g_@@_step_int \ } + =====]~ \int_compare:nNnTF { \str_count:N \g_@@_action_text_str } > { \g_@@_max_action_int } { - \str_substr:Nnn \g_@@_action_text_str + \str_range:Nnn \g_@@_action_text_str { 1 } { \g_@@_max_action_int - 3 } ... } { \g_@@_action_text_str } - % \\ - % \ \ < \int_use:N \g_@@_input_int > % ^^A todo: remove - % \ < \seq_count:N \g_@@_prev_input_seq > % ^^A todo: remove } \@@_print_state: } @@ -6812,7 +7096,7 @@ Set~ \exp_after:wN \token_to_str:N \l_@@_defined_tl \tl_if_single:NT \l_@@_defined_tl { ( \exp_after:wN \token_to_meaning:N \l_@@_defined_tl ) } - = \exp_after:wN \tex_the:D \l_@@_defined_tl + = \exp_after:wN \@@_the:w \l_@@_defined_tl } \@@_omit_after_assignment:w } @@ -6820,21 +7104,25 @@ % \end{macro} % % \begin{macro}[int]{\@@_print_welcome:} -% Welcoming message. +% Welcome message. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_print_welcome: { \@@_print_message:nn { } { - \\ - ========~ Welcome~ to~ the~ unravel~ package~ ========\\ - \iow_indent:n + \bool_if:NTF \g_@@_welcome_message_bool { - "<|"~ denotes~ the~ output~ to~ TeX's~ stomach. \\ - "||"~ denotes~ tokens~ waiting~ to~ be~ used. \\ - "|>"~ denotes~ tokens~ that~ we~ will~ act~ on. \\ - Press~<enter>~to~continue;~'h'~<enter>~for~help. \\ + \\ + ========~ Welcome~ to~ the~ unravel~ package~ ========\\ + \iow_indent:n + { + "<|"~ denotes~ the~ output~ to~ TeX's~ stomach. \\ + "||"~ denotes~ tokens~ waiting~ to~ be~ used. \\ + "|>"~ denotes~ tokens~ that~ we~ will~ act~ on. \\ + Press~<enter>~to~continue;~'h'~<enter>~for~help. \\ + } } + { [=====~Start~=====] } } \@@_print_state: } @@ -6845,13 +7133,7 @@ % Final message. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_print_outcome: - { - % \int_gset_eq:NN \g_@@_max_input_int \c_max_int - % \int_gset_eq:NN \g_@@_max_prev_int \c_max_int - % \int_gset_eq:NN \g_@@_max_output_int \c_max_int - % \@@_print_state: - \@@_print_message:nn { } { [=====~The~end!~=====] \\ } - } + { \@@_print:n { [=====~End~=====] } } % \end{macrocode} % \end{macro} % @@ -6865,18 +7147,23 @@ \int_compare:nNnF \g_@@_nonstop_int > \c_zero { \group_begin: - \int_set_eq:NN \tex_escapechar:D \c_minus_one + \@@_set_escapechar:n { -1 } \int_set_eq:NN \tex_endlinechar:D \c_minus_one - \tl_use:N \g_@@_prompt_before_tl - \tl_gclear:N \g_@@_prompt_before_tl + \tl_use:N \g_@@_before_prompt_tl \@@_prompt_aux: \group_end: } } \cs_new_protected_nopar:Npn \@@_prompt_aux: { - \ior_get_str:Nc \g_@@_prompt_ior { Your~input } - \exp_args:Nv \@@_prompt_treat:n { Your~input } + \int_compare:nNnT { \etex_interactionmode:D } = { 3 } + { + \bool_if:NTF \g_@@_explicit_prompt_bool + { \ior_get_str:Nc \c_@@_prompt_ior } + { \ior_get_str:Nc \c_@@_noprompt_ior } + { Your~input } + \exp_args:Nv \@@_prompt_treat:n { Your~input } + } } \cs_new_protected:Npn \@@_prompt_treat:n #1 { @@ -6908,6 +7195,9 @@ { \tl_gclear:N \g_@@_tmpc_tl } \group_insert_after:N \g_@@_tmpc_tl } + { | } { \@@_prompt_scan_int:nn {#1} + \@@_prompt_vert:n } + { a } { \@@_prompt_all: } } { \@@_prompt_help: } } @@ -6915,7 +7205,9 @@ \cs_new_protected:Npn \@@_prompt_scan_int:nn #1 { \tex_afterassignment:D \@@_prompt_scan_int_after:wn - \l_@@_prompt_tmpa_int = 0 \use_none:n #1 \scan_stop: + \l_@@_prompt_tmpa_int = + \tl_if_head_eq_charcode:fNF { \use_none:n #1 } - { 0 } + \use_ii:nn #1 \scan_stop: } \cs_new_protected:Npn \@@_prompt_scan_int_after:wn #1 \scan_stop: #2 { @@ -6925,87 +7217,222 @@ \cs_new_protected:Npn \@@_prompt_help: { \@@_print:n { "m":~meaning~of~first~token } - \@@_print:n { "q":~semi-quiet } - \@@_print:n { "x":~exit~this~instance~of~unravel } - \@@_print:n { "X":~try~harder~to~exit } + \@@_print:n { "q":~semi-quiet~(same~as~"o1") } + \@@_print:n { "x"/"X":~exit~this~instance~of~unravel/TeX } \@@_print:n { "s<num>":~do~<num>~steps~silently } \@@_print:n - { "o<num>":~0~=>~only~log~not~online,~1~=>~both,~-1~=>~neither.} - \@@_print:n { "C<code>":~run~some~code~immediately } + { "o<num>":~1~=>~log~and~terminal,~0~=>~only~log,~-1~=>~neither.} + \@@_print:n { "C<code>":~run~some~expl3~code~immediately } + \@@_print:n { "|<num>":~silent~steps~until~<num>~fewer~"||" } + \@@_print:n { "a":~print~state~again,~without~truncating } \@@_prompt_aux: } \cs_new_protected:Npn \@@_prompt_silent_steps:n #1 { + \int_compare:nNnF {#1} < \c_zero + { + \int_gset_eq:NN \g_@@_noise_int \c_minus_one + \tl_gset:Nn \g_@@_before_prompt_tl + { + \int_gset_eq:NN \g_@@_noise_int \c_one + \tl_gclear:N \g_@@_before_prompt_tl + } + \int_gset:Nn \g_@@_nonstop_int {#1} + } + } +\cs_new_protected:Npn \@@_prompt_vert:n #1 + { + \int_compare:nNnTF {#1} < { 0 } + { \@@_prompt_vert:Nn > {#1} } + { \@@_prompt_vert:Nn < {#1} } + } +\cs_new_protected:Npn \@@_prompt_vert:Nn #1#2 + { \int_gset_eq:NN \g_@@_noise_int \c_minus_one - \tl_gset:Nn \g_@@_prompt_before_tl - { \int_gset_eq:NN \g_@@_noise_int \c_one } - \int_gset:Nn \g_@@_nonstop_int {#1} + \tl_gset:Nf \g_@@_before_print_state_tl + { + \exp_args:NNf \exp_stop_f: \int_compare:nNnTF + { \int_eval:n { \seq_count:N \g_@@_prev_input_seq - #2 } } + #1 { \seq_count:N \g_@@_prev_input_seq } + { + \int_gset:Nn \g_@@_nonstop_int + { \int_max:nn { \g_@@_nonstop_int } { 2 } } + } + { + \int_gset_eq:NN \g_@@_noise_int \c_one + \tl_gclear:N \g_@@_before_print_state_tl + } + } } +\cs_new_protected_nopar:Npn \@@_prompt_all: + { + \tl_gset:Nx \g_@@_tmpc_tl + { + \exp_not:n + { + \tl_gclear:N \g_@@_tmpc_tl + \int_gset_eq:NN \g_@@_max_output_int \c_max_int + \int_gset_eq:NN \g_@@_max_input_int \c_max_int + \@@_print_state: + } + \@@_prompt_all_aux:N \g_@@_max_output_int + \@@_prompt_all_aux:N \g_@@_max_input_int + } + \group_insert_after:N \g_@@_tmpc_tl + } +\cs_new:Npn \@@_prompt_all_aux:N #1 + { \exp_not:n { \int_gset:Nn #1 } { \int_use:N #1 } } % \end{macrocode} % \end{macro} % +% ^^A todo: I suspect a bug if given 'a' twice in a row +% +% \subsection{Keys} +% +% Each key needs to be defined twice: for its default setting and for +% its setting applying to a single \cs{unravel}. This is due to the +% fact that we cannot use grouping to keep settings local to a single +% \cs{unravel} since the \meta{code} argument of \cs{unravel} may open +% or close groups. +% \begin{macrocode} +\keys_define:nn { unravel/defaults } + { + explicit-prompt .bool_gset:N = \g_@@_default_explicit_prompt_bool , + internal-debug .bool_gset:N = \g_@@_default_internal_debug_bool , + max-action .int_gset:N = \g_@@_default_max_action_int , + max-output .int_gset:N = \g_@@_default_max_output_int , + max-input .int_gset:N = \g_@@_default_max_input_int , + number-steps .bool_gset:N = \g_@@_default_number_steps_bool , + welcome-message .bool_gset:N = \g_@@_default_welcome_message_bool , + } +\keys_define:nn { unravel } + { + explicit-prompt .bool_gset:N = \g_@@_explicit_prompt_bool , + internal-debug .bool_gset:N = \g_@@_internal_debug_bool , + max-action .int_gset:N = \g_@@_max_action_int , + max-output .int_gset:N = \g_@@_max_output_int , + max-input .int_gset:N = \g_@@_max_input_int , + number-steps .bool_gset:N = \g_@@_number_steps_bool , + welcome-message .bool_gset:N = \g_@@_welcome_message_bool , + } +% \end{macrocode} +% +% The |machine| option is somewhat special so it is clearer to define +% it separately. The code is identical for |unravel/defaults| and +% |unravel| keys. To be sure of which options are set, use |.meta:nn| +% and give the path explicitly. +% \begin{macrocode} +\tl_map_inline:nn { { /defaults } { } } + { + \keys_define:nn { unravel #1 } + { + machine .meta:nn = + { unravel #1 } + { + explicit-prompt = false , + internal-debug = false , + max-action = \c_max_int , + max-output = \c_max_int , + max-input = \c_max_int , + number-steps = false , + welcome-message = false , + } , + } + } +% \end{macrocode} +% % \subsection{Main command} % % \begin{macro}{\unravel} -% Simply call an underlying internal command. +% Simply call an underlying code-level command. +% \begin{macrocode} +\NewDocumentCommand \unravel { O { } m } { \unravel:nn {#1} {#2} } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\unravelsetup} +% Simply call an underlying code-level command. % \begin{macrocode} -\cs_new_protected:Npn \unravel #1 { \@@_unravel:n {#1} } +\NewDocumentCommand \unravelsetup { m } { \unravel_setup:n {#1} } % \end{macrocode} % \end{macro} % -% \begin{macro}{\UnravelDebug} -% Turn on debugging mode. +% \begin{macro}{\unravel_setup:n} +% Set keys, updating both default values and current values. % \begin{macrocode} -\cs_new_protected_nopar:Npn \UnravelDebug +\cs_new_protected:Npn \unravel_setup:n #1 { - \bool_set_true:N \l_@@_debug_bool + \keys_set:nn { unravel/defaults } {#1} + \keys_set:nn { unravel } {#1} } % \end{macrocode} % \end{macro} % -% \begin{macro}[int]{\@@_unravel:n} -% Welcome the user, then initialize the input, output and step. Until -% the input is exhausted, print the current status and do one step. +% \begin{macro}[int]{\unravel:nn} +% Initialize and setup keys. Initialize and setup other variables +% including the input. Welcome the user. Then comes the main loop: +% until the input is exhausted, print the current status and do one +% step. The main loop is exited by skipping to the first +% \cs{@@_exit_point:}, while some abort procedures jump to the second +% (and last) one instead. If the main loop finished correctly, print +% its outcome and finally test that everything is all right. % \begin{macrocode} -\cs_new_protected:Npn \@@_unravel:n #1 +\cs_new_protected:Npn \unravel:nn #1#2 + { + \@@_init_key_vars: + \keys_set:nn { unravel } {#1} + \@@_init_vars: + \@@_input_gset:n {#2} + \@@_print_welcome: + \@@_main_loop: + \@@_exit_point: + \@@_print_outcome: + \@@_final_test: + \@@_exit_point: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_init_key_vars:} +% Give variables that are affected by keys their default values (also +% controlled by keys). +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_init_key_vars: + { + \bool_gset_eq:NN \g_@@_explicit_prompt_bool \g_@@_default_explicit_prompt_bool + \bool_gset_eq:NN \g_@@_internal_debug_bool \g_@@_default_internal_debug_bool + \bool_gset_eq:NN \g_@@_number_steps_bool \g_@@_default_number_steps_bool + \bool_gset_eq:NN \g_@@_welcome_message_bool \g_@@_default_welcome_message_bool + \int_gset_eq:NN \g_@@_max_action_int \g_@@_default_max_action_int + \int_gset_eq:NN \g_@@_max_output_int \g_@@_default_max_output_int + \int_gset_eq:NN \g_@@_max_input_int \g_@@_default_max_input_int + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_init_vars:} +% Give initial values to variables used during the processing. These +% have no reason to be modified by the user: neither directly nor +% through keys. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_init_vars: { - \int_gzero:N \g_@@_step_int - \@@_input_gset:n {#1} \seq_gclear:N \g_@@_prev_input_seq \gtl_gclear:N \g_@@_output_gtl + \int_gzero:N \g_@@_step_int \tl_gclear:N \g_@@_if_limit_tl \int_gzero:N \g_@@_if_limit_int \int_gzero:N \g_@@_if_depth_int \gtl_gclear:N \g_@@_after_assignment_gtl \bool_gset_true:N \g_@@_set_box_allowed_bool \bool_gset_false:N \g_@@_name_in_progress_bool - \cs_gset_eq:NN \g_@@_prompt_ior \c_minus_one % ^^A todo:? - \@@_print_welcome: - \@@_main_loop: - \@@_exit_point: - \@@_print_outcome: - \bool_if:nTF - { - \tl_if_empty_p:N \g_@@_if_limit_tl - && \int_compare_p:nNn \g_@@_if_limit_int = \c_zero - && \int_compare_p:nNn \g_@@_if_depth_int = \c_zero - && \seq_if_empty_p:N \g_@@_prev_input_seq - } - { \@@_input_if_empty:TF { } { \@@_bad_finish: } } - { \@@_bad_finish: } - \@@_exit_point: - } -\cs_new_protected_nopar:Npn \@@_bad_finish: - { - \msg_error:nnx { unravel } { internal } - { the-last-unravel-finished-badly } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_main_loop:} -% Loop forever, getting a token and performing the corresponding -% command. +% Loop forever, getting the next token (with expansion) and +% performing the corresponding command. % \begin{macrocode} \cs_new_protected_nopar:Npn \@@_main_loop: { @@ -7017,6 +7444,31 @@ % \end{macrocode} % \end{macro} % +% ^^A todo: improve error message +% \begin{macro}[aux]{\@@_final_test:, \@@_final_bad:} +% Make sure that the \cs{unravel} finished correctly. The error +% message is a bit primitive. +% \begin{macrocode} +\cs_new_protected_nopar:Npn \@@_final_test: + { + \bool_if:nTF + { + \tl_if_empty_p:N \g_@@_if_limit_tl + && \int_compare_p:nNn \g_@@_if_limit_int = \c_zero + && \int_compare_p:nNn \g_@@_if_depth_int = \c_zero + && \seq_if_empty_p:N \g_@@_prev_input_seq + } + { \@@_input_if_empty:TF { } { \@@_final_bad: } } + { \@@_final_bad: } + } +\cs_new_protected_nopar:Npn \@@_final_bad: + { + \msg_error:nnx { unravel } { internal } + { the-last-unravel-finished-badly } + } +% \end{macrocode} +% \end{macro} +% % \subsection{Messages} % % \begin{macrocode} @@ -7077,14 +7529,21 @@ { Missing~\iow_char:N\\endcsname~inserted. } \msg_new:nnn { unravel } { runaway-if } { Runaway~\iow_char:N\\if... } +\msg_new:nnn { unravel } { runaway-macro-parameter } + { + Runaway~macro~parameter~\# #2~after \\\\ + \iow_indent:n {#1} + } \msg_new:nnn { unravel } { extra-or } { Extra~\iow_char:N\\or. } \msg_new:nnn { unravel } { missing-equals } { Missing~equals~for~\iow_char:N\\ifnum~or~\iow_char:N\\ifdim. } \msg_new:nnn { unravel } { internal } - { Internal~error:~'#1'.~\ Please report. } + { Internal~error:~'#1'.~\ Please~report. } \msg_new:nnn { unravel } { not-implemented } { The~following~feature~is~not~implemented:~'#1'. } +\msg_new:nnn { unravel } { endinput-ignored } + { The~primitive~\iow_char:N\\endinput~was~ignored. } % \end{macrocode} % % \begin{macrocode} diff --git a/Master/texmf-dist/tex/latex/unravel/unravel.sty b/Master/texmf-dist/tex/latex/unravel/unravel.sty index 1665ce3acf4..630584380a7 100644 --- a/Master/texmf-dist/tex/latex/unravel/unravel.sty +++ b/Master/texmf-dist/tex/latex/unravel/unravel.sty @@ -11,7 +11,7 @@ %% Communicate any suggestions for changing this package %% to Bruno Le Floch (blflatex@gmail.com). %% -%% File: unravel.dtx Copyright (C) 2013 Bruno Le Floch +%% File: unravel.dtx Copyright (C) 2013, 2015 Bruno Le Floch %% %% It may be distributed and/or modified under the conditions of the %% LaTeX Project Public License (LPPL), either version 1.3c of this @@ -21,80 +21,21 @@ %% http://www.latex-project.org/lppl.txt %% %% ----------------------------------------------------------------------- -\RequirePackage{expl3}[2013/07/01] -\RequirePackage{l3str}[2013/04/24] -\RequirePackage{gtl}[2013/07/28] +\RequirePackage{expl3,xparse}[2015/09/11] +\RequirePackage{gtl}[2015/09/21] \ProvidesExplPackage - {unravel} {2013/07/28} {0.0a} {Watching TeX digest tokens} -\ior_new:N \g__unravel_prompt_ior -\tl_new:N \g__unravel_prompt_before_tl -\int_new:N \l__unravel_prompt_tmpa_int -\int_new:N \g__unravel_nonstop_int -\int_new:N \g__unravel_noise_int -\int_gset_eq:NN \g__unravel_noise_int \c_one -\bool_new:N \l__unravel_debug_bool -\int_new:N \g__unravel_step_int -\str_new:N \g__unravel_action_text_str -\int_new:N \g__unravel_max_action_int -\int_new:N \g__unravel_max_output_int -\int_new:N \g__unravel_max_prev_int -\int_new:N \g__unravel_max_input_int -\int_gset:Nn \g__unravel_max_action_int { 50 } -\int_gset:Nn \g__unravel_max_output_int { 300 } -\int_gset:Nn \g__unravel_max_prev_int { 300 } -\int_gset:Nn \g__unravel_max_input_int { 300 } -\bool_new:N \g__unravel_speedup_macros_bool -\bool_gset_true:N \g__unravel_speedup_macros_bool -\int_new:N \l__unravel_print_int -\int_new:N \g__unravel_input_int -\int_new:N \g__unravel_input_tmpa_int -\tl_new:N \l__unravel_input_tmpa_tl -\seq_new:N \g__unravel_prev_input_seq -\tl_new:N \l__unravel_prev_input_tl -\gtl_new:N \l__unravel_prev_input_gtl -\gtl_new:N \g__unravel_output_gtl -\gtl_new:N \l__unravel_head_gtl -\tl_new:N \l__unravel_head_tl -\token_new:Nn \l__unravel_head_token { ? } -\int_new:N \l__unravel_head_cmd_int -\int_new:N \l__unravel_head_char_int -\tl_new:N \l__unravel_head_meaning_tl -\tl_new:N \l__unravel_tmpa_tl -\gtl_new:N \l__unravel_tmpb_gtl -\tl_new:N \g__unravel_tmpc_tl -\seq_new:N \l__unravel_tmpa_seq -\tl_new:N \l__unravel_defined_tl -\tl_new:N \l__unravel_defining_tl -\cs_new_eq:NN \__unravel_inaccessible:w ? -\gtl_new:N \g__unravel_after_assignment_gtl -\bool_new:N \g__unravel_set_box_allowed_bool -\bool_new:N \g__unravel_name_in_progress_bool -\group_begin: - \char_set_lccode:nn { `* } { `# } - \tex_lowercase:D - { \tl_const:Nn \c__unravel_parameters_tl { ^*1*2*3*4*5*6*7*8*9 } } -\group_end: -\int_new:N \g__unravel_val_level_int -\tl_const:Nn \c__unravel_plus_tl { + } -\tl_const:Nn \c__unravel_minus_tl { - } -\tl_const:Nn \c__unravel_times_tl { * } -\tl_const:Nn \c__unravel_over_tl { / } -\tl_const:Nn \c__unravel_lq_tl { ` } -\tl_const:Nn \c__unravel_rq_tl { ' } -\tl_const:Nn \c__unravel_dq_tl { " } -\tl_const:Nn \c__unravel_lp_tl { ( } -\tl_const:Nn \c__unravel_rp_tl { ) } -\tl_const:Nn \c__unravel_eq_tl { = } -\tl_const:Nn \c__unravel_comma_tl { , } -\tl_const:Nn \c__unravel_point_tl { . } -\tl_new:N \g__unravel_if_limit_tl -\int_new:N \g__unravel_if_limit_int -\int_new:N \g__unravel_if_depth_int -\int_new:N \l__unravel_if_nesting_int -\seq_new:N \l__unravel_leaders_box_seq -\int_new:N \g__unravel_ends_int -\int_gset:Nn \g__unravel_ends_int { 3 } -\gtl_const:Nx \c__unravel_frozen_relax_gtl { \if_int_compare:w 0 = 0 \fi: } + {unravel} {2015/09/22} {0.1} {Watching TeX digest tokens} +\cs_if_exist:NF \str_range:nnn { \RequirePackage{l3str} } +\cs_new_eq:NN \__unravel_currentgrouptype: \etex_currentgrouptype:D +\cs_new_protected_nopar:Npn \__unravel_set_escapechar:n + { \int_set:Nn \tex_escapechar:D } +\cs_new_eq:NN \__unravel_everyeof:w \etex_everyeof:D +\cs_new_eq:NN \__unravel_everypar:w \tex_everypar:D +\cs_new_eq:NN \__unravel_hbox:w \tex_hbox:D +\cs_new_eq:NN \__unravel_nullfont: \tex_nullfont:D +\cs_new_eq:NN \__unravel_the:w \tex_the:D +\cs_new_eq:NN \c__unravel_prompt_ior \c_sixteen +\cs_new_eq:NN \c__unravel_noprompt_ior \c_minus_one \cs_if_exist:NF \exp_last_unbraced:NNn { \cs_new_eq:NN \exp_last_unbraced:NNn \use:nnn } \cs_generate_variant:Nn \exp_last_unbraced:NNn { NNv } @@ -121,21 +62,19 @@ \cs_generate_variant:Nn \gtl_gset:Nn { c } \cs_generate_variant:Nn \gtl_gconcat:NNN { ccc , cNc } \cs_generate_variant:Nn \gtl_gclear:N { c } +\cs_generate_variant:Nn \gtl_gclear_new:N { c } +\cs_new_protected_nopar:Npn \__unravel_tmp:w { } \cs_new_protected:Npn \__unravel_tl_gset_input:Nnn #1#2#3 { \group_begin: - \etex_everyeof:D \exp_after:wN { \token_to_str:N @ @ #1 } + \__unravel_everyeof:w \exp_after:wN { \token_to_str:N @ @ #1 } #2 \tl_gclear:N #1 - \str_if_eq_x:nnF - { \token_to_meaning:N \tex_input:D } - { \token_to_str:N \input } - { \msg_unravel:nnx { unravel } { internal } { input-prim } } \exp_after:wN \__unravel_tl_gset_input_aux:wN \exp_after:wN \prg_do_nothing: \tex_input:D \tl_to_str:n {#3} \scan_stop: \group_end: - \tl_gput_right:NV #1 \etex_everyeof:D + \tl_gput_right:NV #1 \__unravel_everyeof:w } \cs_generate_variant:Nn \__unravel_tl_gset_input:Nnn { Nno } \use:x @@ -143,7 +82,6 @@ \cs_new_protected:Npn \exp_not:N \__unravel_tl_gset_input_aux:wN ##1 \token_to_str:N @ @ ##2 } { \tl_gset:No #2 {#1} } -\cs_new_eq:NN \__unravel_cs_case:NnF \tl_case:NnF \cs_new_nopar:Npn \__unravel_strip_escape:w { \tex_romannumeral:D @@ -153,15 +91,6 @@ \cs_new:Npn \__unravel_strip_escape_aux:N #1 { \c_zero } \cs_new:Npn \__unravel_strip_escape_aux:w #1#2 { - \__int_value:w #1 \c_zero } -\cs_new:Npn \__unravel_meaning_to_char:n #1 - { \__unravel_meaning_to_char_auxi:w #1 \q_mark ~ {} ~ \q_mark \q_stop } -\cs_new:Npn \__unravel_meaning_to_char_auxi:w #1 ~ #2 ~ #3 \q_mark #4 \q_stop - { \__unravel_meaning_to_char_auxii:w #3 ~ #3 ~ \q_stop } -\cs_new:Npn \__unravel_meaning_to_char_auxii:w #1 ~ #2 ~ #3 \q_stop - { \tl_if_empty:nTF {#2} { ~ } {#2} } -\cs_generate_variant:Nn \__unravel_meaning_to_char:n { o } -\cs_new:Npn \__unravel_token_to_char:N #1 - { \__unravel_meaning_to_char:o { \token_to_meaning:N #1 } } \cs_new:Npn \__unravel_to_str:n #1 { \tl_if_head_eq_meaning:nNTF {#1} \scan_stop: @@ -177,28 +106,64 @@ #1 tl \q_mark \q_stop } \cs_new:Npn \__unravel_to_str_auxii:w ##1 #1 ##2 \q_mark ##3 \q_stop - { \cs_if_exist_use:cF { ##2 _to_str:n } { \tl_to_str:n } } + { \cs_if_exist_use:cF { __unravel_ ##2 _to_str:n } { \tl_to_str:n } } } \exp_args:No \__unravel_tmp:w { \tl_to_str:n { s__ } } -\cs_new_protected:Npn \__unravel_prev_input_silent:n #1 +\cs_new:Npn \__unravel_gtl_to_str:n #1 { \__gtl_to_str:w #1 } +\cs_new:Npn \__unravel_str_truncate_left:nn #1#2 { - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_prev_input_tl - \tl_put_right:Nn \l__unravel_prev_input_tl {#1} - \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_prev_input_tl + \exp_args:Nf \__unravel_str_truncate_left_aux:nnn + { \str_count:n {#1} } {#1} {#2} } -\cs_generate_variant:Nn \__unravel_prev_input_silent:n { V , x } -\cs_new_protected:Npn \__unravel_prev_input:n #1 +\cs_new:Npn \__unravel_str_truncate_left_aux:nnn #1#2#3 { - \__unravel_prev_input_silent:n {#1} - \__unravel_print_action:x { \tl_to_str:n {#1} } + \int_compare:nNnTF {#1} > {#3} + { + ( \int_eval:n { #1 - #3 + 25 } ~ more~chars ) ~ + \str_range:nnn {#2} { #1 - #3 + 26 } {#1} + } + { \tl_to_str:n {#2} } } -\cs_generate_variant:Nn \__unravel_prev_input:n { V , x } -\cs_new_protected:Npn \__unravel_prev_input_gtl:N #1 +\cs_new:Npn \__unravel_str_truncate_right:nn #1#2 { - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_prev_input_gtl - \gtl_concat:NNN \l__unravel_prev_input_gtl \l__unravel_prev_input_gtl #1 - \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_prev_input_gtl + \exp_args:Nf \__unravel_str_truncate_right_aux:nnn + { \str_count:n {#1} } {#1} {#2} + } +\cs_new:Npn \__unravel_str_truncate_right_aux:nnn #1#2#3 + { + \int_compare:nNnTF {#1} > {#3} + { + \str_range:nnn {#2} { 1 } { #3 - 25 } ~ + ( \int_eval:n { #1 - #3 + 25 } ~ more~chars ) + } + { \tl_to_str:n {#2} } + } +\cs_new_eq:NN \__unravel_exit_point: \prg_do_nothing: +\cs_new:Npn \__unravel_exit:w #1 \__unravel_exit_point: { } +\cs_new_eq:NN \__unravel_break_point: \prg_do_nothing: +\cs_new:Npn \__unravel_break:w #1 \__unravel_break_point: { } +\prg_new_conditional:Npnn \__unravel_cmd_if_internal: { TF } + { + \int_compare:nNnTF + \l__unravel_head_cmd_int < { \__unravel_tex_use:n { min_internal } } + { \prg_return_false: } + { + \int_compare:nNnTF + \l__unravel_head_cmd_int + > { \__unravel_tex_use:n { max_internal } } + { \prg_return_false: } + { \prg_return_true: } + } } +\cs_new:Npn \__unravel_meaning_to_char:n #1 + { \__unravel_meaning_to_char_auxi:w #1 \q_mark ~ {} ~ \q_mark \q_stop } +\cs_new:Npn \__unravel_meaning_to_char_auxi:w #1 ~ #2 ~ #3 \q_mark #4 \q_stop + { \__unravel_meaning_to_char_auxii:w #3 ~ #3 ~ \q_stop } +\cs_new:Npn \__unravel_meaning_to_char_auxii:w #1 ~ #2 ~ #3 \q_stop + { \tl_if_empty:nTF {#2} { ~ } {#2} } +\cs_generate_variant:Nn \__unravel_meaning_to_char:n { o } +\cs_new:Npn \__unravel_token_to_char:N #1 + { \__unravel_meaning_to_char:o { \token_to_meaning:N #1 } } \prg_new_conditional:Npnn \__unravel_token_if_expandable:N #1 { p , T , F , TF } { @@ -223,18 +188,16 @@ } { \prg_return_true: } } -\cs_new_eq:NN \__unravel_exit_point: \prg_do_nothing: -\cs_new:Npn \__unravel_exit:w #1 \__unravel_exit_point: { } -\cs_new_eq:NN \__unravel_break_point: \prg_do_nothing: -\cs_new:Npn \__unravel_break:w #1 \__unravel_break_point: { } \group_begin: \char_set_catcode_active:n { `Z } \prg_new_protected_conditional:Npnn \__unravel_token_if_definable:N #1 { TF } { \group_begin: - \int_set:Nn \tex_escapechar:D { 92 } - \exp_args:No \tl_if_single:nTF { \token_to_str:N #1 } + \__unravel_set_escapechar:n { 92 } + \tl_set:Nx \l__unravel_tmpa_tl + { \exp_args:No \str_tail:n { \token_to_str:N #1 } } + \tl_if_empty:NTF \l__unravel_tmpa_tl { \exp_args:Nx \char_set_lccode:nn { ` \str_head:n {#1} } { `Z } @@ -261,6 +224,123 @@ } { \prg_return_false: } } +\cs_new_protected:Npn \__unravel_prev_input_silent:n #1 + { + \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_prev_input_tl + \tl_put_right:Nn \l__unravel_prev_input_tl {#1} + \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_prev_input_tl + } +\cs_generate_variant:Nn \__unravel_prev_input_silent:n { V , x } +\cs_new_protected:Npn \__unravel_prev_input:n #1 + { + \__unravel_prev_input_silent:n {#1} + \__unravel_print_action:x { \tl_to_str:n {#1} } + } +\cs_generate_variant:Nn \__unravel_prev_input:n { V , x } +\cs_new_protected:Npn \__unravel_prev_input_gtl:N #1 + { + \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_prev_input_gtl + \gtl_concat:NNN \l__unravel_prev_input_gtl \l__unravel_prev_input_gtl #1 + \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_prev_input_gtl + } +\cs_new_protected:Npn \__unravel_prev_input_join_get:nN #1 + { + \int_case:nnF {#1} + { + { 2 } { \__unravel_join_get_aux:NNN \skip_eval:n \etex_glueexpr:D } + { 3 } { \__unravel_join_get_aux:NNN \muskip_eval:n \etex_muexpr:D } + } + { + \msg_error:nnn { unravel } { internal } { join-factor } + \__unravel_join_get_aux:NNN \use:n \prg_do_nothing: + } + } +\cs_new_protected:Npn \__unravel_join_get_aux:NNN #1#2#3 + { + \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl + \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_tmpa_tl + \tl_set:Nx #3 { #1 { \l__unravel_tmpa_tl #2 \l__unravel_head_tl } } + } +\tl_new:N \g__unravel_before_print_state_tl +\tl_new:N \g__unravel_before_prompt_tl +\int_new:N \l__unravel_prompt_tmpa_int +\int_new:N \g__unravel_nonstop_int +\int_new:N \g__unravel_noise_int +\int_gset_eq:NN \g__unravel_noise_int \c_one +\bool_new:N \g__unravel_default_explicit_prompt_bool +\bool_new:N \g__unravel_default_internal_debug_bool +\bool_new:N \g__unravel_default_number_steps_bool +\bool_gset_true:N \g__unravel_default_number_steps_bool +\bool_new:N \g__unravel_default_welcome_message_bool +\bool_gset_true:N \g__unravel_default_welcome_message_bool +\bool_new:N \g__unravel_explicit_prompt_bool +\bool_new:N \g__unravel_internal_debug_bool +\bool_new:N \g__unravel_number_steps_bool +\bool_new:N \g__unravel_welcome_message_bool +\int_new:N \g__unravel_step_int +\str_new:N \g__unravel_action_text_str +\int_new:N \g__unravel_default_max_action_int +\int_new:N \g__unravel_default_max_output_int +\int_new:N \g__unravel_default_max_input_int +\int_gset:Nn \g__unravel_default_max_action_int { 50 } +\int_gset:Nn \g__unravel_default_max_output_int { 300 } +\int_gset:Nn \g__unravel_default_max_input_int { 300 } +\int_new:N \g__unravel_max_action_int +\int_new:N \g__unravel_max_output_int +\int_new:N \g__unravel_max_input_int +\bool_new:N \g__unravel_speedup_macros_bool +\bool_gset_true:N \g__unravel_speedup_macros_bool +\int_new:N \l__unravel_print_int +\int_new:N \g__unravel_input_int +\int_new:N \g__unravel_input_tmpa_int +\tl_new:N \l__unravel_input_tmpa_tl +\seq_new:N \g__unravel_prev_input_seq +\tl_new:N \l__unravel_prev_input_tl +\gtl_new:N \l__unravel_prev_input_gtl +\gtl_new:N \g__unravel_output_gtl +\gtl_new:N \l__unravel_head_gtl +\tl_new:N \l__unravel_head_tl +\token_new:Nn \l__unravel_head_token { ? } +\int_new:N \l__unravel_head_cmd_int +\int_new:N \l__unravel_head_char_int +\tl_new:N \l__unravel_head_meaning_tl +\tl_new:N \l__unravel_tmpa_tl +\gtl_new:N \l__unravel_unused_gtl +\gtl_new:N \l__unravel_tmpb_gtl +\tl_new:N \g__unravel_tmpc_tl +\seq_new:N \l__unravel_tmpa_seq +\tl_new:N \l__unravel_defined_tl +\tl_new:N \l__unravel_defining_tl +\cs_new_eq:NN \__unravel_inaccessible:w ? +\gtl_new:N \g__unravel_after_assignment_gtl +\bool_new:N \g__unravel_set_box_allowed_bool +\bool_new:N \g__unravel_name_in_progress_bool +\group_begin: + \cs_set:Npx \__unravel_tmp:w #1 { \c_hash_str #1 } + \tl_const:Nx \c__unravel_parameters_tl + { ^ \tl_map_function:nN { 123456789 } \__unravel_tmp:w } +\group_end: +\int_new:N \g__unravel_val_level_int +\tl_new:N \g__unravel_if_limit_tl +\int_new:N \g__unravel_if_limit_int +\int_new:N \g__unravel_if_depth_int +\int_new:N \l__unravel_if_nesting_int +\seq_new:N \l__unravel_leaders_box_seq +\int_new:N \g__unravel_ends_int +\int_gset:Nn \g__unravel_ends_int { 3 } +\tl_const:Nn \c__unravel_plus_tl { + } +\tl_const:Nn \c__unravel_minus_tl { - } +\tl_const:Nn \c__unravel_times_tl { * } +\tl_const:Nn \c__unravel_over_tl { / } +\tl_const:Nn \c__unravel_lq_tl { ` } +\tl_const:Nn \c__unravel_rq_tl { ' } +\tl_const:Nn \c__unravel_dq_tl { " } +\tl_const:Nn \c__unravel_lp_tl { ( } +\tl_const:Nn \c__unravel_rp_tl { ) } +\tl_const:Nn \c__unravel_eq_tl { = } +\tl_const:Nn \c__unravel_comma_tl { , } +\tl_const:Nn \c__unravel_point_tl { . } +\gtl_const:Nx \c__unravel_frozen_relax_gtl { \if_int_compare:w 0 = 0 \fi: } \cs_new_protected:Npn \__unravel_tex_const:nn #1#2 { \int_const:cn { c__unravel_tex_#1_int } {#2} } \cs_new:Npn \__unravel_tex_use:n #1 { \int_use:c { c__unravel_tex_#1_int } } @@ -683,7 +763,7 @@ \__unravel_tex_primitive:nnn { lefthyphenmin } { assign_int } { 51 } \__unravel_tex_primitive:nnn { righthyphenmin } { assign_int } { 52 } \__unravel_tex_primitive:nnn { holdinginserts } { assign_int } { 53 } -\__unravel_tex_primitive:nnn { errorcontegtlines } { assign_int } { 54 } +\__unravel_tex_primitive:nnn { errorcontextlines } { assign_int } { 54 } \__unravel_tex_primitive:nnn { pdfoutput } { assign_int } { 55 } \__unravel_tex_primitive:nnn { pdfcompresslevel } { assign_int } { 56 } \__unravel_tex_primitive:nnn { pdfdecimaldigits } { assign_int } { 57 } @@ -1158,14 +1238,16 @@ \cs_new_protected:Npn \__unravel_input_split_auxiii:w #1 \__unravel_input_split_end: { + \gtl_gclear_new:c + { g__unravel_input_ \int_use:N \g__unravel_input_tmpa_int _gtl } \gtl_gset:cn { g__unravel_input_ \int_use:N \g__unravel_input_tmpa_int _gtl } {#1} \int_gdecr:N \g__unravel_input_tmpa_int } \cs_new_protected_nopar:Npn \__unravel_input_gset:n { - \int_gset_eq:NN \g__unravel_input_int \c_one - \gtl_gset:cn { g__unravel_input_1_gtl } + \int_gzero:N \g__unravel_input_int + \__unravel_back_input:n } \cs_new_protected:Npn \__unravel_input_get:N #1 { @@ -1262,6 +1344,7 @@ \cs_new_protected_nopar:Npn \__unravel_back_input:n { \int_gincr:N \g__unravel_input_int + \gtl_gclear_new:c { g__unravel_input_ \int_use:N \g__unravel_input_int _gtl } \gtl_gset:cn { g__unravel_input_ \int_use:N \g__unravel_input_int _gtl } } \cs_generate_variant:Nn \__unravel_back_input:n { x , V , o } @@ -1308,21 +1391,20 @@ \msg_error:nn { unravel } { missing-dollar } \__unravel_print_action: } -\group_begin: - \char_set_lccode:nn { `. } { `: } - \tex_lowercase:D - { - \cs_new:Npn \__unravel_macro_split_do:NN #1 - { - \exp_after:wN \__unravel_macro_split_do:wN - \token_to_meaning:N #1 \q_mark { } . -> \q_mark \use_none:nnnn - \q_stop - } - \cs_new:Npn \__unravel_macro_split_do:wN - #1 . #2 -> #3 \q_mark #4 #5 \q_stop #6 - { #4 #6 {#1} {#2} {#3} } - } -\group_end: +\use:x + { + \exp_not:n { \cs_new:Npn \__unravel_macro_split_do:NN #1 } + { + \exp_not:n { \exp_after:wN \__unravel_macro_split_do:wN } + \exp_not:n { \token_to_meaning:N #1 \q_mark { } } + \tl_to_str:n { : } \exp_not:n { -> \q_mark \use_none:nnnn } + \exp_not:N \q_stop + } + \exp_not:n { \cs_new:Npn \__unravel_macro_split_do:wN } + \exp_not:n {#1} \tl_to_str:n { : } \exp_not:n { #2 -> } + \exp_not:n { #3 \q_mark #4 #5 \q_stop #6 } + { \exp_not:n { #4 #6 {#1} {#2} {#3} } } + } \cs_new:Npn \__unravel_macro_prefix:N #1 { \__unravel_macro_split_do:NN #1 \use_i:nnn } \cs_new:Npn \__unravel_macro_parameter:N #1 @@ -1349,22 +1431,28 @@ } \cs_new_protected_nopar:Npn \__unravel_macro_call_quick: { - \exp_after:wN \__unravel_macro_call_quick_loop:NN \l__unravel_tmpa_tl + \exp_after:wN \__unravel_macro_call_quick_loop:NNN \l__unravel_tmpa_tl { ? \use_none_delimit_by_q_stop:w } \q_stop } -\cs_new_protected_nopar:Npn \__unravel_macro_call_quick_loop:NN #1#2 +\cs_new_protected:Npn \__unravel_macro_call_quick_loop:NNN #1#2#3 { \use_none:n #2 \__unravel_input_gpop_item:NF \l__unravel_tmpa_tl - { \msg_error:nn { unravel } { runaway-macro-parameter } } + { \__unravel_macro_call_quick_runaway:Nw #3 } \tl_put_right:Nx \l__unravel_head_tl { { \exp_not:V \l__unravel_tmpa_tl } } - \__unravel_macro_call_quick_loop:NN + \__unravel_macro_call_quick_loop:NNN + #3 + } +\cs_new_protected:Npn \__unravel_macro_call_quick_runaway:Nw #1#2 \q_stop + { + \msg_error:nnxx { unravel } { runaway-macro-parameter } + { \tl_to_str:N \l__unravel_head_tl } { \tl_to_str:n {#1} } } \cs_new_protected_nopar:Npn \__unravel_expand: { \__unravel_set_action_text: - \bool_if:NT \l__unravel_debug_bool + \bool_if:NT \g__unravel_internal_debug_bool { \__unravel_set_cmd: \iow_term:x { Exp:~\int_use:N \l__unravel_head_cmd_int } @@ -1527,7 +1615,7 @@ } { \msg_error:nn { unravel } { missing-font-id } - \__unravel_prev_input:n { \tex_nullfont:D } + \__unravel_prev_input:n { \__unravel_nullfont: } \__unravel_back_error: } } @@ -1573,7 +1661,7 @@ \__unravel_prev_input_silent:V \l__unravel_tmpa_tl \__unravel_set_action_text: \__unravel_set_action_text:x - { \g__unravel_action_text_str = ~ \tl_to_str:N \l__unravel_tmpa_tl } + { \g__unravel_action_text_str \use:n { ~ => ~ } \tl_to_str:N \l__unravel_tmpa_tl } \int_compare:nNnF {#3} > { 3 } { \__unravel_print_action: } \int_gset:Nn \g__unravel_val_level_int {#1} } @@ -1592,7 +1680,7 @@ { 76 } { 3 } % assign_mu_glue { 77 } { 1 \__unravel_scan_font_dimen: } % assign_font_dimen { 78 } { 0 \__unravel_scan_font_int: } % assign_font_int - { 79 } { 0 } % set_aux + { 79 } { \__unravel_thing_set_aux: } % set_aux { 80 } { 0 } % set_prev_graf { 81 } { 1 } % set_page_dimen { 82 } { 0 } % set_page_int @@ -1606,6 +1694,8 @@ } { 8 } } +\cs_new_nopar:Npn \__unravel_thing_set_aux: + { \int_compare:nNnTF \l__unravel_head_char_int = { 1 } { 1 } { 0 } } \cs_new_nopar:Npn \__unravel_thing_last_item: { \int_compare:nNnTF \l__unravel_head_char_int < { 26 } @@ -1669,7 +1759,7 @@ { 2 } \skip_eval:n { 3 } \muskip_eval:n } - { \tex_the:D } + { \__unravel_the:w } } \cs_new_protected:Npn \__unravel_scan_expr:N #1 { \__unravel_scan_expr_aux:NN #1 \c_false_bool } @@ -1760,16 +1850,9 @@ { \__unravel_scan_signs: \__unravel_set_cmd: - \int_compare:nNnTF - \l__unravel_head_cmd_int < { \__unravel_tex_use:n { min_internal } } + \__unravel_cmd_if_internal:TF + { \__unravel_scan_something_internal:n { 0 } } { \__unravel_scan_int_char: } - { - \int_compare:nNnTF - \l__unravel_head_cmd_int - > { \__unravel_tex_use:n { max_internal } } - { \__unravel_scan_int_char: } - { \__unravel_scan_something_internal:n { 0 } } - } } \cs_new_protected_nopar:Npn \__unravel_scan_int_char: { @@ -1825,50 +1908,43 @@ } } \cs_new_protected_nopar:Npn \__unravel_scan_normal_dimen: - { \__unravel_scan_dimen:NN \c_false_bool \c_false_bool } -\cs_new_protected:Npn \__unravel_scan_dimen:NN #1#2 + { \__unravel_scan_dimen:nN { 2 } \c_false_bool } +\cs_new_protected:Npn \__unravel_scan_dimen:nN #1#2 { \__unravel_scan_signs: \seq_gput_right:Nn \g__unravel_prev_input_seq { } \__unravel_set_cmd: - \int_compare:nNnTF - \l__unravel_head_cmd_int < { \__unravel_tex_use:n { min_internal } } - { \__unravel_scan_dimen_char:NN #1#2 } + \__unravel_cmd_if_internal:TF { - \int_compare:nNnTF - \l__unravel_head_cmd_int - > { \__unravel_tex_use:n { max_internal } } - { \__unravel_scan_dimen_char:NN #1#2 } + \int_compare:nNnTF {#1} = { 3 } { - \bool_if:NTF #1 + \__unravel_scan_something_internal:n { 3 } + \int_case:nnF \g__unravel_val_level_int { - \__unravel_scan_something_internal:n { 3 } - \int_case:nnF \g__unravel_val_level_int - { - { 0 } { \__unravel_scan_dim_unit:NN #1 #2 } - { 3 } { } - } - { - \msg_error:nn { unravel } { incompatible-units } - % ^^A todo: error recovery - } + { 0 } { \__unravel_scan_dim_unit:nN {#1} #2 } + { 3 } { } } { - \__unravel_scan_something_internal:n { 2 } - \int_case:nnF \g__unravel_val_level_int - { - { 0 } { \__unravel_scan_dim_unit:NN #1#2 } - { 3 } % ^^A todo: error recovery - { \msg_error:nn { unravel } { incompatible-units } } - } - { } + \msg_error:nn { unravel } { incompatible-units } + % ^^A todo: error recovery } } + { + \__unravel_scan_something_internal:n { 1 } + \int_case:nnF \g__unravel_val_level_int + { + { 0 } { \__unravel_scan_dim_unit:nN {#1} #2 } + { 3 } % ^^A todo: error recovery + { \msg_error:nn { unravel } { incompatible-units } } + } + { } + } } + { \__unravel_scan_dimen_char:nN {#1} #2 } \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl \__unravel_prev_input_silent:V \l__unravel_head_tl } -\cs_new_protected:Npn \__unravel_scan_dimen_char:NN #1#2 +\cs_new_protected:Npn \__unravel_scan_dimen_char:nN #1#2 { \tl_if_eq:NNT \l__unravel_head_tl \c__unravel_comma_tl { \tl_set_eq:NN \l__unravel_head_tl \c__unravel_point_tl } @@ -1896,9 +1972,9 @@ \__unravel_scan_int: } } - \__unravel_scan_dim_unit:NN #1#2 + \__unravel_scan_dim_unit:nN {#1} #2 } -\cs_new_protected:Npn \__unravel_scan_dim_unit:NN #1#2 +\cs_new_protected:Npn \__unravel_scan_dim_unit:nN #1#2 { \bool_if:NT #2 { @@ -1910,35 +1986,16 @@ } \__unravel_get_x_non_blank: \__unravel_set_cmd: - \int_compare:nNnTF - \l__unravel_head_cmd_int < { \__unravel_tex_use:n { min_internal } } - { \__unravel_back_input: } + \__unravel_cmd_if_internal:TF { - \int_compare:nNnTF - \l__unravel_head_cmd_int - > { \__unravel_tex_use:n { max_internal } } - { \__unravel_back_input: } - { - \seq_gput_right:Nn \g__unravel_prev_input_seq { } - \bool_if:NTF #1 - { \__unravel_scan_something_internal:n { 3 } } - { \__unravel_scan_something_internal:n { 2 } } - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_tmpa_tl - \tl_set:Nx \l__unravel_tmpa_tl - { - \bool_if:NTF #1 \muskip_eval:n \skip_eval:n - { - \l__unravel_tmpa_tl - \bool_if:NTF #1 \etex_muexpr:D \etex_glueexpr:D - \l__unravel_head_tl - } - } - \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_tmpa_tl - \__unravel_break:w - } + \seq_gput_right:Nn \g__unravel_prev_input_seq { } + \__unravel_scan_something_internal:n {#1} + \__unravel_prev_input_join_get:nN {#1} \l__unravel_tmpa_tl + \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_tmpa_tl + \__unravel_break:w } - \bool_if:NT #1 + { \__unravel_back_input: } + \int_compare:nNnT {#1} = { 3 } { \__unravel_scan_keyword:nT { mM uU } { \__unravel_break:w } \msg_error:nn { unravel } { missing-mudim } @@ -1985,47 +2042,34 @@ { \__unravel_scan_glue:n { 3 } } \cs_new_protected:Npn \__unravel_scan_glue:n #1 { - \int_compare:nNnTF {#1} = { 2 } - { \__unravel_scan_glue_aux:nN {#1} \c_false_bool } - { \__unravel_scan_glue_aux:nN {#1} \c_true_bool } - } -\cs_new_protected:Npn \__unravel_scan_glue_aux:nN #1#2 - { + \seq_gput_right:Nn \g__unravel_prev_input_seq { } \__unravel_scan_signs: \seq_gput_right:Nn \g__unravel_prev_input_seq { } \__unravel_set_cmd: - \int_compare:nNnTF - \l__unravel_head_cmd_int < { \__unravel_tex_use:n { min_internal } } - { \__unravel_back_input: \__unravel_scan_dimen:NN #2 \c_false_bool } + \__unravel_cmd_if_internal:TF { - \int_compare:nNnTF - \l__unravel_head_cmd_int - > { \__unravel_tex_use:n { max_internal } } + \__unravel_scan_something_internal:n {#1} + \int_case:nnF \g__unravel_val_level_int { - \__unravel_back_input: - \__unravel_scan_dimen:NN #2 \c_false_bool + { 0 } { \__unravel_scan_dimen:nN {#1} \c_false_bool } + {#1} { \__unravel_break:w } } { - \__unravel_scan_something_internal:n {#1} - \int_case:nnF \g__unravel_val_level_int - { - { 0 } { \__unravel_scan_dimen:NN #2 \c_false_bool } - { 1 } { \bool_if:NT #2 { \msg_error: } } % ^^A todo: ?? - } - { - \int_compare:nNnF \g__unravel_val_level_int = {#1} - { \msg_error:nn { unravel } { incompatible-units } } - \__unravel_break:w - } + \int_compare:nNnF { \g__unravel_val_level_int + #1 } = 3 + { \msg_error:nn { unravel } { incompatible-units } } } } + { \__unravel_back_input: \__unravel_scan_dimen:nN {#1} \c_false_bool } + \__unravel_prev_input_join_get:nN {#1} \l__unravel_tmpa_tl + \seq_gput_right:Nn \g__unravel_prev_input_seq { } + \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_tmpa_tl \__unravel_scan_keyword:nT { pP lL uU sS } - { \__unravel_scan_dimen:NN #2 \c_true_bool } + { \__unravel_scan_dimen:nN {#1} \c_true_bool } \__unravel_scan_keyword:nT { mM iI nN uU sS } - { \__unravel_scan_dimen:NN #2 \c_true_bool } + { \__unravel_scan_dimen:nN {#1} \c_true_bool } \__unravel_break_point: - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl - \__unravel_prev_input_silent:V \l__unravel_head_tl + \__unravel_prev_input_join_get:nN {#1} \l__unravel_tmpa_tl + \__unravel_prev_input_silent:V \l__unravel_tmpa_tl } \cs_new_protected_nopar:Npn \__unravel_scan_file_name: { @@ -2235,11 +2279,12 @@ { \bool_if:NTF #1 { - \__unravel_cs_case:NnF \l__unravel_head_token + \int_case:nnTF \l__unravel_head_cmd_int { - \tex_hrule:D { \__unravel_do_leaders_rule: } - \tex_vrule:D { \__unravel_do_leaders_rule: } + { \__unravel_tex_use:n { hrule } } { } + { \__unravel_tex_use:n { vrule } } { } } + { \__unravel_do_leaders_rule: } { \__unravel_do_box_error: } } { \__unravel_do_box_error: } @@ -2304,7 +2349,7 @@ } \cs_new_protected:Npn \__unravel_do_box_explicit:N #1 { - \token_if_eq_meaning:NNTF \l__unravel_head_token \tex_hbox:D + \token_if_eq_meaning:NNTF \l__unravel_head_token \__unravel_hbox:w { \__unravel_box_hook:N \tex_everyhbox:D } { \__unravel_box_hook:N \tex_everyvbox:D } % ^^A todo: TeX calls |normal_paragraph| here. @@ -2339,7 +2384,7 @@ \__unravel_print_action: \__unravel_back_input:o {##1} \__unravel_set_action_text:x - { \token_to_meaning:N #1 \tl_to_str:o {##1} } + { \token_to_meaning:N #1 = \tl_to_str:o {##1} } \tl_if_empty:oF {##1} { \__unravel_print_action: } } } @@ -2363,42 +2408,29 @@ { \prg_return_true: } { \prg_return_false: } } -\group_begin: - \char_set_catcode_other:n { 0 } - \cs_new_protected:Npn \__unravel_char:n #1 - { - \tex_char:D #1 \scan_stop: - \__unravel_charcode_if_safe:nTF {#1} - { - \group_begin: - \char_set_lccode:nn { 0 } {#1} - \tex_lowercase:D - { \group_end: \tl_set:Nn \l__unravel_tmpa_tl { ^^@ } } - } - { - \tl_set:Nx \l__unravel_tmpa_tl - { \exp_not:N \char \int_eval:n {#1} ~ } - } - \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_tmpa_tl - \__unravel_print_action:x { \tl_to_str:N \l__unravel_tmpa_tl } - } -\group_end: +\cs_new_protected:Npn \__unravel_char:n #1 + { + \tex_char:D #1 \scan_stop: + \__unravel_charcode_if_safe:nTF {#1} + { \tl_set:Nx \l__unravel_tmpa_tl { \char_generate:nn {#1} { 12 } } } + { + \tl_set:Nx \l__unravel_tmpa_tl + { \exp_not:N \char \int_eval:n {#1} ~ } + } + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_tmpa_tl + \__unravel_print_action:x { \tl_to_str:N \l__unravel_tmpa_tl } + } \cs_generate_variant:Nn \__unravel_char:n { V , x } -\group_begin: - \char_set_catcode_other:n { 0 } - \cs_new_protected:Npn \__unravel_char_in_mmode:n #1 - { - \int_compare:nNnTF { \tex_mathcode:D #1 } = { "8000 } - { % math active - \group_begin: - \char_set_lccode:nn { 0 } { \l__unravel_tmpa_tl } - \tex_lowercase:D - { \group_end: \gtl_set:Nn \l__unravel_head_gtl { ^^@ } } - \__unravel_back_input: - } - { \__unravel_char:n {#1} } - } -\group_end: +\cs_new_protected:Npn \__unravel_char_in_mmode:n #1 + { + \int_compare:nNnTF { \tex_mathcode:D #1 } = { "8000 } + { % math active + \gtl_set:Nx \l__unravel_head_gtl + { \char_generate:nn {#1} { 12 } } + \__unravel_back_input: + } + { \__unravel_char:n {#1} } + } \cs_generate_variant:Nn \__unravel_char_in_mmode:n { V , x } \cs_new_protected:Npn \__unravel_mathchar:n #1 { @@ -2411,10 +2443,10 @@ \cs_generate_variant:Nn \__unravel_mathchar:n { x } \cs_new_protected:Npn \__unravel_new_graf:N #1 { - \tl_set:NV \l__unravel_tmpa_tl \tex_everypar:D - \tex_everypar:D { } + \tl_set:NV \l__unravel_tmpa_tl \__unravel_everypar:w + \__unravel_everypar:w { } \bool_if:NTF #1 { \tex_indent:D } { \tex_noindent:D } - \exp_args:NV \tex_everypar:D \l__unravel_tmpa_tl + \exp_args:NV \__unravel_everypar:w \l__unravel_tmpa_tl \__unravel_back_input:V \l__unravel_tmpa_tl \__unravel_print_action:x { @@ -2435,7 +2467,7 @@ } \cs_new_protected_nopar:Npn \__unravel_handle_left_brace: { - \int_case:nnF \etex_currentgrouptype:D + \int_case:nnF \__unravel_currentgrouptype: { { 1 } { \__unravel_end_simple_group: } % simple { 2 } { \__unravel_end_box_group: } % hbox @@ -2445,7 +2477,7 @@ { 6 } { \__unravel_end_align_group: } % align { 7 } { \__unravel_end_no_align_group: } % no_align { 8 } { \__unravel_end_output_group: } % output - { 9 } { \__unravel_end_math_group: } % math + { 9 } { \__unravel_end_simple_group: } % math { 10 } { \__unravel_end_disc_group: } % disc { 11 } { \__unravel_end_graf: \__unravel_end_simple_group: } % insert { 12 } { \__unravel_end_graf: \__unravel_end_simple_group: } % vcenter @@ -2487,14 +2519,14 @@ } \cs_new_protected_nopar:Npn \__unravel_off_save: { - \int_compare:nNnTF \etex_currentgrouptype:D = { 0 } + \int_compare:nNnTF \__unravel_currentgrouptype: = { 0 } { % bottom-level \msg_error:nnx { unravel } { extra-close } { \token_to_meaning:N \l__unravel_head_token } } { \__unravel_back_input: - \int_case:nnF \etex_currentgrouptype:D + \int_case:nnF \__unravel_currentgrouptype: { { 14 } % semi_simple_group { \gtl_set:Nn \l__unravel_head_gtl { \group_end: } } @@ -2542,10 +2574,44 @@ \__unravel_back_input: } } +\cs_new_protected_nopar:Npn \__unravel_goto_inner_math: + { + \__unravel_box_hook:N \tex_everymath:D + $ % $ + \__unravel_box_hook_end: + } +\cs_new_protected_nopar:Npn \__unravel_goto_display_math: + { + \__unravel_box_hook:N \tex_everydisplay:D + $ $ + \__unravel_box_hook_end: + } +\cs_new_protected_nopar:Npn \__unravel_after_math: + { + \mode_if_inner:TF + { + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl + $ % $ + } + { + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl + \__unravel_get_x_next: + \token_if_eq_catcode:NNF + \l__unravel_head_token \c_math_toggle_token + { + \__unravel_back_input: + \tl_set:Nn \l__unravel_head_tl { $ } % $ + \msg_error:nn { unravel } { missing-dollar } + } + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl + $ $ + } + \__unravel_print_action: + } \cs_new_protected_nopar:Npn \__unravel_do_step: { \__unravel_set_action_text: - \bool_if:NT \l__unravel_debug_bool + \bool_if:NT \g__unravel_internal_debug_bool { \iow_term:x { Cmd:~\int_use:N \l__unravel_head_cmd_int } } \cs_if_exist_use:cF { __unravel_cmd_ \int_use:N \l__unravel_head_cmd_int : } @@ -2569,18 +2635,23 @@ \mode_if_math:TF { \int_compare:nNnTF - \etex_currentgrouplevel:D = { 15 } % math_shift_group + \__unravel_currentgrouptype: = { 15 } % math_shift_group { \__unravel_after_math: } { \__unravel_off_save: } } { + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl \__unravel_get_next: \token_if_eq_catcode:NNTF \l__unravel_head_token \c_math_toggle_token { \mode_if_inner:TF { \__unravel_back_input: \__unravel_goto_inner_math: } - { \__unravel_goto_display_math: } + { + \gtl_gput_right:NV + \g__unravel_output_gtl \l__unravel_head_tl + \__unravel_goto_display_math: + } } { \__unravel_back_input: \__unravel_goto_inner_math: } } @@ -2600,10 +2671,45 @@ { \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_head_tl \__unravel_print_action: - \__unravel_scan_math: - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl - \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl - \tl_use:N \l__unravel_head_tl \scan_stop: + \__unravel_get_x_non_relax: + \__unravel_set_cmd: + \int_case:nnTF \l__unravel_head_cmd_int + { + { \__unravel_tex_use:n { the_char } } + { \__unravel_prev_input:V \l__unravel_head_tl } + { \__unravel_tex_use:n { other_char } } + { \__unravel_prev_input:V \l__unravel_head_tl } + { \__unravel_tex_use:n { char_given } } + { \__unravel_prev_input:V \l__unravel_head_tl } + { \__unravel_tex_use:n { char_num } } + { + \__unravel_prev_input:V \l__unravel_head_tl + \__unravel_scan_int: + } + { \__unravel_tex_use:n { math_char_num } } + { + \__unravel_prev_input:V \l__unravel_head_tl + \__unravel_scan_int: + } + { \__unravel_tex_use:n { math_given } } + { \__unravel_prev_input:V \l__unravel_head_tl } + { \__unravel_tex_use:n { delim_num } } + { \__unravel_prev_input:V \l__unravel_head_tl \__unravel_scan_int: } + } + { + \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl + \tl_use:N \l__unravel_head_tl \scan_stop: + } + { + \__unravel_back_input: + \__unravel_scan_left_brace: + \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl + \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl + \gtl_gconcat:NNN \g__unravel_output_gtl + \g__unravel_output_gtl \c_group_begin_gtl + \tl_use:N \l__unravel_head_tl \c_group_begin_token + } \__unravel_print_action:x { \tl_to_str:N \l__unravel_head_tl } } \__unravel_new_tex_cmd:nn { endv } % 9 @@ -2657,7 +2763,7 @@ \__unravel_back_input: \__unravel_back_input:n { - \tex_hbox:D to \tex_hsize:D { } + \__unravel_hbox:w to \tex_hsize:D { } \tex_vfill:D \tex_penalty:D - '10000000000 ~ } @@ -2823,8 +2929,8 @@ \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_head_tl \__unravel_print_action: \token_if_eq_meaning:NNTF \l__unravel_head_token \tex_kern:D - { \__unravel_scan_dimen:NN \c_true_bool \c_false_bool } - { \__unravel_scan_dimen:NN \c_false_bool \c_false_bool } + { \__unravel_scan_dimen:nN { 2 } \c_false_bool } + { \__unravel_scan_dimen:nN { 3 } \c_false_bool } \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl \tl_use:N \l__unravel_head_tl \scan_stop: \__unravel_print_action:x { \tl_to_str:N \l__unravel_head_tl } @@ -2908,7 +3014,7 @@ { \int_compare:nNnT \l__unravel_head_char_int = { 1 } % indent { - \tex_hbox:D width \tex_parindent:D { } + \__unravel_hbox:w width \tex_parindent:D { } \gtl_gput_right:NV \g__unravel_output_gtl \l__unravel_head_tl } \__unravel_print_action: @@ -3563,7 +3669,7 @@ { \__unravel_scan_font_int: } { \__unravel_scan_int: } } \__unravel_prefixed_new:nn { set_aux } % 79 - { % prevdepth = 1, spacefactor = 0 + { % prevdepth = 1, spacefactor = 102 \int_compare:nNnTF \l__unravel_head_char_int = \c_one { \__unravel_assign_value:nn { } { \__unravel_scan_normal_dimen: } } { \__unravel_assign_value:nn { } { \__unravel_scan_int: } } @@ -3737,25 +3843,34 @@ \__unravel_prefixed_new:nn { set_interaction } % 100 { \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_tmpa_tl - \tl_put_right:NV \l__unravel_head_tl \l__unravel_tmpa_tl + \tl_put_left:NV \l__unravel_head_tl \l__unravel_tmpa_tl \tl_use:N \l__unravel_head_tl \scan_stop: \__unravel_print_action:x { \tl_to_str:N \l__unravel_head_tl } } \__unravel_prefixed_new:nn { letterspace_font } % 101 { - % ^^A todo... - % new_letterspaced_font(a); - \msg_error:nnx { unravel } { not-implemented } { letterspace-font } - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl - \__unravel_omit_after_assignment:w + \__unravel_prev_input_silent:V \l__unravel_head_tl + \__unravel_set_action_text:x { \tl_to_str:N \l__unravel_head_tl } + \__unravel_scan_r_token: + \__unravel_print_action:x + { \g__unravel_action_text_str \tl_to_str:N \l__unravel_defined_tl } + \exp_after:wN \cs_set_eq:NN \l__unravel_defined_tl \__unravel_nullfont: + \__unravel_scan_optional_equals: + \__unravel_scan_font_ident: + \__unravel_scan_int: + \__unravel_assign_token:n { } } \__unravel_prefixed_new:nn { pdf_copy_font } % 102 { - % ^^A todo... - % make_font_copy(a); - \msg_error:nnx { unravel } { not-implemented } { pdf-copy-font } - \seq_gpop_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl - \__unravel_omit_after_assignment:w + \__unravel_prev_input_silent:V \l__unravel_head_tl + \__unravel_set_action_text:x { \tl_to_str:N \l__unravel_head_tl } + \__unravel_scan_r_token: + \__unravel_print_action:x + { \g__unravel_action_text_str \tl_to_str:N \l__unravel_defined_tl } + \exp_after:wN \cs_set_eq:NN \l__unravel_defined_tl \__unravel_nullfont: + \__unravel_scan_optional_equals: + \__unravel_scan_font_ident: + \__unravel_assign_token:n { } } \__unravel_prefixed_new:nn { register } % 89 { \__unravel_do_register:N \c_zero } @@ -3938,7 +4053,7 @@ { \int_case:nnF \l__unravel_head_char_int { - { 1 } { \__unravel_print_action: } % \endinput + { 1 } { \__unravel_endinput: } % \endinput { 2 } { \__unravel_scantokens: } % \scantokens } { % 0=\input @@ -3946,6 +4061,11 @@ { \__unravel_insert_relax: } { \__unravel_input: } } } +\cs_new_protected_nopar:Npn \__unravel_endinput: + { + \msg_warning:nn { unravel } { endinput-ignored } + \__unravel_print_action: + } \cs_new_protected_nopar:Npn \__unravel_scantokens: { \seq_gput_right:Nn \g__unravel_prev_input_seq { } @@ -4142,7 +4262,7 @@ \fi: \int_incr:N \l__unravel_if_nesting_int \fi: - \__unravel_input_gpop:N \l__unravel_tmpa_gtl + \__unravel_input_gpop:N \l__unravel_unused_gtl \int_compare:nNnTF \l__unravel_if_nesting_int = \c_zero { \__unravel_pass_text: } { \__unravel_pass_text_nested: } @@ -4334,7 +4454,7 @@ { \seq_gput_right:NV \g__unravel_prev_input_seq \l__unravel_head_tl \__unravel_print_action: - \bool_if:NT \l__unravel_debug_bool { \iow_term:n { {\ifcase level~#1} } } + \bool_if:NT \g__unravel_internal_debug_bool { \iow_term:n { {\ifcase level~#1} } } \__unravel_scan_int: \seq_get_right:NN \g__unravel_prev_input_seq \l__unravel_head_tl \tl_set:Nx \l__unravel_head_tl { \tl_tail:N \l__unravel_head_tl } @@ -4433,7 +4553,7 @@ \cs_new_protected:Npn \__unravel_set_action_text:x #1 { \group_begin: - \int_set:Nn \tex_escapechar:D { 92 } + \__unravel_set_escapechar:n { 92 } \str_gset:Nx \g__unravel_action_text_str {#1} \group_end: } @@ -4449,7 +4569,8 @@ \cs_new_protected:Npn \__unravel_print_state: { \group_begin: - \int_set:Nn \tex_escapechar:D { 92 } + \__unravel_set_escapechar:n { 92 } + \tl_use:N \g__unravel_before_print_state_tl \int_compare:nNnT \g__unravel_noise_int > \c_zero { \exp_args:Nx \__unravel_print_state_output:n @@ -4469,66 +4590,16 @@ { \tl_if_empty:nF {#1} { - \int_set:Nn \l__unravel_print_int { \str_count:n {#1} } \__unravel_print_message:nn { <| ~ } - { - \int_compare:nNnTF - \l__unravel_print_int > \g__unravel_max_output_int - { - ( - \int_eval:n - { - \l__unravel_print_int - - \g__unravel_max_output_int + 14 - } ~ - chars - )~ - ... - \str_substr:nnn {#1} - { \l__unravel_print_int - \g__unravel_max_output_int + 15 } - { \l__unravel_print_int } - } - {#1} - } + { \__unravel_str_truncate_left:nn {#1} { \g__unravel_max_output_int } } } } \cs_new_protected:Npn \__unravel_print_state_prev:n #1 - { - % \int_set:Nn \l__unravel_print_int { \str_count:n {#1} } - \__unravel_print_message:nn { || ~ } {#1} - % { - % \int_compare:nNnTF \l__unravel_print_int > \g__unravel_max_prev_int - % { - % ( - % \int_eval:n - % { \l__unravel_print_int - \g__unravel_max_prev_int + 14 } ~ - % chars - % )~ - % ... - % \str_substr:nnn {#1} - % { \l__unravel_print_int - \g__unravel_max_prev_int + 15 } - % { \l__unravel_print_int } - % } - % {#1} - % } - } + { \__unravel_print_message:nn { || ~ } {#1} } \cs_new_protected:Npn \__unravel_print_state_input:n #1 { - \int_set:Nn \l__unravel_print_int { \str_count:n {#1} } \__unravel_print_message:nn { |> ~ } - { - \int_compare:nNnTF \l__unravel_print_int > \g__unravel_max_input_int - { - \str_substr:nnn {#1} { 1 } { \g__unravel_max_input_int - 14 } - ...~ - ( - \int_eval:n - { \l__unravel_print_int - \g__unravel_max_input_int + 14 } ~ - chars - ) - } - {#1} - } + { \__unravel_str_truncate_right:nn {#1} { \g__unravel_max_input_int } } } \cs_new_protected:Npn \__unravel_print_meaning: { @@ -4546,21 +4617,20 @@ \cs_new_protected:Npn \__unravel_print_action: { \int_gincr:N \g__unravel_step_int - \__unravel_print_message:nn { } + \__unravel_print:x { - % \\ - [=====~ Step~ \int_use:N \g__unravel_step_int \ =====]~ + [===== + \bool_if:NT \g__unravel_number_steps_bool + { ~ Step ~ \int_use:N \g__unravel_step_int \ } + =====]~ \int_compare:nNnTF { \str_count:N \g__unravel_action_text_str } > { \g__unravel_max_action_int } { - \str_substr:Nnn \g__unravel_action_text_str + \str_range:Nnn \g__unravel_action_text_str { 1 } { \g__unravel_max_action_int - 3 } ... } { \g__unravel_action_text_str } - % \\ - % \ \ < \int_use:N \g__unravel_input_int > % ^^A todo: remove - % \ < \seq_count:N \g__unravel_prev_input_seq > % ^^A todo: remove } \__unravel_print_state: } @@ -4592,7 +4662,7 @@ Set~ \exp_after:wN \token_to_str:N \l__unravel_defined_tl \tl_if_single:NT \l__unravel_defined_tl { ( \exp_after:wN \token_to_meaning:N \l__unravel_defined_tl ) } - = \exp_after:wN \tex_the:D \l__unravel_defined_tl + = \exp_after:wN \__unravel_the:w \l__unravel_defined_tl } \__unravel_omit_after_assignment:w } @@ -4600,44 +4670,47 @@ { \__unravel_print_message:nn { } { - \\ - ========~ Welcome~ to~ the~ unravel~ package~ ========\\ - \iow_indent:n + \bool_if:NTF \g__unravel_welcome_message_bool { - "<|"~ denotes~ the~ output~ to~ TeX's~ stomach. \\ - "||"~ denotes~ tokens~ waiting~ to~ be~ used. \\ - "|>"~ denotes~ tokens~ that~ we~ will~ act~ on. \\ - Press~<enter>~to~continue;~'h'~<enter>~for~help. \\ + \\ + ========~ Welcome~ to~ the~ unravel~ package~ ========\\ + \iow_indent:n + { + "<|"~ denotes~ the~ output~ to~ TeX's~ stomach. \\ + "||"~ denotes~ tokens~ waiting~ to~ be~ used. \\ + "|>"~ denotes~ tokens~ that~ we~ will~ act~ on. \\ + Press~<enter>~to~continue;~'h'~<enter>~for~help. \\ + } } + { [=====~Start~=====] } } \__unravel_print_state: } \cs_new_protected_nopar:Npn \__unravel_print_outcome: - { - % \int_gset_eq:NN \g__unravel_max_input_int \c_max_int - % \int_gset_eq:NN \g__unravel_max_prev_int \c_max_int - % \int_gset_eq:NN \g__unravel_max_output_int \c_max_int - % \__unravel_print_state: - \__unravel_print_message:nn { } { [=====~The~end!~=====] \\ } - } + { \__unravel_print:n { [=====~End~=====] } } \cs_new_protected_nopar:Npn \__unravel_prompt: { \int_gdecr:N \g__unravel_nonstop_int \int_compare:nNnF \g__unravel_nonstop_int > \c_zero { \group_begin: - \int_set_eq:NN \tex_escapechar:D \c_minus_one + \__unravel_set_escapechar:n { -1 } \int_set_eq:NN \tex_endlinechar:D \c_minus_one - \tl_use:N \g__unravel_prompt_before_tl - \tl_gclear:N \g__unravel_prompt_before_tl + \tl_use:N \g__unravel_before_prompt_tl \__unravel_prompt_aux: \group_end: } } \cs_new_protected_nopar:Npn \__unravel_prompt_aux: { - \ior_get_str:Nc \g__unravel_prompt_ior { Your~input } - \exp_args:Nv \__unravel_prompt_treat:n { Your~input } + \int_compare:nNnT { \etex_interactionmode:D } = { 3 } + { + \bool_if:NTF \g__unravel_explicit_prompt_bool + { \ior_get_str:Nc \c__unravel_prompt_ior } + { \ior_get_str:Nc \c__unravel_noprompt_ior } + { Your~input } + \exp_args:Nv \__unravel_prompt_treat:n { Your~input } + } } \cs_new_protected:Npn \__unravel_prompt_treat:n #1 { @@ -4669,6 +4742,9 @@ { \tl_gclear:N \g__unravel_tmpc_tl } \group_insert_after:N \g__unravel_tmpc_tl } + { | } { \__unravel_prompt_scan_int:nn {#1} + \__unravel_prompt_vert:n } + { a } { \__unravel_prompt_all: } } { \__unravel_prompt_help: } } @@ -4676,7 +4752,9 @@ \cs_new_protected:Npn \__unravel_prompt_scan_int:nn #1 { \tex_afterassignment:D \__unravel_prompt_scan_int_after:wn - \l__unravel_prompt_tmpa_int = 0 \use_none:n #1 \scan_stop: + \l__unravel_prompt_tmpa_int = + \tl_if_head_eq_charcode:fNF { \use_none:n #1 } - { 0 } + \use_ii:nn #1 \scan_stop: } \cs_new_protected:Npn \__unravel_prompt_scan_int_after:wn #1 \scan_stop: #2 { @@ -4686,44 +4764,159 @@ \cs_new_protected:Npn \__unravel_prompt_help: { \__unravel_print:n { "m":~meaning~of~first~token } - \__unravel_print:n { "q":~semi-quiet } - \__unravel_print:n { "x":~exit~this~instance~of~unravel } - \__unravel_print:n { "X":~try~harder~to~exit } + \__unravel_print:n { "q":~semi-quiet~(same~as~"o1") } + \__unravel_print:n { "x"/"X":~exit~this~instance~of~unravel/TeX } \__unravel_print:n { "s<num>":~do~<num>~steps~silently } \__unravel_print:n - { "o<num>":~0~=>~only~log~not~online,~1~=>~both,~-1~=>~neither.} - \__unravel_print:n { "C<code>":~run~some~code~immediately } + { "o<num>":~1~=>~log~and~terminal,~0~=>~only~log,~-1~=>~neither.} + \__unravel_print:n { "C<code>":~run~some~expl3~code~immediately } + \__unravel_print:n { "|<num>":~silent~steps~until~<num>~fewer~"||" } + \__unravel_print:n { "a":~print~state~again,~without~truncating } \__unravel_prompt_aux: } \cs_new_protected:Npn \__unravel_prompt_silent_steps:n #1 { + \int_compare:nNnF {#1} < \c_zero + { + \int_gset_eq:NN \g__unravel_noise_int \c_minus_one + \tl_gset:Nn \g__unravel_before_prompt_tl + { + \int_gset_eq:NN \g__unravel_noise_int \c_one + \tl_gclear:N \g__unravel_before_prompt_tl + } + \int_gset:Nn \g__unravel_nonstop_int {#1} + } + } +\cs_new_protected:Npn \__unravel_prompt_vert:n #1 + { + \int_compare:nNnTF {#1} < { 0 } + { \__unravel_prompt_vert:Nn > {#1} } + { \__unravel_prompt_vert:Nn < {#1} } + } +\cs_new_protected:Npn \__unravel_prompt_vert:Nn #1#2 + { \int_gset_eq:NN \g__unravel_noise_int \c_minus_one - \tl_gset:Nn \g__unravel_prompt_before_tl - { \int_gset_eq:NN \g__unravel_noise_int \c_one } - \int_gset:Nn \g__unravel_nonstop_int {#1} + \tl_gset:Nf \g__unravel_before_print_state_tl + { + \exp_args:NNf \exp_stop_f: \int_compare:nNnTF + { \int_eval:n { \seq_count:N \g__unravel_prev_input_seq - #2 } } + #1 { \seq_count:N \g__unravel_prev_input_seq } + { + \int_gset:Nn \g__unravel_nonstop_int + { \int_max:nn { \g__unravel_nonstop_int } { 2 } } + } + { + \int_gset_eq:NN \g__unravel_noise_int \c_one + \tl_gclear:N \g__unravel_before_print_state_tl + } + } } -\cs_new_protected:Npn \unravel #1 { \__unravel_unravel:n {#1} } -\cs_new_protected_nopar:Npn \UnravelDebug +\cs_new_protected_nopar:Npn \__unravel_prompt_all: { - \bool_set_true:N \l__unravel_debug_bool + \tl_gset:Nx \g__unravel_tmpc_tl + { + \exp_not:n + { + \tl_gclear:N \g__unravel_tmpc_tl + \int_gset_eq:NN \g__unravel_max_output_int \c_max_int + \int_gset_eq:NN \g__unravel_max_input_int \c_max_int + \__unravel_print_state: + } + \__unravel_prompt_all_aux:N \g__unravel_max_output_int + \__unravel_prompt_all_aux:N \g__unravel_max_input_int + } + \group_insert_after:N \g__unravel_tmpc_tl } -\cs_new_protected:Npn \__unravel_unravel:n #1 +\cs_new:Npn \__unravel_prompt_all_aux:N #1 + { \exp_not:n { \int_gset:Nn #1 } { \int_use:N #1 } } +\keys_define:nn { unravel/defaults } + { + explicit-prompt .bool_gset:N = \g__unravel_default_explicit_prompt_bool , + internal-debug .bool_gset:N = \g__unravel_default_internal_debug_bool , + max-action .int_gset:N = \g__unravel_default_max_action_int , + max-output .int_gset:N = \g__unravel_default_max_output_int , + max-input .int_gset:N = \g__unravel_default_max_input_int , + number-steps .bool_gset:N = \g__unravel_default_number_steps_bool , + welcome-message .bool_gset:N = \g__unravel_default_welcome_message_bool , + } +\keys_define:nn { unravel } + { + explicit-prompt .bool_gset:N = \g__unravel_explicit_prompt_bool , + internal-debug .bool_gset:N = \g__unravel_internal_debug_bool , + max-action .int_gset:N = \g__unravel_max_action_int , + max-output .int_gset:N = \g__unravel_max_output_int , + max-input .int_gset:N = \g__unravel_max_input_int , + number-steps .bool_gset:N = \g__unravel_number_steps_bool , + welcome-message .bool_gset:N = \g__unravel_welcome_message_bool , + } +\tl_map_inline:nn { { /defaults } { } } + { + \keys_define:nn { unravel #1 } + { + machine .meta:nn = + { unravel #1 } + { + explicit-prompt = false , + internal-debug = false , + max-action = \c_max_int , + max-output = \c_max_int , + max-input = \c_max_int , + number-steps = false , + welcome-message = false , + } , + } + } +\NewDocumentCommand \unravel { O { } m } { \unravel:nn {#1} {#2} } +\NewDocumentCommand \unravelsetup { m } { \unravel_setup:n {#1} } +\cs_new_protected:Npn \unravel_setup:n #1 + { + \keys_set:nn { unravel/defaults } {#1} + \keys_set:nn { unravel } {#1} + } +\cs_new_protected:Npn \unravel:nn #1#2 + { + \__unravel_init_key_vars: + \keys_set:nn { unravel } {#1} + \__unravel_init_vars: + \__unravel_input_gset:n {#2} + \__unravel_print_welcome: + \__unravel_main_loop: + \__unravel_exit_point: + \__unravel_print_outcome: + \__unravel_final_test: + \__unravel_exit_point: + } +\cs_new_protected_nopar:Npn \__unravel_init_key_vars: + { + \bool_gset_eq:NN \g__unravel_explicit_prompt_bool \g__unravel_default_explicit_prompt_bool + \bool_gset_eq:NN \g__unravel_internal_debug_bool \g__unravel_default_internal_debug_bool + \bool_gset_eq:NN \g__unravel_number_steps_bool \g__unravel_default_number_steps_bool + \bool_gset_eq:NN \g__unravel_welcome_message_bool \g__unravel_default_welcome_message_bool + \int_gset_eq:NN \g__unravel_max_action_int \g__unravel_default_max_action_int + \int_gset_eq:NN \g__unravel_max_output_int \g__unravel_default_max_output_int + \int_gset_eq:NN \g__unravel_max_input_int \g__unravel_default_max_input_int + } +\cs_new_protected_nopar:Npn \__unravel_init_vars: { - \int_gzero:N \g__unravel_step_int - \__unravel_input_gset:n {#1} \seq_gclear:N \g__unravel_prev_input_seq \gtl_gclear:N \g__unravel_output_gtl + \int_gzero:N \g__unravel_step_int \tl_gclear:N \g__unravel_if_limit_tl \int_gzero:N \g__unravel_if_limit_int \int_gzero:N \g__unravel_if_depth_int \gtl_gclear:N \g__unravel_after_assignment_gtl \bool_gset_true:N \g__unravel_set_box_allowed_bool \bool_gset_false:N \g__unravel_name_in_progress_bool - \cs_gset_eq:NN \g__unravel_prompt_ior \c_minus_one % ^^A todo:? - \__unravel_print_welcome: + } +\cs_new_protected_nopar:Npn \__unravel_main_loop: + { + \__unravel_get_x_next: + \__unravel_set_cmd: + \__unravel_do_step: \__unravel_main_loop: - \__unravel_exit_point: - \__unravel_print_outcome: + } +\cs_new_protected_nopar:Npn \__unravel_final_test: + { \bool_if:nTF { \tl_if_empty_p:N \g__unravel_if_limit_tl @@ -4731,22 +4924,14 @@ && \int_compare_p:nNn \g__unravel_if_depth_int = \c_zero && \seq_if_empty_p:N \g__unravel_prev_input_seq } - { \__unravel_input_if_empty:TF { } { \__unravel_bad_finish: } } - { \__unravel_bad_finish: } - \__unravel_exit_point: + { \__unravel_input_if_empty:TF { } { \__unravel_final_bad: } } + { \__unravel_final_bad: } } -\cs_new_protected_nopar:Npn \__unravel_bad_finish: +\cs_new_protected_nopar:Npn \__unravel_final_bad: { \msg_error:nnx { unravel } { internal } { the-last-unravel-finished-badly } } -\cs_new_protected_nopar:Npn \__unravel_main_loop: - { - \__unravel_get_x_next: - \__unravel_set_cmd: - \__unravel_do_step: - \__unravel_main_loop: - } \msg_new:nnn { unravel } { unknown-primitive } { Internal~error:~the~primitive~'#1'~is~not~known. } \msg_new:nnn { unravel } { extra-fi-or-else } @@ -4804,14 +4989,21 @@ { Missing~\iow_char:N\\endcsname~inserted. } \msg_new:nnn { unravel } { runaway-if } { Runaway~\iow_char:N\\if... } +\msg_new:nnn { unravel } { runaway-macro-parameter } + { + Runaway~macro~parameter~\# #2~after \\\\ + \iow_indent:n {#1} + } \msg_new:nnn { unravel } { extra-or } { Extra~\iow_char:N\\or. } \msg_new:nnn { unravel } { missing-equals } { Missing~equals~for~\iow_char:N\\ifnum~or~\iow_char:N\\ifdim. } \msg_new:nnn { unravel } { internal } - { Internal~error:~'#1'.~\ Please report. } + { Internal~error:~'#1'.~\ Please~report. } \msg_new:nnn { unravel } { not-implemented } { The~following~feature~is~not~implemented:~'#1'. } +\msg_new:nnn { unravel } { endinput-ignored } + { The~primitive~\iow_char:N\\endinput~was~ignored. } %% %% %% End of file `unravel.sty'. |