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