use std::fmt; use std::future::Future; use std::ops::RangeInclusive; use futures::FutureExt; use futures::future::LocalBoxFuture; use orchid_base::error::{OrcErrv, OrcRes, Reporter, mk_errv}; use orchid_base::interner::{Interner, Tok}; use orchid_base::location::{Pos, SrcRange}; use orchid_base::name::Sym; use orchid_base::parse::ParseCtx; use orchid_base::reqnot::Requester; use crate::api; use crate::context::{ctx, i}; use crate::expr::BorrowedExprStore; use crate::parser::PTokTree; use crate::tree::GenTokTree; pub async fn ekey_cascade() -> Tok { i().i("An error cascading from a recursive call").await } pub async fn ekey_not_applicable() -> Tok { i().i("Pseudo-error to communicate that the current branch in a dispatch doesn't apply").await } const MSG_INTERNAL_ERROR: &str = "This error is a sentinel for the extension library.\ it should not be emitted by the extension."; pub async fn err_cascade() -> OrcErrv { mk_errv(ekey_cascade().await, MSG_INTERNAL_ERROR, [Pos::None]) } pub async fn err_not_applicable() -> OrcErrv { mk_errv(ekey_not_applicable().await, MSG_INTERNAL_ERROR, [Pos::None]) } pub struct LexContext<'a> { pub(crate) exprs: &'a BorrowedExprStore, pub text: &'a Tok, pub id: api::ParsId, pub pos: u32, i: Interner, pub(crate) src: Sym, pub(crate) rep: &'a Reporter, } impl<'a> LexContext<'a> { pub fn new( exprs: &'a BorrowedExprStore, text: &'a Tok, id: api::ParsId, pos: u32, src: Sym, rep: &'a Reporter, ) -> Self { Self { exprs, i: i(), id, pos, rep, src, text } } pub fn src(&self) -> &Sym { &self.src } /// This function returns [PTokTree] because it can never return /// [orchid_base::tree::Token::NewExpr]. You can use /// [crate::parser::p_tree2gen] to convert this to [crate::tree::GenTokTree] /// for embedding in the return value. pub async fn recurse(&self, tail: &'a str) -> OrcRes<(&'a str, PTokTree)> { let start = self.pos(tail); let Some(lx) = ctx().reqnot().request(api::SubLex { pos: start, id: self.id }).await else { return Err(err_cascade().await); }; let tree = PTokTree::from_api(&lx.tree, &mut { self.exprs }, &mut (), &self.src, &i()).await; Ok((&self.text[lx.pos as usize..], tree)) } pub fn pos(&self, tail: &'a str) -> u32 { (self.text.len() - tail.len()) as u32 } pub fn pos_tt(&self, tail_with: &'a str, tail_without: &'a str) -> SrcRange { SrcRange::new(self.pos(tail_with)..self.pos(tail_without), &self.src) } pub fn pos_lt(&self, len: impl TryInto, tail: &'a str) -> SrcRange { SrcRange::new(self.pos(tail) - len.try_into().unwrap()..self.pos(tail), &self.src) } } impl ParseCtx for LexContext<'_> { fn i(&self) -> &Interner { &self.i } fn rep(&self) -> &Reporter { self.rep } } pub trait Lexer: Send + Sync + Sized + Default + 'static { const CHAR_FILTER: &'static [RangeInclusive]; fn lex<'a>( tail: &'a str, lctx: &'a LexContext<'a>, ) -> impl Future>; } pub trait DynLexer: Send + Sync + 'static { fn char_filter(&self) -> &'static [RangeInclusive]; fn lex<'a>( &self, tail: &'a str, ctx: &'a LexContext<'a>, ) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree)>>; } impl DynLexer for T { fn char_filter(&self) -> &'static [RangeInclusive] { T::CHAR_FILTER } fn lex<'a>( &self, tail: &'a str, ctx: &'a LexContext<'a>, ) -> LocalBoxFuture<'a, OrcRes<(&'a str, GenTokTree)>> { T::lex(tail, ctx).boxed_local() } } pub type LexerObj = &'static dyn DynLexer;