use alloc::boxed::Box;
use vize_l0::Span;
use vize_l1::embed::syntax::ForHeadPart;
use super::{BindingId, BindingLookup, Occurrence, ResolutionErrorKind, walk};
use crate::lang::js::NativeForInput;
mod borrowed;
pub(crate) use borrowed::resolve_for_facts;
mod declaration;
mod facts;
mod sink;
pub use declaration::ForAliasDeclaration;
pub(in crate::resolution) use declaration::OriginalForAlias;
pub use facts::{ForAlias, ForAliasId, ForAliasRole, ForResolvedBinding};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ForResolutionError {
pub part: ForHeadPart,
pub span: Span,
pub kind: ForResolutionErrorKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ForResolutionErrorKind {
Reference(ResolutionErrorKind),
UnsupportedAlias,
DuplicateAlias,
ReservedAlias,
}
#[derive(Debug)]
pub struct RejectedForResolution<'a> {
input: NativeForInput<'a>,
pub error: ForResolutionError,
}
impl<'a> RejectedForResolution<'a> {
#[must_use]
pub const fn input(&self) -> &NativeForInput<'a> {
&self.input
}
#[must_use]
pub fn into_input(self) -> NativeForInput<'a> {
self.input
}
}
#[derive(Debug)]
pub struct ForResolution<'a> {
input: NativeForInput<'a>,
collection: Occurrence<'a>,
collection_authored: Span,
value: ForAlias<'a>,
key: Option<ForAlias<'a>>,
value_parameter: &'a oxc_ast::ast::FormalParameter<'a>,
key_parameter: Option<&'a oxc_ast::ast::FormalParameter<'a>>,
}
impl<'a> ForResolution<'a> {
#[must_use]
pub const fn input(&self) -> &NativeForInput<'a> {
&self.input
}
#[must_use]
pub const fn collection(&self) -> Occurrence<'a> {
self.collection
}
#[must_use]
pub const fn collection_occurrence(&self) -> &Occurrence<'a> {
&self.collection
}
#[must_use]
pub const fn collection_authored_span(&self) -> Span {
self.collection_authored
}
#[must_use]
pub const fn value(&self) -> ForAlias<'a> {
self.value
}
#[must_use]
pub const fn key(&self) -> Option<ForAlias<'a>> {
self.key
}
pub fn lookup_body(
&self,
name: &str,
enclosing: &impl BindingLookup,
) -> Option<ForResolvedBinding> {
if self.value.name() == name {
return Some(ForResolvedBinding::Local(self.value.id()));
}
if let Some(key) = self.key.filter(|key| key.name() == name) {
return Some(ForResolvedBinding::Local(key.id()));
}
enclosing.lookup(name).map(ForResolvedBinding::Enclosing)
}
#[must_use]
pub fn into_input(self) -> NativeForInput<'a> {
self.input
}
}
pub fn resolve_for_head<'a>(
input: NativeForInput<'a>,
enclosing: &impl BindingLookup,
) -> Result<ForResolution<'a>, Box<RejectedForResolution<'a>>> {
match borrowed::resolve_for_facts(&input, enclosing) {
Ok(facts) => facts.join(input).map_err(|input| {
Box::new(RejectedForResolution {
input: *input,
error: borrowed::invalid_source(),
})
}),
Err(error) => Err(Box::new(RejectedForResolution { input, error })),
}
}
type Facts<'a> = (
Occurrence<'a>,
Span,
OriginalForAlias<'a>,
Option<OriginalForAlias<'a>>,
);
fn resolve<'a>(
input: &NativeForInput<'a>,
enclosing: &impl BindingLookup,
) -> Result<Facts<'a>, ForResolutionError> {
let source = input.references().ok_or(ForResolutionError {
part: ForHeadPart::Collection,
span: Span::new(0, 0),
kind: ForResolutionErrorKind::Reference(ResolutionErrorKind::InvalidSpan),
})?;
let mut sink = sink::Collection::new(enclosing);
let (value, key) = walk::original_for_head(&source, &mut sink)?;
let collection = sink.finish()?;
let collection_authored = source
.collection_authored_span(source.collection().span())
.map_err(|_| ForResolutionError {
part: ForHeadPart::Collection,
span: collection.span,
kind: ForResolutionErrorKind::Reference(ResolutionErrorKind::InvalidSpan),
})?;
Ok((collection, collection_authored, value, key))
}
use oxc_span::GetSpan;
#[cfg(test)]
mod tests;