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