1use crate::commands::methods::MacroParser;
6use crate::commands::primitives::{PrimitiveIdentifier, PRIMITIVES};
7use crate::engine::fontsystem::Font;
8use crate::engine::fontsystem::FontSystem;
9use crate::engine::mouth::strings::InputTokenizer;
10use crate::engine::state::State;
11use crate::engine::{EngineAux, EngineReferences, EngineTypes};
12use crate::prelude::CSHandler;
13use crate::tex::catcodes::{CategoryCodeScheme, CommandCode};
14use crate::tex::characters::StringLineSource;
15use crate::tex::nodes::boxes::{BoxInfo, TeXBox};
16use crate::tex::nodes::WhatsitFunction;
17use crate::tex::numerics::{MuSkip, Skip, TeXInt};
18use crate::tex::tokens::control_sequences::CSName;
19use crate::tex::tokens::token_lists::{CharWrite, StringCharWrite, TokenList};
20use crate::tex::tokens::Token;
21use crate::utils::errors::TeXResult;
22use either::Either;
23use std::fmt::Display;
24
25pub mod etex;
26pub mod methods;
27pub mod primitives;
28pub mod tex;
29
30#[derive(Debug)]
32pub enum ResolvedToken<'a, ET: EngineTypes> {
33 Tk { char: ET::Char, code: CommandCode },
35 Cmd(Option<&'a TeXCommand<ET>>),
38}
39
40#[derive(Debug)]
42pub enum CharOrPrimitive<ET: EngineTypes> {
43 Char(ET::Char, Option<CommandCode>),
44 Primitive(PrimitiveIdentifier),
45}
46
47#[derive(Copy, Clone, Eq, PartialEq, Debug)]
49pub enum ActiveConditional<I: TeXInt> {
50 Unfinished(PrimitiveIdentifier),
52 Case(I),
54 True(PrimitiveIdentifier),
56 Else(PrimitiveIdentifier),
58}
59impl<I: TeXInt> ActiveConditional<I> {
60 pub fn name(&self) -> PrimitiveIdentifier {
62 match self {
63 Self::Case(_) => PRIMITIVES.ifcase,
64 Self::True(n) | Self::Unfinished(n) | Self::Else(n) => *n,
65 }
66 }
67}
68
69#[derive(Clone, Debug)]
71pub enum TeXCommand<ET: EngineTypes> {
72 Macro(Macro<ET::Token>),
74 Char { char: ET::Char, code: CommandCode },
76 CharDef(ET::Char),
78 MathChar(u32),
80 Font(<ET::FontSystem as FontSystem>::Font),
82 IntRegister(usize),
84 DimRegister(usize),
86 SkipRegister(usize),
88 MuSkipRegister(usize),
90 ToksRegister(usize),
92 Primitive {
94 name: PrimitiveIdentifier,
95 cmd: PrimitiveCommand<ET>,
96 },
97}
98impl<ET: EngineTypes> TeXCommand<ET> {
99 pub const fn meaning<'a>(
101 &'a self,
102 int: &'a <<ET::Token as Token>::CS as CSName<ET::Char>>::Handler,
103 cc: &'a CategoryCodeScheme<ET::Char>,
104 escapechar: Option<ET::Char>,
105 ) -> Meaning<'a, ET> {
106 Meaning {
107 cmd: self,
108 int,
109 cc,
110 escapechar,
111 }
112 }
113
114 pub fn the<F: FnMut(&mut EngineAux<ET>, &ET::State, &mut ET::Gullet, ET::Token)>(
118 &self,
119 engine: &mut EngineReferences<ET>,
120 token: ET::Token,
121 mut cont: F,
122 ) -> TeXResult<(), ET> {
123 use crate::tex::tokens::token_lists::Otherize;
124 use std::fmt::Write;
125 match self {
126 Self::IntRegister(u) => {
127 let val = engine.state.get_int_register(*u);
128 write!(
129 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
130 "{val}"
131 )?;
132 }
133 Self::DimRegister(u) => {
134 let val = engine.state.get_dim_register(*u);
135 write!(
136 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
137 "{val}"
138 )?;
139 }
140 Self::SkipRegister(u) => {
141 let val = engine.state.get_skip_register(*u);
142 write!(
143 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
144 "{val}"
145 )?;
146 }
147 Self::MuSkipRegister(u) => {
148 let val = engine.state.get_muskip_register(*u);
149 write!(
150 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
151 "{val}"
152 )?;
153 }
154 Self::CharDef(c) => {
155 let val: u64 = (*c).into();
156 write!(
157 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
158 "{val}"
159 )?;
160 }
161 Self::MathChar(u) => {
162 write!(
163 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
164 "{u}"
165 )?;
166 }
167 Self::ToksRegister(u) => {
168 for t in &engine.state.get_toks_register(*u).0 {
169 cont(engine.aux, engine.state, engine.gullet, t.clone());
170 }
171 }
172 Self::Font(fnt) => {
173 let t = fnt.name();
174 cont(
175 engine.aux,
176 engine.state,
177 engine.gullet,
178 ET::Token::from_cs(t.clone()),
179 );
180 }
181 Self::Primitive { name, cmd } => return cmd.the(engine, token, *name, cont),
182 o => engine.general_error(format!(
183 "You can't use {} after \\the",
184 o.meaning(
185 engine.aux.memory.cs_interner(),
186 engine.state.get_catcode_scheme(),
187 engine.state.get_escape_char()
188 )
189 ))?,
190 }
191 Ok(())
192 }
193}
194
195#[derive(Copy, Clone, Debug)]
199pub enum PrimitiveCommand<ET: EngineTypes> {
200 Conditional(fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<bool, ET>),
202 Expandable(fn(&mut EngineReferences<ET>, &mut Vec<ET::Token>, ET::Token) -> TeXResult<(), ET>),
204 SimpleExpandable(fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<(), ET>),
207 Unexpandable {
209 scope: CommandScope,
210 apply: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<(), ET>,
211 },
212 Assignment(fn(&mut EngineReferences<ET>, ET::Token, bool) -> TeXResult<(), ET>),
215 Int {
218 read: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<ET::Int, ET>,
219 assign: Option<
220 for<'a, 'b> fn(&'a mut EngineReferences<'b, ET>, ET::Token, bool) -> TeXResult<(), ET>,
221 >,
222 },
223 Dim {
226 read: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<ET::Dim, ET>,
227 assign: Option<
228 for<'a, 'b> fn(&'a mut EngineReferences<'b, ET>, ET::Token, bool) -> TeXResult<(), ET>,
229 >,
230 },
231 Skip {
234 read: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<Skip<ET::Dim>, ET>,
235 assign: Option<
236 for<'a, 'b> fn(&'a mut EngineReferences<'b, ET>, ET::Token, bool) -> TeXResult<(), ET>,
237 >,
238 },
239 MuSkip {
242 read: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<MuSkip<ET::MuDim>, ET>,
243 assign: Option<
244 for<'a, 'b> fn(&'a mut EngineReferences<'b, ET>, ET::Token, bool) -> TeXResult<(), ET>,
245 >,
246 },
247 FontCmd {
250 read: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<ET::Font, ET>,
251 assign: Option<
252 for<'a, 'b> fn(&'a mut EngineReferences<'b, ET>, ET::Token, bool) -> TeXResult<(), ET>,
253 >,
254 },
255 Box(
259 fn(
260 &mut EngineReferences<ET>,
261 ET::Token,
262 ) -> TeXResult<Either<Option<TeXBox<ET>>, BoxInfo<ET>>, ET>,
263 ),
264 PrimitiveInt,
266 PrimitiveDim,
268 PrimitiveSkip,
270 PrimitiveMuSkip,
272 PrimitiveToks,
274 Whatsit {
277 get: fn(
278 &mut EngineReferences<ET>,
279 ET::Token,
280 ) -> TeXResult<Option<Box<WhatsitFunction<ET>>>, ET>,
281 immediate: fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<(), ET>,
282 the: Option<fn(&mut EngineReferences<ET>, ET::Token) -> TeXResult<Vec<ET::Token>, ET>>,
283 },
284 Relax,
286}
287impl<ET: EngineTypes> PrimitiveCommand<ET> {
288 pub fn the<F: FnMut(&mut EngineAux<ET>, &ET::State, &mut ET::Gullet, ET::Token)>(
292 &self,
293 engine: &mut EngineReferences<ET>,
294 token: ET::Token,
295 name: PrimitiveIdentifier,
296 mut cont: F,
297 ) -> TeXResult<(), ET> {
298 use crate::tex::tokens::token_lists::Otherize;
299 use std::fmt::Write;
300 match self {
301 Self::Int { read, .. } => {
302 let val = read(engine, token)?;
303 write!(
304 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
305 "{val}"
306 )?;
307 }
308 Self::Dim { read, .. } => {
309 let val = read(engine, token)?;
310 write!(
311 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
312 "{val}"
313 )?;
314 }
315 Self::Skip { read, .. } => {
316 let val = read(engine, token)?;
317 write!(
318 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
319 "{val}"
320 )?;
321 }
322 Self::MuSkip { read, .. } => {
323 let val = read(engine, token)?;
324 write!(
325 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
326 "{val}"
327 )?;
328 }
329 Self::PrimitiveInt => {
330 let val = engine.state.get_primitive_int(name);
331 write!(
332 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
333 "{val}"
334 )?;
335 }
336 Self::PrimitiveDim => {
337 let val = engine.state.get_primitive_dim(name);
338 write!(
339 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
340 "{val}"
341 )?;
342 }
343 Self::PrimitiveSkip => {
344 let val = engine.state.get_primitive_skip(name);
345 write!(
346 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
347 "{val}"
348 )?;
349 }
350 Self::PrimitiveMuSkip => {
351 let val = engine.state.get_primitive_muskip(name);
352 write!(
353 Otherize::new(&mut |t| cont(engine.aux, engine.state, engine.gullet, t)),
354 "{val}"
355 )?;
356 }
357 Self::PrimitiveToks => {
358 for t in &engine.state.get_primitive_tokens(name).0 {
359 cont(engine.aux, engine.state, engine.gullet, t.clone());
360 }
361 }
362 Self::FontCmd { read, .. } => {
363 let fnt = read(engine, token)?;
364 let t = fnt.name();
365 cont(
366 engine.aux,
367 engine.state,
368 engine.gullet,
369 ET::Token::from_cs(t.clone()),
370 );
371 }
372 Self::Whatsit { the: Some(the), .. } => {
373 for t in the(engine, token)? {
374 cont(engine.aux, engine.state, engine.gullet, t);
375 }
376 }
377 _ if name == PRIMITIVES.toks => {
378 let u = engine.read_register_index(false, &token)?;
379 for t in &engine.state.get_toks_register(u).0 {
380 cont(engine.aux, engine.state, engine.gullet, t.clone());
381 }
382 }
383 _ => engine.general_error(format!(
384 "You can't use {} after \\the",
385 name.display(engine.state.get_escape_char())
386 ))?,
387 }
388 Ok(())
389 }
390}
391
392pub struct Meaning<'a, ET: EngineTypes> {
394 cmd: &'a TeXCommand<ET>,
395 int: &'a <<ET::Token as Token>::CS as CSName<ET::Char>>::Handler,
396 cc: &'a CategoryCodeScheme<ET::Char>,
397 escapechar: Option<ET::Char>,
398}
399impl<ET: EngineTypes> Meaning<'_, ET> {
400 pub fn write_chars<W: CharWrite<ET::Char, ET::CSName>>(&self, f: &mut W) -> std::fmt::Result {
404 match self.cmd {
405 TeXCommand::Macro(m) => m.meaning_char(self.int, self.cc, self.escapechar, f),
406 TeXCommand::Char { char, code } => code.meaning(*char, f),
407 TeXCommand::CharDef(c) => {
408 if let Some(e) = self.escapechar {
409 f.push_char(e);
410 }
411 write!(f, "char\"{:X}", Into::<u64>::into(*c))
412 }
413 TeXCommand::MathChar(u) => {
414 if let Some(e) = self.escapechar {
415 f.push_char(e);
416 }
417 write!(f, "mathchar\"{u:X}")
418 }
419 TeXCommand::Font(i) => {
420 write!(f, "select font ")?;
421 i.display(self.int, f)
422 }
423 TeXCommand::IntRegister(i) => {
424 if let Some(e) = self.escapechar {
425 f.push_char(e);
426 }
427 write!(f, "count{i}")
428 }
429 TeXCommand::DimRegister(i) => {
430 if let Some(e) = self.escapechar {
431 f.push_char(e);
432 }
433 write!(f, "dimen{i}")
434 }
435 TeXCommand::SkipRegister(i) => {
436 if let Some(e) = self.escapechar {
437 f.push_char(e);
438 }
439 write!(f, "skip{i}")
440 }
441 TeXCommand::MuSkipRegister(i) => {
442 if let Some(e) = self.escapechar {
443 f.push_char(e);
444 }
445 write!(f, "muskip{i}")
446 }
447 TeXCommand::ToksRegister(i) => {
448 if let Some(e) = self.escapechar {
449 f.push_char(e);
450 }
451 write!(f, "toks{i}")
452 }
453 TeXCommand::Primitive { name, .. } => {
454 write!(f, "{}", name.display(self.escapechar))
455 }
456 }
457 }
458}
459impl<ET: EngineTypes> Display for Meaning<'_, ET> {
460 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
461 self.write_chars(&mut StringCharWrite::new(f))
462 }
463}
464
465#[derive(Clone, Debug)]
467pub struct MacroSignature<T: Token> {
468 pub arity: u8,
470 pub params: TokenList<T>,
472}
473
474#[derive(Clone, Debug)]
476pub struct Macro<T: Token> {
477 pub protected: bool,
479 pub long: bool,
481 pub outer: bool,
483 pub expansion: TokenList<T>,
485 pub signature: MacroSignature<T>,
487}
488impl<T: Token> Macro<T> {
489 pub fn new<Sig: AsRef<str>, Exp: AsRef<str>, ET: EngineTypes<Token = T, Char = T::Char>>(
494 int: &mut <T::CS as CSName<T::Char>>::Handler,
495 cc: &CategoryCodeScheme<T::Char>,
496 sig: Sig,
497 exp: Exp,
498 ) -> TeXResult<Self, ET> {
499 let mut parser = MacroParser::new();
500 let sig = sig.as_ref();
501 if !sig.is_empty() {
502 let sigsrc: StringLineSource<T::Char> = sig.into();
503 let mut sigsrc = InputTokenizer::new(sigsrc);
504 let par = int.par();
505 while let Some(t) = sigsrc.get_next(int, cc, None, &par)? {
506 parser.do_signature_token::<ET>(t)?;
507 }
508 }
509 let exp = exp.as_ref();
510 let expsrc: StringLineSource<T::Char> = exp.into();
511 let mut expsrc = InputTokenizer::new(expsrc);
512 let par = int.par();
513 while let Some(t) = expsrc.get_next(int, cc, None, &par)? {
514 parser.do_expansion_token::<ET>(t)?;
515 }
516 Ok(parser.close(false, false, false))
517 }
518
519 pub fn meaning<'a>(
521 &'a self,
522 int: &'a <T::CS as CSName<T::Char>>::Handler,
523 cc: &'a CategoryCodeScheme<T::Char>,
524 escapechar: Option<T::Char>,
525 ) -> impl Display + 'a {
526 MacroMeaning {
527 cmd: self,
528 int,
529 cc,
530 escapechar,
531 }
532 }
533 pub fn meaning_char<F: CharWrite<T::Char, T::CS>>(
537 &self,
538 int: &<T::CS as CSName<T::Char>>::Handler,
539 cc: &CategoryCodeScheme<T::Char>,
540 escapechar: Option<T::Char>,
541 f: &mut F,
542 ) -> std::fmt::Result {
543 if self.protected {
544 if let Some(e) = escapechar {
545 f.push_char(e);
546 }
547 write!(f, "protected ")?;
548 }
549 if self.long {
550 if let Some(e) = escapechar {
551 f.push_char(e);
552 }
553 write!(f, "long ")?;
554 }
555 if self.outer {
556 if let Some(e) = escapechar {
557 f.push_char(e);
558 }
559 write!(f, "outer ")?;
560 }
561 write!(f, "macro:")?;
562 self.signature
563 .params
564 .display(int, cc, escapechar, false)
565 .fmt_cw(f)?;
566 write!(f, "->")?;
567 self.expansion.display(int, cc, escapechar, true).fmt_cw(f)
568 }
569}
570
571struct MacroMeaning<'a, T: Token> {
572 cmd: &'a Macro<T>,
573 int: &'a <T::CS as CSName<T::Char>>::Handler,
574 cc: &'a CategoryCodeScheme<T::Char>,
575 escapechar: Option<T::Char>,
576}
577impl<T: Token> Display for MacroMeaning<'_, T> {
578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
579 self.cmd.meaning_char(
580 self.int,
581 self.cc,
582 self.escapechar,
583 &mut StringCharWrite::new(f),
584 )
585 }
586}
587
588#[derive(Clone, Debug, Copy)]
590pub enum CommandScope {
591 SwitchesToVertical,
595 SwitchesToHorizontal,
598 MathOnly,
601 SwitchesToHorizontalOrMath,
604 Any,
606}