use super::{BindingLookup, ResolutionError, walk};
use crate::lang::js::NativeHandlerInput;
use alloc::boxed::Box;
use vize_l0::Span;
pub(crate) struct ResolvedHandlerFacts<'a> {
body: &'a oxc_ast::ast::FunctionBody<'a>,
source: vize_l1::embed::EmbedSource<'a>,
tables: Tables<'a>,
}
impl<'a> ResolvedHandlerFacts<'a> {
pub(crate) fn join(
self,
input: &mut Option<NativeHandlerInput<'a>>,
) -> Option<HandlerResolution<'a>> {
let original = input.as_ref()?;
let source = original.operand().syntax().source();
if !core::ptr::eq(self.body, original.body())
|| !core::ptr::eq(self.source.authored_root(), source.authored_root())
|| !core::ptr::eq(self.source.text(), source.text())
|| self.source.span() != source.span()
{
return None;
}
Some(HandlerResolution {
input: input.take()?,
tables: self.tables,
})
}
}
pub(crate) fn resolve_handler_facts<'a>(
input: &NativeHandlerInput<'a>,
bindings: &impl BindingLookup,
) -> Result<ResolvedHandlerFacts<'a>, ResolutionError> {
let source = input.references();
let mut pending = Pending::new();
walk::handler_body(&source, &mut pending)?;
let tables = pending.finish(bindings)?;
Ok(ResolvedHandlerFacts {
body: input.body(),
source: input.operand().syntax().source(),
tables,
})
}
mod facts;
pub use facts::{
HandlerBinding, HandlerBindingRef, HandlerDeclaration, HandlerDeclarationKind, HandlerLocalId,
HandlerReference, HandlerScope, HandlerScopeId, HandlerSyntax,
};
pub(super) mod sink;
use sink::{Pending, Tables};
#[derive(Debug)]
pub struct HandlerResolution<'a> {
input: NativeHandlerInput<'a>,
tables: Tables<'a>,
}
impl<'a> HandlerResolution<'a> {
#[must_use]
pub const fn input(&self) -> &NativeHandlerInput<'a> {
&self.input
}
#[must_use]
pub fn scopes(&self) -> &[HandlerScope] {
&self.tables.scopes
}
#[must_use]
pub fn bindings(&self) -> &[HandlerBinding<'a>] {
&self.tables.bindings
}
#[must_use]
pub fn declarations(&self) -> &[HandlerDeclaration<'a>] {
&self.tables.declarations
}
#[must_use]
pub fn references(&self) -> &[HandlerReference<'a>] {
&self.tables.references
}
#[must_use]
pub const fn syntax(&self) -> HandlerSyntax {
self.tables.syntax
}
#[must_use]
pub fn into_input(self) -> NativeHandlerInput<'a> {
self.input
}
pub fn authored_span(&self, span: Span) -> Result<Span, vize_l1::embed::SourceError> {
self.input.operand().syntax().source().authored_span(span)
}
}
#[derive(Debug)]
pub struct RejectedHandlerResolution<'a> {
input: NativeHandlerInput<'a>,
pub error: ResolutionError,
}
impl<'a> RejectedHandlerResolution<'a> {
#[must_use]
pub const fn input(&self) -> &NativeHandlerInput<'a> {
&self.input
}
#[must_use]
pub fn into_input(self) -> NativeHandlerInput<'a> {
self.input
}
}
pub fn resolve_handler<'a>(
input: NativeHandlerInput<'a>,
bindings: &impl BindingLookup,
) -> Result<HandlerResolution<'a>, Box<RejectedHandlerResolution<'a>>> {
let result = {
let source = input.references();
let mut pending = Pending::new();
walk::handler_body(&source, &mut pending).and_then(|()| pending.finish(bindings))
};
match result {
Ok(tables) => Ok(HandlerResolution { input, tables }),
Err(error) => Err(Box::new(RejectedHandlerResolution { input, error })),
}
}
#[cfg(test)]
mod tests;