[latex3-commits] [l3svn] r5868 - A few fixes and reorganizations in l3check
noreply at latex-project.org
noreply at latex-project.org
Wed Aug 19 17:38:26 CEST 2015
Author: bruno
Date: 2015-08-19 17:38:25 +0200 (Wed, 19 Aug 2015)
New Revision: 5868
Modified:
trunk/l3trial/l3check/l3check.dtx
Log:
A few fixes and reorganizations in l3check
In particular now \cs_if_exist:NTF and friends test that
their argument is a function (i.e. not a variable) and
complain otherwise. This shows up in e.g.
"\cs_if_exist:NF \c_backslash_str" in experimental l3str.
Modified: trunk/l3trial/l3check/l3check.dtx
===================================================================
--- trunk/l3trial/l3check/l3check.dtx 2015-08-19 02:39:15 UTC (rev 5867)
+++ trunk/l3trial/l3check/l3check.dtx 2015-08-19 15:38:25 UTC (rev 5868)
@@ -250,17 +250,31 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[aux]{\@@_exp_args:Nc}
-% Copy \cs{exp_args:Nc} with no check, to use in situations where the
+% \begin{macro}[aux]
+% {
+% \@@_old_exp_args:Nc, \@@_old_exp_args:NNc, \@@_old_exp_args:Ncc,
+% \@@_old_cs_if_exist:NTF, \@@_old_cs_if_exist:NT, \@@_old_cs_if_exist:NF,
+% \@@_old_cs_if_free:NTF, \@@_old_cs_if_free:NT, \@@_old_cs_if_free:NF,
+% }
+% Copy \cs{exp_args:Nc} and a few others with no check, to use in situations where the
% check should be omitted.
% \begin{macrocode}
-\cs_new_eq:NN \@@_exp_args:Nc \exp_args:Nc
+\cs_new_eq:NN \@@_old_exp_args:Nc \exp_args:Nc
+\cs_new_eq:NN \@@_old_exp_args:NNc \exp_args:NNc
+\cs_new_eq:NN \@@_old_exp_args:Ncc \exp_args:Ncc
+\cs_new_eq:NN \@@_old_cs_if_exist:NTF \cs_if_exist:NTF
+\cs_new_eq:NN \@@_old_cs_if_exist:NT \cs_if_exist:NT
+\cs_new_eq:NN \@@_old_cs_if_exist:NF \cs_if_exist:NF
+\cs_new_eq:NN \@@_old_cs_if_free:NTF \cs_if_free:NTF
+\cs_new_eq:NN \@@_old_cs_if_free:NT \cs_if_free:NT
+\cs_new_eq:NN \@@_old_cs_if_free:NF \cs_if_free:NF
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\tl_if_in:ffTF, \str_case:fnF, \tl_if_empty:fTF}
+% \begin{macro}{\use:nf, \tl_if_in:ffTF, \str_case:fnF, \tl_if_empty:fTF}
% Just a variant we need.
% \begin{macrocode}
+\cs_generate_variant:Nn \use:nn { nf }
\cs_generate_variant:Nn \tl_if_in:nnTF { ff }
\cs_generate_variant:Nn \str_case:nnF { f }
\cs_generate_variant:Nn \tl_if_empty:nTF { f }
@@ -302,18 +316,22 @@
% \end{variable}
% \end{variable}
%
-% \begin{macro}{\@@_error:nn, \@@_error:nnn}
-% \begin{macro}[EXP]{\@@_error_exp:nn, \@@_error_exp:nnn}
+% \begin{macro}{\@@_error:nn, \@@_error:nnn, \@@_error:nnnn}
+% \begin{macro}[EXP]{\@@_error_exp:nn, \@@_error_exp:nnn, \@@_error_exp:nnnn}
% Wrappers around errors, expandable or not.
% \begin{macrocode}
\cs_new_nopar:Npn \@@_error:nn
{ \msg_error:nnn { check } }
\cs_new_nopar:Npn \@@_error:nnn
{ \msg_error:nnnn { check } }
+\cs_new_nopar:Npn \@@_error:nnnn
+ { \msg_error:nnnnn { check } }
\cs_new_nopar:Npn \@@_error_exp:nn
{ \msg_expandable_error:nnn { check } }
\cs_new_nopar:Npn \@@_error_exp:nnn
{ \msg_expandable_error:nnnn { check } }
+\cs_new_nopar:Npn \@@_error_exp:nnnn
+ { \msg_expandable_error:nnnnn { check } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -328,16 +346,16 @@
{ \msg_warning:nnnn { check } }
\cs_new_nopar:Npn \@@_warning_exp:nn
{
- \cs_if_exist_use:NF
- \msg_expandable_warning:nnn
- \msg_expandable_error:nnn
+ \@@_old_cs_if_exist:NTF \msg_expandable_warning:nnn
+ { \msg_expandable_warning:nnn }
+ { \msg_expandable_error:nnn }
{ check }
}
\cs_new_nopar:Npn \@@_warning_exp:nnn
{
- \cs_if_exist_use:NF
- \msg_expandable_warning:nnnn
- \msg_expandable_error:nnnn
+ \@@_old_cs_if_exist:NTF \msg_expandable_warning:nnnn
+ { \msg_expandable_warning:nnnn }
+ { \msg_expandable_error:nnnn }
{ check }
}
% \end{macrocode}
@@ -420,13 +438,14 @@
{ ##3 {##1} }
\cs_new:Npn \@@_split_name_var:Nw ##1##2 #2 ##3 #2 ##4 \q_mark ##5
{ ##5 ##1 ##3 #2 ##4 \q_mark ##5 }
- \cs_new:Npn \@@_split_name_var_end:Nw ##1##2 #2 ##3 \q_stop ##4##5##6
+ \cs_new:Npn \@@_split_name_var_end:Nw ##1##2 \q_mark ##3 \q_stop ##4##5##6
{ ##5 {##1} {##2} }
}
\exp_after:wN \@@_tmp:w \tl_to_str:n { : _ }
% \end{macrocode}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \begin{macro}[int, EXP, pTF]{\@@_if_tl_macro:N}
% Test if the variable is a non-long, non-protected macro with no argument.
@@ -585,7 +604,7 @@
% sure that its second expansion is the same as the second expansion
% of the original macro.
%
-% We use \cs{@@_exp_args:Nc}, a copy of \cs{exp_args:Nc}, because we
+% We use \cs{@@_old_exp_args:Nc}, a copy of \cs{exp_args:Nc}, because we
% are building a previously not-defined control sequence.
% \begin{macrocode}
\cs_new_protected:Npn \check_patch:Npnn #1#2#
@@ -595,9 +614,9 @@
\tl_if_in:ffTF
{ \token_get_prefix_spec:N #1 }
{ \tl_to_str:n { protected } }
- { \@@_exp_args:Nc \@@_patch:NoNnnn }
- { \@@_exp_args:Nc \@@_patch_exp:NoNnnn }
- { @@_patched_ \cs_to_str:N #1 }
+ { \@@_old_exp_args:Nc \@@_patch:NoNnnn }
+ { \@@_old_exp_args:Nc \@@_patch_exp:NoNnnn }
+ { @@_old_ \cs_to_str:N #1 }
{ \l_@@_module_tl }
#1
{#2}
@@ -607,7 +626,7 @@
\cs_generate_variant:Nn \check_patch:Npnn { c }
\cs_new_protected:Npn \@@_patch:NnNnnn #1#2#3#4#5#6
{
- \cs_new_eq:NN #1 #3
+ \if_meaning:w #1 #3 \else: \cs_new_eq:NN #1 #3 \fi:
\cs_gset_protected:Npn #3 #4
{
\@@_if_on:nT {#2} { \if_false: { \fi: #6 \if_false: } \fi: }
@@ -617,7 +636,7 @@
\cs_generate_variant:Nn \@@_patch:NnNnnn { No }
\cs_new_protected:Npn \@@_patch_exp:NnNnnn #1#2#3#4#5#6
{
- \cs_new_eq:NN #1 #3
+ \if_meaning:w #1 #3 \else: \cs_new_eq:NN #1 #3 \fi:
\cs_gset:Npn #3 #4
{
\@@_exp:w
@@ -640,57 +659,72 @@
% then construct the parameter text for \cs{check_patch:Npnn}, both
% braced and not braced. At the same time, fill the
% \cs{l_@@_extra_code_tl} variable with code that checks |N|-type
-% arguments.
+% arguments. Also accept |T| and |F| arguments.
% \begin{macrocode}
\cs_new_protected:Npn \check_patch:Nn #1#2
{
- \@@_split_name:Nnnn #1
- { \@@_patch_parm:Nnn #1 {#2} }
- { \use_i:nnn { \@@_error:nn { patch-var } {#1} } }
- { \@@_error:nn { patch-non-expl } {#1} }
+ \token_if_macro:NTF #1
+ {
+ \tl_if_in:ffTF
+ { \token_get_prefix_spec:N #1 }
+ { \tl_to_str:n { protected } }
+ { \@@_patch_aux:NNn \check_is_N:n #1 }
+ { \@@_patch_aux:NNn \check_is_N_exp:n #1 }
+ }
+ { \msg_error:nnnnnn { check } { patch-non-macro } {#1} { } { } }
+ {#2}
}
+\cs_new_protected:Npn \@@_patch_aux:NNn #1#2#3
+ {
+ \@@_split_name:Nnnn #2
+ { \@@_patch_parm:NNnn #1 #2 {#3} }
+ { \use_i:nnn { \@@_error:nn { patch-var } {#2} } }
+ { \@@_error:nn { patch-non-expl } {#2} }
+ }
\cs_generate_variant:Nn \check_patch:Nn { c }
-\cs_new_protected:Npn \@@_patch_parm:Nnn #1#2#3
+\cs_new_protected:Npn \@@_patch_parm:NNnn #1#2#3#4
{
\int_zero:N \l_@@_parm_int
\tl_clear:N \l_@@_parm_tl
\tl_clear:N \l_@@_parm_braced_tl
\tl_clear:N \l_@@_extra_code_tl
- \tl_map_inline:nn {#3}
+ \tl_map_inline:nn {#4}
{
\int_incr:N \l_@@_parm_int
- \@@_patch_parm:VNn \l_@@_parm_int ##1 {#3}
+ \@@_patch_parm:VNNn \l_@@_parm_int ##1 #1 {#4}
}
\use:x
{
\exp_not:N \check_patch:Npnn
- \exp_not:N #1
+ \exp_not:N #2
\exp_not:V \l_@@_parm_tl
{ \exp_not:V \l_@@_parm_braced_tl }
{
\exp_not:V \l_@@_extra_code_tl
- \exp_not:n {#2}
+ \exp_not:n {#3}
}
}
}
-\cs_new_protected:Npn \@@_patch_parm:nNn #1#2#3
+\cs_new_protected:Npn \@@_patch_parm:nNNn #1#2#3#4
{
\str_case:nnTF {#2}
{
- n { \tl_put_right:Nn \l_@@_parm_braced_tl { { ## #1 } } }
N
{
\tl_put_right:Nn \l_@@_parm_braced_tl { ## #1 }
- \tl_put_right:Nn \l_@@_extra_code_tl { \check_is_N:n { ## #1 } }
+ \tl_put_right:Nn \l_@@_extra_code_tl { #3 { ## #1 } }
}
+ n { \tl_put_right:Nn \l_@@_parm_braced_tl { { ## #1 } } }
+ T { \tl_put_right:Nn \l_@@_parm_braced_tl { { ## #1 } } }
+ F { \tl_put_right:Nn \l_@@_parm_braced_tl { { ## #1 } } }
}
{ \tl_put_right:Nn \l_@@_parm_tl { ## #1 } }
{
\tl_map_break:n
- { \@@_error:nn { patch-non-base } {#3} }
+ { \@@_error:nn { patch-non-base } {#4} }
}
}
-\cs_generate_variant:Nn \@@_patch_parm:nNn { V }
+\cs_generate_variant:Nn \@@_patch_parm:nNNn { V }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -699,6 +733,22 @@
%
% ^^A todo: document
%
+% \begin{macro}{\check_omit:NN}
+% \begin{macro}[aux]{\@@_omit_aux:NNN}
+% This cannot be nested!
+% \begin{macrocode}
+\cs_new_protected:Npn \check_omit:NN #1#2
+ { \@@_old_exp_args:Nc \@@_omit_aux:NNN { @@_saved_ \cs_to_str:N #1 } #1 #2 }
+\cs_new_protected:Npn \@@_omit_aux:NNN #1#2#3
+ {
+ \cs_gset_eq:NN #1 #2
+ \cs_gset_protected_nopar:Npn #2
+ { \cs_gset_eq:NN #2 #1 #3 }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}{\check_is_N:n}
% \begin{macro}[EXP]{\check_is_N_exp:n}
% \begin{macro}[aux, EXP]{\@@_if_N_type:nF}
@@ -711,7 +761,7 @@
\@@_if_N_type:nF {#1}
{ \@@_error:nn { is-not-N-type } {#1} }
}
-\cs_new:Npn \@@_N_type_exp:n #1
+\cs_new:Npn \check_is_N_exp:n #1
{
\@@_if_N_type:nF {#1}
{ \@@_error_exp:nn { is-not-N-type } {#1} }
@@ -875,12 +925,12 @@
% \begin{macrocode}
\cs_new_protected:Npn \check_is_defined:N #1
{
- \cs_if_exist:NF #1
+ \@@_old_cs_if_exist:NF #1
{ \@@_error:nn { is-not-defined } {#1} }
}
\cs_new:Npn \check_is_defined_exp:N #1
{
- \cs_if_exist:NF #1
+ \@@_old_cs_if_exist:NF #1
{ \@@_error_exp:nn { is-not-defined } {#1} }
}
\cs_new:Npn \check_is_defined_exp:c #1
@@ -895,25 +945,25 @@
% \begin{macrocode}
\cs_new_protected:Npn \check_is_defined_tl:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_tl_aux:NN #1 \@@_error:nnn }
{ \@@_error:nn { is-not-defined } {#1} }
}
\cs_new:Npn \check_is_defined_tl_exp:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_tl_aux:NN #1 \@@_error_exp:nnn }
{ \@@_error_exp:nn { is-not-defined } {#1} }
}
\cs_new_protected:Npn \check_is_tl:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_tl_aux:NN #1 \@@_error:nnn }
{ \@@_is_name_type:NnN #1 { tl } \@@_error:nnn }
}
\cs_new:Npn \check_is_tl_exp:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_tl_aux:NN #1 \@@_error_exp:nnn }
{ \@@_is_name_type:NnN #1 { tl } \@@_error_exp:nnn }
}
@@ -931,25 +981,25 @@
% \begin{macrocode}
\cs_new_protected:Npn \check_is_defined_seq:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_seq_aux:NN #1 \@@_error:nn }
{ \@@_error:nn { is-not-defined } {#1} }
}
\cs_new:Npn \check_is_defined_seq_exp:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_seq_aux:NN #1 \@@_error_exp:nnn }
{ \@@_error_exp:nn { is-not-defined } {#1} }
}
\cs_new_protected:Npn \check_is_seq:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_seq_aux:NN #1 \@@_error:nnn }
{ \@@_is_name_type:NnN #1 { seq } \@@_error:nnn }
}
\cs_new:Npn \check_is_seq_exp:N #1
{
- \cs_if_exist:NTF #1
+ \@@_old_cs_if_exist:NTF #1
{ \@@_is_seq_aux:NN #1 \@@_error_exp:nnn }
{ \@@_is_name_type:NnN #1 { seq } \@@_error_exp:nnn }
}
@@ -998,30 +1048,34 @@
% ^^A todo: more informative error saying what the variable is if it has the wrong type.
% \begin{macrocode}
\msg_new:nnn { check } { is-not-defined }
- { Assertion~failed:~'#1'~is~not~defined. }
+ { '#1'~is~not~defined. }
\msg_new:nnn { check } { is-not-N-type }
- { Assertion~failed:~'#1'~is~not~a~single~N-type~token. }
+ { '#1'~is~not~a~single~N-type~token. }
\msg_new:nnn { check } { is-not-scope }
{
- Assertion~failed:~'#2'~is~not~a~
- \str_case:nnF {#1}
+ \use:nf { '#2'~is~not~a~ }
{
- { l } { local }
- { g } { global }
- } {#1} ~
- variable~(starting~with~'#1_').
+ \str_case:nnF {#1}
+ {
+ { l } { local }
+ { g } { global }
+ } {#1} ~
+ variable~(starting~with~'#1_').
+ }
}
\msg_new:nnn { check } { is-not }
{
- Assertion~failed:~'#2'~is~not~a~
- \str_case:nnF {#1}
+ \use:nf { '#2'~is~not~a~ }
{
- { function } { function }
- { variable } { variable }
- { tl } { token~list }
- { seq } { sequence }
+ \str_case:nnF {#1}
+ {
+ { function } { function }
+ { variable } { variable }
+ { tl } { token~list }
+ { seq } { sequence }
+ }
+ {#1} .
}
- {#1} .
}
\msg_new:nnn { check } { patch-var }
{ Only~functions~can~be~patched.~'#1'~is~a~variable }
@@ -1068,6 +1122,8 @@
{ Redundant~#1-expansion~of~'#2' }
\msg_new:nnn { check } { internal }
{ Internal~error:~#1!! }
+\msg_new:nnn { check } { bad-signature }
+ { Signature~'#2'~expected~for~an~argument~of~'#1'.~Got~'#3'. }
% \end{macrocode}
%
% \subsection{\texttt{l3kernel}}
@@ -1077,8 +1133,7 @@
% The following is based on file \texttt{expl3-code} at revision 5859 or so.
%
% Difficulty with \cs{int_gdecr:N} being defined as \cs{tex_global:D}
-% \cs{int_decr:N}. Same for \cs{cs_gset_eq:NN} and \cs{cs_new_eq:NN}
-% defined in terms of \cs{cs_set_eq:NN}. Same for \cs{int_gadd:Nn},
+% \cs{int_decr:N}. Same for \cs{int_gadd:Nn},
% \cs{int_gsub:Nn}, \cs{int_gset:Nn},
% |(dim/skip/muskip)_(gzero:N/gset:Nn/gset_eq:NN/gadd:Nn/gsub:Nn)|,
% \cs{box_gset_eq:NN}, \cs{box_gset_eq_clear:NN},
@@ -1093,47 +1148,60 @@
{
% \end{macrocode}
%
+% First standardize some definitions: the $16$ assignment functions
+% |\cs_(set/gset/new)(/_protected)(/_nopar):Np(n/x)| are normally
+% defined in terms of each other, but that complicates checking, since
+% some are defined as \cs{tex_long:D} or \cs{etex_protected:D} followed
+% by others.
+% \begin{macrocode}
+ \cs_gset_protected_nopar:Npn \cs_set_nopar:Npn { \tex_def:D }
+ \cs_gset_protected_nopar:Npn \cs_set_nopar:Npx { \tex_edef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset_nopar:Npn { \tex_gdef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset_nopar:Npx { \tex_xdef:D }
+ \cs_gset_protected_nopar:Npn \cs_set:Npn { \tex_long:D \tex_def:D }
+ \cs_gset_protected_nopar:Npn \cs_set:Npx { \tex_long:D \tex_edef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset:Npn { \tex_long:D \tex_gdef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \tex_xdef:D }
+ \cs_gset_protected_nopar:Npn \cs_set_protected_nopar:Npn { \etex_protected:D \tex_def:D }
+ \cs_gset_protected_nopar:Npn \cs_set_protected_nopar:Npx { \etex_protected:D \tex_edef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset_protected_nopar:Npn { \etex_protected:D \tex_gdef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset_protected_nopar:Npx { \etex_protected:D \tex_xdef:D }
+ \cs_gset_protected_nopar:Npn \cs_set_protected:Npn { \etex_protected:D \tex_long:D \tex_def:D }
+ \cs_gset_protected_nopar:Npn \cs_set_protected:Npx { \etex_protected:D \tex_long:D \tex_edef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset_protected:Npn { \etex_protected:D \tex_long:D \tex_gdef:D }
+ \cs_gset_protected_nopar:Npn \cs_gset_protected:Npx { \etex_protected:D \tex_long:D \tex_xdef:D }
+% \end{macrocode}
+% Simplify \cs{cs_gset_eq:NN} and \cs{cs_new_eq:NN} similarly rather
+% than defining them in terms of \cs{cs_set_eq:NN}
+% \begin{macrocode}
+ \cs_gset_protected:Npn \cs_gset_eq:NN #1 { \tex_global:D \tex_let:D #1 = ~ }
+ \cs_gset_protected:Npn \cs_new_eq:NN #1 { \__chk_if_free_cs:N #1 \tex_global:D \tex_let:D #1 = ~ }
+% \end{macrocode}
+%
% We could change \cs{group_begin:}, \cs{group_end:},
% \cs{group_insert_after:N}, but do not.
%
% Let us do |\cs_(set/gset/new)(/_protected)(/_nopar):N(/p)(n/x)|, $48$
-% assignment functions. First clean them up a bit, since some are
-% defined as \cs{tex_global:D} followed by others.
-% \begin{macrocode}
- \cs_set_protected_nopar:Npn \cs_set_nopar:Npn { \tex_def:D }
- \cs_set_protected_nopar:Npn \cs_set_nopar:Npx { \tex_edef:D }
- \cs_set_protected_nopar:Npn \cs_gset_nopar:Npn { \tex_gdef:D }
- \cs_set_protected_nopar:Npn \cs_gset_nopar:Npx { \tex_xdef:D }
- \cs_set_protected_nopar:Npn \cs_set:Npn { \tex_long:D \tex_def:D }
- \cs_set_protected_nopar:Npn \cs_set:Npx { \tex_long:D \tex_edef:D }
- \cs_set_protected_nopar:Npn \cs_gset:Npn { \tex_long:D \tex_gdef:D }
- \cs_set_protected_nopar:Npn \cs_gset:Npx { \tex_long:D \tex_xdef:D }
- \cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npn { \etex_protected:D \tex_def:D }
- \cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npx { \etex_protected:D \tex_edef:D }
- \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npn { \etex_protected:D \tex_gdef:D }
- \cs_set_protected_nopar:Npn \cs_gset_protected_nopar:Npx { \etex_protected:D \tex_xdef:D }
- \cs_set_protected_nopar:Npn \cs_set_protected:Npn { \etex_protected:D \tex_long:D \tex_def:D }
- \cs_set_protected_nopar:Npn \cs_set_protected:Npx { \etex_protected:D \tex_long:D \tex_edef:D }
- \cs_set_protected_nopar:Npn \cs_gset_protected:Npn { \etex_protected:D \tex_long:D \tex_gdef:D }
- \cs_set_protected_nopar:Npn \cs_gset_protected:Npx { \etex_protected:D \tex_long:D \tex_xdef:D }
-% \end{macrocode}
-% The plan is eventually to
+% assignment functions. For now, just check that the first argument is
+% a single token, is a function (not yet), and for the |:Nn|/|:Nx|
+% defining functions, check that the signature is right. Additionally,
+% check that \enquote{nopar} is used properly: have a warning when
+% trying to define a long macro with no parameter or a non-long macro
+% with parameters. The plan is eventually to
% \begin{itemize}
-% \item check that \enquote{nopar} is used properly;
% \item list any undefined token appearing in any cs definition, in
-% particular variants;
+% particular variants of existing tokens;
% \item detect what parts are arguments of what and detect e.g.,
% brace groups used as N-type arguments, etc.
+% \item try to detect the case of expandable commands which use
+% protected commands.
% \item perhaps detect functions from the \enquote{msg} module, and
% check that the corresponding message exists.
% \end{itemize}
-% For now, just check that the first argument is a single token, is a
-% function, and for the |:Nn|/|:Nx| defining functions, check that the
-% signature is right. Additionally, have a warning when trying to
-% define a long macro with no parameter or a non-long macro with
-% parameters. Note that we do not touch the \enquote{new} functions as
-% they call the \enquote{gset} functions internally (otherwise we would
-% get two warnings/errors).
+% Note that we do not touch the \enquote{new} functions as they call
+% the \enquote{gset} functions internally (otherwise we would get two
+% warnings/errors).
+% % ^^A todo: reinstate \check_is_function:N when more is done
% \begin{macrocode}
\group_begin:
\cs_set:Npn \check_tmp:w #1#2#3
@@ -1142,14 +1210,14 @@
##1 ##2 ## { ##1 ##2 }
{
\check_is_N:n {##1}
- % \check_is_function:N ##1 % ^^A todo: reinstate when more is done
+ % \check_is_function:N ##1
\tl_if_empty:nT {##2} { \@@_warning:nn { par-noarg } {##1} }
}
\check_patch:cpnn { cs_ #1 #2 _nopar:Np #3 }
##1 ##2 ## { ##1 ##2 }
{
\check_is_N:n {##1}
- % \check_is_function:N ##1 % ^^A todo: reinstate when more is done
+ % \check_is_function:N ##1
\tl_if_empty:nF {##2} { \@@_warning:nn { arg-nopar } {##1} }
}
\check_patch:cpnn { cs_ #1 #2 :N #3 }
@@ -1183,15 +1251,12 @@
% The second argument of |\cs_(set/gset/new)_eq:NN| should be defined,
% except if it is \cs{scan_stop:}, \cs{tex_relax:D} or
% \cs{tex_undefined:D}, in which case that was probably the point.
-% Also redefine the |:Nc|, |:cN| and |:cc| variants to avoid using
-% actual |c|-expansion, since the resulting control sequences are often
-% undefined.
% \begin{macrocode}
\tl_map_inline:nn { {set} {gset} {new} }
{
\check_patch:cn { cs_#1_eq:NN }
{
- \cs_if_exist:NF ##2
+ \@@_old_cs_if_exist:NF ##2
{
\str_case:nnF {##2}
{
@@ -1202,23 +1267,6 @@
{ \@@_warning:nnn { set-eq-undef } {##1} {##2} }
}
}
- \cs_gset_protected:cpx { cs_#1_eq:cN } ##1
- {
- \exp_not:N \exp_after:wN \exp_not:c { cs_#1_eq:NN }
- \exp_not:N \cs:w ##1 \cs_end:
- }
- \cs_gset_protected:cpx { cs_#1_eq:Nc } ##1##2
- {
- \exp_not:N \exp_after:wN \exp_not:c { cs_#1_eq:NN }
- \exp_not:N \exp_after:wN ##1
- \exp_not:N \cs:w ##2 \cs_end:
- }
- \cs_gset_protected:cpx { cs_#1_eq:cc } ##1##2
- {
- \exp_not:N \exp_after:wN \exp_not:c { cs_#1_eq:NN }
- \exp_not:N \cs:w ##1 \exp_not:N \exp_after:wN \cs_end:
- \exp_not:N \cs:w ##2 \cs_end:
- }
}
% \end{macrocode}
%
@@ -1230,17 +1278,130 @@
% \end{macrocode}
% \end{macro}
%
-% ^^A todo:
-% |\prg_(set/new)(/_protected)_conditional:N(/p)nn|,
-% |\prg_(/g)set_eq_conditional:NNn|,
-% |\cs_to_str:N|, |\cs_if_(exist/free)(/_p):(N/c)(T/F/TF)|,
-% |\cs_if_exist_use:(N/c)(/T/F/TF)|,
-% \cs{iow_log:x} \cs{iow_term:x},
-% |\cs_undefine:(N/c)|,
-% \cs{cs_generate_from_arg_count:NNnn},
-% \cs{cs_if_eq:NN}(TF), |\cs_(show/log):N|
+% Next the $8$ |\prg_(set/new)(/_protected)_conditional:N(/p)nn|, for
+% which we just check that the first argument is N-type and is a
+% function (the |:| is crucial to place |_p|), and for the |:Nnn|-type
+% case, that the first argument is a function with an appropriate
+% signature. Also patch the |\prg_(set/new)_eq_conditional:NNn| to
+% check that the N-type arguments are functions.
+% \begin{macrocode}
+ \group_begin:
+ \cs_set:Npn \check_tmp:w #1#2#3
+ {
+ \check_patch:cpnn { prg_ #1 #2 _conditional :Npnn }
+ ##1 ##2 ## { ##1 ##2 }
+ {
+ \check_is_N:n {##1}
+ \check_is_function:N ##1
+ }
+ \check_patch:cpnn { prg_ #1 #2 _conditional :Nnn }
+ ##1 { ##1 }
+ {
+ \check_is_N:n {##1}
+ \check_is_function:N ##1
+ \check_signature_is_base:N ##1
+ }
+ }
+ \tl_map_inline:nn { {set} {new} }
+ {
+ \tl_map_inline:nn { { } {_protected} }
+ { \check_tmp:w {#1} {##1} }
+ \check_patch:cn { prg_#1_eq_conditional:NNn }
+ {
+ \check_is_function:N ##1
+ \check_is_function:N ##2
+ }
+ }
+ \group_end:
+% \end{macrocode}
%
+% A few functions simply need checking of their |N|-type arguments,
+% or just that their |N|-type argument is a function.
% \begin{macrocode}
+ \check_patch:Nn \cs_to_str:N { }
+ \check_patch:Nn \cs_undefine:N { }
+ \check_patch:Nn \cs_show:N { }
+ \check_patch:Nn \cs_log:N { }
+ \check_patch:Nn \cs_if_exist_p:N { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist:NF { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist:NT { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist:NTF { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_free_p:N { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_free:NF { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_free:NT { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_free:NTF { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist_use:N { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist_use:NF { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist_use:NT { \check_is_function_exp:N #1 }
+ \check_patch:Nn \cs_if_exist_use:NTF { \check_is_function_exp:N #1 }
+% \end{macrocode}
+%
+% \begin{macrocode}
+ \check_patch:Nn \cs_generate_from_arg_count:NNnn
+ {
+ \check_is_function:N #1
+ \check_is_function:N #2
+ \str_if_eq_x:nnF { \check_signature:N #2 } { Npn }
+ {
+ \@@_error:nnnn { bad-signature }
+ { \cs_generate_from_arg_count:NNnn } { Npn } {#1}
+ }
+ }
+% \end{macrocode}
+%
+% Maybe the following is a bit to restrictive.
+% \begin{macrocode}
+ \tl_map_inline:nn
+ { \cs_if_eq_p:NN \cs_if_eq:NNT \cs_if_eq:NNF \cs_if_eq:NNTF }
+ {
+ \check_patch:Nn #1
+ {
+ \check_is_function_exp:N ##1
+ \check_is_defined_exp:N ##1
+ \check_is_function_exp:N ##2
+ \check_is_defined_exp:N ##2
+ }
+ }
+% \end{macrocode}
+%
+% When outputting a message, a function definition is made using
+% begin-group and end-group tokens which are spaces (character code
+% $32$), and that confuses the new \cs{cs_set_protected_nopar:Npn}. To
+% avoid this, go back temporarily to the old definition of that
+% function.
+% \begin{macrocode}
+ \cs_new_eq:NN \@@_new_cs_set_protected_nopar:Npn \cs_set_protected_nopar:Npn
+ \use:x
+ {
+ \exp_not:n { \cs_gset_protected:Npn \__msg_interrupt_text:n #1 }
+ {
+ \exp_not:n { \cs_set_eq:NN \cs_set_protected_nopar:Npn \@@_old_cs_set_protected_nopar:Npn }
+ \exp_not:o { \__msg_interrupt_text:n {#1} }
+ \exp_not:n { \cs_set_eq:NN \cs_set_protected_nopar:Npn \@@_new_cs_set_protected_nopar:Npn }
+ }
+ }
+% \end{macrocode}
+%
+% In \cs{int_new:N} etc., there appears \cs{__chk_if_free_cs:N}, which
+% calls \cs{cs_if_free:NF}. Replace that by \cs{@@_old_cs_if_free:NF}
+% to avoid balking at variables.
+% \begin{macrocode}
+ \use:x
+ {
+ \exp_not:n { \cs_gset_protected:Npn \__chk_if_free_cs:N #1 }
+ {
+ \exp_not:f
+ {
+ \exp_after:wN \use_i_ii:nnn
+ \exp_after:wN \exp_stop_f:
+ \exp_after:wN \@@_old_cs_if_free:NF
+ \__chk_if_free_cs:N {#1}
+ }
+ }
+ }
+% \end{macrocode}
+%
+% \begin{macrocode}
}
% \end{macrocode}
%
@@ -1250,7 +1411,101 @@
\check_new:nn { expan }
{
% \end{macrocode}
+% ^^A todo: we may need \group_align_safe_begin:/end: in case of alignment primitive
+% ^^A todo: check that first arg of \exp_args:N... is indeed N
%
+% \begin{macro}
+% {
+% \cs_set_eq:cN, \cs_set_eq:Nc, \cs_set_eq:cc,
+% \cs_gset_eq:cN, \cs_gset_eq:Nc, \cs_gset_eq:cc,
+% \cs_new_eq:cN, \cs_new_eq:Nc, \cs_new_eq:cc,
+% \cs_set:cpn, \cs_set_protected:cpn, \cs_set_nopar:cpn, \cs_set_protected_nopar:cpn,
+% \cs_set:cpx, \cs_set_protected:cpx, \cs_set_nopar:cpx, \cs_set_protected_nopar:cpx,
+% \cs_gset:cpn, \cs_gset_protected:cpn, \cs_gset_nopar:cpn, \cs_gset_protected_nopar:cpn,
+% \cs_gset:cpx, \cs_gset_protected:cpx, \cs_gset_nopar:cpx, \cs_gset_protected_nopar:cpx,
+% \cs_new:cpn, \cs_new_protected:cpn, \cs_new_nopar:cpn, \cs_new_protected_nopar:cpn,
+% \cs_new:cpx, \cs_new_protected:cpx, \cs_new_nopar:cpx, \cs_new_protected_nopar:cpx,
+% \tl_new:c, \tl_show:c, \tl_log:c, \tl_clear_new:c, \tl_gclear_new:c, \tl_const:cn, \tl_const:cx,
+% \clist_new:c, \clist_show:c, \clist_log:c, \clist_clear_new:c, \clist_gclear_new:c, \clist_const:cn,
+% \seq_new:c, \seq_show:c, \seq_log:c, \seq_clear_new:c, \seq_gclear_new:c,
+% \prop_new:c, \prop_show:c, \prop_log:c, \prop_clear_new:c, \prop_gclear_new:c,
+% \int_new:c, \int_show:c, \int_log:c, \int_zero_new:c, \int_gzero_new:c, \int_const:cn,
+% \dim_new:c, \dim_show:c, \dim_log:c, \dim_zero_new:c, \dim_gzero_new:c, \dim_const:cn,
+% \skip_new:c, \skip_show:c, \skip_log:c, \skip_zero_new:c, \skip_gzero_new:c, \skip_const:cn,
+% \muskip_new:c, \muskip_show:c, \muskip_log:c, \muskip_zero_new:c, \muskip_gzero_new:c, \muskip_const:cn,
+% }
+% Redefine some |:Nc|, |:cN| and |:cc| variants to use
+% \cs{@@_old_exp_args:Nc} and similar functions which will omit
+% existence checks, since here the resulting control sequences are
+% often undefined.
+% \begin{macrocode}
+ \tl_map_inline:nn { {set} {gset} {new} }
+ {
+ \cs_gset_protected_nopar:cpx { cs_#1_eq:cN }
+ {
+ \exp_not:N \@@_old_exp_args:Nc
+ \exp_not:c { cs_#1_eq:NN }
+ }
+ \cs_gset_protected_nopar:cpx { cs_#1_eq:Nc }
+ {
+ \exp_not:N \@@_old_exp_args:NNc
+ \exp_not:c { cs_#1_eq:NN }
+ }
+ \cs_gset_protected_nopar:cpx { cs_#1_eq:cc }
+ {
+ \exp_not:N \@@_old_exp_args:Ncc
+ \exp_not:c { cs_#1_eq:NN }
+ }
+ }
+ \group_begin:
+ \cs_set_protected:Npn \check_tmp:w #1#2
+ {
+ \exp_after:wN \cs_gset_protected_nopar:Npx \cs:w #1 : c #2 \cs_end:
+ {
+ \exp_not:N \@@_old_exp_args:Nc
+ \exp_not:c { #1 : N#2 }
+ }
+ }
+ \tl_map_inline:nn { {set} {gset} {new} }
+ {
+ \tl_map_inline:nn { { } { _protected } { _nopar } { _protected_nopar } }
+ {
+ \tl_map_inline:nn { n x }
+ { \check_tmp:w { cs_#1##1 } { p ####1 } }
+ }
+ }
+ \tl_map_inline:nn { {tl} {clist} {seq} {prop} {int} {dim} {skip} {muskip} }
+ {
+ \check_tmp:w { #1_new } { }
+ \check_tmp:w { #1_show } { }
+ \check_tmp:w { #1_log } { }
+ }
+ \tl_map_inline:nn { {tl} {clist} {seq} {prop} }
+ {
+ \check_tmp:w { #1_clear_new } { }
+ \check_tmp:w { #1_gclear_new } { }
+ }
+ \tl_map_inline:nn { {int} {dim} {skip} {muskip} }
+ {
+ \check_tmp:w { #1_zero_new } { }
+ \check_tmp:w { #1_gzero_new } { }
+ \check_tmp:w { #1_const } { n }
+ }
+ \check_tmp:w { tl_const } { n }
+ \check_tmp:w { tl_const } { x }
+ \check_tmp:w { clist_const } { n }
+ \group_end:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]{\use:c}
+% Remove fine-tuning. Here \cs{use:N} does not exist so use
+% \cs{use:n}.
+% \begin{macrocode}
+ \cs_gset_nopar:Npn \use:c { \exp_args:Nc \use:n }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}[EXP]
% {
% \exp_not:o, \exp_not:c, \exp_not:f, \exp_not:V, \exp_not:v,
@@ -1266,7 +1521,7 @@
% \exp_last_unbraced:NNNV, \exp_last_unbraced:NNNo,
% }
% Remove hand-tuning, to make sure that our modified \cs{::N},
-% \cs{::V}, \cs{::o} and \cs{::f} are called. We need to base
+% \cs{::V}, \cs{::o}, and so on are called. We need to base
% \cs{exp_not:c} on \cs{exp_not:N} and not \cs{exp_not:n}
% because the |n| variant is a primitive, which does not
% accept unbraced arguments.
@@ -1309,16 +1564,31 @@
% \end{macrocode}
% \end{macro}
%
-% ^^A todo: we may need \group_align_safe_begin:/end: in case |#1| is an alignment primitive!
-% \begin{macro}[EXP]{\use:c}
-% Remove some more fine-tuning.
+% \begin{macro}[EXP]{\::N, \::V, \::V_unbraced}
+% Check that the argument is a single token. The |V|-type expansion
+% already takes care of checking for existence.
% \begin{macrocode}
- \cs_gset_nopar:Npn \use:c { \exp_args:Nc \use:n }
+ \check_patch:Npnn \::N #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_is_N_exp:n {#3} }
+ \check_patch:Npnn \::V #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_is_N_exp:n {#3} }
+ \check_patch:Npnn \::V_unbraced \::: #1#2 { \::: {#1} {#2} }
+ { \check_is_N_exp:n {#2} }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\::o, \::f, \::o_unbraced, \::f_unbraced}
-% \begin{macro}[aux, EXP]{\@@_if_head_is_expandable:nF}
+% \begin{macro}[EXP]{\::c}
+% Check existence of the function constructed here.
+% \begin{macrocode}
+ \check_patch:Npnn \::c #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_is_defined_exp:c {#3} }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[EXP]
+% {\::o, \::f, \::o_unbraced, \::f_unbraced, \exp_last_two_unbraced:Noo}
+% \begin{macro}[EXP]{\check_should_o_expand:n, \check_should_f_expand:n}
+% \begin{macro}[aux, EXP]{\@@_if_head_is_expandable:nF, \@@_if_head_is_expandable_aux:n}
% These functions expand an argument, once or fully. If the argument
% does not expand at all under the specified expansion type, warn the
% user.
@@ -1340,58 +1610,38 @@
{ \prg_return_false: }
}
}
- \check_patch:Npnn \::o #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ \cs_new:Npn \check_should_o_expand:n #1
{
- \@@_if_head_is_expandable:nF {#3}
- { \@@_warning_exp:nnn { no-expansion } { o } {#3} }
+ \@@_if_head_is_expandable:nF {#1}
+ { \@@_warning_exp:nnn { no-expansion } { o } {#1} }
}
- \check_patch:Npnn \::f #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ \cs_new:Npn \check_should_f_expand:n #1
{
- \tl_if_head_eq_catcode:nNF {#3} \c_space_token
+ \tl_if_head_eq_catcode:nNF {#1} \c_space_token
{
- \@@_if_head_is_expandable:nF {#3}
- { \@@_warning_exp:nnn { no-expansion } { f } {#3} }
+ \@@_if_head_is_expandable:nF {#1}
+ { \@@_warning_exp:nnn { no-expansion } { f } {#1} }
}
}
+ \check_patch:Npnn \::o #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_should_o_expand:n {#3} }
+ \check_patch:Npnn \::f #1 \::: #2#3 { {#1} \::: {#2} {#3} }
+ { \check_should_f_expand:n {#3} }
\check_patch:Npnn \::o_unbraced \::: #1#2 { \::: {#1} {#2} }
- {
- \@@_if_head_is_expandable:nF {#2}
- { \@@_warning_exp:nnn { no-expansion } { o } {#2} }
- }
+ { \check_should_o_expand:n {#2} }
\check_patch:Npnn \::f_unbraced \::: #1#2 { \::: {#1} {#2} }
+ { \check_should_f_expand:n {#2} }
+ \check_patch:Npnn \exp_last_two_unbraced:Noo #1#2#3 { {#1} {#2} {#3} }
{
- \tl_if_head_eq_catcode:nNF {#2} \c_space_token
- {
- \@@_if_head_is_expandable:nF {#2}
- { \@@_warning_exp:nnn { no-expansion } { f } {#2} }
- }
+ \check_is_N:n {#1}
+ \check_should_o_expand:n {#2}
+ \check_should_o_expand:n {#3}
}
% \end{macrocode}
% \end{macro}
% \end{macro}
-%
-% ^^A todo: check that first arg of \exp_args:N... is indeed N!
-%
-% \begin{macro}[EXP]{\::N}
-% Check that this is a single token.
-% \begin{macrocode}
- \check_patch:Npnn \::N #1 \::: #2#3 { {#1} \::: {#2} {#3} }
- { \check_is_N:n {#3} }
-% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[EXP]{\::c}
-% \begin{macrocode}
- \check_patch:Npnn \::c #1 \::: #2#3 { {#1} \::: {#2} {#3} }
- { \check_is_defined_exp:c {#3} }
-% \end{macrocode}
-% \end{macro}
-%
-% ^^A todo:
-% \cs{::V}, \cs{::v}, \cs{::x}
-% |\::(V/v/x)_unbraced|,
-% |\exp_last_two_unbraced:Noo|,
-%
% ^^A todo: extra checks for \cs{cs_generate_variant:Nn}.
% \begin{macrocode}
\check_patch:Nn \cs_generate_variant:Nn
@@ -1457,7 +1707,7 @@
{
\exp_not:n { \cs_gset_protected:Npn \__char_set_catcode:Nn #1#2 }
{
- \exp_not:n { \cs_set_eq:NN \exp_args:Nc \@@_exp_args:Nc }
+ \exp_not:n { \cs_set_eq:NN \exp_args:Nc \@@_old_exp_args:Nc }
\exp_not:o { \__char_set_catcode:Nn {#1} {#2} }
\exp_not:n { \cs_set_nopar:Npn \exp_args:Nc { \::c \::: } }
}
@@ -1469,59 +1719,7 @@
% \cs{prg_new_conditional:Npnn} and its friends use that function to
% generate new control sequences.
%
-% The |c| variants of all \enquote{defining} commands should use
-% \cs{@@_exp_args:Nc} and not \cs{exp_args:Nc} for their first
-% argument, so that the existence check is omitted. Also for
-% \texttt{show} commands.
% \begin{macrocode}
- \group_begin:
- \cs_set_protected:Npn \check_tmp:w #1#2
- {
- \exp_after:wN \cs_gset_protected_nopar:Npx \cs:w #1 : c #2 \cs_end:
- {
- \exp_not:N \@@_exp_args:Nc
- \exp_not:c { #1 : N#2 }
- }
- }
- \tl_map_inline:nn { {set} {gset} {new} }
- {
- \tl_map_inline:nn { { } { _protected } { _nopar } { _protected_nopar } }
- {
- \tl_map_inline:nn { n x }
- { \check_tmp:w { cs_#1##1 } { p ####1 } }
- }
- }
- \tl_map_inline:nn { {tl} {clist} {seq} {prop} {int} {dim} {skip} {muskip} }
- {
- \check_tmp:w { #1_new } { }
- \check_tmp:w { #1_show } { }
- \check_tmp:w { #1_log } { }
- \check_tmp:w { #1_if_exist_p } { }
- \check_tmp:w { #1_if_exist } { TF }
- \check_tmp:w { #1_if_exist } { T }
- \check_tmp:w { #1_if_exist } { F }
- }
- \tl_map_inline:nn { {tl} {clist} {seq} {prop} }
- {
- \check_tmp:w { #1_clear_new } { }
- \check_tmp:w { #1_gclear_new } { }
- }
- \tl_map_inline:nn { {int} {dim} {skip} {muskip} }
- {
- \check_tmp:w { #1_zero_new } { }
- \check_tmp:w { #1_gzero_new } { }
- \check_tmp:w { #1_const } { n }
- }
- \check_tmp:w { tl_const } { n }
- \check_tmp:w { tl_const } { x }
- \check_tmp:w { clist_const } { n }
- \check_tmp:w { tl_concat } { NN }
- \check_tmp:w { clist_concat } { NN }
- \check_tmp:w { seq_concat } { NN }
- \group_end:
-% \end{macrocode}
-%
-% \begin{macrocode}
}
% \end{macrocode}
%
More information about the latex3-commits
mailing list