621 lines
22 KiB
Rust
621 lines
22 KiB
Rust
use crate::util::maybe;
|
|
|
|
use super::{typecheck::typerefs::TypeRefs, *};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum ReturnTypeOther {
|
|
Import(Metadata),
|
|
Let(Metadata),
|
|
Set(Metadata),
|
|
EmptyBlock(Metadata),
|
|
NoBlockReturn(Metadata),
|
|
IndexingNonArray(Metadata),
|
|
DerefNonBorrow(Metadata),
|
|
Loop,
|
|
}
|
|
|
|
#[derive(thiserror::Error, Debug, Clone, PartialEq, PartialOrd)]
|
|
pub enum NumValueError {
|
|
#[error("Cannot divide by zero")]
|
|
DivideZero,
|
|
}
|
|
|
|
enum BlockReturn<'b> {
|
|
Early(&'b Statement),
|
|
Normal(ReturnKind, &'b Option<Box<Expression>>),
|
|
}
|
|
|
|
impl TypeKind {
|
|
pub fn signed(&self) -> bool {
|
|
match self {
|
|
TypeKind::Bool => false,
|
|
TypeKind::I8 => true,
|
|
TypeKind::I16 => true,
|
|
TypeKind::I32 => true,
|
|
TypeKind::I64 => true,
|
|
TypeKind::I128 => true,
|
|
TypeKind::U8 => false,
|
|
TypeKind::U16 => false,
|
|
TypeKind::U32 => false,
|
|
TypeKind::U64 => false,
|
|
TypeKind::U128 => false,
|
|
TypeKind::Void => false,
|
|
TypeKind::Char => false,
|
|
TypeKind::Array(..) => false,
|
|
TypeKind::CustomType(..) => false,
|
|
TypeKind::CodegenPtr(..) => false,
|
|
TypeKind::Vague(..) => false,
|
|
TypeKind::Borrow(..) => false,
|
|
TypeKind::UserPtr(..) => false,
|
|
TypeKind::F16 => true,
|
|
TypeKind::F32B => true,
|
|
TypeKind::F32 => true,
|
|
TypeKind::F64 => true,
|
|
TypeKind::F128 => true,
|
|
TypeKind::F80 => true,
|
|
TypeKind::F128PPC => true,
|
|
}
|
|
}
|
|
|
|
pub fn size_of(&self) -> u64 {
|
|
match self {
|
|
TypeKind::Bool => 1,
|
|
TypeKind::I8 => 8,
|
|
TypeKind::U8 => 8,
|
|
TypeKind::I16 => 16,
|
|
TypeKind::U16 => 16,
|
|
TypeKind::I32 => 32,
|
|
TypeKind::U32 => 32,
|
|
TypeKind::I64 => 64,
|
|
TypeKind::U64 => 64,
|
|
TypeKind::I128 => 128,
|
|
TypeKind::U128 => 128,
|
|
TypeKind::Void => 0,
|
|
TypeKind::Char => 8,
|
|
TypeKind::Array(type_kind, len) => type_kind.size_of() * (*len as u64),
|
|
TypeKind::CustomType(..) => 32,
|
|
TypeKind::CodegenPtr(_) => 64,
|
|
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
|
TypeKind::Borrow(..) => 64,
|
|
TypeKind::UserPtr(_) => 64,
|
|
TypeKind::F16 => 16,
|
|
TypeKind::F32B => 16,
|
|
TypeKind::F32 => 32,
|
|
TypeKind::F64 => 64,
|
|
TypeKind::F128 => 128,
|
|
TypeKind::F80 => 80,
|
|
TypeKind::F128PPC => 128,
|
|
}
|
|
}
|
|
|
|
pub fn alignment(&self) -> u32 {
|
|
match self {
|
|
TypeKind::Bool => 1,
|
|
TypeKind::I8 => 8,
|
|
TypeKind::U8 => 8,
|
|
TypeKind::I16 => 16,
|
|
TypeKind::U16 => 16,
|
|
TypeKind::I32 => 32,
|
|
TypeKind::U32 => 32,
|
|
TypeKind::I64 => 64,
|
|
TypeKind::U64 => 64,
|
|
TypeKind::I128 => 128,
|
|
TypeKind::U128 => 128,
|
|
TypeKind::Void => 0,
|
|
TypeKind::Char => 8,
|
|
TypeKind::Array(type_kind, _) => type_kind.alignment(),
|
|
TypeKind::CustomType(..) => 32,
|
|
TypeKind::CodegenPtr(_) => 64,
|
|
TypeKind::Vague(_) => panic!("Tried to sizeof a vague type!"),
|
|
TypeKind::Borrow(_, _) => 64,
|
|
TypeKind::UserPtr(_) => 64,
|
|
TypeKind::F16 => 16,
|
|
TypeKind::F32B => 16,
|
|
TypeKind::F32 => 32,
|
|
TypeKind::F64 => 64,
|
|
TypeKind::F128 => 128,
|
|
TypeKind::F80 => 80,
|
|
TypeKind::F128PPC => 128,
|
|
}
|
|
}
|
|
|
|
pub fn is_mutable(&self) -> bool {
|
|
match self {
|
|
TypeKind::Borrow(_, false) => false,
|
|
_ => true,
|
|
}
|
|
}
|
|
|
|
pub fn category(&self) -> TypeCategory {
|
|
match self {
|
|
TypeKind::I8
|
|
| TypeKind::I16
|
|
| TypeKind::I32
|
|
| TypeKind::I64
|
|
| TypeKind::I128
|
|
| TypeKind::U8
|
|
| TypeKind::U16
|
|
| TypeKind::U32
|
|
| TypeKind::U64
|
|
| TypeKind::U128
|
|
| TypeKind::Char => TypeCategory::Integer,
|
|
TypeKind::F16
|
|
| TypeKind::F32B
|
|
| TypeKind::F32
|
|
| TypeKind::F64
|
|
| TypeKind::F128
|
|
| TypeKind::F80
|
|
| TypeKind::F128PPC => TypeCategory::Real,
|
|
TypeKind::Void => TypeCategory::Other,
|
|
TypeKind::Bool => TypeCategory::Bool,
|
|
TypeKind::Array(_, _) => TypeCategory::Other,
|
|
TypeKind::CustomType(..) => TypeCategory::Other,
|
|
TypeKind::Borrow(_, _) => TypeCategory::Other,
|
|
TypeKind::UserPtr(_) => TypeCategory::Other,
|
|
TypeKind::CodegenPtr(_) => TypeCategory::Other,
|
|
TypeKind::Vague(vague_type) => match vague_type {
|
|
VagueType::Unknown => TypeCategory::Other,
|
|
VagueType::Integer => TypeCategory::Integer,
|
|
VagueType::Decimal => TypeCategory::Real,
|
|
VagueType::TypeRef(_) => TypeCategory::TypeRef,
|
|
},
|
|
}
|
|
}
|
|
|
|
pub fn try_collapse_two(
|
|
(lhs1, rhs1): (&TypeKind, &TypeKind),
|
|
(lhs2, rhs2): (&TypeKind, &TypeKind),
|
|
) -> Option<(TypeKind, TypeKind)> {
|
|
if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&lhs2), rhs1.narrow_into(&rhs2)) {
|
|
Some((lhs, rhs))
|
|
} else if let (Ok(lhs), Ok(rhs)) = (lhs1.narrow_into(&rhs2), rhs1.narrow_into(&lhs2)) {
|
|
Some((rhs, lhs))
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn unroll_borrow(&self) -> TypeKind {
|
|
match self {
|
|
TypeKind::Borrow(type_kind, mut1) => match *type_kind.clone() {
|
|
TypeKind::Borrow(type_kind, mut2) => match (mut1, mut2) {
|
|
(false, false) => TypeKind::Borrow(Box::new(*type_kind.clone()), false),
|
|
_ => TypeKind::Borrow(Box::new(*type_kind.clone()), true),
|
|
},
|
|
_ => self.clone(),
|
|
},
|
|
_ => self.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BinaryOperator {
|
|
pub fn is_commutative(&self) -> bool {
|
|
match self {
|
|
BinaryOperator::Add => true,
|
|
BinaryOperator::Minus => false,
|
|
BinaryOperator::Mult => true,
|
|
BinaryOperator::Div => false,
|
|
BinaryOperator::Mod => false,
|
|
BinaryOperator::And => true,
|
|
BinaryOperator::Cmp(cmp_operator) => match cmp_operator {
|
|
CmpOperator::LT => false,
|
|
CmpOperator::LE => false,
|
|
CmpOperator::GT => false,
|
|
CmpOperator::GE => false,
|
|
CmpOperator::EQ => true,
|
|
CmpOperator::NE => true,
|
|
},
|
|
BinaryOperator::Or => true,
|
|
BinaryOperator::Xor => true,
|
|
BinaryOperator::BitOr => true,
|
|
BinaryOperator::BitAnd => true,
|
|
BinaryOperator::BitshiftRight => false,
|
|
BinaryOperator::BitshiftLeft => false,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(PartialEq, Eq, PartialOrd, Ord)]
|
|
pub enum TypeCategory {
|
|
Integer,
|
|
Real,
|
|
Bool,
|
|
Other,
|
|
TypeRef,
|
|
}
|
|
|
|
impl TypeCategory {
|
|
pub fn is_simple_maths(&self) -> bool {
|
|
match self {
|
|
TypeCategory::Integer => true,
|
|
TypeCategory::Real => true,
|
|
TypeCategory::Other => false,
|
|
TypeCategory::TypeRef => false,
|
|
TypeCategory::Bool => true,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl StructType {
|
|
pub fn get_field_ty(&self, name: &String) -> Option<&TypeKind> {
|
|
self.0
|
|
.iter()
|
|
.find(|StructField(n, _, _)| n == name)
|
|
.map(|StructField(_, ty, _)| ty)
|
|
}
|
|
|
|
pub fn get_field_ty_mut(&mut self, name: &String) -> Option<&mut TypeKind> {
|
|
self.0
|
|
.iter_mut()
|
|
.find(|StructField(n, _, _)| n == name)
|
|
.map(|StructField(_, ty, _)| ty)
|
|
}
|
|
}
|
|
|
|
impl Block {
|
|
fn return_expr(&self) -> Result<BlockReturn, ReturnTypeOther> {
|
|
let mut early_return = None;
|
|
|
|
for statement in &self.statements {
|
|
let ret = statement.return_type(&Default::default(), SourceModuleId(0));
|
|
if let Ok((ReturnKind::Hard, _)) = ret {
|
|
early_return = Some(statement);
|
|
}
|
|
}
|
|
|
|
if let Some(s) = early_return {
|
|
return Ok(BlockReturn::Early(s));
|
|
}
|
|
|
|
self.return_expression
|
|
.as_ref()
|
|
.map(|(r, e)| BlockReturn::Normal(*r, e))
|
|
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta))
|
|
}
|
|
|
|
pub fn return_meta(&self) -> Metadata {
|
|
self.return_expression
|
|
.as_ref()
|
|
.map(|e| e.1.as_ref().map(|e| e.1).unwrap_or(Metadata::default()))
|
|
.or(self.statements.last().map(|s| s.1))
|
|
.unwrap_or(self.meta)
|
|
}
|
|
|
|
pub fn return_type(
|
|
&self,
|
|
refs: &TypeRefs,
|
|
mod_id: SourceModuleId,
|
|
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
|
let mut early_return = None;
|
|
|
|
for statement in &self.statements {
|
|
let ret = statement.return_type(refs, mod_id);
|
|
if let Ok((ReturnKind::Hard, _)) = ret {
|
|
early_return = early_return.or(ret.ok());
|
|
}
|
|
}
|
|
|
|
if let Some((ReturnKind::Hard, ret_ty)) = early_return {
|
|
return Ok((ReturnKind::Hard, ret_ty));
|
|
}
|
|
|
|
self.return_expression
|
|
.as_ref()
|
|
.ok_or(ReturnTypeOther::NoBlockReturn(self.meta))
|
|
.and_then(|(kind, stmt)| {
|
|
Ok((
|
|
*kind,
|
|
stmt.as_ref()
|
|
.and_then(|s| s.return_type(refs, mod_id).ok())
|
|
.map(|s| s.1)
|
|
.unwrap_or(TypeKind::Void),
|
|
))
|
|
})
|
|
}
|
|
|
|
pub fn backing_var(&self) -> Option<&NamedVariableRef> {
|
|
match self.return_expr().ok()? {
|
|
BlockReturn::Early(statement) => statement.backing_var(),
|
|
BlockReturn::Normal(kind, expr) => {
|
|
if let Some(expr) = expr {
|
|
if kind == ReturnKind::Soft {
|
|
expr.backing_var()
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Statement {
|
|
pub fn return_type(
|
|
&self,
|
|
refs: &TypeRefs,
|
|
mod_id: SourceModuleId,
|
|
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
|
use StmtKind::*;
|
|
match &self.0 {
|
|
Let(var, _, expr) => if_hard(
|
|
expr.return_type(refs, mod_id)?,
|
|
Err(ReturnTypeOther::Let(var.2 + expr.1)),
|
|
),
|
|
Set(lhs, rhs) => if_hard(rhs.return_type(refs, mod_id)?, Err(ReturnTypeOther::Set(lhs.1 + rhs.1))),
|
|
Import(_) => todo!(),
|
|
Expression(expression) => expression.return_type(refs, mod_id),
|
|
While(_) => Err(ReturnTypeOther::Loop),
|
|
}
|
|
}
|
|
|
|
pub fn backing_var(&self) -> Option<&NamedVariableRef> {
|
|
match &self.0 {
|
|
StmtKind::Let(_, _, _) => None,
|
|
StmtKind::Set(_, _) => None,
|
|
StmtKind::Import(_) => None,
|
|
StmtKind::Expression(expr) => expr.backing_var(),
|
|
StmtKind::While(_) => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Expression {
|
|
pub fn return_type(
|
|
&self,
|
|
refs: &TypeRefs,
|
|
mod_id: SourceModuleId,
|
|
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
|
use ExprKind::*;
|
|
match &self.0 {
|
|
Literal(lit) => Ok((ReturnKind::Soft, lit.as_type())),
|
|
Variable(var) => var.return_type(),
|
|
BinOp(_, then_e, else_e, return_ty) => {
|
|
let then_r = then_e.return_type(refs, mod_id)?;
|
|
let else_r = else_e.return_type(refs, mod_id)?;
|
|
|
|
Ok(match (then_r.0, else_r.0) {
|
|
(ReturnKind::Hard, ReturnKind::Hard) => (ReturnKind::Hard, return_ty.clone()),
|
|
_ => (ReturnKind::Soft, return_ty.clone()),
|
|
})
|
|
}
|
|
Block(block) => block.return_type(refs, mod_id),
|
|
FunctionCall(fcall) => fcall.return_type(),
|
|
If(expr) => expr.return_type(refs, mod_id),
|
|
Indexed(expression, _, _) => {
|
|
let expr_type = expression.return_type(refs, mod_id)?;
|
|
if let TypeKind::Array(elem_ty, _) = expr_type.1.resolve_weak(refs) {
|
|
Ok((ReturnKind::Soft, *elem_ty))
|
|
} else if let TypeKind::UserPtr(_) = expr_type.1.resolve_weak(refs) {
|
|
Ok((ReturnKind::Soft, expr_type.1))
|
|
} else {
|
|
Err(ReturnTypeOther::IndexingNonArray(expression.1))
|
|
}
|
|
}
|
|
Array(expressions) => {
|
|
let first = expressions
|
|
.iter()
|
|
.next()
|
|
.map(|e| e.return_type(refs, mod_id))
|
|
.unwrap_or(Ok((ReturnKind::Soft, TypeKind::Void)))?;
|
|
Ok((
|
|
ReturnKind::Soft,
|
|
TypeKind::Array(Box::new(first.1), expressions.len() as u64),
|
|
))
|
|
}
|
|
Accessed(_, type_kind, _) => Ok((ReturnKind::Soft, type_kind.clone())),
|
|
Struct(name, _) => Ok((
|
|
ReturnKind::Soft,
|
|
TypeKind::CustomType(CustomTypeKey(name.clone(), mod_id)),
|
|
)),
|
|
Borrow(expr, mutable) => {
|
|
let ret_type = expr.return_type(refs, mod_id)?;
|
|
Ok((ret_type.0, TypeKind::Borrow(Box::new(ret_type.1), *mutable)))
|
|
}
|
|
Deref(expr) => {
|
|
let (kind, ret_type) = expr.return_type(refs, mod_id)?;
|
|
match ret_type.resolve_weak(refs) {
|
|
TypeKind::Borrow(type_kind, _) => Ok((kind, *type_kind)),
|
|
_ => Err(ReturnTypeOther::DerefNonBorrow(expr.1)),
|
|
}
|
|
}
|
|
CastTo(expr, type_kind) => match expr.return_type(refs, mod_id) {
|
|
Ok(ret_type) => match ret_type {
|
|
(ReturnKind::Hard, ty) => Ok((ReturnKind::Hard, ty)),
|
|
_ => Ok((ReturnKind::Soft, type_kind.clone())),
|
|
},
|
|
Err(_) => Ok((ReturnKind::Soft, type_kind.clone())),
|
|
},
|
|
AssociatedFunctionCall(_, fcall) => fcall.return_type(),
|
|
}
|
|
}
|
|
|
|
pub fn backing_var(&self) -> Option<&NamedVariableRef> {
|
|
match &self.0 {
|
|
ExprKind::Variable(var_ref) => Some(var_ref),
|
|
ExprKind::Indexed(lhs, _, _) => lhs.backing_var(),
|
|
ExprKind::Accessed(lhs, _, _) => lhs.backing_var(),
|
|
ExprKind::Borrow(expr, _) => expr.backing_var(),
|
|
ExprKind::Deref(expr) => expr.backing_var(),
|
|
ExprKind::Block(block) => block.backing_var(),
|
|
ExprKind::Array(_) => None,
|
|
ExprKind::Struct(_, _) => None,
|
|
ExprKind::Literal(_) => None,
|
|
ExprKind::BinOp(_, _, _, _) => None,
|
|
ExprKind::FunctionCall(_) => None,
|
|
ExprKind::If(_) => None,
|
|
ExprKind::CastTo(expression, _) => expression.backing_var(),
|
|
ExprKind::AssociatedFunctionCall(..) => None,
|
|
}
|
|
}
|
|
|
|
pub fn num_value(&self) -> Result<Option<i128>, NumValueError> {
|
|
Ok(match &self.0 {
|
|
ExprKind::Variable(_) => None,
|
|
ExprKind::Indexed(..) => None,
|
|
ExprKind::Accessed(..) => None,
|
|
ExprKind::Array(_) => None,
|
|
ExprKind::Struct(..) => None,
|
|
ExprKind::Literal(literal) => literal.num_value(),
|
|
ExprKind::BinOp(op, lhs, rhs, _) => match op {
|
|
BinaryOperator::Add => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a + b),
|
|
BinaryOperator::Minus => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a - b),
|
|
BinaryOperator::Mult => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a * b),
|
|
BinaryOperator::And => None,
|
|
BinaryOperator::Cmp(_) => None,
|
|
BinaryOperator::Div => {
|
|
let rhs_value = rhs.num_value()?;
|
|
if rhs_value == Some(0) {
|
|
Err(NumValueError::DivideZero)?
|
|
}
|
|
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a / b)
|
|
}
|
|
BinaryOperator::Mod => {
|
|
let rhs_value = rhs.num_value()?;
|
|
if rhs_value == Some(0) {
|
|
Err(NumValueError::DivideZero)?
|
|
}
|
|
maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a % b)
|
|
}
|
|
BinaryOperator::Or => None,
|
|
BinaryOperator::Xor => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a ^ b),
|
|
BinaryOperator::BitOr => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a | b),
|
|
BinaryOperator::BitAnd => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a & b),
|
|
BinaryOperator::BitshiftRight => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a >> b),
|
|
BinaryOperator::BitshiftLeft => maybe(lhs.num_value()?, rhs.num_value()?, |a, b| a << b),
|
|
},
|
|
ExprKind::FunctionCall(..) => None,
|
|
ExprKind::If(_) => None,
|
|
ExprKind::Block(_) => None,
|
|
ExprKind::Borrow(_, _) => None,
|
|
ExprKind::Deref(_) => None,
|
|
ExprKind::CastTo(expression, _) => expression.num_value()?,
|
|
ExprKind::AssociatedFunctionCall(..) => None,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl IfExpression {
|
|
pub fn return_type(
|
|
&self,
|
|
refs: &TypeRefs,
|
|
mod_id: SourceModuleId,
|
|
) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
|
let then_r = self.1.return_type(refs, mod_id)?;
|
|
if let Some(else_e) = self.2.as_ref() {
|
|
let else_r = else_e.return_type(refs, mod_id)?;
|
|
|
|
let kind = if then_r.0 == ReturnKind::Hard && else_r.0 == ReturnKind::Hard {
|
|
ReturnKind::Hard
|
|
} else {
|
|
ReturnKind::Soft
|
|
};
|
|
Ok((kind, then_r.1))
|
|
} else {
|
|
Ok((ReturnKind::Soft, then_r.1))
|
|
}
|
|
}
|
|
}
|
|
|
|
impl NamedVariableRef {
|
|
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
|
Ok((ReturnKind::Soft, self.0.clone()))
|
|
}
|
|
}
|
|
|
|
impl FunctionCall {
|
|
pub fn return_type(&self) -> Result<(ReturnKind, TypeKind), ReturnTypeOther> {
|
|
Ok((ReturnKind::Soft, self.return_type.clone()))
|
|
}
|
|
}
|
|
|
|
fn if_hard<TErr>(
|
|
return_type: (ReturnKind, TypeKind),
|
|
default: Result<(ReturnKind, TypeKind), TErr>,
|
|
) -> Result<(ReturnKind, TypeKind), TErr> {
|
|
if let (ReturnKind::Hard, _) = return_type {
|
|
Ok(return_type)
|
|
} else {
|
|
default
|
|
}
|
|
}
|
|
|
|
pub fn pick_return<T>(lhs: (ReturnKind, T), rhs: (ReturnKind, T)) -> (ReturnKind, T) {
|
|
use ReturnKind::*;
|
|
match (lhs.0, rhs.0) {
|
|
(Hard, Hard) => (Hard, lhs.1),
|
|
(Hard, Soft) => (Soft, rhs.1),
|
|
(Soft, Hard) => (Soft, lhs.1),
|
|
(_, _) => (Soft, lhs.1),
|
|
}
|
|
}
|
|
|
|
impl Literal {
|
|
pub fn num_value(&self) -> Option<i128> {
|
|
match self {
|
|
Literal::I8(val) => Some(*val as i128),
|
|
Literal::I16(val) => Some(*val as i128),
|
|
Literal::I32(val) => Some(*val as i128),
|
|
Literal::I64(val) => Some(*val as i128),
|
|
Literal::I128(val) => Some(*val as i128),
|
|
Literal::U8(val) => Some(*val as i128),
|
|
Literal::U16(val) => Some(*val as i128),
|
|
Literal::U32(val) => Some(*val as i128),
|
|
Literal::U64(val) => Some(*val as i128),
|
|
Literal::U128(val) => Some(*val as i128),
|
|
Literal::Bool(_) => None,
|
|
Literal::String(_) => None,
|
|
Literal::Vague(VagueLiteral::Number(val)) => Some(*val as i128),
|
|
Literal::Vague(VagueLiteral::Decimal(_)) => None,
|
|
Literal::F16(_) => None,
|
|
Literal::F32B(_) => None,
|
|
Literal::F32(_) => None,
|
|
Literal::F64(_) => None,
|
|
Literal::F80(_) => None,
|
|
Literal::F128(_) => None,
|
|
Literal::F128PPC(_) => None,
|
|
Literal::Char(_) => None,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq, PartialOrd, Ord)]
|
|
pub enum EqualsIssue {
|
|
#[error("Function is already defined locally at {:?}", (.0).range)]
|
|
ExistsLocally(Metadata),
|
|
#[error("Equals")]
|
|
Equals,
|
|
#[error("Function {0} is already declared locally at {:?}", (.1).range)]
|
|
AlreadyExtern(String, Metadata),
|
|
#[error("Function {0} is already imported from another module")]
|
|
ConflictWithImport(String),
|
|
#[error("Function is defined as an intrinsic")]
|
|
ExistsAsIntrinsic,
|
|
}
|
|
|
|
impl FunctionDefinition {
|
|
pub fn equals_as_imported(&self, other: &FunctionDefinition) -> Result<(), EqualsIssue> {
|
|
match &self.kind {
|
|
FunctionDefinitionKind::Local(_, metadata) => Err(EqualsIssue::ExistsLocally(*metadata)),
|
|
FunctionDefinitionKind::Extern(imported) => {
|
|
if *imported {
|
|
Err(EqualsIssue::ConflictWithImport(self.name.clone()))
|
|
} else {
|
|
if self.is_pub == other.is_pub
|
|
&& self.name == other.name
|
|
&& self.parameters == other.parameters
|
|
&& self.return_type == other.return_type
|
|
{
|
|
Ok(())
|
|
} else {
|
|
Err(EqualsIssue::AlreadyExtern(self.name.clone(), self.signature()))
|
|
}
|
|
}
|
|
}
|
|
FunctionDefinitionKind::Intrinsic(_) => Err(EqualsIssue::ExistsAsIntrinsic),
|
|
}
|
|
}
|
|
}
|