1use crate::commands::{CommandScope, PrimitiveCommand, TeXCommand};
3use crate::engine::state::State;
4use crate::engine::{EngineReferences, EngineTypes, TeXEngine};
5use crate::prelude::Character;
6use crate::tex::nodes::boxes::{BoxInfo, TeXBox};
7use crate::tex::numerics::{MuSkip, Skip};
8use crate::utils::HMap;
9use either::Either;
10use lazy_static::lazy_static;
11use std::sync::RwLock;
12
13macro_rules! cmtodos {
14 ($engine:ident,$($name:ident),*) => {
15 $(cmtodo!($engine,$name);)*
16 };
17}
18
19macro_rules! cmstodos {
20 ($engine:ident,$($name:ident),*) => {
21 $(cmstodo!($engine,$name);)*
22 };
23}
24
25macro_rules! cmtodo {
26 ($engine:ident,$name:ident) => {{
27 let command = $crate::commands::PrimitiveCommand::SimpleExpandable(|e, _| {
28 e.general_error(format!(
29 "Not yet implemented: \\{} at {}",
30 stringify!($name),
31 crate::engine::mouth::Mouth::current_sourceref(e.mouth).display(e.filesystem)
32 ))
33 });
34 let refs = $engine.get_engine_refs();
35 refs.state
36 .register_primitive(refs.aux, stringify!($name), command);
37 }};
38}
39
40macro_rules! cmstodo {
41 ($engine:ident,$name:ident) => {{
42 let command = $crate::commands::PrimitiveCommand::Unexpandable {
43 scope: $crate::commands::CommandScope::Any,
44 apply: |e, _| {
45 e.general_error(format!(
46 "Not yet implemented: \\{} at {}",
47 stringify!($name),
48 $crate::engine::mouth::Mouth::current_sourceref(e.mouth).display(e.filesystem)
49 ))
50 },
51 };
52 let refs = $engine.get_engine_refs();
53 refs.state
54 .register_primitive(refs.aux, stringify!($name), command);
55 }};
56}
57
58use crate::tex::nodes::WhatsitFunction;
59use crate::utils::errors::TeXResult;
60pub(crate) use cmstodo;
61pub(crate) use cmstodos;
62pub(crate) use cmtodo;
63pub(crate) use cmtodos;
64
65pub fn register_expandable<E: TeXEngine>(
67 engine: &mut E,
68 name: &'static str,
69 f: fn(
70 &mut EngineReferences<E::Types>,
71 &mut Vec<<E::Types as EngineTypes>::Token>,
72 <E::Types as EngineTypes>::Token,
73 ) -> TeXResult<(), E::Types>,
74) {
75 let command = PrimitiveCommand::Expandable(f);
76 let refs = engine.get_engine_refs();
77 refs.state.register_primitive(refs.aux, name, command);
78}
79
80pub fn register_simple_expandable<E: TeXEngine>(
82 engine: &mut E,
83 name: &'static str,
84 f: fn(
85 &mut EngineReferences<E::Types>,
86 <E::Types as EngineTypes>::Token,
87 ) -> TeXResult<(), E::Types>,
88) {
89 let command = PrimitiveCommand::SimpleExpandable(f);
90 let refs = engine.get_engine_refs();
91 refs.state.register_primitive(refs.aux, name, command);
92}
93
94pub fn register_conditional<E: TeXEngine>(
96 engine: &mut E,
97 name: &'static str,
98 f: fn(
99 &mut EngineReferences<E::Types>,
100 <E::Types as EngineTypes>::Token,
101 ) -> TeXResult<bool, E::Types>,
102) {
103 let command = PrimitiveCommand::Conditional(f);
104 let refs = engine.get_engine_refs();
105 refs.state.register_primitive(refs.aux, name, command);
106}
107
108pub fn register_unexpandable<E: TeXEngine>(
110 engine: &mut E,
111 name: &'static str,
112 scope: CommandScope,
113 f: fn(
114 &mut EngineReferences<E::Types>,
115 <E::Types as EngineTypes>::Token,
116 ) -> TeXResult<(), E::Types>,
117) {
118 let command = PrimitiveCommand::Unexpandable { scope, apply: f };
119 let refs = engine.get_engine_refs();
120 refs.state.register_primitive(refs.aux, name, command)
121}
122
123pub fn register_primitive_int<E: TeXEngine>(engine: &mut E, names: &[&'static str]) {
125 let refs = engine.get_engine_refs();
126 for name in names {
127 refs.state
128 .register_primitive(refs.aux, name, PrimitiveCommand::PrimitiveInt);
129 }
130}
131
132pub fn register_int<E: TeXEngine>(
135 engine: &mut E,
136 name: &'static str,
137 read: fn(
138 &mut EngineReferences<E::Types>,
139 <E::Types as EngineTypes>::Token,
140 ) -> TeXResult<<E::Types as EngineTypes>::Int, E::Types>,
141 assign: Option<
142 for<'a, 'b> fn(
143 &'a mut EngineReferences<'b, E::Types>,
144 <E::Types as EngineTypes>::Token,
145 bool,
146 ) -> TeXResult<(), E::Types>,
147 >,
148) {
149 let refs = engine.get_engine_refs();
150 let command = PrimitiveCommand::Int { read, assign };
151 refs.state.register_primitive(refs.aux, name, command);
152}
153
154pub fn register_dim<E: TeXEngine>(
157 engine: &mut E,
158 name: &'static str,
159 read: fn(
160 &mut EngineReferences<E::Types>,
161 <E::Types as EngineTypes>::Token,
162 ) -> TeXResult<<E::Types as EngineTypes>::Dim, E::Types>,
163 assign: Option<
164 for<'a, 'b> fn(
165 &'a mut EngineReferences<'b, E::Types>,
166 <E::Types as EngineTypes>::Token,
167 bool,
168 ) -> TeXResult<(), E::Types>,
169 >,
170) {
171 let refs = engine.get_engine_refs();
172 let command = PrimitiveCommand::Dim { read, assign };
173 refs.state.register_primitive(refs.aux, name, command);
174}
175
176pub fn register_skip<E: TeXEngine>(
179 engine: &mut E,
180 name: &'static str,
181 read: fn(
182 &mut EngineReferences<E::Types>,
183 <E::Types as EngineTypes>::Token,
184 ) -> TeXResult<Skip<<E::Types as EngineTypes>::Dim>, E::Types>,
185 assign: Option<
186 for<'a, 'b> fn(
187 &'a mut EngineReferences<'b, E::Types>,
188 <E::Types as EngineTypes>::Token,
189 bool,
190 ) -> TeXResult<(), E::Types>,
191 >,
192) {
193 let refs = engine.get_engine_refs();
194 let command = PrimitiveCommand::Skip { read, assign };
195 refs.state.register_primitive(refs.aux, name, command);
196}
197
198pub fn register_muskip<E: TeXEngine>(
201 engine: &mut E,
202 name: &'static str,
203 read: fn(
204 &mut EngineReferences<E::Types>,
205 <E::Types as EngineTypes>::Token,
206 ) -> TeXResult<MuSkip<<E::Types as EngineTypes>::MuDim>, E::Types>,
207 assign: Option<
208 for<'a, 'b> fn(
209 &'a mut EngineReferences<'b, E::Types>,
210 <E::Types as EngineTypes>::Token,
211 bool,
212 ) -> TeXResult<(), E::Types>,
213 >,
214) {
215 let refs = engine.get_engine_refs();
216 let command = PrimitiveCommand::MuSkip { read, assign };
217 refs.state.register_primitive(refs.aux, name, command);
218}
219
220pub fn register_font<E: TeXEngine>(
223 engine: &mut E,
224 name: &'static str,
225 read: fn(
226 &mut EngineReferences<E::Types>,
227 <E::Types as EngineTypes>::Token,
228 ) -> TeXResult<<E::Types as EngineTypes>::Font, E::Types>,
229 assign: Option<
230 for<'a, 'b> fn(
231 &'a mut EngineReferences<'b, E::Types>,
232 <E::Types as EngineTypes>::Token,
233 bool,
234 ) -> TeXResult<(), E::Types>,
235 >,
236) {
237 let refs = engine.get_engine_refs();
238 let command = PrimitiveCommand::FontCmd { read, assign };
239 refs.state.register_primitive(refs.aux, name, command);
240}
241
242pub fn register_box<E: TeXEngine>(
245 engine: &mut E,
246 name: &'static str,
247 read: fn(
248 &mut EngineReferences<E::Types>,
249 <E::Types as EngineTypes>::Token,
250 ) -> TeXResult<Either<Option<TeXBox<E::Types>>, BoxInfo<E::Types>>, E::Types>,
251) {
252 let refs = engine.get_engine_refs();
253 let command = PrimitiveCommand::Box(read);
254 refs.state.register_primitive(refs.aux, name, command);
255}
256
257pub fn register_assignment<E: TeXEngine>(
259 engine: &mut E,
260 name: &'static str,
261 assign: for<'a, 'b> fn(
262 &'a mut EngineReferences<'b, E::Types>,
263 <E::Types as EngineTypes>::Token,
264 bool,
265 ) -> TeXResult<(), E::Types>,
266) {
267 let refs = engine.get_engine_refs();
268 let command = PrimitiveCommand::Assignment(assign);
269 refs.state.register_primitive(refs.aux, name, command);
270}
271
272pub fn register_primitive_dim<E: TeXEngine>(engine: &mut E, names: &[&'static str]) {
274 let refs = engine.get_engine_refs();
275 for name in names {
276 refs.state
277 .register_primitive(refs.aux, name, PrimitiveCommand::PrimitiveDim);
278 }
279}
280
281pub fn register_primitive_skip<E: TeXEngine>(engine: &mut E, names: &[&'static str]) {
283 let refs = engine.get_engine_refs();
284 for name in names {
285 refs.state
286 .register_primitive(refs.aux, name, PrimitiveCommand::PrimitiveSkip);
287 }
288}
289
290pub fn register_primitive_muskip<E: TeXEngine>(engine: &mut E, names: &[&'static str]) {
292 let refs = engine.get_engine_refs();
293 for name in names {
294 refs.state
295 .register_primitive(refs.aux, name, PrimitiveCommand::PrimitiveMuSkip);
296 }
297}
298
299pub fn register_primitive_toks<E: TeXEngine>(engine: &mut E, names: &[&'static str]) {
301 let refs = engine.get_engine_refs();
302 for name in names {
303 refs.state
304 .register_primitive(refs.aux, name, PrimitiveCommand::PrimitiveToks);
305 }
306}
307
308pub fn register_whatsit<E: TeXEngine>(
310 engine: &mut E,
311 name: &'static str,
312 get: fn(
313 &mut EngineReferences<E::Types>,
314 <E::Types as EngineTypes>::Token,
315 ) -> TeXResult<Option<Box<WhatsitFunction<E::Types>>>, E::Types>,
316 immediate: fn(
317 &mut EngineReferences<E::Types>,
318 <E::Types as EngineTypes>::Token,
319 ) -> TeXResult<(), E::Types>,
320 the: Option<
321 fn(
322 &mut EngineReferences<E::Types>,
323 <E::Types as EngineTypes>::Token,
324 ) -> TeXResult<Vec<<E::Types as EngineTypes>::Token>, E::Types>,
325 >,
326) {
327 let command = PrimitiveCommand::Whatsit {
328 get,
329 immediate,
330 the,
331 };
332 let refs = engine.get_engine_refs();
333 refs.state.register_primitive(refs.aux, name, command);
334}
335
336#[derive(Clone)]
338pub struct PrimitiveCommands<ET: EngineTypes> {
339 commands: Vec<TeXCommand<ET>>,
340 names: HMap<&'static str, u16>,
341}
342impl<ET: EngineTypes> Default for PrimitiveCommands<ET> {
343 fn default() -> Self {
344 Self {
345 commands: Vec::new(),
346 names: HMap::default(),
347 }
348 }
349}
350impl<ET: EngineTypes> PrimitiveCommands<ET> {
351 pub fn register(
353 &mut self,
354 name: &'static str,
355 cmd: PrimitiveCommand<ET>,
356 ) -> PrimitiveIdentifier {
357 let id = PRIMITIVES.new_id(name);
358 let idx = id.as_u16() as usize;
359 if idx >= self.commands.len() {
360 self.commands.resize(
361 idx + 1,
362 TeXCommand::Primitive {
363 name: id,
364 cmd: PrimitiveCommand::Relax,
365 },
366 );
367 }
368 self.commands[idx] = TeXCommand::Primitive { name: id, cmd };
369 self.names.insert(name, idx as u16);
370 id
371 }
372 pub fn get_id(&self, id: PrimitiveIdentifier) -> Option<&TeXCommand<ET>> {
374 let idx = id.as_u16() as usize;
375 self.commands.get(idx)
376 }
377 pub fn get_name(&self, s: &str) -> Option<PrimitiveIdentifier> {
379 self.names
380 .get(s)
381 .and_then(|&u| PrimitiveIdentifier::try_from_u16(u))
382 }
383}
384
385pub struct PrimitiveInterner {
390 interner: RwLock<
391 string_interner::StringInterner<
392 string_interner::backend::StringBackend<string_interner::symbol::SymbolU16>,
393 rustc_hash::FxBuildHasher,
394 >,
395 >,
396 pub globaldefs: PrimitiveIdentifier,
397 pub relax: PrimitiveIdentifier,
398 pub mag: PrimitiveIdentifier,
399 pub fam: PrimitiveIdentifier,
400 pub ifcase: PrimitiveIdentifier,
401 pub tracingifs: PrimitiveIdentifier,
402 pub tracingassigns: PrimitiveIdentifier,
403 pub tracingcommands: PrimitiveIdentifier,
404 pub tracinggroups: PrimitiveIdentifier,
405 pub tracingrestores: PrimitiveIdentifier,
406 pub r#else: PrimitiveIdentifier,
407 pub fi: PrimitiveIdentifier,
408 pub or: PrimitiveIdentifier,
409 pub global: PrimitiveIdentifier,
410 pub long: PrimitiveIdentifier,
411 pub outer: PrimitiveIdentifier,
412 pub protected: PrimitiveIdentifier,
413 pub def: PrimitiveIdentifier,
414 pub edef: PrimitiveIdentifier,
415 pub xdef: PrimitiveIdentifier,
416 pub gdef: PrimitiveIdentifier,
417 pub everyeof: PrimitiveIdentifier,
418 pub everyhbox: PrimitiveIdentifier,
419 pub everyvbox: PrimitiveIdentifier,
420 pub everyjob: PrimitiveIdentifier,
421 pub count: PrimitiveIdentifier,
422 pub noexpand: PrimitiveIdentifier,
423 pub unexpanded: PrimitiveIdentifier,
424 pub endcsname: PrimitiveIdentifier,
425 pub the: PrimitiveIdentifier,
426 pub toks: PrimitiveIdentifier,
427 pub vsize: PrimitiveIdentifier,
428 pub output: PrimitiveIdentifier,
429 pub badness: PrimitiveIdentifier,
430 pub outputpenalty: PrimitiveIdentifier,
431 pub dimen: PrimitiveIdentifier,
432 pub skip: PrimitiveIdentifier,
433 pub everypar: PrimitiveIdentifier,
434 pub indent: PrimitiveIdentifier,
435 pub noindent: PrimitiveIdentifier,
436 pub hangindent: PrimitiveIdentifier,
437 pub hangafter: PrimitiveIdentifier,
438 pub leftskip: PrimitiveIdentifier,
439 pub rightskip: PrimitiveIdentifier,
440 pub hsize: PrimitiveIdentifier,
441 pub pdfpagewidth: PrimitiveIdentifier,
442 pub everymath: PrimitiveIdentifier,
443 pub everydisplay: PrimitiveIdentifier,
444 pub char: PrimitiveIdentifier,
445 pub tabskip: PrimitiveIdentifier,
446 pub cr: PrimitiveIdentifier,
447 pub crcr: PrimitiveIdentifier,
448 pub everycr: PrimitiveIdentifier,
449 pub span: PrimitiveIdentifier,
450 pub noalign: PrimitiveIdentifier,
451 pub omit: PrimitiveIdentifier,
452 pub baselineskip: PrimitiveIdentifier,
453 pub lineskip: PrimitiveIdentifier,
454 pub lineskiplimit: PrimitiveIdentifier,
455 pub parindent: PrimitiveIdentifier,
456 pub hrule: PrimitiveIdentifier,
457 pub vrule: PrimitiveIdentifier,
458 pub vskip: PrimitiveIdentifier,
459 pub hskip: PrimitiveIdentifier,
460 pub vfil: PrimitiveIdentifier,
461 pub hfil: PrimitiveIdentifier,
462 pub vfill: PrimitiveIdentifier,
463 pub hfill: PrimitiveIdentifier,
464 pub parskip: PrimitiveIdentifier,
465 pub delimiter: PrimitiveIdentifier,
466 pub abovedisplayskip: PrimitiveIdentifier,
467 pub belowdisplayskip: PrimitiveIdentifier,
468 pub iffalse: PrimitiveIdentifier,
469 pub iftrue: PrimitiveIdentifier,
470 pub year: PrimitiveIdentifier,
471 pub month: PrimitiveIdentifier,
472 pub day: PrimitiveIdentifier,
473 pub time: PrimitiveIdentifier,
474 pub mathchar: PrimitiveIdentifier,
475}
476impl PrimitiveInterner {
477 fn new() -> Self {
478 let mut interner = string_interner::StringInterner::<
479 string_interner::backend::StringBackend<string_interner::symbol::SymbolU16>,
480 rustc_hash::FxBuildHasher,
481 >::new();
482 let globaldefs = PrimitiveIdentifier(interner.get_or_intern_static("globaldefs"));
483 let relax = PrimitiveIdentifier(interner.get_or_intern_static("relax"));
484 let mag = PrimitiveIdentifier(interner.get_or_intern_static("mag"));
485 let fam = PrimitiveIdentifier(interner.get_or_intern_static("fam"));
486 let ifcase = PrimitiveIdentifier(interner.get_or_intern_static("ifcase"));
487 let tracingifs = PrimitiveIdentifier(interner.get_or_intern_static("tracingifs"));
488 let tracingassigns = PrimitiveIdentifier(interner.get_or_intern_static("tracingassigns"));
489 let tracingcommands = PrimitiveIdentifier(interner.get_or_intern_static("tracingcommands"));
490 let tracinggroups = PrimitiveIdentifier(interner.get_or_intern_static("tracinggroups"));
491 let tracingrestores = PrimitiveIdentifier(interner.get_or_intern_static("tracingrestores"));
492 let r#else = PrimitiveIdentifier(interner.get_or_intern_static("else"));
493 let fi = PrimitiveIdentifier(interner.get_or_intern_static("fi"));
494 let or = PrimitiveIdentifier(interner.get_or_intern_static("or"));
495 let global = PrimitiveIdentifier(interner.get_or_intern_static("global"));
496 let long = PrimitiveIdentifier(interner.get_or_intern_static("long"));
497 let outer = PrimitiveIdentifier(interner.get_or_intern_static("outer"));
498 let protected = PrimitiveIdentifier(interner.get_or_intern_static("protected"));
499 let def = PrimitiveIdentifier(interner.get_or_intern_static("def"));
500 let edef = PrimitiveIdentifier(interner.get_or_intern_static("edef"));
501 let xdef = PrimitiveIdentifier(interner.get_or_intern_static("xdef"));
502 let gdef = PrimitiveIdentifier(interner.get_or_intern_static("gdef"));
503 let everyeof = PrimitiveIdentifier(interner.get_or_intern_static("everyeof"));
504 let everyhbox = PrimitiveIdentifier(interner.get_or_intern_static("everyhbox"));
505 let everyvbox = PrimitiveIdentifier(interner.get_or_intern_static("everyvbox"));
506 let everyjob = PrimitiveIdentifier(interner.get_or_intern_static("everyjob"));
507 let count = PrimitiveIdentifier(interner.get_or_intern_static("count"));
508 let noexpand = PrimitiveIdentifier(interner.get_or_intern_static("noexpand"));
509 let endcsname = PrimitiveIdentifier(interner.get_or_intern_static("endcsname"));
510 let unexpanded = PrimitiveIdentifier(interner.get_or_intern_static("unexpanded"));
511 let the = PrimitiveIdentifier(interner.get_or_intern_static("the"));
512 let toks = PrimitiveIdentifier(interner.get_or_intern_static("toks"));
513 let vsize = PrimitiveIdentifier(interner.get_or_intern_static("vsize"));
514 let output = PrimitiveIdentifier(interner.get_or_intern_static("output"));
515 let badness = PrimitiveIdentifier(interner.get_or_intern_static("badness"));
516 let outputpenalty = PrimitiveIdentifier(interner.get_or_intern_static("outputpenalty"));
517 let dimen = PrimitiveIdentifier(interner.get_or_intern_static("dimen"));
518 let skip = PrimitiveIdentifier(interner.get_or_intern_static("skip"));
519 let everypar = PrimitiveIdentifier(interner.get_or_intern_static("everypar"));
520 let indent = PrimitiveIdentifier(interner.get_or_intern_static("indent"));
521 let noindent = PrimitiveIdentifier(interner.get_or_intern_static("noindent"));
522 let hangindent = PrimitiveIdentifier(interner.get_or_intern_static("hangindent"));
523 let hangafter = PrimitiveIdentifier(interner.get_or_intern_static("hangafter"));
524 let leftskip = PrimitiveIdentifier(interner.get_or_intern_static("leftskip"));
525 let rightskip = PrimitiveIdentifier(interner.get_or_intern_static("rightskip"));
526 let hsize = PrimitiveIdentifier(interner.get_or_intern_static("hsize"));
527 let pdfpagewidth = PrimitiveIdentifier(interner.get_or_intern_static("pdfpagewidth"));
528 let everymath = PrimitiveIdentifier(interner.get_or_intern_static("everymath"));
529 let everydisplay = PrimitiveIdentifier(interner.get_or_intern_static("everydisplay"));
530 let char = PrimitiveIdentifier(interner.get_or_intern_static("char"));
531 let tabskip = PrimitiveIdentifier(interner.get_or_intern_static("tabskip"));
532 let cr = PrimitiveIdentifier(interner.get_or_intern_static("cr"));
533 let crcr = PrimitiveIdentifier(interner.get_or_intern_static("crcr"));
534 let everycr = PrimitiveIdentifier(interner.get_or_intern_static("everycr"));
535 let span = PrimitiveIdentifier(interner.get_or_intern_static("span"));
536 let noalign = PrimitiveIdentifier(interner.get_or_intern_static("noalign"));
537 let omit = PrimitiveIdentifier(interner.get_or_intern_static("omit"));
538 let baselineskip = PrimitiveIdentifier(interner.get_or_intern_static("baselineskip"));
539 let lineskip = PrimitiveIdentifier(interner.get_or_intern_static("lineskip"));
540 let lineskiplimit = PrimitiveIdentifier(interner.get_or_intern_static("lineskiplimit"));
541 let parindent = PrimitiveIdentifier(interner.get_or_intern_static("parindent"));
542 let hrule = PrimitiveIdentifier(interner.get_or_intern_static("hrule"));
543 let vrule = PrimitiveIdentifier(interner.get_or_intern_static("vrule"));
544 let vskip = PrimitiveIdentifier(interner.get_or_intern_static("vskip"));
545 let hskip = PrimitiveIdentifier(interner.get_or_intern_static("hskip"));
546 let vfil = PrimitiveIdentifier(interner.get_or_intern_static("vfil"));
547 let hfil = PrimitiveIdentifier(interner.get_or_intern_static("hfil"));
548 let vfill = PrimitiveIdentifier(interner.get_or_intern_static("vfill"));
549 let hfill = PrimitiveIdentifier(interner.get_or_intern_static("hfill"));
550 let parskip = PrimitiveIdentifier(interner.get_or_intern_static("parskip"));
551 let delimiter = PrimitiveIdentifier(interner.get_or_intern_static("delimiter"));
552 let abovedisplayskip =
553 PrimitiveIdentifier(interner.get_or_intern_static("abovedisplayskip"));
554 let belowdisplayskip =
555 PrimitiveIdentifier(interner.get_or_intern_static("belowdisplayskip"));
556 let iffalse = PrimitiveIdentifier(interner.get_or_intern_static("iffalse"));
557 let iftrue = PrimitiveIdentifier(interner.get_or_intern_static("iftrue"));
558 let year = PrimitiveIdentifier(interner.get_or_intern_static("year"));
559 let month = PrimitiveIdentifier(interner.get_or_intern_static("month"));
560 let day = PrimitiveIdentifier(interner.get_or_intern_static("day"));
561 let time = PrimitiveIdentifier(interner.get_or_intern_static("time"));
562 let mathchar = PrimitiveIdentifier(interner.get_or_intern_static("mathchar"));
563 PrimitiveInterner {
564 interner: RwLock::new(interner),
565 globaldefs,
566 relax,
567 mag,
568 fam,
569 ifcase,
570 tracingifs,
571 tracingassigns,
572 tracingcommands,
573 tracinggroups,
574 r#else,
575 fi,
576 or,
577 global,
578 long,
579 outer,
580 protected,
581 def,
582 edef,
583 xdef,
584 gdef,
585 everyeof,
586 count,
587 tracingrestores,
588 noexpand,
589 endcsname,
590 unexpanded,
591 the,
592 toks,
593 everyhbox,
594 everyvbox,
595 everyjob,
596 vsize,
597 output,
598 badness,
599 outputpenalty,
600 dimen,
601 skip,
602 everypar,
603 indent,
604 noindent,
605 hangindent,
606 hangafter,
607 leftskip,
608 rightskip,
609 hsize,
610 pdfpagewidth,
611 everymath,
612 everydisplay,
613 char,
614 tabskip,
615 cr,
616 crcr,
617 everycr,
618 span,
619 noalign,
620 omit,
621 baselineskip,
622 lineskip,
623 lineskiplimit,
624 parindent,
625 hrule,
626 vrule,
627 vskip,
628 hskip,
629 vfil,
630 hfil,
631 vfill,
632 hfill,
633 parskip,
634 delimiter,
635 abovedisplayskip,
636 belowdisplayskip,
637 iffalse,
638 iftrue,
639 year,
640 month,
641 day,
642 time,
643 mathchar
644 }
645 }
646
647 fn new_id(&self, s: &'static str) -> PrimitiveIdentifier {
648 let mut lock = self.interner.write().unwrap();
649 PrimitiveIdentifier(lock.get_or_intern_static(s))
650 }
651}
652lazy_static!(
653 pub static ref PRIMITIVES:PrimitiveInterner = PrimitiveInterner::new();
655);
656
657#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
659pub struct PrimitiveIdentifier(string_interner::symbol::SymbolU16);
660impl PrimitiveIdentifier {
661 pub fn display<C: Character>(self, escapechar: Option<C>) -> impl std::fmt::Display {
666 PrintableIdentifier(self, escapechar)
667 }
668 pub fn as_u16(&self) -> u16 {
670 use string_interner::Symbol;
671 self.0.to_usize() as u16
672 }
673 pub fn try_from_u16(u: u16) -> Option<Self> {
675 use string_interner::Symbol;
676 string_interner::symbol::SymbolU16::try_from_usize(u as usize).map(PrimitiveIdentifier)
677 }
678}
679
680struct PrintableIdentifier<C: Character>(PrimitiveIdentifier, Option<C>);
681impl<C: Character> std::fmt::Display for PrintableIdentifier<C> {
682 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
683 let lock = PRIMITIVES.interner.read().unwrap();
684 match self.1 {
685 None => (),
686 Some(c) => c.display_fmt(f),
687 }
688 write!(f, "{}", lock.resolve(self.0 .0).unwrap())
689 }
690}