arena_terms_parser/
token.rs1use crate::TokenID;
13use arena_terms::Term;
14use parlex::{ParlexError, Span, Token};
15
16#[derive(Debug, Clone, Copy, Default)]
26pub enum Value {
27 #[default]
28 None,
29 Term(Term),
30 Index(usize),
31}
32
33macro_rules! impl_tryfrom_value {
38 ( $( $Variant:ident => $ty:ty ),+ $(,)? ) => {
39 $(
40 impl ::core::convert::TryFrom<Value> for $ty {
41 type Error = ParlexError;
42 fn try_from(v: Value) -> Result<Self, ParlexError> {
43 match v {
44 Value::$Variant(x) => Ok(x),
45 other => Err(ParlexError {
46 message: format!("expected `Value::{}`, found {:?}", stringify!($Variant), other),
47 span: None,
48 }),
49 }
50 }
51 }
52 )+
53 };
54}
55
56impl_tryfrom_value! {
58 Term => Term,
59 Index => usize,
60}
61
62impl TryFrom<Value> for Option<Term> {
64 type Error = ParlexError;
65 fn try_from(v: Value) -> Result<Self, ParlexError> {
66 match v {
67 Value::None => Ok(None),
68 Value::Term(x) => Ok(Some(x)),
69 other => Err(ParlexError {
70 message: format!("expected `Value::Term` or `Value::None`, found {:?}", other),
71 span: None,
72 }),
73 }
74 }
75}
76
77#[derive(Debug, Clone)]
85pub struct TermToken {
86 pub token_id: TokenID,
88 pub value: Value,
90 pub span: Option<Span>,
92 pub op_tab_index: Option<usize>,
94}
95
96impl TermToken {
97 #[must_use]
106 pub fn new(token_id: TokenID, value: Value, span: Option<Span>) -> Self {
107 Self {
108 token_id,
109 value,
110 span,
111 op_tab_index: None,
112 }
113 }
114}
115
116impl TermToken {
117 pub fn merge_span(&mut self, other_token: &TermToken) {
118 match other_token.span() {
119 Some(other_span) => match &mut self.span {
120 Some(span) => {
121 *span = span.merge(&other_span);
122 }
123 None => {
124 self.span = Some(other_span);
125 }
126 },
127 None => (),
128 }
129 }
130}
131
132impl Token for TermToken {
135 type TokenID = TokenID;
136
137 fn token_id(&self) -> Self::TokenID {
138 self.token_id
139 }
140 fn span(&self) -> Option<Span> {
141 self.span
142 }
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148 use core::convert::TryFrom;
149
150 #[test]
151 fn try_from_value_to_usize_success() {
152 let v = Value::Index(42);
153 let got = usize::try_from(v).expect("Index -> usize should succeed");
154 assert_eq!(got, 42);
155 }
156
157 #[test]
158 fn try_from_value_to_usize_wrong_variant_err() {
159 let v = Value::None;
161 let err = usize::try_from(v).expect_err("None -> usize must error");
162 let msg = format!("{err:#}");
163 assert!(msg.contains("expected `Value::Index`"), "msg={msg}");
165 assert!(msg.contains("None"), "msg={msg}");
166 }
167
168 #[test]
169 fn try_from_value_to_option_term_none_success() {
170 let v = Value::None;
171 let got = <Option<Term>>::try_from(v).expect("None -> Option<Term> should succeed");
172 assert!(got.is_none());
173 }
174
175 #[test]
176 fn try_from_value_to_option_term_wrong_variant_err() {
177 let v = Value::Index(7);
178 let err = <Option<Term>>::try_from(v).expect_err("Index -> Option<Term> must error");
179 let msg = format!("{err:#}");
180 dbg!(&msg);
181 assert!(
183 msg.contains("expected `Value::Term` or `Value::None`"),
184 "msg={msg}"
185 );
186 }
187
188 #[test]
189 fn roundtrip_index_via_value() {
190 let input = 123usize;
191 let got = usize::try_from(Value::Index(input)).unwrap();
192 assert_eq!(got, input);
193 }
194}