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 _ => (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.print_err("Please use ");
870 self.print_esc_str("mathaccent");
871 self.printer.print_str(" for accents in math mode");
872 self.help(&[
873 "I'm changing \\accent to \\mathaccent here; wish me luck.",
874 "(Accents are not the same in formulas as they are in text.)",
875 ]);
876 self.error();
877 }
878 let umath = self.cur_cmd == Cmd::MathAccent && self.cur_chr == 1;
879 let p = self.new_node(
880 id::ACCENT,
881 accent_sub::BOTH_FLEXIBLE,
882 NodeData::Noad(Box::default()),
883 );
884 self.tail_append(p);
885 let mut sub = accent_sub::BOTH_FLEXIBLE;
886 let (mut top, mut bot) = (NodeRef::NULL, NodeRef::NULL);
887 let fraction = 0;
888 let mut overlay = false;
889 if umath {
890 let (want_top, want_bot) = if self.scan_keyword("bottom") {
891 (false, true)
892 } else if self.scan_keyword("both") {
893 (true, true)
894 } else if self.scan_keyword("overlay") {
895 overlay = true;
896 (true, false)
897 } else {
898 let _ = self.scan_keyword("top");
899 (true, false)
900 };
901 if want_top {
902 let (k, fixed) = self.scan_accent_char(true);
903 top = k;
904 if fixed {
905 sub |= accent_sub::FIXED_TOP;
906 }
907 }
908 if want_bot {
909 let (k, fixed) = self.scan_accent_char(true);
910 bot = k;
911 if fixed {
912 sub |= accent_sub::FIXED_BOTTOM;
913 }
914 }
915 } else {
916 top = self.scan_accent_char(false).0;
917 }
918 self.nodes.set_subtype(p, sub);
919 if let Some(n) = self.nodes.noad_mut(p) {
920 n.accent = top;
921 n.bot_accent = bot;
922 n.fraction = fraction;
923 if overlay {
924 n.options |= noad_opt::OVERLAY;
925 }
926 }
927 let st = cramped_style(self.cur_list().math_style);
928 self.scan_math(p, Field::Nucleus, st);
929 }
930
931 fn sub_sup(&mut self, sup: bool, no_style: bool) {
934 let field = if sup { Field::Sup } else { Field::Sub };
935 let (head, tail) = (self.cur_list().head, self.cur_list().tail);
936 let mut target = NodeRef::NULL;
937 let mut t_nonempty = false;
938 if tail != head && self.nodes.scripts_allowed(tail) {
939 target = tail;
940 t_nonempty = !self.noad_field(tail, field).is_null();
941 }
942 if target.is_null() || t_nonempty {
943 let n = self.new_noad(noad_sub::ORD);
945 let k = self.new_sub_list(true, NodeRef::NULL);
946 self.set_noad_field(n, Field::Nucleus, k);
947 self.tail_append(n);
948 target = n;
949 if t_nonempty {
950 if sup {
951 self.print_err("Double superscript");
952 self.help(&["I treat `x^1^2' essentially like `x^1{}^2'."]);
953 } else {
954 self.print_err("Double subscript");
955 self.help(&["I treat `x_1_2' essentially like `x_1{}_2'."]);
956 }
957 self.error();
958 }
959 }
960 let st = self.cur_list().math_style;
961 let style = if no_style {
962 if let Some(n) = self.nodes.noad_mut(target) {
963 n.options |= if sup {
964 noad_opt::NO_SUPER_SCRIPT
965 } else {
966 noad_opt::NO_SUB_SCRIPT
967 };
968 }
969 st
970 } else if sup {
971 sup_style(st)
972 } else {
973 sub_style(st)
974 };
975 self.scan_math(target, field, style);
976 }
977
978 fn math_fraction(&mut self) {
980 let c = self.cur_chr;
981 let delimited = c >= 4;
983 let kind = c % 4;
984 if !self.cur_list().incompleat_noad.is_null() {
985 if delimited {
986 let a = self.scan_delimiter(false, false);
987 let b = self.scan_delimiter(false, false);
988 self.nodes.flush_list(a);
989 self.nodes.flush_list(b);
990 }
991 if kind == 3 {
992 let m = self.scan_delimiter(false, false);
993 self.nodes.flush_list(m);
994 self.scan_fraction_options();
995 } else if kind == 0 {
996 let _ = self.scan_keyword("exact");
997 self.scan_normal_dimen();
998 }
999 self.print_err("Ambiguous; you need another { and }");
1000 self.help(&[
1001 "I'm ignoring this fraction specification, since I don't",
1002 "know whether a construction like `x \\over y \\over z'",
1003 "means `{x \\over y} \\over z' or `x \\over {y \\over z}'.",
1004 ]);
1005 self.error();
1006 return;
1007 }
1008 let head = self.cur_list().head;
1009 let first = self.nodes.next(head);
1010 let num = self.new_sub_list(true, first);
1011 let mut fr = FractionData {
1012 thickness: DEFAULT_CODE,
1013 num,
1014 denom: NodeRef::NULL,
1015 left: NodeRef::NULL,
1016 right: NodeRef::NULL,
1017 middle: NodeRef::NULL,
1018 options: 0,
1019 new_hlist: NodeRef::NULL,
1020 };
1021 self.nodes.set_next(head, NodeRef::NULL);
1022 self.cur_list_mut().tail = head;
1023 if delimited {
1024 fr.left = self.scan_delimiter(false, false);
1025 fr.right = self.scan_delimiter(false, false);
1026 }
1027 match kind {
1028 0 => {
1029 if self.scan_keyword("exact") {
1030 fr.options |= noad_opt::EXACT;
1031 }
1032 self.scan_normal_dimen();
1033 fr.thickness = self.cur_val;
1034 }
1035 1 => fr.thickness = DEFAULT_CODE,
1036 2 => fr.thickness = 0,
1037 _ => {
1038 fr.middle = self.scan_delimiter(false, false);
1039 fr.options |= self.scan_fraction_options();
1040 fr.thickness = 0;
1041 }
1042 }
1043 let n = self.new_node(id::FRACTION, 0, NodeData::Fraction(Box::new(fr)));
1044 self.cur_list_mut().incompleat_noad = n;
1045 let st = cramped_style(self.cur_list().math_style);
1048 self.cur_list_mut().math_style = st;
1049 }
1050
1051 fn scan_fraction_options(&mut self) -> u32 {
1053 let mut o = 0;
1054 loop {
1055 if self.scan_keyword("noaxis") {
1056 o |= noad_opt::NO_AXIS;
1057 } else if self.scan_keyword("exact") {
1058 o |= noad_opt::EXACT;
1059 } else {
1060 return o;
1061 }
1062 }
1063 }
1064
1065 fn fin_mlist(&mut self, p: NodeRef) -> NodeRef {
1068 let inc = self.cur_list().incompleat_noad;
1069 let head = self.cur_list().head;
1070 let q;
1071 if !inc.is_null() {
1072 let first = self.nodes.next(head);
1073 let denom = self.new_sub_list(true, first);
1074 if let NodeData::Fraction(f) = self.nodes.data_mut(inc) {
1075 f.denom = denom;
1076 }
1077 if p.is_null() {
1078 q = inc;
1079 } else {
1080 let num = match self.nodes.data(inc) {
1083 NodeData::Fraction(f) => f.num,
1084 _ => NodeRef::NULL,
1085 };
1086 let num_list = self.nodes.list_ptr_kernel(num);
1087 q = num_list;
1088 let dp = self.cur_list().delim_ptr;
1089 if num_list.is_null() || self.nodes.id(num_list) != id::FENCE || dp.is_null() {
1090 self.confusion("right");
1091 }
1092 let after = self.nodes.next(dp);
1093 self.nodes.set_kernel_list(num, after);
1094 if !after.is_null() {
1095 self.nodes.set_prev(after, NodeRef::NULL);
1096 }
1097 self.nodes.link(dp, inc);
1098 self.nodes.link(inc, p);
1099 }
1100 } else {
1101 let tail = self.cur_list().tail;
1102 self.nodes.link(tail, p);
1103 q = self.nodes.next(head);
1104 }
1105 self.nodes.set_next(head, NodeRef::NULL);
1106 if !q.is_null() {
1107 self.nodes.set_prev(q, NodeRef::NULL);
1108 }
1109 self.pop_nest();
1110 q
1111 }
1112
1113 pub fn math_right_brace(&mut self) {
1116 match self.save.cur_group {
1117 GroupCode::Math => {
1118 self.unsave();
1119 let r = self.pop_saved();
1120 let root_follows = r & (1 << 62) != 0;
1121 let (noad, f) = field_from_ref(r & !(1 << 62));
1122 let p = self.fin_mlist(NodeRef::NULL);
1123 let k = self.noad_field(noad, f);
1124 self.nodes.set_kernel_list(k, p);
1125 if !p.is_null() && self.nodes.next(p).is_null() {
1126 let pid = self.nodes.id(p);
1127 let flatten = self.eqtb.int(ip::MATHFLATTENMODE);
1131 let bit = match self.nodes.subtype(p) {
1132 noad_sub::ORD => 1,
1133 noad_sub::BIN => 2,
1134 noad_sub::REL => 4,
1135 noad_sub::PUNCT => 8,
1136 noad_sub::INNER => 16,
1137 _ => 0,
1138 };
1139 if pid == id::NOAD && flatten & bit != 0 {
1140 let (sub, sup) = (
1141 self.noad_field(p, Field::Sub),
1142 self.noad_field(p, Field::Sup),
1143 );
1144 if sub.is_null() && sup.is_null() {
1145 let nuc = self.noad_field(p, Field::Nucleus);
1147 self.set_noad_field(p, Field::Nucleus, NodeRef::NULL);
1148 self.nodes.flush_list(p);
1149 self.nodes.set_kernel_list(k, NodeRef::NULL);
1150 self.nodes.flush_list(k);
1151 self.set_noad_field(noad, f, nuc);
1152 }
1153 } else if pid == id::ACCENT
1154 && f == Field::Nucleus
1155 && noad == self.cur_list().tail
1156 && self.nodes.id(noad) == id::NOAD
1157 && self.nodes.subtype(noad) == noad_sub::ORD
1158 {
1159 let head = self.cur_list().head;
1161 let mut q = head;
1162 while self.nodes.next(q) != noad {
1163 q = self.nodes.next(q);
1164 }
1165 self.nodes.set_kernel_list(k, NodeRef::NULL);
1166 self.nodes.link(q, p);
1167 self.nodes.set_next(noad, NodeRef::NULL);
1168 self.nodes.flush_list(noad);
1169 self.cur_list_mut().tail = p;
1170 }
1171 }
1172 if root_follows {
1173 let st = cramped_style(self.cur_list().math_style);
1174 self.scan_math(noad, Field::Nucleus, st);
1175 }
1176 }
1177 GroupCode::MathChoice => self.build_choices(),
1178 GroupCode::Vcenter => {
1179 if self.par_token_before_group_end(1) {
1180 return;
1181 }
1182 self.end_graf();
1183 self.unsave();
1184 let (spec, _dir) = self.pop_spec_pub();
1185 let head = self.cur_list().head;
1186 let first = self.nodes.next(head);
1187 self.nodes.set_next(head, NodeRef::NULL);
1188 let first = self.filter_list("vpack_filter", first, "vcenter");
1189 let d = self.eqtb.dimen(dp::BOXMAXDEPTH);
1190 let b = self.vpackage(first, spec, d);
1191 self.pop_nest();
1192 let n = self.new_noad(noad_sub::VCENTER);
1193 let k = self.new_sub_list(false, b);
1194 self.set_noad_field(n, Field::Nucleus, k);
1195 self.tail_append(n);
1196 }
1197 _ => self.confusion("rightbrace"),
1198 }
1199 }
1200
1201 fn append_choices(&mut self) {
1203 let c = self.new_node(
1204 id::CHOICE,
1205 0,
1206 NodeData::Choice(Box::new([NodeRef::NULL; 4])),
1207 );
1208 self.tail_append(c);
1209 self.push_saved(0);
1210 self.push_math(GroupCode::MathChoice, 0);
1211 self.scan_left_brace();
1212 }
1213
1214 fn build_choices(&mut self) {
1216 self.unsave();
1217 let p = self.fin_mlist(NodeRef::NULL);
1218 let k = self.pop_saved();
1219 let tail = self.cur_list().tail;
1220 if let NodeData::Choice(c) = self.nodes.data_mut(tail) {
1221 c[(k as usize).min(3)] = p;
1222 }
1223 if k >= 3 {
1224 return;
1225 }
1226 self.push_saved(k + 1);
1227 self.push_math(GroupCode::MathChoice, 2 * (k as i32 + 1));
1228 self.scan_left_brace();
1229 }
1230
1231 fn math_left_right(&mut self) {
1234 let c = self.cur_chr;
1235 if c == 14 {
1238 self.math_vextensible();
1239 return;
1240 }
1241 let t = match c % 10 {
1242 1 => fence_sub::LEFT,
1243 2 => fence_sub::MIDDLE,
1244 _ => fence_sub::RIGHT,
1245 };
1246 if t != fence_sub::LEFT && self.save.cur_group != GroupCode::MathLeft {
1247 if self.save.cur_group == GroupCode::MathShift {
1248 self.get_nonblank_nonrelax_noncall();
1250 if self.cur_cmd == Cmd::DelimNum {
1251 if self.cur_chr == 0 {
1252 self.scan_twenty_seven_bit_int();
1253 } else {
1254 self.scan_umath_triple();
1255 }
1256 }
1257 self.print_err("Extra ");
1258 if t == fence_sub::MIDDLE {
1259 self.print_esc_str("middle");
1260 self.help(&["I'm ignoring a \\middle that had no matching \\left."]);
1261 } else {
1262 self.print_esc_str("right");
1263 self.help(&["I'm ignoring a \\right that had no matching \\left."]);
1264 }
1265 self.error();
1266 } else {
1267 self.off_save();
1268 }
1269 return;
1270 }
1271 let mut fe = FenceData {
1272 class: -1,
1273 ..FenceData::default()
1274 };
1275 if c >= 10 {
1276 loop {
1277 if self.scan_keyword("height") {
1278 self.scan_normal_dimen();
1279 fe.height = self.cur_val;
1280 } else if self.scan_keyword("depth") {
1281 self.scan_normal_dimen();
1282 fe.depth = self.cur_val;
1283 } else if self.scan_keyword("axis") {
1284 fe.options |= noad_opt::AXIS;
1285 } else if self.scan_keyword("noaxis") {
1286 fe.options |= noad_opt::NO_AXIS;
1287 } else if self.scan_keyword("exact") {
1288 fe.options |= noad_opt::EXACT;
1289 } else if self.scan_keyword("class") {
1290 self.scan_int();
1291 fe.class = self.cur_val;
1292 } else {
1293 break;
1294 }
1295 }
1296 }
1297 fe.delim = self.scan_delimiter(false, false);
1298 let p = self.new_node(id::FENCE, t, NodeData::Fence(Box::new(fe)));
1299 let q = if t == fence_sub::LEFT {
1300 p
1301 } else {
1302 let q = self.fin_mlist(p);
1303 self.unsave();
1304 q
1305 };
1306 if t != fence_sub::RIGHT {
1307 let st = self.cur_list().math_style;
1308 self.push_math(GroupCode::MathLeft, st);
1309 let head = self.cur_list().head;
1310 self.nodes.link(head, q);
1311 self.cur_list_mut().tail = p;
1312 self.cur_list_mut().delim_ptr = p;
1313 } else {
1314 let n = self.new_noad(noad_sub::INNER);
1315 let k = self.new_sub_list(true, q);
1316 self.set_noad_field(n, Field::Nucleus, k);
1317 self.tail_append(n);
1318 }
1319 }
1320
1321 fn math_vextensible(&mut self) {
1323 let mut fe = FenceData {
1324 class: -1,
1325 ..FenceData::default()
1326 };
1327 loop {
1328 if self.scan_keyword("height") {
1329 self.scan_normal_dimen();
1330 fe.height = self.cur_val;
1331 } else if self.scan_keyword("depth") {
1332 self.scan_normal_dimen();
1333 fe.depth = self.cur_val;
1334 } else if self.scan_keyword("axis") {
1335 fe.options |= noad_opt::AXIS;
1336 } else if self.scan_keyword("noaxis") {
1337 fe.options |= noad_opt::NO_AXIS;
1338 } else if self.scan_keyword("exact") {
1339 fe.options |= noad_opt::EXACT;
1340 } else {
1341 break;
1342 }
1343 }
1344 fe.delim = self.scan_delimiter(false, false);
1345 let p = self.new_node(id::FENCE, fence_sub::NO, NodeData::Fence(Box::new(fe)));
1347 let n = self.new_noad(noad_sub::INNER);
1348 let k = self.new_sub_list(true, p);
1349 self.set_noad_field(n, Field::Nucleus, k);
1350 self.tail_append(n);
1351 }
1352
1353 fn start_eq_no(&mut self) {
1355 self.push_saved(i64::from(self.cur_chr));
1356 self.go_into_ordinary_math();
1357 }
1358
1359 pub fn math_box_end(&mut self, b: NodeRef) {
1362 let n = self.new_noad(noad_sub::ORD);
1363 let k = self.new_sub_list(false, b);
1364 self.set_noad_field(n, Field::Nucleus, k);
1365 self.tail_append(n);
1366 }
1367
1368 pub fn math_char_in_text(&mut self) {
1371 let mc = match self.cur_cmd {
1372 Cmd::MathCharNum => self.scan_math_char_num(),
1373 Cmd::MathGiven => MathChar::from_given(self.cur_chr),
1374 _ => MathChar::from_packed(i64::from(self.cur_chr)),
1375 };
1376 if mc.class >= 8 {
1377 self.treat_as_active();
1378 return;
1379 }
1380 let f = self.fam_fnt(mc.fam, 0);
1381 let g = self.new_char_node(f, mc.chr);
1382 self.tail_append(g);
1383 self.cur_list_mut().space_factor = 1000;
1384 }
1385
1386 pub fn fam_fnt(&self, fam: u32, size: u32) -> u32 {
1389 self.eqtb
1390 .math_font
1391 .get((size * crate::eqtb::NUM_FAMILIES as u32 + fam) as usize)
1392 .map_or(0, |s| s.val)
1393 }
1394
1395 fn after_math(&mut self) {
1399 let mut m = self.mode;
1400 let mut l = false;
1401 let mut p = self.fin_mlist(NodeRef::NULL);
1402 let a;
1403 if self.mode == Mode::DisplayMath && m == Mode::Math {
1404 self.check_dollar_follows();
1406 let hl = self.formula_to_hlist(p, 2, false);
1407 a = self.hpack(hl, PackSpec::NATURAL);
1408 self.take_outer_math_dirs();
1409 self.unsave();
1410 if self.pop_saved() == 1 {
1411 l = true;
1412 }
1413 m = self.mode;
1414 p = self.fin_mlist(NodeRef::NULL);
1415 } else {
1416 a = NodeRef::NULL;
1417 }
1418 if m == Mode::Math {
1419 self.finish_math_in_text(p);
1420 } else {
1421 if a.is_null() {
1422 self.check_dollar_follows();
1423 }
1424 self.finish_displayed_math(p, a, l);
1425 }
1426 }
1427
1428 fn take_outer_math_dirs(&mut self) -> Option<(i32, i32)> {
1431 let level = self.save.cur_level;
1432 while let Some(&(l, m, t)) = self.outer_math_dirs.last() {
1433 if l < level {
1434 break;
1435 }
1436 self.outer_math_dirs.pop();
1437 if l == level {
1438 return Some((m, t));
1439 }
1440 }
1441 None
1442 }
1443
1444 fn check_dollar_follows(&mut self) {
1446 self.get_x_token();
1447 if self.cur_cmd != Cmd::MathShift
1448 && !(self.cur_cmd == Cmd::MathShiftCs && self.cur_chr == 1)
1449 {
1450 self.print_err("Display math should end with $$");
1451 self.help(&[
1452 "The `$' that I just saw supposedly matches a previous `$$'.",
1453 "So I shall assume that you typed `$$' both times.",
1454 ]);
1455 self.back_error();
1456 }
1457 }
1458
1459 fn finish_math_in_text(&mut self, p: NodeRef) {
1460 let ms = self.eqtb.dimen(dp::MATHSURROUND);
1461 let mg = self
1462 .eqtb
1463 .glue(crate::primitives_gen::assign_glue::MATHSURROUNDSKIP);
1464 let pen = self.mode == Mode::Horizontal;
1465 let (math_dir, text_dir) = self.take_outer_math_dirs().unwrap_or((
1472 self.dir_param(crate::primitives_gen::assign_dir::MATHDIR),
1473 self.dir_param(crate::primitives_gen::assign_dir::TEXTDIR),
1474 ));
1475 let wrap = (math_dir != text_dir).then(|| math_dir.rem_euclid(4) as i8);
1476 let b = self.new_math_node(ms, mg, 0);
1477 self.tail_append(b);
1478 if let Some(d) = wrap {
1479 let p = self.new_dir_node(d, false);
1480 self.tail_append(p);
1481 }
1482 let hl = self.formula_to_hlist(p, 2, pen);
1483 let tail = self.cur_list().tail;
1484 self.nodes.link(tail, hl);
1485 let mut t = tail;
1486 while !self.nodes.next(t).is_null() {
1487 t = self.nodes.next(t);
1488 }
1489 self.cur_list_mut().tail = t;
1490 if let Some(d) = wrap {
1491 let p = self.new_dir_node(d, true);
1492 self.tail_append(p);
1493 }
1494 let e = self.new_math_node(ms, mg, 1);
1495 self.tail_append(e);
1496 self.cur_list_mut().space_factor = 1000;
1497 self.unsave();
1498 }
1499
1500 fn new_math_node(&mut self, surround: i32, skip: crate::glue::Glue, sub: u16) -> NodeRef {
1502 let p = self.new_node(
1503 id::MATH,
1504 sub,
1505 NodeData::Math {
1506 surround,
1507 glue: crate::glue::Glue::ZERO,
1508 },
1509 );
1510 if (skip.width != 0 || skip.stretch != 0 || skip.shrink != 0)
1511 && let NodeData::Math { glue, .. } = self.nodes.data_mut(p)
1512 {
1513 *glue = skip;
1514 }
1515 p
1516 }
1517
1518 fn finish_displayed_math(&mut self, p: NodeRef, a: NodeRef, l: bool) {
1520 use crate::nodes::glue_sub as gs;
1521 self.take_outer_math_dirs();
1522 let hl = self.formula_to_hlist(p, 0, false);
1523 let adj_head = self.nodes.new_temp();
1524 self.ts.adjust_tail = Some(adj_head);
1525 let mut b = self.hpack(hl, PackSpec::NATURAL);
1526 let p = self.nodes.list_ptr(b);
1527 let t = self.ts.adjust_tail.unwrap_or(adj_head);
1528 self.ts.adjust_tail = None;
1529 let mut w = self.nodes.box_data(b).map_or(0, |x| x.width);
1530 let z = self.eqtb.dimen(dp::DISPLAYWIDTH);
1531 let s = self.eqtb.dimen(dp::DISPLAYINDENT);
1532 let (mut e, q) = if a.is_null() {
1533 (0, 0)
1534 } else {
1535 let e = self.nodes.box_data(a).map_or(0, |x| x.width);
1536 let f2 = self.fam_fnt(2, 0);
1537 let mq = self.math_quad_text(f2);
1538 let step = self.eqtb.int(ip::MATHEQNOGAPSTEP);
1539 let gap = if step == 1000 {
1540 mq
1541 } else {
1542 retex_arith::xn_over_d(mq, step, 1000).map_or(0, |r| r.quotient)
1543 };
1544 (e, e + gap)
1545 };
1546 if w + q > z {
1547 let tot = self.ts.last_totals;
1549 if e != 0
1550 && (w - tot.1[0] + q <= z
1551 || tot.1[1] != 0
1552 || tot.1[2] != 0
1553 || tot.1[3] != 0
1554 || tot.1[4] != 0)
1555 {
1556 self.nodes.set_list_ptr(b, NodeRef::NULL);
1557 self.nodes.free(b);
1558 b = self.hpack(p, PackSpec::Exactly(z - q));
1559 } else {
1560 e = 0;
1561 if w > z {
1562 self.nodes.set_list_ptr(b, NodeRef::NULL);
1563 self.nodes.free(b);
1564 b = self.hpack(p, PackSpec::Exactly(z));
1565 }
1566 }
1567 w = self.nodes.box_data(b).map_or(0, |x| x.width);
1568 }
1569 self.nodes.set_subtype(b, 6); let mut d = half(z - w);
1572 if e > 0 && d < 2 * e {
1573 d = half(z - w - e);
1574 let p = self.nodes.list_ptr(b);
1575 if !p.is_null() && self.nodes.id(p) == id::GLUE {
1576 d = 0;
1577 }
1578 }
1579 let pen = self.new_penalty_node(self.eqtb.int(ip::PREDISPLAYPENALTY));
1581 self.tail_append(pen);
1582 let pds = self.eqtb.dimen(dp::PREDISPLAYSIZE);
1583 let (g1, mut g2) = if d + s <= pds || l {
1584 (gs::ABOVE_DISPLAY, gs::BELOW_DISPLAY)
1585 } else {
1586 (gs::ABOVE_DISPLAY_SHORT, gs::BELOW_DISPLAY_SHORT)
1587 };
1588 let mode = self.eqtb.int(ip::MATHDISPLAYSKIPMODE);
1589 if l && e == 0 {
1590 if let Some(bd) = self.nodes.box_data_mut(a) {
1591 bd.shift = s;
1592 }
1593 self.nodes.set_subtype(a, 7);
1594 self.append_to_vlist(a);
1595 let pen = self.new_penalty_node(10000);
1596 self.tail_append(pen);
1597 } else {
1598 self.append_display_skip(g1, mode, true);
1599 }
1600 if e != 0 {
1605 let r = self.new_kern_node(z - w - e - d, 0);
1606 self.nodes.set_subtype(a, 7);
1607 let k = self.new_kern_node(if l { z - w - d } else { d }, 0);
1610 if l {
1611 self.nodes.link(a, r);
1612 self.nodes.link(r, b);
1613 self.nodes.link(b, k);
1614 b = a;
1615 } else {
1616 self.nodes.link(k, b);
1617 self.nodes.link(b, r);
1618 self.nodes.link(r, a);
1619 b = k;
1620 }
1621 b = self.hpack(b, PackSpec::NATURAL);
1622 d = 0;
1623 }
1624 if let Some(bd) = self.nodes.box_data_mut(b) {
1625 bd.shift = s + d;
1626 }
1627 self.append_to_vlist(b);
1628 if !a.is_null() && e == 0 && !l {
1630 let pen = self.new_penalty_node(10000);
1631 self.tail_append(pen);
1632 let aw = self.nodes.box_data(a).map_or(0, |x| x.width);
1633 if let Some(bd) = self.nodes.box_data_mut(a) {
1634 bd.shift = s + z - aw;
1635 }
1636 self.nodes.set_subtype(a, 7);
1637 self.append_to_vlist(a);
1638 g2 = 0;
1639 }
1640 if t != adj_head {
1641 let first = self.nodes.next(adj_head);
1642 let tail = self.cur_list().tail;
1643 self.nodes.link(tail, first);
1644 self.cur_list_mut().tail = t;
1645 }
1646 self.nodes.free(adj_head);
1647 let pen = self.new_penalty_node(self.eqtb.int(ip::POSTDISPLAYPENALTY));
1648 self.tail_append(pen);
1649 if g2 > 0 {
1650 self.append_display_skip(g2, mode, false);
1651 }
1652 self.resume_after_display();
1653 }
1654
1655 fn append_display_skip(&mut self, sub: u16, mode: i32, _above: bool) {
1659 let g = self.eqtb.glue(crate::build::glue_param_of_subtype(sub));
1660 let zero = g.width == 0 && g.stretch == 0 && g.shrink == 0;
1661 let skip = match mode {
1662 2 => zero,
1663 3 => true,
1664 _ => false,
1665 };
1666 if !skip {
1667 let n = self.new_param_glue(sub);
1668 self.tail_append(n);
1669 }
1670 }
1671
1672 fn math_quad_text(&self, f2: u32) -> i32 {
1674 let v = self.math_param_value(0, 2);
1675 if v != crate::codes::UNDEFINED_MATH_PARAM {
1676 v
1677 } else {
1678 self.quad(f2)
1679 }
1680 }
1681
1682 pub fn math_param_value(&self, p: u32, s: u32) -> i32 {
1684 self.eqtb
1685 .math_param
1686 .get(&(p * 8 + s))
1687 .map_or(crate::codes::UNDEFINED_MATH_PARAM, |x| x.val)
1688 }
1689
1690 fn resume_after_display(&mut self) {
1692 if self.save.cur_group != GroupCode::MathShift {
1693 self.confusion("display");
1694 }
1695 self.unsave();
1696 let pg = self.cur_list().prev_graf + 3;
1697 self.cur_list_mut().prev_graf = pg;
1698 self.push_nest(Mode::Horizontal);
1699 self.cur_list_mut().space_factor = 1000;
1700 let l = self.cur_lang() as i32;
1701 self.cur_list_mut().clang = l;
1702 let lp = self.new_local_par();
1703 self.tail_append(lp);
1704 self.get_x_token();
1706 if self.cur_cmd != Cmd::Spacer {
1707 self.back_input();
1708 }
1709 if self.nest.len() == 2 {
1710 self.build_page_from("after_display");
1711 }
1712 }
1713
1714 pub fn finish_display_alignment(&mut self, p: NodeRef, q: NodeRef, aux_save: i32) {
1716 self.do_assignments();
1717 if self.cur_cmd != Cmd::MathShift {
1718 self.print_err("Missing $$ inserted");
1719 self.help(&[
1720 "Displays can use special alignments (like \\eqalignno)",
1721 "only if nothing but the alignment itself is between $$'s.",
1722 ]);
1723 self.back_error();
1724 } else {
1725 self.check_dollar_follows();
1726 }
1727 self.pop_nest();
1728 let pen = self.new_penalty_node(self.eqtb.int(ip::PREDISPLAYPENALTY));
1729 self.tail_append(pen);
1730 let g = self.new_param_glue(crate::nodes::glue_sub::ABOVE_DISPLAY);
1731 self.tail_append(g);
1732 let tail = self.cur_list().tail;
1733 self.nodes.link(tail, p);
1734 if !p.is_null() {
1735 self.cur_list_mut().tail = q;
1736 }
1737 let pen = self.new_penalty_node(self.eqtb.int(ip::POSTDISPLAYPENALTY));
1738 self.tail_append(pen);
1739 let g = self.new_param_glue(crate::nodes::glue_sub::BELOW_DISPLAY);
1740 self.tail_append(g);
1741 self.cur_list_mut().prev_depth = aux_save;
1742 self.resume_after_display();
1743 }
1744
1745 pub fn flush_math(&mut self) {
1747 let head = self.cur_list().head;
1748 let first = self.nodes.next(head);
1749 self.nodes.flush_list(first);
1750 let inc = self.cur_list().incompleat_noad;
1751 self.nodes.flush_list(inc);
1752 self.nodes.set_next(head, NodeRef::NULL);
1753 self.cur_list_mut().tail = head;
1754 self.cur_list_mut().incompleat_noad = NodeRef::NULL;
1755 }
1756
1757 pub fn ins_tokens(&mut self, toks: Vec<Token>) {
1759 self.ins_list(Rc::from(toks));
1760 }
1761}
1762
1763pub use retex_arith::half;
1764
1765fn classic_delimiter(v: i32) -> Option<(u32, u32, u32, u32)> {
1767 if v < 0 {
1768 return None;
1769 }
1770 let v = v as u32;
1771 Some((
1772 (v / 0o4000000) % 16,
1773 (v / 0o10000) % 256,
1774 (v / 256) % 16,
1775 v % 256,
1776 ))
1777}