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, u16::from(s), 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_from("before_display");
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 NodeData::Disc { replace, .. } => {
375 let mut r = *replace;
376 let (mut u, mut last) = (0, None);
377 while !r.is_null() {
378 let (d, vis) = match self.nodes.data(r) {
379 NodeData::Glyph(_) => (self.glyph_dimensions(r).0, true),
380 NodeData::Box(bx) => (bx.width, true),
381 NodeData::Rule { width, .. } => (*width, true),
382 NodeData::Kern { kern, .. } => (*kern, false),
383 _ => (0, false),
384 };
385 u += d;
386 if vis {
387 last = Some(u);
388 }
389 r = self.nodes.next(r);
390 }
391 last.map_or((0, false), |u| (u, true))
392 }
393 _ => (0, false),
394 };
395 if visible {
396 if v < max_dimen {
397 v += d;
398 w = v;
399 } else {
400 w = max_dimen;
401 break;
402 }
403 } else if v < max_dimen {
404 v += d;
405 }
406 p = self.nodes.next(p);
407 }
408 w
409 }
410
411 fn display_line_size(&self, prev_graf: i32) -> (i32, i32) {
413 let hsize = self.eqtb.dimen(dp::HSIZE);
414 match &self.eqtb.par_shape.val {
415 None => {
416 let hi = self.eqtb.dimen(dp::HANGINDENT);
417 let ha = self.eqtb.int(ip::HANGAFTER);
418 if hi != 0 && ((ha >= 0 && prev_graf + 2 > ha) || (prev_graf + 1 < -ha)) {
419 (hsize - hi.abs(), if hi > 0 { hi } else { 0 })
420 } else {
421 (hsize, 0)
422 }
423 }
424 Some(shape) => {
425 let n = (shape.len() / 2) as i32;
426 let i = if prev_graf + 2 >= n { n } else { prev_graf + 2 };
427 let k = 2 * (i.max(1) as usize - 1);
428 let indent = shape.get(k).copied().unwrap_or(0);
429 let len = shape.get(k + 1).copied().unwrap_or(hsize);
430 (len, indent)
431 }
432 }
433 }
434
435 pub fn math_command(&mut self) {
439 let cmd = self.cur_cmd;
440 match cmd {
441 Cmd::Letter | Cmd::OtherChar | Cmd::CharGiven => {
442 let code = self.eqtb.math.get(self.cur_chr);
443 self.set_math_char(MathChar::from_packed(code));
444 }
445 Cmd::CharNum => {
446 self.scan_char_num();
447 self.cur_chr = self.cur_val as u32;
448 let code = self.eqtb.math.get(self.cur_chr);
449 self.set_math_char(MathChar::from_packed(code));
450 }
451 Cmd::MathCharNum => {
452 let mc = self.scan_math_char_num();
453 self.set_math_char(mc);
454 }
455 Cmd::MathGiven => {
456 let mc = MathChar::from_given(self.cur_chr);
457 self.set_math_char(mc);
458 }
459 Cmd::XmathGiven => {
460 let mc = MathChar::from_packed(i64::from(self.cur_chr));
461 self.set_math_char(mc);
462 }
463 Cmd::DelimNum => {
464 let mc = self.scan_delim_num_char();
465 self.set_math_char(mc);
466 }
467 Cmd::LeftBrace => {
468 let n = self.new_noad(noad_sub::ORD);
469 self.tail_append(n);
470 self.back_input();
471 let st = self.cur_list().math_style;
472 self.scan_math(n, Field::Nucleus, st);
473 }
474 Cmd::MathComp => {
475 let sub = self.cur_chr as u16;
476 let n = self.new_noad(sub);
477 self.tail_append(n);
478 let st = self.cur_list().math_style;
479 let st = if sub == noad_sub::OVER || sub == noad_sub::UNDER {
480 if sub == noad_sub::OVER {
481 cramped_style(st)
482 } else {
483 st
484 }
485 } else {
486 st
487 };
488 self.scan_math(n, Field::Nucleus, st);
489 }
490 Cmd::LimitSwitch => self.math_limit_switch(),
491 Cmd::SupMark | Cmd::SubMark => {
492 let sup = cmd == Cmd::SupMark;
493 self.sub_sup(sup, false);
494 }
495 Cmd::SuperSubScript => {
496 let sup = self.cur_chr == Cmd::SupMark as u32;
497 self.sub_sup(sup, false);
498 }
499 Cmd::NoSuperSubScript => {
500 let sup = self.cur_chr == Cmd::SupMark as u32;
501 self.sub_sup(sup, true);
502 }
503 Cmd::Radical => self.math_radical(),
504 Cmd::Accent | Cmd::MathAccent => self.math_ac(),
505 Cmd::Vcenter => {
506 self.scan_spec(GroupCode::Vcenter, None);
507 self.normal_paragraph();
508 self.push_nest(Mode::InternalVertical);
509 self.cur_list_mut().prev_depth = IGNORE_DEPTH;
510 let t = self.eqtb.toks_param(tp::EVERYVBOX).clone();
511 if !t.is_empty() {
512 self.begin_token_list(t, TokKind::EveryVboxText);
513 }
514 }
515 Cmd::MathStyle => {
516 let s = self.cur_chr.min(7) as u8;
517 let n = self.new_style(s);
518 self.tail_append(n);
519 self.cur_list_mut().math_style = i32::from(s);
520 }
521 Cmd::NonScript => {
522 let g = self.new_glue_node(
523 crate::glue::Glue::ZERO,
524 crate::nodes::glue_sub::COND_MATH_GLUE,
525 );
526 self.tail_append(g);
527 }
528 Cmd::MathChoice => {
529 if self.cur_chr == 0 {
530 self.append_choices();
531 } else {
532 let n = self.new_noad(noad_sub::ORD);
534 self.tail_append(n);
535 let st = num_style(self.cur_list().math_style);
536 self.scan_left_brace();
537 let sub = self.new_sub_list(true, NodeRef::NULL);
538 self.set_noad_field(n, Field::Nucleus, sub);
539 self.push_saved(field_ref(n, Field::Nucleus));
540 self.push_math(GroupCode::Math, st);
541 }
542 }
543 Cmd::Above => self.math_fraction(),
544 Cmd::MathShift => {
545 if self.save.cur_group == GroupCode::MathShift {
546 self.after_math();
547 } else {
548 self.off_save();
549 }
550 }
551 Cmd::MathShiftCs => {
552 let c = self.cur_chr;
555 let ok = (c == 3 && self.mode == Mode::Math)
556 || (c == 1 && self.mode == Mode::DisplayMath);
557 if (c == 1 || c == 3) && self.save.cur_group == GroupCode::MathShift && ok {
558 self.after_math();
559 } else if c == 1 || c == 3 {
560 if self.save.cur_group == GroupCode::MathShift {
561 self.print_err("Invalid math code");
562 self.help(&["I'm going to ignore this math shift command."]);
563 self.error();
564 } else {
565 self.off_save();
566 }
567 } else {
568 self.report_illegal_case();
569 }
570 }
571 Cmd::EqNo => {
572 if self.privileged() {
573 if self.save.cur_group == GroupCode::MathShift {
574 self.start_eq_no();
575 } else {
576 self.off_save();
577 }
578 }
579 }
580 Cmd::LeftRight => self.math_left_right(),
581 Cmd::Endv
582 | Cmd::ParEnd
583 | Cmd::Stop
584 | Cmd::Vskip
585 | Cmd::UnVbox
586 | Cmd::Valign
587 | Cmd::Hrule => self.insert_dollar_sign(),
588 Cmd::Halign => {
589 if self.privileged() {
590 if self.save.cur_group == GroupCode::MathShift {
591 self.init_align();
592 } else {
593 self.off_save();
594 }
595 }
596 }
597 _ => {
598 let (c, r) = (self.cur_cmd, self.cur_chr);
599 let s = self.print_to_string(|e| e.print_cmd_chr(c, r));
600 self.not_implemented(&String::from_utf8_lossy(&s));
601 }
602 }
603 }
604
605 fn scan_math_char_num(&mut self) -> MathChar {
607 match self.cur_chr {
608 0 => {
609 let g = self.scan_math_given();
610 MathChar::from_given(g)
611 }
612 1 => {
613 let v = self.scan_umath_triple();
614 MathChar::from_packed(v)
615 }
616 _ => {
617 self.scan_int();
618 MathChar::from_packed(i64::from(self.cur_val))
619 }
620 }
621 }
622
623 fn scan_delim_num_char(&mut self) -> MathChar {
625 if self.cur_chr == 0 {
626 self.scan_twenty_seven_bit_int();
627 MathChar::from_classic(self.cur_val / 0o10000)
628 } else {
629 let v = self.scan_umath_triple();
630 MathChar::from_packed(v)
631 }
632 }
633
634 fn fam_in_range(&self) -> Option<u32> {
636 let f = self.eqtb.int(ip::FAM);
637 if (0..crate::eqtb::NUM_FAMILIES as i32).contains(&f) {
638 Some(f as u32)
639 } else {
640 None
641 }
642 }
643
644 fn effective_fam(&self, mc: MathChar) -> u32 {
647 if mc.class == 7
648 && let Some(f) = self.fam_in_range()
649 {
650 return f;
651 }
652 let vf = self.eqtb.int(ip::VARIABLEFAM);
653 if vf >= 0
654 && mc.fam == vf as u32
655 && let Some(f) = self.fam_in_range()
656 {
657 return f;
658 }
659 mc.fam
660 }
661
662 fn treat_as_active(&mut self) {
664 let cs = self.hash.active(self.cur_chr);
665 self.cur_cs = cs;
666 let m = self.eqtb.meaning(cs).clone();
667 self.cur_cmd = m.cmd;
668 self.cur_chr = m.chr;
669 self.x_token();
670 self.back_input();
671 }
672
673 fn set_math_char(&mut self, mc: MathChar) {
675 if mc.class >= 8 {
676 self.treat_as_active();
677 return;
678 }
679 let fam = self.effective_fam(mc);
680 let k = self.new_math_char(fam, mc.chr);
681 let sub = class_subtype(mc.class);
682 let p = self.new_noad(sub);
683 self.set_noad_field(p, Field::Nucleus, k);
684 self.tail_append(p);
685 }
686
687 fn scan_math(&mut self, p: NodeRef, f: Field, style: i32) -> bool {
691 self.scan_math_flag(p, f, style, 0)
692 }
693
694 fn scan_math_flag(&mut self, p: NodeRef, f: Field, style: i32, flag: i64) -> bool {
697 self.get_nonblank_nonrelax_noncall();
698 let mc = loop {
699 match self.cur_cmd {
700 Cmd::Letter | Cmd::OtherChar | Cmd::CharGiven => {
701 let code = self.eqtb.math.get(self.cur_chr);
702 let mc = MathChar::from_packed(code);
703 if mc.class == 8 {
704 self.treat_as_active();
705 self.get_nonblank_nonrelax_noncall();
706 continue;
707 }
708 break mc;
709 }
710 Cmd::CharNum => {
711 self.scan_char_num();
712 self.cur_chr = self.cur_val as u32;
713 self.cur_cmd = Cmd::CharGiven;
714 }
715 Cmd::MathCharNum => break self.scan_math_char_num(),
716 Cmd::MathGiven => break MathChar::from_given(self.cur_chr),
717 Cmd::XmathGiven => break MathChar::from_packed(i64::from(self.cur_chr)),
718 Cmd::DelimNum => break self.scan_delim_num_char(),
719 _ => {
720 self.back_input();
722 self.scan_left_brace();
723 let sub = self.new_sub_list(true, NodeRef::NULL);
724 let old = self.noad_field(p, f);
725 self.nodes.flush_list(old);
726 self.set_noad_field(p, f, sub);
727 self.push_saved(field_ref(p, f) | flag);
728 self.push_math(GroupCode::Math, style);
729 return true;
730 }
731 }
732 };
733 self.finish_scan_math(p, f, mc);
734 false
735 }
736
737 fn finish_scan_math(&mut self, p: NodeRef, f: Field, mc: MathChar) {
738 let fam = if mc.class == 8 {
739 0
740 } else {
741 self.effective_fam(mc)
742 };
743 let k = self.new_math_char(fam, mc.chr);
744 let old = self.noad_field(p, f);
745 self.nodes.flush_list(old);
746 self.set_noad_field(p, f, k);
747 }
748
749 fn math_limit_switch(&mut self) {
751 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
752 if head != tail
753 && self.nodes.id(tail) == id::NOAD
754 && matches!(
755 self.nodes.subtype(tail),
756 noad_sub::OP_DISPLAY_LIMITS | noad_sub::OP_LIMITS | noad_sub::OP_NO_LIMITS
757 )
758 {
759 self.nodes.set_subtype(tail, self.cur_chr as u16);
760 return;
761 }
762 self.print_err("Limit controls must follow a math operator");
763 self.help(&["I'm ignoring this misplaced \\limits or \\nolimits command."]);
764 self.error();
765 }
766
767 fn scan_delimiter(&mut self, radical: bool, fam_char: bool) -> NodeRef {
771 let parts: Option<(u32, u32, u32, u32)> = if fam_char {
772 self.scan_math_family();
773 let fam = self.cur_val as u32;
774 self.scan_char_num();
775 Some((fam, self.cur_val as u32, 0, 0))
776 } else if radical {
777 self.scan_twenty_seven_bit_int();
778 classic_delimiter(self.cur_val)
779 } else {
780 self.get_nonblank_nonrelax_noncall();
781 match self.cur_cmd {
782 Cmd::Letter | Cmd::OtherChar => delcode_parts(self.eqtb.del.get(self.cur_chr)),
783 Cmd::DelimNum => {
784 if self.cur_chr == 0 {
785 self.scan_twenty_seven_bit_int();
786 classic_delimiter(self.cur_val)
787 } else {
788 let v = self.scan_umath_triple();
789 let mc = MathChar::from_packed(v);
790 Some((mc.fam, mc.chr, 0, 0))
791 }
792 }
793 _ => None,
794 }
795 };
796 let parts = match parts {
797 Some(p) => p,
798 None => {
799 self.print_err("Missing delimiter (. inserted)");
800 self.help(&[
801 "I was expecting to see something like `(' or `\\{' or",
802 "`\\}' here. If you typed, e.g., `{' instead of `\\{', you",
803 "should probably delete the `{' by typing `1' now, so that",
804 "braces don't get unbalanced. Otherwise just proceed",
805 "Acceptable delimiters are characters whose \\delcode is",
806 "nonnegative, or you can use `\\delimiter <delimiter code>'.",
807 ]);
808 self.back_error();
809 (0, 0, 0, 0)
810 }
811 };
812 self.new_delim(parts)
813 }
814
815 fn math_radical(&mut self) {
817 let c = self.cur_chr as u16;
818 let p = self.new_node(id::RADICAL, c, NodeData::Noad(Box::default()));
819 self.tail_append(p);
820 let mut opts = 0u32;
821 let mut width = 0i32;
822 if c == radical_sub::UHEXTENSIBLE || c >= radical_sub::UUNDERDELIMITER {
823 loop {
824 if self.scan_keyword("width") {
825 self.scan_normal_dimen();
826 width = self.cur_val;
827 } else if self.scan_keyword("left") {
828 opts |= noad_opt::LEFT;
829 } else if self.scan_keyword("middle") {
830 opts |= noad_opt::MIDDLE;
831 } else if self.scan_keyword("right") {
832 opts |= noad_opt::RIGHT;
833 } else {
834 break;
835 }
836 }
837 }
838 let d = self.scan_delimiter(c == radical_sub::RADICAL, c != radical_sub::RADICAL);
839 if let Some(n) = self.nodes.noad_mut(p) {
840 n.left = d;
841 n.options = opts;
842 n.width = width;
843 }
844 let st = self.cur_list().math_style;
845 match c {
846 radical_sub::UHEXTENSIBLE => {}
847 radical_sub::UROOT => {
848 if !self.scan_math_flag(p, Field::Degree, 6, 1 << 62) {
852 self.scan_math(p, Field::Nucleus, cramped_style(st));
853 }
854 }
855 radical_sub::UUNDERDELIMITER => {
856 self.scan_math(p, Field::Nucleus, sub_style(st));
857 }
858 radical_sub::UOVERDELIMITER => {
859 self.scan_math(p, Field::Nucleus, sup_style(st));
860 }
861 radical_sub::UDELIMITERUNDER => {
862 self.scan_math(p, Field::Nucleus, st);
863 }
864 _ => {
865 self.scan_math(p, Field::Nucleus, cramped_style(st));
866 }
867 }
868 }
869
870 fn scan_accent_char(&mut self, umath: bool) -> (NodeRef, bool) {
872 let fixed = umath && self.scan_keyword("fixed");
873 let mc = if umath {
874 let v = self.scan_umath_triple();
875 MathChar::from_packed(v)
876 } else {
877 let g = self.scan_math_given();
878 MathChar::from_given(g)
879 };
880 let fam = if mc.class == 8 {
881 0
882 } else {
883 self.effective_fam(mc)
884 };
885 (self.new_math_char(fam, mc.chr), fixed)
886 }
887
888 fn math_ac(&mut self) {
890 if self.cur_cmd == Cmd::Accent {
891 self.print_err("Please use ");
892 self.print_esc_str("mathaccent");
893 self.printer.print_str(" for accents in math mode");
894 self.help(&[
895 "I'm changing \\accent to \\mathaccent here; wish me luck.",
896 "(Accents are not the same in formulas as they are in text.)",
897 ]);
898 self.error();
899 }
900 let umath = self.cur_cmd == Cmd::MathAccent && self.cur_chr == 1;
901 let p = self.new_node(
902 id::ACCENT,
903 accent_sub::BOTH_FLEXIBLE,
904 NodeData::Noad(Box::default()),
905 );
906 self.tail_append(p);
907 let mut sub = accent_sub::BOTH_FLEXIBLE;
908 let (mut top, mut bot) = (NodeRef::NULL, NodeRef::NULL);
909 let fraction = 0;
910 let mut overlay = false;
911 if umath {
912 let (want_top, want_bot) = if self.scan_keyword("bottom") {
913 (false, true)
914 } else if self.scan_keyword("both") {
915 (true, true)
916 } else if self.scan_keyword("overlay") {
917 overlay = true;
918 (true, false)
919 } else {
920 let _ = self.scan_keyword("top");
921 (true, false)
922 };
923 if want_top {
924 let (k, fixed) = self.scan_accent_char(true);
925 top = k;
926 if fixed {
927 sub |= accent_sub::FIXED_TOP;
928 }
929 }
930 if want_bot {
931 let (k, fixed) = self.scan_accent_char(true);
932 bot = k;
933 if fixed {
934 sub |= accent_sub::FIXED_BOTTOM;
935 }
936 }
937 } else {
938 top = self.scan_accent_char(false).0;
939 }
940 self.nodes.set_subtype(p, sub);
941 if let Some(n) = self.nodes.noad_mut(p) {
942 n.accent = top;
943 n.bot_accent = bot;
944 n.fraction = fraction;
945 if overlay {
946 n.options |= noad_opt::OVERLAY;
947 }
948 }
949 let st = cramped_style(self.cur_list().math_style);
950 self.scan_math(p, Field::Nucleus, st);
951 }
952
953 fn sub_sup(&mut self, sup: bool, no_style: bool) {
956 let field = if sup { Field::Sup } else { Field::Sub };
957 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
958 let mut target = NodeRef::NULL;
959 let mut t_nonempty = false;
960 if tail != head && self.nodes.scripts_allowed(tail) {
961 target = tail;
962 t_nonempty = !self.noad_field(tail, field).is_null();
963 }
964 if target.is_null() || t_nonempty {
965 let n = self.new_noad(noad_sub::ORD);
967 let k = self.new_sub_list(true, NodeRef::NULL);
968 self.set_noad_field(n, Field::Nucleus, k);
969 self.tail_append(n);
970 target = n;
971 if t_nonempty {
972 if sup {
973 self.print_err("Double superscript");
974 self.help(&["I treat `x^1^2' essentially like `x^1{}^2'."]);
975 } else {
976 self.print_err("Double subscript");
977 self.help(&["I treat `x_1_2' essentially like `x_1{}_2'."]);
978 }
979 self.error();
980 }
981 }
982 let st = self.cur_list().math_style;
983 let style = if no_style {
984 if let Some(n) = self.nodes.noad_mut(target) {
985 n.options |= if sup {
986 noad_opt::NO_SUPER_SCRIPT
987 } else {
988 noad_opt::NO_SUB_SCRIPT
989 };
990 }
991 st
992 } else if sup {
993 sup_style(st)
994 } else {
995 sub_style(st)
996 };
997 self.scan_math(target, field, style);
998 }
999
1000 fn math_fraction(&mut self) {
1002 let c = self.cur_chr;
1003 let delimited = c >= 4;
1005 let kind = c % 4;
1006 if !self.cur_list().incompleat_noad.is_null() {
1007 if delimited {
1008 let a = self.scan_delimiter(false, false);
1009 let b = self.scan_delimiter(false, false);
1010 self.nodes.flush_list(a);
1011 self.nodes.flush_list(b);
1012 }
1013 if kind == 3 {
1014 let m = self.scan_delimiter(false, false);
1015 self.nodes.flush_list(m);
1016 self.scan_fraction_options();
1017 } else if kind == 0 {
1018 let _ = self.scan_keyword("exact");
1019 self.scan_normal_dimen();
1020 }
1021 self.print_err("Ambiguous; you need another { and }");
1022 self.help(&[
1023 "I'm ignoring this fraction specification, since I don't",
1024 "know whether a construction like `x \\over y \\over z'",
1025 "means `{x \\over y} \\over z' or `x \\over {y \\over z}'.",
1026 ]);
1027 self.error();
1028 return;
1029 }
1030 let head = self.cur_list().head;
1031 let first = self.nodes.next(head);
1032 let num = self.new_sub_list(true, first);
1033 let mut fr = FractionData {
1034 thickness: DEFAULT_CODE,
1035 num,
1036 denom: NodeRef::NULL,
1037 left: NodeRef::NULL,
1038 right: NodeRef::NULL,
1039 middle: NodeRef::NULL,
1040 options: 0,
1041 new_hlist: NodeRef::NULL,
1042 };
1043 self.nodes.set_next(head, NodeRef::NULL);
1044 self.cur_list_mut().tail = head;
1045 if delimited {
1046 fr.left = self.scan_delimiter(false, false);
1047 fr.right = self.scan_delimiter(false, false);
1048 }
1049 match kind {
1050 0 => {
1051 if self.scan_keyword("exact") {
1052 fr.options |= noad_opt::EXACT;
1053 }
1054 self.scan_normal_dimen();
1055 fr.thickness = self.cur_val;
1056 }
1057 1 => fr.thickness = DEFAULT_CODE,
1058 2 => fr.thickness = 0,
1059 _ => {
1060 fr.middle = self.scan_delimiter(false, false);
1061 fr.options |= self.scan_fraction_options();
1062 fr.thickness = 0;
1063 }
1064 }
1065 let n = self.new_node(id::FRACTION, 0, NodeData::Fraction(Box::new(fr)));
1066 self.cur_list_mut().incompleat_noad = n;
1067 let st = cramped_style(self.cur_list().math_style);
1070 self.cur_list_mut().math_style = st;
1071 }
1072
1073 fn scan_fraction_options(&mut self) -> u32 {
1075 let mut o = 0;
1076 loop {
1077 if self.scan_keyword("noaxis") {
1078 o |= noad_opt::NO_AXIS;
1079 } else if self.scan_keyword("exact") {
1080 o |= noad_opt::EXACT;
1081 } else {
1082 return o;
1083 }
1084 }
1085 }
1086
1087 fn fin_mlist(&mut self, p: NodeRef) -> NodeRef {
1090 let inc = self.cur_list().incompleat_noad;
1091 let head = self.cur_list().head;
1092 let q;
1093 if !inc.is_null() {
1094 let first = self.nodes.next(head);
1095 let denom = self.new_sub_list(true, first);
1096 if let NodeData::Fraction(f) = self.nodes.data_mut(inc) {
1097 f.denom = denom;
1098 }
1099 if p.is_null() {
1100 q = inc;
1101 } else {
1102 let num = match self.nodes.data(inc) {
1105 NodeData::Fraction(f) => f.num,
1106 _ => NodeRef::NULL,
1107 };
1108 let num_list = self.nodes.list_ptr_kernel(num);
1109 q = num_list;
1110 let dp = self.cur_list().delim_ptr;
1111 if num_list.is_null() || self.nodes.id(num_list) != id::FENCE || dp.is_null() {
1112 self.confusion("right");
1113 }
1114 let after = self.nodes.next(dp);
1115 self.nodes.set_kernel_list(num, after);
1116 if !after.is_null() {
1117 self.nodes.set_prev(after, NodeRef::NULL);
1118 }
1119 self.nodes.link(dp, inc);
1120 self.nodes.link(inc, p);
1121 }
1122 } else {
1123 let tail = self.cur_list().tail;
1124 self.nodes.link(tail, p);
1125 q = self.nodes.next(head);
1126 }
1127 self.nodes.set_next(head, NodeRef::NULL);
1128 if !q.is_null() {
1129 self.nodes.set_prev(q, NodeRef::NULL);
1130 }
1131 self.pop_nest();
1132 q
1133 }
1134
1135 pub fn math_right_brace(&mut self) {
1138 match self.save.cur_group {
1139 GroupCode::Math => {
1140 self.unsave();
1141 let r = self.pop_saved();
1142 let root_follows = r & (1 << 62) != 0;
1143 let (noad, f) = field_from_ref(r & !(1 << 62));
1144 let p = self.fin_mlist(NodeRef::NULL);
1145 let k = self.noad_field(noad, f);
1146 self.nodes.set_kernel_list(k, p);
1147 if !p.is_null() && self.nodes.next(p).is_null() {
1148 let pid = self.nodes.id(p);
1149 let flatten = self.eqtb.int(ip::MATHFLATTENMODE);
1153 let bit = match self.nodes.subtype(p) {
1154 noad_sub::ORD => 1,
1155 noad_sub::BIN => 2,
1156 noad_sub::REL => 4,
1157 noad_sub::PUNCT => 8,
1158 noad_sub::INNER => 16,
1159 _ => 0,
1160 };
1161 if pid == id::NOAD && flatten & bit != 0 {
1162 let (sub, sup) = (
1163 self.noad_field(p, Field::Sub),
1164 self.noad_field(p, Field::Sup),
1165 );
1166 if sub.is_null() && sup.is_null() {
1167 let nuc = self.noad_field(p, Field::Nucleus);
1169 self.set_noad_field(p, Field::Nucleus, NodeRef::NULL);
1170 self.nodes.flush_list(p);
1171 self.nodes.set_kernel_list(k, NodeRef::NULL);
1172 self.nodes.flush_list(k);
1173 self.set_noad_field(noad, f, nuc);
1174 }
1175 } else if pid == id::ACCENT
1176 && f == Field::Nucleus
1177 && noad == self.cur_list().tail
1178 && self.nodes.id(noad) == id::NOAD
1179 && self.nodes.subtype(noad) == noad_sub::ORD
1180 {
1181 let head = self.cur_list().head;
1183 let mut q = head;
1184 while self.nodes.next(q) != noad {
1185 q = self.nodes.next(q);
1186 }
1187 self.nodes.set_kernel_list(k, NodeRef::NULL);
1188 self.nodes.link(q, p);
1189 self.nodes.set_next(noad, NodeRef::NULL);
1190 self.nodes.flush_list(noad);
1191 self.cur_list_mut().tail = p;
1192 }
1193 }
1194 if root_follows {
1195 let st = cramped_style(self.cur_list().math_style);
1196 self.scan_math(noad, Field::Nucleus, st);
1197 }
1198 }
1199 GroupCode::MathChoice => self.build_choices(),
1200 GroupCode::Vcenter => {
1201 if self.par_token_before_group_end(1) {
1202 return;
1203 }
1204 self.end_graf();
1205 self.unsave();
1206 let (spec, _dir) = self.pop_spec_pub();
1207 let head = self.cur_list().head;
1208 let first = self.nodes.next(head);
1209 self.nodes.set_next(head, NodeRef::NULL);
1210 let first = self.filter_list("vpack_filter", first, "vcenter");
1211 let d = self.eqtb.dimen(dp::BOXMAXDEPTH);
1212 let b = self.vpackage(first, spec, d);
1213 self.pop_nest();
1214 let n = self.new_noad(noad_sub::VCENTER);
1215 let k = self.new_sub_list(false, b);
1216 self.set_noad_field(n, Field::Nucleus, k);
1217 self.tail_append(n);
1218 }
1219 _ => self.confusion("rightbrace"),
1220 }
1221 }
1222
1223 fn append_choices(&mut self) {
1225 let c = self.new_node(
1226 id::CHOICE,
1227 0,
1228 NodeData::Choice(Box::new([NodeRef::NULL; 4])),
1229 );
1230 self.tail_append(c);
1231 self.push_saved(0);
1232 self.push_math(GroupCode::MathChoice, 0);
1233 self.scan_left_brace();
1234 }
1235
1236 fn build_choices(&mut self) {
1238 self.unsave();
1239 let p = self.fin_mlist(NodeRef::NULL);
1240 let k = self.pop_saved();
1241 let tail = self.cur_list().tail;
1242 if let NodeData::Choice(c) = self.nodes.data_mut(tail) {
1243 c[(k as usize).min(3)] = p;
1244 }
1245 if k >= 3 {
1246 return;
1247 }
1248 self.push_saved(k + 1);
1249 self.push_math(GroupCode::MathChoice, 2 * (k as i32 + 1));
1250 self.scan_left_brace();
1251 }
1252
1253 fn math_left_right(&mut self) {
1256 let c = self.cur_chr;
1257 if c == 14 {
1260 self.math_vextensible();
1261 return;
1262 }
1263 let t = match c % 10 {
1264 1 => fence_sub::LEFT,
1265 2 => fence_sub::MIDDLE,
1266 _ => fence_sub::RIGHT,
1267 };
1268 if t != fence_sub::LEFT && self.save.cur_group != GroupCode::MathLeft {
1269 if self.save.cur_group == GroupCode::MathShift {
1270 self.get_nonblank_nonrelax_noncall();
1272 if self.cur_cmd == Cmd::DelimNum {
1273 if self.cur_chr == 0 {
1274 self.scan_twenty_seven_bit_int();
1275 } else {
1276 self.scan_umath_triple();
1277 }
1278 }
1279 self.print_err("Extra ");
1280 if t == fence_sub::MIDDLE {
1281 self.print_esc_str("middle");
1282 self.help(&["I'm ignoring a \\middle that had no matching \\left."]);
1283 } else {
1284 self.print_esc_str("right");
1285 self.help(&["I'm ignoring a \\right that had no matching \\left."]);
1286 }
1287 self.error();
1288 } else {
1289 self.off_save();
1290 }
1291 return;
1292 }
1293 let mut fe = FenceData {
1294 class: -1,
1295 ..FenceData::default()
1296 };
1297 if c >= 10 {
1298 loop {
1299 if self.scan_keyword("height") {
1300 self.scan_normal_dimen();
1301 fe.height = self.cur_val;
1302 } else if self.scan_keyword("depth") {
1303 self.scan_normal_dimen();
1304 fe.depth = self.cur_val;
1305 } else if self.scan_keyword("axis") {
1306 fe.options |= noad_opt::AXIS;
1307 } else if self.scan_keyword("noaxis") {
1308 fe.options |= noad_opt::NO_AXIS;
1309 } else if self.scan_keyword("exact") {
1310 fe.options |= noad_opt::EXACT;
1311 } else if self.scan_keyword("class") {
1312 self.scan_int();
1313 fe.class = self.cur_val;
1314 } else {
1315 break;
1316 }
1317 }
1318 }
1319 fe.delim = self.scan_delimiter(false, false);
1320 let p = self.new_node(id::FENCE, t, NodeData::Fence(Box::new(fe)));
1321 let q = if t == fence_sub::LEFT {
1322 p
1323 } else {
1324 let q = self.fin_mlist(p);
1325 self.unsave();
1326 q
1327 };
1328 if t != fence_sub::RIGHT {
1329 let st = self.cur_list().math_style;
1330 self.push_math(GroupCode::MathLeft, st);
1331 let head = self.cur_list().head;
1332 self.nodes.link(head, q);
1333 self.cur_list_mut().tail = p;
1334 self.cur_list_mut().delim_ptr = p;
1335 } else {
1336 let n = self.new_noad(noad_sub::INNER);
1337 let k = self.new_sub_list(true, q);
1338 self.set_noad_field(n, Field::Nucleus, k);
1339 self.tail_append(n);
1340 }
1341 }
1342
1343 fn math_vextensible(&mut self) {
1345 let mut fe = FenceData {
1346 class: -1,
1347 ..FenceData::default()
1348 };
1349 loop {
1350 if self.scan_keyword("height") {
1351 self.scan_normal_dimen();
1352 fe.height = self.cur_val;
1353 } else if self.scan_keyword("depth") {
1354 self.scan_normal_dimen();
1355 fe.depth = self.cur_val;
1356 } else if self.scan_keyword("axis") {
1357 fe.options |= noad_opt::AXIS;
1358 } else if self.scan_keyword("noaxis") {
1359 fe.options |= noad_opt::NO_AXIS;
1360 } else if self.scan_keyword("exact") {
1361 fe.options |= noad_opt::EXACT;
1362 } else {
1363 break;
1364 }
1365 }
1366 fe.delim = self.scan_delimiter(false, false);
1367 let p = self.new_node(id::FENCE, fence_sub::NO, NodeData::Fence(Box::new(fe)));
1369 let n = self.new_noad(noad_sub::INNER);
1370 let k = self.new_sub_list(true, p);
1371 self.set_noad_field(n, Field::Nucleus, k);
1372 self.tail_append(n);
1373 }
1374
1375 fn start_eq_no(&mut self) {
1377 self.push_saved(i64::from(self.cur_chr));
1378 self.go_into_ordinary_math();
1379 }
1380
1381 pub fn math_box_end(&mut self, b: NodeRef) {
1384 let n = self.new_noad(noad_sub::ORD);
1385 let k = self.new_sub_list(false, b);
1386 self.set_noad_field(n, Field::Nucleus, k);
1387 self.tail_append(n);
1388 }
1389
1390 pub fn math_char_in_text(&mut self) {
1393 let mc = match self.cur_cmd {
1394 Cmd::MathCharNum => self.scan_math_char_num(),
1395 Cmd::MathGiven => MathChar::from_given(self.cur_chr),
1396 _ => MathChar::from_packed(i64::from(self.cur_chr)),
1397 };
1398 if mc.class >= 8 {
1399 self.treat_as_active();
1400 return;
1401 }
1402 let f = self.fam_fnt(mc.fam, 0);
1403 let g = self.new_char_node(f, mc.chr);
1404 self.tail_append(g);
1405 self.cur_list_mut().space_factor = 1000;
1406 }
1407
1408 pub fn fam_fnt(&self, fam: u32, size: u32) -> u32 {
1411 self.eqtb
1412 .math_font
1413 .get((size * crate::eqtb::NUM_FAMILIES as u32 + fam) as usize)
1414 .map_or(0, |s| s.val)
1415 }
1416
1417 fn after_math(&mut self) {
1421 let mut m = self.mode;
1422 let mut l = false;
1423 let mut p = self.fin_mlist(NodeRef::NULL);
1424 let a;
1425 if self.mode == Mode::DisplayMath && m == Mode::Math {
1426 self.check_dollar_follows();
1428 let hl = self.formula_to_hlist(p, 2, false);
1429 a = self.hpack(hl, PackSpec::NATURAL);
1430 self.take_outer_math_dirs();
1431 self.unsave();
1432 if self.pop_saved() == 1 {
1433 l = true;
1434 }
1435 m = self.mode;
1436 p = self.fin_mlist(NodeRef::NULL);
1437 } else {
1438 a = NodeRef::NULL;
1439 }
1440 if m == Mode::Math {
1441 self.finish_math_in_text(p);
1442 } else {
1443 if a.is_null() {
1444 self.check_dollar_follows();
1445 }
1446 self.finish_displayed_math(p, a, l);
1447 }
1448 }
1449
1450 fn take_outer_math_dirs(&mut self) -> Option<(i32, i32)> {
1453 let level = self.save.cur_level;
1454 while let Some(&(l, m, t)) = self.outer_math_dirs.last() {
1455 if l < level {
1456 break;
1457 }
1458 self.outer_math_dirs.pop();
1459 if l == level {
1460 return Some((m, t));
1461 }
1462 }
1463 None
1464 }
1465
1466 fn check_dollar_follows(&mut self) {
1468 self.get_x_token();
1469 if self.cur_cmd != Cmd::MathShift
1470 && !(self.cur_cmd == Cmd::MathShiftCs && self.cur_chr == 1)
1471 {
1472 self.print_err("Display math should end with $$");
1473 self.help(&[
1474 "The `$' that I just saw supposedly matches a previous `$$'.",
1475 "So I shall assume that you typed `$$' both times.",
1476 ]);
1477 self.back_error();
1478 }
1479 }
1480
1481 fn finish_math_in_text(&mut self, p: NodeRef) {
1482 let ms = self.eqtb.dimen(dp::MATHSURROUND);
1483 let mg = self
1484 .eqtb
1485 .glue(crate::primitives_gen::assign_glue::MATHSURROUNDSKIP);
1486 let pen = self.mode == Mode::Horizontal;
1487 let (math_dir, text_dir) = self.take_outer_math_dirs().unwrap_or((
1494 self.dir_param(crate::primitives_gen::assign_dir::MATHDIR),
1495 self.dir_param(crate::primitives_gen::assign_dir::TEXTDIR),
1496 ));
1497 let wrap = (math_dir != text_dir).then(|| math_dir.rem_euclid(4) as i8);
1498 let b = self.new_math_node(ms, mg, 0);
1499 self.tail_append(b);
1500 if let Some(d) = wrap {
1501 let p = self.new_dir_node(d, false);
1502 self.tail_append(p);
1503 }
1504 let hl = self.formula_to_hlist(p, 2, pen);
1505 let tail = self.cur_list().tail;
1506 self.nodes.link(tail, hl);
1507 let mut t = tail;
1508 while !self.nodes.next(t).is_null() {
1509 t = self.nodes.next(t);
1510 }
1511 self.cur_list_mut().tail = t;
1512 if let Some(d) = wrap {
1513 let p = self.new_dir_node(d, true);
1514 self.tail_append(p);
1515 }
1516 let e = self.new_math_node(ms, mg, 1);
1517 self.tail_append(e);
1518 self.cur_list_mut().space_factor = 1000;
1519 self.unsave();
1520 }
1521
1522 fn new_math_node(&mut self, surround: i32, skip: crate::glue::Glue, sub: u16) -> NodeRef {
1524 let p = self.new_node(
1525 id::MATH,
1526 sub,
1527 NodeData::Math {
1528 surround,
1529 glue: crate::glue::Glue::ZERO,
1530 },
1531 );
1532 if (skip.width != 0 || skip.stretch != 0 || skip.shrink != 0)
1533 && let NodeData::Math { glue, .. } = self.nodes.data_mut(p)
1534 {
1535 *glue = skip;
1536 }
1537 p
1538 }
1539
1540 fn finish_displayed_math(&mut self, p: NodeRef, a: NodeRef, l: bool) {
1542 use crate::nodes::glue_sub as gs;
1543 self.take_outer_math_dirs();
1544 let hl = self.formula_to_hlist(p, 0, false);
1545 let adj_head = self.nodes.new_temp();
1546 self.ts.adjust_tail = Some(adj_head);
1547 let mut b = self.hpack(hl, PackSpec::NATURAL);
1548 let p = self.nodes.list_ptr(b);
1549 let t = self.ts.adjust_tail.unwrap_or(adj_head);
1550 self.ts.adjust_tail = None;
1551 let mut w = self.nodes.box_data(b).map_or(0, |x| x.width);
1552 let z = self.eqtb.dimen(dp::DISPLAYWIDTH);
1553 let s = self.eqtb.dimen(dp::DISPLAYINDENT);
1554 let (mut e, q) = if a.is_null() {
1555 (0, 0)
1556 } else {
1557 let e = self.nodes.box_data(a).map_or(0, |x| x.width);
1558 let f2 = self.fam_fnt(2, 0);
1559 let mq = self.math_quad_text(f2);
1560 let step = self.eqtb.int(ip::MATHEQNOGAPSTEP);
1561 let gap = if step == 1000 {
1562 mq
1563 } else {
1564 retex_arith::xn_over_d(mq, step, 1000).map_or(0, |r| r.quotient)
1565 };
1566 (e, e + gap)
1567 };
1568 if w + q > z {
1569 let tot = self.ts.last_totals;
1571 if e != 0
1572 && (w - tot.1[0] + q <= z
1573 || tot.1[1] != 0
1574 || tot.1[2] != 0
1575 || tot.1[3] != 0
1576 || tot.1[4] != 0)
1577 {
1578 self.nodes.set_list_ptr(b, NodeRef::NULL);
1579 self.nodes.free(b);
1580 b = self.hpack(p, PackSpec::Exactly(z - q));
1581 } else {
1582 e = 0;
1583 if w > z {
1584 self.nodes.set_list_ptr(b, NodeRef::NULL);
1585 self.nodes.free(b);
1586 b = self.hpack(p, PackSpec::Exactly(z));
1587 }
1588 }
1589 w = self.nodes.box_data(b).map_or(0, |x| x.width);
1590 }
1591 self.nodes.set_subtype(b, 6); let mut d = half(z - w);
1594 if e > 0 && d < 2 * e {
1595 d = half(z - w - e);
1596 let p = self.nodes.list_ptr(b);
1597 if !p.is_null() && self.nodes.id(p) == id::GLUE {
1598 d = 0;
1599 }
1600 }
1601 let pen = self.new_penalty_node(self.eqtb.int(ip::PREDISPLAYPENALTY));
1603 self.tail_append(pen);
1604 let pds = self.eqtb.dimen(dp::PREDISPLAYSIZE);
1605 let (g1, mut g2) = if d + s <= pds || l {
1606 (gs::ABOVE_DISPLAY, gs::BELOW_DISPLAY)
1607 } else {
1608 (gs::ABOVE_DISPLAY_SHORT, gs::BELOW_DISPLAY_SHORT)
1609 };
1610 let mode = self.eqtb.int(ip::MATHDISPLAYSKIPMODE);
1611 if l && e == 0 {
1612 if let Some(bd) = self.nodes.box_data_mut(a) {
1613 bd.shift = s;
1614 }
1615 self.nodes.set_subtype(a, 7);
1616 self.append_to_vlist(a, "equation_number");
1617 let pen = self.new_penalty_node(10000);
1618 self.tail_append(pen);
1619 } else {
1620 self.append_display_skip(g1, mode, true);
1621 }
1622 if e != 0 {
1627 let r = self.new_kern_node(z - w - e - d, 0);
1628 self.nodes.set_subtype(a, 7);
1629 let k = self.new_kern_node(if l { z - w - d } else { d }, 0);
1632 if l {
1633 self.nodes.link(a, r);
1634 self.nodes.link(r, b);
1635 self.nodes.link(b, k);
1636 b = a;
1637 } else {
1638 self.nodes.link(k, b);
1639 self.nodes.link(b, r);
1640 self.nodes.link(r, a);
1641 b = k;
1642 }
1643 b = self.hpack(b, PackSpec::NATURAL);
1644 d = 0;
1645 }
1646 if let Some(bd) = self.nodes.box_data_mut(b) {
1647 bd.shift = s + d;
1648 }
1649 self.append_to_vlist(b, "equation");
1650 if !a.is_null() && e == 0 && !l {
1652 let pen = self.new_penalty_node(10000);
1653 self.tail_append(pen);
1654 let aw = self.nodes.box_data(a).map_or(0, |x| x.width);
1655 if let Some(bd) = self.nodes.box_data_mut(a) {
1656 bd.shift = s + z - aw;
1657 }
1658 self.nodes.set_subtype(a, 7);
1659 self.append_to_vlist(a, "equation_number");
1660 g2 = 0;
1661 }
1662 if t != adj_head {
1663 let first = self.nodes.next(adj_head);
1664 let tail = self.cur_list().tail;
1665 self.nodes.link(tail, first);
1666 self.cur_list_mut().tail = t;
1667 }
1668 self.nodes.free(adj_head);
1669 let pen = self.new_penalty_node(self.eqtb.int(ip::POSTDISPLAYPENALTY));
1670 self.tail_append(pen);
1671 if g2 > 0 {
1672 self.append_display_skip(g2, mode, false);
1673 }
1674 self.resume_after_display();
1675 }
1676
1677 fn append_display_skip(&mut self, sub: u16, mode: i32, _above: bool) {
1681 let g = self.eqtb.glue(crate::build::glue_param_of_subtype(sub));
1682 let zero = g.width == 0 && g.stretch == 0 && g.shrink == 0;
1683 let skip = match mode {
1684 2 => zero,
1685 3 => true,
1686 _ => false,
1687 };
1688 if !skip {
1689 let n = self.new_param_glue(sub);
1690 self.tail_append(n);
1691 }
1692 }
1693
1694 fn math_quad_text(&self, f2: u32) -> i32 {
1696 let v = self.math_param_value(0, 2);
1697 if v != crate::codes::UNDEFINED_MATH_PARAM {
1698 v
1699 } else {
1700 self.quad(f2)
1701 }
1702 }
1703
1704 pub fn math_param_value(&self, p: u32, s: u32) -> i32 {
1706 self.eqtb
1707 .math_param
1708 .get(&(p * 8 + s))
1709 .map_or(crate::codes::UNDEFINED_MATH_PARAM, |x| x.val)
1710 }
1711
1712 fn resume_after_display(&mut self) {
1714 if self.save.cur_group != GroupCode::MathShift {
1715 self.confusion("display");
1716 }
1717 self.unsave();
1718 let pg = self.cur_list().prev_graf + 3;
1719 self.cur_list_mut().prev_graf = pg;
1720 self.push_nest(Mode::Horizontal);
1721 self.cur_list_mut().space_factor = 1000;
1722 let l = self.cur_lang() as i32;
1723 self.cur_list_mut().clang = l;
1724 let lp = self.new_local_par();
1725 self.tail_append(lp);
1726 self.get_x_token();
1728 if self.cur_cmd != Cmd::Spacer {
1729 self.back_input();
1730 }
1731 if self.nest.len() == 2 {
1732 self.build_page_from("after_display");
1733 }
1734 }
1735
1736 pub fn finish_display_alignment(&mut self, p: NodeRef, q: NodeRef, aux_save: i32) {
1738 self.do_assignments();
1739 if self.cur_cmd != Cmd::MathShift {
1740 self.print_err("Missing $$ inserted");
1741 self.help(&[
1742 "Displays can use special alignments (like \\eqalignno)",
1743 "only if nothing but the alignment itself is between $$'s.",
1744 ]);
1745 self.back_error();
1746 } else {
1747 self.check_dollar_follows();
1748 }
1749 self.pop_nest();
1750 let pen = self.new_penalty_node(self.eqtb.int(ip::PREDISPLAYPENALTY));
1751 self.tail_append(pen);
1752 let g = self.new_param_glue(crate::nodes::glue_sub::ABOVE_DISPLAY);
1753 self.tail_append(g);
1754 let tail = self.cur_list().tail;
1755 self.nodes.link(tail, p);
1756 if !p.is_null() {
1757 self.cur_list_mut().tail = q;
1758 }
1759 let pen = self.new_penalty_node(self.eqtb.int(ip::POSTDISPLAYPENALTY));
1760 self.tail_append(pen);
1761 let g = self.new_param_glue(crate::nodes::glue_sub::BELOW_DISPLAY);
1762 self.tail_append(g);
1763 self.cur_list_mut().prev_depth = aux_save;
1764 self.resume_after_display();
1765 }
1766
1767 pub fn flush_math(&mut self) {
1769 let head = self.cur_list().head;
1770 let first = self.nodes.next(head);
1771 self.nodes.flush_list(first);
1772 let inc = self.cur_list().incompleat_noad;
1773 self.nodes.flush_list(inc);
1774 self.nodes.set_next(head, NodeRef::NULL);
1775 self.cur_list_mut().tail = head;
1776 self.cur_list_mut().incompleat_noad = NodeRef::NULL;
1777 }
1778
1779 pub fn ins_tokens(&mut self, toks: Vec<Token>) {
1781 self.ins_list(Rc::from(toks));
1782 }
1783}
1784
1785pub use retex_arith::half;
1786
1787fn classic_delimiter(v: i32) -> Option<(u32, u32, u32, u32)> {
1789 if v < 0 {
1790 return None;
1791 }
1792 let v = v as u32;
1793 Some((
1794 (v / 0o4000000) % 16,
1795 (v / 0o10000) % 256,
1796 (v / 256) % 16,
1797 v % 256,
1798 ))
1799}