From ab7ff35d6c0e655f1e2b37dc2549996a69fe3fdf Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Fri, 24 Nov 2023 12:57:06 +0100 Subject: [PATCH] implement basics of generics and generic checking --- src/builtins/mod.rs | 9 ++-- src/globals.rs | 26 +++++++++ src/namespace/command.rs | 5 +- src/namespace/mod.rs | 36 ++++++++++--- src/namespace/typedef.rs | 111 ++++++++++++++++++++++++++++----------- src/typed.rs | 2 +- 6 files changed, 146 insertions(+), 43 deletions(-) create mode 100644 src/globals.rs diff --git a/src/builtins/mod.rs b/src/builtins/mod.rs index ec7db4c..a6e6e2f 100644 --- a/src/builtins/mod.rs +++ b/src/builtins/mod.rs @@ -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(); diff --git a/src/globals.rs b/src/globals.rs new file mode 100644 index 0000000..3de4b77 --- /dev/null +++ b/src/globals.rs @@ -0,0 +1,26 @@ +// concepts +// root type namespace +// -> builtin types/traits/functions +// -> builtin constants +// +// generic item namespaces +// -> in generic functions ( `add [ T T ] -> T` ) +// -> in generic types ( vec ) +// -> generic traits ( T: From ) +// +// 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 diff --git a/src/namespace/command.rs b/src/namespace/command.rs index 0b6fac0..22dcd1a 100644 --- a/src/namespace/command.rs +++ b/src/namespace/command.rs @@ -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, pub(super) output: Option, - // generic_ns: HashMap>, } diff --git a/src/namespace/mod.rs b/src/namespace/mod.rs index bc553ce..1c6beeb 100644 --- a/src/namespace/mod.rs +++ b/src/namespace/mod.rs @@ -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, - output: Option, - ) -> Result { + name: &'a str, + // TODO: refacto with builder pattern maybe? + generics: Vec<(&'a str, Vec<&Trait>)>, + input: Option<&'a TypeDef>, + output: Option<&'a TypeDef>, + ) -> Result> { if self.data_namespace.borrow().contains_key(name) { Err(NsRegistrationError::NameAlreadyExists) } else { + let mut internal_generics_namespace: HashMap> = 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>), } diff --git a/src/namespace/typedef.rs b/src/namespace/typedef.rs index ca4488a..0e1ecc0 100644 --- a/src/namespace/typedef.rs +++ b/src/namespace/typedef.rs @@ -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>), Record(Vec<(String, TypeDef<'a>)>), } impl<'a> TypeDef<'a> { + pub(super) fn check_generics_exist( + &'a self, + map: &HashMap>, + ) -> 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( - ns.get_type(*id) - .expect("Incorrect 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::Single(id) => TypeDef::Type( + ns.get_type(*id) + .expect("Unregistered internal type 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> for TypeDef<'a> { } } -impl<'a> From> for TypeDef<'a> { - fn from(value: Trait<'a>) -> Self { - TypeDef::Trait(value) - } -} - pub(super) enum InternalTypeDef { - Single(TypeNamespaceId), + Single(TypeId), + Generic(String), List(Vec), Record(Vec<(String, InternalTypeDef)>), } -impl From> 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(), ), } diff --git a/src/typed.rs b/src/typed.rs index 0f07b7e..3e7ffbb 100644 --- a/src/typed.rs +++ b/src/typed.rs @@ -195,7 +195,7 @@ impl<'a> ConcreteTypeDef<'a> { fn try_from_typedef(val: &TypeDef<'a>) -> Option { match val { TypeDef::Type(typ) => Some(Self::Single(*typ)), - TypeDef::Trait(_) => None, + TypeDef::Generic(_) => todo!(), TypeDef::List(list) => { let out: Vec> = list.iter().filter_map(Self::try_from_typedef).collect();