1use std::rc::Rc;
5
6use retex_arith::{self as arith, MAX_DIMEN, UNITY};
7
8use crate::Engine;
9use crate::cmd::Cmd;
10use crate::eqtb::Loc;
11use crate::glue::{self, Glue};
12use crate::hash::NO_CS;
13use crate::input::{ScannerStatus, TokKind};
14use crate::primitives_gen as pg;
15use crate::token::{Token, TokenList};
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
19pub enum ValLevel {
20 #[default]
22 Int = 0,
23 Dimen = 1,
25 Glue = 2,
27 Mu = 3,
29 Ident = 4,
31 Tok = 5,
33}
34
35pub const REG_OFFSET: u32 = 0x1_0000;
38
39#[allow(missing_docs)]
41pub mod reg {
42 pub const COUNT: u32 = 0;
43 pub const ATTRIBUTE: u32 = 1;
44 pub const DIMEN: u32 = 2;
45 pub const SKIP: u32 = 3;
46 pub const MUSKIP: u32 = 4;
47}
48
49#[allow(missing_docs)]
51pub mod last_item {
52 pub const LAST_PENALTY: u32 = 0;
53 pub const LAST_KERN: u32 = 2;
54 pub const LAST_SKIP: u32 = 3;
55 pub const LAST_NODE_TYPE: u32 = 4;
56 pub const INPUT_LINE_NO: u32 = 5;
57 pub const BADNESS: u32 = 6;
58 pub const LAST_SAVED_BOX_RESOURCE_INDEX: u32 = 7;
59 pub const LAST_SAVED_IMAGE_RESOURCE_INDEX: u32 = 8;
60 pub const LAST_SAVED_IMAGE_RESOURCE_PAGES: u32 = 9;
61 pub const LAST_X_POS: u32 = 10;
62 pub const LAST_Y_POS: u32 = 11;
63 pub const RANDOM_SEED: u32 = 12;
64 pub const LUATEX_VERSION: u32 = 13;
65 pub const ETEX_MINOR_VERSION: u32 = 14;
66 pub const ETEX_VERSION: u32 = 15;
67 pub const CURRENT_GROUP_LEVEL: u32 = 16;
68 pub const CURRENT_GROUP_TYPE: u32 = 17;
69 pub const CURRENT_IF_LEVEL: u32 = 18;
70 pub const CURRENT_IF_TYPE: u32 = 19;
71 pub const CURRENT_IF_BRANCH: u32 = 20;
72 pub const GLUE_STRETCH_ORDER: u32 = 21;
73 pub const GLUE_SHRINK_ORDER: u32 = 22;
74 pub const ETEX_GLUE_STRETCH_ORDER: u32 = 23;
75 pub const ETEX_GLUE_SHRINK_ORDER: u32 = 24;
76 pub const FONT_CHAR_WD: u32 = 25;
77 pub const FONT_CHAR_HT: u32 = 26;
78 pub const FONT_CHAR_DP: u32 = 27;
79 pub const FONT_CHAR_IC: u32 = 28;
80 pub const PAR_SHAPE_LENGTH: u32 = 29;
81 pub const PAR_SHAPE_INDENT: u32 = 30;
82 pub const PAR_SHAPE_DIMEN: u32 = 31;
83 pub const GLUE_STRETCH: u32 = 32;
84 pub const GLUE_SHRINK: u32 = 33;
85 pub const MU_TO_GLUE: u32 = 34;
86 pub const GLUE_TO_MU: u32 = 35;
87 pub const NUM_EXPR: u32 = 36;
88 pub const DIM_EXPR: u32 = 38;
89 pub const GLUE_EXPR: u32 = 39;
90 pub const MU_EXPR: u32 = 40;
91}
92
93pub const LUATEX_VERSION: i32 = 122;
95pub const LUATEX_REVISION: &str = "0";
97pub const ETEX_VERSION: i32 = 2;
99pub const ETEX_MINOR_VERSION: i32 = 6;
101pub const ETEX_REVISION: &str = ".6";
103
104impl Engine {
105 pub fn get_nonblank_noncall(&mut self) {
109 loop {
110 self.get_x_token();
111 if self.cur_cmd != Cmd::Spacer {
112 break;
113 }
114 }
115 }
116
117 pub fn get_nonblank_or_protected(&mut self) {
121 loop {
122 self.get_token();
123 if self.cur_cmd <= Cmd::MAX_COMMAND {
124 if self.cur_cmd == Cmd::Spacer {
125 continue;
126 }
127 return;
128 }
129 if self.cur_cmd >= Cmd::Call
130 && self.cur_cmd < Cmd::EndTemplate
131 && self
132 .eqtb
133 .meaning(self.cur_cs)
134 .mac
135 .as_ref()
136 .is_some_and(|m| m.protected)
137 {
138 return;
139 }
140 self.expand();
141 }
142 }
143
144 pub fn get_nonblank_nonrelax_noncall(&mut self) {
146 loop {
147 self.get_x_token();
148 if self.cur_cmd != Cmd::Spacer && self.cur_cmd != Cmd::Relax {
149 break;
150 }
151 }
152 }
153
154 pub fn scan_optional_space(&mut self) {
156 self.get_x_token();
157 if self.cur_cmd != Cmd::Spacer {
158 self.back_input();
159 }
160 }
161
162 pub fn scan_left_brace(&mut self) {
164 self.get_nonblank_nonrelax_noncall();
165 if self.cur_cmd != Cmd::LeftBrace {
166 self.print_err("Missing { inserted");
167 self.help(&[
168 "A left brace was mandatory here, so I've put one in.",
169 "You might want to delete and/or insert some corrections",
170 "so that I will find a matching right brace soon.",
171 "If you're confused by all this, try typing `I}' now.",
173 ]);
174 self.back_error();
175 self.cur_tok = Token::LEFT_BRACE;
176 self.cur_cmd = Cmd::LeftBrace;
177 self.cur_chr = '{' as u32;
178 self.input.align_state += 1;
179 }
180 }
181
182 pub fn scan_optional_equals(&mut self) {
184 self.get_nonblank_noncall();
185 if self.cur_tok != Token::other('=' as u32) {
186 self.back_input();
187 }
188 }
189
190 pub fn scan_keyword(&mut self, s: &str) -> bool {
192 let mut matched = [Token(0); 32];
194 let bytes = s.as_bytes();
195 if bytes.len() > matched.len() {
196 return self.scan_long_keyword(bytes);
198 }
199 let mut k = 0;
200 while k < bytes.len() {
201 self.get_x_token();
202 let c = u32::from(bytes[k]);
203 let upper = if bytes[k].is_ascii_lowercase() {
204 c - 32
205 } else {
206 c
207 };
208 if self.cur_cs == NO_CS && (self.cur_chr == c || self.cur_chr == upper) {
209 matched[k] = self.cur_tok;
210 k += 1;
211 } else if self.cur_cmd != Cmd::Spacer || k > 0 {
212 self.back_input();
213 if k > 0 {
214 self.back_list(Rc::from(&matched[..k]));
215 }
216 return false;
217 }
218 }
219 true
220 }
221
222 #[cold]
224 fn scan_long_keyword(&mut self, bytes: &[u8]) -> bool {
225 let mut matched = Vec::new();
226 while matched.len() < bytes.len() {
227 self.get_x_token();
228 let b = bytes[matched.len()];
229 let c = u32::from(b);
230 let upper = if b.is_ascii_lowercase() { c - 32 } else { c };
231 if self.cur_cs == NO_CS && (self.cur_chr == c || self.cur_chr == upper) {
232 matched.push(self.cur_tok);
233 } else if self.cur_cmd != Cmd::Spacer || !matched.is_empty() {
234 self.back_input();
235 if !matched.is_empty() {
236 self.back_list(Rc::from(matched));
237 }
238 return false;
239 }
240 }
241 true
242 }
243
244 pub fn back_list(&mut self, list: TokenList) {
246 self.begin_token_list(list, TokKind::BackedUp);
247 }
248
249 pub fn mu_error(&mut self) {
251 self.print_err("Incompatible glue units");
252 self.help(&["I'm going to assume that 1mu=1pt when they're mixed."]);
253 self.error();
254 }
255
256 #[inline]
260 pub fn scan_int(&mut self) {
261 self.get_nonblank_noncall();
262 if self.cur_cmd.is_internal() {
264 self.scan_something_internal(ValLevel::Int, false);
265 } else {
266 self.scan_int_from_first();
267 }
268 }
269
270 #[inline(never)]
273 fn scan_int_from_first(&mut self) {
274 let mut ok_so_far = true;
275 let mut negative = false;
277 let mut first = true;
278 loop {
279 if !first {
280 self.get_nonblank_noncall();
281 }
282 first = false;
283 if self.cur_tok == Token::other('-' as u32) {
284 negative = !negative;
285 self.cur_tok = Token::other('+' as u32);
286 }
287 if self.cur_tok != Token::other('+' as u32) {
288 break;
289 }
290 }
291 if self.cur_tok == Token::other('`' as u32) {
292 self.get_token();
294 if self.cur_tok.0 < crate::token::CS_TOKEN_FLAG {
295 self.cur_val = self.cur_chr as i32;
296 if self.cur_cmd <= Cmd::RightBrace {
297 if self.cur_cmd == Cmd::RightBrace {
298 self.input.align_state += 1;
299 } else {
300 self.input.align_state -= 1;
301 }
302 }
303 } else {
304 let cs = self.cur_tok.cs_id();
305 self.cur_val = match self.hash.kind(cs) {
306 crate::hash::CsKind::Active(c) | crate::hash::CsKind::Single(c) => *c as i32,
307 _ => 0x11_0000,
308 };
309 }
310 if self.cur_val > 0x10_FFFF {
311 self.print_err("Improper alphabetic constant");
312 self.help(&[
313 "A one-character control sequence belongs after a ` mark.",
314 "So I'm essentially inserting \\0 here.",
315 ]);
316 self.cur_val = '0' as i32;
317 self.back_error();
318 } else {
319 self.scan_optional_space();
320 }
321 } else if self.cur_cmd.is_internal() {
322 self.scan_something_internal(ValLevel::Int, false);
323 } else if self.cur_cmd == Cmd::MathStyle {
324 self.cur_val = self.cur_chr as i32;
326 } else {
327 let mut radix: i64 = 10;
329 let mut m: i64 = 214_748_364;
330 if self.cur_tok == Token::other('\'' as u32) {
331 radix = 8;
332 m = 0o2000000000;
333 self.get_x_token();
334 } else if self.cur_tok == Token::other('"' as u32) {
335 radix = 16;
336 m = 0o1000000000;
337 self.get_x_token();
338 }
339 let mut vacuous = true;
340 let mut val: i64 = 0;
341 loop {
342 let t = self.cur_tok;
343 let d: i64 = if !t.is_cs()
344 && t.cmd() == Cmd::OtherChar
345 && (0x30..=0x39).contains(&t.chr())
346 && i64::from(t.chr() - 0x30) < radix
347 {
348 i64::from(t.chr() - 0x30)
349 } else if radix == 16
350 && !t.is_cs()
351 && (t.cmd() == Cmd::Letter || t.cmd() == Cmd::OtherChar)
352 && (0x41..=0x46).contains(&t.chr())
353 {
354 i64::from(t.chr() - 0x41 + 10)
355 } else {
356 break;
357 };
358 vacuous = false;
359 if val >= m && (val > m || d > 7 || radix != 10) {
360 if ok_so_far {
361 self.print_err("Number too big");
362 self.help(&[
363 "I can only go up to 2147483647='17777777777=\"7FFFFFFF,",
364 "so I'm using that number instead of yours.",
365 ]);
366 self.error();
367 val = i64::from(arith::INFINITY);
368 ok_so_far = false;
369 }
370 } else {
371 val = val * radix + d;
372 }
373 self.get_x_token();
374 }
375 self.cur_val = val as i32;
376 if vacuous {
377 self.missing_number();
378 } else if self.cur_cmd != Cmd::Spacer {
379 self.back_input();
380 }
381 }
382 if negative {
383 self.cur_val = self.cur_val.wrapping_neg();
384 }
385 }
386
387 fn missing_number(&mut self) {
389 self.print_err("Missing number, treated as zero");
390 self.help(&[
391 "A number should have been here; I inserted `0'.",
392 "(If you can't figure out why I needed to see a number,",
393 "look up `weird error' in the index to The TeXbook.)",
394 ]);
395 self.back_error();
396 }
397
398 fn scan_limited(&mut self, max: i32, what: &str, help: &'static str) {
399 self.scan_int();
400 if self.cur_val < 0 || self.cur_val > max {
401 self.print_err(&format!("Bad {what} ("));
402 self.printer.print_int(self.cur_val.into());
403 self.printer.print_char(')' as u32);
404 self.help(&[help, "I changed this one to zero."]);
405 self.int_error_zero();
406 }
407 }
408
409 fn int_error_zero(&mut self) {
410 self.error();
411 self.cur_val = 0;
412 }
413
414 pub fn scan_register_num(&mut self) {
416 self.scan_limited(
417 65535,
418 "register code",
419 "A register code must be between 0 and 65535.",
420 );
421 }
422
423 pub fn scan_char_num(&mut self) {
425 self.scan_limited(
426 0x10_FFFF,
427 "character code",
428 "A character code must be between 0 and 1114111.",
429 );
430 }
431
432 pub fn scan_four_bit_int(&mut self) {
434 self.scan_limited(
435 15,
436 "number",
437 "Since I expected to read a number between 0 and 15,",
438 );
439 }
440
441 pub fn scan_four_bit_int_or_more(&mut self) {
444 self.scan_int();
445 }
446
447 pub fn scan_math_given(&mut self) -> u32 {
457 self.scan_int();
458 let v = self.cur_val;
459 let g = if v < 0 {
460 self.print_err("Bad mathchar (");
461 self.printer.print_int(v.into());
462 self.printer.print_char(')' as u32);
463 0
464 } else if v <= 0x8000 {
465 return v as u32;
466 } else if crate::codes::math_char(v.into()) > 0x10FFFF {
467 self.print_err("Invalid math code during > 0x8000 mathcode fallback");
468 0
469 } else {
470 v as u32 | crate::codes::MATH_GIVEN_PACKED
471 };
472 if g == 0 {
473 self.help(&["I'm going to use 0 instead of that illegal code value."]);
474 self.error();
475 }
476 self.cur_val = crate::codes::math_given_report(g);
477 g
478 }
479
480 pub fn scan_twenty_seven_bit_int(&mut self) {
482 self.scan_int();
483 if self.cur_val < 0 || self.cur_val > 0o777777777 {
484 self.print_err("Bad delimiter code (");
485 self.printer.print_int(self.cur_val.into());
486 self.printer.print_char(')' as u32);
487 self.help(&[
488 "A numeric delimiter code must be between 0 and 2^{27}-1.",
489 "I changed this one to zero.",
490 ]);
491 self.int_error_zero();
492 }
493 }
494
495 pub fn scan_math_family(&mut self) {
497 self.scan_limited(255, "number", "A family number must be between 0 and 255.");
498 }
499
500 pub fn scan_category_code(&mut self) {
502 self.scan_limited(
503 15,
504 "category code",
505 "A category code must be between 0 and 15.",
506 );
507 }
508
509 pub fn scan_normal_dimen(&mut self) {
513 self.scan_dimen(false, false, false);
514 }
515
516 pub fn scan_dimen(&mut self, mu: bool, inf: bool, shortcut: bool) -> glue::GlueOrder {
521 let mut f: i32 = 0;
522 let mut arith_error = false;
523 let mut cur_order = glue::NORMAL;
524 let mut negative = false;
525 'attach_sign: {
526 if !shortcut {
527 negative = false;
528 loop {
529 self.get_nonblank_noncall();
530 if self.cur_tok == Token::other('-' as u32) {
531 negative = !negative;
532 self.cur_tok = Token::other('+' as u32);
533 }
534 if self.cur_tok != Token::other('+' as u32) {
535 break;
536 }
537 }
538 if self.cur_cmd.is_internal() {
539 if mu {
540 self.scan_something_internal(ValLevel::Mu, false);
541 if self.cur_val_level >= ValLevel::Glue {
542 self.cur_val = self.cur_glue.width;
543 }
544 if self.cur_val_level == ValLevel::Mu {
545 break 'attach_sign;
546 }
547 if self.cur_val_level != ValLevel::Int {
548 self.mu_error();
549 }
550 } else {
551 self.scan_something_internal(ValLevel::Dimen, false);
552 if self.cur_val_level == ValLevel::Dimen {
553 break 'attach_sign;
554 }
555 }
556 } else {
557 self.back_input();
558 if self.cur_tok == Token::other(',' as u32) {
559 self.cur_tok = Token::other('.' as u32);
560 }
561 let mut radix10 = true;
562 if self.cur_tok != Token::other('.' as u32) {
563 self.scan_int_radix(&mut radix10);
564 } else {
565 self.cur_val = 0;
566 }
567 if self.cur_tok == Token::other(',' as u32) {
568 self.cur_tok = Token::other('.' as u32);
569 }
570 if radix10 && self.cur_tok == Token::other('.' as u32) {
571 let mut digits: Vec<u8> = Vec::new();
573 self.get_token(); loop {
575 self.get_x_token();
576 let t = self.cur_tok;
577 if t.is_cs()
578 || t.cmd() != Cmd::OtherChar
579 || !(0x30..=0x39).contains(&t.chr())
580 {
581 break;
582 }
583 if digits.len() < 17 {
584 digits.push((t.chr() - 0x30) as u8);
585 }
586 }
587 f = arith::round_decimals(&digits);
588 if self.cur_cmd != Cmd::Spacer {
589 self.back_input();
590 }
591 }
592 }
593 }
594 if self.cur_val < 0 {
595 negative = !negative;
596 self.cur_val = self.cur_val.wrapping_neg();
597 }
598 'attach_fraction: {
600 'done: {
601 if inf && self.scan_keyword("fi") {
602 cur_order = glue::FI;
603 while self.scan_keyword("l") {
604 if cur_order == glue::FILLL {
605 break;
606 }
607 cur_order += 1;
608 }
609 break 'attach_fraction;
610 }
611 let save_cur_val = self.cur_val;
613 self.get_nonblank_noncall();
614 let v: i32;
615 if !self.cur_cmd.is_internal() {
616 self.back_input();
617 if mu {
618 if !self.scan_keyword("mu") {
620 self.print_err("Illegal unit of measure (");
621 self.printer.print_str("mu inserted)");
622 self.help(&[
623 "The unit of measurement in math glue must be mu.",
624 "To recover gracefully from this error, it's best to",
625 "delete the erroneous units; e.g., type `2' to delete",
626 "two letters. (See Chapter 27 of The TeXbook.)",
627 ]);
628 self.error();
629 }
630 break 'attach_fraction;
631 }
632 if self.scan_keyword("em") {
633 v = self.quad(self.eqtb.cur_font.val);
634 self.scan_optional_space();
635 } else if self.scan_keyword("ex") {
636 v = self.x_height(self.eqtb.cur_font.val);
637 self.scan_optional_space();
638 } else if self.scan_keyword("px") {
639 v = self.eqtb.dimen(pg::assign_dimen::PXDIMEN);
640 self.scan_optional_space();
641 } else {
642 if self.scan_keyword("true") {
644 self.prepare_mag();
645 let mag = self.eqtb.int(pg::assign_int::MAG);
646 if mag != 1000 {
647 match arith::xn_over_d(self.cur_val, 1000, mag) {
648 Ok(r) => {
649 self.cur_val = r.quotient;
650 f = ((1000 * i64::from(f)
651 + 0o200000 * i64::from(r.remainder))
652 / i64::from(mag))
653 as i32;
654 }
655 Err(_) => arith_error = true,
656 }
657 self.cur_val += f / 0o200000;
658 f %= 0o200000;
659 }
660 }
661 if self.scan_keyword("pt") {
662 break 'attach_fraction;
663 }
664 let (num, denom): (i32, i32) = if self.scan_keyword("in") {
665 (7227, 100)
666 } else if self.scan_keyword("pc") {
667 (12, 1)
668 } else if self.scan_keyword("cm") {
669 (7227, 254)
670 } else if self.scan_keyword("mm") {
671 (7227, 2540)
672 } else if self.scan_keyword("bp") {
673 (7227, 7200)
674 } else if self.scan_keyword("dd") {
675 (1238, 1157)
676 } else if self.scan_keyword("cc") {
677 (14856, 1157)
678 } else if self.scan_keyword("nd") {
679 (685, 642)
680 } else if self.scan_keyword("nc") {
681 (1370, 107)
682 } else if self.scan_keyword("sp") {
683 break 'done;
684 } else {
685 self.print_err("Illegal unit of measure (");
686 self.printer.print_str("pt inserted)");
687 self.help(&[
688 "Dimensions can be in units of em, ex, in, pt, pc,",
689 "cm, mm, dd, cc, nd, nc, bp, or sp; but yours is a new one!",
690 "I'll assume that you meant to say pt, for printer's points.",
691 "To recover gracefully from this error, it's best to",
692 "delete the erroneous units; e.g., type `2' to delete",
693 "two letters. (See Chapter 27 of The TeXbook.)",
694 ]);
695 self.error();
696 break 'attach_fraction;
697 };
698 match arith::xn_over_d(self.cur_val, num, denom) {
699 Ok(r) => {
700 self.cur_val = r.quotient;
701 f = ((i64::from(num) * i64::from(f)
702 + 0o200000 * i64::from(r.remainder))
703 / i64::from(denom))
704 as i32;
705 }
706 Err(_) => arith_error = true,
707 }
708 self.cur_val = self.cur_val.wrapping_add(f / 0o200000);
709 f %= 0o200000;
710 break 'attach_fraction;
711 }
712 } else {
713 if mu {
714 self.scan_something_internal(ValLevel::Mu, false);
715 if self.cur_val_level >= ValLevel::Glue {
716 self.cur_val = self.cur_glue.width;
717 }
718 if self.cur_val_level != ValLevel::Mu {
719 self.mu_error();
720 }
721 } else {
722 self.scan_something_internal(ValLevel::Dimen, false);
723 }
724 v = self.cur_val;
725 }
726 let frac = arith::xn_over_d(v, f, 0o200000)
728 .map(|r| r.quotient)
729 .unwrap_or_else(|_| {
730 arith_error = true;
731 0
732 });
733 self.cur_val = arith::nx_plus_y(save_cur_val, v, frac).unwrap_or_else(|_| {
734 arith_error = true;
735 0
736 });
737 break 'attach_sign;
738 }
739 self.scan_optional_space();
741 break 'attach_sign;
742 }
743 if self.cur_val >= 0o40000 {
745 arith_error = true;
746 } else {
747 self.cur_val = self.cur_val * UNITY + f;
748 }
749 self.scan_optional_space();
750 }
751 if arith_error || self.cur_val.wrapping_abs() >= 0o10000000000 || self.cur_val == i32::MIN {
753 self.print_err("Dimension too large");
754 self.help(&[
755 "I can't work with sizes bigger than about 19 feet.",
756 "Continue and I'll use the largest value I can.",
757 ]);
758 self.error();
759 self.cur_val = MAX_DIMEN;
760 }
761 if negative {
762 self.cur_val = -self.cur_val;
763 }
764 cur_order
765 }
766
767 fn scan_int_radix(&mut self, radix10: &mut bool) {
770 self.get_nonblank_noncall();
772 let t = self.cur_tok;
773 *radix10 = !(t == Token::other('\'' as u32)
774 || t == Token::other('"' as u32)
775 || t == Token::other('`' as u32)
776 || self.cur_cmd.is_internal());
777 self.back_input();
778 self.scan_int();
779 }
780
781 pub fn prepare_mag(&mut self) {
783 let mag = self.eqtb.int(pg::assign_int::MAG);
784 if self.mag_set > 0 && mag != self.mag_set {
785 self.print_err("Incompatible magnification (");
786 self.printer.print_int(mag.into());
787 self.printer.print_str(");");
788 self.printer
789 .print_nl(" the previous value will be retained");
790 self.help(&[
791 "I can handle only one magnification ratio per job. So I've",
792 "reverted to the magnification you used earlier on this run.",
793 ]);
794 self.int_error(self.mag_set);
795 self.eqtb.int_par[pg::assign_int::MAG as usize].val = self.mag_set;
796 }
797 let mag = self.eqtb.int(pg::assign_int::MAG);
798 if mag <= 0 || mag > 32768 {
799 self.print_err("Illegal magnification has been changed to 1000");
800 self.help(&["The magnification ratio must be between 1 and 32768."]);
801 self.int_error(mag);
802 self.eqtb.int_par[pg::assign_int::MAG as usize].val = 1000;
803 }
804 self.mag_set = self.eqtb.int(pg::assign_int::MAG);
805 }
806
807 pub fn int_error(&mut self, n: i32) {
809 self.printer.print_str(" (");
810 self.printer.print_int(n.into());
811 self.printer.print_char(')' as u32);
812 self.error();
813 }
814
815 pub fn scan_glue(&mut self, level: ValLevel) {
820 let mu = level == ValLevel::Mu;
821 let mut negative = false;
822 loop {
823 self.get_nonblank_noncall();
824 if self.cur_tok == Token::other('-' as u32) {
825 negative = !negative;
826 self.cur_tok = Token::other('+' as u32);
827 }
828 if self.cur_tok != Token::other('+' as u32) {
829 break;
830 }
831 }
832 if self.cur_cmd.is_internal() {
833 self.scan_something_internal(level, negative);
834 if self.cur_val_level >= ValLevel::Glue {
835 if self.cur_val_level != level {
836 self.mu_error();
837 }
838 return;
839 }
840 if self.cur_val_level == ValLevel::Int {
841 self.scan_dimen(mu, false, true);
842 } else if level == ValLevel::Mu {
843 self.mu_error();
844 }
845 } else {
846 self.back_input();
847 self.scan_dimen(mu, false, false);
848 if negative {
849 self.cur_val = -self.cur_val;
850 }
851 }
852 let mut q = Glue::fixed(self.cur_val);
853 if self.scan_keyword("plus") {
854 let o = self.scan_dimen(mu, true, false);
855 q.stretch = self.cur_val;
856 q.stretch_order = o;
857 }
858 if self.scan_keyword("minus") {
859 let o = self.scan_dimen(mu, true, false);
860 q.shrink = self.cur_val;
861 q.shrink_order = o;
862 }
863 self.cur_glue = q;
864 self.cur_val_level = level;
865 }
866
867 fn scanned(&mut self, v: i32, level: ValLevel) {
871 self.cur_val = v;
872 self.cur_val_level = level;
873 }
874
875 fn scanned_glue(&mut self, g: Glue, level: ValLevel) {
876 self.cur_glue = g;
877 self.cur_val = g.width;
878 self.cur_val_level = level;
879 }
880
881 pub fn scan_something_internal(&mut self, level: ValLevel, negative: bool) {
883 let m = self.cur_chr;
884 match self.cur_cmd {
885 Cmd::DefCharCode => {
886 self.scan_char_num();
887 let c = self.cur_val as u32;
888 use pg::def_char_code as dc;
889 let v = match m {
890 dc::CATCODE => i64::from(self.eqtb.catcode(c)),
891 dc::LCCODE => self.eqtb.lc.get(c),
892 dc::UCCODE => self.eqtb.uc.get(c),
893 dc::SFCODE => self.eqtb.sf.get(c),
894 _ => i64::from(crate::codes::math_code_report(self.eqtb.math.get(c))),
895 };
896 self.scanned(v as i32, ValLevel::Int);
897 }
898 Cmd::DefDelCode | Cmd::ExtdefDelCode => {
899 self.scan_char_num();
900 let v = self.eqtb.del.get(self.cur_val as u32);
901 self.scanned(crate::codes::delcode_report(v, self.cur_cmd), ValLevel::Int);
902 }
903 Cmd::ExtdefMathCode => {
904 self.scan_char_num();
905 let v = self.eqtb.math.get(self.cur_val as u32);
906 self.scanned(crate::codes::math_code_report(v), ValLevel::Int);
907 }
908 Cmd::ToksRegister | Cmd::AssignToks | Cmd::DefFamily | Cmd::SetFont | Cmd::DefFont => {
909 if level != ValLevel::Tok {
910 self.missing_number();
911 self.scanned(0, ValLevel::Dimen);
912 } else if self.cur_cmd <= Cmd::AssignToks {
913 let list = if self.cur_cmd == Cmd::ToksRegister {
914 if m == 0 {
915 self.scan_register_num();
916 self.eqtb.toks[self.cur_val as usize].val.clone()
917 } else {
918 self.eqtb.toks[(m - REG_OFFSET) as usize].val.clone()
919 }
920 } else if m >= REG_OFFSET {
921 self.eqtb.toks[(m - REG_OFFSET) as usize].val.clone()
922 } else {
923 self.eqtb.toks_param(m).clone()
924 };
925 self.cur_toks = Some(list);
926 self.cur_val_level = ValLevel::Tok;
927 } else {
928 self.back_input();
929 self.scan_font_ident();
930 self.cur_val_level = ValLevel::Ident;
931 }
932 }
933 Cmd::AssignInt => {
934 let v = if m >= REG_OFFSET {
935 self.eqtb.count[(m - REG_OFFSET) as usize].val
936 } else {
937 self.eqtb.int(m)
938 };
939 self.scanned(v, ValLevel::Int);
940 }
941 Cmd::AssignAttr => {
942 let v = self.eqtb.attr[(m - REG_OFFSET.min(m)) as usize].val;
943 self.scanned(v, ValLevel::Int);
944 }
945 Cmd::AssignDirection => self.scanned(self.dir_param(m), ValLevel::Int),
946 Cmd::AssignDir => {
947 let d = self.dir_param(m);
951 if level == ValLevel::Tok {
952 let name = crate::showbox::DIR_NAMES[d.rem_euclid(4) as usize];
953 self.cur_toks = Some(crate::the::str_toks(name.as_bytes()).into());
954 self.scanned(0, ValLevel::Tok);
955 } else {
956 self.mu_error();
957 self.scanned(0, ValLevel::Int);
958 }
959 }
960 Cmd::AssignDimen => {
961 let v = if m >= REG_OFFSET {
962 self.eqtb.dimen[(m - REG_OFFSET) as usize].val
963 } else {
964 self.eqtb.dimen(m)
965 };
966 self.scanned(v, ValLevel::Dimen);
967 }
968 Cmd::AssignGlue => {
969 let g = if m >= REG_OFFSET {
970 self.eqtb.skip[(m - REG_OFFSET) as usize].val
971 } else {
972 self.eqtb.glue(m)
973 };
974 self.scanned_glue(g, ValLevel::Glue);
975 }
976 Cmd::AssignMuGlue => {
977 let g = if m >= REG_OFFSET {
978 self.eqtb.muskip[(m - REG_OFFSET) as usize].val
979 } else {
980 self.eqtb.glue(m + crate::eqtb::MU_GLUE_OFFSET)
981 };
982 self.scanned_glue(g, ValLevel::Mu);
983 }
984 Cmd::SetAux => {
985 let v = self.fetch_aux(m);
986 if let Some((v, l)) = v {
987 self.scanned(v, l);
988 } else {
989 self.scanned(
990 0,
991 if m == SET_AUX_PREV_DEPTH {
992 ValLevel::Dimen
993 } else {
994 ValLevel::Int
995 },
996 );
997 }
998 }
999 Cmd::SetPrevGraf => {
1000 let v = self.fetch_prev_graf();
1001 self.scanned(v, ValLevel::Int);
1002 }
1003 Cmd::SetPageInt => {
1004 let v = match m {
1005 0 => self.dead_cycles,
1006 1 => self.insert_penalties,
1007 _ => self.err.interaction as i32,
1008 };
1009 self.scanned(v, ValLevel::Int);
1010 }
1011 Cmd::SetPageDimen => {
1012 let v = self.page_so_far_value(m);
1013 self.scanned(v, ValLevel::Dimen);
1014 }
1015 Cmd::SetTexShape => {
1016 let v = self
1017 .eqtb
1018 .par_shape
1019 .val
1020 .as_ref()
1021 .map_or(0, |s| (s.len() / 2) as i32);
1022 self.scanned(v, ValLevel::Int);
1023 }
1024 Cmd::SetEtexShape => {
1025 self.scan_int();
1026 let n = self.cur_val;
1027 let v = match &self.eqtb.etex_shape[m as usize].val {
1028 None => 0,
1029 Some(_) if n < 0 => 0,
1030 Some(s) => {
1031 let len = s.len() as i32;
1032 if n == 0 {
1033 len
1034 } else {
1035 s[(n.min(len) - 1) as usize]
1036 }
1037 }
1038 };
1039 self.scanned(v, ValLevel::Int);
1040 }
1041 Cmd::SetBoxDimen => {
1042 self.scan_register_num();
1043 let p = self.eqtb.boxes[self.cur_val as usize].val;
1044 let v = if p.is_null() {
1045 0
1046 } else {
1047 let b = self.nodes.box_data(p);
1048 match (m, b) {
1049 (2, Some(b)) => b.width,
1050 (3, Some(b)) => b.depth,
1051 (4, Some(b)) => b.height,
1052 _ => 0,
1053 }
1054 };
1055 self.scanned(v, ValLevel::Dimen);
1056 }
1057 Cmd::CharGiven | Cmd::XmathGiven => {
1058 self.scanned(self.cur_chr as i32, ValLevel::Int);
1059 }
1060 Cmd::MathGiven => {
1061 self.scanned(crate::codes::math_given_report(self.cur_chr), ValLevel::Int);
1062 }
1063 Cmd::AssignFontDimen => {
1064 let v = self.find_font_dimen(false);
1065 self.scanned(v, ValLevel::Dimen);
1066 }
1067 Cmd::AssignFontInt => {
1068 self.scan_font_ident();
1069 let f = self.cur_val as u32;
1070 let v = self.font_int_param(f, m);
1071 self.scanned(v, ValLevel::Int);
1072 }
1073 Cmd::Register => {
1074 self.scan_register_num();
1075 let n = self.cur_val as usize;
1076 match m {
1077 reg::COUNT => self.scanned(self.eqtb.count[n].val, ValLevel::Int),
1078 reg::ATTRIBUTE => self.scanned(self.eqtb.attr[n].val, ValLevel::Int),
1079 reg::DIMEN => self.scanned(self.eqtb.dimen[n].val, ValLevel::Dimen),
1080 reg::SKIP => {
1081 let g = self.eqtb.skip[n].val;
1082 self.scanned_glue(g, ValLevel::Glue);
1083 }
1084 _ => {
1085 let g = self.eqtb.muskip[n].val;
1086 self.scanned_glue(g, ValLevel::Mu);
1087 }
1088 }
1089 }
1090 Cmd::SetMathParam => {
1091 let found = self.scan_math_style();
1093 let style = self.cur_val as u32;
1094 let v = self
1095 .eqtb
1096 .math_param
1097 .get(&(m * 8 + style))
1098 .filter(|_| found)
1099 .map_or(crate::codes::UNDEFINED_MATH_PARAM, |s| s.val);
1100 if crate::codes::math_param_is_glue(m) {
1101 let g = if found && v == crate::codes::UNDEFINED_MATH_PARAM {
1103 let (l, r) = ((m - 49) / 8, (m - 49) % 8);
1104 self.math_spacing(l, r, style)
1105 .map_or(crate::glue::Glue::ZERO, |(g, _)| g)
1106 } else {
1107 self.math_param_glue(v)
1108 };
1109 self.scanned_glue(g, ValLevel::Mu);
1110 } else if m == crate::mathparams::mp::RADICAL_DEGREE_RAISE {
1111 self.scanned(v, ValLevel::Int);
1113 } else {
1114 self.scanned(v, ValLevel::Dimen);
1115 }
1116 }
1117 Cmd::LastItem => self.fetch_last_item(m, level),
1118 _ => {
1119 self.print_err("You can't use `");
1120 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
1121 self.printer.print_str("' after ");
1122 self.print_esc_str("the");
1123 self.help(&["I'm forgetting what you said and using zero instead."]);
1124 self.error();
1125 if level != ValLevel::Tok {
1126 self.scanned(0, ValLevel::Dimen);
1127 } else {
1128 self.scanned(0, ValLevel::Int);
1129 }
1130 }
1131 }
1132 while self.cur_val_level > level {
1134 if self.cur_val_level == ValLevel::Glue {
1135 self.cur_val = self.cur_glue.width;
1136 } else if self.cur_val_level == ValLevel::Mu {
1137 self.mu_error();
1138 }
1139 self.cur_val_level = match self.cur_val_level {
1140 ValLevel::Tok => ValLevel::Ident,
1141 ValLevel::Ident => ValLevel::Mu,
1142 ValLevel::Mu => ValLevel::Glue,
1143 ValLevel::Glue => ValLevel::Dimen,
1144 _ => ValLevel::Int,
1145 };
1146 if self.cur_val_level == ValLevel::Glue || self.cur_val_level == ValLevel::Mu {
1147 }
1149 }
1150 if negative {
1151 if self.cur_val_level >= ValLevel::Glue {
1152 let g = &mut self.cur_glue;
1153 g.width = -g.width;
1154 g.stretch = -g.stretch;
1155 g.shrink = -g.shrink;
1156 self.cur_val = g.width;
1157 } else {
1158 self.cur_val = self.cur_val.wrapping_neg();
1159 }
1160 }
1161 }
1162
1163 fn fetch_last_item(&mut self, m: u32, level: ValLevel) {
1165 use last_item as li;
1166 match m {
1167 li::LAST_PENALTY | li::LAST_KERN | li::LAST_SKIP | li::LAST_NODE_TYPE => {
1168 let (v, g, l) = self.fetch_last_node_item(m);
1169 if l >= ValLevel::Glue {
1170 self.scanned_glue(g, l);
1171 } else {
1172 self.scanned(v, l);
1173 }
1174 }
1175 li::INPUT_LINE_NO => self.scanned(self.input.line(), ValLevel::Int),
1176 li::BADNESS => self.scanned(self.last_badness, ValLevel::Int),
1177 li::LUATEX_VERSION => self.scanned(LUATEX_VERSION, ValLevel::Int),
1178 li::ETEX_VERSION => self.scanned(ETEX_VERSION, ValLevel::Int),
1179 li::ETEX_MINOR_VERSION => self.scanned(ETEX_MINOR_VERSION, ValLevel::Int),
1180 li::CURRENT_GROUP_LEVEL => {
1181 self.scanned(i32::from(self.save.cur_level) - 1, ValLevel::Int)
1182 }
1183 li::CURRENT_GROUP_TYPE => self.scanned(self.save.cur_group as i32, ValLevel::Int),
1184 li::CURRENT_IF_LEVEL => self.scanned(self.cond.stack.len() as i32, ValLevel::Int),
1185 li::CURRENT_IF_TYPE => {
1186 let v = if self.cond.stack.is_empty() {
1187 0
1188 } else if self.cond.cur_if < crate::cond::UNLESS_CODE {
1189 self.cond.cur_if as i32 + 1
1190 } else {
1191 -((self.cond.cur_if - crate::cond::UNLESS_CODE) as i32 + 1)
1192 };
1193 self.scanned(v, ValLevel::Int);
1194 }
1195 li::CURRENT_IF_BRANCH => {
1196 let v = match self.cond.if_limit {
1197 crate::cond::OR_CODE | crate::cond::ELSE_CODE => 1,
1198 crate::cond::FI_CODE => -1,
1199 _ => 0,
1200 };
1201 self.scanned(v, ValLevel::Int);
1202 }
1203 li::RANDOM_SEED => self.scanned(self.random_seed, ValLevel::Int),
1204 li::LAST_X_POS => self.scanned(self.last_x_pos, ValLevel::Int),
1205 li::LAST_Y_POS => self.scanned(self.last_y_pos, ValLevel::Int),
1206 li::LAST_SAVED_BOX_RESOURCE_INDEX
1207 | li::LAST_SAVED_IMAGE_RESOURCE_INDEX
1208 | li::LAST_SAVED_IMAGE_RESOURCE_PAGES => {
1209 self.scanned(self.last_saved_resource(m), ValLevel::Int)
1210 }
1211 li::GLUE_STRETCH_ORDER
1212 | li::GLUE_SHRINK_ORDER
1213 | li::ETEX_GLUE_STRETCH_ORDER
1214 | li::ETEX_GLUE_SHRINK_ORDER => {
1215 self.scan_normal_glue();
1216 let g = self.cur_glue;
1217 let o = if m == li::GLUE_STRETCH_ORDER || m == li::ETEX_GLUE_STRETCH_ORDER {
1218 g.stretch_order
1219 } else {
1220 g.shrink_order
1221 };
1222 let v = if m == li::ETEX_GLUE_STRETCH_ORDER || m == li::ETEX_GLUE_SHRINK_ORDER {
1225 i32::from(o)
1226 } else {
1227 i32::from(o.saturating_sub(1)).max(0)
1228 };
1229 self.scanned(v, ValLevel::Int);
1230 }
1231 li::FONT_CHAR_WD | li::FONT_CHAR_HT | li::FONT_CHAR_DP | li::FONT_CHAR_IC => {
1232 self.scan_font_ident();
1233 let f = self.cur_val as u32;
1234 self.scan_char_num();
1235 let v = self.font_char_dimen(f, self.cur_val as u32, m - li::FONT_CHAR_WD);
1236 self.scanned(v, ValLevel::Dimen);
1237 }
1238 li::PAR_SHAPE_LENGTH | li::PAR_SHAPE_INDENT | li::PAR_SHAPE_DIMEN => {
1239 let q = m - li::PAR_SHAPE_LENGTH;
1240 self.scan_int();
1241 let v = match &self.eqtb.par_shape.val {
1242 None => 0,
1243 Some(s) if self.cur_val <= 0 => {
1244 let _ = s;
1245 0
1246 }
1247 Some(s) => {
1248 let n = (s.len() / 2) as i32;
1249 let mut cv = self.cur_val;
1250 let mut q = q;
1251 if q == 2 {
1252 q = (cv % 2) as u32;
1253 cv = (cv + q as i32) / 2;
1254 }
1255 if cv > n {
1256 cv = n;
1257 }
1258 let idx = 2 * (cv - 1) as usize + if q == 0 { 1 } else { 0 };
1260 s[idx]
1261 }
1262 };
1263 self.scanned(v, ValLevel::Dimen);
1264 }
1265 li::GLUE_STRETCH | li::GLUE_SHRINK => {
1266 self.scan_normal_glue();
1267 let g = self.cur_glue;
1268 self.scanned(
1269 if m == li::GLUE_STRETCH {
1270 g.stretch
1271 } else {
1272 g.shrink
1273 },
1274 ValLevel::Dimen,
1275 );
1276 }
1277 li::MU_TO_GLUE => {
1278 self.scan_mu_glue();
1279 let g = self.cur_glue;
1280 self.scanned_glue(g, ValLevel::Glue);
1281 }
1282 li::GLUE_TO_MU => {
1283 self.scan_normal_glue();
1284 let g = self.cur_glue;
1285 self.scanned_glue(g, ValLevel::Mu);
1286 }
1287 li::NUM_EXPR | li::DIM_EXPR | li::GLUE_EXPR | li::MU_EXPR => {
1288 let l = match m {
1289 li::NUM_EXPR => ValLevel::Int,
1290 li::DIM_EXPR => ValLevel::Dimen,
1291 li::GLUE_EXPR => ValLevel::Glue,
1292 _ => ValLevel::Mu,
1293 };
1294 self.scan_expr(l);
1295 }
1296 _ => {
1297 let _ = level;
1298 self.scanned(0, ValLevel::Int);
1299 }
1300 }
1301 }
1302
1303 pub fn scan_normal_glue(&mut self) {
1305 self.scan_glue(ValLevel::Glue);
1306 }
1307
1308 pub fn scan_mu_glue(&mut self) {
1310 self.scan_glue(ValLevel::Mu);
1311 }
1312
1313 pub fn scan_math_style(&mut self) -> bool {
1319 self.get_nonblank_noncall();
1320 if self.cur_cmd == Cmd::MathStyle {
1321 self.cur_val = self.cur_chr as i32;
1322 return true;
1323 }
1324 self.print_err("Missing math style, treated as ");
1325 self.print_esc_str("displaystyle");
1326 self.help(&["A style should have been here; I inserted `\\displaystyle'."]);
1327 self.back_error();
1328 self.cur_val = 0;
1329 false
1330 }
1331
1332 pub fn scan_expr(&mut self, level: ValLevel) {
1337 let mut arith_err = false;
1338 let r = self.scan_expr_level(level, &mut arith_err, 0);
1339 if arith_err {
1340 self.print_err("Arithmetic overflow");
1341 self.help(&[
1342 "I can't evaluate this expression,",
1343 "since the result is out of range.",
1344 ]);
1345 self.error();
1346 match level {
1347 ValLevel::Glue | ValLevel::Mu => {
1348 self.cur_glue = Glue::ZERO;
1349 self.cur_val = 0;
1350 }
1351 _ => self.cur_val = 0,
1352 }
1353 } else {
1354 match level {
1355 ValLevel::Glue | ValLevel::Mu => {
1356 self.cur_glue = r;
1357 self.cur_val = r.width;
1358 }
1359 _ => self.cur_val = r.width,
1360 }
1361 }
1362 self.cur_val_level = level;
1363 }
1364
1365 fn scan_expr_level(&mut self, l: ValLevel, err: &mut bool, depth: u32) -> Glue {
1368 let max = |l: ValLevel| {
1370 if l == ValLevel::Int {
1371 arith::INFINITY
1372 } else {
1373 MAX_DIMEN
1374 }
1375 };
1376 let mut e = Glue::ZERO;
1377 let mut first = true;
1378 let mut negative_next = false;
1379 loop {
1380 let mut t = self.scan_expr_factor(l, err, depth);
1384 self.get_nonblank_noncall();
1385 loop {
1386 if self.cur_tok == Token::other('*' as u32) {
1387 self.scan_int_factor(err, depth);
1388 let f = self.cur_val;
1389 self.get_nonblank_noncall();
1391 if self.cur_tok == Token::other('/' as u32) {
1392 self.scan_int_factor(err, depth);
1393 let d = self.cur_val;
1394 t = self.expr_scale(t, f, d, l, err);
1395 self.get_nonblank_noncall();
1396 } else {
1397 t = self.expr_mult(t, f, l, err);
1398 }
1399 } else if self.cur_tok == Token::other('/' as u32) {
1400 self.scan_int_factor(err, depth);
1401 let d = self.cur_val;
1402 t = self.expr_div(t, d, l, err);
1403 self.get_nonblank_noncall();
1404 } else {
1405 break;
1406 }
1407 }
1408 if first {
1409 e = t;
1410 first = false;
1411 } else {
1412 e = self.expr_add(e, t, l, negative_next, max(l), err);
1413 }
1414 if self.cur_tok == Token::other('+' as u32) {
1415 negative_next = false;
1416 } else if self.cur_tok == Token::other('-' as u32) {
1417 negative_next = true;
1418 } else {
1419 if self.cur_cmd != Cmd::Relax || depth > 0 {
1423 self.back_input();
1424 }
1425 return e;
1426 }
1427 }
1428 }
1429
1430 fn scan_expr_factor(&mut self, l: ValLevel, err: &mut bool, depth: u32) -> Glue {
1431 self.get_nonblank_noncall();
1432 if self.cur_tok == Token::other('(' as u32) {
1433 let v = self.scan_expr_paren(l, err, depth);
1434 return v;
1435 }
1436 self.back_input();
1437 match l {
1438 ValLevel::Int => {
1439 self.scan_int();
1440 Glue::fixed(self.cur_val)
1441 }
1442 ValLevel::Dimen => {
1443 self.scan_normal_dimen();
1444 Glue::fixed(self.cur_val)
1445 }
1446 ValLevel::Glue => {
1447 self.scan_normal_glue();
1448 self.cur_glue
1449 }
1450 _ => {
1451 self.scan_mu_glue();
1452 self.cur_glue
1453 }
1454 }
1455 }
1456
1457 fn scan_expr_paren(&mut self, l: ValLevel, err: &mut bool, depth: u32) -> Glue {
1458 let v = self.scan_expr_level(l, err, depth + 1);
1459 self.get_nonblank_noncall();
1461 if self.cur_tok != Token::other(')' as u32) {
1462 self.print_err("Missing ) inserted for expression");
1463 self.help(&["I was expecting to see `+', `-', `*', `/', or `)'. Didn't."]);
1464 self.back_error();
1465 }
1466 v
1467 }
1468
1469 fn scan_int_factor(&mut self, err: &mut bool, depth: u32) {
1470 self.get_nonblank_noncall();
1471 if self.cur_tok == Token::other('(' as u32) {
1472 let v = self.scan_expr_paren(ValLevel::Int, err, depth);
1473 self.cur_val = v.width;
1474 } else {
1475 self.back_input();
1476 self.scan_int();
1477 }
1478 }
1479
1480 fn expr_add(
1481 &mut self,
1482 a: Glue,
1483 b: Glue,
1484 l: ValLevel,
1485 neg: bool,
1486 max: i32,
1487 err: &mut bool,
1488 ) -> Glue {
1489 let mut add = |x: i32, y: i32| match arith::add_or_sub(x, y, max, neg) {
1490 Ok(v) => v,
1491 Err(_) => {
1492 *err = true;
1493 0
1494 }
1495 };
1496 if l <= ValLevel::Dimen {
1497 return Glue::fixed(add(a.width, b.width));
1498 }
1499 let mut e = a;
1500 e.width = add(a.width, b.width);
1501 if e.stretch_order == b.stretch_order {
1502 e.stretch = add(e.stretch, b.stretch);
1503 } else if e.stretch_order < b.stretch_order && b.stretch != 0 {
1504 e.stretch = if neg { -b.stretch } else { b.stretch };
1505 e.stretch_order = b.stretch_order;
1506 }
1507 if e.shrink_order == b.shrink_order {
1508 e.shrink = add(e.shrink, b.shrink);
1509 } else if e.shrink_order < b.shrink_order && b.shrink != 0 {
1510 e.shrink = if neg { -b.shrink } else { b.shrink };
1511 e.shrink_order = b.shrink_order;
1512 }
1513 normalize_glue(e)
1514 }
1515
1516 fn expr_mult(&mut self, t: Glue, f: i32, l: ValLevel, err: &mut bool) -> Glue {
1517 let mut m = |x: i32| {
1518 let r = if l == ValLevel::Int {
1519 arith::mult_integers(x, f)
1520 } else {
1521 arith::nx_plus_y(x, f, 0)
1522 };
1523 r.unwrap_or_else(|_| {
1524 *err = true;
1525 0
1526 })
1527 };
1528 if l <= ValLevel::Dimen {
1529 return Glue::fixed(m(t.width));
1530 }
1531 let mut g = t;
1532 g.width = m(g.width);
1533 g.stretch = m(g.stretch);
1534 g.shrink = m(g.shrink);
1535 normalize_glue(g)
1536 }
1537
1538 fn expr_div(&mut self, t: Glue, f: i32, l: ValLevel, err: &mut bool) -> Glue {
1539 let mut d = |x: i32| {
1540 arith::quotient(x, f).unwrap_or_else(|_| {
1541 *err = true;
1542 0
1543 })
1544 };
1545 if l <= ValLevel::Dimen {
1546 return Glue::fixed(d(t.width));
1547 }
1548 let mut g = t;
1549 g.width = d(g.width);
1550 g.stretch = d(g.stretch);
1551 g.shrink = d(g.shrink);
1552 normalize_glue(g)
1553 }
1554
1555 fn expr_scale(&mut self, t: Glue, n: i32, f: i32, l: ValLevel, err: &mut bool) -> Glue {
1556 let max = if l == ValLevel::Int {
1557 arith::INFINITY
1558 } else {
1559 MAX_DIMEN
1560 };
1561 let mut s = |x: i32| {
1562 arith::fract(x, n, f, max).unwrap_or_else(|_| {
1563 *err = true;
1564 0
1565 })
1566 };
1567 if l <= ValLevel::Dimen {
1568 return Glue::fixed(s(t.width));
1569 }
1570 let mut g = t;
1571 g.width = s(g.width);
1572 g.stretch = s(g.stretch);
1573 g.shrink = s(g.shrink);
1574 normalize_glue(g)
1575 }
1576
1577 fn copy_plain_tokens(
1587 &mut self,
1588 out: &mut Vec<Token>,
1589 unbalance: &mut i32,
1590 xpand: bool,
1591 ) -> Option<Token> {
1592 let Some(crate::input::Level::Tokens(t)) = self.input.stack.last_mut() else {
1593 return None;
1594 };
1595 while let Some(&tok) = t.list.get(t.loc) {
1596 if tok.is_cs() {
1597 let m = self.eqtb.meaning(tok.cs_id());
1598 let plain = if m.cmd <= Cmd::MAX_COMMAND {
1599 !(Cmd::TabMark..=Cmd::MacParam).contains(&m.cmd)
1602 } else if m.cmd.is_outer_or_special() {
1603 false
1604 } else if xpand {
1605 m.cmd >= Cmd::Call && m.mac.as_ref().is_some_and(|m| m.protected)
1606 } else {
1607 true
1608 };
1609 if !plain {
1610 return None;
1611 }
1612 } else {
1613 match tok.cmd() {
1614 Cmd::LeftBrace => {
1615 self.input.align_state += 1;
1616 *unbalance += 1;
1617 }
1618 Cmd::RightBrace => {
1619 self.input.align_state -= 1;
1620 *unbalance -= 1;
1621 if *unbalance == 0 {
1622 t.loc += 1;
1623 return Some(tok);
1624 }
1625 }
1626 Cmd::TabMark | Cmd::CarRet | Cmd::MacParam => return None,
1627 _ => {}
1628 }
1629 }
1630 out.push(tok);
1631 t.loc += 1;
1632 }
1633 None
1634 }
1635
1636 pub fn scan_toks(&mut self, macro_def: bool, xpand: bool) -> Vec<Token> {
1642 if macro_def {
1643 self.input.scanner_status = ScannerStatus::Defining;
1644 } else {
1645 self.input.scanner_status = ScannerStatus::Absorbing;
1646 }
1647 self.input.warning_index = self.cur_cs;
1648 let mut out: Vec<Token> = Vec::new();
1649 let saved_runaway = std::mem::take(&mut self.runaway_list);
1652 macro_rules! runaway {
1653 ($e:expr) => {{
1654 self.runaway_list = std::mem::take(&mut out);
1655 let r = $e;
1656 out = std::mem::take(&mut self.runaway_list);
1657 r
1658 }};
1659 }
1660 let mut unbalance: i32;
1661 let mut t: u32 = 0x30; let mut hash_brace = Token(0);
1663 'found: {
1664 if macro_def {
1665 'params: loop {
1668 runaway!(self.get_token());
1669 if self.cur_tok.0 < Token::RIGHT_BRACE.0 & !0x1F_FFFF | 0x1F_FFFF
1670 && !self.cur_tok.is_cs()
1671 && self.cur_cmd <= Cmd::RightBrace
1672 {
1673 break; }
1675 if self.cur_cmd == Cmd::MacParam {
1679 let s = Token::match_token(self.cur_chr);
1681 runaway!(self.get_token());
1682 if self.cur_cmd == Cmd::LeftBrace && !self.cur_tok.is_cs() {
1683 hash_brace = self.cur_tok;
1684 out.push(self.cur_tok);
1685 break 'params;
1686 }
1687 if t == 0x39 {
1688 self.print_err("You already have nine parameters");
1689 self.help(&["I'm going to ignore the # sign you just used."]);
1690 self.error();
1691 } else {
1692 t += 1;
1693 if self.cur_tok != Token::other(t) {
1694 self.print_err("Parameters must be numbered consecutively");
1695 self.help(&[
1696 "I've inserted the digit you should have used after the #.",
1697 "Type `1' to delete what you did use.",
1698 ]);
1699 self.back_error();
1700 }
1701 self.cur_tok = s;
1702 }
1703 }
1704 out.push(self.cur_tok);
1705 }
1706 out.push(Token::END_MATCH);
1707 if hash_brace.0 == 0 && self.cur_cmd == Cmd::RightBrace {
1708 self.print_err("Missing { inserted");
1709 self.input.align_state += 1;
1710 self.help(&[
1711 "Where was the left brace? You said something like `\\def\\a}',",
1712 "which I'm going to interpret as `\\def\\a{}'.",
1713 ]);
1714 self.error();
1715 break 'found;
1716 }
1717 } else {
1718 self.scan_left_brace();
1719 }
1720 unbalance = 1;
1722 loop {
1723 if let Some(end_brace) = self.copy_plain_tokens(&mut out, &mut unbalance, xpand) {
1727 self.cur_tok = end_brace;
1728 self.cur_cmd = Cmd::RightBrace;
1729 self.cur_chr = end_brace.chr();
1730 self.cur_cs = NO_CS;
1731 break 'found;
1732 }
1733 if xpand {
1734 loop {
1736 runaway!(self.get_next());
1737 if self.cur_cmd >= Cmd::Call
1738 && self
1739 .eqtb
1740 .meaning(self.cur_cs)
1741 .mac
1742 .as_ref()
1743 .is_some_and(|m| m.protected)
1744 {
1745 self.cur_cmd = Cmd::Relax;
1746 self.cur_chr = crate::input::NO_EXPAND_FLAG;
1747 break;
1748 }
1749 if self.cur_cmd <= Cmd::MAX_COMMAND {
1750 break;
1751 }
1752 if self.cur_cmd != Cmd::The {
1753 runaway!(self.expand());
1754 } else {
1755 let list = runaway!(self.the_toks());
1756 out.extend_from_slice(&list);
1757 }
1758 }
1759 runaway!(self.x_token());
1760 } else {
1761 runaway!(self.get_token());
1762 }
1763 if self.cur_cmd == Cmd::MacParam && macro_def {
1766 let s = self.cur_tok;
1768 if xpand {
1769 runaway!(self.get_x_token());
1770 } else {
1771 runaway!(self.get_token());
1772 }
1773 if self.cur_cmd != Cmd::MacParam {
1774 let c = self.cur_tok;
1775 if c.is_cs() || c.cmd() != Cmd::OtherChar || c.chr() <= 0x30 || c.chr() > t
1776 {
1777 self.print_err("Illegal parameter number in definition of ");
1778 self.sprint_cs(self.input.warning_index);
1779 self.help(&[
1780 "You meant to type ## instead of #, right?",
1781 "Or maybe a } was forgotten somewhere earlier, and things",
1782 "are all screwed up? I'm going to assume that you meant ##.",
1783 ]);
1784 self.back_error();
1785 self.cur_tok = s;
1786 } else {
1787 self.cur_tok = Token::out_param(c.chr() - 0x30);
1788 }
1789 }
1790 } else if self.cur_tok.is_cs()
1791 || self.cur_cmd > Cmd::MacParam
1792 || self.cur_cmd < Cmd::LeftBrace
1793 {
1794 } else if self.cur_cmd < Cmd::RightBrace {
1796 unbalance += 1;
1797 } else if self.cur_cmd == Cmd::RightBrace {
1798 unbalance -= 1;
1799 if unbalance == 0 {
1800 break 'found;
1801 }
1802 }
1803 out.push(self.cur_tok);
1804 }
1805 }
1806 self.input.scanner_status = ScannerStatus::Normal;
1807 self.runaway_list = saved_runaway;
1808 if hash_brace.0 != 0 {
1809 out.push(hash_brace);
1810 }
1811 out
1812 }
1813}
1814
1815pub const SET_AUX_PREV_DEPTH: u32 = 1;
1817pub const SET_AUX_SPACE_FACTOR: u32 = 134;
1819
1820pub fn normalize_glue(mut g: Glue) -> Glue {
1823 if g.stretch == 0 {
1824 g.stretch_order = glue::NORMAL;
1825 }
1826 if g.shrink == 0 {
1827 g.shrink_order = glue::NORMAL;
1828 }
1829 g
1830}
1831
1832#[allow(dead_code)]
1834fn _loc(_: Loc) {}