use std::collections::BTreeMap;
use encoding::LibName;
use strict_encoding::TypeName;
use crate::typelib::{Dependency, ExternTypes, InlineRef, InlineRef1, InlineRef2, LibRef};
use crate::{SemId, Translate, TranspileError, TranspileRef, Ty};
pub type TypeIndex = BTreeMap<TypeName, SemId>;
#[deprecated(since = "1.3.0", note = "use CompileError")]
pub type TranslateError = CompileError;
#[derive(Clone, Eq, PartialEq, Debug, Display, Error, From)]
#[display(doc_comments)]
pub enum CompileError {
DuplicateName(TypeName),
UnknownType {
unknown: TypeName,
within: Ty<TranspileRef>,
},
Continue,
DuplicatedDependency(Dependency),
NestedInline(TypeName, String, String),
UnknownLib(LibName),
TooManyDependencies,
TooManyTypes,
LibTooLarge(LibName),
}
impl From<TranspileError> for CompileError {
fn from(err: TranspileError) -> Self {
match err {
TranspileError::UnknownType { unknown, within } => {
Self::UnknownType { unknown, within }
}
TranspileError::UnknownLib(lib) => Self::UnknownLib(lib),
TranspileError::TooManyDependencies => Self::TooManyDependencies,
TranspileError::TooManyTypes => Self::TooManyTypes,
TranspileError::LibTooLarge(lib) => Self::LibTooLarge(lib),
}
}
}
pub struct NestedContext {
pub top_name: TypeName,
pub index: TypeIndex,
pub extern_types: ExternTypes,
pub stack: Vec<String>,
}
impl Translate<LibRef> for TranspileRef {
type Context = ();
type Builder = NestedContext;
type Error = CompileError;
fn translate(
self,
builder: &mut Self::Builder,
ctx: &Self::Context,
) -> Result<LibRef, Self::Error> {
match self {
TranspileRef::Embedded(ty) => {
builder.stack.push(ty.cls().to_string());
let res = ty.translate(builder, ctx).map(LibRef::Inline);
builder.stack.pop();
res
}
TranspileRef::Named(name) => {
let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
Ok(LibRef::Named(*id))
}
TranspileRef::Extern(ext) => Ok(LibRef::Extern(ext.into())),
}
}
}
impl Translate<InlineRef> for TranspileRef {
type Context = ();
type Builder = NestedContext;
type Error = CompileError;
fn translate(
self,
builder: &mut Self::Builder,
ctx: &Self::Context,
) -> Result<InlineRef, Self::Error> {
match self {
TranspileRef::Embedded(ty) => {
builder.stack.push(ty.cls().to_string());
let res = ty.translate(builder, ctx).map(InlineRef::Inline);
builder.stack.pop();
res
}
TranspileRef::Named(name) => {
let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
Ok(InlineRef::Named(*id))
}
TranspileRef::Extern(ext) => Ok(InlineRef::Extern(ext.into())),
}
}
}
impl Translate<InlineRef1> for TranspileRef {
type Context = ();
type Builder = NestedContext;
type Error = CompileError;
fn translate(
self,
builder: &mut Self::Builder,
ctx: &Self::Context,
) -> Result<InlineRef1, Self::Error> {
match self {
TranspileRef::Embedded(ty) => {
builder.stack.push(ty.cls().to_string());
let res = ty.translate(builder, ctx).map(InlineRef1::Inline);
builder.stack.pop();
res
}
TranspileRef::Named(name) => {
let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
Ok(InlineRef1::Named(*id))
}
TranspileRef::Extern(ext) => Ok(InlineRef1::Extern(ext.into())),
}
}
}
impl Translate<InlineRef2> for TranspileRef {
type Context = ();
type Builder = NestedContext;
type Error = CompileError;
fn translate(
self,
builder: &mut Self::Builder,
_ctx: &Self::Context,
) -> Result<InlineRef2, Self::Error> {
match self {
TranspileRef::Embedded(_ty) => {
let mut path = builder.stack.clone();
let name = path.pop().unwrap_or_else(|| s!("<unnamed>"));
Err(CompileError::NestedInline(builder.top_name.clone(), path.join("."), name))
}
TranspileRef::Named(name) => {
let id = builder.index.get(&name).ok_or(CompileError::Continue)?;
Ok(InlineRef2::Named(*id))
}
TranspileRef::Extern(ext) => Ok(InlineRef2::Extern(ext.into())),
}
}
}