use crate::expression::Expression;
use crate::identifier::Identifier;
use crate::span::Spanned;
use crate::statement::Statement;
pub type ModuleItem = Spanned<ModuleItemKind>;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ModuleItemKind {
Statement(Statement),
Import(ImportDeclaration),
Export(ExportDeclaration),
}
impl std::fmt::Display for ModuleItemKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Statement(stmt) => write!(f, "{stmt}"),
Self::Import(decl) => write!(f, "{decl}"),
Self::Export(decl) => write!(f, "{decl}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ImportDeclaration {
specifiers: Vec<ImportSpecifier>,
source: String,
}
impl ImportDeclaration {
#[must_use]
pub fn new(specifiers: Vec<ImportSpecifier>, source: impl Into<String>) -> Self {
Self {
specifiers,
source: source.into(),
}
}
#[must_use]
pub fn specifiers(&self) -> &[ImportSpecifier] {
&self.specifiers
}
#[must_use]
pub fn source(&self) -> &str {
&self.source
}
}
impl std::fmt::Display for ImportDeclaration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let specs = self
.specifiers
.iter()
.map(|s| format!("{s}"))
.collect::<Vec<_>>()
.join(", ");
write!(f, "import {specs} from {:?};", self.source)
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ImportSpecifier {
Named {
imported: Identifier,
local: Identifier,
},
Default {
local: Identifier,
},
Namespace {
local: Identifier,
},
}
impl std::fmt::Display for ImportSpecifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Named { imported, local } => {
if imported == local {
write!(f, "{{ {imported} }}")
} else {
write!(f, "{{ {imported} as {local} }}")
}
}
Self::Default { local } => write!(f, "{local}"),
Self::Namespace { local } => write!(f, "* as {local}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExportDeclaration {
Named {
specifiers: Vec<ExportSpecifier>,
source: Option<String>,
},
Default {
declaration: ExportDefault,
},
Declaration {
declaration: Statement,
},
All {
exported: Option<Identifier>,
source: String,
},
}
impl std::fmt::Display for ExportDeclaration {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Named { specifiers, source } => {
write_export_named(f, specifiers, source.as_deref())
}
Self::Default { declaration } => write!(f, "export default {declaration};"),
Self::Declaration { declaration } => write!(f, "export {declaration}"),
Self::All { exported, source } => write_export_all(f, exported.as_ref(), source),
}
}
}
fn write_export_named(
f: &mut std::fmt::Formatter<'_>,
specifiers: &[ExportSpecifier],
source: Option<&str>,
) -> std::fmt::Result {
let specs = specifiers
.iter()
.map(|s| format!("{s}"))
.collect::<Vec<_>>()
.join(", ");
match source {
Some(src) => write!(f, "export {{ {specs} }} from {src:?};"),
None => write!(f, "export {{ {specs} }};"),
}
}
fn write_export_all(
f: &mut std::fmt::Formatter<'_>,
exported: Option<&Identifier>,
source: &str,
) -> std::fmt::Result {
match exported {
Some(name) => write!(f, "export * as {name} from {source:?};"),
None => write!(f, "export * from {source:?};"),
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ExportSpecifier {
local: Identifier,
exported: Identifier,
}
impl ExportSpecifier {
#[must_use]
pub fn new(local: Identifier, exported: Identifier) -> Self {
Self { local, exported }
}
#[must_use]
pub fn local(&self) -> &Identifier {
&self.local
}
#[must_use]
pub fn exported(&self) -> &Identifier {
&self.exported
}
}
impl std::fmt::Display for ExportSpecifier {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.local == self.exported {
write!(f, "{}", self.local)
} else {
write!(f, "{} as {}", self.local, self.exported)
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ExportDefault {
Expression(Expression),
Function(crate::function::Function),
Class(crate::class::Class),
}
impl std::fmt::Display for ExportDefault {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Expression(expr) => write!(f, "{expr}"),
Self::Function(func) => write!(f, "{func}"),
Self::Class(class) => write!(f, "{class}"),
}
}
}