move types.rs -> complex_types.rs, simple_types.rs -> types.rs
This commit is contained in:
parent
9eeea6fe08
commit
9b8a1fe0df
5 changed files with 370 additions and 370 deletions
317
src/complex_types.rs
Normal file
317
src/complex_types.rs
Normal 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;
|
|
@ -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;
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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;
|
224
src/types.rs
224
src/types.rs
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue