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(_, _) | Getters::Dimen(_, _) | Getters::Glue(_, _) => true,
157 Getters::CatCode(_, _)
158 | Getters::MathCode(_, _)
159 | Getters::TokenList(_, _)
160 | Getters::Font(_, _) => false,
161 }
162 }
163}
164
165impl<S: TexlangState> Command<S> {
166 pub fn resolve(
168 &self,
169 token: token::Token,
170 input: &mut vm::ExpandedStream<S>,
171 ) -> txl::Result<Variable<S>> {
172 let index = match &self.index_resolver {
173 None => Index(0),
174 Some(index_resolver) => {
175 input
176 .vm_mut()
177 .stack_push(token, error::OperationKind::VariableIndex);
178 let err_or = index_resolver.resolve(token, input);
179 input.vm_mut().stack_pop();
180 err_or?
181 }
182 };
183 Ok(new_variable(&self.getters, index))
184 }
185
186 pub fn resolve_type<T: SupportedType>(
188 &self,
189 token: token::Token,
190 input: &mut vm::ExpandedStream<S>,
191 ) -> txl::Result<Option<TypedVariable<S, T>>> {
192 let Some((ref_fn, ref_mut_fn)) = T::try_cast(self) else {
193 return Ok(None);
194 };
195 let index = match &self.index_resolver {
196 None => Index(0),
197 Some(index_resolver) => index_resolver.resolve(token, input)?,
198 };
199 Ok(Some(TypedVariable(ref_fn, ref_mut_fn, index)))
200 }
201}
202
203impl<S> Command<S> {
204 pub(crate) fn key(&self) -> CommandKey {
205 let getters_key = self.getters.key();
206 match &self.index_resolver {
207 None => CommandKey::Singleton(getters_key),
208 Some(index_resolver) => match index_resolver {
209 IndexResolver::Static(a) => CommandKey::ArrayStatic(getters_key, *a),
210 IndexResolver::Dynamic(f) => CommandKey::ArrayDynamic(getters_key, *f as usize),
211 },
212 }
213 }
214}
215
216impl<S: TexlangState> Command<S> {
217 pub fn value<'a>(
219 &self,
220 token: token::Token,
221 input: &'a mut vm::ExpandedStream<S>,
222 ) -> txl::Result<ValueRef<'a>> {
223 Ok(self.resolve(token, input)?.value(input.state()))
224 }
225
226 pub(crate) fn set_value_using_input(
232 &self,
233 token: token::Token,
234 input: &mut vm::ExecutionInput<S>,
235 scope: groupingmap::Scope,
236 ) -> txl::Result<()> {
237 let variable = self.resolve(token, input.as_mut())?;
238 input
239 .vm_mut()
240 .stack_push(token, error::OperationKind::VariableAssignment);
241 let err_or = variable.set_value_using_input(input, scope);
242 input.vm_mut().stack_pop();
243 err_or
244 }
245}
246
247#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
249pub(crate) enum CommandKey {
250 Singleton(GettersKey),
251 ArrayStatic(GettersKey, Index),
252 ArrayDynamic(GettersKey, usize),
253}
254
255impl CommandKey {
256 pub(crate) fn getter_key(&self) -> GettersKey {
257 match self {
258 CommandKey::Singleton(k) => *k,
259 CommandKey::ArrayStatic(k, _) => *k,
260 CommandKey::ArrayDynamic(k, _) => *k,
261 }
262 }
263}
264
265#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
267pub(crate) struct GettersKey(usize, usize);
268
269pub struct TypedVariable<S, T>(RefFn<S, T>, MutRefFn<S, T>, Index);
271
272impl<S, T> Copy for TypedVariable<S, T> {}
273
274impl<S, T> Clone for TypedVariable<S, T> {
275 fn clone(&self) -> Self {
276 *self
277 }
278}
279
280impl<S, T> TypedVariable<S, T> {
281 pub fn get<'a>(&self, state: &'a S) -> &'a T {
283 (self.0)(state, self.2)
284 }
285
286 fn key(&self) -> (usize, usize, Index) {
287 (self.0 as usize, self.1 as usize, self.2)
288 }
289}
290
291impl<S, T> TypedVariable<S, T>
292where
293 S: TexlangState,
294 T: SupportedType,
295{
296 pub fn set(&self, input: &mut vm::ExecutionInput<S>, scope: groupingmap::Scope, value: T) {
305 let r: &mut T = (self.1)(input.state_mut(), self.2);
306 let overwritten_value = std::mem::replace(r, value);
307 if !input.groups().is_empty() {
310 SupportedType::update_save_stack(input, self, scope, overwritten_value);
311 } else {
312 SupportedType::recycle(input, overwritten_value);
313 }
314 }
315}
316impl<S, T> TypedVariable<S, T>
317where
318 S: TexlangState,
319 T: SupportedType,
320{
321 fn set_using_input(
322 &self,
323 input: &mut vm::ExecutionInput<S>,
324 scope: groupingmap::Scope,
325 ) -> txl::Result<()> {
326 let (_, value) = <(OptionalEquals, T)>::parse(input)?;
327 self.set(input, scope, value);
328 Ok(())
329 }
330}
331
332impl<S, T> PartialEq for TypedVariable<S, T> {
333 fn eq(&self, rhs: &TypedVariable<S, T>) -> bool {
334 self.key() == rhs.key()
335 }
336}
337
338impl<S, T> Eq for TypedVariable<S, T> {}
339
340impl<S, T> Hash for TypedVariable<S, T> {
341 fn hash<H>(&self, state: &mut H)
342 where
343 H: Hasher,
344 {
345 self.key().hash(state);
346 }
347}
348
349pub trait SupportedType: Sized + Debug + Parsable {
355 fn new_command<S>(
357 ref_fn: RefFn<S, Self>,
358 ref_mut_fn: MutRefFn<S, Self>,
359 index_resolver: Option<IndexResolver<S>>,
360 ) -> Command<S>;
361
362 fn update_save_stack<S>(
364 input: &mut vm::ExecutionInput<S>,
365 variable: &TypedVariable<S, Self>,
366 scope: groupingmap::Scope,
367 overwritten_value: Self,
368 ) {
369 (_, _, _, _) = (input, variable, scope, overwritten_value);
370 }
371
372 fn recycle<S>(input: &mut vm::ExecutionInput<S>, overwritten_value: Self) {
377 (_, _) = (input, overwritten_value)
378 }
379
380 fn new_typed_variable<S>(command: &Command<S>, index: Index) -> Option<TypedVariable<S, Self>>;
384
385 fn try_cast<S>(command: &Command<S>) -> Option<(RefFn<S, Self>, MutRefFn<S, Self>)>;
387}
388
389fn update_save_stack<S, T: Clone + SupportedType, F>(
398 input: &mut vm::ExecutionInput<S>,
399 variable: &TypedVariable<S, T>,
400 scope: groupingmap::Scope,
401 overwritten_value: T,
402 map_getter: F,
403) where
404 F: Fn(&mut SaveStackElement<S>) -> &mut SaveStackMap<S, T>,
405{
406 match scope {
407 groupingmap::Scope::Global => {
408 let n = input.groups().len();
409 for _ in 0..n {
410 let group = &mut input.groups()[0];
411 if let Some(stale_value) = map_getter(group).remove(variable) {
412 SupportedType::recycle(input, stale_value);
413 }
414 }
415 }
416 groupingmap::Scope::Local => {
417 if let Some((group, _)) = input.current_group_mut() {
418 if let Some(stale_value) = map_getter(group).save(*variable, overwritten_value) {
419 SupportedType::recycle(input, stale_value);
420 }
421 }
422 }
423 }
424}
425
426macro_rules! supported_type_impl {
427 ( $(
428 {
429 rust_type: $rust_type: path,
430 enum_variant: $enum_variant: ident,
431 $( save_stack_field: $save_stack_field: ident, )?
432 $( recycle_fn: $recycle_fn: ident, )?
433 },
434 )+ ) => {
435
436 pub enum ValueRef<'a> {
438 $(
439 $enum_variant(&'a $rust_type),
440 )+
441 }
442
443 pub enum Variable<S> {
464 $(
465 $enum_variant(TypedVariable<S, $rust_type>),
466 )+
467 }
468
469 fn new_variable<S>(getters: &Getters<S>, index: Index) -> Variable<S> {
470 match getters {
471 $(
472 Getters::$enum_variant(a, b) => Variable::$enum_variant(TypedVariable(*a, *b, index)),
473 )+
474 }
475 }
476
477 impl<S: TexlangState> Variable<S> {
478 pub fn value<'a>(&self, state: &'a S) -> ValueRef<'a> {
480 match self {
481 $(
482 Variable::$enum_variant(variable) => ValueRef::$enum_variant(variable.get(state)),
483 )+
484 }
485 }
486
487 fn set_value_using_input(
489 &self,
490 input: &mut vm::ExecutionInput<S>,
491 scope: groupingmap::Scope,
492 ) -> txl::Result<()> {
493 match self {
494 $(
495 Variable::$enum_variant(variable) => variable.set_using_input(input, scope),
496 )+
497 }
498 }
499 }
500
501 enum Getters<S> {
502 $(
503 $enum_variant(RefFn<S, $rust_type>, MutRefFn<S, $rust_type>),
504 )+
505 }
506
507 impl<S> Clone for Getters<S> {
508 fn clone(&self) -> Self {
509 match self {
510 $(
511 Self::$enum_variant(a, b) => Self::$enum_variant(*a, *b),
512 )+
513 }
514 }
515 }
516
517 impl<S> Getters<S> {
518 fn key(&self) -> GettersKey {
519 match self {
520 $(
521 Getters::$enum_variant(a, b) => GettersKey(*a as usize, *b as usize),
522 )+
523 }
524 }
525 }
526
527 $(
528 impl SupportedType for $rust_type {
529 fn new_command<S>(
530 ref_fn: RefFn<S, Self>,
531 ref_mut_fn: MutRefFn<S, Self>,
532 index_resolver: Option<IndexResolver<S>>,
533 ) -> Command<S> {
534 Command {
535 getters: Getters::$enum_variant(ref_fn, ref_mut_fn),
536 index_resolver,
537 }
538 }
539 $(
540 fn update_save_stack<S>(
541 input: &mut vm::ExecutionInput<S>,
542 variable: &TypedVariable<S, Self>,
543 scope: groupingmap::Scope,
544 overwritten_value: Self,
545 ) {
546 update_save_stack(input, variable, scope, overwritten_value, |element| {
547 &mut element.$save_stack_field
548 })
549 }
550 )?
551 $(
552 fn recycle<S>(input: &mut vm::ExecutionInput<S>, overwritten_value: Self) {
553 $recycle_fn(input, overwritten_value)
554 }
555 )?
556 fn new_typed_variable<S>(
557 command: &Command<S>,
558 index: Index,
559 ) -> Option<TypedVariable<S, Self>> {
560 match command.getters {
561 Getters::$enum_variant(a, b) => Some(TypedVariable(a, b, index)),
562 _ => None,
563 }
564 }
565 fn try_cast<S>(command: &Command<S>) -> Option<(RefFn<S, Self>, MutRefFn<S, Self>)> {
566 match command.getters {
567 Getters::$enum_variant(a, b) => Some((a,b)),
568 _ => None,
569 }
570 }
571 }
572 )+
573
574 pub(crate) struct SaveStackElement<S> {
576 $( $(
577 $save_stack_field: SaveStackMap<S, $rust_type>,
578 )? )+
579 }
580
581 impl<S> Default for SaveStackElement<S> {
582 fn default() -> Self {
583 Self {
584 $( $(
585 $save_stack_field: Default::default(),
586 )? )+
587 }
588 }
589 }
590
591 impl<S> SaveStackElement<S> {
592 pub(crate) fn restore(self, input: &mut vm::ExecutionInput<S>) {
593 $( $(
594 self.$save_stack_field.restore(input);
595 )? )+
596 }
597
598 pub(crate) fn serializable<'a>(
599 &'a self,
600 built_ins: &HashMap<GettersKey, token::CsName>,
601 ) -> SerializableSaveStackElement<'a> {
602 SerializableSaveStackElement {
603 $( $(
604 $save_stack_field: self.$save_stack_field.serializable(built_ins),
605 )? )+
606 }
607 }
608 }
609
610 #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
611 pub(crate) struct SerializableSaveStackElement<'a> {
612 $( $(
613 $save_stack_field: Vec<(token::CsName, usize, Cow<'a, $rust_type>)>,
614 )? )+
615 }
616
617 impl<'a> SerializableSaveStackElement<'a> {
618 pub(crate) fn finish_deserialization<S>(
619 self,
620 built_ins: &HashMap<token::CsName, command::BuiltIn<S>>,
621 ) -> SaveStackElement<S> {
622 SaveStackElement {
623 $( $(
624 $save_stack_field: SaveStackMap::from_deserialized(self.$save_stack_field, built_ins),
625 )? )+
626 }
627 }
628 }
629 };
630}
631
632supported_type_impl!(
633 {
634 rust_type: i32,
635 enum_variant: Int,
636 save_stack_field: i32,
637 },
638 {
639 rust_type: core::Scaled,
640 enum_variant: Dimen,
641 save_stack_field: dimen,
642 },
643 {
644 rust_type: core::Glue,
645 enum_variant: Glue,
646 save_stack_field: glue,
647 },
648 {
649 rust_type: types::CatCode,
650 enum_variant: CatCode,
651 save_stack_field: catcode,
652 },
653 {
654 rust_type: types::MathCode,
655 enum_variant: MathCode,
656 save_stack_field: math_code,
657 },
658 {
659 rust_type: Vec<token::Token>,
660 enum_variant: TokenList,
661 save_stack_field: token_list,
662 recycle_fn: recycle_token_list,
663 },
664 {
665 rust_type: types::Font,
666 enum_variant: Font,
667 save_stack_field: font,
668 },
669 );
675
676fn recycle_token_list<S>(input: &mut vm::ExecutionInput<S>, overwritten_value: Vec<token::Token>) {
677 input.return_token_buffer(overwritten_value);
678}
679
680struct SaveStackMap<S, T>(HashMap<TypedVariable<S, T>, T>);
682
683impl<S, T> Default for SaveStackMap<S, T> {
684 fn default() -> Self {
685 Self(HashMap::new())
686 }
687}
688
689impl<S, T: Clone + SupportedType> SaveStackMap<S, T> {
690 fn save(&mut self, variable: TypedVariable<S, T>, value: T) -> Option<T> {
691 match self.0.entry(variable) {
692 std::collections::hash_map::Entry::Occupied(_) => Some(value),
693 std::collections::hash_map::Entry::Vacant(v) => {
694 v.insert(value);
695 None
696 }
697 }
698 }
699
700 fn remove(&mut self, variable: &TypedVariable<S, T>) -> Option<T> {
701 self.0.remove(variable)
702 }
703
704 fn restore(self, input: &mut vm::ExecutionInput<S>) {
705 for (v, restored_value) in self.0 {
706 let dest = (v.1)(input.state_mut(), v.2);
707 let overwritten_value = std::mem::replace(dest, restored_value);
708 SupportedType::recycle(input, overwritten_value);
709 }
710 }
711
712 fn serializable<'a>(
713 &'a self,
714 built_ins: &HashMap<GettersKey, token::CsName>,
715 ) -> Vec<(token::CsName, usize, Cow<'a, T>)> {
716 self.0
717 .iter()
718 .map(|(typed_variable, value): (&TypedVariable<S, T>, &T)| {
719 let key = GettersKey(typed_variable.0 as usize, typed_variable.1 as usize);
720 let cs_name = built_ins.get(&key).unwrap();
721 (*cs_name, typed_variable.2 .0, Cow::Borrowed(value))
722 })
723 .collect()
724 }
725}
726
727impl<S, T: SupportedType + Clone> SaveStackMap<S, T> {
728 fn from_deserialized<'a>(
729 deserialized: Vec<(token::CsName, usize, Cow<'a, T>)>,
730 built_ins: &HashMap<token::CsName, command::BuiltIn<S>>,
731 ) -> Self {
732 let m = deserialized
733 .into_iter()
734 .map(
735 |(cs_name, index, value): (token::CsName, usize, Cow<'a, T>)| {
736 let built_in = built_ins.get(&cs_name).unwrap();
738 let typed_variable = match built_in.cmd() {
739 command::Command::Variable(variable_command) => {
740 SupportedType::new_typed_variable(variable_command, Index(index))
742 .unwrap()
743 }
744 _ => panic!("wrong type of built in TODO return an error here"),
745 };
746 (typed_variable, value.into_owned())
747 },
748 )
749 .collect();
750 Self(m)
751 }
752}