use crate::resolution::{BindingId, Usage};
use oxc_parser::AdmittedProgram;
use vize_l0::{Span, String};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ScriptUnitId(pub(crate) u32);
impl ScriptUnitId {
#[must_use]
pub const fn index(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct ScopeId(pub(crate) u32);
impl ScopeId {
#[must_use]
pub const fn index(self) -> u32 {
self.0
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Namespace {
Value,
Type,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct ScriptProfile {
pub typescript: bool,
pub jsx: bool,
pub module: bool,
}
#[derive(Debug)]
pub struct ScriptUnit {
pub id: ScriptUnitId,
pub span: Span,
pub profile: ScriptProfile,
pub scope: ScopeId,
walk: ProgramWalkState,
pub(crate) origin: ProgramOrigin,
}
#[derive(Debug)]
pub(crate) struct ProgramOrigin {
pub(crate) body: usize,
pub(crate) length: usize,
pub(crate) has_call: bool,
has_comments: bool,
pub(crate) has_export: bool,
pub(crate) reserved_binding: bool,
pub(crate) setup_eligible: bool,
pub(crate) ordinary_empty_eligible: bool,
pub(crate) module_source_gaps: u8,
}
impl ProgramOrigin {
pub(crate) fn checked(admitted: &AdmittedProgram<'_, '_>) -> Self {
let program = admitted.program();
Self {
body: program.body.as_ptr() as usize,
length: program.body.len(),
has_call: false,
has_comments: !program.comments.is_empty(),
has_export: false,
reserved_binding: false,
setup_eligible: crate::lang::js::file::setup::initial(program)
&& !admitted.has_legacy_literals(),
ordinary_empty_eligible: crate::lang::js::file::ordinary::initial(admitted),
module_source_gaps: 0,
}
}
}
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ProgramWalkState {
Pending,
Complete,
Interrupted,
}
impl ScriptUnit {
pub(crate) fn new(
id: ScriptUnitId,
span: Span,
profile: ScriptProfile,
scope: ScopeId,
origin: ProgramOrigin,
) -> Self {
Self {
id,
span,
profile,
scope,
walk: ProgramWalkState::Pending,
origin,
}
}
pub(crate) fn complete_walk(&mut self) {
if self.walk == ProgramWalkState::Pending {
self.walk = ProgramWalkState::Complete;
}
}
pub(crate) fn interrupt_walk(&mut self) {
if self.walk == ProgramWalkState::Pending {
self.walk = ProgramWalkState::Interrupted;
}
}
pub(crate) fn walk_completed(&self) -> bool {
self.walk == ProgramWalkState::Complete
}
#[must_use]
pub fn has_invocations(&self) -> bool {
self.origin.has_call
}
#[must_use]
pub fn has_comments(&self) -> bool {
self.origin.has_comments
}
#[must_use]
pub fn interruption(&self) -> Option<FileIssue> {
(self.walk == ProgramWalkState::Interrupted).then_some(FileIssue {
unit: self.id,
span: self.span,
kind: FileIssueKind::InterruptedProgram,
})
}
}
#[derive(Debug)]
pub struct Scope {
pub id: ScopeId,
pub parent: Option<ScopeId>,
pub span: Span,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeclarationKind {
Const,
Let,
Var,
Import,
Function,
Parameter,
Class,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InitializerKind {
PrimitiveLiteral,
Function,
Unknown,
PrimitiveStringWithNulOrCr,
PrimitiveStringWithLoneSurrogates,
}
impl InitializerKind {
#[must_use]
pub const fn is_primitive(self) -> bool {
matches!(
self,
Self::PrimitiveLiteral
| Self::PrimitiveStringWithNulOrCr
| Self::PrimitiveStringWithLoneSurrogates
)
}
}
#[derive(Debug)]
pub struct Declaration {
pub id: BindingId,
pub unit: ScriptUnitId,
pub scope: ScopeId,
pub name: String,
pub span: Span,
pub namespace: Namespace,
pub kind: DeclarationKind,
pub initializer: InitializerKind,
pub import_source: Option<String>,
pub imported_name: Option<String>,
pub(crate) direct_program: bool,
}
impl Declaration {
#[must_use]
pub fn is_direct_program(&self) -> bool {
self.direct_program
}
#[must_use]
pub fn script_unit(&self) -> Option<ScriptUnitId> {
Some(self.unit)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReferenceTarget {
Resolved(BindingId),
Unresolved,
}
#[derive(Debug)]
pub struct Reference {
pub unit: ScriptUnitId,
pub scope: ScopeId,
pub name: String,
pub span: Span,
pub usage: Usage,
pub shorthand: bool,
pub constructor: bool,
pub namespace: Namespace,
pub target: ReferenceTarget,
}
#[derive(Debug)]
pub struct Export {
pub unit: ScriptUnitId,
pub name: String,
pub local: Option<BindingId>,
pub source: Option<String>,
pub namespace: Namespace,
pub span: Span,
pub(crate) local_reference: Option<usize>,
pub(crate) source_site: Option<super::SourceSite>,
}
#[derive(Debug)]
pub struct Import {
pub unit: ScriptUnitId,
pub source: String,
pub namespace: Namespace,
pub span: Span,
pub(crate) source_site: Option<super::SourceSite>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct FileIssue {
pub unit: ScriptUnitId,
pub span: Span,
pub kind: FileIssueKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FileIssueKind {
InvalidSource,
InvalidProfile,
InvalidSpan,
DuplicateUnit,
DuplicateDeclaration,
UnresolvedReference,
UnsupportedSyntax,
BindingLimit,
UnsupportedComponent,
InterruptedProgram,
InterruptedTemplate,
ActiveTemplateWalk,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TemplateIssue {
pub node: Option<vize_l0::id::NodeId>,
pub span: Span,
pub kind: FileIssueKind,
}