1use std::rc::Rc;
18
19use crate::Engine;
20use crate::build::PackSpec;
21use crate::cmd::Cmd;
22use crate::eqtb::{Loc, Val};
23use crate::input::TokKind;
24use crate::maincontrol::{IGNORE_DEPTH, Mode};
25use crate::nodes::{
26 DEFAULT_CODE, FenceData, FractionData, NodeData, NodeRef, accent_sub, fence_sub, id, noad_opt,
27 noad_sub, radical_sub,
28};
29use crate::primitives_gen::{assign_dimen as dp, assign_int as ip, assign_toks as tp};
30use crate::save::GroupCode;
31use crate::token::Token;
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
35pub enum Field {
36 Nucleus = 0,
38 Sup = 1,
40 Sub = 2,
42 Degree = 3,
44}
45
46impl Field {
47 fn from_i64(v: i64) -> Field {
48 match v & 3 {
49 0 => Field::Nucleus,
50 1 => Field::Sup,
51 2 => Field::Sub,
52 _ => Field::Degree,
53 }
54 }
55}
56
57fn field_ref(noad: NodeRef, f: Field) -> i64 {
58 (i64::from(noad.0) << 2) | f as i64
59}
60
61fn field_from_ref(v: i64) -> (NodeRef, Field) {
62 (NodeRef((v >> 2) as u32), Field::from_i64(v))
63}
64
65#[derive(Clone, Copy, Debug, PartialEq, Eq)]
67pub struct MathChar {
68 pub class: u32,
70 pub fam: u32,
72 pub chr: u32,
74}
75
76impl MathChar {
77 pub fn from_given(g: u32) -> MathChar {
79 if g & crate::codes::MATH_GIVEN_PACKED != 0 {
80 MathChar::from_packed(i64::from(g & !crate::codes::MATH_GIVEN_PACKED))
81 } else {
82 MathChar::from_classic(g as i32)
83 }
84 }
85
86 pub fn from_classic(c: i32) -> MathChar {
88 if c >= 0x8000 {
89 return MathChar {
90 class: 8,
91 fam: 0,
92 chr: 0,
93 };
94 }
95 let c = c.max(0) as u32;
96 MathChar {
97 class: c >> 12,
98 fam: (c >> 8) & 0xF,
99 chr: c & 0xFF,
100 }
101 }
102
103 pub fn from_packed(v: i64) -> MathChar {
105 if v == crate::codes::MATH_ACTIVE {
106 return MathChar {
107 class: 8,
108 fam: 0,
109 chr: 0,
110 };
111 }
112 MathChar {
113 class: crate::codes::math_class(v),
114 fam: crate::codes::math_fam(v),
115 chr: crate::codes::math_char(v),
116 }
117 }
118}
119
120pub fn delcode_parts(v: i64) -> Option<(u32, u32, u32, u32)> {
123 if v < 0 {
124 return None;
125 }
126 if v & (1 << 62) != 0 {
127 Some((
128 ((v >> 53) & 0xF) as u32,
129 ((v >> 32) & 0xFF) as u32,
130 ((v >> 21) & 0xF) as u32,
131 (v & 0xFF) as u32,
132 ))
133 } else {
134 Some((((v >> 21) & 0xFF) as u32, (v & 0x1F_FFFF) as u32, 0, 0))
135 }
136}
137
138fn class_subtype(class: u32) -> u16 {
140 match class {
141 1 => noad_sub::OP_DISPLAY_LIMITS,
142 2 => noad_sub::BIN,
143 3 => noad_sub::REL,
144 4 => noad_sub::OPEN,
145 5 => noad_sub::CLOSE,
146 6 => noad_sub::PUNCT,
147 _ => noad_sub::ORD,
148 }
149}
150
151pub const fn cramped_style(s: i32) -> i32 {
153 2 * (s / 2) + 1
154}
155
156pub const fn sub_style(s: i32) -> i32 {
158 2 * (s / 4) + 4 + 1
159}
160
161pub const fn sup_style(s: i32) -> i32 {
163 2 * (s / 4) + 4 + (s % 2)
164}
165
166pub const fn num_style(s: i32) -> i32 {
168 s + 2 - 2 * (s / 6)
169}
170
171pub const fn denom_style(s: i32) -> i32 {
173 2 * (s / 2) + 1 + 2 - 2 * (s / 6)
174}
175
176impl Engine {
177 pub fn new_noad(&mut self, sub: u16) -> NodeRef {
181 self.new_node(id::NOAD, sub, NodeData::Noad(Box::default()))
182 }
183
184 pub fn new_math_char(&mut self, fam: u32, chr: u32) -> NodeRef {
186 self.new_node(id::MATH_CHAR, 0, NodeData::MathChar { fam, chr })
187 }
188
189 pub fn new_sub_list(&mut self, mlist: bool, head: NodeRef) -> NodeRef {
191 self.new_node(
192 if mlist { id::SUB_MLIST } else { id::SUB_BOX },
193 0,
194 NodeData::SubList { head },
195 )
196 }
197
198 pub fn new_delim(&mut self, parts: (u32, u32, u32, u32)) -> NodeRef {
200 self.new_node(
201 id::DELIM,
202 0,
203 NodeData::Delim {
204 small_fam: parts.0,
205 small_char: parts.1,
206 large_fam: parts.2,
207 large_char: parts.3,
208 },
209 )
210 }
211
212 pub fn new_style(&mut self, s: u8) -> NodeRef {
214 self.new_node(id::STYLE, 0, NodeData::Style { style: s })
215 }
216
217 pub fn noad_field(&self, p: NodeRef, f: Field) -> NodeRef {
219 match self.nodes.noad(p) {
220 Some(n) => match f {
221 Field::Nucleus => n.nucleus,
222 Field::Sup => n.sup,
223 Field::Sub => n.sub,
224 Field::Degree => n.degree,
225 },
226 None => NodeRef::NULL,
227 }
228 }
229
230 pub fn set_noad_field(&mut self, p: NodeRef, f: Field, k: NodeRef) {
233 if let Some(n) = self.nodes.noad_mut(p) {
234 match f {
235 Field::Nucleus => n.nucleus = k,
236 Field::Sup => n.sup = k,
237 Field::Sub => n.sub = k,
238 Field::Degree => n.degree = k,
239 }
240 }
241 }
242
243 fn push_math(&mut self, c: GroupCode, style: i32) {
247 self.push_nest(Mode::Math);
248 self.cur_list_mut().incompleat_noad = NodeRef::NULL;
249 self.cur_list_mut().math_style = style;
250 self.new_save_level(c);
251 if c == GroupCode::MathShift {
252 self.begin_math_dirs();
253 }
254 }
255
256 pub fn init_math(&mut self) {
258 let shift_cs = self.cur_cmd == Cmd::MathShiftCs;
259 let display = if shift_cs {
260 self.cur_chr == 0 && self.mode == Mode::Horizontal
262 } else {
263 self.get_token();
264 if self.cur_cmd == Cmd::MathShift && self.mode == Mode::Horizontal {
265 true
266 } else {
267 self.back_input();
268 false
269 }
270 };
271 if display {
272 self.go_into_display_math();
273 } else {
274 self.go_into_ordinary_math();
275 }
276 }
277
278 fn go_into_ordinary_math(&mut self) {
279 self.push_math(GroupCode::MathShift, 2);
280 self.eq_define(Loc::IntPar(ip::FAM), Val::Int(-1));
281 let t = self.eqtb.toks_param(tp::EVERYMATH).clone();
282 if !t.is_empty() {
283 self.begin_token_list(t, TokKind::EveryMathText);
284 }
285 }
286
287 fn go_into_display_math(&mut self) {
290 let max_dimen = 0o7777777777;
291 let mut w = -max_dimen;
292 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
293 let only_local_par = self.nodes.next(head) == tail
294 && matches!(self.nodes.data(tail), NodeData::LocalPar { .. });
295 if head == tail || only_local_par {
296 if only_local_par {
298 self.nodes.flush_list(tail);
299 self.nodes.set_next(head, NodeRef::NULL);
300 }
301 self.pop_nest();
302 } else {
303 let wp = self.eqtb.int(ip::DISPLAYWIDOWPENALTY);
304 self.line_break(wp);
305 w = self.pre_display_width();
306 }
307 let prev_graf = self.cur_list().prev_graf;
309 let (l, s) = self.display_line_size(prev_graf);
310 self.push_math(GroupCode::MathShift, 0);
311 self.mode = Mode::DisplayMath;
312 self.cur_list_mut().mode = Mode::DisplayMath;
313 self.eq_define(Loc::IntPar(ip::FAM), Val::Int(-1));
314 self.eq_define(Loc::DimenPar(dp::PREDISPLAYSIZE), Val::Int(i64::from(w)));
315 self.eq_define(Loc::DimenPar(dp::DISPLAYWIDTH), Val::Int(i64::from(l)));
316 self.eq_define(Loc::DimenPar(dp::DISPLAYINDENT), Val::Int(i64::from(s)));
317 let t = self.eqtb.toks_param(tp::EVERYDISPLAY).clone();
318 if !t.is_empty() {
319 self.begin_token_list(t, TokKind::EveryDisplayText);
320 }
321 if self.nest.len() == 2 {
322 self.build_page();
323 }
324 }
325
326 fn pre_display_width(&mut self) -> i32 {
330 let max_dimen = 0o7777777777;
331 let jb = self.ts.just_box;
332 if jb.is_null() {
333 return -max_dimen;
334 }
335 let Some(b) = self.nodes.box_data(jb).cloned() else {
336 return -max_dimen;
337 };
338 let f = self.eqtb.cur_font.val;
339 let gap = self.eqtb.int(ip::PREDISPLAYGAPFACTOR);
340 let q = self.quad(f);
341 let extra = (q / 1000).wrapping_mul(gap);
343 let mut v = b.shift + extra;
344 let mut w = -max_dimen;
345 let mut p = b.head;
346 while !p.is_null() {
347 let (d, visible) = match self.nodes.data(p) {
348 NodeData::Glyph(_) => (self.glyph_dimensions(p).0, true),
349 NodeData::Box(bx) => (bx.width, true),
350 NodeData::Rule { width, .. } => (*width, true),
351 NodeData::Kern { kern, .. } => (*kern, false),
352 NodeData::MarginKern { width, .. } => (*width, false),
353 NodeData::Math { .. } => (self.nodes.width(p), false),
354 NodeData::Glue { spec, .. } => {
355 let spec = *spec;
356 if b.glue_sign == 1 {
357 if b.glue_order == spec.stretch_order && spec.stretch != 0 {
358 v = max_dimen;
359 }
360 } else if b.glue_sign == 2
361 && b.glue_order == spec.shrink_order
362 && spec.shrink != 0
363 {
364 v = max_dimen;
365 }
366 (
367 spec.width,
368 self.nodes.subtype(p) >= crate::nodes::glue_sub::A_LEADERS,
369 )
370 }
371 _ => (0, false),
372 };
373 if visible {
374 if v < max_dimen {
375 v += d;
376 w = v;
377 } else {
378 w = max_dimen;
379 break;
380 }
381 } else if v < max_dimen {
382 v += d;
383 }
384 p = self.nodes.next(p);
385 }
386 w
387 }
388
389 fn display_line_size(&self, prev_graf: i32) -> (i32, i32) {
391 let hsize = self.eqtb.dimen(dp::HSIZE);
392 match &self.eqtb.par_shape.val {
393 None => {
394 let hi = self.eqtb.dimen(dp::HANGINDENT);
395 let ha = self.eqtb.int(ip::HANGAFTER);
396 if hi != 0 && ((ha >= 0 && prev_graf + 2 > ha) || (prev_graf + 1 < -ha)) {
397 (hsize - hi.abs(), if hi > 0 { hi } else { 0 })
398 } else {
399 (hsize, 0)
400 }
401 }
402 Some(shape) => {
403 let n = (shape.len() / 2) as i32;
404 let i = if prev_graf + 2 >= n { n } else { prev_graf + 2 };
405 let k = 2 * (i.max(1) as usize - 1);
406 let indent = shape.get(k).copied().unwrap_or(0);
407 let len = shape.get(k + 1).copied().unwrap_or(hsize);
408 (len, indent)
409 }
410 }
411 }
412
413 pub fn math_command(&mut self) {
417 let cmd = self.cur_cmd;
418 match cmd {
419 Cmd::Letter | Cmd::OtherChar | Cmd::CharGiven => {
420 let code = self.eqtb.math.get(self.cur_chr);
421 self.set_math_char(MathChar::from_packed(code));
422 }
423 Cmd::CharNum => {
424 self.scan_char_num();
425 self.cur_chr = self.cur_val as u32;
426 let code = self.eqtb.math.get(self.cur_chr);
427 self.set_math_char(MathChar::from_packed(code));
428 }
429 Cmd::MathCharNum => {
430 let mc = self.scan_math_char_num();
431 self.set_math_char(mc);
432 }
433 Cmd::MathGiven => {
434 let mc = MathChar::from_given(self.cur_chr);
435 self.set_math_char(mc);
436 }
437 Cmd::XmathGiven => {
438 let mc = MathChar::from_packed(i64::from(self.cur_chr));
439 self.set_math_char(mc);
440 }
441 Cmd::DelimNum => {
442 let mc = self.scan_delim_num_char();
443 self.set_math_char(mc);
444 }
445 Cmd::LeftBrace => {
446 let n = self.new_noad(noad_sub::ORD);
447 self.tail_append(n);
448 self.back_input();
449 let st = self.cur_list().math_style;
450 self.scan_math(n, Field::Nucleus, st);
451 }
452 Cmd::MathComp => {
453 let sub = self.cur_chr as u16;
454 let n = self.new_noad(sub);
455 self.tail_append(n);
456 let st = self.cur_list().math_style;
457 let st = if sub == noad_sub::OVER || sub == noad_sub::UNDER {
458 if sub == noad_sub::OVER {
459 cramped_style(st)
460 } else {
461 st
462 }
463 } else {
464 st
465 };
466 self.scan_math(n, Field::Nucleus, st);
467 }
468 Cmd::LimitSwitch => self.math_limit_switch(),
469 Cmd::SupMark | Cmd::SubMark => {
470 let sup = cmd == Cmd::SupMark;
471 self.sub_sup(sup, false);
472 }
473 Cmd::SuperSubScript => {
474 let sup = self.cur_chr == Cmd::SupMark as u32;
475 self.sub_sup(sup, false);
476 }
477 Cmd::NoSuperSubScript => {
478 let sup = self.cur_chr == Cmd::SupMark as u32;
479 self.sub_sup(sup, true);
480 }
481 Cmd::Radical => self.math_radical(),
482 Cmd::Accent | Cmd::MathAccent => self.math_ac(),
483 Cmd::Vcenter => {
484 self.scan_spec(GroupCode::Vcenter, None);
485 self.normal_paragraph();
486 self.push_nest(Mode::InternalVertical);
487 self.cur_list_mut().prev_depth = IGNORE_DEPTH;
488 let t = self.eqtb.toks_param(tp::EVERYVBOX).clone();
489 if !t.is_empty() {
490 self.begin_token_list(t, TokKind::EveryVboxText);
491 }
492 }
493 Cmd::MathStyle => {
494 let s = self.cur_chr.min(7) as u8;
495 let n = self.new_style(s);
496 self.tail_append(n);
497 self.cur_list_mut().math_style = i32::from(s);
498 }
499 Cmd::NonScript => {
500 let g = self.new_glue_node(
501 crate::glue::Glue::ZERO,
502 crate::nodes::glue_sub::COND_MATH_GLUE,
503 );
504 self.tail_append(g);
505 }
506 Cmd::MathChoice => {
507 if self.cur_chr == 0 {
508 self.append_choices();
509 } else {
510 let n = self.new_noad(noad_sub::ORD);
512 self.tail_append(n);
513 let st = num_style(self.cur_list().math_style);
514 self.scan_left_brace();
515 let sub = self.new_sub_list(true, NodeRef::NULL);
516 self.set_noad_field(n, Field::Nucleus, sub);
517 self.push_saved(field_ref(n, Field::Nucleus));
518 self.push_math(GroupCode::Math, st);
519 }
520 }
521 Cmd::Above => self.math_fraction(),
522 Cmd::MathShift => {
523 if self.save.cur_group == GroupCode::MathShift {
524 self.after_math();
525 } else {
526 self.off_save();
527 }
528 }
529 Cmd::MathShiftCs => {
530 let c = self.cur_chr;
533 let ok = (c == 3 && self.mode == Mode::Math)
534 || (c == 1 && self.mode == Mode::DisplayMath);
535 if (c == 1 || c == 3) && self.save.cur_group == GroupCode::MathShift && ok {
536 self.after_math();
537 } else if c == 1 || c == 3 {
538 if self.save.cur_group == GroupCode::MathShift {
539 self.print_err("Invalid math code");
540 self.help(&["I'm going to ignore this math shift command."]);
541 self.error();
542 } else {
543 self.off_save();
544 }
545 } else {
546 self.report_illegal_case();
547 }
548 }
549 Cmd::EqNo => {
550 if self.privileged() {
551 if self.save.cur_group == GroupCode::MathShift {
552 self.start_eq_no();
553 } else {
554 self.off_save();
555 }
556 }
557 }
558 Cmd::LeftRight => self.math_left_right(),
559 Cmd::Endv
560 | Cmd::ParEnd
561 | Cmd::Stop
562 | Cmd::Vskip
563 | Cmd::UnVbox
564 | Cmd::Valign
565 | Cmd::Hrule => self.insert_dollar_sign(),
566 Cmd::Halign => {
567 if self.privileged() {
568 if self.save.cur_group == GroupCode::MathShift {
569 self.init_align();
570 } else {
571 self.off_save();
572 }
573 }
574 }
575 _ => {
576 let (c, r) = (self.cur_cmd, self.cur_chr);
577 let s = self.print_to_string(|e| e.print_cmd_chr(c, r));
578 self.not_implemented(&String::from_utf8_lossy(&s));
579 }
580 }
581 }
582
583 fn scan_math_char_num(&mut self) -> MathChar {
585 match self.cur_chr {
586 0 => {
587 let g = self.scan_math_given();
588 MathChar::from_given(g)
589 }
590 1 => {
591 let v = self.scan_umath_triple();
592 MathChar::from_packed(v)
593 }
594 _ => {
595 self.scan_int();
596 MathChar::from_packed(i64::from(self.cur_val))
597 }
598 }
599 }
600
601 fn scan_delim_num_char(&mut self) -> MathChar {
603 if self.cur_chr == 0 {
604 self.scan_twenty_seven_bit_int();
605 MathChar::from_classic(self.cur_val / 0o10000)
606 } else {
607 let v = self.scan_umath_triple();
608 MathChar::from_packed(v)
609 }
610 }
611
612 fn fam_in_range(&self) -> Option<u32> {
614 let f = self.eqtb.int(ip::FAM);
615 if (0..crate::eqtb::NUM_FAMILIES as i32).contains(&f) {
616 Some(f as u32)
617 } else {
618 None
619 }
620 }
621
622 fn effective_fam(&self, mc: MathChar) -> u32 {
625 if mc.class == 7
626 && let Some(f) = self.fam_in_range()
627 {
628 return f;
629 }
630 let vf = self.eqtb.int(ip::VARIABLEFAM);
631 if vf >= 0
632 && mc.fam == vf as u32
633 && let Some(f) = self.fam_in_range()
634 {
635 return f;
636 }
637 mc.fam
638 }
639
640 fn treat_as_active(&mut self) {
642 let cs = self.hash.active(self.cur_chr);
643 self.cur_cs = cs;
644 let m = self.eqtb.meaning(cs).clone();
645 self.cur_cmd = m.cmd;
646 self.cur_chr = m.chr;
647 self.x_token();
648 self.back_input();
649 }
650
651 fn set_math_char(&mut self, mc: MathChar) {
653 if mc.class >= 8 {
654 self.treat_as_active();
655 return;
656 }
657 let fam = self.effective_fam(mc);
658 let k = self.new_math_char(fam, mc.chr);
659 let sub = class_subtype(mc.class);
660 let p = self.new_noad(sub);
661 self.set_noad_field(p, Field::Nucleus, k);
662 self.tail_append(p);
663 }
664
665 fn scan_math(&mut self, p: NodeRef, f: Field, style: i32) -> bool {
669 self.scan_math_flag(p, f, style, 0)
670 }
671
672 fn scan_math_flag(&mut self, p: NodeRef, f: Field, style: i32, flag: i64) -> bool {
675 self.get_nonblank_nonrelax_noncall();
676 let mc = loop {
677 match self.cur_cmd {
678 Cmd::Letter | Cmd::OtherChar | Cmd::CharGiven => {
679 let code = self.eqtb.math.get(self.cur_chr);
680 let mc = MathChar::from_packed(code);
681 if mc.class == 8 {
682 self.treat_as_active();
683 self.get_nonblank_nonrelax_noncall();
684 continue;
685 }
686 break mc;
687 }
688 Cmd::CharNum => {
689 self.scan_char_num();
690 self.cur_chr = self.cur_val as u32;
691 self.cur_cmd = Cmd::CharGiven;
692 }
693 Cmd::MathCharNum => break self.scan_math_char_num(),
694 Cmd::MathGiven => break MathChar::from_given(self.cur_chr),
695 Cmd::XmathGiven => break MathChar::from_packed(i64::from(self.cur_chr)),
696 Cmd::DelimNum => break self.scan_delim_num_char(),
697 _ => {
698 self.back_input();
700 self.scan_left_brace();
701 let sub = self.new_sub_list(true, NodeRef::NULL);
702 let old = self.noad_field(p, f);
703 self.nodes.flush_list(old);
704 self.set_noad_field(p, f, sub);
705 self.push_saved(field_ref(p, f) | flag);
706 self.push_math(GroupCode::Math, style);
707 return true;
708 }
709 }
710 };
711 self.finish_scan_math(p, f, mc);
712 false
713 }
714
715 fn finish_scan_math(&mut self, p: NodeRef, f: Field, mc: MathChar) {
716 let fam = if mc.class == 8 {
717 0
718 } else {
719 self.effective_fam(mc)
720 };
721 let k = self.new_math_char(fam, mc.chr);
722 let old = self.noad_field(p, f);
723 self.nodes.flush_list(old);
724 self.set_noad_field(p, f, k);
725 }
726
727 fn math_limit_switch(&mut self) {
729 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
730 if head != tail
731 && self.nodes.id(tail) == id::NOAD
732 && matches!(
733 self.nodes.subtype(tail),
734 noad_sub::OP_DISPLAY_LIMITS | noad_sub::OP_LIMITS | noad_sub::OP_NO_LIMITS
735 )
736 {
737 self.nodes.set_subtype(tail, self.cur_chr as u16);
738 return;
739 }
740 self.print_err("Limit controls must follow a math operator");
741 self.help(&["I'm ignoring this misplaced \\limits or \\nolimits command."]);
742 self.error();
743 }
744
745 fn scan_delimiter(&mut self, radical: bool, fam_char: bool) -> NodeRef {
749 let parts: Option<(u32, u32, u32, u32)> = if fam_char {
750 self.scan_math_family();
751 let fam = self.cur_val as u32;
752 self.scan_char_num();
753 Some((fam, self.cur_val as u32, 0, 0))
754 } else if radical {
755 self.scan_twenty_seven_bit_int();
756 classic_delimiter(self.cur_val)
757 } else {
758 self.get_nonblank_nonrelax_noncall();
759 match self.cur_cmd {
760 Cmd::Letter | Cmd::OtherChar => delcode_parts(self.eqtb.del.get(self.cur_chr)),
761 Cmd::DelimNum => {
762 if self.cur_chr == 0 {
763 self.scan_twenty_seven_bit_int();
764 classic_delimiter(self.cur_val)
765 } else {
766 let v = self.scan_umath_triple();
767 let mc = MathChar::from_packed(v);
768 Some((mc.fam, mc.chr, 0, 0))
769 }
770 }
771 _ => None,
772 }
773 };
774 let parts = match parts {
775 Some(p) => p,
776 None => {
777 self.print_err("Missing delimiter (. inserted)");
778 self.help(&[
779 "I was expecting to see something like `(' or `\\{' or",
780 "`\\}' here. If you typed, e.g., `{' instead of `\\{', you",
781 "should probably delete the `{' by typing `1' now, so that",
782 "braces don't get unbalanced. Otherwise just proceed",
783 "Acceptable delimiters are characters whose \\delcode is",
784 "nonnegative, or you can use `\\delimiter <delimiter code>'.",
785 ]);
786 self.back_error();
787 (0, 0, 0, 0)
788 }
789 };
790 self.new_delim(parts)
791 }
792
793 fn math_radical(&mut self) {
795 let c = self.cur_chr as u16;
796 let p = self.new_node(id::RADICAL, c, NodeData::Noad(Box::default()));
797 self.tail_append(p);
798 let mut opts = 0u32;
799 let mut width = 0i32;
800 if c == radical_sub::UHEXTENSIBLE || c >= radical_sub::UUNDERDELIMITER {
801 loop {
802 if self.scan_keyword("width") {
803 self.scan_normal_dimen();
804 width = self.cur_val;
805 } else if self.scan_keyword("left") {
806 opts |= noad_opt::LEFT;
807 } else if self.scan_keyword("middle") {
808 opts |= noad_opt::MIDDLE;
809 } else if self.scan_keyword("right") {
810 opts |= noad_opt::RIGHT;
811 } else {
812 break;
813 }
814 }
815 }
816 let d = self.scan_delimiter(c == radical_sub::RADICAL, c != radical_sub::RADICAL);
817 if let Some(n) = self.nodes.noad_mut(p) {
818 n.left = d;
819 n.options = opts;
820 n.width = width;
821 }
822 let st = self.cur_list().math_style;
823 match c {
824 radical_sub::UHEXTENSIBLE => {}
825 radical_sub::UROOT => {
826 if !self.scan_math_flag(p, Field::Degree, 6, 1 << 62) {
830 self.scan_math(p, Field::Nucleus, cramped_style(st));
831 }
832 }
833 radical_sub::UUNDERDELIMITER => {
834 self.scan_math(p, Field::Nucleus, sub_style(st));
835 }
836 radical_sub::UOVERDELIMITER => {
837 self.scan_math(p, Field::Nucleus, sup_style(st));
838 }
839 radical_sub::UDELIMITERUNDER => {
840 self.scan_math(p, Field::Nucleus, st);
841 }
842 _ => {
843 self.scan_math(p, Field::Nucleus, cramped_style(st));
844 }
845 }
846 }
847
848 fn scan_accent_char(&mut self, umath: bool) -> (NodeRef, bool) {
850 let fixed = umath && self.scan_keyword("fixed");
851 let mc = if umath {
852 let v = self.scan_umath_triple();
853 MathChar::from_packed(v)
854 } else {
855 let g = self.scan_math_given();
856 MathChar::from_given(g)
857 };
858 let fam = if mc.class == 8 {
859 0
860 } else {
861 self.effective_fam(mc)
862 };
863 (self.new_math_char(fam, mc.chr), fixed)
864 }
865
866 fn math_ac(&mut self) {
868 if self.cur_cmd == Cmd::Accent {
869 self.back_input();
870 self.get_token();
871 self.print_err("Please use ");
872 self.print_esc_str("mathaccent");
873 self.printer.print_str(" for accents in math mode");
874 self.help(&[
875 "I'm changing \\accent to \\mathaccent here; wish me luck.",
876 "(Accents are not the same in formulas as they are in text.)",
877 ]);
878 self.error();
879 }
880 let umath = self.cur_cmd == Cmd::MathAccent && self.cur_chr == 1;
881 let p = self.new_node(
882 id::ACCENT,
883 accent_sub::BOTH_FLEXIBLE,
884 NodeData::Noad(Box::default()),
885 );
886 self.tail_append(p);
887 let mut sub = accent_sub::BOTH_FLEXIBLE;
888 let (mut top, mut bot) = (NodeRef::NULL, NodeRef::NULL);
889 let fraction = 0;
890 let mut overlay = false;
891 if umath {
892 let (want_top, want_bot) = if self.scan_keyword("bottom") {
893 (false, true)
894 } else if self.scan_keyword("both") {
895 (true, true)
896 } else if self.scan_keyword("overlay") {
897 overlay = true;
898 (true, false)
899 } else {
900 let _ = self.scan_keyword("top");
901 (true, false)
902 };
903 if want_top {
904 let (k, fixed) = self.scan_accent_char(true);
905 top = k;
906 if fixed {
907 sub |= accent_sub::FIXED_TOP;
908 }
909 }
910 if want_bot {
911 let (k, fixed) = self.scan_accent_char(true);
912 bot = k;
913 if fixed {
914 sub |= accent_sub::FIXED_BOTTOM;
915 }
916 }
917 } else {
918 top = self.scan_accent_char(false).0;
919 }
920 self.nodes.set_subtype(p, sub);
921 if let Some(n) = self.nodes.noad_mut(p) {
922 n.accent = top;
923 n.bot_accent = bot;
924 n.fraction = fraction;
925 if overlay {
926 n.options |= noad_opt::OVERLAY;
927 }
928 }
929 let st = cramped_style(self.cur_list().math_style);
930 self.scan_math(p, Field::Nucleus, st);
931 }
932
933 fn sub_sup(&mut self, sup: bool, no_style: bool) {
936 let field = if sup { Field::Sup } else { Field::Sub };
937 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
938 let mut target = NodeRef::NULL;
939 let mut t_nonempty = false;
940 if tail != head && self.nodes.scripts_allowed(tail) {
941 target = tail;
942 t_nonempty = !self.noad_field(tail, field).is_null();
943 }
944 if target.is_null() || t_nonempty {
945 let n = self.new_noad(noad_sub::ORD);
946 self.tail_append(n);
947 target = n;
948 if t_nonempty {
949 if sup {
950 self.print_err("Double superscript");
951 self.help(&["I treat `x^1^2' essentially like `x^1{}^2'."]);
952 } else {
953 self.print_err("Double subscript");
954 self.help(&["I treat `x_1_2' essentially like `x_1{}_2'."]);
955 }
956 self.error();
957 }
958 }
959 let st = self.cur_list().math_style;
960 let style = if no_style {
961 if let Some(n) = self.nodes.noad_mut(target) {
962 n.options |= if sup {
963 noad_opt::NO_SUPER_SCRIPT
964 } else {
965 noad_opt::NO_SUB_SCRIPT
966 };
967 }
968 st
969 } else if sup {
970 sup_style(st)
971 } else {
972 sub_style(st)
973 };
974 self.scan_math(target, field, style);
975 }
976
977 fn math_fraction(&mut self) {
979 let c = self.cur_chr;
980 let delimited = c >= 4;
982 let kind = c % 4;
983 if !self.cur_list().incompleat_noad.is_null() {
984 if delimited {
985 let a = self.scan_delimiter(false, false);
986 let b = self.scan_delimiter(false, false);
987 self.nodes.flush_list(a);
988 self.nodes.flush_list(b);
989 }
990 if kind == 3 {
991 let m = self.scan_delimiter(false, false);
992 self.nodes.flush_list(m);
993 self.scan_fraction_options();
994 } else if kind == 0 {
995 let _ = self.scan_keyword("exact");
996 self.scan_normal_dimen();
997 }
998 self.print_err("Ambiguous; you need another { and }");
999 self.help(&[
1000 "I'm ignoring this fraction specification, since I don't",
1001 "know whether a construction like `x \\over y \\over z'",
1002 "means `{x \\over y} \\over z' or `x \\over {y \\over z}'.",
1003 ]);
1004 self.error();
1005 return;
1006 }
1007 let head = self.cur_list().head;
1008 let first = self.nodes.next(head);
1009 let num = self.new_sub_list(true, first);
1010 let mut fr = FractionData {
1011 thickness: DEFAULT_CODE,
1012 num,
1013 denom: NodeRef::NULL,
1014 left: NodeRef::NULL,
1015 right: NodeRef::NULL,
1016 middle: NodeRef::NULL,
1017 options: 0,
1018 new_hlist: NodeRef::NULL,
1019 };
1020 self.nodes.set_next(head, NodeRef::NULL);
1021 self.cur_list_mut().tail = head;
1022 if delimited {
1023 fr.left = self.scan_delimiter(false, false);
1024 fr.right = self.scan_delimiter(false, false);
1025 }
1026 match kind {
1027 0 => {
1028 if self.scan_keyword("exact") {
1029 fr.options |= noad_opt::EXACT;
1030 }
1031 self.scan_normal_dimen();
1032 fr.thickness = self.cur_val;
1033 }
1034 1 => fr.thickness = DEFAULT_CODE,
1035 2 => fr.thickness = 0,
1036 _ => {
1037 fr.middle = self.scan_delimiter(false, false);
1038 fr.options |= self.scan_fraction_options();
1039 fr.thickness = 0;
1040 }
1041 }
1042 let n = self.new_node(id::FRACTION, 0, NodeData::Fraction(Box::new(fr)));
1043 self.cur_list_mut().incompleat_noad = n;
1044 }
1045
1046 fn scan_fraction_options(&mut self) -> u32 {
1048 let mut o = 0;
1049 loop {
1050 if self.scan_keyword("noaxis") {
1051 o |= noad_opt::NO_AXIS;
1052 } else if self.scan_keyword("exact") {
1053 o |= noad_opt::EXACT;
1054 } else {
1055 return o;
1056 }
1057 }
1058 }
1059
1060 fn fin_mlist(&mut self, p: NodeRef) -> NodeRef {
1063 let inc = self.cur_list().incompleat_noad;
1064 let head = self.cur_list().head;
1065 let q;
1066 if !inc.is_null() {
1067 let first = self.nodes.next(head);
1068 let denom = self.new_sub_list(true, first);
1069 if let NodeData::Fraction(f) = self.nodes.data_mut(inc) {
1070 f.denom = denom;
1071 }
1072 if p.is_null() {
1073 q = inc;
1074 } else {
1075 let num = match self.nodes.data(inc) {
1078 NodeData::Fraction(f) => f.num,
1079 _ => NodeRef::NULL,
1080 };
1081 let num_list = self.nodes.list_ptr_kernel(num);
1082 q = num_list;
1083 let dp = self.cur_list().delim_ptr;
1084 if num_list.is_null() || self.nodes.id(num_list) != id::FENCE || dp.is_null() {
1085 self.confusion("right");
1086 }
1087 let after = self.nodes.next(dp);
1088 self.nodes.set_kernel_list(num, after);
1089 if !after.is_null() {
1090 self.nodes.set_prev(after, NodeRef::NULL);
1091 }
1092 self.nodes.link(dp, inc);
1093 self.nodes.link(inc, p);
1094 }
1095 } else {
1096 let tail = self.cur_list().tail;
1097 self.nodes.link(tail, p);
1098 q = self.nodes.next(head);
1099 }
1100 self.nodes.set_next(head, NodeRef::NULL);
1101 if !q.is_null() {
1102 self.nodes.set_prev(q, NodeRef::NULL);
1103 }
1104 self.pop_nest();
1105 q
1106 }
1107
1108 pub fn math_right_brace(&mut self) {
1111 match self.save.cur_group {
1112 GroupCode::Math => {
1113 self.unsave();
1114 let r = self.pop_saved();
1115 let root_follows = r & (1 << 62) != 0;
1116 let (noad, f) = field_from_ref(r & !(1 << 62));
1117 let p = self.fin_mlist(NodeRef::NULL);
1118 let k = self.noad_field(noad, f);
1119 self.nodes.set_kernel_list(k, p);
1120 if !p.is_null() && self.nodes.next(p).is_null() {
1121 let pid = self.nodes.id(p);
1122 if pid == id::NOAD && self.nodes.subtype(p) == noad_sub::ORD {
1123 let (sub, sup) = (
1124 self.noad_field(p, Field::Sub),
1125 self.noad_field(p, Field::Sup),
1126 );
1127 if sub.is_null() && sup.is_null() {
1128 let nuc = self.noad_field(p, Field::Nucleus);
1130 self.set_noad_field(p, Field::Nucleus, NodeRef::NULL);
1131 self.nodes.flush_list(p);
1132 self.nodes.set_kernel_list(k, NodeRef::NULL);
1133 self.nodes.flush_list(k);
1134 self.set_noad_field(noad, f, nuc);
1135 }
1136 } else if pid == id::ACCENT
1137 && f == Field::Nucleus
1138 && noad == self.cur_list().tail
1139 && self.nodes.id(noad) == id::NOAD
1140 && self.nodes.subtype(noad) == noad_sub::ORD
1141 {
1142 let head = self.cur_list().head;
1144 let mut q = head;
1145 while self.nodes.next(q) != noad {
1146 q = self.nodes.next(q);
1147 }
1148 self.nodes.set_kernel_list(k, NodeRef::NULL);
1149 self.nodes.link(q, p);
1150 self.nodes.set_next(noad, NodeRef::NULL);
1151 self.nodes.flush_list(noad);
1152 self.cur_list_mut().tail = p;
1153 }
1154 }
1155 if root_follows {
1156 let st = cramped_style(self.cur_list().math_style);
1157 self.scan_math(noad, Field::Nucleus, st);
1158 }
1159 }
1160 GroupCode::MathChoice => self.build_choices(),
1161 GroupCode::Vcenter => {
1162 self.end_graf();
1163 self.unsave();
1164 let (spec, _dir) = self.pop_spec_pub();
1165 let head = self.cur_list().head;
1166 let first = self.nodes.next(head);
1167 self.nodes.set_next(head, NodeRef::NULL);
1168 let first = self.filter_list("vpack_filter", first, "vcenter");
1169 let d = self.eqtb.dimen(dp::BOXMAXDEPTH);
1170 let b = self.vpackage(first, spec, d);
1171 self.pop_nest();
1172 let n = self.new_noad(noad_sub::VCENTER);
1173 let k = self.new_sub_list(false, b);
1174 self.set_noad_field(n, Field::Nucleus, k);
1175 self.tail_append(n);
1176 }
1177 _ => self.confusion("rightbrace"),
1178 }
1179 }
1180
1181 fn append_choices(&mut self) {
1183 let c = self.new_node(
1184 id::CHOICE,
1185 0,
1186 NodeData::Choice(Box::new([NodeRef::NULL; 4])),
1187 );
1188 self.tail_append(c);
1189 self.push_saved(0);
1190 self.push_math(GroupCode::MathChoice, 0);
1191 self.scan_left_brace();
1192 }
1193
1194 fn build_choices(&mut self) {
1196 self.unsave();
1197 let p = self.fin_mlist(NodeRef::NULL);
1198 let k = self.pop_saved();
1199 let tail = self.cur_list().tail;
1200 if let NodeData::Choice(c) = self.nodes.data_mut(tail) {
1201 c[(k as usize).min(3)] = p;
1202 }
1203 if k >= 3 {
1204 return;
1205 }
1206 self.push_saved(k + 1);
1207 self.push_math(GroupCode::MathChoice, 2 * (k as i32 + 1));
1208 self.scan_left_brace();
1209 }
1210
1211 fn math_left_right(&mut self) {
1214 let c = self.cur_chr;
1215 if c == 14 {
1218 self.math_vextensible();
1219 return;
1220 }
1221 let t = match c % 10 {
1222 1 => fence_sub::LEFT,
1223 2 => fence_sub::MIDDLE,
1224 _ => fence_sub::RIGHT,
1225 };
1226 if t != fence_sub::LEFT && self.save.cur_group != GroupCode::MathLeft {
1227 if self.save.cur_group == GroupCode::MathShift {
1228 self.get_nonblank_nonrelax_noncall();
1230 if self.cur_cmd == Cmd::DelimNum {
1231 if self.cur_chr == 0 {
1232 self.scan_twenty_seven_bit_int();
1233 } else {
1234 self.scan_umath_triple();
1235 }
1236 }
1237 self.print_err("Extra ");
1238 if t == fence_sub::MIDDLE {
1239 self.print_esc_str("middle");
1240 self.help(&["I'm ignoring a \\middle that had no matching \\left."]);
1241 } else {
1242 self.print_esc_str("right");
1243 self.help(&["I'm ignoring a \\right that had no matching \\left."]);
1244 }
1245 self.error();
1246 } else {
1247 self.off_save();
1248 }
1249 return;
1250 }
1251 let mut fe = FenceData {
1252 class: -1,
1253 ..FenceData::default()
1254 };
1255 if c >= 10 {
1256 loop {
1257 if self.scan_keyword("height") {
1258 self.scan_normal_dimen();
1259 fe.height = self.cur_val;
1260 } else if self.scan_keyword("depth") {
1261 self.scan_normal_dimen();
1262 fe.depth = self.cur_val;
1263 } else if self.scan_keyword("axis") {
1264 fe.options |= noad_opt::AXIS;
1265 } else if self.scan_keyword("noaxis") {
1266 fe.options |= noad_opt::NO_AXIS;
1267 } else if self.scan_keyword("exact") {
1268 fe.options |= noad_opt::EXACT;
1269 } else if self.scan_keyword("class") {
1270 self.scan_int();
1271 fe.class = self.cur_val;
1272 } else {
1273 break;
1274 }
1275 }
1276 }
1277 fe.delim = self.scan_delimiter(false, false);
1278 let p = self.new_node(id::FENCE, t, NodeData::Fence(Box::new(fe)));
1279 let q = if t == fence_sub::LEFT {
1280 p
1281 } else {
1282 let q = self.fin_mlist(p);
1283 self.unsave();
1284 q
1285 };
1286 if t != fence_sub::RIGHT {
1287 let st = self.cur_list().math_style;
1288 self.push_math(GroupCode::MathLeft, st);
1289 let head = self.cur_list().head;
1290 self.nodes.link(head, q);
1291 self.cur_list_mut().tail = p;
1292 self.cur_list_mut().delim_ptr = p;
1293 } else {
1294 let n = self.new_noad(noad_sub::INNER);
1295 let k = self.new_sub_list(true, q);
1296 self.set_noad_field(n, Field::Nucleus, k);
1297 self.tail_append(n);
1298 }
1299 }
1300
1301 fn math_vextensible(&mut self) {
1303 let mut fe = FenceData {
1304 class: -1,
1305 ..FenceData::default()
1306 };
1307 loop {
1308 if self.scan_keyword("height") {
1309 self.scan_normal_dimen();
1310 fe.height = self.cur_val;
1311 } else if self.scan_keyword("depth") {
1312 self.scan_normal_dimen();
1313 fe.depth = self.cur_val;
1314 } else if self.scan_keyword("axis") {
1315 fe.options |= noad_opt::AXIS;
1316 } else if self.scan_keyword("noaxis") {
1317 fe.options |= noad_opt::NO_AXIS;
1318 } else if self.scan_keyword("exact") {
1319 fe.options |= noad_opt::EXACT;
1320 } else {
1321 break;
1322 }
1323 }
1324 fe.delim = self.scan_delimiter(false, false);
1325 let p = self.new_node(id::FENCE, fence_sub::MIDDLE, NodeData::Fence(Box::new(fe)));
1326 let n = self.new_noad(noad_sub::INNER);
1327 let k = self.new_sub_list(true, p);
1328 self.set_noad_field(n, Field::Nucleus, k);
1329 self.tail_append(n);
1330 }
1331
1332 fn start_eq_no(&mut self) {
1334 self.push_saved(i64::from(self.cur_chr));
1335 self.go_into_ordinary_math();
1336 }
1337
1338 pub fn math_box_end(&mut self, b: NodeRef) {
1341 let n = self.new_noad(noad_sub::ORD);
1342 let k = self.new_sub_list(false, b);
1343 self.set_noad_field(n, Field::Nucleus, k);
1344 self.tail_append(n);
1345 }
1346
1347 pub fn math_char_in_text(&mut self) {
1350 let mc = match self.cur_cmd {
1351 Cmd::MathCharNum => self.scan_math_char_num(),
1352 Cmd::MathGiven => MathChar::from_given(self.cur_chr),
1353 _ => MathChar::from_packed(i64::from(self.cur_chr)),
1354 };
1355 if mc.class >= 8 {
1356 self.treat_as_active();
1357 return;
1358 }
1359 let f = self.fam_fnt(mc.fam, 0);
1360 let g = self.new_char_node(f, mc.chr);
1361 self.tail_append(g);
1362 self.cur_list_mut().space_factor = 1000;
1363 }
1364
1365 pub fn fam_fnt(&self, fam: u32, size: u32) -> u32 {
1368 self.eqtb
1369 .math_font
1370 .get((size * crate::eqtb::NUM_FAMILIES as u32 + fam) as usize)
1371 .map_or(0, |s| s.val)
1372 }
1373
1374 fn after_math(&mut self) {
1378 let mut m = self.mode;
1379 let mut l = false;
1380 let mut p = self.fin_mlist(NodeRef::NULL);
1381 let a;
1382 if self.mode == Mode::DisplayMath && m == Mode::Math {
1383 self.check_dollar_follows();
1385 let hl = self.mlist_to_hlist(p, 2, false);
1386 a = self.hpack(hl, PackSpec::NATURAL);
1387 self.unsave();
1388 if self.pop_saved() == 1 {
1389 l = true;
1390 }
1391 m = self.mode;
1392 p = self.fin_mlist(NodeRef::NULL);
1393 } else {
1394 a = NodeRef::NULL;
1395 }
1396 if m == Mode::Math {
1397 self.finish_math_in_text(p);
1398 } else {
1399 if a.is_null() {
1400 self.check_dollar_follows();
1401 }
1402 self.finish_displayed_math(p, a, l);
1403 }
1404 }
1405
1406 fn check_dollar_follows(&mut self) {
1408 self.get_x_token();
1409 if self.cur_cmd != Cmd::MathShift
1410 && !(self.cur_cmd == Cmd::MathShiftCs && self.cur_chr == 1)
1411 {
1412 self.print_err("Display math should end with $$");
1413 self.help(&[
1414 "The `$' that I just saw supposedly matches a previous `$$'.",
1415 "So I shall assume that you typed `$$' both times.",
1416 ]);
1417 self.back_error();
1418 }
1419 }
1420
1421 fn finish_math_in_text(&mut self, p: NodeRef) {
1422 let ms = self.eqtb.dimen(dp::MATHSURROUND);
1423 let mg = self
1424 .eqtb
1425 .glue(crate::primitives_gen::assign_glue::MATHSURROUNDSKIP);
1426 let pen = self.mode == Mode::Horizontal;
1427 let hl = self.mlist_to_hlist(p, 2, pen);
1428 self.unsave();
1429 let math_dir = self.dir_param(crate::primitives_gen::assign_dir::MATHDIR);
1432 let text_dir = self.dir_param(crate::primitives_gen::assign_dir::TEXTDIR);
1433 let wrap = (math_dir != text_dir).then(|| math_dir.rem_euclid(4) as i8);
1434 let b = self.new_math_node(ms, mg, 0);
1435 self.tail_append(b);
1436 if let Some(d) = wrap {
1437 let p = self.new_dir_node(d, false);
1438 self.tail_append(p);
1439 }
1440 let tail = self.cur_list().tail;
1441 self.nodes.link(tail, hl);
1442 let mut t = tail;
1443 while !self.nodes.next(t).is_null() {
1444 t = self.nodes.next(t);
1445 }
1446 self.cur_list_mut().tail = t;
1447 if let Some(d) = wrap {
1448 let p = self.new_dir_node(d, true);
1449 self.tail_append(p);
1450 }
1451 let e = self.new_math_node(ms, mg, 1);
1452 self.tail_append(e);
1453 self.cur_list_mut().space_factor = 1000;
1454 }
1455
1456 fn new_math_node(&mut self, surround: i32, skip: crate::glue::Glue, sub: u16) -> NodeRef {
1458 let p = self.new_node(
1459 id::MATH,
1460 sub,
1461 NodeData::Math {
1462 surround,
1463 glue: crate::glue::Glue::ZERO,
1464 },
1465 );
1466 if (skip.width != 0 || skip.stretch != 0 || skip.shrink != 0)
1467 && let NodeData::Math { glue, .. } = self.nodes.data_mut(p)
1468 {
1469 *glue = skip;
1470 }
1471 p
1472 }
1473
1474 fn finish_displayed_math(&mut self, p: NodeRef, a: NodeRef, l: bool) {
1476 use crate::nodes::glue_sub as gs;
1477 let hl = self.mlist_to_hlist(p, 0, false);
1478 let adj_head = self.nodes.new_temp();
1479 self.ts.adjust_tail = Some(adj_head);
1480 let mut b = self.hpack(hl, PackSpec::NATURAL);
1481 let p = self.nodes.list_ptr(b);
1482 let t = self.ts.adjust_tail.unwrap_or(adj_head);
1483 self.ts.adjust_tail = None;
1484 let mut w = self.nodes.box_data(b).map_or(0, |x| x.width);
1485 let z = self.eqtb.dimen(dp::DISPLAYWIDTH);
1486 let s = self.eqtb.dimen(dp::DISPLAYINDENT);
1487 let (mut e, q) = if a.is_null() {
1488 (0, 0)
1489 } else {
1490 let e = self.nodes.box_data(a).map_or(0, |x| x.width);
1491 let f2 = self.fam_fnt(2, 0);
1492 let mq = self.math_quad_text(f2);
1493 let step = self.eqtb.int(ip::MATHEQNOGAPSTEP);
1494 let gap = if step == 1000 {
1495 mq
1496 } else {
1497 retex_arith::xn_over_d(mq, step, 1000).map_or(0, |r| r.quotient)
1498 };
1499 (e, e + gap)
1500 };
1501 if w + q > z {
1502 let tot = self.ts.last_totals;
1504 if e != 0
1505 && (w - tot.1[0] + q <= z
1506 || tot.1[1] != 0
1507 || tot.1[2] != 0
1508 || tot.1[3] != 0
1509 || tot.1[4] != 0)
1510 {
1511 self.nodes.set_list_ptr(b, NodeRef::NULL);
1512 self.nodes.free(b);
1513 b = self.hpack(p, PackSpec::Exactly(z - q));
1514 } else {
1515 e = 0;
1516 if w > z {
1517 self.nodes.set_list_ptr(b, NodeRef::NULL);
1518 self.nodes.free(b);
1519 b = self.hpack(p, PackSpec::Exactly(z));
1520 }
1521 }
1522 w = self.nodes.box_data(b).map_or(0, |x| x.width);
1523 }
1524 self.nodes.set_subtype(b, 6); let mut d = half(z - w);
1527 if e > 0 && d < 2 * e {
1528 d = half(z - w - e);
1529 let p = self.nodes.list_ptr(b);
1530 if !p.is_null() && self.nodes.id(p) == id::GLUE {
1531 d = 0;
1532 }
1533 }
1534 let pen = self.new_penalty_node(self.eqtb.int(ip::PREDISPLAYPENALTY));
1536 self.tail_append(pen);
1537 let pds = self.eqtb.dimen(dp::PREDISPLAYSIZE);
1538 let (g1, mut g2) = if d + s <= pds || l {
1539 (gs::ABOVE_DISPLAY, gs::BELOW_DISPLAY)
1540 } else {
1541 (gs::ABOVE_DISPLAY_SHORT, gs::BELOW_DISPLAY_SHORT)
1542 };
1543 let mode = self.eqtb.int(ip::MATHDISPLAYSKIPMODE);
1544 if l && e == 0 {
1545 if let Some(bd) = self.nodes.box_data_mut(a) {
1546 bd.shift = s;
1547 }
1548 self.nodes.set_subtype(a, 7);
1549 self.append_to_vlist(a);
1550 let pen = self.new_penalty_node(10000);
1551 self.tail_append(pen);
1552 } else {
1553 self.append_display_skip(g1, mode, true);
1554 }
1555 if e != 0 {
1560 let r = self.new_kern_node(z - w - e - d, 0);
1561 self.nodes.set_subtype(a, 7);
1562 let k = self.new_kern_node(if l { z - w - d } else { d }, 0);
1565 if l {
1566 self.nodes.link(a, r);
1567 self.nodes.link(r, b);
1568 self.nodes.link(b, k);
1569 b = a;
1570 } else {
1571 self.nodes.link(k, b);
1572 self.nodes.link(b, r);
1573 self.nodes.link(r, a);
1574 b = k;
1575 }
1576 b = self.hpack(b, PackSpec::NATURAL);
1577 d = 0;
1578 }
1579 if let Some(bd) = self.nodes.box_data_mut(b) {
1580 bd.shift = s + d;
1581 }
1582 self.append_to_vlist(b);
1583 if !a.is_null() && e == 0 && !l {
1585 let pen = self.new_penalty_node(10000);
1586 self.tail_append(pen);
1587 let aw = self.nodes.box_data(a).map_or(0, |x| x.width);
1588 if let Some(bd) = self.nodes.box_data_mut(a) {
1589 bd.shift = s + z - aw;
1590 }
1591 self.nodes.set_subtype(a, 7);
1592 self.append_to_vlist(a);
1593 g2 = 0;
1594 }
1595 if t != adj_head {
1596 let first = self.nodes.next(adj_head);
1597 let tail = self.cur_list().tail;
1598 self.nodes.link(tail, first);
1599 self.cur_list_mut().tail = t;
1600 }
1601 self.nodes.free(adj_head);
1602 let pen = self.new_penalty_node(self.eqtb.int(ip::POSTDISPLAYPENALTY));
1603 self.tail_append(pen);
1604 if g2 > 0 {
1605 self.append_display_skip(g2, mode, false);
1606 }
1607 self.resume_after_display();
1608 }
1609
1610 fn append_display_skip(&mut self, sub: u16, mode: i32, _above: bool) {
1614 let g = self.eqtb.glue(crate::build::glue_param_of_subtype(sub));
1615 let zero = g.width == 0 && g.stretch == 0 && g.shrink == 0;
1616 let skip = match mode {
1617 2 => zero,
1618 3 => true,
1619 _ => false,
1620 };
1621 if !skip {
1622 let n = self.new_param_glue(sub);
1623 self.tail_append(n);
1624 }
1625 }
1626
1627 fn math_quad_text(&self, f2: u32) -> i32 {
1629 let v = self.math_param_value(0, 2);
1630 if v != crate::codes::UNDEFINED_MATH_PARAM {
1631 v
1632 } else {
1633 self.quad(f2)
1634 }
1635 }
1636
1637 pub fn math_param_value(&self, p: u32, s: u32) -> i32 {
1639 self.eqtb
1640 .math_param
1641 .get(&(p * 8 + s))
1642 .map_or(crate::codes::UNDEFINED_MATH_PARAM, |x| x.val)
1643 }
1644
1645 fn resume_after_display(&mut self) {
1647 if self.save.cur_group != GroupCode::MathShift {
1648 self.confusion("display");
1649 }
1650 self.unsave();
1651 let pg = self.cur_list().prev_graf + 3;
1652 self.cur_list_mut().prev_graf = pg;
1653 self.push_nest(Mode::Horizontal);
1654 self.cur_list_mut().space_factor = 1000;
1655 let l = self.cur_lang() as i32;
1656 self.cur_list_mut().clang = l;
1657 let lp = self.new_local_par();
1658 self.tail_append(lp);
1659 self.get_x_token();
1661 if self.cur_cmd != Cmd::Spacer {
1662 self.back_input();
1663 }
1664 if self.nest.len() == 2 {
1665 self.build_page();
1666 }
1667 }
1668
1669 pub fn finish_display_alignment(&mut self, p: NodeRef, q: NodeRef, aux_save: i32) {
1671 self.do_assignments();
1672 if self.cur_cmd != Cmd::MathShift {
1673 self.print_err("Missing $$ inserted");
1674 self.help(&[
1675 "Displays can use special alignments (like \\eqalignno)",
1676 "only if nothing but the alignment itself is between $$'s.",
1677 ]);
1678 self.back_error();
1679 } else {
1680 self.check_dollar_follows();
1681 }
1682 self.pop_nest();
1683 let pen = self.new_penalty_node(self.eqtb.int(ip::PREDISPLAYPENALTY));
1684 self.tail_append(pen);
1685 let g = self.new_param_glue(crate::nodes::glue_sub::ABOVE_DISPLAY);
1686 self.tail_append(g);
1687 let tail = self.cur_list().tail;
1688 self.nodes.link(tail, p);
1689 if !p.is_null() {
1690 self.cur_list_mut().tail = q;
1691 }
1692 let pen = self.new_penalty_node(self.eqtb.int(ip::POSTDISPLAYPENALTY));
1693 self.tail_append(pen);
1694 let g = self.new_param_glue(crate::nodes::glue_sub::BELOW_DISPLAY);
1695 self.tail_append(g);
1696 self.cur_list_mut().prev_depth = aux_save;
1697 self.resume_after_display();
1698 }
1699
1700 pub fn flush_math(&mut self) {
1702 let head = self.cur_list().head;
1703 let first = self.nodes.next(head);
1704 self.nodes.flush_list(first);
1705 let inc = self.cur_list().incompleat_noad;
1706 self.nodes.flush_list(inc);
1707 self.nodes.set_next(head, NodeRef::NULL);
1708 self.cur_list_mut().tail = head;
1709 self.cur_list_mut().incompleat_noad = NodeRef::NULL;
1710 }
1711
1712 pub fn ins_tokens(&mut self, toks: Vec<Token>) {
1714 self.ins_list(Rc::from(toks));
1715 }
1716}
1717
1718pub use retex_arith::half;
1719
1720fn classic_delimiter(v: i32) -> Option<(u32, u32, u32, u32)> {
1722 if v < 0 {
1723 return None;
1724 }
1725 let v = v as u32;
1726 Some((
1727 (v / 0o4000000) % 16,
1728 (v / 0o10000) % 256,
1729 (v / 256) % 16,
1730 v % 256,
1731 ))
1732}