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::AssignDir | Cmd::AssignDirection => {
946 let v = self.eqtb.int(pg::assign_int::COUNT.min(m + DIR_PAR_BASE));
947 let _ = v;
948 self.scanned(self.dir_param(m), ValLevel::Int);
949 }
950 Cmd::AssignDimen => {
951 let v = if m >= REG_OFFSET {
952 self.eqtb.dimen[(m - REG_OFFSET) as usize].val
953 } else {
954 self.eqtb.dimen(m)
955 };
956 self.scanned(v, ValLevel::Dimen);
957 }
958 Cmd::AssignGlue => {
959 let g = if m >= REG_OFFSET {
960 self.eqtb.skip[(m - REG_OFFSET) as usize].val
961 } else {
962 self.eqtb.glue(m)
963 };
964 self.scanned_glue(g, ValLevel::Glue);
965 }
966 Cmd::AssignMuGlue => {
967 let g = if m >= REG_OFFSET {
968 self.eqtb.muskip[(m - REG_OFFSET) as usize].val
969 } else {
970 self.eqtb.glue(m + crate::eqtb::MU_GLUE_OFFSET)
971 };
972 self.scanned_glue(g, ValLevel::Mu);
973 }
974 Cmd::SetAux => {
975 let v = self.fetch_aux(m);
976 if let Some((v, l)) = v {
977 self.scanned(v, l);
978 } else {
979 self.scanned(
980 0,
981 if m == SET_AUX_PREV_DEPTH {
982 ValLevel::Dimen
983 } else {
984 ValLevel::Int
985 },
986 );
987 }
988 }
989 Cmd::SetPrevGraf => {
990 let v = self.fetch_prev_graf();
991 self.scanned(v, ValLevel::Int);
992 }
993 Cmd::SetPageInt => {
994 let v = match m {
995 0 => self.dead_cycles,
996 1 => self.insert_penalties,
997 _ => self.err.interaction as i32,
998 };
999 self.scanned(v, ValLevel::Int);
1000 }
1001 Cmd::SetPageDimen => {
1002 let v = self.page_so_far_value(m);
1003 self.scanned(v, ValLevel::Dimen);
1004 }
1005 Cmd::SetTexShape => {
1006 let v = self
1007 .eqtb
1008 .par_shape
1009 .val
1010 .as_ref()
1011 .map_or(0, |s| (s.len() / 2) as i32);
1012 self.scanned(v, ValLevel::Int);
1013 }
1014 Cmd::SetEtexShape => {
1015 self.scan_int();
1016 let n = self.cur_val;
1017 let v = match &self.eqtb.etex_shape[m as usize].val {
1018 None => 0,
1019 Some(s) if n < 0 => 0,
1020 Some(s) => {
1021 let len = s.len() as i32;
1022 if n == 0 {
1023 len
1024 } else {
1025 s[(n.min(len) - 1) as usize]
1026 }
1027 }
1028 };
1029 self.scanned(v, ValLevel::Int);
1030 }
1031 Cmd::SetBoxDimen => {
1032 self.scan_register_num();
1033 let p = self.eqtb.boxes[self.cur_val as usize].val;
1034 let v = if p.is_null() {
1035 0
1036 } else {
1037 let b = self.nodes.box_data(p);
1038 match (m, b) {
1039 (2, Some(b)) => b.width,
1040 (3, Some(b)) => b.depth,
1041 (4, Some(b)) => b.height,
1042 _ => 0,
1043 }
1044 };
1045 self.scanned(v, ValLevel::Dimen);
1046 }
1047 Cmd::CharGiven | Cmd::XmathGiven => {
1048 self.scanned(self.cur_chr as i32, ValLevel::Int);
1049 }
1050 Cmd::MathGiven => {
1051 self.scanned(crate::codes::math_given_report(self.cur_chr), ValLevel::Int);
1052 }
1053 Cmd::AssignFontDimen => {
1054 let v = self.find_font_dimen(false);
1055 self.scanned(v, ValLevel::Dimen);
1056 }
1057 Cmd::AssignFontInt => {
1058 self.scan_font_ident();
1059 let f = self.cur_val as u32;
1060 let v = self.font_int_param(f, m);
1061 self.scanned(v, ValLevel::Int);
1062 }
1063 Cmd::Register => {
1064 self.scan_register_num();
1065 let n = self.cur_val as usize;
1066 match m {
1067 reg::COUNT => self.scanned(self.eqtb.count[n].val, ValLevel::Int),
1068 reg::ATTRIBUTE => self.scanned(self.eqtb.attr[n].val, ValLevel::Int),
1069 reg::DIMEN => self.scanned(self.eqtb.dimen[n].val, ValLevel::Dimen),
1070 reg::SKIP => {
1071 let g = self.eqtb.skip[n].val;
1072 self.scanned_glue(g, ValLevel::Glue);
1073 }
1074 _ => {
1075 let g = self.eqtb.muskip[n].val;
1076 self.scanned_glue(g, ValLevel::Mu);
1077 }
1078 }
1079 }
1080 Cmd::SetMathParam => {
1081 let found = self.scan_math_style();
1083 let style = self.cur_val as u32;
1084 let v = self
1085 .eqtb
1086 .math_param
1087 .get(&(m * 8 + style))
1088 .filter(|_| found)
1089 .map_or(crate::codes::UNDEFINED_MATH_PARAM, |s| s.val);
1090 if crate::codes::math_param_is_glue(m) {
1091 let g = if found && v == crate::codes::UNDEFINED_MATH_PARAM {
1093 let (l, r) = ((m - 49) / 8, (m - 49) % 8);
1094 self.math_spacing(l, r, style)
1095 .map_or(crate::glue::Glue::ZERO, |(g, _)| g)
1096 } else {
1097 self.math_param_glue(v)
1098 };
1099 self.scanned_glue(g, ValLevel::Mu);
1100 } else if m == crate::mathparams::mp::RADICAL_DEGREE_RAISE {
1101 self.scanned(v, ValLevel::Int);
1103 } else {
1104 self.scanned(v, ValLevel::Dimen);
1105 }
1106 }
1107 Cmd::LastItem => self.fetch_last_item(m, level),
1108 _ => {
1109 self.print_err("You can't use `");
1110 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
1111 self.printer.print_str("' after ");
1112 self.print_esc_str("the");
1113 self.help(&["I'm forgetting what you said and using zero instead."]);
1114 self.error();
1115 if level != ValLevel::Tok {
1116 self.scanned(0, ValLevel::Dimen);
1117 } else {
1118 self.scanned(0, ValLevel::Int);
1119 }
1120 }
1121 }
1122 while self.cur_val_level > level {
1124 if self.cur_val_level == ValLevel::Glue {
1125 self.cur_val = self.cur_glue.width;
1126 } else if self.cur_val_level == ValLevel::Mu {
1127 self.mu_error();
1128 }
1129 self.cur_val_level = match self.cur_val_level {
1130 ValLevel::Tok => ValLevel::Ident,
1131 ValLevel::Ident => ValLevel::Mu,
1132 ValLevel::Mu => ValLevel::Glue,
1133 ValLevel::Glue => ValLevel::Dimen,
1134 _ => ValLevel::Int,
1135 };
1136 if self.cur_val_level == ValLevel::Glue || self.cur_val_level == ValLevel::Mu {
1137 }
1139 }
1140 if negative {
1141 if self.cur_val_level >= ValLevel::Glue {
1142 let g = &mut self.cur_glue;
1143 g.width = -g.width;
1144 g.stretch = -g.stretch;
1145 g.shrink = -g.shrink;
1146 self.cur_val = g.width;
1147 } else {
1148 self.cur_val = self.cur_val.wrapping_neg();
1149 }
1150 }
1151 }
1152
1153 fn fetch_last_item(&mut self, m: u32, level: ValLevel) {
1155 use last_item as li;
1156 match m {
1157 li::LAST_PENALTY | li::LAST_KERN | li::LAST_SKIP | li::LAST_NODE_TYPE => {
1158 let (v, g, l) = self.fetch_last_node_item(m);
1159 if l >= ValLevel::Glue {
1160 self.scanned_glue(g, l);
1161 } else {
1162 self.scanned(v, l);
1163 }
1164 }
1165 li::INPUT_LINE_NO => self.scanned(self.input.line(), ValLevel::Int),
1166 li::BADNESS => self.scanned(self.last_badness, ValLevel::Int),
1167 li::LUATEX_VERSION => self.scanned(LUATEX_VERSION, ValLevel::Int),
1168 li::ETEX_VERSION => self.scanned(ETEX_VERSION, ValLevel::Int),
1169 li::ETEX_MINOR_VERSION => self.scanned(ETEX_MINOR_VERSION, ValLevel::Int),
1170 li::CURRENT_GROUP_LEVEL => {
1171 self.scanned(i32::from(self.save.cur_level) - 1, ValLevel::Int)
1172 }
1173 li::CURRENT_GROUP_TYPE => self.scanned(self.save.cur_group as i32, ValLevel::Int),
1174 li::CURRENT_IF_LEVEL => self.scanned(self.cond.stack.len() as i32, ValLevel::Int),
1175 li::CURRENT_IF_TYPE => {
1176 let v = if self.cond.stack.is_empty() {
1177 0
1178 } else if self.cond.cur_if < crate::cond::UNLESS_CODE {
1179 self.cond.cur_if as i32 + 1
1180 } else {
1181 -((self.cond.cur_if - crate::cond::UNLESS_CODE) as i32 + 1)
1182 };
1183 self.scanned(v, ValLevel::Int);
1184 }
1185 li::CURRENT_IF_BRANCH => {
1186 let v = match self.cond.if_limit {
1187 crate::cond::OR_CODE | crate::cond::ELSE_CODE => 1,
1188 crate::cond::FI_CODE => -1,
1189 _ => 0,
1190 };
1191 self.scanned(v, ValLevel::Int);
1192 }
1193 li::RANDOM_SEED => self.scanned(self.random_seed, ValLevel::Int),
1194 li::LAST_X_POS => self.scanned(self.last_x_pos, ValLevel::Int),
1195 li::LAST_Y_POS => self.scanned(self.last_y_pos, ValLevel::Int),
1196 li::LAST_SAVED_BOX_RESOURCE_INDEX
1197 | li::LAST_SAVED_IMAGE_RESOURCE_INDEX
1198 | li::LAST_SAVED_IMAGE_RESOURCE_PAGES => {
1199 self.scanned(self.last_saved_resource(m), ValLevel::Int)
1200 }
1201 li::GLUE_STRETCH_ORDER
1202 | li::GLUE_SHRINK_ORDER
1203 | li::ETEX_GLUE_STRETCH_ORDER
1204 | li::ETEX_GLUE_SHRINK_ORDER => {
1205 self.scan_normal_glue();
1206 let g = self.cur_glue;
1207 let o = if m == li::GLUE_STRETCH_ORDER || m == li::ETEX_GLUE_STRETCH_ORDER {
1208 g.stretch_order
1209 } else {
1210 g.shrink_order
1211 };
1212 let v = if m == li::ETEX_GLUE_STRETCH_ORDER || m == li::ETEX_GLUE_SHRINK_ORDER {
1215 i32::from(o)
1216 } else {
1217 i32::from(o.saturating_sub(1)).max(0)
1218 };
1219 self.scanned(v, ValLevel::Int);
1220 }
1221 li::FONT_CHAR_WD | li::FONT_CHAR_HT | li::FONT_CHAR_DP | li::FONT_CHAR_IC => {
1222 self.scan_font_ident();
1223 let f = self.cur_val as u32;
1224 self.scan_char_num();
1225 let v = self.font_char_dimen(f, self.cur_val as u32, m - li::FONT_CHAR_WD);
1226 self.scanned(v, ValLevel::Dimen);
1227 }
1228 li::PAR_SHAPE_LENGTH | li::PAR_SHAPE_INDENT | li::PAR_SHAPE_DIMEN => {
1229 let q = m - li::PAR_SHAPE_LENGTH;
1230 self.scan_int();
1231 let v = match &self.eqtb.par_shape.val {
1232 None => 0,
1233 Some(s) if self.cur_val <= 0 => {
1234 let _ = s;
1235 0
1236 }
1237 Some(s) => {
1238 let n = (s.len() / 2) as i32;
1239 let mut cv = self.cur_val;
1240 let mut q = q;
1241 if q == 2 {
1242 q = (cv % 2) as u32;
1243 cv = (cv + q as i32) / 2;
1244 }
1245 if cv > n {
1246 cv = n;
1247 }
1248 let idx = 2 * (cv - 1) as usize + if q == 0 { 1 } else { 0 };
1250 s[idx]
1251 }
1252 };
1253 self.scanned(v, ValLevel::Dimen);
1254 }
1255 li::GLUE_STRETCH | li::GLUE_SHRINK => {
1256 self.scan_normal_glue();
1257 let g = self.cur_glue;
1258 self.scanned(
1259 if m == li::GLUE_STRETCH {
1260 g.stretch
1261 } else {
1262 g.shrink
1263 },
1264 ValLevel::Dimen,
1265 );
1266 }
1267 li::MU_TO_GLUE => {
1268 self.scan_mu_glue();
1269 let g = self.cur_glue;
1270 self.scanned_glue(g, ValLevel::Glue);
1271 }
1272 li::GLUE_TO_MU => {
1273 self.scan_normal_glue();
1274 let g = self.cur_glue;
1275 self.scanned_glue(g, ValLevel::Mu);
1276 }
1277 li::NUM_EXPR | li::DIM_EXPR | li::GLUE_EXPR | li::MU_EXPR => {
1278 let l = match m {
1279 li::NUM_EXPR => ValLevel::Int,
1280 li::DIM_EXPR => ValLevel::Dimen,
1281 li::GLUE_EXPR => ValLevel::Glue,
1282 _ => ValLevel::Mu,
1283 };
1284 self.scan_expr(l);
1285 }
1286 _ => {
1287 let _ = level;
1288 self.scanned(0, ValLevel::Int);
1289 }
1290 }
1291 }
1292
1293 pub fn scan_normal_glue(&mut self) {
1295 self.scan_glue(ValLevel::Glue);
1296 }
1297
1298 pub fn scan_mu_glue(&mut self) {
1300 self.scan_glue(ValLevel::Mu);
1301 }
1302
1303 pub fn scan_math_style(&mut self) -> bool {
1309 self.get_nonblank_noncall();
1310 if self.cur_cmd == Cmd::MathStyle {
1311 self.cur_val = self.cur_chr as i32;
1312 return true;
1313 }
1314 self.print_err("Missing math style, treated as ");
1315 self.print_esc_str("displaystyle");
1316 self.help(&["A style should have been here; I inserted `\\displaystyle'."]);
1317 self.back_error();
1318 self.cur_val = 0;
1319 false
1320 }
1321
1322 pub fn scan_expr(&mut self, level: ValLevel) {
1327 let mut arith_err = false;
1328 let r = self.scan_expr_level(level, &mut arith_err, 0);
1329 if arith_err {
1330 self.print_err("Arithmetic overflow");
1331 self.help(&[
1332 "I can't evaluate this expression,",
1333 "since the result is out of range.",
1334 ]);
1335 self.error();
1336 match level {
1337 ValLevel::Glue | ValLevel::Mu => {
1338 self.cur_glue = Glue::ZERO;
1339 self.cur_val = 0;
1340 }
1341 _ => self.cur_val = 0,
1342 }
1343 } else {
1344 match level {
1345 ValLevel::Glue | ValLevel::Mu => {
1346 self.cur_glue = r;
1347 self.cur_val = r.width;
1348 }
1349 _ => self.cur_val = r.width,
1350 }
1351 }
1352 self.cur_val_level = level;
1353 }
1354
1355 fn scan_expr_level(&mut self, l: ValLevel, err: &mut bool, depth: u32) -> Glue {
1358 let max = |l: ValLevel| {
1360 if l == ValLevel::Int {
1361 arith::INFINITY
1362 } else {
1363 MAX_DIMEN
1364 }
1365 };
1366 let mut e = Glue::ZERO;
1367 let mut first = true;
1368 let mut negative_next = false;
1369 loop {
1370 let mut t = self.scan_expr_factor(l, err, depth);
1374 self.get_nonblank_noncall();
1375 loop {
1376 if self.cur_tok == Token::other('*' as u32) {
1377 self.scan_int_factor(err, depth);
1378 let f = self.cur_val;
1379 self.get_nonblank_noncall();
1381 if self.cur_tok == Token::other('/' as u32) {
1382 self.scan_int_factor(err, depth);
1383 let d = self.cur_val;
1384 t = self.expr_scale(t, f, d, l, err);
1385 self.get_nonblank_noncall();
1386 } else {
1387 t = self.expr_mult(t, f, l, err);
1388 }
1389 } else if self.cur_tok == Token::other('/' as u32) {
1390 self.scan_int_factor(err, depth);
1391 let d = self.cur_val;
1392 t = self.expr_div(t, d, l, err);
1393 self.get_nonblank_noncall();
1394 } else {
1395 break;
1396 }
1397 }
1398 if first {
1399 e = t;
1400 first = false;
1401 } else {
1402 e = self.expr_add(e, t, l, negative_next, max(l), err);
1403 }
1404 if self.cur_tok == Token::other('+' as u32) {
1405 negative_next = false;
1406 } else if self.cur_tok == Token::other('-' as u32) {
1407 negative_next = true;
1408 } else {
1409 if self.cur_cmd != Cmd::Relax || depth > 0 {
1413 self.back_input();
1414 }
1415 return e;
1416 }
1417 }
1418 }
1419
1420 fn scan_expr_factor(&mut self, l: ValLevel, err: &mut bool, depth: u32) -> Glue {
1421 self.get_nonblank_noncall();
1422 if self.cur_tok == Token::other('(' as u32) {
1423 let v = self.scan_expr_paren(l, err, depth);
1424 return v;
1425 }
1426 self.back_input();
1427 match l {
1428 ValLevel::Int => {
1429 self.scan_int();
1430 Glue::fixed(self.cur_val)
1431 }
1432 ValLevel::Dimen => {
1433 self.scan_normal_dimen();
1434 Glue::fixed(self.cur_val)
1435 }
1436 ValLevel::Glue => {
1437 self.scan_normal_glue();
1438 self.cur_glue
1439 }
1440 _ => {
1441 self.scan_mu_glue();
1442 self.cur_glue
1443 }
1444 }
1445 }
1446
1447 fn scan_expr_paren(&mut self, l: ValLevel, err: &mut bool, depth: u32) -> Glue {
1448 let v = self.scan_expr_level(l, err, depth + 1);
1449 self.get_nonblank_noncall();
1451 if self.cur_tok != Token::other(')' as u32) {
1452 self.print_err("Missing ) inserted for expression");
1453 self.help(&["I was expecting to see `+', `-', `*', `/', or `)'. Didn't."]);
1454 self.back_error();
1455 }
1456 v
1457 }
1458
1459 fn scan_int_factor(&mut self, err: &mut bool, depth: u32) {
1460 self.get_nonblank_noncall();
1461 if self.cur_tok == Token::other('(' as u32) {
1462 let v = self.scan_expr_paren(ValLevel::Int, err, depth);
1463 self.cur_val = v.width;
1464 } else {
1465 self.back_input();
1466 self.scan_int();
1467 }
1468 }
1469
1470 fn expr_add(
1471 &mut self,
1472 a: Glue,
1473 b: Glue,
1474 l: ValLevel,
1475 neg: bool,
1476 max: i32,
1477 err: &mut bool,
1478 ) -> Glue {
1479 let mut add = |x: i32, y: i32| match arith::add_or_sub(x, y, max, neg) {
1480 Ok(v) => v,
1481 Err(_) => {
1482 *err = true;
1483 0
1484 }
1485 };
1486 if l <= ValLevel::Dimen {
1487 return Glue::fixed(add(a.width, b.width));
1488 }
1489 let mut e = a;
1490 e.width = add(a.width, b.width);
1491 if e.stretch_order == b.stretch_order {
1492 e.stretch = add(e.stretch, b.stretch);
1493 } else if e.stretch_order < b.stretch_order && b.stretch != 0 {
1494 e.stretch = if neg { -b.stretch } else { b.stretch };
1495 e.stretch_order = b.stretch_order;
1496 }
1497 if e.shrink_order == b.shrink_order {
1498 e.shrink = add(e.shrink, b.shrink);
1499 } else if e.shrink_order < b.shrink_order && b.shrink != 0 {
1500 e.shrink = if neg { -b.shrink } else { b.shrink };
1501 e.shrink_order = b.shrink_order;
1502 }
1503 normalize_glue(e)
1504 }
1505
1506 fn expr_mult(&mut self, t: Glue, f: i32, l: ValLevel, err: &mut bool) -> Glue {
1507 let mut m = |x: i32| {
1508 let r = if l == ValLevel::Int {
1509 arith::mult_integers(x, f)
1510 } else {
1511 arith::nx_plus_y(x, f, 0)
1512 };
1513 r.unwrap_or_else(|_| {
1514 *err = true;
1515 0
1516 })
1517 };
1518 if l <= ValLevel::Dimen {
1519 return Glue::fixed(m(t.width));
1520 }
1521 let mut g = t;
1522 g.width = m(g.width);
1523 g.stretch = m(g.stretch);
1524 g.shrink = m(g.shrink);
1525 normalize_glue(g)
1526 }
1527
1528 fn expr_div(&mut self, t: Glue, f: i32, l: ValLevel, err: &mut bool) -> Glue {
1529 let mut d = |x: i32| {
1530 arith::quotient(x, f).unwrap_or_else(|_| {
1531 *err = true;
1532 0
1533 })
1534 };
1535 if l <= ValLevel::Dimen {
1536 return Glue::fixed(d(t.width));
1537 }
1538 let mut g = t;
1539 g.width = d(g.width);
1540 g.stretch = d(g.stretch);
1541 g.shrink = d(g.shrink);
1542 normalize_glue(g)
1543 }
1544
1545 fn expr_scale(&mut self, t: Glue, n: i32, f: i32, l: ValLevel, err: &mut bool) -> Glue {
1546 let max = if l == ValLevel::Int {
1547 arith::INFINITY
1548 } else {
1549 MAX_DIMEN
1550 };
1551 let mut s = |x: i32| {
1552 arith::fract(x, n, f, max).unwrap_or_else(|_| {
1553 *err = true;
1554 0
1555 })
1556 };
1557 if l <= ValLevel::Dimen {
1558 return Glue::fixed(s(t.width));
1559 }
1560 let mut g = t;
1561 g.width = s(g.width);
1562 g.stretch = s(g.stretch);
1563 g.shrink = s(g.shrink);
1564 normalize_glue(g)
1565 }
1566
1567 fn copy_plain_tokens(
1577 &mut self,
1578 out: &mut Vec<Token>,
1579 unbalance: &mut i32,
1580 xpand: bool,
1581 ) -> Option<Token> {
1582 let Some(crate::input::Level::Tokens(t)) = self.input.stack.last_mut() else {
1583 return None;
1584 };
1585 while let Some(&tok) = t.list.get(t.loc) {
1586 if tok.is_cs() {
1587 let m = self.eqtb.meaning(tok.cs_id());
1588 let plain = if m.cmd <= Cmd::MAX_COMMAND {
1589 !(Cmd::TabMark..=Cmd::CarRet).contains(&m.cmd)
1590 } else if m.cmd.is_outer_or_special() {
1591 false
1592 } else if xpand {
1593 m.cmd >= Cmd::Call && m.mac.as_ref().is_some_and(|m| m.protected)
1594 } else {
1595 true
1596 };
1597 if !plain {
1598 return None;
1599 }
1600 } else {
1601 match tok.cmd() {
1602 Cmd::LeftBrace => {
1603 self.input.align_state += 1;
1604 *unbalance += 1;
1605 }
1606 Cmd::RightBrace => {
1607 self.input.align_state -= 1;
1608 *unbalance -= 1;
1609 if *unbalance == 0 {
1610 t.loc += 1;
1611 return Some(tok);
1612 }
1613 }
1614 Cmd::TabMark | Cmd::CarRet | Cmd::MacParam => return None,
1615 _ => {}
1616 }
1617 }
1618 out.push(tok);
1619 t.loc += 1;
1620 }
1621 None
1622 }
1623
1624 pub fn scan_toks(&mut self, macro_def: bool, xpand: bool) -> Vec<Token> {
1630 if macro_def {
1631 self.input.scanner_status = ScannerStatus::Defining;
1632 } else {
1633 self.input.scanner_status = ScannerStatus::Absorbing;
1634 }
1635 self.input.warning_index = self.cur_cs;
1636 let mut out: Vec<Token> = Vec::new();
1637 let saved_runaway = std::mem::take(&mut self.runaway_list);
1640 macro_rules! runaway {
1641 ($e:expr) => {{
1642 self.runaway_list = std::mem::take(&mut out);
1643 let r = $e;
1644 out = std::mem::take(&mut self.runaway_list);
1645 r
1646 }};
1647 }
1648 let mut unbalance: i32;
1649 let mut t: u32 = 0x30; let mut hash_brace = Token(0);
1651 'found: {
1652 if macro_def {
1653 'params: loop {
1656 runaway!(self.get_token());
1657 if self.cur_tok.0 < Token::RIGHT_BRACE.0 & !0x1F_FFFF | 0x1F_FFFF
1658 && !self.cur_tok.is_cs()
1659 && self.cur_cmd <= Cmd::RightBrace
1660 {
1661 break; }
1663 if self.cur_cmd == Cmd::MacParam && !self.cur_tok.is_cs() {
1664 let s = Token::match_token(self.cur_chr);
1666 runaway!(self.get_token());
1667 if self.cur_cmd == Cmd::LeftBrace && !self.cur_tok.is_cs() {
1668 hash_brace = self.cur_tok;
1669 out.push(self.cur_tok);
1670 break 'params;
1671 }
1672 if t == 0x39 {
1673 self.print_err("You already have nine parameters");
1674 self.help(&["I'm going to ignore the # sign you just used."]);
1675 self.error();
1676 } else {
1677 t += 1;
1678 if self.cur_tok != Token::other(t) {
1679 self.print_err("Parameters must be numbered consecutively");
1680 self.help(&[
1681 "I've inserted the digit you should have used after the #.",
1682 "Type `1' to delete what you did use.",
1683 ]);
1684 self.back_error();
1685 }
1686 self.cur_tok = s;
1687 }
1688 }
1689 out.push(self.cur_tok);
1690 }
1691 out.push(Token::END_MATCH);
1692 if hash_brace.0 == 0 && self.cur_cmd == Cmd::RightBrace {
1693 self.print_err("Missing { inserted");
1694 self.input.align_state += 1;
1695 self.help(&[
1696 "Where was the left brace? You said something like `\\def\\a}',",
1697 "which I'm going to interpret as `\\def\\a{}'.",
1698 ]);
1699 self.error();
1700 break 'found;
1701 }
1702 } else {
1703 self.scan_left_brace();
1704 }
1705 unbalance = 1;
1707 loop {
1708 if let Some(end_brace) = self.copy_plain_tokens(&mut out, &mut unbalance, xpand) {
1712 self.cur_tok = end_brace;
1713 self.cur_cmd = Cmd::RightBrace;
1714 self.cur_chr = end_brace.chr();
1715 self.cur_cs = NO_CS;
1716 break 'found;
1717 }
1718 if xpand {
1719 loop {
1721 runaway!(self.get_next());
1722 if self.cur_cmd >= Cmd::Call
1723 && self
1724 .eqtb
1725 .meaning(self.cur_cs)
1726 .mac
1727 .as_ref()
1728 .is_some_and(|m| m.protected)
1729 {
1730 self.cur_cmd = Cmd::Relax;
1731 self.cur_chr = crate::input::NO_EXPAND_FLAG;
1732 break;
1733 }
1734 if self.cur_cmd <= Cmd::MAX_COMMAND {
1735 break;
1736 }
1737 if self.cur_cmd != Cmd::The {
1738 runaway!(self.expand());
1739 } else {
1740 let list = runaway!(self.the_toks());
1741 out.extend_from_slice(&list);
1742 }
1743 }
1744 runaway!(self.x_token());
1745 } else {
1746 runaway!(self.get_token());
1747 }
1748 if self.cur_tok.is_cs()
1749 || self.cur_cmd > Cmd::MacParam
1750 || self.cur_cmd < Cmd::LeftBrace
1751 {
1752 } else if self.cur_cmd < Cmd::RightBrace {
1754 unbalance += 1;
1755 } else if self.cur_cmd == Cmd::RightBrace {
1756 unbalance -= 1;
1757 if unbalance == 0 {
1758 break 'found;
1759 }
1760 } else if self.cur_cmd == Cmd::MacParam && macro_def {
1761 let s = self.cur_tok;
1763 if xpand {
1764 runaway!(self.get_x_token());
1765 } else {
1766 runaway!(self.get_token());
1767 }
1768 if self.cur_cmd != Cmd::MacParam || self.cur_tok.is_cs() {
1769 let c = self.cur_tok;
1770 if c.is_cs() || c.cmd() != Cmd::OtherChar || c.chr() <= 0x30 || c.chr() > t
1771 {
1772 self.print_err("Illegal parameter number in definition of ");
1773 self.sprint_cs(self.input.warning_index);
1774 self.help(&[
1775 "You meant to type ## instead of #, right?",
1776 "Or maybe a } was forgotten somewhere earlier, and things",
1777 "are all screwed up? I'm going to assume that you meant ##.",
1778 ]);
1779 self.back_error();
1780 self.cur_tok = s;
1781 } else {
1782 self.cur_tok = Token::out_param(c.chr() - 0x30);
1783 }
1784 }
1785 }
1786 out.push(self.cur_tok);
1787 }
1788 }
1789 self.input.scanner_status = ScannerStatus::Normal;
1790 self.runaway_list = saved_runaway;
1791 if hash_brace.0 != 0 {
1792 out.push(hash_brace);
1793 }
1794 out
1795 }
1796}
1797
1798const DIR_PAR_BASE: u32 = 0;
1800
1801pub const SET_AUX_PREV_DEPTH: u32 = 1;
1803pub const SET_AUX_SPACE_FACTOR: u32 = 134;
1805
1806pub fn normalize_glue(mut g: Glue) -> Glue {
1809 if g.stretch == 0 {
1810 g.stretch_order = glue::NORMAL;
1811 }
1812 if g.shrink == 0 {
1813 g.shrink_order = glue::NORMAL;
1814 }
1815 g
1816}
1817
1818#[allow(dead_code)]
1820fn _loc(_: Loc) {}