From a6282c00eb260a56a17890463492536756183a58 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sat, 11 May 2024 18:07:58 +0200
Subject: [PATCH] local function definition via let

---
 src/lexer.rs              |  2 +-
 src/main.rs               | 79 ++++++++++++++--------------------
 src/parser.rs             |  1 +
 src/procedure_compiler.rs | 90 ++++++++++++++++++++++++++++++---------
 src/runtime.rs            | 31 --------------
 5 files changed, 103 insertions(+), 100 deletions(-)

diff --git a/src/lexer.rs b/src/lexer.rs
index 2941c6a..c8cfa86 100644
--- a/src/lexer.rs
+++ b/src/lexer.rs
@@ -143,7 +143,7 @@ where It: Iterator<Item = char>
                     if c.is_whitespace()
                         || *c == '(' || *c == ')'
                         || *c == '{' || *c == '}'
-                        || *c == ';'
+                        || *c == ';' || *c == '=' || *c == ':'
                     {
                         // finish the current token
 
diff --git a/src/main.rs b/src/main.rs
index 0b3dba9..db260a8 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -17,7 +17,7 @@ use crate::{
     procedure_compiler::ProcedureCompiler
 };
 
-fn compile(scope: &Arc<RwLock<Scope>>, source: &str) -> Vec< tisc::assembler::AssemblyWord > {
+fn compile(scope: &Arc<RwLock<Scope>>, name: &str, source: &str) -> Vec< tisc::assembler::AssemblyWord > {
     ProcedureCompiler::new(scope)
         .compile(
             &parser::parse_expr(
@@ -26,8 +26,7 @@ fn compile(scope: &Arc<RwLock<Scope>>, source: &str) -> Vec< tisc::assembler::As
                 ).peekable()
             ).expect("syntax error")
         )
-        .into_asm()
-        .build()
+        .into_asm(&name.into())
 }
 
 fn main() {
@@ -59,34 +58,38 @@ fn main() {
              ~<LengthPrefixedSeq machine::Word>"
         );
 
-    main_scope.write().unwrap()
-        .declare_proc_parse(
-            "print-nullterm",
-            vec![],
-            vec![
-                "<Ref <Seq Char~Ascii~machine::Word>~<NullTerminatedSeq machine::Word>>
-                ~machine::Address
-                ~machine::Word"
-            ],
-            vec![]);
-
-    main_scope.write().unwrap().declare_proc_parse(
-        "print-lenprefix",
-        vec![],
-        vec![
-            "<Ref <Seq Char~Ascii~machine::Word>~<LengthPrefixedSeq machine::Word>>
-            ~machine::Address
-            ~machine::Word"
-        ],
-        vec![]);
-
-
-
     /* link assembly-program to symbols
      */
     linker.add_procedure("main", compile(&main_scope,
+        "main",
         "{
-            print-lenprefix pfxstr;
+            let print-nullterm = λstr {
+                while (@ str) {
+                    emit (@ str);
+                    ! str (i+ str 1);
+                }
+            };
+
+            let print-lenprefix = λstr {
+                let len = (@ str);
+                ! str (i+ str 1);
+                let end = (i+ str len);
+                while (i- str end) {
+                    emit (@ str);
+                    ! str (i+ str 1);
+                }
+            };
+
+            let hello = λ _ {
+                print-nullterm hello-string;
+                print-lenprefix pfxstr;
+            };
+            let isquare = λx (i* x x);
+
+            hello 'X';
+            emit '\n';
+            emit (i+ '0' (isquare 3));
+            emit '\n';
         }"));
 
     linker.add_static("hello-string",
@@ -96,29 +99,9 @@ fn main() {
             .collect());
 
     linker.add_static("pfxstr",
-        vec![ 4, 'a' as tisc::VM_Word, 'b' as tisc::VM_Word, 'c' as tisc::VM_Word, 'd' as tisc::VM_Word ]
+        vec![ 3, 'a' as tisc::VM_Word, 'b' as tisc::VM_Word, 'c' as tisc::VM_Word, 'd' as tisc::VM_Word ]
     );
 
-    linker.add_procedure("print-nullterm", compile(&main_scope,
-            "λ str {
-                while (@ str) {
-                    emit (@ str);
-                    ! str (i+ str 1);
-                }
-            }"));
-
-    linker.add_procedure("print-lenprefix", compile(&main_scope,
-            "λ str {
-                let len = @ str;
-                ! str (i+ str 1);
-                let end = i+ str len;
-                while (i- str end) {
-                    emit (@ str);
-                    ! str (i+ str 1);
-                }
-            }"
-        ));
-
     let main_addr = linker.get_link_addr(&"main".into()).expect("'main' not linked"); 
     vm.load( linker.link_total().expect("could not link") );
     vm.execute( main_addr );
diff --git a/src/parser.rs b/src/parser.rs
index 5a81a07..d80724c 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -57,6 +57,7 @@ where It: Iterator<Item = char>
                 match sym.as_str() {
                     "!" => {
                         tokens.next();
+                        // todo accept address-expression instead of symbol
                         let name = parse_symbol(tokens)?;
                         let val_expr = parse_expr(tokens)?;
                         let _ = parse_expect(tokens, LTIRToken::StatementSep)?;
diff --git a/src/procedure_compiler.rs b/src/procedure_compiler.rs
index 7d69841..b7a23a4 100644
--- a/src/procedure_compiler.rs
+++ b/src/procedure_compiler.rs
@@ -4,6 +4,10 @@ use {
         sync::{Arc, RwLock},
         ops::Deref,
     },
+    tisc::{
+        assembler::AssemblyWord,
+        linker::LinkAddr
+    },
     crate::{
         expr::{LTExpr, Statement},
         symbols::{Scope, SymbolDef}
@@ -27,14 +31,41 @@ impl ProcedureCompiler {
         }
     }
 
-    pub fn into_asm(self) -> tisc::Assembler {
+    pub fn into_asm(mut self, proc_symbol: &String) -> Vec< tisc::assembler::AssemblyWord > {
         let data_frame_size = self.symbols.read().unwrap().get_frame_size() as i64;
-        tisc::Assembler::new()
-            .lit(data_frame_size)
-            .call("data-frame-alloc")
-            .join(self.asm)
-            .lit(data_frame_size)
-            .call("data-frame-drop")
+
+        let body = self.asm.build();
+        self.linker.add_procedure("__procedure_body__", body);
+        let body_addr = self.linker.get_link_addr(&"__procedure_body__".into()).unwrap();
+        let subroutines = self.linker.link_relative(&"__subroutines__".into()).expect("link error");
+
+        let mut entry = tisc::Assembler::new();
+        if data_frame_size > 0 {
+            entry = entry
+                .lit(data_frame_size)
+                .call("data-frame-alloc");
+        }
+        entry = entry
+            .call_symbol( LinkAddr::Relative{ symbol: "__subroutines__".into(), offset: body_addr });
+
+        if data_frame_size > 0 {
+            entry = entry
+                .lit(data_frame_size)
+                .call("data-frame-drop");
+        }
+
+        let mut superlink = tisc::Linker::new();
+        superlink.add_procedure("", entry.build());
+        superlink.add_procedure("__subroutines__", subroutines);
+
+        let bytecode = superlink.link_relative(proc_symbol).expect("link error");
+/*
+        eprintln!("\n\n{}:", proc_symbol);
+        for (i,w) in tisc::assembler::disassemble(&bytecode).iter().enumerate() {
+            eprintln!("{}:\t\t{}", i, w);
+        }
+*/
+        bytecode
     }
 
     pub fn verify(&self) {
@@ -68,18 +99,37 @@ impl ProcedureCompiler {
                 }
             }
             Statement::LetAssign{ var_id, val_expr } => { 
-                self.symbols.write().unwrap()
-                    .declare_var(
-                        var_id.clone(),
-                        laddertypes::TypeTerm::unit()
-                    );
+                match val_expr {
+                    LTExpr::Abstraction { arg_id:_, arg_type:_, val_expr:_ } => {                        
+                        self.symbols.write().unwrap()
+                            .declare_proc(
+                                var_id.clone(),
+                                vec![],vec![]
+                        );
+                        let lambda_procedure =
+                            ProcedureCompiler::new(&self.symbols)
+                                .compile( val_expr )
+                                .into_asm( var_id );
 
-                self = self.compile_statement(
-                    &Statement::Assignment {
-                        var_id: var_id.clone(),
-                        val_expr: val_expr.clone()
+                        self.linker.add_procedure(
+                            var_id,
+                            lambda_procedure
+                        );
                     }
-                );
+                    _ => {
+                        self.symbols.write().unwrap()
+                            .declare_var(
+                                var_id.clone(),
+                                laddertypes::TypeTerm::unit()
+                            );
+                        self = self.compile_statement(
+                            &Statement::Assignment {
+                                var_id: var_id.clone(),
+                                val_expr: val_expr.clone()
+                            }
+                        );
+                    }
+                }
             }
             Statement::WhileLoop { condition, body } => {
                 let asm = self.asm;
@@ -126,7 +176,7 @@ impl ProcedureCompiler {
                         eprintln!("undefined symbol '{}'!", symbol);
                     }
                 }
-            },
+            }
             LTExpr::Literal { typ, val } => {
                 self.asm = self.asm.lit( *val );
             }
@@ -135,7 +185,7 @@ impl ProcedureCompiler {
                     self = self.compile(arg);
                 }
                 self = self.compile(head);
-            },
+            }
             LTExpr::Abstraction { arg_id: arg_name, arg_type, val_expr } => {
                 let id = self.symbols
                     .write().unwrap()
@@ -148,7 +198,7 @@ impl ProcedureCompiler {
                     .call("data-frame-set");
 
                 self = self.compile(val_expr);
-            },
+            }
             LTExpr::Branch { condition, if_expr, else_expr } => {
                 self = self.compile(condition);
 
diff --git a/src/runtime.rs b/src/runtime.rs
index fe43f21..0bf2cce 100644
--- a/src/runtime.rs
+++ b/src/runtime.rs
@@ -193,37 +193,6 @@ pub fn init_runtime(linker: &mut Linker) -> Arc<RwLock<Scope>> {
             .build()
     );
 
-
-    /*
-     *  let isquare = λx.(i* x x);
-     */
-    symbols.write().unwrap().declare_proc_parse(
-        "isquare",
-        vec![],
-        vec![ "ℤ_2^64~machine::UInt64~machine::Word" ],
-        vec![ "ℤ_2^64~machine::UInt64~machine::Word" ]);
-
-    linker.add_procedure(
-        "isquare",
-        ProcedureCompiler::new(&symbols)
-            .compile(
-                &LTExpr::abstraction(
-                    "x",
-                    "ℤ_2^64~machine::UInt64~machine::Word",
-
-                    LTExpr::application(
-                        LTExpr::symbol("i*"),
-                        vec![
-                           LTExpr::symbol("x"),
-                           LTExpr::symbol("x")
-                        ]
-                    )
-                )
-            )
-            .into_asm()
-            .build()
-    );
-
     symbols.write().unwrap().declare_static_parse(
         "data-frame-ptr",
         "<MutRef <Seq machine::Word>>~machine::Address~machine::Word"