Skip to main content

yog_script_analyze/parser/
decl.rs

1//! Declarations: a file's, a body's — attributes, documentation and
2//! modifiers taken, then the first word whose form starts here parses it,
3//! else a member written type first.
4
5use super::{PResult, Parser};
6use crate::ast::{Attribute, Decl, DeclKind, File, Modifier};
7use crate::source::token::{Punct, Tok};
8use crate::words::{ALL, Role, new, r#ref, r#struct};
9
10impl Parser<'_, '_, '_> {
11    /// The whole source.
12    pub fn file(&mut self) -> File {
13        let mut decls = Vec::new();
14        while *self.tok() != Tok::Eof {
15            let at = self.pos;
16            self.decl_into(&mut decls);
17            // A `}` recovery stops at closes no block out here: past it.
18            if self.pos == at {
19                self.bump();
20            }
21        }
22        File { decls }
23    }
24
25    /// `{ decls }`.
26    pub(crate) fn body(&mut self) -> PResult<Vec<Decl>> {
27        self.need(Punct::LBrace)?;
28        self.braces(Self::decls_to_brace)
29    }
30
31    /// Declarations up to and with the `}` closing them.
32    pub(crate) fn decls_to_brace(&mut self) -> PResult<Vec<Decl>> {
33        let mut decls = Vec::new();
34        loop {
35            if self.eat(Punct::RBrace) {
36                return Ok(decls);
37            }
38            if *self.tok() == Tok::Eof {
39                return Err(self.expected("`}`"));
40            }
41            self.decl_into(&mut decls);
42        }
43    }
44
45    /// One declaration, or past it when it fails.
46    fn decl_into(&mut self, decls: &mut Vec<Decl>) {
47        match self.decl() {
48            Ok(d) => decls.push(d),
49            Err(_) => self.recover(),
50        }
51    }
52
53    pub(crate) fn decl(&mut self) -> PResult<Decl> {
54        let start = self.span();
55        let mut doc = Vec::new();
56        let mut attributes = Vec::new();
57        loop {
58            match self.tok() {
59                Tok::Doc(line) => {
60                    doc.push(line.clone());
61                    self.bump();
62                }
63                Tok::Punct(Punct::LBracket) => attributes.extend(self.attributes()?),
64                _ => break,
65            }
66        }
67        let mut modifiers = Vec::new();
68        while let Some(m) = self.modifier_here() {
69            modifiers.push(m);
70            self.bump();
71        }
72        let kind = self.decl_kind()?;
73        Ok(Decl {
74            attributes,
75            doc,
76            modifiers,
77            kind,
78            span: start.to(self.prev()),
79        })
80    }
81
82    /// `[A, B(…)]`.
83    fn attributes(&mut self) -> PResult<Vec<Attribute>> {
84        self.need(Punct::LBracket)?;
85        self.list(Punct::RBracket, |p| {
86            let path = p.path("an attribute")?;
87            let args = if p.at(Punct::LParen) {
88                p.args()?
89            } else {
90                Vec::new()
91            };
92            Ok(Attribute { path, args })
93        })
94    }
95
96    fn modifier_here(&self) -> Option<Modifier> {
97        // `ref` marks a type only as `ref struct`; elsewhere it's a borrow.
98        if self.at_word(&r#ref::WORD) && !self.nth_word(1, &r#struct::WORD) {
99            return None;
100        }
101        // `new` hides a member only before one (`new bool Add(…)`); else it
102        // makes an object.
103        if self.at_word(&new::WORD)
104            && !self
105                .type_len(1)
106                .is_some_and(|len| matches!(self.nth(1 + len), Tok::Ident(_)))
107        {
108            return None;
109        }
110        ALL.iter().filter(|w| self.at_word(w)).find_map(|w| {
111            w.role(|r| match r {
112                Role::Modifier(m) => Some(*m),
113                _ => None,
114            })
115        })
116    }
117
118    fn decl_kind(&mut self) -> PResult<DeclKind> {
119        // `Name = value;` is a property, whatever word the name is.
120        if matches!(self.tok(), Tok::Ident(_)) && self.nth_is(1, Punct::Eq) {
121            return self.prop().map(DeclKind::Prop);
122        }
123        for word in ALL {
124            for role in word.roles {
125                if let Role::Decl { starts, parse } = role
126                    && self.starts(word, *starts)
127                {
128                    return parse(self);
129                }
130            }
131        }
132        self.member()
133    }
134}