erl_pp/
types.rs

1//! Miscellaneous types.
2use erl_tokenize::tokens::{AtomToken, SymbolToken, VariableToken};
3use erl_tokenize::values::Symbol;
4use erl_tokenize::{LexicalToken, Position, PositionRange};
5use std::fmt;
6use std::hash::{Hash, Hasher};
7use std::mem;
8
9use crate::token_reader::{ReadFrom, TokenReader};
10use crate::{Error, Result};
11
12/// The list of tokens that can be used as a macro name.
13#[derive(Debug, Clone)]
14#[allow(missing_docs)]
15pub enum MacroName {
16    Atom(AtomToken),
17    Variable(VariableToken),
18}
19impl MacroName {
20    /// Returns the value of this token.
21    pub fn value(&self) -> &str {
22        match *self {
23            MacroName::Atom(ref t) => t.value(),
24            MacroName::Variable(ref t) => t.value(),
25        }
26    }
27
28    /// Returns the original textual representation of this token.
29    pub fn text(&self) -> &str {
30        match *self {
31            MacroName::Atom(ref t) => t.text(),
32            MacroName::Variable(ref t) => t.text(),
33        }
34    }
35}
36impl PartialEq for MacroName {
37    fn eq(&self, other: &Self) -> bool {
38        self.value() == other.value()
39    }
40}
41impl Eq for MacroName {}
42impl Hash for MacroName {
43    fn hash<H: Hasher>(&self, hasher: &mut H) {
44        self.value().hash(hasher);
45    }
46}
47impl PositionRange for MacroName {
48    fn start_position(&self) -> Position {
49        match *self {
50            MacroName::Atom(ref t) => t.start_position(),
51            MacroName::Variable(ref t) => t.start_position(),
52        }
53    }
54    fn end_position(&self) -> Position {
55        match *self {
56            MacroName::Atom(ref t) => t.end_position(),
57            MacroName::Variable(ref t) => t.end_position(),
58        }
59    }
60}
61impl fmt::Display for MacroName {
62    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63        write!(f, "{}", self.text())
64    }
65}
66impl ReadFrom for MacroName {
67    fn read_from<T>(reader: &mut TokenReader<T>) -> Result<Self>
68    where
69        T: Iterator<Item = erl_tokenize::Result<LexicalToken>>,
70    {
71        if let Some(token) = reader.try_read()? {
72            Ok(MacroName::Atom(token))
73        } else {
74            let token = reader.read()?;
75            Ok(MacroName::Variable(token))
76        }
77    }
78}
79
80/// Macro variables.
81#[derive(Debug, Clone)]
82#[allow(missing_docs)]
83pub struct MacroVariables {
84    pub _open_paren: SymbolToken,
85    pub list: List<VariableToken>,
86    pub _close_paren: SymbolToken,
87}
88impl MacroVariables {
89    /// Returns an iterator which iterates over this variables.
90    pub fn iter(&self) -> ListIter<VariableToken> {
91        self.list.iter()
92    }
93
94    /// Returns the number of this variables.
95    pub fn len(&self) -> usize {
96        self.list.iter().count()
97    }
98
99    /// Returns `true` if there are no variables.
100    pub fn is_empty(&self) -> bool {
101        self.len() == 0
102    }
103}
104impl PositionRange for MacroVariables {
105    fn start_position(&self) -> Position {
106        self._open_paren.start_position()
107    }
108    fn end_position(&self) -> Position {
109        self._close_paren.end_position()
110    }
111}
112impl fmt::Display for MacroVariables {
113    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
114        write!(f, "({})", self.list)
115    }
116}
117impl ReadFrom for MacroVariables {
118    fn read_from<T>(reader: &mut TokenReader<T>) -> Result<Self>
119    where
120        T: Iterator<Item = erl_tokenize::Result<LexicalToken>>,
121    {
122        Ok(MacroVariables {
123            _open_paren: reader.read_expected(&Symbol::OpenParen)?,
124            list: reader.read()?,
125            _close_paren: reader.read_expected(&Symbol::CloseParen)?,
126        })
127    }
128}
129
130/// Macro arguments.
131#[derive(Debug, Clone)]
132#[allow(missing_docs)]
133pub struct MacroArgs {
134    pub _open_paren: SymbolToken,
135    pub list: List<MacroArg>,
136    pub _close_paren: SymbolToken,
137}
138impl MacroArgs {
139    /// Returns an iterator which iterates over this arguments.
140    pub fn iter(&self) -> ListIter<MacroArg> {
141        self.list.iter()
142    }
143
144    /// Returns the number of this arguments.
145    pub fn len(&self) -> usize {
146        self.list.iter().count()
147    }
148
149    /// Returns `true` if there are no arguments.
150    pub fn is_empty(&self) -> bool {
151        self.len() == 0
152    }
153}
154impl PositionRange for MacroArgs {
155    fn start_position(&self) -> Position {
156        self._open_paren.start_position()
157    }
158    fn end_position(&self) -> Position {
159        self._close_paren.end_position()
160    }
161}
162impl fmt::Display for MacroArgs {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        write!(f, "({})", self.list)
165    }
166}
167impl ReadFrom for MacroArgs {
168    fn read_from<T>(reader: &mut TokenReader<T>) -> Result<Self>
169    where
170        T: Iterator<Item = erl_tokenize::Result<LexicalToken>>,
171    {
172        Ok(MacroArgs {
173            _open_paren: reader.read_expected(&Symbol::OpenParen)?,
174            list: reader.read()?,
175            _close_paren: reader.read_expected(&Symbol::CloseParen)?,
176        })
177    }
178}
179
180/// Macro argument.
181#[derive(Debug, Clone)]
182pub struct MacroArg {
183    /// Tokens which represent a macro argument.
184    ///
185    /// Note that this must not be empty.
186    pub tokens: Vec<LexicalToken>,
187}
188impl PositionRange for MacroArg {
189    fn start_position(&self) -> Position {
190        self.tokens.first().as_ref().unwrap().start_position()
191    }
192    fn end_position(&self) -> Position {
193        self.tokens.last().as_ref().unwrap().end_position()
194    }
195}
196impl fmt::Display for MacroArg {
197    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
198        for t in &self.tokens {
199            write!(f, "{}", t.text())?;
200        }
201        Ok(())
202    }
203}
204impl ReadFrom for MacroArg {
205    fn read_from<T>(reader: &mut TokenReader<T>) -> Result<Self>
206    where
207        T: Iterator<Item = erl_tokenize::Result<LexicalToken>>,
208    {
209        let mut stack = Vec::new();
210        let mut arg = Vec::new();
211        while let Some(token) = reader.try_read_token()? {
212            if let LexicalToken::Symbol(ref s) = token {
213                match s.value() {
214                    Symbol::CloseParen if stack.is_empty() => {
215                        reader.unread_token(s.clone().into());
216                        return if arg.is_empty() {
217                            Err(Error::missing_macro_arg(s.start_position()))
218                        } else {
219                            Ok(MacroArg { tokens: arg })
220                        };
221                    }
222                    Symbol::Comma if stack.is_empty() => {
223                        if arg.is_empty() {
224                            return Err(Error::missing_macro_arg(s.start_position()));
225                        }
226                        reader.unread_token(s.clone().into());
227                        return Ok(MacroArg { tokens: arg });
228                    }
229                    Symbol::OpenParen
230                    | Symbol::OpenBrace
231                    | Symbol::OpenSquare
232                    | Symbol::DoubleLeftAngle => {
233                        stack.push(s.clone());
234                    }
235                    Symbol::CloseParen
236                    | Symbol::CloseBrace
237                    | Symbol::CloseSquare
238                    | Symbol::DoubleRightAngle => {
239                        let last = stack
240                            .pop()
241                            .ok_or_else(|| Error::unbalanced_paren(None, s.clone()))?;
242                        let expected = match last.value() {
243                            Symbol::OpenParen => Symbol::CloseParen,
244                            Symbol::OpenBrace => Symbol::CloseBrace,
245                            Symbol::OpenSquare => Symbol::CloseSquare,
246                            Symbol::DoubleLeftAngle => Symbol::DoubleRightAngle,
247                            _ => unreachable!(),
248                        };
249                        if s.value() != expected {
250                            return Err(Error::unbalanced_paren(Some(last), s.clone()));
251                        }
252                    }
253                    _ => {}
254                }
255            }
256            arg.push(token);
257        }
258        Err(Error::UnexpectedEof)
259    }
260}
261
262/// Tail part of a linked list (cons cell).
263#[derive(Debug, Clone)]
264#[allow(missing_docs)]
265pub enum Tail<T> {
266    Null,
267    Cons {
268        _comma: SymbolToken,
269        head: T,
270        tail: Box<Tail<T>>,
271    },
272}
273impl<T: fmt::Display> fmt::Display for Tail<T> {
274    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
275        match *self {
276            Tail::Null => Ok(()),
277            Tail::Cons {
278                ref head, ref tail, ..
279            } => write!(f, ",{}{}", head, tail),
280        }
281    }
282}
283impl<U: ReadFrom> ReadFrom for Tail<U> {
284    fn read_from<T>(reader: &mut TokenReader<T>) -> Result<Self>
285    where
286        T: Iterator<Item = erl_tokenize::Result<LexicalToken>>,
287    {
288        if let Some(_comma) = reader.try_read_expected(&Symbol::Comma)? {
289            let head = reader.read()?;
290            let tail = Box::new(reader.read()?);
291            Ok(Tail::Cons { _comma, head, tail })
292        } else {
293            Ok(Tail::Null)
294        }
295    }
296}
297
298/// Linked list (cons cell).
299#[derive(Debug, Clone)]
300#[allow(missing_docs)]
301pub enum List<T> {
302    Null,
303    Cons { head: T, tail: Tail<T> },
304}
305impl<T> List<T> {
306    /// Returns an iterator which iterates over the elements in this list.
307    pub fn iter(&self) -> ListIter<T> {
308        ListIter(ListIterInner::List(self))
309    }
310}
311impl<T: fmt::Display> fmt::Display for List<T> {
312    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
313        match *self {
314            List::Null => Ok(()),
315            List::Cons { ref head, ref tail } => write!(f, "{}{}", head, tail),
316        }
317    }
318}
319impl<U: ReadFrom> ReadFrom for List<U> {
320    fn read_from<T>(reader: &mut TokenReader<T>) -> Result<Self>
321    where
322        T: Iterator<Item = erl_tokenize::Result<LexicalToken>>,
323    {
324        if let Some(head) = reader.try_read()? {
325            let tail = reader.read()?;
326            Ok(List::Cons { head, tail })
327        } else {
328            Ok(List::Null)
329        }
330    }
331}
332
333/// An iterator which iterates over the elements in a `List`.
334#[derive(Debug)]
335pub struct ListIter<'a, T: 'a>(ListIterInner<'a, T>);
336impl<'a, T: 'a> Iterator for ListIter<'a, T> {
337    type Item = &'a T;
338    fn next(&mut self) -> Option<Self::Item> {
339        self.0.next()
340    }
341}
342
343#[derive(Debug)]
344enum ListIterInner<'a, T: 'a> {
345    List(&'a List<T>),
346    Tail(&'a Tail<T>),
347    End,
348}
349impl<'a, T: 'a> Iterator for ListIterInner<'a, T> {
350    type Item = &'a T;
351    fn next(&mut self) -> Option<Self::Item> {
352        match mem::replace(self, ListIterInner::End) {
353            ListIterInner::List(&List::Cons { ref head, ref tail }) => {
354                *self = ListIterInner::Tail(tail);
355                Some(head)
356            }
357            ListIterInner::Tail(&Tail::Cons {
358                ref head, ref tail, ..
359            }) => {
360                *self = ListIterInner::Tail(tail);
361                Some(head)
362            }
363            ListIterInner::List(&List::Null)
364            | ListIterInner::Tail(&Tail::Null)
365            | ListIterInner::End => None,
366        }
367    }
368}