move types.rs -> complex_types.rs, simple_types.rs -> types.rs

This commit is contained in:
SArpnt 2024-07-24 00:33:53 -04:00
parent 9eeea6fe08
commit 9b8a1fe0df
Signed by: SArpnt
SSH key fingerprint: SHA256:iDMeic8KkqqEsN4wODlgsk1d/oW1ojZ/cu/MEWyfLBw
5 changed files with 370 additions and 370 deletions

317
src/complex_types.rs Normal file
View file

@ -0,0 +1,317 @@
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
/// Number type for type parameters in types.
pub type NumTypeParam = u64;
/// Number type for type parameters in traits.
pub type NonZeroNumTypeParam = core::num::NonZeroU64;
/// Number type for enum entries.
pub type NumEnumEntry = u64;
/// A handle used to access [`TypeDefinition`]s and [`TraitDefinition`]s
/// from the respective [`TypeTable`] and [`TraitTable`].
///
/// [`TypeDefinition`]: struct.TypeDefinition.html
/// [`TraitDefinition`]: struct.TraitDefinition.html
/// [`TypeTable`]: struct.TypeTable.html
/// [`TraitTable`]: struct.TraitTable.html
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TypeHandle(());
impl TypeHandle {
// TODO: store a fully resolved identifier path
/*
pub fn new() -> Self {
Self()
}
*/
}
/// Storage for [`TraitDefinition`]s accessed with [`TypeHandle`]s.
///
/// [`TraitDefinition`]: struct.TraitDefinition.html
/// [`TypeHandle`]: struct.TypeHandle.html
pub type TraitTable = BTreeMap<TypeHandle, TraitDefinition>;
/// Storage for [`TypeDefinition`]s accessed with [`TypeHandle`]s.
///
/// [`TypeDefinition`]: struct.TypeDefinition.html
/// [`TypeHandle`]: struct.TypeHandle.html
pub type TypeTable = BTreeMap<TypeHandle, TypeDefinition>;
/// TODO
pub type ImplTable = BTreeMap<(), ()>;
/// Base information about a type.
///
/// `T` is what kind of type reference to use, for example a [`GenericType`] or [`QualifiedType`].
///
/// Represents `struct...(*U)` in `struct Def<T, U: Foo<E> + Bar>(*U)`.
///
/// [`GenericType`]: struct.GenericType.html
/// [`QualifiedType`]: struct.QualifiedType.html
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TypeKind<T> {
/// Used when a primitive type has no other way of declaring the size.
/// None for Unsized, Some for sized.
Primitive { size: Option<crate::NonZeroTargetUSize> },
/// A struct with 0 items has size 0.
Struct { items: Vec<T> },
/// An enum with 0 items has size Never.
/// An enum with 1 item has size 0.
Enum { num_items: NumEnumEntry },
/// A union with 0 items has size Never.
Union { items: Vec<T> },
}
/// A definition of a trait.
///
/// Represents `trait Foo<T> where Self: Bar { ... }`.
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct TraitDefinition {
/// Amount of type parameters. Type parameter 0 is Self.
pub num_type_params: NonZeroNumTypeParam,
/// Requirements to implement the trait.
///
/// This should generally used to specify requirements of type parameters,
/// but it can be used to specify requirements of any types.
///
/// Type parameter 0 is Self.
pub clauses: Vec<(GenericType, Binding)>,
/// TODO: named constants and statics required by the trait. functions are just statics
pub associations: (),
}
/// A reference to a trait. You should usually only use this in a [`Binding`].
///
/// Represents `Foo<T>` or `Bar` in `struct Def<T, U: Foo<T> + Bar>(*U)`.
///
/// [`Binding`]: struct.Binding.html
#[derive(Debug, Clone)]
pub struct GenericTrait {
/// Used to get the trait definition from the trait table.
handle: TypeHandle,
/// Fills type parameters of the trait.
///
/// This should be one less than the number of trait parameters on the trait definition
/// (Self isn't filled).
type_params: Vec<GenericType>,
}
/// A binding created from a generic.
///
/// Represents `Foo<T> + Bar` in `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
#[derive(Debug, Clone)]
pub struct Binding(Vec<GenericTrait>);
/// A definition of a type.
///
/// Represents `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
///
/// Also see [`TypeKind`].
///
/// [`TypeKind`]: enum.TypeKind.html
#[derive(Debug, Clone)]
pub struct TypeDefinition {
/// Amount of type parameters.
pub num_type_params: NumTypeParam,
/// Requirements to instantiate the struct.
///
/// This should generally used to specify requirements of type parameters,
/// but it can be used to specify requirements of any types.
pub clauses: Vec<(GenericType, Binding)>,
/// The basic contents of this type.
pub kind: TypeKind<GenericType>,
}
impl TypeDefinition {
/// Fill the generics of this type.
/// This is an expensive operation.
pub fn qualify(&self, generics: Vec<QualifiedType>, type_table: &TypeTable) -> QualifiedType {
todo!("implement TypeDefinition::qualify")
}
}
/// A binding from a generic or a type that may use bindings.
///
/// Represents `*U` or the two last `U`s in `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
#[derive(Debug, Clone)]
pub enum GenericType {
/// A generic type parameter.
///
/// The user should already have a [`TypeDefinition`] or [`TraitDefinition`] this applies to.
///
/// [`TypeDefinition`]: struct.TypeDefinition.html
/// [`TraitDefinition`]: struct.TraitDefinition.html
TypeParam(NumTypeParam),
/// A reference to a type.
Real {
/// Used to get the type definition from the type table.
handle: TypeHandle,
/// Fills type parameters of the trait.
///
/// This should match the number of type parameters on the type definition.
type_params: Vec<GenericType>
},
}
impl GenericType {
pub fn real(
type_table: &TypeTable,
handle: TypeHandle,
type_params: Vec<GenericType>,
) -> Result<Self, ()> {
let t = type_table.get(&handle).ok_or(todo!("InvalidHandleError"))?;
let num_type_params = NumTypeParam::try_from(type_params.len());
if Ok(t.num_type_params) != num_type_params {
return Err(todo!("incorrect generic length error"));
}
Ok(Self::Real {
handle,
type_params,
})
}
}
/// Type with all generics specified.
///
/// Represents `Def(*One<Two>)` from `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
#[derive(Debug, Clone)]
pub struct QualifiedType {
pub kind: TypeKind<QualifiedType>,
}
impl QualifiedType {
/// Calculate the size of this type. This is an expensive operation.
///
/// TODO: if a type contains itself this will overflow the stack
pub fn calc_size(&self) -> Result<Size, CalcSizeError> {
match self.kind {
TypeKind::Primitive { size: Some(size) } => Ok(Size::Sized(size.into())),
TypeKind::Primitive { size: None } => Ok(Size::Dynamic),
TypeKind::Struct { ref items } =>
match items.iter().try_fold(
Size::Sized(0), |a, b| {
match b.calc_size() {
Err(x) => Err(Err(x)),
Ok(Size::Never) => Err(Ok(Size::Never)),
Ok(size) => (a + size).map_err(|x| Err(x.into())),
}
}
) {
Ok(result) => Ok(result),
Err(result) => result,
},
TypeKind::Enum { num_items: _ } => Ok(todo!("calculate enum size")),
TypeKind::Union { ref items } => match items.iter().try_fold(
Option::<crate::TargetUSize>::None, |a, b| {
match b.calc_size() {
Err(x) => Err(Err(x)),
Ok(Size::Sized(size)) => Ok(a.map(|a| a.max(size)).or(Some(size))),
Ok(Size::Dynamic) => Err(Ok(Size::Dynamic)),
Ok(Size::Never) => Ok(a),
}
}
) {
Ok(Some(size)) => Ok(Size::Sized(size)),
Ok(None) => Ok(Size::Never),
Err(result) => result,
},
}
}
}
// TODO
#[non_exhaustive]
pub struct FindTypeError;
// TODO
#[non_exhaustive]
pub enum CalcSizeError {
FindTypeError(FindTypeError),
AddSizeError(AddSizeError),
}
impl From<FindTypeError> for CalcSizeError {
fn from(err: FindTypeError) -> Self {
Self::FindTypeError(err)
}
}
impl From<AddSizeError> for CalcSizeError {
fn from(err: AddSizeError) -> Self {
Self::AddSizeError(err)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// The size of a type.
///
/// See each variant for a description and examples.
///
/// Some types have unspecified sizes:
/// - A slice of [never] types
///
/// Currently [dynamic], since it can have 0 items, but could become Sized in the future.
///
/// [sized]: #variant.Sized
/// [never]: #variant.Never
/// [dynamic]: #variant.Dynamic
pub enum Size {
/// Has a fixed size at compile time.
///
/// Examples:
/// - A struct with no items
/// - A struct with only sized items
/// - An enum with at least one item
/// - A pointer or reference
Sized(crate::TargetUSize),
/// Can never be instantiated.
///
/// Examples:
/// - An enum with no variants
/// - A struct with at least one never variant
/// - A union with only never variants
Never,
/// The size is different at runtime for various instances of the type.
/// The size can be calculated at runtime, usually with a length value at the start.
///
/// Examples:
/// - A slice of [sized] types
/// - A struct ending with a dynamic type
///
/// [sized]: #variant.Sized
Dynamic,
}
impl From<crate::TargetUSize> for Size {
fn from(size: crate::TargetUSize) -> Self {
Self::Sized(size)
}
}
impl PartialOrd for Size {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
use Size::*;
use core::cmp::Ordering::*;
match (self, other) {
(Sized(a), Sized(b)) => Some(a.cmp(b)),
(Never, Never) => Some(Equal),
(Never, Sized(_)) => Some(Less),
(Sized(_), Never) => Some(Greater),
(Dynamic, Dynamic) => None,
(_, Dynamic) => Some(Less),
(Dynamic, _) => Some(Greater),
}
}
}
impl core::ops::Add for Size {
type Output = Result<Self, AddSizeError>;
fn add(self, other: Self) -> Self::Output {
use Size::*;
match (self, other) {
(Sized(a), Sized(b)) => Ok(Sized(a + b)),
(Never, _) | (_, Never) => Ok(Never),
(Dynamic, _) => Err(AddSizeError),
(_, Dynamic) => Ok(Dynamic),
}
}
}
// TODO
#[non_exhaustive]
pub struct AddSizeError;

View file

@ -15,7 +15,7 @@ pub mod rewind;
pub mod text;
pub mod error;
pub mod simple_types;
pub mod types;
pub mod primitives;
pub mod token;

View file

@ -1,6 +1,6 @@
use crate::error::ParseError;
use crate::token::*;
use crate::simple_types::*;
use crate::types::*;
use alloc::vec::Vec;
type Error = crate::error::CompileError<ParseError>;

View file

@ -1,195 +0,0 @@
use crate::token::Identifier;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
/// Number type for type parameters.
pub type NumTypeParam = u64;
/// Number type for enum entries.
pub type NumEnumEntry = u64;
/// A handle used to access [`Type`]s from the [`TypeTable`].
///
/// [`Type`]: struct.Type.html
/// [`TypeTable`]: struct.TypeTable.html
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TypeHandle(pub(crate) Identifier);
/// Storage for [`Type`]s accessed with [`TypeHandle`]s.
///
/// [`Type`]: struct.Type.html
/// [`TypeHandle`]: struct.TypeHandle.html
pub type TypeTable = BTreeMap<TypeHandle, Type>;
/// A name and identifier, for [`struct`]s and [`union`]s.
///
/// [`struct`]: enum.Type.html#variant.Struct
/// [`union`]: enum.Type.html#variant.Union
#[derive(Debug, Clone)]
pub struct Field {
pub name: Identifier,
pub type_: TypeHandle,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Type {
/// Always sized, but specific size depends on target.
Pointer { to: TypeHandle },
/// Used when a primitive type has no other way of declaring the size.
/// None for unsized, Some for sized.
Primitive { size: Option<crate::NonZeroTargetUSize> },
/// A struct with 0 items has size 0.
Struct(Vec<Field>),
/// An enum with 0 items has size never.
/// An enum with 1 item has size 0.
Enum(Vec<Identifier>),
/// A union with 0 items has size never.
Union(Vec<Field>),
}
impl Type {
/// Calculate the size of this type.
///
/// TODO: if a type contains itself this will overflow the stack.
/// TODO: size can go above target usize and overflow.
pub fn calc_size(&self, type_table: &TypeTable) -> Result<Size, CalcSizeError> {
match self {
Type::Pointer { .. } => Ok(Size::Sized(
core::mem::size_of::<crate::TargetUSize>() as crate::TargetUSize
)),
Type::Primitive { size: Some(size) } => Ok(Size::Sized((*size).into())),
Type::Primitive { size: None } => Ok(Size::Dynamic),
Type::Struct(ref items) =>
match items.iter().try_fold(
Size::Sized(0), |a, b| {
let Some(type_) = type_table.get(&b.type_) else {
return Err(Err(FindTypeError.into()))
};
match type_.calc_size(type_table) {
Err(x) => Err(Err(x)),
Ok(Size::Never) => Err(Ok(Size::Never)),
Ok(size) => (a + size).map_err(|x| Err(x.into())),
}
}
) {
Ok(result) => Ok(result),
Err(result) => result,
},
Type::Enum(ref items) => Ok(todo!("calculate enum size")),
Type::Union(ref items) => match items.iter().try_fold(
Option::<crate::TargetUSize>::None, |a, b| {
let Some(type_) = type_table.get(&b.type_) else {
return Err(Err(FindTypeError.into()))
};
match type_.calc_size(type_table) {
Err(x) => Err(Err(x)),
Ok(Size::Sized(size)) => Ok(a.map(|a| a.max(size)).or(Some(size))),
Ok(Size::Dynamic) => Err(Ok(Size::Dynamic)),
Ok(Size::Never) => Ok(a),
}
}
) {
Ok(Some(size)) => Ok(Size::Sized(size)),
Ok(None) => Ok(Size::Never),
Err(result) => result,
},
}
}
}
// TODO
#[non_exhaustive]
pub struct FindTypeError;
// TODO
#[non_exhaustive]
pub enum CalcSizeError {
FindTypeError(FindTypeError),
AddSizeError(AddSizeError),
}
impl From<FindTypeError> for CalcSizeError {
fn from(err: FindTypeError) -> Self {
Self::FindTypeError(err)
}
}
impl From<AddSizeError> for CalcSizeError {
fn from(err: AddSizeError) -> Self {
Self::AddSizeError(err)
}
}
#[non_exhaustive]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
/// The size of a type.
///
/// See each variant for a description and examples.
///
/// Some types have unspecified sizes:
/// - A slice of [never] types
///
/// Currently [dynamic], since it can have 0 items, but could become Sized in the future.
///
/// [sized]: #variant.Sized
/// [never]: #variant.Never
/// [dynamic]: #variant.Dynamic
pub enum Size {
/// Has a fixed size at compile time.
///
/// Examples:
/// - A struct with no items
/// - A struct with only sized items
/// - An enum with at least one item
/// - A pointer or reference
Sized(crate::TargetUSize),
/// Can never be instantiated.
///
/// Examples:
/// - An enum with no variants
/// - A struct with at least one never variant
/// - A union with only never variants
Never,
/// The size is different at runtime for various instances of the type.
/// The size can be calculated at runtime, usually with a length value at the start.
///
/// Examples:
/// - A slice of [sized] types
/// - A struct ending with a dynamic type
///
/// [sized]: #variant.Sized
Dynamic,
}
impl From<crate::TargetUSize> for Size {
fn from(size: crate::TargetUSize) -> Self {
Self::Sized(size)
}
}
impl PartialOrd for Size {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
use Size::*;
use core::cmp::Ordering::*;
match (self, other) {
(Sized(a), Sized(b)) => Some(a.cmp(b)),
(Never, Never) => Some(Equal),
(Never, Sized(_)) => Some(Less),
(Sized(_), Never) => Some(Greater),
(Dynamic, Dynamic) => None,
(_, Dynamic) => Some(Less),
(Dynamic, _) => Some(Greater),
}
}
}
impl core::ops::Add for Size {
type Output = Result<Self, AddSizeError>;
fn add(self, other: Self) -> Self::Output {
use Size::*;
match (self, other) {
(Sized(a), Sized(b)) => Ok(Sized(a + b)),
(Never, _) | (_, Never) => Ok(Never),
(Dynamic, _) => Err(AddSizeError),
(_, Dynamic) => Ok(Dynamic),
}
}
}
// TODO
#[non_exhaustive]
pub struct AddSizeError;

View file

@ -1,194 +1,70 @@
use crate::token::Identifier;
use alloc::vec::Vec;
use alloc::collections::BTreeMap;
/// Number type for type parameters in types.
/// Number type for type parameters.
pub type NumTypeParam = u64;
/// Number type for type parameters in traits.
pub type NonZeroNumTypeParam = core::num::NonZeroU64;
/// Number type for enum entries.
pub type NumEnumEntry = u64;
/// A handle used to access [`TypeDefinition`]s and [`TraitDefinition`]s
/// from the respective [`TypeTable`] and [`TraitTable`].
/// A handle used to access [`Type`]s from the [`TypeTable`].
///
/// [`TypeDefinition`]: struct.TypeDefinition.html
/// [`TraitDefinition`]: struct.TraitDefinition.html
/// [`Type`]: struct.Type.html
/// [`TypeTable`]: struct.TypeTable.html
/// [`TraitTable`]: struct.TraitTable.html
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct TypeHandle(());
impl TypeHandle {
// TODO: store a fully resolved identifier path
/*
pub fn new() -> Self {
Self()
}
*/
pub struct TypeHandle(pub(crate) Identifier);
/// Storage for [`Type`]s accessed with [`TypeHandle`]s.
///
/// [`Type`]: struct.Type.html
/// [`TypeHandle`]: struct.TypeHandle.html
pub type TypeTable = BTreeMap<TypeHandle, Type>;
/// A name and identifier, for [`struct`]s and [`union`]s.
///
/// [`struct`]: enum.Type.html#variant.Struct
/// [`union`]: enum.Type.html#variant.Union
#[derive(Debug, Clone)]
pub struct Field {
pub name: Identifier,
pub type_: TypeHandle,
}
/// Storage for [`TraitDefinition`]s accessed with [`TypeHandle`]s.
///
/// [`TraitDefinition`]: struct.TraitDefinition.html
/// [`TypeHandle`]: struct.TypeHandle.html
pub type TraitTable = BTreeMap<TypeHandle, TraitDefinition>;
/// Storage for [`TypeDefinition`]s accessed with [`TypeHandle`]s.
///
/// [`TypeDefinition`]: struct.TypeDefinition.html
/// [`TypeHandle`]: struct.TypeHandle.html
pub type TypeTable = BTreeMap<TypeHandle, TypeDefinition>;
/// TODO
pub type ImplTable = BTreeMap<(), ()>;
/// Base information about a type.
///
/// `T` is what kind of type reference to use, for example a [`GenericType`] or [`QualifiedType`].
///
/// Represents `struct...(*U)` in `struct Def<T, U: Foo<E> + Bar>(*U)`.
///
/// [`GenericType`]: struct.GenericType.html
/// [`QualifiedType`]: struct.QualifiedType.html
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TypeKind<T> {
pub enum Type {
/// Always sized, but specific size depends on target.
Pointer { to: TypeHandle },
/// Used when a primitive type has no other way of declaring the size.
/// None for Unsized, Some for sized.
/// None for unsized, Some for sized.
Primitive { size: Option<crate::NonZeroTargetUSize> },
/// A struct with 0 items has size 0.
Struct { items: Vec<T> },
/// An enum with 0 items has size Never.
Struct(Vec<Field>),
/// An enum with 0 items has size never.
/// An enum with 1 item has size 0.
Enum { num_items: NumEnumEntry },
/// A union with 0 items has size Never.
Union { items: Vec<T> },
Enum(Vec<Identifier>),
/// A union with 0 items has size never.
Union(Vec<Field>),
}
/// A definition of a trait.
///
/// Represents `trait Foo<T> where Self: Bar { ... }`.
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct TraitDefinition {
/// Amount of type parameters. Type parameter 0 is Self.
pub num_type_params: NonZeroNumTypeParam,
/// Requirements to implement the trait.
impl Type {
/// Calculate the size of this type.
///
/// This should generally used to specify requirements of type parameters,
/// but it can be used to specify requirements of any types.
///
/// Type parameter 0 is Self.
pub clauses: Vec<(GenericType, Binding)>,
/// TODO: named constants and statics required by the trait. functions are just statics
pub associations: (),
}
/// A reference to a trait. You should usually only use this in a [`Binding`].
///
/// Represents `Foo<T>` or `Bar` in `struct Def<T, U: Foo<T> + Bar>(*U)`.
///
/// [`Binding`]: struct.Binding.html
#[derive(Debug, Clone)]
pub struct GenericTrait {
/// Used to get the trait definition from the trait table.
handle: TypeHandle,
/// Fills type parameters of the trait.
///
/// This should be one less than the number of trait parameters on the trait definition
/// (Self isn't filled).
type_params: Vec<GenericType>,
}
/// A binding created from a generic.
///
/// Represents `Foo<T> + Bar` in `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
#[derive(Debug, Clone)]
pub struct Binding(Vec<GenericTrait>);
/// A definition of a type.
///
/// Represents `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
///
/// Also see [`TypeKind`].
///
/// [`TypeKind`]: enum.TypeKind.html
#[derive(Debug, Clone)]
pub struct TypeDefinition {
/// Amount of type parameters.
pub num_type_params: NumTypeParam,
/// Requirements to instantiate the struct.
///
/// This should generally used to specify requirements of type parameters,
/// but it can be used to specify requirements of any types.
pub clauses: Vec<(GenericType, Binding)>,
/// The basic contents of this type.
pub kind: TypeKind<GenericType>,
}
impl TypeDefinition {
/// Fill the generics of this type.
/// This is an expensive operation.
pub fn qualify(&self, generics: Vec<QualifiedType>, type_table: &TypeTable) -> QualifiedType {
todo!("implement TypeDefinition::qualify")
}
}
/// A binding from a generic or a type that may use bindings.
///
/// Represents `*U` or the two last `U`s in `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
#[derive(Debug, Clone)]
pub enum GenericType {
/// A generic type parameter.
///
/// The user should already have a [`TypeDefinition`] or [`TraitDefinition`] this applies to.
///
/// [`TypeDefinition`]: struct.TypeDefinition.html
/// [`TraitDefinition`]: struct.TraitDefinition.html
TypeParam(NumTypeParam),
/// A reference to a type.
Real {
/// Used to get the type definition from the type table.
handle: TypeHandle,
/// Fills type parameters of the trait.
///
/// This should match the number of type parameters on the type definition.
type_params: Vec<GenericType>
},
}
impl GenericType {
pub fn real(
type_table: &TypeTable,
handle: TypeHandle,
type_params: Vec<GenericType>,
) -> Result<Self, ()> {
let t = type_table.get(&handle).ok_or(todo!("InvalidHandleError"))?;
let num_type_params = NumTypeParam::try_from(type_params.len());
if Ok(t.num_type_params) != num_type_params {
return Err(todo!("incorrect generic length error"));
}
Ok(Self::Real {
handle,
type_params,
})
}
}
/// Type with all generics specified.
///
/// Represents `Def(*One<Two>)` from `struct Def<T, U> where U: Foo<T> + Bar (*U)`.
#[derive(Debug, Clone)]
pub struct QualifiedType {
pub kind: TypeKind<QualifiedType>,
}
impl QualifiedType {
/// Calculate the size of this type. This is an expensive operation.
///
/// TODO: if a type contains itself this will overflow the stack
pub fn calc_size(&self) -> Result<Size, CalcSizeError> {
match self.kind {
TypeKind::Primitive { size: Some(size) } => Ok(Size::Sized(size.into())),
TypeKind::Primitive { size: None } => Ok(Size::Dynamic),
TypeKind::Struct { ref items } =>
/// TODO: if a type contains itself this will overflow the stack.
/// TODO: size can go above target usize and overflow.
pub fn calc_size(&self, type_table: &TypeTable) -> Result<Size, CalcSizeError> {
match self {
Type::Pointer { .. } => Ok(Size::Sized(
core::mem::size_of::<crate::TargetUSize>() as crate::TargetUSize
)),
Type::Primitive { size: Some(size) } => Ok(Size::Sized((*size).into())),
Type::Primitive { size: None } => Ok(Size::Dynamic),
Type::Struct(ref items) =>
match items.iter().try_fold(
Size::Sized(0), |a, b| {
match b.calc_size() {
let Some(type_) = type_table.get(&b.type_) else {
return Err(Err(FindTypeError.into()))
};
match type_.calc_size(type_table) {
Err(x) => Err(Err(x)),
Ok(Size::Never) => Err(Ok(Size::Never)),
Ok(size) => (a + size).map_err(|x| Err(x.into())),
@ -198,10 +74,13 @@ impl QualifiedType {
Ok(result) => Ok(result),
Err(result) => result,
},
TypeKind::Enum { num_items: _ } => Ok(todo!("calculate enum size")),
TypeKind::Union { ref items } => match items.iter().try_fold(
Type::Enum(ref items) => Ok(todo!("calculate enum size")),
Type::Union(ref items) => match items.iter().try_fold(
Option::<crate::TargetUSize>::None, |a, b| {
match b.calc_size() {
let Some(type_) = type_table.get(&b.type_) else {
return Err(Err(FindTypeError.into()))
};
match type_.calc_size(type_table) {
Err(x) => Err(Err(x)),
Ok(Size::Sized(size)) => Ok(a.map(|a| a.max(size)).or(Some(size))),
Ok(Size::Dynamic) => Err(Ok(Size::Dynamic)),
@ -296,7 +175,6 @@ impl PartialOrd for Size {
(_, Dynamic) => Some(Less),
(Dynamic, _) => Some(Greater),
}
}
}
impl core::ops::Add for Size {