1use std::collections::BTreeMap;
8use std::fmt::Debug;
9
10use chumsky::{inspector::Inspector, prelude::Input};
11
12use super::manuscript::MacroDefinition;
13use super::symbol::SymbolName;
14
15#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
16pub enum NumeralMode {
17 #[default]
18 Octal,
19 Decimal,
20}
21
22impl NumeralMode {
23 pub(crate) fn radix(self, alternate: bool) -> u32 {
24 match (&self, alternate) {
25 (&NumeralMode::Octal, false) | (&NumeralMode::Decimal, true) => 8,
26 (&NumeralMode::Decimal, false) | (&NumeralMode::Octal, true) => 10,
27 }
28 }
29
30 pub(crate) fn set_numeral_mode(&mut self, mode: NumeralMode) {
31 *self = mode;
32 }
33}
34
35#[test]
36fn test_numeral_mode_default() {
37 assert_eq!(NumeralMode::default(), NumeralMode::Octal);
38}
39
40#[derive(Debug, Clone, PartialEq, Eq)]
41pub(super) struct TruncatableMap<K: Eq, V: Eq> {
42 in_insertion_order: Vec<K>,
43 items: BTreeMap<K, V>,
44}
45
46impl<K: Eq, V: Eq> Default for TruncatableMap<K, V> {
47 fn default() -> Self {
48 TruncatableMap {
49 in_insertion_order: Default::default(),
50 items: BTreeMap::new(),
51 }
52 }
53}
54
55impl<K, V> TruncatableMap<K, V>
56where
57 K: Clone + Eq + Ord + Debug,
58 V: Eq,
59{
60 pub(crate) fn insert(&mut self, k: K, v: V) {
61 if self.items.insert(k.clone(), v).is_some() {
62 panic!("cannot insert duplicate entry for {k:?}");
63 } else {
64 self.in_insertion_order.push(k);
65 }
66 }
67
68 pub(crate) fn get(&self, k: &K) -> Option<&V> {
69 self.items.get(k)
70 }
71
72 pub(crate) fn len(&self) -> usize {
73 self.in_insertion_order.len()
74 }
75
76 pub(crate) fn truncate(&mut self, newlen: usize) {
77 for k in self.in_insertion_order.drain(newlen..) {
78 self.items.remove(&k);
79 }
80 }
81
82 pub(crate) fn map_ref(&self) -> &BTreeMap<K, V> {
83 &self.items
84 }
85}
86
87#[derive(Debug, PartialEq, Eq, Clone)]
88pub(crate) struct State<'src> {
89 pub(super) numeral_mode: NumeralMode,
90 pub(super) body: &'src str,
91 pub(super) macros: TruncatableMap<SymbolName, MacroDefinition>,
92}
93
94impl<'src> State<'src> {
95 pub(crate) fn new(body: &'src str, numeral_mode: NumeralMode) -> State<'src> {
96 State {
97 numeral_mode,
98 body,
99 macros: Default::default(),
100 }
101 }
102
103 pub(crate) fn define_macro(&mut self, definition: MacroDefinition) {
104 self.macros.insert(definition.name.clone(), definition);
106 }
107
108 pub(crate) fn get_macro_definition(&self, name: &SymbolName) -> Option<&MacroDefinition> {
109 self.macros.get(name)
110 }
111
112 pub(crate) fn macros(&self) -> &BTreeMap<SymbolName, MacroDefinition> {
113 self.macros.map_ref()
114 }
115}
116
117impl<'src, I: Input<'src>> Inspector<'src, I> for State<'src> {
118 type Checkpoint = usize;
119
120 #[inline(always)]
121 fn on_token(&mut self, _: &<I as Input<'src>>::Token) {}
122
123 fn on_save<'parse>(
124 &self,
125 _cursor: &chumsky::input::Cursor<'src, 'parse, I>,
126 ) -> Self::Checkpoint {
127 self.macros.len()
128 }
129
130 fn on_rewind<'parse>(
131 &mut self,
132 marker: &chumsky::input::Checkpoint<'src, 'parse, I, Self::Checkpoint>,
133 ) {
134 self.macros.truncate(*marker.inspector());
135 }
136}