use rowan::TextRange;
use crate::diagnostics::DiagnosticKind;
use crate::parser::Parser;
use crate::parser::cst::SyntaxKind;
use crate::parser::cst::token_sets::{EXPR_FIRST_TOKENS, ROOT_EXPR_FIRST_TOKENS};
use crate::parser::lexer::token_text;
impl Parser<'_, '_> {
pub fn parse_root(&mut self) {
self.start_node(SyntaxKind::Root);
while !self.should_stop() && !self.currently_is(SyntaxKind::Error) {
if self.currently_is(SyntaxKind::Id) && self.next_is(SyntaxKind::Equals) {
self.parse_def();
continue;
}
let start = self.current_span().start();
self.start_node(SyntaxKind::Def);
let success = self.parse_expr_or_error();
if !success {
self.error_until_next_def();
}
self.finish_node();
if success {
let end = self.last_non_trivia_end().unwrap_or(start);
let span = TextRange::new(start, end);
let def_text = &self.source[usize::from(start)..usize::from(end)];
self.diagnostics
.report(self.source_id, DiagnosticKind::UnnamedDef, span)
.hint(format!("give it a name like `Name = {}`", def_text.trim()))
.emit();
}
}
self.eat_trivia();
self.finish_node();
}
pub(crate) fn error_until_next_def(&mut self) {
if self.should_stop() {
return;
}
if self.currently_at_def_start() {
return;
}
self.start_node(SyntaxKind::Error);
while !self.should_stop() && !self.currently_at_def_start() {
self.bump();
self.skip_trivia_to_buffer();
}
self.finish_node();
}
pub(crate) fn currently_at_def_start(&mut self) -> bool {
if self.currently_is(SyntaxKind::Id) && self.next_is(SyntaxKind::Equals) {
return true;
}
self.currently_is_one_of(ROOT_EXPR_FIRST_TOKENS)
}
fn parse_def(&mut self) {
self.start_node(SyntaxKind::Def);
let span = self.current_span();
let name = token_text(self.source, &self.tokens[self.pos]);
self.bump();
self.validate_def_name(name, span);
let ate_equals = self.eat_token(SyntaxKind::Equals);
assert!(
ate_equals,
"parse_def: expected '=' but found {:?} (caller should verify Equals is present)",
self.current()
);
if self.currently_is_one_of(EXPR_FIRST_TOKENS) {
self.parse_expr();
} else {
self.error(DiagnosticKind::ExpectedExpression);
}
self.finish_node();
}
}