use rucc_ast::{Ast, Decl, DeclId, Expr, ExprId, Stmt, StmtId, StrId};
use rucc_base::{Interner, Symbol};
use rucc_diag::{DEFAULT_ERROR_LIMIT, Diagnostic, Errors, Span};
use rucc_lex::{Keyword, Punct, Token, TokenKind, Tokens};
use rucc_session::Std;
use crate::cursor::Cursor;
use crate::scope::Scopes;
pub const MAX_NESTING: usize = 256;
#[derive(Debug, Clone, Copy)]
pub struct Context<'a> {
pub interner: &'a Interner,
pub std: Std,
pub gnu: bool,
pub pedantic: bool,
pub error_limit: usize,
}
impl<'a> Context<'a> {
#[must_use]
pub fn new(interner: &'a Interner, std: Std) -> Context<'a> {
Context { interner, std, gnu: true, pedantic: false, error_limit: DEFAULT_ERROR_LIMIT }
}
}
#[derive(Debug)]
pub struct Parsed {
pub ast: Ast,
pub diagnostics: Vec<Diagnostic>,
}
impl Parsed {
#[must_use]
pub fn failed(&self) -> bool {
self.diagnostics.iter().any(|d| d.severity.is_fatal())
}
}
#[derive(Debug)]
pub struct Parser<'a> {
pub(crate) cursor: Cursor<'a>,
pub(crate) tokens: &'a Tokens,
pub(crate) scopes: Scopes,
pub(crate) errors: Errors,
pub(crate) ast: Ast,
pub(crate) cx: Context<'a>,
depth: usize,
too_deep: bool,
}
impl<'a> Parser<'a> {
#[must_use]
pub fn new(tokens: &'a Tokens, cx: Context<'a>) -> Parser<'a> {
Parser {
cursor: Cursor::new(&tokens.tokens),
tokens,
scopes: Scopes::new(),
errors: Errors::new(cx.error_limit),
ast: Ast::new(),
cx,
depth: 0,
too_deep: false,
}
}
#[must_use]
pub fn finish(self) -> Parsed {
Parsed { ast: self.ast, diagnostics: self.errors.finish() }
}
pub(crate) fn error(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
self.errors.push(Diagnostic::error(message, span).with_code(code));
}
pub(crate) fn warn(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
self.errors.push(Diagnostic::warning(message, span).with_code(code));
}
pub(crate) fn pedantic(&mut self, code: &'static str, message: impl Into<String>, span: Span) {
if self.cx.pedantic {
self.warn(code, message, span);
}
}
pub(crate) fn stopped(&self) -> bool {
self.errors.stopped()
}
pub(crate) fn describe(&self, token: Token) -> String {
match token.kind {
TokenKind::Eof => "end of file".to_string(),
TokenKind::Punct(punct) => format!("`{}`", punct.as_str()),
TokenKind::Keyword(word) => format!("`{}`", word.as_str()),
TokenKind::Ident => {
format!("`{}`", self.cx.interner.resolve(Symbol::from_raw(token.value)))
}
TokenKind::Int => "an integer constant".to_string(),
TokenKind::Float => "a floating constant".to_string(),
TokenKind::Char => "a character constant".to_string(),
TokenKind::Str => "a string literal".to_string(),
}
}
pub(crate) fn spelling(&self, name: Symbol) -> &str {
self.cx.interner.resolve(name)
}
pub(crate) fn expect_punct(&mut self, punct: Punct) -> bool {
if self.cursor.eat_punct(punct) {
return true;
}
let found = self.describe(self.cursor.current());
let message = format!("expected `{}`, found {found}", punct.as_str());
let at = if punct == Punct::Semi { self.cursor.prev_end() } else { self.cursor.span() };
self.error("E0400", message, at);
false
}
pub(crate) fn expect_keyword(&mut self, keyword: Keyword) -> bool {
if self.cursor.eat_keyword(keyword) {
return true;
}
let found = self.describe(self.cursor.current());
let message = format!("expected `{}`, found {found}", keyword.as_str());
self.error("E0400", message, self.cursor.span());
false
}
pub(crate) fn expect_ident(&mut self) -> Option<(Symbol, Span)> {
if let Some(name) = self.cursor.current().ident() {
let span = self.cursor.span();
self.cursor.bump();
return Some((name, span));
}
let found = self.describe(self.cursor.current());
self.error("E0401", format!("expected an identifier, found {found}"), self.cursor.span());
None
}
pub(crate) fn string_literal(&mut self) -> Option<StrId> {
let token = self.cursor.current();
if token.kind == TokenKind::Str {
self.cursor.bump();
let literal = self.tokens.strings[token.value as usize].clone();
return Some(self.ast.add_string(literal));
}
let found = self.describe(token);
self.error("E0409", format!("expected a string literal, found {found}"), token.span);
None
}
#[must_use]
pub(crate) fn enter(&mut self) -> bool {
if self.depth >= MAX_NESTING {
if !self.too_deep {
self.too_deep = true;
self.error(
"E0402",
format!("brackets nested more deeply than {MAX_NESTING} levels"),
self.cursor.span(),
);
}
return false;
}
self.depth += 1;
true
}
pub(crate) fn leave(&mut self) {
self.depth -= 1;
}
pub(crate) fn add_expr(&mut self, expr: Expr, span: Span) -> ExprId {
self.ast.expr(expr, span)
}
pub(crate) fn add_stmt(&mut self, stmt: Stmt, span: Span) -> StmtId {
self.ast.stmt(stmt, span)
}
pub(crate) fn add_decl(&mut self, decl: Decl, span: Span) -> DeclId {
self.ast.decl(decl, span)
}
pub(crate) fn poison_expr(&mut self, span: Span) -> ExprId {
self.ast.expr(Expr::Error, span)
}
pub(crate) fn poison_stmt(&mut self, span: Span) -> StmtId {
self.ast.stmt(Stmt::Error, span)
}
pub(crate) fn poison_decl(&mut self, span: Span) -> DeclId {
self.ast.decl(Decl::Error, span)
}
pub(crate) fn span_from(&self, start: Span) -> Span {
start.to(self.cursor.prev_end())
}
}