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