use crate::prelude::*;
use crate::{HeapAddress, VariantIndex, RustFnIndex};
use crate::shared::typed_ids::{TypeId, FunctionId};
use crate::shared::numeric::{Numeric, Signed, Unsigned};
pub struct Binding {
pub mutable: bool,
pub type_id: Option<TypeId>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum EnumVariant {
Simple(Option<Numeric>),
Data(Vec<Option<TypeId>>),
}
impl EnumVariant {
pub fn as_data(self: &Self) -> Option<&Vec<Option<TypeId>>> {
match self {
Self::Data(d) => Some(d),
_ => None,
}
}
pub fn as_simple(self: &Self) -> Option<Numeric> {
match self {
Self::Simple(s) => *s,
_ => None,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Enum {
pub variants: Vec<(String, EnumVariant)>,
pub impl_traits: Map<TypeId, ImplTrait>,
pub primitive: Option<(TypeId, u8)>,
}
impl Enum {
pub fn variant_index(self: &Self, variant: &str) -> Option<VariantIndex> {
self.variants.iter().position(|(name, _)| name == variant).map(|i| i as VariantIndex)
}
pub fn variant_value(self: &Self, variant: &str) -> Option<Numeric> {
self.variants.iter().find(|(n, v)| n == variant && v.as_simple().is_some()).map(|(_, v)| v.as_simple().unwrap())
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Struct {
pub fields: Map<String, Option<TypeId>>,
pub impl_traits: Map<TypeId, ImplTrait>,
}
impl Struct {
pub fn type_id(self: &Self, field: &str) -> Option<TypeId> {
*self.fields.get(field).expect("Field not found")
}
pub fn has_field(self: &Self, field: &str) -> bool {
self.fields.contains_key(field)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Array {
pub type_id: Option<TypeId>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ImplTrait {
pub functions: Map<String, Option<FunctionId>>,
}
impl ImplTrait {
pub fn new() -> Self {
Self { functions: Map::new() }
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Trait {
pub provided: Map<String, Option<FunctionId>>,
pub required: Map<String, Option<FunctionId>>,
}
#[derive(Clone)]
pub struct Function {
pub kind : Option<FunctionKind>,
pub arg_type: Vec<Option<TypeId>>,
pub ret_type: Option<TypeId>,
}
impl Function {
pub fn rust_fn_index(self: &Self) -> Option<RustFnIndex> {
match self.kind {
Some(FunctionKind::Rust(index)) => Some(index),
_ => None,
}
}
pub fn is_resolved(self: &Self) -> bool {
self.ret_type.is_some() && self.kind.is_some() && self.arg_type.iter().all(|arg| arg.is_some())
}
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum FunctionKind {
Function,
Method(TypeId),
Rust(RustFnIndex),
Builtin(TypeId, BuiltinGroup),
Variant(TypeId, VariantIndex),
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum BuiltinGroup {
ArrayLen,
ArrayPush,
ArrayPop,
ArrayTruncate,
ArrayRemove,
}
#[allow(non_camel_case_types)]
#[derive(Clone, PartialEq, Eq, Hash)]
pub enum Type {
void,
u8, u16, u32, u64,
i8, i16, i32, i64,
f32, f64,
bool,
String,
Array(Array),
Enum(Enum),
Struct(Struct),
Trait(Trait),
}
impl Debug for Type {
fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::void => write!(f, "void"),
Type::u8 => write!(f, "u8"),
Type::u16 => write!(f, "u16"),
Type::u32 => write!(f, "u32"),
Type::u64 => write!(f, "u64"),
Type::i8 => write!(f, "i8"),
Type::i16 => write!(f, "i16"),
Type::i32 => write!(f, "i32"),
Type::i64 => write!(f, "i64"),
Type::f32 => write!(f, "f32"),
Type::f64 => write!(f, "f64"),
Type::bool => write!(f, "bool"),
Type::String => write!(f, "String"),
Type::Array(v) => write!(f, "{:?}", v),
Type::Enum(v) => write!(f, "{:?}", v),
Type::Struct(v) => write!(f, "{:?}", v),
Type::Trait(_) => write!(f, "<Trait>"),
}
}
}
impl Display for Type {
fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Type::void => write!(f, "void"),
Type::u8 => write!(f, "u8"),
Type::u16 => write!(f, "u16"),
Type::u32 => write!(f, "u32"),
Type::u64 => write!(f, "u64"),
Type::i8 => write!(f, "i8"),
Type::i16 => write!(f, "i16"),
Type::i32 => write!(f, "i32"),
Type::i64 => write!(f, "i64"),
Type::f32 => write!(f, "f32"),
Type::f64 => write!(f, "f64"),
Type::bool => write!(f, "bool"),
Type::String => write!(f, "String"),
Type::Array(_) => write!(f, "[ _ ]"),
Type::Enum(_) => write!(f, "enum"),
Type::Struct(_) => write!(f, "struct"),
Type::Trait(_) => write!(f, "trait"),
}
}
}
impl Type {
pub const fn primitive_size(self: &Self) -> u8 {
match self {
Type::void => 0,
Type::u8 | Type::i8 | Type::bool => 1,
Type::u16 | Type::i16 => 2,
Type::u32 | Type::i32 | Type::f32 => 4,
Type::u64 | Type::i64 | Type::f64 => 8,
Type::Enum(Enum { primitive: Some((_, s)), .. }) => *s,
Type::String | Type::Enum(_) | Type::Struct(_) | Type::Array(_) | Type::Trait(_) => size_of::<HeapAddress>() as u8,
}
}
pub const fn unsigned(size: usize) -> Self { match size {
1 => Self::u8,
2 => Self::u16,
4 => Self::u32,
8 => Self::u64,
_ => panic!("Unsupported unsigned integer size"), }
}
pub const fn signed(size: usize) -> Self { match size {
1 => Self::i8,
2 => Self::i16,
4 => Self::i32,
8 => Self::i64,
_ => panic!("Unsupported signed integer size"), }
}
pub fn is_compatible_numeric(self: &Self, value: Numeric) -> bool {
use core::{u8, u16, u32, u64, i8, i16, i32, i64};
if value.is_float() && self.is_float() {
true
} else if value.is_integer() && self.is_integer() {
let range = match self {
Type::u8 => (Numeric::Unsigned(u8::MIN as Unsigned), Numeric::Unsigned(u8::MAX as Unsigned)),
Type::u16 => (Numeric::Unsigned(u16::MIN as Unsigned), Numeric::Unsigned(u16::MAX as Unsigned)),
Type::u32 => (Numeric::Unsigned(u32::MIN as Unsigned), Numeric::Unsigned(u32::MAX as Unsigned)),
Type::u64 => (Numeric::Unsigned(u64::MIN as Unsigned), Numeric::Unsigned(u64::MAX as Unsigned)),
Type::i8 => (Numeric::Signed(i8::MIN as Signed), Numeric::Signed(i8::MAX as Signed)),
Type::i16 => (Numeric::Signed(i16::MIN as Signed), Numeric::Signed(i16::MAX as Signed)),
Type::i32 => (Numeric::Signed(i32::MIN as Signed), Numeric::Signed(i32::MAX as Signed)),
Type::i64 => (Numeric::Signed(i64::MIN as Signed), Numeric::Signed(i64::MAX as Signed)),
_ => unreachable!(),
};
range.0 <= value && range.1 >= value
} else {
false
}
}
pub const fn is_ref(self: &Self) -> bool {
match self {
Type::Enum(Enum { primitive: Some(_), .. }) => false,
Type::String | Type::Array(_) | Type::Enum(_) | Type::Struct(_) | Type::Trait(_) => true,
_ => false,
}
}
pub const fn is_copy(self: &Self) -> bool {
match self {
Type::String => true,
_ => self.is_primitive(),
}
}
pub const fn is_primitive(self: &Self) -> bool {
!self.is_ref()
}
pub const fn is_void(self: &Self) -> bool {
match self {
Type::void => true,
_ => false
}
}
pub const fn is_unsigned(self: &Self) -> bool {
match self {
Type::u8 | Type::u16 | Type::u32 | Type::u64 => true,
_ => false
}
}
pub const fn is_signed(self: &Self) -> bool {
match self {
Type::i8 | Type::i16 | Type::i32 | Type::i64 => true,
_ => false
}
}
pub const fn is_integer(self: &Self) -> bool {
self.is_unsigned() || self.is_signed()
}
pub const fn is_float(self: &Self) -> bool {
match self {
Type::f32 | Type::f64 => true,
_ => false
}
}
pub const fn is_string(self: &Self) -> bool {
match self {
Type::String => true,
_ => false
}
}
pub fn is_concrete(self: &Self) -> bool {
match self {
Type::Trait(_) => false,
_ => true
}
}
pub const fn as_array(self: &Self) -> Option<&Array> {
match self {
Type::Array(array) => Some(array),
_ => None
}
}
pub fn as_array_mut(self: &mut Self) -> Option<&mut Array> {
match self {
Type::Array(array) => Some(array),
_ => None
}
}
pub const fn as_struct(self: &Self) -> Option<&Struct> {
match self {
Type::Struct(struct_) => Some(struct_),
_ => None
}
}
pub fn as_struct_mut(self: &mut Self) -> Option<&mut Struct> {
match self {
Type::Struct(struct_) => Some(struct_),
_ => None
}
}
pub const fn as_enum(self: &Self) -> Option<&Enum> {
match self {
Type::Enum(enum_) => Some(enum_),
_ => None
}
}
pub fn as_enum_mut(self: &mut Self) -> Option<&mut Enum> {
match self {
Type::Enum(enum_) => Some(enum_),
_ => None
}
}
pub const fn as_trait(self: &Self) -> Option<&Trait> {
match self {
Type::Trait(trait_def) => Some(trait_def),
_ => None
}
}
pub fn as_trait_mut(self: &mut Self) -> Option<&mut Trait> {
match self {
Type::Trait(trait_def) => Some(trait_def),
_ => None
}
}
pub fn impl_trait_ids(self: &Self) -> Option<impl Iterator<Item=&TypeId>> {
match self {
Type::Struct(struct_) => Some(struct_.impl_traits.keys()),
_ => None,
}
}
pub fn impl_traits(self: &Self) -> Option<impl Iterator<Item=(&TypeId, &ImplTrait)>> {
match self {
Type::Struct(struct_) => Some(struct_.impl_traits.iter()),
_ => None,
}
}
}