yog_script_analyze/parser/
decl.rs1use super::{PResult, Parser};
5use crate::ast::{Decl, DeclKind, File};
6use crate::source::token::{Punct, Tok};
7use crate::words::{ALL, Role};
8
9impl Parser<'_, '_, '_> {
10 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 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 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 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 fn skip_newlines_keeping_docs(&mut self) {
105 while *self.tok() == Tok::Newline {
106 self.bump();
107 }
108 }
109}