mod generated;
mod language;
mod syntax_tree;
mod token_text;
pub(crate) mod grammar;
use std::{cell::RefCell, fmt, rc::Rc};
use crate::{lexer::Lexer, Error, Token, TokenKind};
pub use generated::syntax_kind::SyntaxKind;
pub use language::{SyntaxElement, SyntaxNode, SyntaxNodeChildren, SyntaxNodePtr, SyntaxToken};
pub use syntax_tree::SyntaxTree;
pub(crate) use syntax_tree::SyntaxTreeBuilder;
pub(crate) use token_text::TokenText;
#[derive(Debug)]
pub struct Parser<'a> {
lexer: Lexer<'a>,
current_token: Option<Token>,
builder: Rc<RefCell<SyntaxTreeBuilder>>,
errors: Vec<crate::Error>,
recursion_limit: LimitTracker,
accept_errors: bool,
}
impl<'a> Parser<'a> {
pub fn new(input: &'a str) -> Self {
let lexer = Lexer::new(input);
Self {
lexer,
current_token: None,
builder: Rc::new(RefCell::new(SyntaxTreeBuilder::new())),
errors: Vec::new(),
recursion_limit: Default::default(),
accept_errors: true,
}
}
pub fn with_recursion_limit(input: &'a str, recursion_limit: usize) -> Self {
let mut parser = Parser::new(input);
parser.recursion_limit = LimitTracker::new(recursion_limit);
parser
}
pub fn parse(mut self) -> SyntaxTree {
grammar::document::document(&mut self);
let builder = Rc::try_unwrap(self.builder)
.expect("More than one reference to builder left")
.into_inner();
builder.finish(self.errors, self.recursion_limit)
}
pub(crate) fn at(&mut self, token: TokenKind) -> bool {
if let Some(t) = self.peek() {
if t == token {
return true;
}
return false;
}
false
}
pub(crate) fn bump(&mut self, kind: SyntaxKind) {
self.eat(kind);
self.bump_ignored();
}
pub(crate) fn bump_ignored(&mut self) {
while let Some(TokenKind::Comment | TokenKind::Whitespace | TokenKind::Comma) = self.peek()
{
if let Some(TokenKind::Comment) = self.peek() {
self.bump(SyntaxKind::COMMENT);
}
if let Some(TokenKind::Whitespace) = self.peek() {
self.bump(SyntaxKind::WHITESPACE);
}
if let Some(TokenKind::Comma) = self.peek() {
self.bump(SyntaxKind::COMMA);
}
}
}
pub(crate) fn current(&mut self) -> &Token {
self.peek_token()
.expect("Could not peek at the current token")
}
fn eat(&mut self, kind: SyntaxKind) {
let token = self.pop();
self.builder.borrow_mut().token(kind, token.data());
}
pub(crate) fn limit_err<S: Into<String>>(&mut self, message: S) {
let current = self.current();
let err = Error::with_loc(message, current.data().to_string(), current.index());
self.push_err(err);
self.accept_errors = false;
}
pub(crate) fn err(&mut self, message: &str) {
let current = self.current();
let err = Error::with_loc(message, current.data().to_string(), current.index());
self.push_err(err);
}
pub(crate) fn err_and_pop(&mut self, message: &str) {
let current = self.pop();
self.bump_ignored();
let err = Error::with_loc(message, current.data().to_string(), current.index());
self.push_err(err);
}
pub(crate) fn expect(&mut self, token: TokenKind, kind: SyntaxKind) {
let current = self.current();
let data = current.data().to_string();
let index = current.index();
if self.at(token) {
self.bump(kind);
return;
}
let err = Error::with_loc(format!("expected {:?}, got {}", kind, data), data, index);
self.push_err(err);
}
pub(crate) fn push_err(&mut self, err: crate::error::Error) {
if self.accept_errors {
self.errors.push(err);
}
}
fn next_token(&mut self) -> Option<Token> {
for res in &mut self.lexer {
match res {
Err(e) => {
self.errors.push(e);
}
Ok(token) => {
return Some(token);
}
}
}
None
}
pub(crate) fn pop(&mut self) -> Token {
if let Some(token) = self.current_token.take() {
return token;
}
self.next_token()
.expect("Could not pop a token from the lexer")
}
pub(crate) fn push_ast(&mut self, kind: SyntaxKind, token: Token) {
self.builder.borrow_mut().token(kind, token.data())
}
pub(crate) fn start_node(&mut self, kind: SyntaxKind) -> NodeGuard {
self.builder.borrow_mut().start_node(kind);
let guard = NodeGuard::new(self.builder.clone());
self.bump_ignored();
guard
}
pub(crate) fn peek(&mut self) -> Option<TokenKind> {
self.peek_token().map(|token| token.kind())
}
pub(crate) fn peek_token(&mut self) -> Option<&Token> {
if self.current_token.is_none() {
self.current_token = self.next_token();
}
self.current_token.as_ref()
}
pub(crate) fn peek_token_n(&self, n: usize) -> Option<Token> {
self.current_token
.iter()
.cloned()
.map(Result::Ok)
.chain(self.lexer.clone())
.filter_map(Result::ok)
.filter(|token| !matches!(token.kind(), TokenKind::Whitespace | TokenKind::Comment))
.nth(n - 1)
}
pub(crate) fn peek_n(&self, n: usize) -> Option<TokenKind> {
self.peek_token_n(n).map(|token| token.kind())
}
pub(crate) fn peek_data(&mut self) -> Option<String> {
self.peek_token().map(|token| token.data().to_string())
}
pub(crate) fn peek_data_n(&self, n: usize) -> Option<String> {
self.peek_token_n(n).map(|token| token.data().to_string())
}
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub struct LimitTracker {
current: usize,
pub high: usize,
pub limit: usize,
}
impl Default for LimitTracker {
fn default() -> Self {
Self {
current: 0,
high: 0,
limit: 4_096, }
}
}
impl LimitTracker {
pub fn new(limit: usize) -> Self {
Self {
current: 0,
high: 0,
limit,
}
}
fn limited(&self) -> bool {
self.current > self.limit
}
fn consume(&mut self) {
self.current += 1;
if self.current > self.high {
self.high = self.current;
}
}
fn reset(&mut self) {
self.current = 0;
}
}
impl fmt::Debug for LimitTracker {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "recursion limit: {}, high: {}", self.limit, self.high)
}
}
#[must_use]
pub(crate) struct NodeGuard {
builder: Rc<RefCell<SyntaxTreeBuilder>>,
}
impl NodeGuard {
fn new(builder: Rc<RefCell<SyntaxTreeBuilder>>) -> Self {
Self { builder }
}
pub(crate) fn finish_node(self) {
drop(self);
}
}
impl Drop for NodeGuard {
fn drop(&mut self) {
self.builder.borrow_mut().finish_node();
}
}