forked from katzen-cafe/iowo
implement basics of generics and generic checking
This commit is contained in:
parent
1acb5ef3cf
commit
ab7ff35d6c
6 changed files with 146 additions and 43 deletions
|
@ -26,11 +26,12 @@ pub fn initialise_globals() -> GlobalNamespace {
|
|||
// def math add [ Numeric Numeric ] -> Numeric
|
||||
ns.register_command(
|
||||
CMD_ADD,
|
||||
Some(TypeDef::List(vec![
|
||||
TypeDef::Trait(numeric),
|
||||
TypeDef::Trait(numeric),
|
||||
vec![("T", vec![&numeric])],
|
||||
Some(&TypeDef::List(vec![
|
||||
TypeDef::Generic("T".to_owned()),
|
||||
TypeDef::Generic("T".to_owned()),
|
||||
])),
|
||||
Some(TypeDef::Trait(numeric)),
|
||||
Some(&TypeDef::Generic("T".to_owned())),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
|
26
src/globals.rs
Normal file
26
src/globals.rs
Normal file
|
@ -0,0 +1,26 @@
|
|||
// concepts
|
||||
// root type namespace
|
||||
// -> builtin types/traits/functions
|
||||
// -> builtin constants
|
||||
//
|
||||
// generic item namespaces
|
||||
// -> in generic functions ( `add<T: Num> [ T T ] -> T` )
|
||||
// -> in generic types ( vec<T> )
|
||||
// -> generic traits ( T: From<E> )
|
||||
//
|
||||
// TODO: how builtins? just compile everything to builtin types/defs?
|
||||
|
||||
/// This is the root type namespace.
|
||||
struct RootTypeNamespace {
|
||||
|
||||
}
|
||||
|
||||
mod r#type {
|
||||
|
||||
}
|
||||
struct Type<'a> {
|
||||
pub(super) id: usize,
|
||||
pub(super) namespace: &'a GlobalNamespace,
|
||||
}
|
||||
|
||||
struct InternalType
|
|
@ -1,8 +1,10 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::typedef::{InternalTypeDef, TypeDef};
|
||||
use super::CommandId;
|
||||
use super::TraitId;
|
||||
|
||||
use super::GlobalNamespace;
|
||||
|
||||
|
@ -25,7 +27,7 @@ impl<'a> Command<'a> {
|
|||
.input
|
||||
.as_ref()
|
||||
.map(|inputs| match inputs {
|
||||
InternalTypeDef::Single(_) => 1,
|
||||
InternalTypeDef::Single(_) | InternalTypeDef::Generic(_) => 1,
|
||||
InternalTypeDef::List(list) => list.len(),
|
||||
InternalTypeDef::Record(rec) => rec.len(),
|
||||
})
|
||||
|
@ -68,5 +70,4 @@ pub(super) struct InternalCommand {
|
|||
// gosh this is hacky
|
||||
pub(super) input: Option<InternalTypeDef>,
|
||||
pub(super) output: Option<InternalTypeDef>,
|
||||
// generic_ns: HashMap<String, Vec<usize>>,
|
||||
}
|
||||
|
|
|
@ -102,15 +102,37 @@ impl GlobalNamespace {
|
|||
/// # Errors
|
||||
///
|
||||
/// Will return `NsRegistrationError::NameAlreadyExists` if the desired name is already in use
|
||||
pub fn register_command(
|
||||
pub fn register_command<'a>(
|
||||
&self,
|
||||
name: &str,
|
||||
input: Option<TypeDef>,
|
||||
output: Option<TypeDef>,
|
||||
) -> Result<Command, NsRegistrationError> {
|
||||
name: &'a str,
|
||||
// TODO: refacto with builder pattern maybe?
|
||||
generics: Vec<(&'a str, Vec<&Trait>)>,
|
||||
input: Option<&'a TypeDef>,
|
||||
output: Option<&'a TypeDef>,
|
||||
) -> Result<Command, NsRegistrationError<'a>> {
|
||||
if self.data_namespace.borrow().contains_key(name) {
|
||||
Err(NsRegistrationError::NameAlreadyExists)
|
||||
} else {
|
||||
let mut internal_generics_namespace: HashMap<String, Vec<TraitId>> = HashMap::new();
|
||||
|
||||
for (name, conditions) in generics {
|
||||
if internal_generics_namespace.contains_key(name) {
|
||||
return Err(NsRegistrationError::GenericNameAlreadyExists);
|
||||
}
|
||||
internal_generics_namespace
|
||||
.insert(name.to_string(), conditions.iter().map(|t| t.id).collect());
|
||||
}
|
||||
|
||||
if let Some(def) = input {
|
||||
def.check_generics_exist(&internal_generics_namespace)
|
||||
.map_err(NsRegistrationError::UnregisteredGenericsUsed)?;
|
||||
}
|
||||
|
||||
if let Some(def) = output {
|
||||
def.check_generics_exist(&internal_generics_namespace)
|
||||
.map_err(NsRegistrationError::UnregisteredGenericsUsed)?;
|
||||
}
|
||||
|
||||
self.commands.borrow_mut().push(InternalCommand {
|
||||
name: name.to_owned(),
|
||||
input: input.map(std::convert::Into::into),
|
||||
|
@ -184,6 +206,8 @@ impl GlobalNamespace {
|
|||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NsRegistrationError {
|
||||
pub enum NsRegistrationError<'a> {
|
||||
NameAlreadyExists,
|
||||
GenericNameAlreadyExists,
|
||||
UnregisteredGenericsUsed(Vec<&'a str>),
|
||||
}
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
use std::collections::HashMap;
|
||||
use std::fmt::Debug;
|
||||
use std::fmt::Display;
|
||||
|
||||
use super::TraitId;
|
||||
use super::TypeId;
|
||||
use super::TypeNamespaceId;
|
||||
|
||||
use super::GlobalNamespace;
|
||||
|
@ -10,25 +13,76 @@ use super::r#type::Type;
|
|||
|
||||
pub enum TypeDef<'a> {
|
||||
Type(Type<'a>),
|
||||
Trait(Trait<'a>),
|
||||
Generic(String),
|
||||
List(Vec<TypeDef<'a>>),
|
||||
Record(Vec<(String, TypeDef<'a>)>),
|
||||
}
|
||||
|
||||
impl<'a> TypeDef<'a> {
|
||||
pub(super) fn check_generics_exist(
|
||||
&'a self,
|
||||
map: &HashMap<String, Vec<TraitId>>,
|
||||
) -> Result<(), Vec<&'a str>> {
|
||||
match self {
|
||||
TypeDef::Type(_) => Ok(()),
|
||||
TypeDef::Generic(name) => {
|
||||
if map.contains_key(name) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(vec![name])
|
||||
}
|
||||
}
|
||||
TypeDef::List(defs) => {
|
||||
let r = defs
|
||||
.into_iter()
|
||||
.map(|def| def.check_generics_exist(map))
|
||||
.filter_map(|check_res| {
|
||||
if let Err(invalid_names) = check_res {
|
||||
Some(invalid_names)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.reduce(|mut acc, mut errs| {
|
||||
acc.append(&mut errs);
|
||||
acc
|
||||
});
|
||||
|
||||
match r {
|
||||
Some(e) => Err(e),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
TypeDef::Record(rec) => {
|
||||
let r = rec
|
||||
.into_iter()
|
||||
.map(|(n, def)| def.check_generics_exist(map))
|
||||
.filter_map(|check_res| {
|
||||
if let Err(invalid_names) = check_res {
|
||||
Some(invalid_names)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.reduce(|mut acc, mut errs| {
|
||||
acc.append(&mut errs);
|
||||
acc
|
||||
});
|
||||
|
||||
match r {
|
||||
Some(e) => Err(e),
|
||||
None => Ok(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
pub(super) fn from_internal(ns: &'a GlobalNamespace, def: &InternalTypeDef) -> TypeDef<'a> {
|
||||
match def {
|
||||
InternalTypeDef::Single(id) => match id {
|
||||
// safe to unwrap because this is only used with internal representations
|
||||
TypeNamespaceId::Types(id) => TypeDef::Type(
|
||||
InternalTypeDef::Single(id) => TypeDef::Type(
|
||||
ns.get_type(*id)
|
||||
.expect("Incorrect internal type id. This is a bug."),
|
||||
.expect("Unregistered internal type ID. This is a bug."),
|
||||
),
|
||||
TypeNamespaceId::Traits(id) => TypeDef::Trait(
|
||||
ns.get_trait(*id)
|
||||
.expect("Incorrect internal trait id. This is a bug."),
|
||||
),
|
||||
},
|
||||
InternalTypeDef::Generic(name) => TypeDef::Generic(name.clone()),
|
||||
InternalTypeDef::List(list) => TypeDef::List(
|
||||
list.iter()
|
||||
.map(|def| Self::from_internal(ns, def))
|
||||
|
@ -47,13 +101,14 @@ impl Display for TypeDef<'_> {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
TypeDef::Type(t) => Display::fmt(&t, f),
|
||||
TypeDef::Trait(t) => Display::fmt(&t, f),
|
||||
TypeDef::Generic(name) => Display::fmt(name, f),
|
||||
TypeDef::List(l) => {
|
||||
f.write_str("[ ")?;
|
||||
for (i, item) in l.iter().enumerate() {
|
||||
if i != 0 {
|
||||
f.write_str(", ")?;
|
||||
if let Some(first) = l.first() {
|
||||
Display::fmt(&first, f)?;
|
||||
}
|
||||
for (i, item) in l.iter().skip(1).enumerate() {
|
||||
f.write_str(", ")?;
|
||||
Display::fmt(&item, f)?;
|
||||
}
|
||||
f.write_str(" ]")
|
||||
|
@ -76,7 +131,7 @@ impl Debug for TypeDef<'_> {
|
|||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
TypeDef::Type(t) => Debug::fmt(&t, f),
|
||||
TypeDef::Trait(t) => Debug::fmt(&t, f),
|
||||
TypeDef::Generic(name) => Debug::fmt(name, f),
|
||||
TypeDef::List(l) => {
|
||||
f.write_str("[ ")?;
|
||||
for (i, item) in l.iter().enumerate() {
|
||||
|
@ -107,29 +162,25 @@ impl<'a> From<Type<'a>> for TypeDef<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Trait<'a>> for TypeDef<'a> {
|
||||
fn from(value: Trait<'a>) -> Self {
|
||||
TypeDef::Trait(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) enum InternalTypeDef {
|
||||
Single(TypeNamespaceId),
|
||||
Single(TypeId),
|
||||
Generic(String),
|
||||
List(Vec<InternalTypeDef>),
|
||||
Record(Vec<(String, InternalTypeDef)>),
|
||||
}
|
||||
|
||||
impl From<TypeDef<'_>> for InternalTypeDef {
|
||||
fn from(value: TypeDef) -> Self {
|
||||
impl From<&TypeDef<'_>> for InternalTypeDef {
|
||||
fn from(value: &TypeDef) -> Self {
|
||||
match value {
|
||||
TypeDef::Type(val) => Self::Single(TypeNamespaceId::Types(val.id)),
|
||||
TypeDef::Trait(val) => Self::Single(TypeNamespaceId::Traits(val.id)),
|
||||
TypeDef::Type(val) => Self::Single(val.id),
|
||||
// TODO: rewrite this to be better
|
||||
TypeDef::Generic(name) => Self::Generic(name.to_owned()),
|
||||
TypeDef::List(list) => {
|
||||
Self::List(list.into_iter().map(std::convert::Into::into).collect())
|
||||
}
|
||||
TypeDef::Record(rec) => Self::Record(
|
||||
rec.into_iter()
|
||||
.map(|(name, typ)| (name, typ.into()))
|
||||
.map(|(name, typ)| (name.to_owned(), typ.into()))
|
||||
.collect(),
|
||||
),
|
||||
}
|
||||
|
|
|
@ -195,7 +195,7 @@ impl<'a> ConcreteTypeDef<'a> {
|
|||
fn try_from_typedef(val: &TypeDef<'a>) -> Option<Self> {
|
||||
match val {
|
||||
TypeDef::Type(typ) => Some(Self::Single(*typ)),
|
||||
TypeDef::Trait(_) => None,
|
||||
TypeDef::Generic(_) => todo!(),
|
||||
TypeDef::List(list) => {
|
||||
let out: Vec<ConcreteTypeDef<'a>> =
|
||||
list.iter().filter_map(Self::try_from_typedef).collect();
|
||||
|
|
Loading…
Reference in a new issue