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 => self.printer.print_str("->"),
157 _ => self.print_esc_str("BAD."),
158 }
159 }
160 p += 1;
161 }
162 if magic == Some(p) {
163 self.set_trick_count();
164 }
165 if p < end {
166 self.print_esc_str("ETC.");
167 }
168 }
169
170 pub fn print_cmd_chr(&mut self, cmd: Cmd, chr: u32) {
172 let chr_cmd = |e: &mut Engine, s: &str| {
173 e.printer.print_str(s);
174 e.printer.print_char(chr);
175 };
176 match cmd {
177 Cmd::LeftBrace => chr_cmd(self, "begin-group character "),
178 Cmd::RightBrace => chr_cmd(self, "end-group character "),
179 Cmd::MathShift => chr_cmd(self, "math shift character "),
180 Cmd::MacParam => chr_cmd(self, "macro parameter character "),
181 Cmd::SupMark => chr_cmd(self, "superscript character "),
182 Cmd::SubMark => chr_cmd(self, "subscript character "),
183 Cmd::Endv => self.printer.print_str("end of alignment template"),
184 Cmd::Spacer => chr_cmd(self, "blank space "),
185 Cmd::Letter => chr_cmd(self, "the letter "),
186 Cmd::OtherChar => chr_cmd(self, "the character "),
187 Cmd::TabMark if chr < 0x11_0000 => chr_cmd(self, "alignment tab character "),
188 Cmd::UndefinedCs => self.printer.print_str("undefined"),
189 Cmd::LuaCall => {
190 self.printer.print_str("luacall ");
191 self.printer.print_int(i64::from(chr));
192 }
193 Cmd::LuaExpandableCall => {
194 self.printer.print_str("expandable luacall ");
195 self.printer.print_int(i64::from(chr));
196 }
197 Cmd::Call | Cmd::LongCall | Cmd::OuterCall | Cmd::LongOuterCall => {
198 let n = cmd as u32 - Cmd::Call as u32;
200 if n & 1 != 0 {
201 self.print_esc_str("long");
202 }
203 if n & 2 != 0 {
204 self.print_esc_str("outer");
205 }
206 if n > 0 {
207 self.printer.print_char(' ' as u32);
208 }
209 self.printer.print_str("macro");
210 }
211 Cmd::EndTemplate => self.print_esc_str("outer endtemplate"),
212 Cmd::CharGiven => {
213 self.print_esc_str("char");
214 self.printer.print_hex(i64::from(chr));
215 }
216 Cmd::MathGiven => {
217 self.print_esc_str("mathchar");
218 let v = crate::codes::math_given_report(chr) as u32;
221 self.printer.print_char('"' as u32);
222 for d in [v / 0x1000, (v >> 8) & 0xF, (v >> 4) & 0xF, v & 0xF] {
223 let c = if d < 10 {
224 '0' as u32 + d
225 } else {
226 'A' as u32 + d - 10
227 };
228 self.printer.print_char(c);
229 }
230 }
231 Cmd::XmathGiven => {
232 self.print_esc_str("Umathchar");
233 let code = i64::from(chr);
234 self.printer
235 .print_hex(i64::from(crate::codes::math_class(code)));
236 self.printer
237 .print_str(&format!("\"{:02X}", crate::codes::math_fam(code)));
238 self.printer
239 .print_str(&format!("\"{:06X}", crate::codes::math_char(code)));
240 }
241 Cmd::SetFont => {
242 self.printer.print_str("select font ");
243 self.print_font_name_and_size(chr);
244 }
245 Cmd::AssignInt if chr >= REG_OFFSET => {
246 self.print_esc_str("count");
247 self.printer.print_int(i64::from(chr - REG_OFFSET));
248 }
249 Cmd::AssignAttr => {
250 self.print_esc_str("attribute");
251 self.printer
252 .print_int(i64::from(chr.saturating_sub(REG_OFFSET)));
253 }
254 Cmd::AssignDimen if chr >= REG_OFFSET => {
255 self.print_esc_str("dimen");
256 self.printer.print_int(i64::from(chr - REG_OFFSET));
257 }
258 Cmd::AssignGlue if chr >= REG_OFFSET => {
259 self.print_esc_str("skip");
260 self.printer.print_int(i64::from(chr - REG_OFFSET));
261 }
262 Cmd::AssignMuGlue if chr >= REG_OFFSET => {
263 self.print_esc_str("muskip");
264 self.printer.print_int(i64::from(chr - REG_OFFSET));
265 }
266 Cmd::AssignToks if chr >= REG_OFFSET => {
267 self.print_esc_str("toks");
268 self.printer.print_int(i64::from(chr - REG_OFFSET));
269 }
270 Cmd::IfTest if chr >= crate::cond::UNLESS_CODE => {
271 self.print_esc_str("unless");
272 self.print_cmd_chr(cmd, chr - crate::cond::UNLESS_CODE);
273 }
274 Cmd::Relax if chr == crate::input::NO_EXPAND_FLAG => {
275 self.print_esc_str("notexpanded:");
276 }
277 _ => match crate::primitives::name_of(cmd, chr) {
278 Some(name) => self.print_esc_str(name),
279 None => {
280 self.printer.print_str("[unknown command code! (");
282 self.printer.print_int(i64::from(cmd as u8));
283 self.printer.print_str(", ");
284 self.printer.print_int(i64::from(chr));
285 self.printer.print_str(")]");
286 }
287 },
288 }
289 }
290
291 pub fn print_meaning(&mut self) {
293 if self.cur_cmd.is_call() {
294 let mac = if self.cur_cs != crate::hash::NO_CS {
295 self.eqtb.meaning(self.cur_cs).mac.clone()
296 } else {
297 None
298 };
299 let n = self.cur_cmd as u32 - Cmd::Call as u32;
300 let protected = mac.as_ref().is_some_and(|m| m.protected);
301 if protected {
302 self.print_esc_str("protected");
303 }
304 if n & 1 != 0 {
305 self.print_esc_str("long");
306 }
307 if n & 2 != 0 {
308 self.print_esc_str("outer");
309 }
310 if n > 0 || protected {
311 self.printer.print_char(' ' as u32);
312 }
313 self.printer.print_str("macro");
314 self.printer.print_char(':' as u32);
315 self.printer.print_ln();
316 if let Some(m) = mac {
317 let toks = m.tokens.clone();
318 self.token_show_list(&toks, 0, toks.len(), 10_000_000);
319 }
320 } else if self.cur_cmd == Cmd::TopBotMark && self.cur_chr < 5 {
321 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
322 self.printer.print_char(':' as u32);
323 self.printer.print_ln();
324 if let Some(list) = self.marks.get(0, self.cur_chr) {
325 self.token_show_list(&list, 0, list.len(), 10_000_000);
326 }
327 } else {
328 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
329 }
330 }
331
332 pub fn show_cur_cmd_chr(&mut self) {
334 self.begin_diagnostic();
335 self.printer.print_nl("{");
336 if self.mode != self.shown_mode {
337 self.print_mode(self.mode);
338 self.printer.print_str(": ");
339 self.shown_mode = self.mode;
340 }
341 self.print_cmd_chr(self.cur_cmd, self.cur_chr);
342 if self.eqtb.int(pg::assign_int::TRACINGIFS) > 0
343 && self.cur_cmd >= Cmd::IfTest
344 && self.cur_cmd <= Cmd::FiOrElse
345 {
346 self.printer.print_str(": ");
347 let (mut n, l) = if self.cur_cmd == Cmd::FiOrElse {
348 self.print_cmd_chr(Cmd::IfTest, self.cond.cur_if);
349 self.printer.print_char(' ' as u32);
350 (0, self.cond.if_line)
351 } else {
352 (1, self.input.line())
353 };
354 n += self.cond.stack.len() as i64;
355 self.printer.print_str("(level ");
356 self.printer.print_int(n);
357 self.printer.print_char(')' as u32);
358 if l != 0 {
359 self.printer.print_str(" entered on line ");
360 self.printer.print_int(l.into());
361 }
362 }
363 self.printer.print_char('}' as u32);
364 self.end_diagnostic(false);
365 }
366}