1use crate::command;
9use crate::error;
10use crate::parse::OptionalEquals;
11use crate::prelude as txl;
12use crate::token;
13use crate::traits::*;
14use crate::types;
15use crate::vm;
16use std::borrow::Cow;
17use std::collections::HashMap;
18use std::fmt::Debug;
19use std::hash::{Hash, Hasher};
20use texcraft_stdext::collections::groupingmap;
21
22pub type RefFn<S, T> = fn(state: &S, index: Index) -> &T;
28
29pub type MutRefFn<S, T> = fn(state: &mut S, index: Index) -> &mut T;
35
36#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
38pub struct Index(pub usize);
39
40impl From<usize> for Index {
41 fn from(value: usize) -> Self {
42 Index(value)
43 }
44}
45
46pub enum IndexResolver<S> {
52 Static(Index),
59 Dynamic(fn(token::Token, &mut vm::ExpandedStream<S>) -> txl::Result<Index>),
64}
65
66impl<S> IndexResolver<S> {
67 fn resolve(
69 &self,
70 token: token::Token,
71 input: &mut vm::ExpandedStream<S>,
72 ) -> txl::Result<Index> {
73 match self {
74 IndexResolver::Static(addr) => Ok(*addr),
75 IndexResolver::Dynamic(f) => f(token, input),
78 }
79 }
80}
81
82pub struct Command<S> {
101 getters: Getters<S>,
102 index_resolver: Option<IndexResolver<S>>,
103}
104
105impl<S> Command<S> {
106 pub fn new_singleton<T: SupportedType>(
108 ref_fn: RefFn<S, T>,
109 ref_mut_fn: MutRefFn<S, T>,
110 ) -> Command<S> {
111 SupportedType::new_command(ref_fn, ref_mut_fn, None)
112 }
113
114 pub fn new_array<T: SupportedType>(
116 ref_fn: RefFn<S, T>,
117 ref_mut_fn: MutRefFn<S, T>,
118 index_resolver: IndexResolver<S>,
119 ) -> Command<S> {
120 SupportedType::new_command(ref_fn, ref_mut_fn, Some(index_resolver))
121 }
122
123 pub fn new_getter_provider<T: SupportedType>(
133 ref_fn: RefFn<S, T>,
134 ref_mut_fn: MutRefFn<S, T>,
135 ) -> Command<S> {
136 SupportedType::new_command(
137 ref_fn,
138 ref_mut_fn,
139 Some(IndexResolver::Dynamic(|_, _| panic!())),
140 )
141 }
142
143 pub(crate) fn new_array_element(&self, index: Index) -> Self {
145 Self {
146 getters: self.getters.clone(),
147 index_resolver: Some(IndexResolver::Static(index)),
148 }
149 }
150
151 pub fn is_arithmetic(&self) -> bool {
155 match self.getters {
156 Getters::Int(_, _)
157 | Getters::SmallInt(_, _)
158 | Getters::Dimen(_, _)
159 | Getters::Glue(_, _) => true,
160 Getters::CatCode(_, _)
161 | Getters::MathCode(_, _)
162 | Getters::TokenList(_, _)
163 | Getters::Font(_, _) => false,
164 }
165 }
166}
167
168impl<S: TexlangState> Command<S> {
169 pub fn resolve(
171 &self,
172 token: token::Token,
173 input: &mut vm::ExpandedStream<S>,
174 ) -> txl::Result<Variable<S>> {
175 let index = match &self.index_resolver {
176 None => Index(0),
177 Some(index_resolver) => {
178 input
179 .vm_mut()
180 .stack_push(token, error::OperationKind::VariableIndex);
181 let err_or = index_resolver.resolve(token, input);
182 input.vm_mut().stack_pop();
183 err_or?
184 }
185 };
186 Ok(new_variable(&self.getters, index))
187 }
188
189 pub fn resolve_type<T: SupportedType>(
191 &self,
192 token: token::Token,
193 input: &mut vm::ExpandedStream<S>,
194 ) -> txl::Result<Option<TypedVariable<S, T>>> {
195 let Some((ref_fn, ref_mut_fn)) = T::try_cast(self) else {
196 return Ok(None);
197 };
198 let index = match &self.index_resolver {
199 None => Index(0),
200 Some(index_resolver) => index_resolver.resolve(token, input)?,
201 };
202 Ok(Some(TypedVariable(ref_fn, ref_mut_fn, index)))
203 }
204}
205
206impl<S> Command<S> {
207 pub(crate) fn key(&self) -> CommandKey {
208 let getters_key = self.getters.key();
209 match &self.index_resolver {
210 None => CommandKey::Singleton(getters_key),
211 Some(index_resolver) => match index_resolver {
212 IndexResolver::Static(a) => CommandKey::ArrayStatic(getters_key, *a),
213 IndexResolver::Dynamic(f) => CommandKey::ArrayDynamic(getters_key, *f as usize),
214 },
215 }
216 }
217}
218
219impl<S: TexlangState> Command<S> {
220 pub fn value<'a>(
222 &self,
223 token: token::Token,
224 input: &'a mut vm::ExpandedStream<S>,
225 ) -> txl::Result<ValueRef<'a>> {
226 Ok(self.resolve(token, input)?.value(input.state()))
227 }
228
229 pub(crate) fn set_value_using_input(
235 &self,
236 token: token::Token,
237 input: &mut vm::ExecutionInput<S>,
238 scope: groupingmap::Scope,
239 ) -> txl::Result<()> {
240 let variable = self.resolve(token, input.as_mut())?;
241 input
242 .vm_mut()
243 .stack_push(token, error::OperationKind::VariableAssignment);
244 let err_or = variable.set_value_using_input(input, scope);
245 input.vm_mut().stack_pop();
246 err_or
247 }
248}
249
250#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
252pub(crate) enum CommandKey {
253 Singleton(GettersKey),
254 ArrayStatic(GettersKey, Index),
255 ArrayDynamic(GettersKey, usize),
256}
257
258impl CommandKey {
259 pub(crate) fn getter_key(&self) -> GettersKey {
260 match self {
261 CommandKey::Singleton(k) => *k,
262 CommandKey::ArrayStatic(k, _) => *k,
263 CommandKey::ArrayDynamic(k, _) => *k,
264 }
265 }
266}
267
268#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
270pub(crate) struct GettersKey(usize, usize);
271
272pub struct TypedVariable<S, T>(RefFn<S, T>, MutRefFn<S, T>, Index);
274
275impl<S, T> Copy for TypedVariable<S, T> {}
276
277impl<S, T> Clone for TypedVariable<S, T> {
278 fn clone(&self) -> Self {
279 *self
280 }
281}
282
283impl<S, T> TypedVariable<S, T> {
284 pub fn get<'a>(&self, state: &'a S) -> &'a T {
286 (self.0)(state, self.2)
287 }
288
289 fn key(&self) -> (usize, usize, Index) {
290 (self.0 as usize, self.1 as usize, self.2)
291 }
292}
293
294impl<S, T> TypedVariable<S, T>
295where
296 S: TexlangState,
297 T: SupportedType,
298{
299 pub fn set(&self, input: &mut vm::ExecutionInput<S>, scope: groupingmap::Scope, value: T) {
308 let r: &mut T = (self.1)(input.state_mut(), self.2);
309 let overwritten_value = std::mem::replace(r, value);
310 if !input.groups().is_empty() {
313 SupportedType::update_save_stack(input, self, scope, overwritten_value);
314 } else {
315 SupportedType::recycle(input, overwritten_value);
316 }
317 }
318}
319impl<S, T> TypedVariable<S, T>
320where
321 S: TexlangState,
322 T: SupportedType,
323{
324 fn set_using_input(
325 &self,
326 input: &mut vm::ExecutionInput<S>,
327 scope: groupingmap::Scope,
328 ) -> txl::Result<()> {
329 let (_, value) = <(OptionalEquals, T)>::parse(input)?;
330 self.set(input, scope, value);
331 Ok(())
332 }
333}
334
335impl<S, T> PartialEq for TypedVariable<S, T> {
336 fn eq(&self, rhs: &TypedVariable<S, T>) -> bool {
337 self.key() == rhs.key()
338 }
339}
340
341impl<S, T> Eq for TypedVariable<S, T> {}
342
343impl<S, T> Hash for TypedVariable<S, T> {
344 fn hash<H>(&self, state: &mut H)
345 where
346 H: Hasher,
347 {
348 self.key().hash(state);
349 }
350}
351
352pub trait SupportedType: Sized + Debug + Parsable {
358 fn new_command<S>(
360 ref_fn: RefFn<S, Self>,
361 ref_mut_fn: MutRefFn<S, Self>,
362 index_resolver: Option<IndexResolver<S>>,
363 ) -> Command<S>;
364
365 fn update_save_stack<S>(
367 input: &mut vm::ExecutionInput<S>,
368 variable: &TypedVariable<S, Self>,
369 scope: groupingmap::Scope,
370 overwritten_value: Self,
371 ) {
372 (_, _, _, _) = (input, variable, scope, overwritten_value);
373 }
374
375 fn recycle<S>(input: &mut vm::ExecutionInput<S>, overwritten_value: Self) {
380 (_, _) = (input, overwritten_value)
381 }
382
383 fn new_typed_variable<S>(command: &Command<S>, index: Index) -> Option<TypedVariable<S, Self>>;
387
388 fn try_cast<S>(command: &Command<S>) -> Option<(RefFn<S, Self>, MutRefFn<S, Self>)>;
390}
391
392fn update_save_stack<S, T: Clone + SupportedType, F>(
401 input: &mut vm::ExecutionInput<S>,
402 variable: &TypedVariable<S, T>,
403 scope: groupingmap::Scope,
404 overwritten_value: T,
405 map_getter: F,
406) where
407 F: Fn(&mut SaveStackElement<S>) -> &mut SaveStackMap<S, T>,
408{
409 match scope {
410 groupingmap::Scope::Global => {
411 let n = input.groups().len();
412 for _ in 0..n {
413 let group = &mut input.groups()[0];
414 if let Some(stale_value) = map_getter(group).remove(variable) {
415 SupportedType::recycle(input, stale_value);
416 }
417 }
418 }
419 groupingmap::Scope::Local => {
420 if let Some((group, _)) = input.current_group_mut() {
421 if let Some(stale_value) = map_getter(group).save(*variable, overwritten_value) {
422 SupportedType::recycle(input, stale_value);
423 }
424 }
425 }
426 }
427}
428
429macro_rules! supported_type_impl {
430 ( $(
431 {
432 rust_type: $rust_type: path,
433 enum_variant: $enum_variant: ident,
434 $( save_stack_field: $save_stack_field: ident, )?
435 $( recycle_fn: $recycle_fn: ident, )?
436 },
437 )+ ) => {
438
439 pub enum ValueRef<'a> {
441 $(
442 $enum_variant(&'a $rust_type),
443 )+
444 }
445
446 pub enum Variable<S> {
467 $(
468 $enum_variant(TypedVariable<S, $rust_type>),
469 )+
470 }
471
472 fn new_variable<S>(getters: &Getters<S>, index: Index) -> Variable<S> {
473 match getters {
474 $(
475 Getters::$enum_variant(a, b) => Variable::$enum_variant(TypedVariable(*a, *b, index)),
476 )+
477 }
478 }
479
480 impl<S: TexlangState> Variable<S> {
481 pub fn value<'a>(&self, state: &'a S) -> ValueRef<'a> {
483 match self {
484 $(
485 Variable::$enum_variant(variable) => ValueRef::$enum_variant(variable.get(state)),
486 )+
487 }
488 }
489
490 fn set_value_using_input(
492 &self,
493 input: &mut vm::ExecutionInput<S>,
494 scope: groupingmap::Scope,
495 ) -> txl::Result<()> {
496 match self {
497 $(
498 Variable::$enum_variant(variable) => variable.set_using_input(input, scope),
499 )+
500 }
501 }
502 }
503
504 enum Getters<S> {
505 $(
506 $enum_variant(RefFn<S, $rust_type>, MutRefFn<S, $rust_type>),
507 )+
508 }
509
510 impl<S> Clone for Getters<S> {
511 fn clone(&self) -> Self {
512 match self {
513 $(
514 Self::$enum_variant(a, b) => Self::$enum_variant(*a, *b),
515 )+
516 }
517 }
518 }
519
520 impl<S> Getters<S> {
521 fn key(&self) -> GettersKey {
522 match self {
523 $(
524 Getters::$enum_variant(a, b) => GettersKey(*a as usize, *b as usize),
525 )+
526 }
527 }
528 }
529
530 $(
531 impl SupportedType for $rust_type {
532 fn new_command<S>(
533 ref_fn: RefFn<S, Self>,
534 ref_mut_fn: MutRefFn<S, Self>,
535 index_resolver: Option<IndexResolver<S>>,
536 ) -> Command<S> {
537 Command {
538 getters: Getters::$enum_variant(ref_fn, ref_mut_fn),
539 index_resolver,
540 }
541 }
542 $(
543 fn update_save_stack<S>(
544 input: &mut vm::ExecutionInput<S>,
545 variable: &TypedVariable<S, Self>,
546 scope: groupingmap::Scope,
547 overwritten_value: Self,
548 ) {
549 update_save_stack(input, variable, scope, overwritten_value, |element| {
550 &mut element.$save_stack_field
551 })
552 }
553 )?
554 $(
555 fn recycle<S>(input: &mut vm::ExecutionInput<S>, overwritten_value: Self) {
556 $recycle_fn(input, overwritten_value)
557 }
558 )?
559 fn new_typed_variable<S>(
560 command: &Command<S>,
561 index: Index,
562 ) -> Option<TypedVariable<S, Self>> {
563 match command.getters {
564 Getters::$enum_variant(a, b) => Some(TypedVariable(a, b, index)),
565 _ => None,
566 }
567 }
568 fn try_cast<S>(command: &Command<S>) -> Option<(RefFn<S, Self>, MutRefFn<S, Self>)> {
569 match command.getters {
570 Getters::$enum_variant(a, b) => Some((a,b)),
571 _ => None,
572 }
573 }
574 }
575 )+
576
577 pub(crate) struct SaveStackElement<S> {
579 $( $(
580 $save_stack_field: SaveStackMap<S, $rust_type>,
581 )? )+
582 }
583
584 impl<S> Default for SaveStackElement<S> {
585 fn default() -> Self {
586 Self {
587 $( $(
588 $save_stack_field: Default::default(),
589 )? )+
590 }
591 }
592 }
593
594 impl<S> SaveStackElement<S> {
595 pub(crate) fn restore(self, input: &mut vm::ExecutionInput<S>) {
596 $( $(
597 self.$save_stack_field.restore(input);
598 )? )+
599 }
600
601 pub(crate) fn serializable<'a>(
602 &'a self,
603 built_ins: &HashMap<GettersKey, token::CsName>,
604 ) -> SerializableSaveStackElement<'a> {
605 SerializableSaveStackElement {
606 $( $(
607 $save_stack_field: self.$save_stack_field.serializable(built_ins),
608 )? )+
609 }
610 }
611 }
612
613 #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
614 pub(crate) struct SerializableSaveStackElement<'a> {
615 $( $(
616 $save_stack_field: Vec<(token::CsName, usize, Cow<'a, $rust_type>)>,
617 )? )+
618 }
619
620 impl<'a> SerializableSaveStackElement<'a> {
621 pub(crate) fn finish_deserialization<S>(
622 self,
623 built_ins: &HashMap<token::CsName, command::BuiltIn<S>>,
624 ) -> SaveStackElement<S> {
625 SaveStackElement {
626 $( $(
627 $save_stack_field: SaveStackMap::from_deserialized(self.$save_stack_field, built_ins),
628 )? )+
629 }
630 }
631 }
632 };
633}
634
635supported_type_impl!(
636 {
637 rust_type: i32,
638 enum_variant: Int,
639 save_stack_field: i32,
640 },
641 {
642 rust_type: u8,
643 enum_variant: SmallInt,
644 save_stack_field: u8,
645 },
646 {
647 rust_type: common::Scaled,
648 enum_variant: Dimen,
649 save_stack_field: dimen,
650 },
651 {
652 rust_type: common::Glue,
653 enum_variant: Glue,
654 save_stack_field: glue,
655 },
656 {
657 rust_type: types::CatCode,
658 enum_variant: CatCode,
659 save_stack_field: catcode,
660 },
661 {
662 rust_type: types::MathCode,
663 enum_variant: MathCode,
664 save_stack_field: math_code,
665 },
666 {
667 rust_type: Vec<token::Token>,
668 enum_variant: TokenList,
669 save_stack_field: token_list,
670 recycle_fn: recycle_token_list,
671 },
672 {
673 rust_type: types::Font,
674 enum_variant: Font,
675 save_stack_field: font,
676 },
677 );
683
684fn recycle_token_list<S>(input: &mut vm::ExecutionInput<S>, overwritten_value: Vec<token::Token>) {
685 input.return_token_buffer(overwritten_value);
686}
687
688struct SaveStackMap<S, T>(HashMap<TypedVariable<S, T>, T>);
690
691impl<S, T> Default for SaveStackMap<S, T> {
692 fn default() -> Self {
693 Self(HashMap::new())
694 }
695}
696
697impl<S, T: Clone + SupportedType> SaveStackMap<S, T> {
698 fn save(&mut self, variable: TypedVariable<S, T>, value: T) -> Option<T> {
699 match self.0.entry(variable) {
700 std::collections::hash_map::Entry::Occupied(_) => Some(value),
701 std::collections::hash_map::Entry::Vacant(v) => {
702 v.insert(value);
703 None
704 }
705 }
706 }
707
708 fn remove(&mut self, variable: &TypedVariable<S, T>) -> Option<T> {
709 self.0.remove(variable)
710 }
711
712 fn restore(self, input: &mut vm::ExecutionInput<S>) {
713 for (v, restored_value) in self.0 {
714 let dest = (v.1)(input.state_mut(), v.2);
715 let overwritten_value = std::mem::replace(dest, restored_value);
716 SupportedType::recycle(input, overwritten_value);
717 }
718 }
719
720 fn serializable<'a>(
721 &'a self,
722 built_ins: &HashMap<GettersKey, token::CsName>,
723 ) -> Vec<(token::CsName, usize, Cow<'a, T>)> {
724 self.0
725 .iter()
726 .map(|(typed_variable, value): (&TypedVariable<S, T>, &T)| {
727 let key = GettersKey(typed_variable.0 as usize, typed_variable.1 as usize);
728 let cs_name = built_ins.get(&key).unwrap();
729 (*cs_name, typed_variable.2 .0, Cow::Borrowed(value))
730 })
731 .collect()
732 }
733}
734
735impl<S, T: SupportedType + Clone> SaveStackMap<S, T> {
736 fn from_deserialized<'a>(
737 deserialized: Vec<(token::CsName, usize, Cow<'a, T>)>,
738 built_ins: &HashMap<token::CsName, command::BuiltIn<S>>,
739 ) -> Self {
740 let m = deserialized
741 .into_iter()
742 .map(
743 |(cs_name, index, value): (token::CsName, usize, Cow<'a, T>)| {
744 let built_in = built_ins.get(&cs_name).unwrap();
746 let typed_variable = match built_in.cmd() {
747 command::Command::Variable(variable_command) => {
748 SupportedType::new_typed_variable(variable_command, Index(index))
750 .unwrap()
751 }
752 _ => panic!("wrong type of built in TODO return an error here"),
753 };
754 (typed_variable, value.into_owned())
755 },
756 )
757 .collect();
758 Self(m)
759 }
760}