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 ins: Vec<PageIns>,
138 pub last_glue: Option<Glue>,
141 pub last_penalty: i32,
143 pub last_kern: i32,
145 pub last_node_type: i32,
147}
148
149impl PageState {
150 pub fn init(&mut self, nodes: &mut Nodes) {
152 self.contrib_head = nodes.new_temp();
153 self.page_head = nodes.new_temp();
154 self.page_tail = self.page_head;
155 self.last_node_type = -1;
156 }
157
158 pub fn stretch(&self, o: u8) -> i32 {
160 match o {
161 0 => self.so_far[2],
162 1 => self.fi_stretch,
163 2 => self.so_far[3],
164 3 => self.so_far[4],
165 _ => self.so_far[5],
166 }
167 }
168
169 pub fn stretch_mut(&mut self, o: u8) -> &mut i32 {
171 match o {
172 0 => &mut self.so_far[2],
173 1 => &mut self.fi_stretch,
174 2 => &mut self.so_far[3],
175 3 => &mut self.so_far[4],
176 _ => &mut self.so_far[5],
177 }
178 }
179}
180
181#[derive(Default)]
183pub struct TsState {
184 pub show_prefix: Vec<u8>,
187 pub font_in_short_display: i64,
189 pub output_active: bool,
191 pub adjust_head: NodeRef,
193 pub pre_adjust_head: NodeRef,
195 pub adjust_tail: Option<NodeRef>,
197 pub pre_adjust_tail: Option<NodeRef>,
199 pub pack_begin_line: i32,
202 pub disc_ptr: [NodeRef; 4],
205 pub attr_cache: Option<(u64, Option<AttrList>)>,
207 pub align: crate::align::AlignState,
209 pub last_totals: ([i32; 5], [i32; 5]),
211 pub just_box: NodeRef,
213 pub math: crate::mlist::MathState,
215}
216
217impl std::fmt::Debug for TsState {
218 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
219 f.debug_struct("TsState")
220 .field("output_active", &self.output_active)
221 .finish_non_exhaustive()
222 }
223}
224
225impl Engine {
226 pub fn filter_list(&mut self, cb: &str, head: NodeRef, group: &str) -> NodeRef {
231 match self.run_list_filter(cb, head, group) {
232 crate::ListFilter::Keep(h) => {
233 if !h.is_null() {
234 self.nodes.set_prev(h, NodeRef::NULL);
235 }
236 h
237 }
238 crate::ListFilter::Flush => {
239 self.nodes.flush_list(head);
240 NodeRef::NULL
241 }
242 }
243 }
244
245 pub fn page_is_empty(&self) -> bool {
247 self.page.page_head == self.page.page_tail
248 && self.nodes.next(self.page.contrib_head).is_null()
249 }
250
251 pub fn not_implemented(&mut self, what: &str) {
253 self.print_err("retex: not implemented yet: ");
254 self.printer.print_str(what);
255 self.help(&["This command is not supported by retex yet."]);
256 self.error();
257 }
258
259 pub fn cur_attr(&mut self) -> Option<AttrList> {
261 let generation = self.eqtb.attr_generation;
262 if let Some((g, a)) = &self.ts.attr_cache
263 && *g == generation
264 {
265 return a.clone();
266 }
267 let mut v: Vec<(u32, i32)> = Vec::new();
268 for (i, s) in self.eqtb.attr.iter().enumerate() {
269 if s.val != crate::eqtb::UNUSED_ATTRIBUTE {
270 v.push((i as u32, s.val));
271 }
272 }
273 let a: Option<AttrList> = if v.is_empty() {
274 None
275 } else {
276 Some(std::rc::Rc::from(v))
277 };
278 self.ts.attr_cache = Some((generation, a.clone()));
279 a
280 }
281
282 pub fn new_node(&mut self, id: u8, subtype: u16, data: crate::nodes::NodeData) -> NodeRef {
284 let p = self.nodes.alloc(id, subtype, data);
285 if self.eqtb.attrs_in_use {
286 let a = self.cur_attr();
287 self.nodes.set_attr(p, a);
288 }
289 p
290 }
291
292 pub fn alter_aux(&mut self) {
294 let c = self.cur_chr;
295 if (c == SET_AUX_PREV_DEPTH)
296 != (self.mode.abs_kind() == crate::maincontrol::ModeKind::Vertical)
297 {
298 self.report_illegal_case();
299 return;
300 }
301 self.scan_optional_equals();
302 if c == SET_AUX_PREV_DEPTH {
303 self.scan_normal_dimen();
304 self.cur_list_mut().prev_depth = self.cur_val;
305 } else {
306 self.scan_int();
307 if self.cur_val <= 0 || self.cur_val > 32767 {
308 self.print_err("Bad space factor");
309 self.help(&["I allow only values in the range 1..32767 here."]);
310 self.int_error(self.cur_val);
311 } else {
312 self.cur_list_mut().space_factor = self.cur_val;
313 }
314 }
315 }
316
317 pub fn alter_prev_graf(&mut self) {
319 self.scan_optional_equals();
320 self.scan_int();
321 let v = self.cur_val;
322 if v < 0 {
323 self.print_err("Bad ");
324 self.print_esc_str("prevgraf");
325 self.help(&["I allow only nonnegative values here."]);
326 self.int_error(v);
327 } else {
328 let mut p = self.nest.len() - 1;
330 while self.nest[p].mode.abs_kind() == crate::maincontrol::ModeKind::Math && p > 0 {
331 p -= 1;
332 }
333 self.nest[p].prev_graf = v;
334 }
335 }
336
337 pub fn alter_page_so_far(&mut self) {
339 let c = self.cur_chr as usize;
340 self.scan_optional_equals();
341 self.scan_normal_dimen();
342 if c < self.page.so_far.len() {
343 self.page.so_far[c] = self.cur_val;
344 }
345 }
346
347 pub fn alter_box_dimen(&mut self) {
351 let c = self.cur_chr;
352 self.scan_register_num();
353 let b = self.eqtb.boxes[self.cur_val as usize].val;
354 self.scan_optional_equals();
355 self.scan_normal_dimen();
356 let v = self.cur_val;
357 if let Some(bd) = self.nodes.box_data_mut(b) {
358 match c {
359 2 => bd.width = v,
360 3 => bd.depth = v,
361 _ => bd.height = v,
362 }
363 }
364 }
365
366 pub fn fetch_aux(&mut self, m: u32) -> Option<(i32, ValLevel)> {
368 let vertical = self.mode.abs_kind() == crate::maincontrol::ModeKind::Vertical;
369 if (m == SET_AUX_PREV_DEPTH) != vertical {
370 self.print_err("Improper ");
371 self.print_cmd_chr(crate::cmd::Cmd::SetAux, m);
372 self.help(&[
373 "You can refer to \\spacefactor only in horizontal mode;",
374 "you can refer to \\prevdepth only in vertical mode; and",
375 "neither of these is meaningful inside \\write. So",
376 "I'm forgetting what you said and using zero instead.",
377 ]);
378 self.error();
379 return Some((
380 0,
381 if m == SET_AUX_PREV_DEPTH {
382 ValLevel::Dimen
383 } else {
384 ValLevel::Int
385 },
386 ));
387 }
388 let cl = self.cur_list();
389 if m == SET_AUX_PREV_DEPTH {
390 Some((cl.prev_depth, ValLevel::Dimen))
391 } else {
392 Some((cl.space_factor, ValLevel::Int))
393 }
394 }
395
396 pub fn fetch_prev_graf(&mut self) -> i32 {
398 if self.mode == crate::maincontrol::Mode::None {
399 return 0;
400 }
401 let mut p = self.nest.len() - 1;
402 while self.nest[p].mode.abs_kind() == crate::maincontrol::ModeKind::Math && p > 0 {
403 p -= 1;
404 }
405 self.nest[p].prev_graf
406 }
407
408 pub fn page_so_far_value(&self, m: u32) -> i32 {
410 if self.page.contents == PageContents::Empty && !self.ts.output_active && m == 0 {
411 return retex_arith::MAX_DIMEN;
412 }
413 self.page.so_far.get(m as usize).copied().unwrap_or(0)
414 }
415
416 pub fn fetch_last_node_item(&mut self, m: u32) -> (i32, crate::glue::Glue, ValLevel) {
418 use crate::nodes::NodeData;
419 use crate::scan::last_item as li;
420 let level = match m {
421 li::LAST_KERN => ValLevel::Dimen,
422 li::LAST_SKIP => ValLevel::Glue,
423 _ => ValLevel::Int,
424 };
425 let tail = self.cur_list().tail;
426 let head = self.cur_list().head;
427 if m == li::LAST_NODE_TYPE {
428 if tail == head {
429 if self.mode == crate::maincontrol::Mode::Vertical && self.nest.len() == 1 {
430 return (self.page.last_node_type, Glue::ZERO, level);
431 }
432 return (-1, Glue::ZERO, level);
433 }
434 let v = etex_node_type(self.nodes.id(tail), self.nodes.subtype(tail));
435 return (v, Glue::ZERO, level);
436 }
437 if tail != head {
438 match &self.nodes.get(tail).data {
439 NodeData::Penalty { penalty } if m == li::LAST_PENALTY => {
440 return (*penalty, Glue::ZERO, level);
441 }
442 NodeData::Kern { kern, .. } if m == li::LAST_KERN => {
443 return (*kern, Glue::ZERO, level);
444 }
445 NodeData::Glue { spec, .. } if m == li::LAST_SKIP => {
446 let l = if self.nodes.get(tail).subtype == crate::nodes::glue_sub::MU_GLUE {
447 ValLevel::Mu
448 } else {
449 level
450 };
451 return (spec.width, *spec, l);
452 }
453 _ => {}
454 }
455 } else if self.mode == crate::maincontrol::Mode::Vertical && self.nest.len() == 1 {
456 match m {
457 li::LAST_PENALTY => return (self.page.last_penalty, Glue::ZERO, level),
458 li::LAST_KERN => return (self.page.last_kern, Glue::ZERO, level),
459 li::LAST_SKIP => {
460 if let Some(g) = self.page.last_glue {
461 return (g.width, g, level);
462 }
463 }
464 _ => {}
465 }
466 }
467 (0, Glue::ZERO, level)
468 }
469
470 pub fn box_is_hlist(&self, p: NodeRef) -> bool {
472 self.nodes.id(p) == crate::nodes::id::HLIST
473 }
474
475 pub fn cur_math_style(&self) -> i32 {
477 if self.mode.abs_kind() == crate::maincontrol::ModeKind::Math {
478 self.cur_list().math_style
479 } else {
480 -1
481 }
482 }
483
484 pub fn insert_height(&self, n: u32) -> i32 {
486 self.page
487 .ins
488 .iter()
489 .find(|r| r.n == n)
490 .map_or(0, |r| r.height)
491 }
492}
493
494pub fn etex_node_type(t: u8, subtype: u16) -> i32 {
499 use crate::nodes::id;
500 match t {
501 id::GLYPH => {
502 if subtype & crate::nodes::glyph_sub::LIGATURE != 0 {
503 7
504 } else {
505 0
506 }
507 }
508 id::HLIST => 1,
509 id::VLIST => 2,
510 id::RULE => 3,
511 id::INS => 4,
512 id::MARK => 5,
513 id::ADJUST => 6,
514 id::DISC => 8,
515 id::WHATSIT | id::LOCAL_PAR | id::DIR | id::BOUNDARY => 9,
516 id::MATH => 10,
517 id::GLUE => 11,
518 id::KERN | id::MARGIN_KERN => 12,
519 id::PENALTY => 13,
520 id::UNSET => 14,
521 _ => 15,
522 }
523}