% \iffalse
%% File: l3chk.dtx Copyright (C) 1990-1998 LaTeX3 project
%
%<*dtx>
          \ProvidesFile{l3chk.dtx}
%</dtx>
%<package>\NeedsTeXFormat{LaTeX2e}
%<package>\ProvidesPackage{l3chk}
%<driver> \ProvidesFile{l3chk.drv}
% \fi
%         \ProvidesFile{l3chk.dtx}
          [1998/04/20 v1.0e L3 Experimental check module]
%
% \iffalse
%<*driver>
\documentclass{l3doc}

\begin{document}
\DocInput{l3chk.dtx}
\end{document}
%</driver>
% \fi
%
% \GetFileInfo{l3chk.dtx}
% \title{The \textsf{l3chk} package\thanks{This file
%         has version number \fileversion, last
%         revised \filedate.}\\
% Checking things\ldots}
% \author{\Team}
% \date{\filedate}
% \maketitle
%
% \section{The chk module}
%
% To ensure that functions and variables are properly used certain
% checking functions are implemented that may or may not be compiled
% into the final format.
% 
% \subsection{Functions}
% 
% \begin{function}{%
%                  \chk_var_or_const:N |
% }
% \begin{syntax}
%   "\chk_var_or_const:N" <cs>
% \end{syntax}
% Checks that <cs> is a proper variable or constant which means that its
% name starts out with "\L", "\l", "\G", "\g", "\R", "\C", "\c", or "\q".
% \end{function}
% 
% \begin{function}{%
%                  \chk_local:N |
%                  \chk_global:N |
% }
% \begin{syntax}
%   "\chk_local:N" <cs>
% \end{syntax}
% Checks that <cs> is a proper local or global variable. This means that
% its name starts out with "\L", "\l", or "\G", "\g" respectively.
% \end{function}
% 
% \begin{function}{%
%                  \chk_local_or_pref_global:N |
%                  \pref_global_chk: |
% }
% To allow implementations where we precede some function with
% "\pref_global:D" without loosing the possibility to check for the
% correct variable type the following helper functions can be used:
% "\chk_local_or_pref_global:N" <cs> is the variable check which is
% usually let to "\chk_local:N", i.e.\ it will check that its argument
% is a local variable. This behavior will be changed by
% "\pref_global_chk:".  This function first changes
% "\chk_local_or_pref_global:N" to check for global variables then it
% issues a "\pref_global:D". After use "\chk_local_or_pref_global:N"
% will restore itself to "\chk_local:N".  So, if we use
% "\chk_local_or_pref_global:N" inside some function "\foo_bar:n" we can
% implement a global version "\foo_gbar:n" by defining
% \begin{quote}
%    "\def_new:Npn \foo_gbar:n {\pref_global_chk: \foo_bar:n }"
% \end{quote}
% provided that "\foo_bar:n" is built in a way that prefixing it with
% "\pref_global:D" turns its operation into a global one. See
% implementation for details.
% \end{function}
% 
% \subsection{Constants}
% 
% \begin{variable}{\c_undefined}
% This constant is always undefined and therefore can be used to check
% for free function names.
% \end{variable}
% 
% \subsection{Internal functions}
% 
% \begin{function}{%
%                  \chk_global_aux:w |
%                  \chk_local_aux:w |
%                  \chk_var_or_const_aux:w |
% }
% Helper functions that implement the checking.
% \end{function}
%
% \StopEventually{}
%
%    \section{The code}
%
%    We start by ensuring that the required packages are loaded.
%    \begin{macrocode}
%<package>\RequirePackage{l3basics}
%<package>\RequirePackage{l3int}
%<*package>
%    \end{macrocode}
%
% The |\chk| module contains those functions that are used primarily
% during the development of \LaTeX3 for checking that things are not mixed up
% too badly.  All these functions are of type `{\tt e}' since they
% issue error messages if certain conditions are violated.
%
% \subsection{Checking variable assignments}
%
% \begin{macro}{\chk_local:N}
% \begin{macro}{\chk_local_aux:w}
%    This function checks that its argument is a proper local
%    variable, i.e.\ its name starts with |\l| or |\L|. 
%    It is not allowed that the name starts with |\g| or |\G|,
%    which means that we do not allow to update global
%    variables locally. But see |\pref_global_chk:| below for 
%    the encoding of functions that might accept global variables
%    in certain situations.  Not checked is the case that the
%    argument isn't a variable at all, i.e.\ it doesn't have 
%    a |_| as second letter. Maybe we should add this for safety
%    during the implementation since it will find certain errors
%    involving wrong expansion in earlier stage.
%    \begin{macrocode}
\def_new:Npn \chk_local:N #1{\exp_after:NN
                           \chk_local_aux:w \token_to_string:N#1\q_stop}
\def_new:Npn \chk_local_aux:w #1#2#3\q_stop{
   \if_num:w\tex_uccode:D`#2=`G\scan_stop:
       \err_latex_bug:n{Local~mismatch:~local~function~called~with~
                     global~variable:^^J\text_put_four_sp: #1#2#3~
                     on~line~\tex_the:D\tex_inputlineno:D}
   \else:
     \if_num:w\tex_uccode:D`#2=`L\scan_stop:
     \else:
       \err_latex_bug:n{Variable~mismatch:~function~not~called~with~
                     proper~variable:^^J\text_put_four_sp: #1#2#3~
                     on~line~\tex_the:D\tex_inputlineno:D}\fi:
   \fi:}
%    \end{macrocode}
%    We set the |\l_iow_new_line_code| at this point, just in case we
%    run into errors.
%    \begin{macrocode}
\tex_newlinechar:D=`\^^J
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\chk_global:N}
% \begin{macro}{\chk_global_aux:w}
%    |\chk_global:N| is similar to |\chk_local:N| but looks only
%    for global variables.
%    \begin{macrocode}
\def_new:Npn \chk_global:N #1{\exp_after:NN
                           \chk_global_aux:w \token_to_string:N#1\q_stop}
\def_new:Npn \chk_global_aux:w #1#2#3\q_stop{
   \if_num:w\tex_uccode:D`#2=`L\scan_stop:
       \err_latex_bug:n{Global~mismatch:~global~function~called~with~
                   local~variable:~#1#2#3~
                   on~line~\tex_the:D\tex_inputlineno:D}
   \else:
     \if_num:w\tex_uccode:D`#2=`G\scan_stop:
     \else:
       \err_latex_bug:n{Variable~mismatch:~function~not~called~with~
                     proper~variable:~#1#2#3~
                     on~line~\tex_the:D\tex_inputlineno:D}\fi:\fi:}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\pref_global_chk:}
% \begin{macro}{\chk_local_or_pref_global:N}
%    To allow implementations where we precede some function with
%    |\pref_global:D| without loosing the possibility to check for the
%    correct type of a variable, the following helper functions can be
%    used: |\chk_local_or_pref_global:N| \m{variable} is the variable
%    check which is usually |\let:NN| to |\chk_local:N|, i.e.\ it will
%    check for local variables. This behavior will be changed by
%    |\pref_global_chk:|.  This function first changes
%    |\chk_local_or_pref_global:N| to check for global variables, then
%    issues a |\pref_global:D|. After being used,
%    |\chk_local_or_pref_global:N| will restore itself to
%    |\chk_local:N|. So, if we use |\chk_local_or_pref_global:N|
%    inside some function |\foo_bar:n| we can implement a global
%    version |\foo_gbar:n| by defining
%    \begin{verbatim}
%       \def_new:Npn \foo_gbar:n {\pref_global_chk: \foo_bar:n }
%\end{verbatim}
%    provided of course, that |\foo_bar:n| is defined in a way that a
%    |\pref_global:D| does work. Such a scheme has to be used
%    carefully, but its advantage is that the checking version has the
%    same structure as a streamlined version, we only have to change
%    |\pref_global_chk:| into |\pref_global:D| and omit the
%    |\chk_local_or_pref_global:N| function in the body.
%    \begin{macrocode}
\def_new:Npn \pref_global_chk: {
    \gdef:Npn \chk_local_or_pref_global:N ##1{
          \chk_global:N ##1
          \glet:NN \chk_local_or_pref_global:N \chk_local:N}
    \pref_global:D}
\let_new:NN \chk_local_or_pref_global:N \chk_local:N
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\chk_var_or_const:N}
% \begin{macro}{\chk_var_or_const_aux:w}
%    |\chk_var_or_const:N| is used in situations where we want to check
%    that we have a variable (or a constant) but do not care whether
%    or not it is global (for example, in allocation routines).
%    \begin{macrocode}
\def_new:Npn \chk_var_or_const:N #1{\exp_after:NN
     \chk_var_or_const_aux:w \token_to_string:N#1\q_stop }
\def_new:Npn \chk_var_or_const_aux:w #1#2#3\q_stop {
    \if_num:w\tex_uccode:D`#2=`L\scan_stop:
    \else:
      \if_num:w\tex_uccode:D`#2=`G\scan_stop:
      \else:
        \if_num:w\tex_uccode:D`#2=`C\scan_stop:
        \else:
%    \end{macrocode}
%    We also allow the beast to be a quark, i.e.\ to start with |\q|.
%    \begin{macrocode}
          \if_char_code:w#2q\scan_stop:
          \else:
%    \end{macrocode}
%    We might also want to allow that it is a user definable
%    variable which means that its name consists of letters only. We
%    could check this by testing that there is no |_|, but this is not
%    implemented so far.
%    \begin{macrocode}
           \err_latex_bug:n{Variable~mismatch:~function~not~called~with~
                       proper~variable:^^J\text_put_four_sp: #1#2#3~
                       on~line~\tex_the:D\tex_inputlineno:D}\fi:\fi:\fi:
    \fi:}
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%
% \subsection{Doing some tracing}
%
%  \begin{macro}{\tracingall}
%  \begin{macro}{\absolutelytracingall}
%  \begin{macro}{\donotcheck}
%    During |\tracingall| we don't want to see all this code coming
%    from the checking functions since something more substantial is
%    probably wrong. Therefore this definition of it turns the
%    functions of as far as possible.
%    \begin{macrocode}
\def_new:Npn\donotcheck{
  \let:NN \chk_global:N \use_none:n
  \let:NN \chk_local:N \use_none:n
  \let:NN \chk_local_or_pref_global:N \use_none:n
  \let:NN \pref_global_chk: \pref_global:D
  \let:NN \chk_new_cs:N \use_none:n
  \let:NN \chk_exist_cs:N \use_none:n
  \let:NN \chk_var_or_const:N \use_none:n
  \let:NN \cs_record_name:N \use_none:n
  \let:NN \cs_record_name:c \use_none:n
  \let:NN \cs_record_meaning:N \use_none:n
  \let:NN \register_record_name:N \use_none:n
}
\def_new:Npn\absolutelytracingall{
%    \end{macrocode}
%  \end{macro}
%
%    We do the settings by hand to avoid uninteresting lines in the
%    log file as much as possible.
%    \begin{macrocode}
  \pref_global:D\g_trace_commands_status\c_two
  \pref_global:D\g_trace_statistics_status\c_two
  \pref_global:D\g_trace_pages_status\c_one
  \pref_global:D\g_trace_output_status\c_one
  \pref_global:D\g_trace_chars_status\c_one
  \pref_global:D\g_trace_macros_status\c_two
  \pref_global:D\g_trace_paragraphs_status\c_one
  \pref_global:D\g_trace_restores_status\c_one
  \pref_global:D\g_trace_box_breadth_int\c_ten_thousand
  \pref_global:D\g_trace_box_depth_int\c_ten_thousand
  \pref_global:D\g_trace_online_status\c_one
  \mode_errorstop:D}
%
% Use LaTeX2e definition for now.
%\def_new:Npn\tracingall{
%  \donotcheck
%  \absolutelytracingall
%}
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%  \begin{macro}{\tracingoff}
%    This macro turns off all tracing.
%    \begin{macrocode}
\def_new:Npn\tracingoff{
%    \end{macrocode}
%    First we turn off |\g_trace_online_status| so that we get minimal
%    rubbish on the terminal. Of course, in the log file all
%    assignments are shown.
%    \begin{macrocode}
  \pref_global:D\g_trace_online_status\c_zero
  \pref_global:D\g_trace_commands_status\c_zero
  \pref_global:D\g_trace_statistics_status\c_zero
  \pref_global:D\g_trace_pages_status\c_zero
  \pref_global:D\g_trace_output_status\c_zero
  \pref_global:D\g_trace_chars_status\c_zero
  \pref_global:D\g_trace_macros_status\c_zero
  \pref_global:D\g_trace_paragraphs_status\c_zero
  \pref_global:D\g_trace_restores_status\c_zero
  \pref_global:D\g_trace_box_breadth_int\c_zero
  \pref_global:D\g_trace_box_depth_int\c_zero
}
%    \end{macrocode}
%  \end{macro}
%
% \subsection{Tracing modules}
%
%  \begin{macro}{\traceon}
%  \begin{macro}{\traceoff}
%    Turning the tracing of modules on or off. (primitive version).
%    \begin{macrocode}
%<*trace>
\def_new:Npn\traceon#1{\for_clist:Nnn\l_tmpa_tlp{#1}
         {
          \cs_free:cF{g_trace_\l_tmpa_tlp _status}
            {\int_gincr:c{g_trace_\l_tmpa_tlp _status}}
         }}
\def_new:Npn\traceoff#1{\for_clist:Nnn\l_tmpa_tlp{#1}
         {
          \cs_free:cF{g_trace_\l_tmpa_tlp _status}
            {\int_gdecr:c{g_trace_\l_tmpa_tlp _status}}
         }}
%</trace>
%<-trace>\let_new:NN\traceon\use_none:n
%<-trace>\let_new:NN\traceoff\use_none:n
%</package>
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%
%    Show token usage:
%    \begin{macrocode}
%<*showmemory>
\showMemUsage
%</showmemory>
%    \end{macrocode}
%
