1use std::fmt;
2
3use wast::parser::{Cursor, Parse, Parser, Peek, Result};
4
5use crate::{AsAtoms, Atom, Integer, Sign};
6
7pub fn symbolic<S: AsRef<str>>(s: S) -> Index {
8 Index::Symbolic(SymbolicIndex::new(s.as_ref().to_owned()))
9}
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub enum Index {
13 Numeric(NumericIndex),
14 Symbolic(SymbolicIndex),
15}
16
17impl fmt::Display for Index {
18 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
19 match self {
20 Self::Numeric(i) => write!(f, "{}", i.src()),
21 Self::Symbolic(i) => write!(f, "{}", i.to_string()),
22 }
23 }
24}
25
26impl Parse<'_> for Index {
27 fn parse(parser: Parser<'_>) -> Result<Self> {
28 match parser.parse::<NumericIndex>() {
29 Ok(ni) => Ok(Self::Numeric(ni)),
30 Err(_) => match parser.parse::<SymbolicIndex>() {
31 Ok(si) => Ok(Self::Symbolic(si)),
32 Err(err) => Err(err),
33 },
34 }
35 }
36}
37
38impl AsAtoms for Index {
39 fn as_atoms(&self) -> Vec<Atom> {
40 match self {
41 Self::Numeric(i) => i.as_atoms(),
42 Self::Symbolic(i) => i.as_atoms(),
43 }
44 }
45}
46
47impl Peek for Index {
48 fn peek(cursor: Cursor<'_>) -> bool {
49 cursor.id().is_some() || cursor.integer().is_some()
50 }
51
52 fn display() -> &'static str {
53 "an index"
54 }
55}
56
57#[derive(Debug, Clone, PartialEq, Eq)]
58pub struct Indexes {
59 idxs: Vec<Index>,
60}
61
62impl Indexes {
63 pub fn new(idxs: Vec<Index>) -> Self {
64 Self { idxs }
65 }
66}
67
68impl IntoIterator for Indexes {
69 type Item = Index;
70 type IntoIter = std::vec::IntoIter<Index>;
71
72 fn into_iter(self) -> Self::IntoIter {
73 self.idxs.into_iter()
74 }
75}
76
77impl AsAtoms for Indexes {
78 fn as_atoms(&self) -> Vec<Atom> {
79 self.idxs.iter().map(|i| Atom::new(i.to_string())).collect()
80 }
81}
82
83impl Parse<'_> for Indexes {
84 fn parse(parser: Parser<'_>) -> Result<Self> {
85 let mut idxs = Vec::new();
86
87 while parser.peek::<Index>() {
88 idxs.push(parser.parse()?);
89 }
90
91 Ok(Self { idxs })
92 }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
96pub struct NumericIndex {
97 i: Integer,
98 span: Option<wast::Span>,
99}
100
101impl NumericIndex {
102 pub fn new(i: Integer) -> Self {
103 Self { i, span: None }
104 }
105
106 pub fn span(&self) -> Option<wast::Span> {
107 self.span
108 }
109
110 pub fn sign(&self) -> Option<Sign> {
112 self.i.sign()
113 }
114
115 pub fn src(&self) -> &str {
117 self.i.src()
118 }
119
120 pub fn val(&self) -> (Option<&String>, Option<u32>) {
123 self.i.val()
124 }
125}
126
127impl AsAtoms for NumericIndex {
128 fn as_atoms(&self) -> Vec<Atom> {
129 vec![Atom::new(self.i.to_string())]
130 }
131}
132
133impl Parse<'_> for NumericIndex {
134 fn parse(parser: Parser<'_>) -> Result<Self> {
135 let span = Some(parser.cur_span());
136 let i = parser.parse::<Integer>()?;
137
138 Ok(Self { i, span })
139 }
140}
141
142impl Peek for NumericIndex {
143 fn peek(cursor: Cursor<'_>) -> bool {
144 cursor.integer().is_some()
145 }
146
147 fn display() -> &'static str {
148 "a numeric index"
149 }
150}
151
152#[derive(Debug, Clone)]
153pub struct SymbolicIndex {
154 name: String,
155
156 span: Option<wast::Span>,
159}
160
161impl SymbolicIndex {
162 pub fn new(name: String) -> Self {
165 Self { name, span: None }
166 }
167
168 pub fn name(&self) -> &str {
169 &self.name
170 }
171
172 pub fn span(&self) -> Option<wast::Span> {
173 self.span
174 }
175}
176
177impl std::hash::Hash for SymbolicIndex {
178 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
179 self.name.hash(state);
180 }
181}
182
183impl PartialEq for SymbolicIndex {
184 fn eq(&self, other: &Self) -> bool {
185 self.name == other.name
186 }
187}
188
189impl Eq for SymbolicIndex {}
190
191impl fmt::Display for SymbolicIndex {
192 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
193 write!(f, "${}", self.name)
194 }
195}
196
197impl AsAtoms for SymbolicIndex {
198 fn as_atoms(&self) -> Vec<Atom> {
199 vec![Atom::new(self.to_string())]
200 }
201}
202
203impl Parse<'_> for SymbolicIndex {
204 fn parse(parser: Parser<'_>) -> Result<Self> {
205 let id = parser.parse::<wast::Id>()?;
206 let name = id.name().to_owned();
207 let span = Some(id.span());
208
209 Ok(Self { name, span })
210 }
211}
212
213impl Peek for SymbolicIndex {
214 fn peek(cursor: Cursor<'_>) -> bool {
215 cursor.id().is_some()
216 }
217
218 fn display() -> &'static str {
219 "a symbolic index"
220 }
221}