use alloc::string::String;
use core::fmt;
use miden_debug_types::{SourceSpan, Span, Spanned};
use super::{ProcedureName, QualifiedProcedureName};
use crate::{
Word,
ast::{DocString, InvocationTarget},
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProcedureAlias {
docs: Option<DocString>,
name: ProcedureName,
target: AliasTarget,
}
impl ProcedureAlias {
pub fn new(name: ProcedureName, target: AliasTarget) -> Self {
Self { docs: None, name, target }
}
pub fn with_docs(mut self, docs: Option<Span<String>>) -> Self {
self.docs = docs.map(DocString::new);
self
}
pub fn docs(&self) -> Option<Span<&str>> {
self.docs.as_ref().map(|docstring| docstring.as_spanned_str())
}
#[inline]
pub fn name(&self) -> &ProcedureName {
&self.name
}
#[inline]
pub fn target(&self) -> &AliasTarget {
&self.target
}
#[inline]
pub fn target_mut(&mut self) -> &mut AliasTarget {
&mut self.target
}
#[inline]
pub fn is_absolute(&self) -> bool {
matches!(self.target, AliasTarget::MastRoot(_) | AliasTarget::AbsoluteProcedurePath(_))
}
#[inline]
pub fn is_renamed(&self) -> bool {
match self.target() {
AliasTarget::MastRoot(_) => true,
AliasTarget::ProcedurePath(fqn) | AliasTarget::AbsoluteProcedurePath(fqn) => {
fqn.name != self.name
},
}
}
}
impl Spanned for ProcedureAlias {
fn span(&self) -> SourceSpan {
self.target.span()
}
}
impl crate::prettier::PrettyPrint for ProcedureAlias {
fn render(&self) -> crate::prettier::Document {
use crate::prettier::*;
let mut doc = self
.docs
.as_ref()
.map(|docstring| docstring.render())
.unwrap_or(Document::Empty);
doc += const_text("pub proc ");
doc += match &self.target {
target @ AliasTarget::MastRoot(_) => display(format_args!("{}->{}", target, self.name)),
target => {
let prefix = if self.is_absolute() { "::" } else { "" };
if self.is_renamed() {
display(format_args!("{}{}->{}", prefix, target, &self.name))
} else {
display(format_args!("{prefix}{target}"))
}
},
};
doc
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AliasTarget {
MastRoot(Span<Word>),
ProcedurePath(QualifiedProcedureName),
AbsoluteProcedurePath(QualifiedProcedureName),
}
impl Spanned for AliasTarget {
fn span(&self) -> SourceSpan {
match self {
Self::MastRoot(spanned) => spanned.span(),
Self::ProcedurePath(spanned) | Self::AbsoluteProcedurePath(spanned) => spanned.span(),
}
}
}
impl From<Span<Word>> for AliasTarget {
fn from(digest: Span<Word>) -> Self {
Self::MastRoot(digest)
}
}
impl TryFrom<InvocationTarget> for AliasTarget {
type Error = InvocationTarget;
fn try_from(target: InvocationTarget) -> Result<Self, Self::Error> {
let span = target.span();
match target {
InvocationTarget::MastRoot(digest) => Ok(Self::MastRoot(digest)),
InvocationTarget::ProcedurePath { name, module } => {
let ns = crate::LibraryNamespace::from_ident_unchecked(module);
let module = crate::LibraryPath::new_from_components(ns, []);
Ok(Self::ProcedurePath(QualifiedProcedureName { span, module, name }))
},
InvocationTarget::AbsoluteProcedurePath { name, path: module } => {
Ok(Self::AbsoluteProcedurePath(QualifiedProcedureName { span, module, name }))
},
target @ InvocationTarget::ProcedureName(_) => Err(target),
}
}
}
impl From<&AliasTarget> for InvocationTarget {
fn from(target: &AliasTarget) -> Self {
match target {
AliasTarget::MastRoot(digest) => Self::MastRoot(*digest),
AliasTarget::ProcedurePath(fqn) => {
let name = fqn.name.clone();
let module = fqn.module.last_component().to_ident();
Self::ProcedurePath { name, module }
},
AliasTarget::AbsoluteProcedurePath(fqn) => Self::AbsoluteProcedurePath {
name: fqn.name.clone(),
path: fqn.module.clone(),
},
}
}
}
impl From<AliasTarget> for InvocationTarget {
fn from(target: AliasTarget) -> Self {
match target {
AliasTarget::MastRoot(digest) => Self::MastRoot(digest),
AliasTarget::ProcedurePath(fqn) => {
let name = fqn.name;
let module = fqn.module.last_component().to_ident();
Self::ProcedurePath { name, module }
},
AliasTarget::AbsoluteProcedurePath(fqn) => {
Self::AbsoluteProcedurePath { name: fqn.name, path: fqn.module }
},
}
}
}
impl crate::prettier::PrettyPrint for AliasTarget {
fn render(&self) -> crate::prettier::Document {
use miden_core::utils::DisplayHex;
use crate::prettier::*;
match self {
Self::MastRoot(digest) => display(DisplayHex(digest.as_bytes().as_slice())),
Self::ProcedurePath(fqn) => display(fqn),
Self::AbsoluteProcedurePath(fqn) => display(format_args!("::{fqn}")),
}
}
}
impl fmt::Display for AliasTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use crate::prettier::PrettyPrint;
self.pretty_print(f)
}
}