erl_parse/cst/forms/
mod.rs

1use erl_tokenize::tokens::{AtomToken, IntegerToken, StringToken, SymbolToken, VariableToken};
2use erl_tokenize::values::Symbol;
3use erl_tokenize::{LexicalToken, Position, PositionRange};
4
5use self::parts::RecordFieldDecl;
6use crate::cst::clauses::{FunDeclClause, SpecClause};
7use crate::cst::commons::parts::{Args, Clauses, ModulePrefix, NameAndArity};
8use crate::cst::commons::{ProperList, Tuple};
9use crate::cst::Type;
10use crate::traits::{Parse, TokenRead};
11use crate::{Parser, Result};
12
13pub mod parts;
14
15/// `-` `module` `(` `AtomToken` `)` `.`
16#[derive(Debug, Clone)]
17pub struct ModuleAttr {
18    pub _hyphen: SymbolToken,
19    pub _module: AtomToken,
20    pub _open: SymbolToken,
21    pub module_name: AtomToken,
22    pub _close: SymbolToken,
23    pub _dot: SymbolToken,
24}
25impl Parse for ModuleAttr {
26    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
27    where
28        T: TokenRead,
29    {
30        let this = ModuleAttr {
31            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
32            _module: track!(parser.expect("module"))?,
33            _open: track!(parser.expect(&Symbol::OpenParen))?,
34            module_name: track!(parser.parse())?,
35            _close: track!(parser.expect(&Symbol::CloseParen))?,
36            _dot: track!(parser.expect(&Symbol::Dot))?,
37        };
38        {
39            let module = &this.module_name;
40            let reader = parser.reader_mut();
41            let module_string = StringToken::from_value(module.value(), module.start_position());
42            reader.define_macro("MODULE", vec![module.clone().into()]);
43            reader.define_macro("MODULE_STRING", vec![module_string.into()]);
44        }
45        Ok(this)
46    }
47}
48impl PositionRange for ModuleAttr {
49    fn start_position(&self) -> Position {
50        self._hyphen.start_position()
51    }
52    fn end_position(&self) -> Position {
53        self._dot.end_position()
54    }
55}
56
57/// `-` `export` `(` `ProperList<NameAndArity>` `)` `.`
58#[derive(Debug, Clone)]
59pub struct ExportAttr {
60    pub _hyphen: SymbolToken,
61    pub _export: AtomToken,
62    pub _open: SymbolToken,
63    pub exports: ProperList<NameAndArity>,
64    pub _close: SymbolToken,
65    pub _dot: SymbolToken,
66}
67impl Parse for ExportAttr {
68    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
69    where
70        T: TokenRead,
71    {
72        Ok(ExportAttr {
73            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
74            _export: track!(parser.expect("export"))?,
75            _open: track!(parser.expect(&Symbol::OpenParen))?,
76            exports: track!(parser.parse())?,
77            _close: track!(parser.expect(&Symbol::CloseParen))?,
78            _dot: track!(parser.expect(&Symbol::Dot))?,
79        })
80    }
81}
82impl PositionRange for ExportAttr {
83    fn start_position(&self) -> Position {
84        self._hyphen.start_position()
85    }
86    fn end_position(&self) -> Position {
87        self._dot.end_position()
88    }
89}
90
91/// `-` `export_type` `(` `ProperList<NameAndArity>` `)` `.`
92#[derive(Debug, Clone)]
93pub struct ExportTypeAttr {
94    pub _hyphen: SymbolToken,
95    pub _export_type: AtomToken,
96    pub _open: SymbolToken,
97    pub exports: ProperList<NameAndArity>,
98    pub _close: SymbolToken,
99    pub _dot: SymbolToken,
100}
101impl Parse for ExportTypeAttr {
102    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
103    where
104        T: TokenRead,
105    {
106        Ok(ExportTypeAttr {
107            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
108            _export_type: track!(parser.expect("export_type"))?,
109            _open: track!(parser.expect(&Symbol::OpenParen))?,
110            exports: track!(parser.parse())?,
111            _close: track!(parser.expect(&Symbol::CloseParen))?,
112            _dot: track!(parser.expect(&Symbol::Dot))?,
113        })
114    }
115}
116impl PositionRange for ExportTypeAttr {
117    fn start_position(&self) -> Position {
118        self._hyphen.start_position()
119    }
120    fn end_position(&self) -> Position {
121        self._dot.end_position()
122    }
123}
124
125/// `-` `import` `(` `AtomToken` `,` `ProperList<NameAndArity>` `)` `.`
126#[derive(Debug, Clone)]
127pub struct ImportAttr {
128    pub _hyphen: SymbolToken,
129    pub _import: AtomToken,
130    pub _open: SymbolToken,
131    pub module_name: AtomToken,
132    pub _comma: SymbolToken,
133    pub imports: ProperList<NameAndArity>,
134    pub _close: SymbolToken,
135    pub _dot: SymbolToken,
136}
137impl Parse for ImportAttr {
138    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
139    where
140        T: TokenRead,
141    {
142        Ok(ImportAttr {
143            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
144            _import: track!(parser.expect("import"))?,
145            _open: track!(parser.expect(&Symbol::OpenParen))?,
146            module_name: track!(parser.parse())?,
147            _comma: track!(parser.expect(&Symbol::Comma))?,
148            imports: track!(parser.parse())?,
149            _close: track!(parser.expect(&Symbol::CloseParen))?,
150            _dot: track!(parser.expect(&Symbol::Dot))?,
151        })
152    }
153}
154impl PositionRange for ImportAttr {
155    fn start_position(&self) -> Position {
156        self._hyphen.start_position()
157    }
158    fn end_position(&self) -> Position {
159        self._dot.end_position()
160    }
161}
162
163/// `-` `file` `(` `StringToken` `,` `IntegerToken` `)` `.`
164#[derive(Debug, Clone)]
165pub struct FileAttr {
166    pub _hyphen: SymbolToken,
167    pub _file: AtomToken,
168    pub _open: SymbolToken,
169    pub file_name: StringToken,
170    pub _comma: SymbolToken,
171    pub line_num: IntegerToken,
172    pub _close: SymbolToken,
173    pub _dot: SymbolToken,
174}
175impl Parse for FileAttr {
176    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
177    where
178        T: TokenRead,
179    {
180        Ok(FileAttr {
181            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
182            _file: track!(parser.expect("file"))?,
183            _open: track!(parser.expect(&Symbol::OpenParen))?,
184            file_name: track!(parser.parse())?,
185            _comma: track!(parser.expect(&Symbol::Comma))?,
186            line_num: track!(parser.parse())?,
187            _close: track!(parser.expect(&Symbol::CloseParen))?,
188            _dot: track!(parser.expect(&Symbol::Dot))?,
189        })
190    }
191}
192impl PositionRange for FileAttr {
193    fn start_position(&self) -> Position {
194        self._hyphen.start_position()
195    }
196    fn end_position(&self) -> Position {
197        self._dot.end_position()
198    }
199}
200
201/// `-` `AtomToken` `(` `Vec<LexicalToken>` `)` `.`
202#[derive(Debug, Clone)]
203pub struct WildAttr {
204    pub _hyphen: SymbolToken,
205    pub attr_name: AtomToken,
206    pub _open: SymbolToken,
207    pub attr_value: Vec<LexicalToken>,
208    pub _close: SymbolToken,
209    pub _dot: SymbolToken,
210}
211impl Parse for WildAttr {
212    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
213    where
214        T: TokenRead,
215    {
216        let _hyphen = track!(parser.expect(&Symbol::Hyphen))?;
217        let attr_name = track!(parser.parse())?;
218        let _open = track!(parser.expect(&Symbol::OpenParen))?;
219
220        let count = parser.peek(|parser| {
221            for i in 0.. {
222                let v = track!(parser.parse::<LexicalToken>())?
223                    .as_symbol_token()
224                    .map(SymbolToken::value);
225                if v == Some(Symbol::Dot) {
226                    use std::cmp;
227                    return Ok(cmp::max(i, 1) - 1);
228                }
229            }
230            unreachable!()
231        });
232        let attr_value = (0..track!(count)?)
233            .map(|_| parser.parse().expect("Never fails"))
234            .collect();
235        Ok(WildAttr {
236            _hyphen,
237            attr_name,
238            _open,
239            attr_value,
240            _close: track!(parser.expect(&Symbol::CloseParen))?,
241            _dot: track!(parser.expect(&Symbol::Dot))?,
242        })
243    }
244}
245impl PositionRange for WildAttr {
246    fn start_position(&self) -> Position {
247        self._hyphen.start_position()
248    }
249    fn end_position(&self) -> Position {
250        self._dot.end_position()
251    }
252}
253
254/// `-` `spec` `Option<ModulePrefix>` `AtomToken` `Clauses<SpecClause>` `.`
255#[derive(Debug, Clone)]
256pub struct FunSpec {
257    pub _hyphen: SymbolToken,
258    pub _spec: AtomToken,
259    pub module: Option<ModulePrefix<AtomToken>>,
260    pub fun_name: AtomToken,
261    pub clauses: Clauses<SpecClause>,
262    pub _dot: SymbolToken,
263}
264impl Parse for FunSpec {
265    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
266    where
267        T: TokenRead,
268    {
269        Ok(FunSpec {
270            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
271            _spec: track!(parser.expect("spec"))?,
272            module: track!(parser.parse())?,
273            fun_name: track!(parser.parse())?,
274            clauses: track!(parser.parse())?,
275            _dot: track!(parser.expect(&Symbol::Dot))?,
276        })
277    }
278}
279impl PositionRange for FunSpec {
280    fn start_position(&self) -> Position {
281        self._hyphen.start_position()
282    }
283    fn end_position(&self) -> Position {
284        self._dot.end_position()
285    }
286}
287
288/// `-` `callback` `AtomToken` `Clauses<SpecClause>` `.`
289#[derive(Debug, Clone)]
290pub struct CallbackSpec {
291    pub _hyphen: SymbolToken,
292    pub _spec: AtomToken,
293    pub callback_name: AtomToken,
294    pub clauses: Clauses<SpecClause>,
295    pub _dot: SymbolToken,
296}
297impl Parse for CallbackSpec {
298    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
299    where
300        T: TokenRead,
301    {
302        Ok(CallbackSpec {
303            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
304            _spec: track!(parser.expect("callback"))?,
305            callback_name: track!(parser.parse())?,
306            clauses: track!(parser.parse())?,
307            _dot: track!(parser.expect(&Symbol::Dot))?,
308        })
309    }
310}
311impl PositionRange for CallbackSpec {
312    fn start_position(&self) -> Position {
313        self._hyphen.start_position()
314    }
315    fn end_position(&self) -> Position {
316        self._dot.end_position()
317    }
318}
319
320/// `Clauses<FunDeclClause>` `.`
321#[derive(Debug, Clone)]
322pub struct FunDecl {
323    pub clauses: Clauses<FunDeclClause>,
324    pub _dot: SymbolToken,
325}
326impl Parse for FunDecl {
327    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
328    where
329        T: TokenRead,
330    {
331        Ok(FunDecl {
332            clauses: track!(parser.parse())?,
333            _dot: track!(parser.expect(&Symbol::Dot))?,
334        })
335    }
336}
337impl PositionRange for FunDecl {
338    fn start_position(&self) -> Position {
339        self.clauses.start_position()
340    }
341    fn end_position(&self) -> Position {
342        self._dot.end_position()
343    }
344}
345
346/// `-` `record` `(` `AtomToken` `,` `Tuple<RecordFieldDecl>` `)` `.`
347#[derive(Debug, Clone)]
348pub struct RecordDecl {
349    pub _hyphen: SymbolToken,
350    pub _record: AtomToken,
351    pub _open: SymbolToken,
352    pub record_name: AtomToken,
353    pub _comma: SymbolToken,
354    pub fields: Tuple<RecordFieldDecl>,
355    pub _close: SymbolToken,
356    pub _dot: SymbolToken,
357}
358impl Parse for RecordDecl {
359    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
360    where
361        T: TokenRead,
362    {
363        Ok(RecordDecl {
364            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
365            _record: track!(parser.expect("record"))?,
366            _open: track!(parser.expect(&Symbol::OpenParen))?,
367            record_name: track!(parser.parse())?,
368            _comma: track!(parser.expect(&Symbol::Comma))?,
369            fields: track!(parser.parse())?,
370            _close: track!(parser.expect(&Symbol::CloseParen))?,
371            _dot: track!(parser.expect(&Symbol::Dot))?,
372        })
373    }
374}
375impl PositionRange for RecordDecl {
376    fn start_position(&self) -> Position {
377        self._hyphen.start_position()
378    }
379    fn end_position(&self) -> Position {
380        self._dot.end_position()
381    }
382}
383
384/// `-` `type|opaque` `AtomToken` `Args<VariableToken>` `::` `Type` `.`
385#[derive(Debug, Clone)]
386pub struct TypeDecl {
387    pub _hyphen: SymbolToken,
388    pub type_kind: AtomToken,
389    pub type_name: AtomToken,
390    pub variables: Args<VariableToken>,
391    pub _double_colon: SymbolToken,
392    pub ty: Type,
393    pub _dot: SymbolToken,
394}
395impl Parse for TypeDecl {
396    fn parse<T>(parser: &mut Parser<T>) -> Result<Self>
397    where
398        T: TokenRead,
399    {
400        Ok(TypeDecl {
401            _hyphen: track!(parser.expect(&Symbol::Hyphen))?,
402            type_kind: track!(parser.expect_any(&["type", "opaque"]))?,
403            type_name: track!(parser.parse())?,
404            variables: track!(parser.parse())?,
405            _double_colon: track!(parser.expect(&Symbol::DoubleColon))?,
406            ty: track!(parser.parse())?,
407            _dot: track!(parser.expect(&Symbol::Dot))?,
408        })
409    }
410}
411impl PositionRange for TypeDecl {
412    fn start_position(&self) -> Position {
413        self._hyphen.start_position()
414    }
415    fn end_position(&self) -> Position {
416        self._dot.end_position()
417    }
418}