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 match self.run_list_filter(cb, head, group) {
250 crate::ListFilter::Keep(h) => {
251 if !h.is_null() {
252 self.nodes.set_prev(h, NodeRef::NULL);
253 }
254 h
255 }
256 crate::ListFilter::Flush => {
257 self.nodes.flush_list(head);
258 NodeRef::NULL
259 }
260 }
261 }
262
263 pub fn page_is_empty(&self) -> bool {
265 self.page.page_head == self.page.page_tail
266 && self.nodes.next(self.page.contrib_head).is_null()
267 }
268
269 pub fn not_implemented(&mut self, what: &str) {
271 self.print_err("retex: not implemented yet: ");
272 self.printer.print_str(what);
273 self.help(&["This command is not supported by retex yet."]);
274 self.error();
275 }
276
277 pub fn cur_attr(&mut self) -> Option<AttrList> {
279 let generation = self.eqtb.attr_generation;
280 if let Some((g, a)) = &self.ts.attr_cache
281 && *g == generation
282 {
283 return a.clone();
284 }
285 let mut v: Vec<(u32, i32)> = Vec::new();
286 for (i, s) in self.eqtb.attr.iter().enumerate() {
287 if s.val != crate::eqtb::UNUSED_ATTRIBUTE {
288 v.push((i as u32, s.val));
289 }
290 }
291 let a: Option<AttrList> = if v.is_empty() {
292 None
293 } else {
294 Some(std::rc::Rc::from(v))
295 };
296 self.ts.attr_cache = Some((generation, a.clone()));
297 a
298 }
299
300 pub fn new_node(&mut self, id: u8, subtype: u16, data: crate::nodes::NodeData) -> NodeRef {
302 let p = self.nodes.alloc(id, subtype, data);
303 self.give_new_attr(p);
304 p
305 }
306
307 #[inline]
310 pub fn give_new_attr(&mut self, p: NodeRef) {
311 if let Some(a) = &self.ts.attr_override {
312 let a = a.clone();
313 self.nodes.set_attr(p, a);
314 } else if self.eqtb.attrs_in_use {
315 let a = self.cur_attr();
316 self.nodes.set_attr(p, a);
317 }
318 }
319
320 pub fn alter_aux(&mut self) {
322 let c = self.cur_chr;
323 if (c == SET_AUX_PREV_DEPTH)
324 != (self.mode.abs_kind() == crate::maincontrol::ModeKind::Vertical)
325 {
326 self.report_illegal_case();
327 return;
328 }
329 self.scan_optional_equals();
330 if c == SET_AUX_PREV_DEPTH {
331 self.scan_normal_dimen();
332 self.cur_list_mut().prev_depth = self.cur_val;
333 } else {
334 self.scan_int();
335 if self.cur_val <= 0 || self.cur_val > 32767 {
336 self.print_err("Bad space factor");
337 self.help(&["I allow only values in the range 1..32767 here."]);
338 self.int_error(self.cur_val);
339 } else {
340 self.cur_list_mut().space_factor = self.cur_val;
341 }
342 }
343 }
344
345 pub fn alter_prev_graf(&mut self) {
347 self.scan_optional_equals();
348 self.scan_int();
349 let v = self.cur_val;
350 if v < 0 {
351 self.print_err("Bad ");
352 self.print_esc_str("prevgraf");
353 self.help(&["I allow only nonnegative values here."]);
354 self.int_error(v);
355 } else {
356 let mut p = self.nest.len() - 1;
358 while self.nest[p].mode.abs_kind() == crate::maincontrol::ModeKind::Math && p > 0 {
359 p -= 1;
360 }
361 self.nest[p].prev_graf = v;
362 }
363 }
364
365 pub fn alter_page_so_far(&mut self) {
367 let c = self.cur_chr as usize;
368 self.scan_optional_equals();
369 self.scan_normal_dimen();
370 if c < self.page.so_far.len() {
371 self.page.so_far[c] = self.cur_val;
372 }
373 }
374
375 pub fn alter_box_dimen(&mut self) {
379 let c = self.cur_chr;
380 self.scan_register_num();
381 let b = self.eqtb.boxes[self.cur_val as usize].val;
382 self.scan_optional_equals();
383 self.scan_normal_dimen();
384 let v = self.cur_val;
385 if let Some(bd) = self.nodes.box_data_mut(b) {
386 match c {
387 2 => bd.width = v,
388 3 => bd.depth = v,
389 _ => bd.height = v,
390 }
391 }
392 }
393
394 pub fn fetch_aux(&mut self, m: u32) -> Option<(i32, ValLevel)> {
396 let vertical = self.mode.abs_kind() == crate::maincontrol::ModeKind::Vertical;
397 if (m == SET_AUX_PREV_DEPTH) != vertical {
398 self.print_err("Improper ");
399 self.print_cmd_chr(crate::cmd::Cmd::SetAux, m);
400 self.help(&[
401 "You can refer to \\spacefactor only in horizontal mode;",
402 "you can refer to \\prevdepth only in vertical mode; and",
403 "neither of these is meaningful inside \\write. So",
404 "I'm forgetting what you said and using zero instead.",
405 ]);
406 self.error();
407 return Some((
408 0,
409 if m == SET_AUX_PREV_DEPTH {
410 ValLevel::Dimen
411 } else {
412 ValLevel::Int
413 },
414 ));
415 }
416 let cl = self.cur_list();
417 if m == SET_AUX_PREV_DEPTH {
418 Some((cl.prev_depth, ValLevel::Dimen))
419 } else {
420 Some((cl.space_factor, ValLevel::Int))
421 }
422 }
423
424 pub fn fetch_prev_graf(&mut self) -> i32 {
426 if self.mode == crate::maincontrol::Mode::None {
427 return 0;
428 }
429 let mut p = self.nest.len() - 1;
430 while self.nest[p].mode.abs_kind() == crate::maincontrol::ModeKind::Math && p > 0 {
431 p -= 1;
432 }
433 self.nest[p].prev_graf
434 }
435
436 pub fn page_so_far_value(&self, m: u32) -> i32 {
438 if self.page.contents == PageContents::Empty && !self.ts.output_active {
441 return if m == 0 { retex_arith::MAX_DIMEN } else { 0 };
442 }
443 self.page.so_far.get(m as usize).copied().unwrap_or(0)
444 }
445
446 pub fn fetch_last_node_item(&mut self, m: u32) -> (i32, crate::glue::Glue, ValLevel) {
448 use crate::nodes::NodeData;
449 use crate::scan::last_item as li;
450 let level = match m {
451 li::LAST_KERN => ValLevel::Dimen,
452 li::LAST_SKIP => ValLevel::Glue,
453 _ => ValLevel::Int,
454 };
455 let tail = self.cur_list().tail;
456 let head = self.cur_list().head;
457 if m == li::LAST_NODE_TYPE {
458 if tail == head {
459 if self.mode == crate::maincontrol::Mode::Vertical && self.nest.len() == 1 {
460 return (self.page.last_node_type, Glue::ZERO, level);
461 }
462 return (-1, Glue::ZERO, level);
463 }
464 let v = etex_node_type(self.nodes.id(tail), self.nodes.subtype(tail));
465 return (v, Glue::ZERO, level);
466 }
467 if tail != head {
468 match &self.nodes.get(tail).data {
469 NodeData::Penalty { penalty } if m == li::LAST_PENALTY => {
470 return (*penalty, Glue::ZERO, level);
471 }
472 NodeData::Kern { kern, .. } if m == li::LAST_KERN => {
473 return (*kern, Glue::ZERO, level);
474 }
475 NodeData::Glue { spec, .. } if m == li::LAST_SKIP => {
476 let l = if self.nodes.get(tail).subtype == crate::nodes::glue_sub::MU_GLUE {
477 ValLevel::Mu
478 } else {
479 level
480 };
481 return (spec.width, *spec, l);
482 }
483 _ => {}
484 }
485 } else if self.mode == crate::maincontrol::Mode::Vertical && self.nest.len() == 1 {
486 match m {
487 li::LAST_PENALTY => return (self.page.last_penalty, Glue::ZERO, level),
488 li::LAST_KERN => return (self.page.last_kern, Glue::ZERO, level),
489 li::LAST_SKIP => {
490 if let Some(g) = self.page.last_glue {
491 return (g.width, g, level);
492 }
493 }
494 _ => {}
495 }
496 }
497 (0, Glue::ZERO, level)
498 }
499
500 pub fn box_is_hlist(&self, p: NodeRef) -> bool {
502 self.nodes.id(p) == crate::nodes::id::HLIST
503 }
504
505 pub fn cur_math_style(&self) -> i32 {
507 if self.mode.abs_kind() == crate::maincontrol::ModeKind::Math {
508 self.cur_list().math_style
509 } else {
510 -1
511 }
512 }
513
514 pub fn insert_height(&self, n: u32) -> i32 {
516 self.page
517 .ins
518 .iter()
519 .find(|r| r.n == n)
520 .map_or(0, |r| r.height)
521 }
522}
523
524pub fn etex_node_type(t: u8, subtype: u16) -> i32 {
529 use crate::nodes::id;
530 match t {
531 id::GLYPH => {
532 if subtype & crate::nodes::glyph_sub::LIGATURE != 0 {
533 7
534 } else {
535 0
536 }
537 }
538 id::HLIST => 1,
539 id::VLIST => 2,
540 id::RULE => 3,
541 id::INS => 4,
542 id::MARK => 5,
543 id::ADJUST => 6,
544 id::DISC => 8,
545 id::LOCAL_PAR => -1,
549 id::WHATSIT | id::DIR | id::BOUNDARY => 9,
550 id::MATH => 10,
551 id::GLUE => 11,
552 id::KERN | id::MARGIN_KERN => 12,
553 id::PENALTY => 13,
554 id::UNSET => 14,
555 _ => 15,
556 }
557}