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
|
// def math add [ Numeric Numeric ] -> Numeric
|
||||||
ns.register_command(
|
ns.register_command(
|
||||||
CMD_ADD,
|
CMD_ADD,
|
||||||
Some(TypeDef::List(vec![
|
vec![("T", vec![&numeric])],
|
||||||
TypeDef::Trait(numeric),
|
Some(&TypeDef::List(vec![
|
||||||
TypeDef::Trait(numeric),
|
TypeDef::Generic("T".to_owned()),
|
||||||
|
TypeDef::Generic("T".to_owned()),
|
||||||
])),
|
])),
|
||||||
Some(TypeDef::Trait(numeric)),
|
Some(&TypeDef::Generic("T".to_owned())),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.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::Debug;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
use super::typedef::{InternalTypeDef, TypeDef};
|
use super::typedef::{InternalTypeDef, TypeDef};
|
||||||
use super::CommandId;
|
use super::CommandId;
|
||||||
|
use super::TraitId;
|
||||||
|
|
||||||
use super::GlobalNamespace;
|
use super::GlobalNamespace;
|
||||||
|
|
||||||
|
@ -25,7 +27,7 @@ impl<'a> Command<'a> {
|
||||||
.input
|
.input
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|inputs| match inputs {
|
.map(|inputs| match inputs {
|
||||||
InternalTypeDef::Single(_) => 1,
|
InternalTypeDef::Single(_) | InternalTypeDef::Generic(_) => 1,
|
||||||
InternalTypeDef::List(list) => list.len(),
|
InternalTypeDef::List(list) => list.len(),
|
||||||
InternalTypeDef::Record(rec) => rec.len(),
|
InternalTypeDef::Record(rec) => rec.len(),
|
||||||
})
|
})
|
||||||
|
@ -68,5 +70,4 @@ pub(super) struct InternalCommand {
|
||||||
// gosh this is hacky
|
// gosh this is hacky
|
||||||
pub(super) input: Option<InternalTypeDef>,
|
pub(super) input: Option<InternalTypeDef>,
|
||||||
pub(super) output: Option<InternalTypeDef>,
|
pub(super) output: Option<InternalTypeDef>,
|
||||||
// generic_ns: HashMap<String, Vec<usize>>,
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,15 +102,37 @@ impl GlobalNamespace {
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
/// Will return `NsRegistrationError::NameAlreadyExists` if the desired name is already in use
|
/// Will return `NsRegistrationError::NameAlreadyExists` if the desired name is already in use
|
||||||
pub fn register_command(
|
pub fn register_command<'a>(
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &'a str,
|
||||||
input: Option<TypeDef>,
|
// TODO: refacto with builder pattern maybe?
|
||||||
output: Option<TypeDef>,
|
generics: Vec<(&'a str, Vec<&Trait>)>,
|
||||||
) -> Result<Command, NsRegistrationError> {
|
input: Option<&'a TypeDef>,
|
||||||
|
output: Option<&'a TypeDef>,
|
||||||
|
) -> Result<Command, NsRegistrationError<'a>> {
|
||||||
if self.data_namespace.borrow().contains_key(name) {
|
if self.data_namespace.borrow().contains_key(name) {
|
||||||
Err(NsRegistrationError::NameAlreadyExists)
|
Err(NsRegistrationError::NameAlreadyExists)
|
||||||
} else {
|
} 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 {
|
self.commands.borrow_mut().push(InternalCommand {
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
input: input.map(std::convert::Into::into),
|
input: input.map(std::convert::Into::into),
|
||||||
|
@ -184,6 +206,8 @@ impl GlobalNamespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum NsRegistrationError {
|
pub enum NsRegistrationError<'a> {
|
||||||
NameAlreadyExists,
|
NameAlreadyExists,
|
||||||
|
GenericNameAlreadyExists,
|
||||||
|
UnregisteredGenericsUsed(Vec<&'a str>),
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
|
|
||||||
|
use super::TraitId;
|
||||||
|
use super::TypeId;
|
||||||
use super::TypeNamespaceId;
|
use super::TypeNamespaceId;
|
||||||
|
|
||||||
use super::GlobalNamespace;
|
use super::GlobalNamespace;
|
||||||
|
@ -10,25 +13,76 @@ use super::r#type::Type;
|
||||||
|
|
||||||
pub enum TypeDef<'a> {
|
pub enum TypeDef<'a> {
|
||||||
Type(Type<'a>),
|
Type(Type<'a>),
|
||||||
Trait(Trait<'a>),
|
Generic(String),
|
||||||
List(Vec<TypeDef<'a>>),
|
List(Vec<TypeDef<'a>>),
|
||||||
Record(Vec<(String, TypeDef<'a>)>),
|
Record(Vec<(String, TypeDef<'a>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> 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> {
|
pub(super) fn from_internal(ns: &'a GlobalNamespace, def: &InternalTypeDef) -> TypeDef<'a> {
|
||||||
match def {
|
match def {
|
||||||
InternalTypeDef::Single(id) => match id {
|
InternalTypeDef::Single(id) => TypeDef::Type(
|
||||||
// safe to unwrap because this is only used with internal representations
|
ns.get_type(*id)
|
||||||
TypeNamespaceId::Types(id) => TypeDef::Type(
|
.expect("Unregistered internal type ID. This is a bug."),
|
||||||
ns.get_type(*id)
|
),
|
||||||
.expect("Incorrect internal type id. This is a bug."),
|
InternalTypeDef::Generic(name) => TypeDef::Generic(name.clone()),
|
||||||
),
|
|
||||||
TypeNamespaceId::Traits(id) => TypeDef::Trait(
|
|
||||||
ns.get_trait(*id)
|
|
||||||
.expect("Incorrect internal trait id. This is a bug."),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
InternalTypeDef::List(list) => TypeDef::List(
|
InternalTypeDef::List(list) => TypeDef::List(
|
||||||
list.iter()
|
list.iter()
|
||||||
.map(|def| Self::from_internal(ns, def))
|
.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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TypeDef::Type(t) => Display::fmt(&t, f),
|
TypeDef::Type(t) => Display::fmt(&t, f),
|
||||||
TypeDef::Trait(t) => Display::fmt(&t, f),
|
TypeDef::Generic(name) => Display::fmt(name, f),
|
||||||
TypeDef::List(l) => {
|
TypeDef::List(l) => {
|
||||||
f.write_str("[ ")?;
|
f.write_str("[ ")?;
|
||||||
for (i, item) in l.iter().enumerate() {
|
if let Some(first) = l.first() {
|
||||||
if i != 0 {
|
Display::fmt(&first, f)?;
|
||||||
f.write_str(", ")?;
|
}
|
||||||
}
|
for (i, item) in l.iter().skip(1).enumerate() {
|
||||||
|
f.write_str(", ")?;
|
||||||
Display::fmt(&item, f)?;
|
Display::fmt(&item, f)?;
|
||||||
}
|
}
|
||||||
f.write_str(" ]")
|
f.write_str(" ]")
|
||||||
|
@ -76,7 +131,7 @@ impl Debug for TypeDef<'_> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
TypeDef::Type(t) => Debug::fmt(&t, f),
|
TypeDef::Type(t) => Debug::fmt(&t, f),
|
||||||
TypeDef::Trait(t) => Debug::fmt(&t, f),
|
TypeDef::Generic(name) => Debug::fmt(name, f),
|
||||||
TypeDef::List(l) => {
|
TypeDef::List(l) => {
|
||||||
f.write_str("[ ")?;
|
f.write_str("[ ")?;
|
||||||
for (i, item) in l.iter().enumerate() {
|
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 {
|
pub(super) enum InternalTypeDef {
|
||||||
Single(TypeNamespaceId),
|
Single(TypeId),
|
||||||
|
Generic(String),
|
||||||
List(Vec<InternalTypeDef>),
|
List(Vec<InternalTypeDef>),
|
||||||
Record(Vec<(String, InternalTypeDef)>),
|
Record(Vec<(String, InternalTypeDef)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<TypeDef<'_>> for InternalTypeDef {
|
impl From<&TypeDef<'_>> for InternalTypeDef {
|
||||||
fn from(value: TypeDef) -> Self {
|
fn from(value: &TypeDef) -> Self {
|
||||||
match value {
|
match value {
|
||||||
TypeDef::Type(val) => Self::Single(TypeNamespaceId::Types(val.id)),
|
TypeDef::Type(val) => Self::Single(val.id),
|
||||||
TypeDef::Trait(val) => Self::Single(TypeNamespaceId::Traits(val.id)),
|
// TODO: rewrite this to be better
|
||||||
|
TypeDef::Generic(name) => Self::Generic(name.to_owned()),
|
||||||
TypeDef::List(list) => {
|
TypeDef::List(list) => {
|
||||||
Self::List(list.into_iter().map(std::convert::Into::into).collect())
|
Self::List(list.into_iter().map(std::convert::Into::into).collect())
|
||||||
}
|
}
|
||||||
TypeDef::Record(rec) => Self::Record(
|
TypeDef::Record(rec) => Self::Record(
|
||||||
rec.into_iter()
|
rec.into_iter()
|
||||||
.map(|(name, typ)| (name, typ.into()))
|
.map(|(name, typ)| (name.to_owned(), typ.into()))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
@ -195,7 +195,7 @@ impl<'a> ConcreteTypeDef<'a> {
|
||||||
fn try_from_typedef(val: &TypeDef<'a>) -> Option<Self> {
|
fn try_from_typedef(val: &TypeDef<'a>) -> Option<Self> {
|
||||||
match val {
|
match val {
|
||||||
TypeDef::Type(typ) => Some(Self::Single(*typ)),
|
TypeDef::Type(typ) => Some(Self::Single(*typ)),
|
||||||
TypeDef::Trait(_) => None,
|
TypeDef::Generic(_) => todo!(),
|
||||||
TypeDef::List(list) => {
|
TypeDef::List(list) => {
|
||||||
let out: Vec<ConcreteTypeDef<'a>> =
|
let out: Vec<ConcreteTypeDef<'a>> =
|
||||||
list.iter().filter_map(Self::try_from_typedef).collect();
|
list.iter().filter_map(Self::try_from_typedef).collect();
|
||||||
|
|
Loading…
Reference in a new issue