mod grammar;
use crate::syntax::kind::SyntaxKind;
use crate::syntax::lexer::{Lexed, lex};
use crate::syntax::tree::SyntaxNode;
use rowan::{Checkpoint, GreenNode, GreenNodeBuilder};
use std::ops::Range;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseError {
pub message: String,
pub range: Range<usize>,
}
impl std::fmt::Display for ParseError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}..{}: {}",
self.range.start, self.range.end, self.message
)
}
}
#[derive(Debug, Clone)]
pub struct Parsed {
green: GreenNode,
errors: Vec<ParseError>,
}
impl Parsed {
pub fn syntax(&self) -> SyntaxNode {
SyntaxNode::new_root(self.green.clone())
}
pub fn errors(&self) -> &[ParseError] {
&self.errors
}
pub fn ok(&self) -> Option<SyntaxNode> {
self.errors.is_empty().then(|| self.syntax())
}
}
pub fn parse(src: &str) -> Parsed {
let mut p = Parser::new(src);
grammar::source_file(&mut p);
p.finish()
}
pub(crate) struct Parser<'a> {
tokens: Lexed<'a>,
pos: usize,
builder: GreenNodeBuilder<'static>,
errors: Vec<ParseError>,
}
impl<'a> Parser<'a> {
fn new(src: &'a str) -> Self {
Parser {
tokens: lex(src),
pos: 0,
builder: GreenNodeBuilder::new(),
errors: Vec::new(),
}
}
fn finish(self) -> Parsed {
debug_assert_eq!(self.pos, self.tokens.len(), "tokens left unconsumed");
Parsed {
green: self.builder.finish(),
errors: self.errors,
}
}
fn nth_index(&self, n: usize) -> Option<usize> {
(self.pos..self.tokens.len())
.filter(|&i| !self.tokens.kind(i).is_trivia())
.nth(n)
}
pub(crate) fn nth(&self, n: usize) -> SyntaxKind {
self.nth_index(n)
.map_or(SyntaxKind::EOF, |i| self.tokens.kind(i))
}
pub(crate) fn current(&self) -> SyntaxKind {
self.nth(0)
}
pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
self.current() == kind
}
pub(crate) fn at_any(&self, kinds: &[SyntaxKind]) -> bool {
kinds.contains(&self.current())
}
pub(crate) fn at_end(&self) -> bool {
self.at(SyntaxKind::EOF)
}
fn current_range(&self) -> Range<usize> {
let range = self
.tokens
.range(self.nth_index(0).unwrap_or(self.tokens.len()));
usize::from(range.start())..usize::from(range.end())
}
fn push(&mut self, i: usize) {
self.builder
.token(self.tokens.kind(i).into(), self.tokens.text(i));
}
pub(crate) fn flush_trivia(&mut self) {
while self.tokens.kind(self.pos).is_trivia() {
self.push(self.pos);
self.pos += 1;
}
}
pub(crate) fn bump(&mut self) {
self.flush_trivia();
if self.pos < self.tokens.len() {
self.push(self.pos);
self.pos += 1;
}
}
pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
if self.at(kind) {
self.bump();
true
} else {
false
}
}
pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
if self.eat(kind) {
return true;
}
self.error(format!("expected {kind:?}, found {:?}", self.current()));
false
}
pub(crate) fn error(&mut self, message: impl Into<String>) {
let range = self.current_range();
self.errors.push(ParseError {
message: message.into(),
range,
});
}
pub(crate) fn error_and_bump(&mut self, message: impl Into<String>) {
self.start_node(SyntaxKind::ERROR);
self.error(message);
if !self.at_end() {
self.bump();
}
self.finish_node();
}
pub(crate) fn start_node(&mut self, kind: SyntaxKind) {
self.builder.start_node(kind.into());
}
pub(crate) fn finish_node(&mut self) {
self.builder.finish_node();
}
pub(crate) fn checkpoint(&self) -> Checkpoint {
self.builder.checkpoint()
}
pub(crate) fn start_node_at(&mut self, cp: Checkpoint, kind: SyntaxKind) {
self.builder.start_node_at(cp, kind.into());
}
pub(crate) fn eat_trailing_comment(&mut self) {
let mut i = self.pos;
while self.tokens.kind(i) == SyntaxKind::WHITESPACE && !self.tokens.text(i).contains('\n') {
i += 1;
}
if !(self.tokens.kind(i).is_comment() && !self.tokens.text(i).contains('\n')) {
return;
}
for j in self.pos..=i {
self.push(j);
}
self.pos = i + 1;
}
pub(crate) fn finish_stmt(&mut self) {
self.eat_trailing_comment();
self.finish_node();
}
}