Skip to main content

wat_ast/
index.rs

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    /// Returns the sign token for this integer.
111    pub fn sign(&self) -> Option<Sign> {
112        self.i.sign()
113    }
114
115    /// Returns the original source text for this integer.
116    pub fn src(&self) -> &str {
117        self.i.src()
118    }
119
120    /// Returns the value string that can be parsed for this integer, as well as
121    /// the base that it should be parsed in
122    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 only makes sense when SymbolicIndex was parsed from a token
157    /// stream.
158    span: Option<wast::Span>,
159}
160
161impl SymbolicIndex {
162    /// This method can be used when you are building an in-memory data
163    /// structure. In that case, there's no need for a span.
164    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}