From a1b95c58927a4c985e7bf9f19616cfd7796953e5 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Fri, 30 Apr 2021 03:49:53 +0200
Subject: [PATCH] type terms, first parsing & serialization

---
 math/radix_transform/src/main.rs | 116 ++++++++++++++++++---------
 nested/src/bimap.rs              |  28 +++++++
 nested/src/core/context.rs       | 133 +++++++++++++++++++++++++++++++
 nested/src/core/mod.rs           |  12 +++
 nested/src/core/type_term.rs     | 133 +++++++++++++++++++++++++++++++
 nested/src/lib.rs                |   3 +
 6 files changed, 386 insertions(+), 39 deletions(-)
 create mode 100644 nested/src/bimap.rs
 create mode 100644 nested/src/core/context.rs
 create mode 100644 nested/src/core/type_term.rs

diff --git a/math/radix_transform/src/main.rs b/math/radix_transform/src/main.rs
index 1440884..220a6cf 100644
--- a/math/radix_transform/src/main.rs
+++ b/math/radix_transform/src/main.rs
@@ -8,7 +8,9 @@ use {
             Observer,
             ObserverBroadcast,
             InnerViewPort,
-            OuterViewPort
+            OuterViewPort,
+            TypeTerm,
+            TypeDict
         },
         sequence::{SequenceView, VecBuffer},
         integer::{RadixProjection}
@@ -17,6 +19,23 @@ use {
 
 #[async_std::main]
 async fn main() {
+    let mut td = TypeDict::new();
+    for tn in vec![
+        "MachineWord", "MachineInt", "MachineSlab",
+        "Vec", "NullTerminatedString",
+        "Sequence", "Ascii",
+        "PositionalInt", "Digit", "LittleEndian", "BigEndian",
+        "DiffStream", "ℕ"
+    ] { td.add_typename(tn.into()); }
+
+    let radix_types = vec![
+        td.type_term_from_str("( ℕ )").unwrap(),
+        td.type_term_from_str("( PositionalInt 10 LittleEndian )").unwrap(),
+        td.type_term_from_str("( Sequence ( Digit 10 ) )").unwrap(),
+        td.type_term_from_str("( Sequence Ascii )").unwrap(),
+        td.type_term_from_str("( Sequence MachineSlab )").unwrap()
+    ];
+
     nested::magic_header();
     eprintln!("    Convert Radix of Positional Integer");
     nested::magic_header();
@@ -24,50 +43,69 @@ async fn main() {
     let mut args = std::env::args();
     args.next().expect("Arg $0 missing!");
 
-    eprintln!("
-$1: src_radix
-  ( ℕ )
-  ( PositionalInt 10 LittleEndian )
-  ( Sequence (Digit 10) )
-  ( Sequence Ascii )
-  ( ArgString )
-");
+    eprintln!("\n$1: src_radix");
+    for t in radix_types.iter() {
+        eprintln!("  {}", td.type_term_to_str(t));
+    }
+
+    eprintln!("\n$2: dst_radix");
+    for t in radix_types.iter() {
+        eprintln!("  {}", td.type_term_to_str(t));
+    }
+
     let src_radix_str = args.next().expect("Arg $1 required!");
-
-    
-    eprintln!("
-$2: dst_radix
-  ( ℕ )
-  ( PositionalInt 10 LittleEndian )
-  ( Sequence (Digit 10) )
-  ( Sequence Ascii )
-  ( ArgString )
-");
     let dst_radix_str = args.next().expect("Arg $2 required!");
-    
-    eprintln!("
->0: n
-  ( ℕ ) ~~ <1
-  ( PositionalInt src_radix LittleEndian )
-  ( Sequence (Digit src_radix) )
-  ( Sequence MachineInt )
-  ( PipeStream bincode (SequenceDiff MachineInt) )
-");
-
-    eprintln!("
-<1: n
-  ( ℕ ) ~~ >0
-  ( PositionalInt dst_radix LittleEndian )
-  ( Sequence (Digit dst_radix) )
-  ( Sequence MachineInt )
-  ( PipeStream bincode (SequenceDiff MachineInt) )
-");
-
-    nested::magic_header();
 
     let src_radix = usize::from_str_radix(&src_radix_str, 10).expect("could not parse src_radix");
     let dst_radix = usize::from_str_radix(&dst_radix_str, 10).expect("could not parse dst_radix");
 
+    let in_types = vec![
+        td.type_term_from_str("( ℕ )").unwrap(),
+        td.type_term_from_str("( PositionalInt )").unwrap()
+            .num_arg(src_radix as i64)
+            .arg(td.type_term_from_str("( LittleEndian )").unwrap())
+            .clone(),
+
+        td.type_term_from_str("( Sequence )").unwrap()
+            .arg(
+                td.type_term_from_str("( Digit )").unwrap()
+                    .num_arg(src_radix as i64).clone()
+            )
+            .clone(),
+
+        td.type_term_from_str("( Sequence MachineInt )").unwrap(),
+        td.type_term_from_str("( DiffStream ( Vec MachineInt ) )").unwrap(),
+    ];
+
+    let out_types = vec![
+        td.type_term_from_str("( ℕ )").unwrap(),
+        td.type_term_from_str("( PositionalInt )").unwrap()
+            .num_arg(dst_radix as i64)
+            .arg(td.type_term_from_str("( LittleEndian )").unwrap()).clone(),
+
+        td.type_term_from_str("( Sequence )").unwrap()
+            .arg(
+                td.type_term_from_str("( Digit )").unwrap()
+                    .num_arg(dst_radix as i64).clone()
+            )
+            .clone(),
+
+        td.type_term_from_str("( Sequence MachineInt )").unwrap(),
+        td.type_term_from_str("( DiffStream ( Vec MachineInt ) )").unwrap(),
+    ];
+
+    eprintln!("\n>0: n");
+    for t in in_types.iter() {
+        eprintln!("  {}", td.type_term_to_str(t));
+    }
+
+    eprintln!("\n<1: n");
+    for t in out_types.iter() {
+        eprintln!("  {}", td.type_term_to_str(t));
+    }
+
+    nested::magic_header();
+
     let src_digits_port = ViewPort::new();
     let dst_digits_port = ViewPort::new();
 
diff --git a/nested/src/bimap.rs b/nested/src/bimap.rs
new file mode 100644
index 0000000..202df48
--- /dev/null
+++ b/nested/src/bimap.rs
@@ -0,0 +1,28 @@
+use std::{
+    collections::HashMap,
+    hash::Hash
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct Bimap<V: Eq + Hash, Λ: Eq + Hash> {
+    pub mλ: HashMap::<V, Λ>,
+    pub my: HashMap::<Λ, V>
+}
+
+impl<V: Eq + Hash + Clone, Λ: Eq + Hash + Clone> Bimap<V, Λ> {
+    pub fn new() -> Self {
+        Bimap {
+            mλ: HashMap::new(),
+            my: HashMap::new()
+        }
+    }
+
+    pub fn insert(&mut self, y: V, λ: Λ) {
+        self.mλ.insert(y.clone(), λ.clone());
+        self.my.insert(λ, y);
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
diff --git a/nested/src/core/context.rs b/nested/src/core/context.rs
new file mode 100644
index 0000000..47d85d5
--- /dev/null
+++ b/nested/src/core/context.rs
@@ -0,0 +1,133 @@
+use {
+    std::{
+        collections::HashMap,
+        sync::{Arc, RwLock},
+        any::Any
+    },
+    crate::{
+        bimap::Bimap,
+        core::type_term::{TypeID, TypeTerm}
+    }
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub enum ReprTree {
+    Leaf(Arc<dyn Any + Send + Sync>),
+    Branch(HashMap<TypeTerm, Arc<RwLock<ReprTree>>>)
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+#[derive(Clone)]
+pub struct Object {
+    type_tag: TypeTerm,
+    repr: Arc<RwLock<ReprTree>>
+}
+
+impl Object {
+    fn downcast(&self, repr_type: TypeTerm) -> Option<Object> {
+        match &*self.repr.read().unwrap() {
+            ReprTree::Leaf(data) =>
+                if self.type_tag == repr_type {
+                    Some(self.clone())
+                } else {
+                    None
+                },
+            ReprTree::Branch(reprs) =>
+                Some(Object{
+                    type_tag: repr_type.clone(),
+                    repr: reprs.get(&repr_type)?.clone()
+                })
+        }
+    }
+
+    fn downcast_chain<'a>(
+        &self,
+        repr_chain: impl Iterator<Item = &'a TypeTerm>
+    ) -> Option<Object> {
+        repr_chain.fold(
+            Some(self.clone()),
+            |s, t| s?.downcast(t.clone())
+        )
+    }
+
+    fn get_data<T: Any + Send + Sync>(&self) -> Option<Arc<T>> {
+        match &*self.repr.read().unwrap() {
+            ReprTree::Leaf(data) => Arc::downcast::<T>(data.clone()).ok(),
+            _ => None
+        }
+    }    
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct TypeDict {
+    typenames: Bimap::<String, u64>,
+    type_id_counter: u64
+}
+
+impl TypeDict {
+    pub fn new() -> Self {
+        TypeDict {
+            typenames: Bimap::new(),
+            type_id_counter: 0
+        }
+    }
+
+    pub fn add_typename(&mut self, tn: String) {
+        self.typenames.insert(tn, self.type_id_counter);
+        self.type_id_counter += 1;
+    }
+
+    pub fn type_term_from_str(&self, typename: &str) -> Option<TypeTerm> {
+        TypeTerm::from_str(typename, &self.typenames.mλ)
+    }
+
+    pub fn type_term_to_str(&self, term: &TypeTerm) -> String {
+        term.to_str(&self.typenames.my)
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub struct Context {
+    type_dict: TypeDict,
+
+    // map type_id -> constructor
+    constructors: HashMap<u64, Box<Fn() -> Arc<dyn Any + Send + Sync>>>,
+
+    objects: HashMap<String, Object>
+}
+
+impl Context {
+    pub fn add_obj(
+        &mut self,
+        name: String,
+        typename: &str
+    ) {
+        self.objects.insert(
+            name,
+            Object {
+                type_tag: self.type_dict.type_term_from_str(typename).unwrap(),
+                repr: Arc::new(RwLock::new(ReprTree::Branch(HashMap::new())))
+            }
+        );
+    }
+
+    pub fn add_repr(&mut self, name: &String, typename: &str, repr: Arc<RwLock<ReprTree>>) {
+        match &mut *self.objects.get_mut(name).unwrap().repr.write().unwrap() {
+            ReprTree::Leaf(_) => {/*error*/},
+            ReprTree::Branch(repr_map) => {
+                repr_map.insert(self.type_dict.type_term_from_str(typename).unwrap(), repr.clone());
+            }
+        }
+    }
+
+    pub fn get_obj(&self, name: &String) -> Option<Object> {
+        self.objects.get(name).cloned()
+    }
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
diff --git a/nested/src/core/mod.rs b/nested/src/core/mod.rs
index 30c8d6c..a0cb989 100644
--- a/nested/src/core/mod.rs
+++ b/nested/src/core/mod.rs
@@ -3,6 +3,8 @@ pub mod view;
 pub mod observer;
 pub mod channel;
 pub mod port;
+pub mod type_term;
+pub mod context;
 
 pub use {
     view::{View},
@@ -24,6 +26,16 @@ pub use {
         ViewPort,
         InnerViewPort,
         OuterViewPort
+    },
+    type_term::{
+        TypeID,
+        TypeTerm
+    },
+    context::{
+        ReprTree,
+        TypeDict,
+        Context,
+        Object
     }
 };
 
diff --git a/nested/src/core/type_term.rs b/nested/src/core/type_term.rs
new file mode 100644
index 0000000..044413a
--- /dev/null
+++ b/nested/src/core/type_term.rs
@@ -0,0 +1,133 @@
+use std::{
+    sync::Arc,
+    any::Any,
+    ops::Deref,
+    collections::HashMap,
+    iter::Peekable
+};
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+pub type TypeID = u64;
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub enum TypeTerm {
+    Type {
+        id: TypeID,
+        args: Vec<TypeTerm>
+    },
+    Num(i64)
+}
+
+impl TypeTerm {
+    pub fn new(id: TypeID) -> Self {
+        TypeTerm::Type{ id, args: vec![] }
+    }
+
+    pub fn arg(&mut self, t: TypeTerm) -> &mut Self {
+        if let TypeTerm::Type{ id, args } = self {
+            args.push(t);
+        }
+
+        self
+    }
+
+    pub fn num_arg(&mut self, v: i64) -> &mut Self {
+        self.arg(TypeTerm::Num(v))
+    }
+
+    pub fn from_str(s: &str, names: &HashMap<String, u64>) -> Option<Self> {
+        let mut term_stack = Vec::<Option<TypeTerm>>::new();
+
+        for token in s.split_whitespace() {
+            match token {
+                "(" => {
+                    term_stack.push(None);
+                },
+                ")" => {
+                    let t = term_stack.pop().unwrap();
+                    if term_stack.len() > 0 {
+                        let mut f = term_stack.last_mut().unwrap();
+                        if let Some(f) = f {
+                            f.arg(t.unwrap());
+                        } else {
+                            //error
+                        }
+                    } else {
+                        return t;
+                    }
+                },
+                atom => {
+                    let mut f = term_stack.last_mut().unwrap();
+
+                    match f {
+                        Some(f) =>
+                            if atom.chars().nth(0).unwrap().is_numeric() {
+                                f.num_arg(i64::from_str_radix(atom, 10).unwrap());
+                            } else {
+                                f.arg(TypeTerm::new(*names.get(atom).expect(&format!("invalid atom {}", atom))));
+                            }
+                        None => {
+                            *f = Some(TypeTerm::new(*names.get(atom).expect(&format!("invalid atom {}", atom))));
+                        }
+                    }
+                }
+            }
+        }
+
+        None
+    }
+
+    // only adds parenthesis where args.len > 0
+    pub fn to_str1(&self, names: &HashMap<u64, String>) -> String {
+        match self {
+            TypeTerm::Type{ id, args } =>
+                if args.len() > 0 {
+                    format!(
+                        "( {} {})",
+                        names[id],
+                        if args.len() > 0 {
+                            args.iter().fold(
+                                String::new(),
+                                |str, term| format!("{}{} ", str, term.to_str1(names) )
+                            )
+                        } else {
+                            String::new()
+                        }
+                    )
+                } else {
+                    names[id].clone()
+                },
+
+            TypeTerm::Num(n) =>
+                format!("{}", n)
+        }
+    }
+
+    // always adds an enclosing pair of parenthesis
+    pub fn to_str(&self, names: &HashMap<u64, String>) -> String {
+        match self {
+            TypeTerm::Type{ id, args } =>
+                format!(
+                    "( {} {})",
+                    names[id],
+                    if args.len() > 0 {
+                        args.iter().fold(
+                            String::new(),
+                            |str, term| format!("{}{} ", str, term.to_str1(names) )
+                        )
+                    } else {
+                        String::new()
+                    }),
+
+            TypeTerm::Num(n) =>
+                format!("{}", n)
+        }
+    }
+
+}
+
+//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>
+
diff --git a/nested/src/lib.rs b/nested/src/lib.rs
index 6d65631..e9c4c1a 100644
--- a/nested/src/lib.rs
+++ b/nested/src/lib.rs
@@ -1,4 +1,5 @@
 #![feature(trait_alias)]
+#![feature(non_ascii_idents)]
 
 pub mod core;
 pub mod projection;
@@ -13,6 +14,8 @@ pub mod integer;
 pub mod string_editor;
 pub mod leveled_term_view;
 
+pub mod bimap;
+
 pub fn magic_header() {
     eprintln!("<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>");
 }