Skip to main content

yog_script_analyze/parser/
decl.rs

1//! Declarations: a file's, a body's — documentation and modifiers taken,
2//! then the first word whose form starts here parses it.
3
4use super::{PResult, Parser};
5use crate::ast::{Decl, DeclKind, File};
6use crate::source::token::{Punct, Tok};
7use crate::words::{ALL, Role};
8
9impl Parser<'_, '_, '_> {
10    /// The whole source.
11    pub fn file(&mut self) -> File {
12        let mut decls = Vec::new();
13        loop {
14            self.skip_newlines_keeping_docs();
15            if *self.tok() == Tok::Eof {
16                return File { decls };
17            }
18            self.decl_into(&mut decls);
19        }
20    }
21
22    /// `{ decls }`.
23    pub(crate) fn body(&mut self) -> PResult<Vec<Decl>> {
24        self.need(Punct::LBrace)?;
25        let mut decls = Vec::new();
26        self.braces(|p| {
27            loop {
28                p.skip_newlines_keeping_docs();
29                if p.eat(Punct::RBrace) {
30                    return Ok(decls);
31                }
32                if *p.tok() == Tok::Eof {
33                    return Err(p.expected("`}`"));
34                }
35                p.decl_into(&mut decls);
36            }
37        })
38    }
39
40    /// One declaration and its end, or past it when it fails.
41    fn decl_into(&mut self, decls: &mut Vec<Decl>) {
42        match self.decl().and_then(|d| self.end_stmt().map(|()| d)) {
43            Ok(d) => decls.push(d),
44            Err(_) => {
45                self.recover();
46                self.eat(Punct::Semi);
47            }
48        }
49    }
50
51    pub(crate) fn decl(&mut self) -> PResult<Decl> {
52        let start = self.span();
53        let mut doc = Vec::new();
54        while let Tok::Doc(line) = self.tok() {
55            doc.push(line.clone());
56            self.bump();
57            self.skip_newlines_keeping_docs();
58        }
59        let mut modifiers = Vec::new();
60        while let Some(m) = self.modifier_here() {
61            modifiers.push(m);
62            self.bump();
63        }
64        let kind = self.decl_kind()?;
65        Ok(Decl {
66            doc,
67            modifiers,
68            kind,
69            span: start.to(self.prev()),
70        })
71    }
72
73    fn modifier_here(&self) -> Option<crate::ast::Modifier> {
74        ALL.iter().filter(|w| self.at_word(w)).find_map(|w| {
75            w.role(|r| {
76                if let Role::Modifier(m) = r {
77                    Some(*m)
78                } else {
79                    None
80                }
81            })
82        })
83    }
84
85    fn decl_kind(&mut self) -> PResult<DeclKind> {
86        // A name and `=` is a property, whatever word the name is.
87        let named = matches!(self.tok(), Tok::Ident(_));
88        if named && matches!(self.nth(1), Tok::Punct(Punct::Eq | Punct::FatArrow)) {
89            return self.generic_decl();
90        }
91        for word in ALL {
92            for role in word.roles {
93                if let Role::Decl { starts, parse } = role
94                    && self.starts(word, *starts)
95                {
96                    return parse(self);
97                }
98            }
99        }
100        self.generic_decl()
101    }
102
103    /// Newlines skipped, a doc line kept for the declaration after it.
104    fn skip_newlines_keeping_docs(&mut self) {
105        while *self.tok() == Tok::Newline {
106            self.bump();
107        }
108    }
109}