use core::fmt;
use bytecode_lang::BuildError;
use hir_lang::{NodeRef, Span, Symbol};
use crate::intrinsics::Arity;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum Unsupported {
Class,
Record,
Reference,
RefPlace,
VarVar,
Intrinsic,
Asm,
BigInt,
ForeignUnit,
TypeDirected,
ExternValue,
ExternArgs,
Conversion,
Cast,
Pattern,
}
impl Unsupported {
#[must_use]
pub const fn describe(self) -> &'static str {
match self {
Self::Class => {
"classes, impls, mixins, and receiver parameters arrive in bcgen-lang 0.5"
}
Self::Record => {
"declared record, struct, and sum types arrive with classes in bcgen-lang 0.5"
}
Self::Reference => {
"dereference, borrow, and by-reference patterns (the dynamic profile has no pointer values)"
}
Self::RefPlace => {
"a reference to an appended element, a variable variable, or a value that is not a place"
}
Self::VarVar => "variable variables (LSB frames have no names at run time)",
Self::Intrinsic => "atomic, volatile, and fence intrinsics (native backends only)",
Self::Asm => "inline assembly (native backends only)",
Self::BigInt => "big-integer literals (no big-integer runtime yet)",
Self::ForeignUnit => {
"definitions of another unit (LSB modules link to host functions only)"
}
Self::TypeDirected => {
"type-directed paths and type-level values arrive with typed fast paths in bcgen-lang 0.5"
}
Self::ExternValue => {
"a host function used as a value (its parameter list is unknown to the compiler)"
}
Self::ExternArgs => "spread or named arguments to a host function",
Self::Conversion => "a conversion at a width dynamic values do not have",
Self::Cast => "a cast to a type the dynamic profile cannot test or produce",
Self::Pattern => "a pattern form the dynamic profile cannot test",
}
}
}
impl fmt::Display for Unsupported {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.describe())
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[non_exhaustive]
pub enum CompileError {
Unsupported {
feature: Unsupported,
node: NodeRef,
span: Span,
},
Unresolved {
node: NodeRef,
span: Span,
},
ErrorNode {
node: NodeRef,
span: Span,
},
LiteralOutOfRange {
node: NodeRef,
span: Span,
},
NotAssignable {
node: NodeRef,
span: Span,
},
UnknownIntrinsic {
name: Symbol,
node: NodeRef,
span: Span,
},
IntrinsicArity {
node: NodeRef,
span: Span,
arity: Arity,
found: u32,
},
TooManyArgs {
node: NodeRef,
span: Span,
limit: u32,
},
TooManyParams {
node: NodeRef,
span: Span,
limit: u32,
},
TooManyJumps {
node: NodeRef,
span: Span,
},
BudgetExceeded {
limit: u64,
},
Build(BuildError),
}
impl CompileError {
#[must_use]
pub const fn node(&self) -> Option<NodeRef> {
match *self {
Self::Unsupported { node, .. }
| Self::Unresolved { node, .. }
| Self::ErrorNode { node, .. }
| Self::LiteralOutOfRange { node, .. }
| Self::NotAssignable { node, .. }
| Self::UnknownIntrinsic { node, .. }
| Self::IntrinsicArity { node, .. }
| Self::TooManyArgs { node, .. }
| Self::TooManyParams { node, .. }
| Self::TooManyJumps { node, .. } => Some(node),
Self::BudgetExceeded { .. } | Self::Build(_) => None,
}
}
#[must_use]
pub const fn span(&self) -> Option<Span> {
match *self {
Self::Unsupported { span, .. }
| Self::Unresolved { span, .. }
| Self::ErrorNode { span, .. }
| Self::LiteralOutOfRange { span, .. }
| Self::NotAssignable { span, .. }
| Self::UnknownIntrinsic { span, .. }
| Self::IntrinsicArity { span, .. }
| Self::TooManyArgs { span, .. }
| Self::TooManyParams { span, .. }
| Self::TooManyJumps { span, .. } => Some(span),
Self::BudgetExceeded { .. } | Self::Build(_) => None,
}
}
}
impl fmt::Display for CompileError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Unsupported { feature, span, .. } => {
write!(f, "unsupported at {span:?}: {feature}")
}
Self::Unresolved { span, .. } => write!(f, "unresolved path at {span:?}"),
Self::ErrorNode { span, .. } => write!(f, "error node at {span:?}"),
Self::LiteralOutOfRange { span, .. } => {
write!(f, "integer literal at {span:?} is outside the i64 range")
}
Self::NotAssignable { span, .. } => {
write!(f, "assignment target at {span:?} is not a writable place")
}
Self::UnknownIntrinsic { span, .. } => {
write!(f, "intrinsic at {span:?} is not in the intrinsic table")
}
Self::IntrinsicArity {
span, arity, found, ..
} => {
write!(
f,
"intrinsic at {span:?} takes {arity} operands, not {found}"
)
}
Self::TooManyArgs { span, limit, .. } => {
write!(f, "call at {span:?} has more than {limit} arguments")
}
Self::TooManyParams { span, limit, .. } => {
write!(f, "function at {span:?} has more than {limit} parameters")
}
Self::TooManyJumps { span, .. } => write!(
f,
"finally at {span:?} is left by more than 124 distinct jump targets"
),
Self::BudgetExceeded { limit } => {
write!(f, "the instruction budget of {limit} ran out")
}
Self::Build(e) => write!(f, "LSB builder: {e}"),
}
}
}
impl core::error::Error for CompileError {}
impl From<BuildError> for CompileError {
fn from(e: BuildError) -> Self {
Self::Build(e)
}
}