1use std::{borrow::Cow, fmt, rc::Rc};
2
3use libxml::tree::Node;
4
5use super::argument::ArgWrap;
6use crate::{
7 Digested, Locator,
8 common::{
9 arena::{self, SymHashMap as HashMap, SymStr},
10 dimension::Dimension,
11 error::*,
12 font,
13 glue::Glue,
14 mudimension::MuDimension,
15 muglue::MuGlue,
16 number::Number,
17 numeric_ops::NumericOps,
18 object::Object,
19 },
20 definition::{BeforeDigestClosure, Definition, DigestionClosure},
21 document::Document,
22 gullet,
23 parameter::Parameters,
24 pin, state,
25 state::{Scope, Stored},
26 tbox::Tbox,
27 token::*,
28 tokens::Tokens,
29 whatsit::Whatsit,
30};
31
32#[derive(Clone, PartialEq)]
34pub enum RegisterValue {
35 Number(Number),
37 Dimension(Dimension),
39 MuDimension(MuDimension),
41 Glue(Glue),
43 MuGlue(MuGlue),
45 Token(Token),
47 Tokens(Tokens),
49 Pair(crate::common::pair::Pair),
51}
52impl From<Number> for RegisterValue {
53 fn from(n: Number) -> RegisterValue { RegisterValue::Number(n) }
54}
55impl From<Number> for Option<RegisterValue> {
56 fn from(n: Number) -> Option<RegisterValue> { Some(n.into()) }
57}
58impl From<Dimension> for RegisterValue {
59 fn from(n: Dimension) -> RegisterValue { RegisterValue::Dimension(n) }
60}
61impl From<MuDimension> for RegisterValue {
62 fn from(n: MuDimension) -> RegisterValue { RegisterValue::MuDimension(n) }
63}
64impl From<Glue> for RegisterValue {
65 fn from(n: Glue) -> RegisterValue { RegisterValue::Glue(n) }
66}
67impl From<MuGlue> for RegisterValue {
68 fn from(n: MuGlue) -> RegisterValue { RegisterValue::MuGlue(n) }
69}
70impl From<Token> for RegisterValue {
71 fn from(n: Token) -> RegisterValue { RegisterValue::Token(n) }
72}
73impl From<Tokens> for RegisterValue {
74 fn from(n: Tokens) -> RegisterValue { RegisterValue::Tokens(n) }
75}
76impl From<crate::common::pair::Pair> for RegisterValue {
77 fn from(p: crate::common::pair::Pair) -> RegisterValue { RegisterValue::Pair(p) }
78}
79impl From<&RegisterValue> for RegisterType {
80 fn from(v: &RegisterValue) -> RegisterType {
81 match *v {
82 RegisterValue::Number(_) => RegisterType::Number,
83 RegisterValue::Dimension(_) => RegisterType::Dimension,
84 RegisterValue::MuDimension(_) => RegisterType::MuDimension,
85 RegisterValue::Glue(_) => RegisterType::Glue,
86 RegisterValue::MuGlue(_) => RegisterType::MuGlue,
87 RegisterValue::Token(_) => RegisterType::Token,
88 RegisterValue::Tokens(_) => RegisterType::Tokens,
89 RegisterValue::Pair(_) => RegisterType::Dimension,
90 }
91 }
92}
93
94impl Default for RegisterValue {
95 fn default() -> Self { RegisterValue::Number(Number::new(0)) }
96}
97impl Object for RegisterValue {
98 fn stringify(&self) -> String { s!("RegisterValue[{}]", self) }
99
100 fn revert(&self) -> Result<Tokens> {
101 match self {
102 RegisterValue::Number(value) => Ok(Tokens::new(ExplodeText!(value))),
104 RegisterValue::Dimension(value) => Ok(Tokens::new(ExplodeText!(value))),
105 RegisterValue::MuDimension(value) => Ok(Tokens::new(ExplodeText!(value))),
106 RegisterValue::Glue(value) => Ok(Tokens::new(ExplodeText!(value))),
107 RegisterValue::MuGlue(value) => Ok(Tokens::new(ExplodeText!(value))),
108 RegisterValue::Token(value) => Ok(Tokens!(value.revert())),
109 RegisterValue::Tokens(value) => Ok(Tokens::new(value.clone().revert())), RegisterValue::Pair(value) => value.revert(),
111 }
112 }
113}
114
115impl RegisterValue {
116 pub fn coerce_to(self, rtype: RegisterType) -> RegisterValue {
127 let cur = self.register_type();
128 if cur == rtype {
129 return self;
130 }
131 let numeric = matches!(
132 cur,
133 RegisterType::Number
134 | RegisterType::Dimension
135 | RegisterType::MuDimension
136 | RegisterType::Glue
137 | RegisterType::MuGlue
138 );
139 if !numeric {
140 return self;
141 }
142 let raw = self.value_of();
143 match rtype {
144 RegisterType::Number => RegisterValue::Number(Number::new(raw)),
145 RegisterType::Dimension => RegisterValue::Dimension(Dimension::new(raw)),
146 RegisterType::MuDimension => RegisterValue::MuDimension(MuDimension::new(raw)),
147 RegisterType::Glue => RegisterValue::Glue(Glue::new(raw)),
148 RegisterType::MuGlue => RegisterValue::MuGlue(MuGlue::new(raw)),
149 _ => RegisterValue::Number(Number::new(raw)),
152 }
153 }
154}
155
156impl NumericOps for RegisterValue {
157 fn new(number: i64) -> Self { RegisterValue::Number(Number::new(number)) }
158 fn new_f64(number: f64) -> Self { RegisterValue::Number(Number::new_f64(number)) }
159 fn value_of(self) -> i64 {
160 match self {
161 RegisterValue::Number(v) => v.value_of(),
162 RegisterValue::Dimension(v) => v.value_of(),
163 RegisterValue::MuDimension(v) => v.value_of(),
164 RegisterValue::Glue(v) => v.value_of(),
165 RegisterValue::MuGlue(v) => v.value_of(),
166 RegisterValue::Token(v) => {
167 let message = s!(".value_of called on Token {:?}", v);
168 Warn!("register", "value_of", message);
169 -1
170 },
171 RegisterValue::Tokens(v) => {
172 let message = s!(".value_of called on Tokens {:?}", v);
173 Warn!("register", "value_of", message);
174 -1
175 },
176 RegisterValue::Pair(_) => 0,
177 }
178 }
179 fn register_type(&self) -> RegisterType {
180 match self {
181 RegisterValue::Number(_) => RegisterType::Number,
182 RegisterValue::Dimension(_) => RegisterType::Dimension,
183 RegisterValue::MuDimension(_) => RegisterType::MuDimension,
184 RegisterValue::Glue(_) => RegisterType::Glue,
185 RegisterValue::MuGlue(_) => RegisterType::MuGlue,
186 RegisterValue::Token(_) => RegisterType::Token,
187 RegisterValue::Tokens(_) => RegisterType::Tokens,
188 RegisterValue::Pair(_) => RegisterType::Dimension,
189 }
190 }
191 fn add<T: NumericOps>(self, other: T) -> Self {
192 match self {
193 RegisterValue::Number(v) => RegisterValue::Number(v.add(other)),
194 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.add(other)),
195 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.add(other)),
196 RegisterValue::Glue(v) => RegisterValue::Glue(v.add(other)),
197 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.add(other)),
198 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
199 }
200 }
201 fn subtract<T: NumericOps>(self, other: T) -> Self {
202 match self {
203 RegisterValue::Number(v) => RegisterValue::Number(v.subtract(other)),
204 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.subtract(other)),
205 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.subtract(other)),
206 RegisterValue::Glue(v) => RegisterValue::Glue(v.subtract(other)),
207 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.subtract(other)),
208 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
209 }
210 }
211 fn multiply<T: NumericOps>(self, other: T) -> Self {
212 match self {
213 RegisterValue::Number(v) => RegisterValue::Number(v.multiply(other)),
214 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.multiply(other)),
215 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.multiply(other)),
216 RegisterValue::Glue(v) => RegisterValue::Glue(v.multiply(other)),
217 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.multiply(other)),
218 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
219 }
220 }
221 fn negate(self) -> Self {
222 match self {
223 RegisterValue::Number(v) => RegisterValue::Number(v.negate()),
224 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.negate()),
225 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.negate()),
226 RegisterValue::Glue(v) => RegisterValue::Glue(v.negate()),
227 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.negate()),
228 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
229 }
230 }
231 fn divide<T: NumericOps>(self, other: T) -> Self
232 where Self: Sized {
233 match self {
234 RegisterValue::Number(v) => RegisterValue::Number(v.divide(other)),
235 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.divide(other)),
236 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.divide(other)),
237 RegisterValue::Glue(v) => RegisterValue::Glue(v.divide(other)),
238 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.divide(other)),
239 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
240 }
241 }
242 fn smaller<T: NumericOps>(self, other: T) -> Self
243 where Self: Sized {
244 match self {
245 RegisterValue::Number(v) => RegisterValue::Number(v.smaller(other)),
246 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.smaller(other)),
247 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.smaller(other)),
248 RegisterValue::Glue(v) => RegisterValue::Glue(v.smaller(other)),
249 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.smaller(other)),
250 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
251 }
252 }
253 fn larger<T: NumericOps>(self, other: T) -> Self
254 where Self: Sized {
255 match self {
256 RegisterValue::Number(v) => RegisterValue::Number(v.larger(other)),
257 RegisterValue::Dimension(v) => RegisterValue::Dimension(v.larger(other)),
258 RegisterValue::MuDimension(v) => RegisterValue::MuDimension(v.larger(other)),
259 RegisterValue::Glue(v) => RegisterValue::Glue(v.larger(other)),
260 RegisterValue::MuGlue(v) => RegisterValue::MuGlue(v.larger(other)),
261 RegisterValue::Token(_) | RegisterValue::Tokens(_) | RegisterValue::Pair(_) => self,
262 }
263 }
264 fn into_glue_type(self) -> Glue {
267 match self {
268 RegisterValue::Glue(v) => v,
269 _ => Glue::default(), }
271 }
272 fn to_attribute(&self) -> String
273 where Self: fmt::Display {
274 match self {
275 RegisterValue::Number(v) => v.to_attribute(),
276 RegisterValue::Dimension(v) => v.to_attribute(),
277 RegisterValue::MuDimension(v) => v.to_attribute(),
278 RegisterValue::Glue(v) => v.to_attribute(),
279 RegisterValue::MuGlue(v) => v.to_attribute(),
280 other => other.to_string(),
282 }
283 }
284}
285
286impl From<&RegisterValue> for Number {
287 fn from(v: &RegisterValue) -> Number {
288 match v {
289 RegisterValue::Number(n) => *n,
290 RegisterValue::Dimension(other) => Number::new(other.value_of()),
291 RegisterValue::MuDimension(other) => Number::new(other.value_of()),
292 RegisterValue::Glue(other) => Number::new(other.value_of()),
293 RegisterValue::MuGlue(other) => Number::new(other.value_of()),
294 RegisterValue::Token(other) => other.to_number(),
295 RegisterValue::Tokens(other) => other.to_number(),
296 RegisterValue::Pair(_) => Number::new(0),
297 }
298 }
299}
300impl From<RegisterValue> for Number {
301 fn from(v: RegisterValue) -> Number { (&v).into() }
302}
303impl From<RegisterValue> for Dimension {
304 fn from(v: RegisterValue) -> Dimension { (&v).into() }
305}
306impl From<RegisterValue> for Glue {
307 fn from(v: RegisterValue) -> Glue { (&v).into() }
308}
309impl From<RegisterValue> for MuGlue {
310 fn from(v: RegisterValue) -> MuGlue { (&v).into() }
311}
312impl From<RegisterValue> for f64 {
313 fn from(v: RegisterValue) -> f64 { v.value_of() as f64 }
314}
315impl From<RegisterValue> for i64 {
316 fn from(v: RegisterValue) -> i64 { v.value_of() }
317}
318
319impl From<Number> for Dimension {
320 fn from(n: Number) -> Dimension { Dimension::new(n.value_of()) }
321}
322impl From<Number> for Glue {
323 fn from(n: Number) -> Glue { Glue::new(n.value_of()) }
324}
325impl From<Number> for MuGlue {
326 fn from(n: Number) -> MuGlue { MuGlue::new(n.value_of()) }
327}
328
329impl From<RegisterValue> for Tokens {
332 fn from(v: RegisterValue) -> Tokens {
333 match v {
334 RegisterValue::Tokens(tks) => tks,
335 RegisterValue::Token(t) => Tokens!(t),
336 _ => Tokens!(T_OTHER!(v.value_of().to_string())),
337 }
338 }
339}
340
341impl From<&RegisterValue> for Dimension {
342 fn from(v: &RegisterValue) -> Dimension {
343 match v {
344 RegisterValue::Dimension(n) => *n,
345 RegisterValue::MuDimension(other) => Dimension::new(other.value_of()),
346 RegisterValue::Number(other) => Dimension::new(other.value_of()),
347 RegisterValue::Glue(other) => Dimension::new(other.value_of()),
348 RegisterValue::MuGlue(other) => Dimension::new(other.value_of()),
349 RegisterValue::Token(other) => other.to_number().into(),
350 RegisterValue::Tokens(other) => {
351 let message = s!(
352 "Token register can not be cast into a dimension: {:?}",
353 other
354 );
355 let err = || {
358 Error!("expected", "dimension", message);
359 Ok(())
360 };
361 err().ok();
362 Dimension::new(0)
363 },
364 RegisterValue::Pair(_) => Dimension::new(0),
365 }
366 }
367}
368impl From<&RegisterValue> for Glue {
369 fn from(v: &RegisterValue) -> Glue {
370 match v {
371 RegisterValue::Glue(n) => *n,
372 RegisterValue::Number(other) => Glue::new(other.value_of()),
373 RegisterValue::Dimension(other) => Glue::new(other.value_of()),
374 RegisterValue::MuDimension(other) => Glue::new(other.value_of()),
375 RegisterValue::MuGlue(other) => Glue::new(other.value_of()),
376 RegisterValue::Token(other) => other.to_number().into(),
377 RegisterValue::Tokens(other) => {
378 let message = s!("Token register can not be cast into a Glue: {other:?}");
379 let err = || {
382 Error!("expected", "dimension", message);
383 Ok(())
384 };
385 err().ok();
386 Glue::new(0)
387 },
388 RegisterValue::Pair(_) => Glue::new(0),
389 }
390 }
391}
392
393impl From<&RegisterValue> for MuGlue {
394 fn from(v: &RegisterValue) -> MuGlue {
395 match v {
396 RegisterValue::MuGlue(n) => *n,
397 RegisterValue::Number(other) => MuGlue::new(other.value_of()),
398 RegisterValue::Dimension(other) => MuGlue::new(other.value_of()),
399 RegisterValue::MuDimension(other) => MuGlue::new(other.value_of()),
400 RegisterValue::Glue(other) => MuGlue {
401 skip: other.skip,
402 plus: other.plus,
403 pfill: other.pfill,
404 minus: other.minus,
405 mfill: other.mfill,
406 },
407 RegisterValue::Token(other) => other.to_number().into(),
408 RegisterValue::Tokens(other) => {
409 let message = s!("Token register can not be cast into a Glue: {:?}", other);
410 let err = || {
411 Error!("expected", "dimension", message);
412 Ok(())
413 };
414 err().ok();
415 MuGlue::new(0)
416 },
417 RegisterValue::Pair(_) => MuGlue::new(0),
418 }
419 }
420}
421
422impl fmt::Debug for RegisterValue {
424 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
425 match self {
426 RegisterValue::Number(n) => write!(f, "{n:?}"),
427 RegisterValue::Dimension(d) => write!(f, "{d:?}"),
428 RegisterValue::MuDimension(d) => write!(f, "{d:?}"),
429 RegisterValue::Glue(g) => write!(f, "{g:?}"),
430 RegisterValue::MuGlue(g) => write!(f, "{g:?}"),
431 RegisterValue::Tokens(t) => write!(f, "{t:?}"),
432 RegisterValue::Token(t) => write!(f, "{t:?}"),
433 RegisterValue::Pair(p) => write!(f, "{p:?}"),
434 }
435 }
436}
437
438impl fmt::Display for RegisterValue {
440 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
441 match self {
442 RegisterValue::Number(n) => write!(f, "{n}"),
443 RegisterValue::Dimension(d) => write!(f, "{d}"),
444 RegisterValue::MuDimension(d) => write!(f, "{d}"),
445 RegisterValue::Glue(g) => write!(f, "{g}"),
446 RegisterValue::MuGlue(g) => write!(f, "{g}"),
447 RegisterValue::Tokens(t) => write!(f, "{t}"),
448 RegisterValue::Token(t) => write!(f, "{t}"),
449 RegisterValue::Pair(p) => write!(f, "{p}"),
450 }
451 }
452}
453
454#[derive(Debug, Copy, Clone, Eq)]
456pub enum RegisterType {
457 Number,
459 Dimension,
461 MuDimension,
463 Glue,
465 MuGlue,
467 Token,
469 Tokens,
471 CharDef,
473 Any,
475}
476impl PartialEq for RegisterType {
479 fn eq(&self, other: &Self) -> bool {
480 use RegisterType::*;
481 match self {
482 Number | CharDef => matches!(other, Number | CharDef),
483 Dimension => matches!(other, Dimension),
484 MuDimension => matches!(other, MuDimension),
485 Glue => matches!(other, Glue),
486 MuGlue => matches!(other, MuGlue),
487 Token => matches!(other, Token),
488 Tokens => matches!(other, Tokens),
489 Any => matches!(other, Any),
490 }
491 }
492}
493
494pub type RegisterGetterClosure = Rc<dyn Fn(Vec<ArgWrap>) -> Option<RegisterValue>>;
496pub type RegisterSetterClosure = Rc<dyn Fn(RegisterValue, Option<Scope>, Vec<ArgWrap>)>;
498
499#[derive(Clone)]
501pub struct Register {
502 pub cs: Token,
504 pub address: String,
506 pub parameters: Option<Parameters>,
508 pub register_type: RegisterType,
510 pub readonly: bool,
512 pub value: Option<RegisterValue>,
514 pub getter: Option<RegisterGetterClosure>,
516 pub setter: Option<RegisterSetterClosure>,
518 pub default: Option<RegisterValue>,
520 pub mathglyph: Option<char>,
522 pub role: Option<SymStr>,
524 pub chardef_props: HashMap<Stored>,
526 pub locator: Locator,
528}
529impl Default for Register {
530 fn default() -> Self {
531 Register {
532 cs: T_CS!("Register"),
533 address: String::from("Register"),
534 locator: Locator::default(),
535 parameters: None,
536 register_type: RegisterType::Number,
537 getter: None,
538 setter: None,
539 readonly: false,
540 value: None,
541 mathglyph: None,
542 role: None,
543 chardef_props: HashMap::default(),
544 default: None,
545 }
546 }
547}
548impl PartialEq for Register {
549 fn eq(&self, other: &Register) -> bool {
550 self.register_type == other.register_type
551 && self.parameters == other.parameters
552 && self.value == other.value
553 && self.address == other.address
554 }
555}
556impl fmt::Debug for Register {
557 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
558 write!(
559 f,
560 "Register[cs:{:?}, address:{:?}, parameters:{:?}, type:{:?}, readonly:{:?}, value:{:?}, default:{:?}]",
561 self.cs,
562 self.address,
563 self.parameters,
564 self.register_type,
565 self.readonly,
566 self.value,
567 self.default,
568 )
569 }
570}
571impl fmt::Display for Register {
572 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{self:?}") }
573}
574
575impl Object for Register {
576 fn stringify(&self) -> String { format!("{self:?}") }
577}
578
579impl Definition for Register {
580 fn is_register(&self) -> bool { true }
581 fn is_prefix(&self) -> bool { false }
582 fn is_readonly(&self) -> bool { self.readonly }
583 fn invoke(&self, _once_only: bool) -> Result<Tokens> { Ok(Tokens!()) }
585 fn get_parameters(&self) -> Option<&Parameters> { self.parameters.as_ref() }
586 fn get_cs(&self) -> Cow<'_, Token> { Cow::Owned(self.cs) }
587 fn get_cs_name(&self) -> Cow<'_, str> { Cow::Owned(self.cs.with_cs_name(ToString::to_string)) }
588 fn get_alias(&self) -> Option<&String> { None }
589
590 fn set_value(&self, value: RegisterValue, scope: Option<Scope>, args: Vec<ArgWrap>) {
591 if matches!(self.register_type, RegisterType::CharDef) {
592 let message = self
593 .cs
594 .with_cs_name(|cs_str| s!("Can't assign to chardef {}", cs_str));
595 let err = || {
596 Error!("unexpected", "chardef", message);
597 Ok(())
598 };
599 err().ok();
600 } else if let Some(setter) = &self.setter {
601 setter(value, scope, args);
602 } else {
603 if self.readonly {
605 let message = s!("Can't assign to register {}", self.address);
606 Warn!("unexpected", self.address, message);
607 } else {
608 let loc = if args.is_empty() {
609 Cow::Borrowed(&self.address)
610 } else {
611 let args_string: String = args
616 .into_iter()
617 .map(|a| {
618 a.as_tokens()
619 .ok()
620 .flatten()
621 .map_or_else(String::new, |tks| tks.to_string())
622 })
623 .collect::<Vec<String>>()
624 .join("");
625 Cow::Owned(format!("{}{args_string}", self.address))
626 };
627 state::assign_value(&loc, value, scope);
628 }
629 }
630 }
631 fn invoke_primitive(&self) -> Result<Vec<Digested>> {
634 if matches!(self.register_type, RegisterType::CharDef) {
638 let mut props = HashMap::default();
639 if let Some(role) = self.role {
640 props.insert("role", Stored::String(role));
641 }
642 let in_display = state::lookup_string("IN_MATH_DISPLAY") == "true"
645 || state::lookup_font()
646 .map(|f| f.get_mathstyle().map(|s| s.as_ref()) == Some("display"))
647 .unwrap_or(false);
648 for (k, v) in &self.chardef_props {
649 let key_str = arena::with(*k, |s| s.to_string());
650 match key_str.as_str() {
651 "need_scriptpos" => {
652 if !props.contains_key("scriptpos") {
654 let val = if in_display { "mid" } else { "post" };
655 props.insert("scriptpos", Stored::String(arena::pin_static(val)));
656 }
657 },
658 "need_mathstyle" => {
659 if !props.contains_key("mathstyle") {
661 let val = if in_display { "display" } else { "text" };
662 props.insert("mathstyle", Stored::String(arena::pin_static(val)));
663 }
664 },
665 _ => {
666 props.insert_sym(*k, v.clone());
667 },
668 }
669 }
670 return Ok(vec![Digested::from(
671 if let Some(mathglyph) = self.mathglyph {
672 if !props.contains_key("name") {
674 let cs_name = self.get_cs_name();
675 let n = cs_name.trim_start_matches('\\');
676 let has_matching_meaning = props.get("meaning").is_some_and(|m| {
677 if let Stored::String(s) = m {
678 arena::with(*s, |ms| ms == n)
679 } else {
680 false
681 }
682 });
683 if !has_matching_meaning {
684 props.insert("name", Stored::String(arena::pin(n)));
685 }
686 }
687 Tbox::new(
688 arena::pin_char(mathglyph),
689 None,
690 None,
691 Tokens!(
692 T_CS!("\\mathchar"),
693 self.value.as_ref().unwrap().revert()?,
694 T_CS!("\\relax")
695 ),
696 props,
697 )
698 } else {
699 Tbox::new(
700 font::decode_str(self.value.clone().unwrap().value_of() as u8, None, false)
701 .unwrap_or_else(|| pin!("")),
702 None,
703 None,
704 Tokens!(
705 T_CS!("\\char"),
706 self.value.as_ref().unwrap().revert()?,
707 T_CS!("\\relax")
708 ),
709 props,
710 )
711 },
712 )]);
713 }
714
715 let args = self.read_arguments()?;
718 gullet::read_keyword(&["="])?;
719 let value = gullet::read_value(self.register_type().unwrap())?;
720
721 self.set_value(value, None, args);
722
723 state::after_assignment();
724 Ok(Vec::new())
728 }
729
730 fn before_digest(&self) -> Option<&Vec<BeforeDigestClosure>> { None }
731 fn after_digest(&self) -> Option<&Vec<DigestionClosure>> { None }
732 fn read_arguments(&self) -> Result<Vec<ArgWrap>> {
733 let params = &self.parameters;
734 match params {
735 None => Ok(Vec::new()),
736 Some(params) => params.read_arguments(Some(self)),
737 }
738 }
739
740 fn do_absorption(&self, _document: &mut Document, _whatsit: &Whatsit) -> Result<Vec<Node>> {
741 fatal!(
742 Definition,
743 Unexpected,
744 "do_absorption on Primitive should never be called!"
745 );
746 }
747 fn value_of(&self, args: Vec<ArgWrap>) -> Option<RegisterValue> {
748 if matches!(self.register_type, RegisterType::CharDef) {
749 self.value.clone()
750 } else if let Some(ref getter) = self.getter {
751 getter(args)
752 } else {
753 let key = if args.is_empty() {
754 Cow::Borrowed(&self.address)
755 } else {
756 let args_string: String = args
757 .iter()
758 .map(ToString::to_string)
759 .collect::<Vec<String>>()
760 .join("");
761 Cow::Owned(format!("{}{args_string}", self.address))
762 };
763 state::with_value(&key, |v_opt| match v_opt {
764 Some(v) => v.into(),
765 None => self.default.clone(),
766 })
767 }
768 }
769 fn register_type(&self) -> Option<RegisterType> { Some(self.register_type) }
770}
771
772impl Register {
773 pub fn is_readonly(&self) -> bool { self.readonly }
775 pub fn new_chardef(
780 cs: Token,
781 value: Option<RegisterValue>,
782 mathglyph: Option<char>,
783 role: Option<SymStr>,
784 ) -> Self {
785 Register {
786 cs,
787 parameters: None,
788 value,
789 mathglyph,
790 role,
791 chardef_props: HashMap::default(),
792 register_type: RegisterType::CharDef,
793 readonly: true,
794 locator: gullet::get_locator(),
795 ..Register::default()
796 }
797 }
798
799 pub fn new_math_chardef(
803 cs: Token,
804 value: Option<RegisterValue>,
805 mathglyph: Option<char>,
806 role: Option<SymStr>,
807 props: CharDefProps,
808 ) -> Self {
809 let chardef_props = props.to_hashmap();
810 Register {
811 cs,
812 parameters: None,
813 value,
814 mathglyph,
815 role,
816 chardef_props,
817 register_type: RegisterType::CharDef,
818 readonly: true,
819 locator: gullet::get_locator(),
820 ..Register::default()
821 }
822 }
823
824 pub fn get_address(&self) -> Cow<'_, str> {
825 if self.address.is_empty() {
826 self.get_cs_name()
827 } else {
828 Cow::Borrowed(&self.address)
829 }
830 }
831}
832
833pub struct CharDefProps {
834 pub meaning: Option<SymStr>,
835 pub stretchy: Option<SymStr>,
837 pub scriptpos: Option<SymStr>,
838 pub mathstyle: Option<SymStr>,
839 pub need_scriptpos: bool,
840 pub need_mathstyle: bool,
841}
842impl CharDefProps {
843 fn to_hashmap(&self) -> HashMap<Stored> {
844 let mut chardef_props = HashMap::default();
845 if let Some(m) = self.meaning {
846 chardef_props.insert("meaning", Stored::String(m));
847 }
848 if let Some(s) = self.stretchy {
852 chardef_props.insert("stretchy", Stored::String(s));
853 }
854 if let Some(sp) = self.scriptpos {
855 chardef_props.insert("scriptpos", Stored::String(sp));
856 }
857 if let Some(ms) = self.mathstyle {
858 chardef_props.insert("mathstyle", Stored::String(ms));
859 }
860 if self.need_scriptpos {
861 chardef_props.insert("need_scriptpos", Stored::Bool(true));
862 }
863 if self.need_mathstyle {
864 chardef_props.insert("need_mathstyle", Stored::Bool(true));
865 }
866 chardef_props
867 }
868}
869
870#[cfg(test)]
871mod tests {
872 use super::*;
873
874 #[test]
875 fn register_type_number_and_chardef_equal() {
876 assert_eq!(RegisterType::Number, RegisterType::CharDef);
880 assert_eq!(RegisterType::CharDef, RegisterType::Number);
881 }
882
883 #[test]
884 fn register_type_distinct_between_other_variants() {
885 assert_ne!(RegisterType::Number, RegisterType::Dimension);
886 assert_ne!(RegisterType::Dimension, RegisterType::MuDimension);
887 assert_ne!(RegisterType::Glue, RegisterType::MuGlue);
888 assert_ne!(RegisterType::Token, RegisterType::Tokens);
889 }
890
891 #[test]
892 fn register_type_self_equality() {
893 for rt in [
895 RegisterType::Number,
896 RegisterType::Dimension,
897 RegisterType::MuDimension,
898 RegisterType::Glue,
899 RegisterType::MuGlue,
900 RegisterType::Token,
901 RegisterType::Tokens,
902 ] {
903 assert_eq!(rt, rt.clone(), "{rt:?}");
904 }
905 }
906
907 #[test]
908 fn register_value_from_number() {
909 let n = Number::new(42);
910 let rv: RegisterValue = n.into();
911 match rv {
912 RegisterValue::Number(v) => assert_eq!(v.value_of(), 42),
913 other => panic!("expected Number, got {other:?}"),
914 }
915 }
916
917 #[test]
918 fn register_value_from_dimension() {
919 let d = Dimension::new(65536);
920 let rv: RegisterValue = d.into();
921 match rv {
922 RegisterValue::Dimension(v) => assert_eq!(v.value_of(), 65536),
923 other => panic!("expected Dimension, got {other:?}"),
924 }
925 }
926
927 #[test]
928 fn register_value_from_pair() {
929 use crate::common::{float::Float, pair::Pair};
930 let p = Pair::new(Float(1.0), Float(2.0));
931 let rv: RegisterValue = p.into();
932 match rv {
933 RegisterValue::Pair(_) => {},
934 other => panic!("expected Pair, got {other:?}"),
935 }
936 }
937
938 #[test]
939 fn register_type_from_value() {
940 let n = RegisterValue::Number(Number::new(1));
942 let d = RegisterValue::Dimension(Dimension::new(1));
943 assert_eq!(RegisterType::from(&n), RegisterType::Number);
944 assert_eq!(RegisterType::from(&d), RegisterType::Dimension);
945 }
946
947 #[test]
948 fn register_value_equality() {
949 let a = RegisterValue::Number(Number::new(42));
950 let b = RegisterValue::Number(Number::new(42));
951 let c = RegisterValue::Number(Number::new(43));
952 assert_eq!(a, b);
953 assert_ne!(a, c);
954 }
955}
956
957