1use crate::Engine;
5use crate::cmd::Cmd;
6use crate::hash::{CsId, CsKind};
7use crate::primitives_gen as pg;
8use crate::scan::REG_OFFSET;
9use crate::token::Token;
10
11impl Engine {
12 pub fn print_esc_bytes(&mut self, s: &[u8]) {
15 let c = self.eqtb.int(pg::assign_int::ESCAPECHAR);
16 if (0..=0x10_FFFF).contains(&c) {
17 self.printer.print_char(c as u32);
18 }
19 self.printer.print_bytes(s);
20 }
21
22 pub fn print_esc_str(&mut self, s: &str) {
24 self.print_esc_bytes(s.as_bytes());
25 }
26
27 pub fn print_cs(&mut self, p: CsId) {
30 if !self.hash.contains(p) {
31 self.print_esc_str("IMPOSSIBLE.");
33 return;
34 }
35 match self.hash.kind(p).clone() {
36 CsKind::Null => {
37 self.print_esc_str("csname");
38 self.print_esc_str("endcsname");
39 self.printer.print_char(' ' as u32);
40 }
41 CsKind::Single(c) => {
42 self.print_esc_bytes(&crate::utf8x::encode(c));
43 if self.eqtb.catcode(c) == 11 {
44 self.printer.print_char(' ' as u32);
45 }
46 }
47 CsKind::Active(c) => self.printer.print_char(c),
48 CsKind::Undefined => self.print_esc_str("IMPOSSIBLE."),
49 CsKind::Internal => {
50 let name = self.hash.name(p).to_vec();
51 self.printer.print_bytes(&name);
52 }
53 CsKind::Multi | CsKind::Frozen => {
54 let name = self.hash.name(p).to_vec();
55 self.print_esc_bytes(&name);
56 self.printer.print_char(' ' as u32);
57 }
58 }
59 }
60
61 pub fn sprint_cs(&mut self, p: CsId) {
63 match self.hash.kind(p).clone() {
64 CsKind::Null => {
65 self.print_esc_str("csname");
66 self.print_esc_str("endcsname");
67 }
68 CsKind::Active(c) => self.printer.print_char(c),
69 CsKind::Undefined => self.print_esc_str("IMPOSSIBLE."),
70 CsKind::Internal => {
71 let name = self.hash.name(p).to_vec();
72 self.printer.print_bytes(&name);
73 }
74 _ => {
75 let name = self.hash.name(p).to_vec();
76 self.print_esc_bytes(&name);
77 }
78 }
79 }
80
81 pub fn show_token_list(&mut self, list: &[Token], start: usize, end: usize, l: i64) {
85 self.show_token_list_impl(list, start, end, None, l);
86 }
87
88 pub fn show_token_list_ctx(&mut self, list: &[Token], loc: usize, l: i64) {
91 self.show_token_list_impl(list, 0, list.len(), Some(loc), l);
92 }
93
94 pub fn token_show_list(&mut self, list: &[Token], start: usize, end: usize, l: i64) {
96 self.show_token_list(list, start, end, l);
97 }
98
99 fn show_token_list_impl(
100 &mut self,
101 list: &[Token],
102 start: usize,
103 end: usize,
104 magic: Option<usize>,
105 l: i64,
106 ) {
107 let mut match_chr = '#' as u32;
108 let mut n = b'0';
109 self.printer.tally = 0;
110 let mut p = start;
111 while p < end && (self.printer.tally as i64) < l {
112 if magic == Some(p) {
113 self.set_trick_count();
114 }
115 let t = list[p];
116 if t.is_cs() {
117 self.print_cs(t.cs_id());
118 } else {
119 let c = t.chr();
120 match Cmd::from_u8(t.cmd_code() as u8) {
121 Cmd::LeftBrace
122 | Cmd::RightBrace
123 | Cmd::MathShift
124 | Cmd::TabMark
125 | Cmd::SupMark
126 | Cmd::SubMark
127 | Cmd::Spacer
128 | Cmd::Letter
129 | Cmd::OtherChar => self.printer.print_char(c),
130 Cmd::MacParam => {
131 self.printer.print_char(c);
132 if !self.single_mac_param {
133 self.printer.print_char(c);
134 }
135 }
136 Cmd::CarRet => {
137 self.printer.print_char(match_chr);
139 if c <= 9 {
140 self.printer.print_char(c + '0' as u32);
141 } else {
142 self.printer.print_char('!' as u32);
143 return;
144 }
145 }
146 Cmd::ParEnd => {
147 match_chr = c;
149 self.printer.print_char(c);
150 n += 1;
151 self.printer.print_char(u32::from(n));
152 if n > b'9' {
153 return;
154 }
155 }
156 Cmd::Stop => {
157 let tally = self.printer.tally;
163 self.printer.print_str("->");
164 if self.printer.selector == crate::print::Selector::LogOnly {
165 self.printer.tally = tally;
166 }
167 }
168 _ => self.print_esc_str("BAD."),
169 }
170 }
171 p += 1;
172 }
173 if magic == Some(p) {
174 self.set_trick_count();
175 }
176 if p < end {
177 self.print_esc_str("ETC.");
178 }
179 }
180
181 pub fn print_cmd_chr(&mut self, cmd: Cmd, chr: u32) {
183 let chr_cmd = |e: &mut Engine, s: &str| {
184 e.printer.print_str(s);
185 e.printer.print_char(chr);
186 };
187 match cmd {
188 Cmd::LeftBrace => chr_cmd(self, "begin-group character "),
189 Cmd::RightBrace => chr_cmd(self, "end-group character "),
190 Cmd::MathShift => chr_cmd(self, "math shift character "),
191 Cmd::MacParam if chr < 0x11_0000 => chr_cmd(self, "macro parameter character "),
192 Cmd::SupMark => chr_cmd(self, "superscript character "),
193 Cmd::SubMark => chr_cmd(self, "subscript character "),
194 Cmd::Endv => self.printer.print_str("end of alignment template"),
195 Cmd::Spacer => chr_cmd(self, "blank space "),
196 Cmd::Letter => chr_cmd(self, "the letter "),
197 Cmd::OtherChar => chr_cmd(self, "the character "),
198 Cmd::TabMark if chr < 0x11_0000 => chr_cmd(self, "alignment tab character "),
199 Cmd::UndefinedCs => self.printer.print_str("undefined"),
200 Cmd::LuaCall => {
201 self.printer.print_str("luacall ");
202 self.printer.print_int(i64::from(chr));
203 }
204 Cmd::LuaExpandableCall => {
205 self.printer.print_str("expandable luacall ");
206 self.printer.print_int(i64::from(chr));
207 }
208 Cmd::Call | Cmd::LongCall | Cmd::OuterCall | Cmd::LongOuterCall => {
209 let n = cmd as u32 - Cmd::Call as u32;
211 if n & 1 != 0 {
212 self.print_esc_str("long");
213 }
214 if n & 2 != 0 {
215 self.print_esc_str("outer");
216 }
217 if n > 0 {
218 self.printer.print_char(' ' as u32);
219 }
220 self.printer.print_str("macro");
221 }
222 Cmd::EndTemplate => self.print_esc_str("outer endtemplate"),
223 Cmd::CharGiven => {
224 self.print_esc_str("char");
225 self.printer.print_hex(i64::from(chr));
226 }
227 Cmd::MathGiven => {
228 self.print_esc_str("mathchar");
229 let v = crate::codes::math_given_report(chr) as u32;
232 self.printer.print_char('"' as u32);
233 for d in [v / 0x1000, (v >> 8) & 0xF, (v >> 4) & 0xF, v & 0xF] {
234 let c = if d < 10 {
235 '0' as u32 + d
236 } else {
237 'A' as u32 + d - 10
238 };
239 self.printer.print_char(c);
240 }
241 }
242 Cmd::XmathGiven => {
243 self.print_esc_str("Umathchar");
244 let code = i64::from(chr);
245 self.printer
246 .print_hex(i64::from(crate::codes::math_class(code)));
247 self.printer
248 .print_str(&format!("\"{:02X}", crate::codes::math_fam(code)));
249 self.printer
250 .print_str(&format!("\"{:06X}", crate::codes::math_char(code)));
251 }
252 Cmd::SetFont => {
253 self.printer.print_str("select font ");
254 self.print_font_name_and_size(chr);
255 }
256 Cmd::AssignInt if chr >= REG_OFFSET => {
257 self.print_esc_str("count");
258 self.printer.print_int(i64::from(chr - REG_OFFSET));
259 }
260 Cmd::AssignAttr => {
261 self.print_esc_str("attribute");
262 self.printer
263 .print_int(i64::from(chr.saturating_sub(REG_OFFSET)));
264 }
265 Cmd::AssignDimen if chr >= REG_OFFSET => {
266 self.print_esc_str("dimen");
267 self.printer.print_int(i64::from(chr - REG_OFFSET));
268 }
269 Cmd::AssignGlue if chr >= REG_OFFSET => {
270 self.print_esc_str("skip");
271 self.printer.print_int(i64::from(chr - REG_OFFSET));
272 }
273 Cmd::AssignMuGlue if chr >= REG_OFFSET => {
274 self.print_esc_str("muskip");
275 self.printer.print_int(i64::from(chr - REG_OFFSET));
276 }
277 Cmd::AssignToks if chr >= REG_OFFSET => {
278 self.print_esc_str("toks");
279 self.printer.print_int(i64::from(chr - REG_OFFSET));
280 }
281 Cmd::IfTest if chr >= crate::cond::UNLESS_CODE => {
282 self.print_esc_str("unless");
283 self.print_cmd_chr(cmd, chr - crate::cond::UNLESS_CODE);
284 }
285 Cmd::Relax if chr == crate::input::NO_EXPAND_FLAG => {
286 self.print_esc_str("notexpanded:");
287 }
288 _ => match crate::primitives::name_of(cmd, chr) {
289 Some(name) => self.print_esc_str(name),
290 None => {
291 self.printer.print_str("[unknown command code! (");
293 self.printer.print_int(i64::from(cmd as u8));
294 self.printer.print_str(", ");
295 self.printer.print_int(i64::from(chr));
296 self.printer.print_str(")]");
297 }
298 },
299 }
300 }
301
302 pub fn print_meaning(&mut self) {
304 if self.cur_cmd.is_call() {
305 let mac = if self.cur_cs != crate::hash::NO_CS {
306 self.eqtb.meaning(self.cur_cs).mac.clone()
307 } else {
308 None
309 };
310 let n = self.cur_cmd as u32 - Cmd::Call as u32;
311 let protected = mac.as_ref().is_some_and(|m| m.protected);
312 if protected {
313 self.print_esc_str("protected");
314 }
315 if n & 1 != 0 {
316 self.print_esc_str("long");
317 }
318 if n & 2 != 0 {
319 self.print_esc_str("outer");
320 }
321 if n > 0 || protected {
322 self.printer.print_char(' ' as u32);
323 }
324 self.printer.print_str("macro");
325 self.printer.print_char(':' as u32);
326 self.printer.print_ln();
327 if let Some(m) = mac {
328 let toks = m.tokens.clone();
329 self.token_show_list(&toks, 0, toks.len(), 10_000_000);
330 }
331 } else if self.cur_cmd == Cmd::TopBotMark && self.cur_chr < 5 {
332 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
333 self.printer.print_char(':' as u32);
334 self.printer.print_ln();
335 if let Some(list) = self.marks.get(0, self.cur_chr) {
336 self.token_show_list(&list, 0, list.len(), 10_000_000);
337 }
338 } else {
339 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
340 }
341 }
342
343 pub fn show_cur_cmd_chr(&mut self) {
345 self.begin_diagnostic();
346 self.printer.print_nl("{");
347 if self.mode != self.shown_mode {
348 self.print_mode(self.mode);
349 self.printer.print_str(": ");
350 self.shown_mode = self.mode;
351 }
352 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
353 if self.eqtb.int(pg::assign_int::TRACINGIFS) > 0
354 && self.cur_cmd >= Cmd::IfTest
355 && self.cur_cmd <= Cmd::FiOrElse
356 {
357 self.printer.print_str(": ");
358 let (mut n, l) = if self.cur_cmd == Cmd::FiOrElse {
359 self.print_cmd_chr(Cmd::IfTest, self.cond.cur_if);
360 self.printer.print_char(' ' as u32);
361 (0, self.cond.if_line)
362 } else {
363 (1, self.input.line())
364 };
365 n += self.cond.stack.len() as i64;
366 self.printer.print_str("(level ");
367 self.printer.print_int(n);
368 self.printer.print_char(')' as u32);
369 if l != 0 {
370 self.printer.print_str(" entered on line ");
371 self.printer.print_int(l.into());
372 }
373 }
374 self.printer.print_char('}' as u32);
375 self.end_diagnostic(false);
376 }
377}