use super::{PResult, Parser};
use crate::ast::{Decl, DeclKind, File};
use crate::source::token::{Punct, Tok};
use crate::words::{ALL, Role};
impl Parser<'_, '_, '_> {
pub fn file(&mut self) -> File {
let mut decls = Vec::new();
loop {
self.skip_newlines_keeping_docs();
if *self.tok() == Tok::Eof {
return File { decls };
}
self.decl_into(&mut decls);
}
}
pub(crate) fn body(&mut self) -> PResult<Vec<Decl>> {
self.need(Punct::LBrace)?;
let mut decls = Vec::new();
self.braces(|p| {
loop {
p.skip_newlines_keeping_docs();
if p.eat(Punct::RBrace) {
return Ok(decls);
}
if *p.tok() == Tok::Eof {
return Err(p.expected("`}`"));
}
p.decl_into(&mut decls);
}
})
}
fn decl_into(&mut self, decls: &mut Vec<Decl>) {
match self.decl().and_then(|d| self.end_stmt().map(|()| d)) {
Ok(d) => decls.push(d),
Err(_) => {
self.recover();
self.eat(Punct::Semi);
}
}
}
pub(crate) fn decl(&mut self) -> PResult<Decl> {
let start = self.span();
let mut doc = Vec::new();
while let Tok::Doc(line) = self.tok() {
doc.push(line.clone());
self.bump();
self.skip_newlines_keeping_docs();
}
let mut modifiers = Vec::new();
while let Some(m) = self.modifier_here() {
modifiers.push(m);
self.bump();
}
let kind = self.decl_kind()?;
Ok(Decl {
doc,
modifiers,
kind,
span: start.to(self.prev()),
})
}
fn modifier_here(&self) -> Option<crate::ast::Modifier> {
ALL.iter().filter(|w| self.at_word(w)).find_map(|w| {
w.role(|r| {
if let Role::Modifier(m) = r {
Some(*m)
} else {
None
}
})
})
}
fn decl_kind(&mut self) -> PResult<DeclKind> {
let named = matches!(self.tok(), Tok::Ident(_));
if named && matches!(self.nth(1), Tok::Punct(Punct::Eq | Punct::FatArrow)) {
return self.generic_decl();
}
for word in ALL {
for role in word.roles {
if let Role::Decl { starts, parse } = role
&& self.starts(word, *starts)
{
return parse(self);
}
}
}
self.generic_decl()
}
fn skip_newlines_keeping_docs(&mut self) {
while *self.tok() == Tok::Newline {
self.bump();
}
}
}