1use std::collections::HashMap;
17
18use crate::Engine;
19use crate::glue::Glue;
20use crate::nodes::{AttrList, NodeRef, Nodes};
21use crate::scan::{SET_AUX_PREV_DEPTH, ValLevel};
22use crate::token::TokenList;
23
24pub const NULL_FLAG: i32 = -0o10000000000;
26
27pub const EJECT_PENALTY: i32 = -10000;
29
30pub const INF_PENALTY: i32 = 10000;
32
33pub const INF_BAD: i32 = 10000;
35
36pub const AWFUL_BAD: i32 = 0o7777777777;
38
39pub const DEPLORABLE: i32 = 100000;
41
42#[derive(Debug, Default, Clone)]
44pub struct Marks {
45 pub classes: HashMap<u32, [Option<TokenList>; 5]>,
47}
48
49impl Marks {
50 pub fn get(&self, class: u32, code: u32) -> Option<TokenList> {
52 self.classes
53 .get(&class)
54 .and_then(|m| m.get(code as usize).cloned().flatten())
55 }
56
57 pub fn set(&mut self, class: u32, code: usize, t: Option<TokenList>) {
59 let e = self.classes.entry(class).or_default();
60 e[code] = t;
61 }
62}
63
64pub mod mark_code {
66 pub const TOP: usize = 0;
68 pub const FIRST: usize = 1;
70 pub const BOT: usize = 2;
72 pub const SPLIT_FIRST: usize = 3;
74 pub const SPLIT_BOT: usize = 4;
76}
77
78#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
80pub enum PageContents {
81 #[default]
83 Empty,
84 InsertsOnly,
86 BoxThere,
88}
89
90#[derive(Debug, Clone, Copy)]
93pub struct PageIns {
94 pub n: u32,
96 pub split_up: bool,
99 pub height: i32,
101 pub broken_ptr: NodeRef,
103 pub broken_ins: NodeRef,
105 pub last_ins_ptr: NodeRef,
107 pub best_ins_ptr: NodeRef,
110}
111
112#[derive(Debug, Default, Clone)]
114pub struct PageState {
115 pub contrib_head: NodeRef,
117 pub page_head: NodeRef,
119 pub page_tail: NodeRef,
121 pub so_far: [i32; 8],
124 pub fi_stretch: i32,
126 pub max_depth: i32,
128 pub contents: PageContents,
130 pub best_break: NodeRef,
132 pub least_cost: i32,
134 pub best_size: i32,
136 pub best_so_far: [i32; 8],
138 pub best_infinite: bool,
140 pub last_break: Option<crate::pagenote::PageBreakInfo>,
142 pub ins: Vec<PageIns>,
144 pub last_glue: Option<Glue>,
147 pub last_penalty: i32,
149 pub last_kern: i32,
151 pub last_node_type: i32,
153}
154
155impl PageState {
156 pub fn init(&mut self, nodes: &mut Nodes) {
158 self.contrib_head = nodes.new_temp();
159 self.page_head = nodes.new_temp();
160 self.page_tail = self.page_head;
161 self.last_node_type = -1;
162 }
163
164 pub fn stretch(&self, o: u8) -> i32 {
166 match o {
167 0 => self.so_far[2],
168 1 => self.fi_stretch,
169 2 => self.so_far[3],
170 3 => self.so_far[4],
171 _ => self.so_far[5],
172 }
173 }
174
175 pub fn stretch_mut(&mut self, o: u8) -> &mut i32 {
177 match o {
178 0 => &mut self.so_far[2],
179 1 => &mut self.fi_stretch,
180 2 => &mut self.so_far[3],
181 3 => &mut self.so_far[4],
182 _ => &mut self.so_far[5],
183 }
184 }
185}
186
187#[derive(Default)]
189pub struct TsState {
190 pub show_prefix: Vec<u8>,
193 pub font_in_short_display: i64,
195 pub output_active: bool,
197 pub adjust_head: NodeRef,
199 pub pre_adjust_head: NodeRef,
201 pub adjust_tail: Option<NodeRef>,
203 pub pre_adjust_tail: Option<NodeRef>,
205 pub pack_begin_line: i32,
208 pub disc_ptr: [NodeRef; 4],
211 pub attr_cache: Option<(u64, Option<AttrList>)>,
213 pub attr_override: Option<Option<AttrList>>,
217 pub box_attrs: Vec<Option<AttrList>>,
220 pub align: crate::align::AlignState,
222 pub last_totals: ([i32; 5], [i32; 5]),
224 pub just_box: NodeRef,
226 pub math: crate::mlist::MathState,
228}
229
230impl std::fmt::Debug for TsState {
231 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232 f.debug_struct("TsState")
233 .field("output_active", &self.output_active)
234 .finish_non_exhaustive()
235 }
236}
237
238impl Engine {
239 pub fn filter_list(&mut self, cb: &str, head: NodeRef, group: &str) -> NodeRef {
244 if head.is_null() {
247 return head;
248 }
249 self.nodes.set_prev(head, NodeRef::NULL);
252 match self.run_list_filter(cb, head, group) {
253 crate::ListFilter::Keep(h) => {
254 if !h.is_null() {
255 self.nodes.set_prev(h, NodeRef::NULL);
256 }
257 h
258 }
259 crate::ListFilter::Flush => {
260 self.nodes.flush_list(head);
261 NodeRef::NULL
262 }
263 }
264 }
265
266 pub fn page_is_empty(&self) -> bool {
268 self.page.page_head == self.page.page_tail
269 && self.nodes.next(self.page.contrib_head).is_null()
270 }
271
272 pub fn not_implemented(&mut self, what: &str) {
274 self.print_err("retex: not implemented yet: ");
275 self.printer.print_str(what);
276 self.help(&["This command is not supported by retex yet."]);
277 self.error();
278 }
279
280 pub fn cur_attr(&mut self) -> Option<AttrList> {
282 let generation = self.eqtb.attr_generation;
283 if let Some((g, a)) = &self.ts.attr_cache
284 && *g == generation
285 {
286 return a.clone();
287 }
288 let mut v: Vec<(u32, i32)> = Vec::new();
289 for (i, s) in self.eqtb.attr.iter().enumerate() {
290 if s.val != crate::eqtb::UNUSED_ATTRIBUTE {
291 v.push((i as u32, s.val));
292 }
293 }
294 let a: Option<AttrList> = if v.is_empty() {
295 None
296 } else {
297 Some(std::rc::Rc::from(v))
298 };
299 self.ts.attr_cache = Some((generation, a.clone()));
300 a
301 }
302
303 pub fn new_node(&mut self, id: u8, subtype: u16, data: crate::nodes::NodeData) -> NodeRef {
305 let p = self.nodes.alloc(id, subtype, data);
306 self.give_new_attr(p);
307 p
308 }
309
310 #[inline]
313 pub fn give_new_attr(&mut self, p: NodeRef) {
314 if let Some(a) = &self.ts.attr_override {
315 let a = a.clone();
316 self.nodes.set_attr(p, a);
317 } else if self.eqtb.attrs_in_use {
318 let a = self.cur_attr();
319 self.nodes.set_attr(p, a);
320 }
321 }
322
323 pub fn alter_aux(&mut self) {
325 let c = self.cur_chr;
326 if (c == SET_AUX_PREV_DEPTH)
327 != (self.mode.abs_kind() == crate::maincontrol::ModeKind::Vertical)
328 {
329 self.report_illegal_case();
330 return;
331 }
332 self.scan_optional_equals();
333 if c == SET_AUX_PREV_DEPTH {
334 self.scan_normal_dimen();
335 self.cur_list_mut().prev_depth = self.cur_val;
336 } else {
337 self.scan_int();
338 if self.cur_val <= 0 || self.cur_val > 32767 {
339 self.print_err("Bad space factor");
340 self.help(&["I allow only values in the range 1..32767 here."]);
341 self.int_error(self.cur_val);
342 } else {
343 self.cur_list_mut().space_factor = self.cur_val;
344 }
345 }
346 }
347
348 pub fn alter_prev_graf(&mut self) {
350 self.scan_optional_equals();
351 self.scan_int();
352 let v = self.cur_val;
353 if v < 0 {
354 self.print_err("Bad ");
355 self.print_esc_str("prevgraf");
356 self.help(&["I allow only nonnegative values here."]);
357 self.int_error(v);
358 } else {
359 let mut p = self.nest.len() - 1;
361 while self.nest[p].mode.abs_kind() == crate::maincontrol::ModeKind::Math && p > 0 {
362 p -= 1;
363 }
364 self.nest[p].prev_graf = v;
365 }
366 }
367
368 pub fn alter_page_so_far(&mut self) {
370 let c = self.cur_chr as usize;
371 self.scan_optional_equals();
372 self.scan_normal_dimen();
373 if c < self.page.so_far.len() {
374 self.page.so_far[c] = self.cur_val;
375 }
376 }
377
378 pub fn alter_box_dimen(&mut self) {
382 let c = self.cur_chr;
383 self.scan_register_num();
384 let b = self.eqtb.boxes[self.cur_val as usize].val;
385 self.scan_optional_equals();
386 self.scan_normal_dimen();
387 let v = self.cur_val;
388 if let Some(bd) = self.nodes.box_data_mut(b) {
389 match c {
390 2 => bd.width = v,
391 3 => bd.depth = v,
392 _ => bd.height = v,
393 }
394 }
395 }
396
397 pub fn fetch_aux(&mut self, m: u32) -> Option<(i32, ValLevel)> {
399 let vertical = self.mode.abs_kind() == crate::maincontrol::ModeKind::Vertical;
400 if (m == SET_AUX_PREV_DEPTH) != vertical {
401 self.print_err("Improper ");
402 self.print_cmd_chr(crate::cmd::Cmd::SetAux, m);
403 self.help(&[
404 "You can refer to \\spacefactor only in horizontal mode;",
405 "you can refer to \\prevdepth only in vertical mode; and",
406 "neither of these is meaningful inside \\write. So",
407 "I'm forgetting what you said and using zero instead.",
408 ]);
409 self.error();
410 return Some((
411 0,
412 if m == SET_AUX_PREV_DEPTH {
413 ValLevel::Dimen
414 } else {
415 ValLevel::Int
416 },
417 ));
418 }
419 let cl = self.cur_list();
420 if m == SET_AUX_PREV_DEPTH {
421 Some((cl.prev_depth, ValLevel::Dimen))
422 } else {
423 Some((cl.space_factor, ValLevel::Int))
424 }
425 }
426
427 pub fn fetch_prev_graf(&mut self) -> i32 {
429 if self.mode == crate::maincontrol::Mode::None {
430 return 0;
431 }
432 let mut p = self.nest.len() - 1;
433 while self.nest[p].mode.abs_kind() == crate::maincontrol::ModeKind::Math && p > 0 {
434 p -= 1;
435 }
436 self.nest[p].prev_graf
437 }
438
439 pub fn page_so_far_value(&self, m: u32) -> i32 {
441 if self.page.contents == PageContents::Empty && !self.ts.output_active {
444 return if m == 0 { retex_arith::MAX_DIMEN } else { 0 };
445 }
446 self.page.so_far.get(m as usize).copied().unwrap_or(0)
447 }
448
449 pub fn fetch_last_node_item(&mut self, m: u32) -> (i32, crate::glue::Glue, ValLevel) {
451 use crate::nodes::NodeData;
452 use crate::scan::last_item as li;
453 let level = match m {
454 li::LAST_KERN => ValLevel::Dimen,
455 li::LAST_SKIP => ValLevel::Glue,
456 _ => ValLevel::Int,
457 };
458 let tail = self.cur_list().tail;
459 let head = self.cur_list().head;
460 if m == li::LAST_NODE_TYPE {
461 if tail == head {
462 if self.mode == crate::maincontrol::Mode::Vertical && self.nest.len() == 1 {
463 return (self.page.last_node_type, Glue::ZERO, level);
464 }
465 return (-1, Glue::ZERO, level);
466 }
467 let v = etex_node_type(self.nodes.id(tail), self.nodes.subtype(tail));
468 return (v, Glue::ZERO, level);
469 }
470 if tail != head {
471 match &self.nodes.get(tail).data {
472 NodeData::Penalty { penalty } if m == li::LAST_PENALTY => {
473 return (*penalty, Glue::ZERO, level);
474 }
475 NodeData::Kern { kern, .. } if m == li::LAST_KERN => {
476 return (*kern, Glue::ZERO, level);
477 }
478 NodeData::Glue { spec, .. } if m == li::LAST_SKIP => {
479 let l = if self.nodes.get(tail).subtype == crate::nodes::glue_sub::MU_GLUE {
480 ValLevel::Mu
481 } else {
482 level
483 };
484 return (spec.width, *spec, l);
485 }
486 _ => {}
487 }
488 } else if self.mode == crate::maincontrol::Mode::Vertical && self.nest.len() == 1 {
489 match m {
490 li::LAST_PENALTY => return (self.page.last_penalty, Glue::ZERO, level),
491 li::LAST_KERN => return (self.page.last_kern, Glue::ZERO, level),
492 li::LAST_SKIP => {
493 if let Some(g) = self.page.last_glue {
494 return (g.width, g, level);
495 }
496 }
497 _ => {}
498 }
499 }
500 (0, Glue::ZERO, level)
501 }
502
503 pub fn box_is_hlist(&self, p: NodeRef) -> bool {
505 self.nodes.id(p) == crate::nodes::id::HLIST
506 }
507
508 pub fn cur_math_style(&self) -> i32 {
510 if self.mode.abs_kind() == crate::maincontrol::ModeKind::Math {
511 self.cur_list().math_style
512 } else {
513 -1
514 }
515 }
516
517 pub fn insert_height(&self, n: u32) -> i32 {
519 self.page
520 .ins
521 .iter()
522 .find(|r| r.n == n)
523 .map_or(0, |r| r.height)
524 }
525}
526
527pub fn etex_node_type(t: u8, subtype: u16) -> i32 {
532 use crate::nodes::id;
533 match t {
534 id::GLYPH => {
535 if subtype & crate::nodes::glyph_sub::LIGATURE != 0 {
536 7
537 } else {
538 0
539 }
540 }
541 id::HLIST => 1,
542 id::VLIST => 2,
543 id::RULE => 3,
544 id::INS => 4,
545 id::MARK => 5,
546 id::ADJUST => 6,
547 id::DISC => 8,
548 id::LOCAL_PAR => -1,
552 id::WHATSIT | id::DIR | id::BOUNDARY => 9,
553 id::MATH => 10,
554 id::GLUE => 11,
555 id::KERN | id::MARGIN_KERN => 12,
556 id::PENALTY => 13,
557 id::UNSET => 14,
558 _ => 15,
559 }
560}