summaryrefslogtreecommitdiff
path: root/Build/source/texk/web2c/luatexdir/tex/conditional.w
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/texk/web2c/luatexdir/tex/conditional.w')
-rw-r--r--Build/source/texk/web2c/luatexdir/tex/conditional.w556
1 files changed, 287 insertions, 269 deletions
diff --git a/Build/source/texk/web2c/luatexdir/tex/conditional.w b/Build/source/texk/web2c/luatexdir/tex/conditional.w
index 53967087102..fa4e73b49cb 100644
--- a/Build/source/texk/web2c/luatexdir/tex/conditional.w
+++ b/Build/source/texk/web2c/luatexdir/tex/conditional.w
@@ -19,7 +19,6 @@
@ @c
-
#include "ptexlib.h"
@ @c
@@ -49,14 +48,12 @@ int if_limit; /* upper bound on |fi_or_else| codes */
int cur_if; /* type of conditional being worked on */
int if_line; /* line where that conditional began */
-
@ When we skip conditional text, we keep track of the line number
where skipping began, for use in error messages.
@c
int skip_line; /* skipping began here */
-
@ Here is a procedure that ignores text until coming to an \.{\\or},
\.{\\else}, or \.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$
nesting. After it has acted, |cur_chr| will indicate the token that
@@ -66,14 +63,12 @@ procedure run faster).
@c
void pass_text(void)
{
- int l; /* level of $\.{\\if}\ldots\.{\\fi}$ nesting */
- int save_scanner_status; /* |scanner_status| upon entry */
- save_scanner_status = scanner_status;
+ int l = 0; /* level of $\.{\\if}\ldots\.{\\fi}$ nesting */
+ int save_scanner_status = scanner_status; /* |scanner_status| upon entry */
scanner_status = skipping;
- l = 0;
skip_line = line;
while (1) {
- get_next(); /* get_token_lua(); */
+ get_next();
if (cur_cmd == fi_or_else_cmd) {
if (l == 0)
break;
@@ -88,7 +83,6 @@ void pass_text(void)
show_cur_cmd_chr();
}
-
@ When we begin to process a new \.{\\if}, we set |if_limit:=if_code|; then
if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if}
condition has been evaluated, \.{\\relax} will be inserted.
@@ -123,18 +117,17 @@ void pop_condition_stack(void)
flush_node(p);
}
-
@ Here's a procedure that changes the |if_limit| code corresponding to
a given value of |cond_ptr|.
@c
void change_if_limit(int l, halfword p)
{
- halfword q;
if (p == cond_ptr) {
- if_limit = l; /* that's the easy case */
+ /* that's the easy case */
+ if_limit = l;
} else {
- q = cond_ptr;
+ halfword q = cond_ptr;
while (1) {
if (q == null)
confusion("if");
@@ -147,21 +140,21 @@ void change_if_limit(int l, halfword p)
}
}
-
@ The conditional \.{\\ifcsname} is equivalent to \.{\\expandafter}
\.{\\expandafter} \.{\\ifdefined} \.{\\csname}, except that no new
control sequence will be entered into the hash table (once all tokens
preceding the mandatory \.{\\endcsname} have been expanded).
@c
+static halfword last_tested_cs ;
+
static boolean test_for_cs(void)
{
- boolean b; /*is the condition true? */
+ boolean b = false; /*is the condition true? */
int m, s; /*to be tested against the second operand */
- halfword n, p, q; /*for traversing token lists in \.{\\ifx} tests */
- n = get_avail();
- p = n; /*head of the list of characters */
- b = false;
+ halfword q; /*for traversing token lists in \.{\\ifx} tests */
+ halfword n = get_avail();
+ halfword p = n; /*head of the list of characters */
while (1) {
get_x_token();
if (cur_cs != 0)
@@ -169,6 +162,7 @@ static boolean test_for_cs(void)
store_new_token(cur_tok);
}
if (cur_cmd != end_cs_name_cmd) {
+ last_tested_cs = null_cs;
if (int_par(suppress_ifcsname_error_code)) {
do {
get_x_token();
@@ -201,41 +195,35 @@ static boolean test_for_cs(void)
} else {
buffer[m++] = (packed_ASCII_code) (0xF0 + s / 0x40000);
buffer[m++] = (packed_ASCII_code) (0x80 + (s % 0x40000) / 0x1000);
- buffer[m++] =
- (packed_ASCII_code) (0x80 + ((s % 0x40000) % 0x1000) / 0x40);
- buffer[m++] =
- (packed_ASCII_code) (0x80 + ((s % 0x40000) % 0x1000) % 0x40);
+ buffer[m++] = (packed_ASCII_code) (0x80 + ((s % 0x40000) % 0x1000) / 0x40);
+ buffer[m++] = (packed_ASCII_code) (0x80 + ((s % 0x40000) % 0x1000) % 0x40);
}
p = token_link(p);
}
if (m > first) {
- cur_cs = id_lookup(first, m - first); /*|no_new_control_sequence| is |true| */
+ cur_cs = id_lookup(first, m - first); /* |no_new_control_sequence| is |true| */
} else if (m == first) {
- cur_cs = null_cs; /*the list is empty */
+ cur_cs = null_cs; /* the list is empty */
}
b = (eq_type(cur_cs) != undefined_cs_cmd);
flush_list(n);
+ last_cs_name = cur_cs;
return b;
}
-
@ An active character will be treated as category 13 following
\.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}.
@c
-#define get_x_token_or_active_char() do { \
- get_x_token(); \
- if (cur_cmd==relax_cmd && cur_chr==no_expand_flag) { \
- if (is_active_cs(cs_text(cur_cs))) { \
- cur_cmd=active_char_cmd; \
- cur_chr=active_cs_value(cs_text(cur_tok-cs_token_flag)); \
- } \
- } \
- } while (0)
-
-
-
-
+#define get_x_token_or_active_char() do { \
+ get_x_token(); \
+ if (cur_cmd==relax_cmd && cur_chr==no_expand_flag) { \
+ if (is_active_cs(cs_text(cur_cs))) { \
+ cur_cmd=active_char_cmd; \
+ cur_chr=active_cs_value(cs_text(cur_tok-cs_token_flag)); \
+ } \
+ } \
+} while (0)
@ A condition is started when the |expand| procedure encounters
an |if_test| command; in that case |expand| reduces to |conditional|,
@@ -245,7 +233,7 @@ which is a recursive procedure.
@c
void conditional(void)
{
- boolean b; /*is the condition true? */
+ boolean b = false; /*is the condition true? */
int r; /*relation to be evaluated */
int m, n; /*to be tested against the second operand */
halfword p, q; /*for traversing token lists in \.{\\ifx} tests */
@@ -253,245 +241,271 @@ void conditional(void)
halfword save_cond_ptr; /*|cond_ptr| corresponding to this conditional */
int this_if; /*type of this conditional */
boolean is_unless; /*was this if preceded by `\.{\\unless}' ? */
- b = false; /*default is false, just in case */
- if (int_par(tracing_ifs_code) > 0)
- if (int_par(tracing_commands_code) <= 1)
- show_cur_cmd_chr();
+ if ((int_par(tracing_ifs_code) > 0) && (int_par(tracing_commands_code) <= 1))
+ show_cur_cmd_chr();
push_condition_stack();
save_cond_ptr = cond_ptr;
is_unless = (cur_chr >= unless_code);
this_if = cur_chr % unless_code;
/* Either process \.{\\ifcase} or set |b| to the value of a boolean condition */
switch (this_if) {
- case if_char_code:
- case if_cat_code:
- /* Test if two characters match */
- get_x_token_or_active_char();
- if ((cur_cmd > active_char_cmd) || (cur_chr > biggest_char)) { /*not a character */
- m = relax_cmd;
- n = too_big_char;
- } else {
- m = cur_cmd;
- n = cur_chr;
- }
- get_x_token_or_active_char();
- if ((cur_cmd > active_char_cmd) || (cur_chr > biggest_char)) {
- cur_cmd = relax_cmd;
- cur_chr = too_big_char;
- }
- if (this_if == if_char_code)
- b = (n == cur_chr);
- else
- b = (m == cur_cmd);
- break;
- case if_int_code:
- case if_dim_code:
- case if_abs_dim_code:
- case if_abs_num_code:
- /* Test relation between integers or dimensions */
- /* Here we use the fact that |"<"|, |"="|, and |">"| are consecutive ASCII
- codes. */
- if (this_if == if_int_code || this_if == if_abs_num_code)
- scan_int();
- else
- scan_normal_dimen();
- n = cur_val;
- if (n < 0)
- if (this_if == if_abs_dim_code || this_if == if_abs_num_code)
+ case if_char_code:
+ case if_cat_code:
+ /* Test if two characters match */
+ get_x_token_or_active_char();
+ if ((cur_cmd > active_char_cmd) || (cur_chr > biggest_char)) {
+ /*not a character */
+ m = relax_cmd;
+ n = too_big_char;
+ } else {
+ m = cur_cmd;
+ n = cur_chr;
+ }
+ get_x_token_or_active_char();
+ if ((cur_cmd > active_char_cmd) || (cur_chr > biggest_char)) {
+ cur_cmd = relax_cmd;
+ cur_chr = too_big_char;
+ }
+ if (this_if == if_char_code)
+ b = (n == cur_chr);
+ else
+ b = (m == cur_cmd);
+ break;
+ case if_int_code:
+ case if_dim_code:
+ case if_abs_dim_code:
+ case if_abs_num_code:
+ /* Test relation between integers or dimensions */
+ /* Here we use the fact that |"<"|, |"="|, and |">"| are consecutive ASCII codes. */
+ if (this_if == if_int_code || this_if == if_abs_num_code)
+ scan_int();
+ else
+ scan_normal_dimen();
+ n = cur_val;
+ if ((n < 0) && (this_if == if_abs_dim_code || this_if == if_abs_num_code))
negate(n);
-
- /* Get the next non-blank non-call... */
- do {
- get_x_token();
- } while (cur_cmd == spacer_cmd);
-
- if ((cur_tok >= other_token + '<') && (cur_tok <= other_token + '>')) {
+ /* Get the next non-blank non-call... */
+ do {
+ get_x_token();
+ } while (cur_cmd == spacer_cmd);
+ /*
+ if ((cur_tok >= other_token + '<') && (cur_tok <= other_token + '>')) {
+ r = cur_tok - other_token;
+ } else {
+ */
r = cur_tok - other_token;
- } else {
- print_err("Missing = inserted for ");
- print_cmd_chr(if_test_cmd, this_if);
- help1("I was expecting to see `<', `=', or `>'. Didn't.");
- back_error();
- r = '=';
- }
- if (this_if == if_int_code || this_if == if_abs_num_code)
- scan_int();
- else
- scan_normal_dimen();
-
- if (cur_val < 0)
- if (this_if == if_abs_dim_code || this_if == if_abs_num_code)
+ if ((r < '<') || (r > '>')) {
+ print_err("Missing = inserted for ");
+ print_cmd_chr(if_test_cmd, this_if);
+ help1("I was expecting to see `<', `=', or `>'. Didn't.");
+ back_error();
+ r = '=';
+ }
+ if (this_if == if_int_code || this_if == if_abs_num_code)
+ scan_int();
+ else
+ scan_normal_dimen();
+ if ((cur_val < 0) && (this_if == if_abs_dim_code || this_if == if_abs_num_code))
negate(cur_val);
-
- switch (r) {
- case '<':
- b = (n < cur_val);
+ switch (r) {
+ case '<':
+ b = (n < cur_val);
+ break;
+ case '=':
+ b = (n == cur_val);
+ break;
+ case '>':
+ b = (n > cur_val);
+ break;
+ default:
+ /* can't happen */
+ b = false;
+ break;
+ }
+ break;
+ case if_odd_code:
+ /* Test if an integer is odd */
+ scan_int();
+ b = odd(cur_val);
break;
- case '=':
- b = (n == cur_val);
+ case if_vmode_code:
+ b = (abs(cur_list.mode_field) == vmode);
break;
- case '>':
- b = (n > cur_val);
+ case if_hmode_code:
+ b = (abs(cur_list.mode_field) == hmode);
break;
- default:
- b = false;
- break; /*can't happen */
- }
- break;
- case if_odd_code:
- /* Test if an integer is odd */
- scan_int();
- b = odd(cur_val);
- break;
- case if_vmode_code:
- b = (abs(cur_list.mode_field) == vmode);
- break;
- case if_hmode_code:
- b = (abs(cur_list.mode_field) == hmode);
- break;
- case if_mmode_code:
- b = (abs(cur_list.mode_field) == mmode);
- break;
- case if_inner_code:
- b = (cur_list.mode_field < 0);
- break;
- case if_void_code:
- case if_hbox_code:
- case if_vbox_code:
- /* Test box register status */
- scan_register_num();
- p = box(cur_val);
- if (this_if == if_void_code)
+ case if_mmode_code:
+ b = (abs(cur_list.mode_field) == mmode);
+ break;
+ case if_inner_code:
+ b = (cur_list.mode_field < 0);
+ break;
+ /*
+ case if_void_code:
+ case if_hbox_code:
+ case if_vbox_code:
+ scan_register_num();
+ p = box(cur_val);
+ if (this_if == if_void_code)
+ b = (p == null);
+ else if (p == null)
+ b = false;
+ else if (this_if == if_hbox_code)
+ b = (type(p) == hlist_node);
+ else
+ b = (type(p) == vlist_node);
+ break;
+ */
+ case if_void_code:
+ scan_register_num();
+ p = box(cur_val);
b = (p == null);
- else if (p == null)
- b = false;
- else if (this_if == if_hbox_code)
- b = (type(p) == hlist_node);
- else
- b = (type(p) == vlist_node);
- break;
- case ifx_code:
- /* Test if two tokens match */
- /* Note that `\.{\\ifx}' will declare two macros different if one is \\{long}
- or \\{outer} and the other isn't, even though the texts of the macros are
- the same.
-
- We need to reset |scanner_status|, since \.{\\outer} control sequences
- are allowed, but we might be scanning a macro definition or preamble.
- */
- save_scanner_status = scanner_status;
- scanner_status = normal;
- get_next(); /* get_token_lua(); */
- n = cur_cs;
- p = cur_cmd;
- q = cur_chr;
- get_next(); /* get_token_lua(); */
- if (cur_cmd != p) {
- b = false;
- } else if (cur_cmd < call_cmd) {
- b = (cur_chr == q);
- } else {
- /* Test if two macro texts match */
- /* Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
- different in examples like this:
- $$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
- {}\\def\\a\{\\c\}&
- {}\\def\\c\{\}\cr
- {}\\def\\b\{\\d\}&
- {}\\def\\d\{\}\cr}}$$ */
- p = token_link(cur_chr);
- q = token_link(equiv(n)); /*omit reference counts */
- if (p == q) {
- b = true;
+ break;
+ case if_hbox_code:
+ scan_register_num();
+ p = box(cur_val);
+ b = (p != null) && (type(p) == hlist_node);
+ break;
+ case if_vbox_code:
+ scan_register_num();
+ p = box(cur_val);
+ b = (p != null) && (type(p) == vlist_node);
+ break;
+ case ifx_code:
+ /*
+ Test if two tokens match
+
+ Note that `\.{\\ifx}' will declare two macros different if one is \\{long}
+ or \\{outer} and the other isn't, even though the texts of the macros are
+ the same.
+
+ We need to reset |scanner_status|, since \.{\\outer} control sequences
+ are allowed, but we might be scanning a macro definition or preamble.
+ */
+ save_scanner_status = scanner_status;
+ scanner_status = normal;
+ get_next();
+ n = cur_cs;
+ p = cur_cmd;
+ q = cur_chr;
+ get_next();
+ if (cur_cmd != p) {
+ b = false;
+ } else if (cur_cmd < call_cmd) {
+ b = (cur_chr == q);
} else {
- while ((p != null) && (q != null)) {
- if (token_info(p) != token_info(q)) {
- p = null;
- } else {
- p = token_link(p);
- q = token_link(q);
+ /*
+ Test if two macro texts match
+
+ Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are
+ different in examples like this:
+
+ $$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr
+ {}\\def\\a\{\\c\}&
+ {}\\def\\c\{\}\cr
+ {}\\def\\b\{\\d\}&
+ {}\\def\\d\{\}\cr}}$$
+ */
+ p = token_link(cur_chr);
+ /*omit reference counts */
+ q = token_link(equiv(n));
+ if (p == q) {
+ b = true;
+ } else {
+ while ((p != null) && (q != null)) {
+ if (token_info(p) != token_info(q)) {
+ p = null;
+ break;
+ } else {
+ p = token_link(p);
+ q = token_link(q);
+ }
}
+ b = ((p == null) && (q == null));
}
- b = ((p == null) && (q == null));
}
- }
- scanner_status = save_scanner_status;
- break;
- case if_eof_code:
- scan_four_bit_int();
- b = (read_open[cur_val] == closed);
- break;
- case if_true_code:
- b = true;
- break;
- case if_false_code:
- b = false;
- break;
- case if_case_code:
- /* Select the appropriate case
- and |return| or |goto common_ending| */
- scan_int();
- n = cur_val; /*|n| is the number of cases to pass */
- if (int_par(tracing_commands_code) > 1) {
- begin_diagnostic();
- tprint("{case ");
- print_int(n);
- print_char('}');
- end_diagnostic(false);
- }
- while (n != 0) {
- pass_text();
- if (cond_ptr == save_cond_ptr) {
- if (cur_chr == or_code)
- decr(n);
- else
- goto COMMON_ENDING;
- } else if (cur_chr == fi_code) {
- pop_condition_stack();
+ scanner_status = save_scanner_status;
+ break;
+ case if_eof_code:
+ scan_four_bit_int();
+ b = (read_open[cur_val] == closed);
+ break;
+ case if_true_code:
+ b = true;
+ break;
+ case if_false_code:
+ b = false;
+ break;
+ case if_case_code:
+ /* Select the appropriate case and |return| or |goto common_ending| */
+ scan_int();
+ /* |n| is the number of cases to pass */
+ n = cur_val;
+ if (int_par(tracing_commands_code) > 1) {
+ begin_diagnostic();
+ tprint("{case ");
+ print_int(n);
+ print_char('}');
+ end_diagnostic(false);
}
- }
- change_if_limit(or_code, save_cond_ptr);
- return; /*wait for \.{\\or}, \.{\\else}, or \.{\\fi} */
- break;
- case if_primitive_code:
- save_scanner_status = scanner_status;
- scanner_status = normal;
- get_next(); /* get_token_lua(); */
- scanner_status = save_scanner_status;
- m = prim_lookup(cs_text(cur_cs));
- b = ((cur_cmd != undefined_cs_cmd) &&
- (m != undefined_primitive) &&
- (cur_cmd == get_prim_eq_type(m)) &&
- (cur_chr == get_prim_equiv(m)));
- break;
- case if_def_code:
- /* The conditional \.{\\ifdefined} tests if a control sequence is defined. */
- /* We need to reset |scanner_status|, since \.{\\outer} control sequences
- are allowed, but we might be scanning a macro definition or preamble. */
- save_scanner_status = scanner_status;
- scanner_status = normal;
- get_next(); /* get_token_lua(); */
- b = (cur_cmd != undefined_cs_cmd);
- scanner_status = save_scanner_status;
- break;
- case if_cs_code:
- b = test_for_cs();
- break;
- case if_in_csname_code:
- b = is_in_csname;
- break;
- case if_font_char_code:
- /* The conditional \.{\\iffontchar} tests the existence of a character in
- a font. */
- scan_font_ident();
- n = cur_val;
- scan_char_num();
- b = char_exists(n, cur_val);
- break;
- default: /* there are no other cases, but for -Wall: */
- b = false;
+ while (n != 0) {
+ pass_text();
+ if (cond_ptr == save_cond_ptr) {
+ if (cur_chr == or_code)
+ decr(n);
+ else
+ goto COMMON_ENDING;
+ } else if (cur_chr == fi_code) {
+ pop_condition_stack();
+ }
+ }
+ change_if_limit(or_code, save_cond_ptr);
+ /*wait for \.{\\or}, \.{\\else}, or \.{\\fi} */
+ return;
+ break;
+ case if_primitive_code:
+ save_scanner_status = scanner_status;
+ scanner_status = normal;
+ get_next();
+ scanner_status = save_scanner_status;
+ m = prim_lookup(cs_text(cur_cs));
+ b = ((cur_cmd != undefined_cs_cmd) &&
+ (m != undefined_primitive) &&
+ (cur_cmd == get_prim_eq_type(m)) &&
+ (cur_chr == get_prim_equiv(m)));
+ break;
+ case if_def_code:
+ /*
+ The conditional \.{\\ifdefined} tests if a control sequence is defined.
+ We need to reset |scanner_status|, since \.{\\outer} control sequences
+ are allowed, but we might be scanning a macro definition or preamble.
+ */
+ save_scanner_status = scanner_status;
+ scanner_status = normal;
+ get_next();
+ b = (cur_cmd != undefined_cs_cmd);
+ scanner_status = save_scanner_status;
+ break;
+ case if_cs_code:
+ b = test_for_cs();
+ break;
+ case if_in_csname_code:
+ b = is_in_csname;
+ break;
+ case if_font_char_code:
+ /*
+ The conditional \.{\\iffontchar} tests the existence of a character in
+ a font.
+ */
+ scan_font_ident();
+ n = cur_val;
+ scan_char_num();
+ b = char_exists(n, cur_val);
+ break;
+ default:
+ /* there are no other cases, but for -Wall: */
+ b = false;
}
-
if (is_unless)
b = !b;
if (int_par(tracing_commands_code) > 1) {
@@ -505,14 +519,16 @@ void conditional(void)
}
if (b) {
change_if_limit(else_code, save_cond_ptr);
- return; /*wait for \.{\\else} or \.{\\fi} */
+ /*wait for \.{\\else} or \.{\\fi} */
+ return;
}
- /* Skip to \.{\\else} or \.{\\fi}, then |goto common_ending| */
/*
- In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
- \.{\\else} that we come to after learning that the \.{\\if} is false is
- not the \.{\\else} we're looking for. Hence the following curious
- logic is needed.
+ Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|
+
+ In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first
+ \.{\\else} that we come to after learning that the \.{\\if} is false is
+ not the \.{\\else} we're looking for. Hence the following curious
+ logic is needed.
*/
while (1) {
pass_text();
@@ -527,8 +543,10 @@ void conditional(void)
}
}
COMMON_ENDING:
- if (cur_chr == fi_code)
+ if (cur_chr == fi_code) {
pop_condition_stack();
- else
- if_limit = fi_code; /*wait for \.{\\fi} */
+ } else {
+ /*wait for \.{\\fi} */
+ if_limit = fi_code;
+ }
}