use std::sync::Arc;
use crate::parser::ast::stmt::{Ast, Stmt};
use crate::parser::core::error::{ParseError, ParseErrorKind};
use crate::parser::parsing::expr_parser::parse_expression_with_context;
use crate::parser::parsing::parse_context::{ParseContext, RecoveryScope};
use crate::parser::parsing::stmt_parser::StmtParser;
use crate::parser::TokenKind;
use linkrs_core::types::expr::contextual::ContextualExpression;
use linkrs_core::types::expr::expression_context::ExpressionAnalysisContext;
#[derive(Debug, Clone)]
pub struct ParserResult {
pub ast: Arc<Ast>,
}
pub struct Parser<'a> {
ctx: ParseContext<'a>,
expr_context: Arc<ExpressionAnalysisContext>,
}
impl<'a> Parser<'a> {
pub fn new(input: &'a str) -> Self {
let expr_context = Arc::new(ExpressionAnalysisContext::new());
let mut ctx = ParseContext::new(input);
ctx.set_expression_context(expr_context.clone());
Self { ctx, expr_context }
}
pub fn with_type_alias_manager(
mut self,
manager: Arc<linkrs_core::metadata::TypeAliasManager>,
) -> Self {
self.ctx.set_type_alias_manager(manager);
self
}
pub fn from_string(input: String) -> Self {
let expr_context = Arc::new(ExpressionAnalysisContext::new());
let mut ctx = ParseContext::from_string(input);
ctx.set_expression_context(expr_context.clone());
Self { ctx, expr_context }
}
pub fn set_compat_mode(&mut self, enabled: bool) {
self.ctx.set_compat_mode(enabled);
}
pub fn parse(&mut self) -> Result<ParserResult, ParseError> {
let expr_context = Arc::new(ExpressionAnalysisContext::new());
self.ctx.set_expression_context(expr_context.clone());
self.expr_context = expr_context;
self.ctx.reset_recovery_count();
let stmt = match self.parse_statement() {
Ok(stmt) => stmt,
Err(e) => {
let recorded = self.ctx.errors();
if !recorded.is_empty() {
let first = &recorded.errors[0];
return Err(ParseError {
kind: first.kind.clone(),
message: Box::from(first.message.as_ref()),
position: first.position,
offset: first.offset,
unexpected_token: first
.unexpected_token
.as_ref()
.map(|t| Box::from(t.as_ref())),
expected_tokens: first.expected_tokens.clone(),
context: None,
hints: first.hints.clone(),
recovered: first.recovered,
});
}
return Err(e);
}
};
if self.ctx.match_token(TokenKind::Semicolon) {
}
if self.ctx.current_token().kind != TokenKind::Eof {
self.ctx.add_error(ParseError::new(
ParseErrorKind::UnexpectedToken,
format!(
"Unexpected token after end of statement: {:?}",
self.ctx.current_token().kind
),
self.ctx.current_position(),
));
}
let ast = Ast::new(stmt, self.expr_context.clone());
Ok(ParserResult { ast: Arc::new(ast) })
}
pub fn parse_statement(&mut self) -> Result<Stmt, ParseError> {
if self.ctx.is_recovery_exhausted() {
return Err(ParseError::new(
crate::parser::core::error::ParseErrorKind::SyntaxError,
"Too many parse errors, aborting".to_string(),
self.ctx.current_position(),
));
}
match StmtParser::parse_statement(&mut self.ctx) {
Ok(stmt) => Ok(stmt),
Err(e) => {
if self.ctx.is_recovery_exhausted() {
Err(e)
} else {
self.ctx.try_recover(e, RecoveryScope::Statement)?;
self.parse_statement()
}
}
}
}
pub fn parse_expression_contextual(&mut self) -> Result<ContextualExpression, ParseError> {
match parse_expression_with_context(&mut self.ctx, self.expr_context.clone()) {
Ok(expr) => Ok(expr),
Err(e) => {
if self.ctx.is_recovery_exhausted() {
Err(e)
} else {
self.ctx.try_recover(e, RecoveryScope::Expression)?;
self.parse_expression_contextual()
}
}
}
}
pub fn expression_context(&self) -> &Arc<ExpressionAnalysisContext> {
&self.expr_context
}
pub fn expression_context_clone(&self) -> Arc<ExpressionAnalysisContext> {
self.expr_context.clone()
}
pub fn has_errors(&self) -> bool {
self.ctx.has_errors()
}
pub fn errors(&self) -> &crate::parser::ParseErrors {
self.ctx.errors()
}
pub fn take_errors(&mut self) -> crate::parser::ParseErrors {
self.ctx.take_errors()
}
}