From 4a705241fe4139d34e2aac852aeeb500fbe6cb64 Mon Sep 17 00:00:00 2001
From: Michael Sippel <micha@fragmental.art>
Date: Sat, 10 May 2025 16:27:56 +0200
Subject: [PATCH] manage include blocks & only output required blocks once

---
 src/c_gen/gen_lib.rs            |  6 ++--
 src/c_gen/morph/target_morph.rs | 54 +++++++++++++++++++++++----------
 src/main.rs                     | 27 ++++++++++-------
 3 files changed, 58 insertions(+), 29 deletions(-)

diff --git a/src/c_gen/gen_lib.rs b/src/c_gen/gen_lib.rs
index f8858bb..95359cc 100644
--- a/src/c_gen/gen_lib.rs
+++ b/src/c_gen/gen_lib.rs
@@ -1,12 +1,14 @@
 use {
-    super::types::get_c_repr_arg_type, crate::{c_gen::LdmcCTargetMorph, LdmcPrimMorph}, laddertypes::{morphism::MorphismInstance, parser::*, TypeDict}, std::collections::HashMap
+    super::types::get_c_repr_arg_type, crate::{c_gen::LdmcCTargetMorph, LdmcPrimMorph}, laddertypes::{morphism::MorphismInstance, parser::*, MorphismType, TypeDict}, std::collections::HashMap
 };
 
 pub fn generate_lib(
     dict: &mut impl TypeDict,
+    include_blocks: Vec< String >,
+    include_dependencies: HashMap< MorphismType, usize >,
     morphisms: Vec< (String, MorphismInstance<LdmcPrimMorph>) >
 ) -> Result<String, ()> {
-    let mut target = LdmcCTargetMorph::new();
+    let mut target = LdmcCTargetMorph::new( include_blocks, include_dependencies );
     let mut wrappers = String::new();
 
     for (name, morph) in morphisms {
diff --git a/src/c_gen/morph/target_morph.rs b/src/c_gen/morph/target_morph.rs
index fcb90fb..161d6fa 100644
--- a/src/c_gen/morph/target_morph.rs
+++ b/src/c_gen/morph/target_morph.rs
@@ -1,18 +1,20 @@
 use {
     crate::{
         c_gen::types::{
-            encode_morph_type_to_symbol, get_c_repr_definition, get_c_repr_type, encode_type_to_value
+            encode_morph_type_to_symbol, encode_type_to_value, get_c_repr_definition, get_c_repr_kind, get_c_repr_type
         },
         morphism::LdmcPrimMorph
     },
     laddertypes::{
-        parser::*, MorphismInstance, TypeDict, TypeTerm, Morphism
+        parser::*, Morphism, MorphismInstance, MorphismType, TypeDict, TypeTerm
     },
     std::collections::HashMap
 };
 
 pub struct LdmcCTargetMorph {
-    includes: Vec< String >,
+    include_blocks: Vec< String >,
+    include_dependencies: HashMap< MorphismType, usize >,
+    active_includes: Vec< usize >,
     active_types: Vec< TypeTerm >,
     active_instantiations: Vec< LdmcPrimMorph >,
     active_lenpfx_types: Vec< (TypeTerm, TypeTerm) >,
@@ -21,19 +23,35 @@ pub struct LdmcCTargetMorph {
 }
 
 impl LdmcCTargetMorph {
-    pub fn new() -> Self {
-        LdmcCTargetMorph {
-            includes: vec![
-                "#include <stdint.h>".into(),
-                "#include <array/length-prefix.h>".into(),
-                "#define FUSE(morph, src, dst) { int result = morph(src,dst); if(result) return result; }".into(),
-            ],
+    pub fn add_required_include_block(&mut self, block: String) {
+        let i = self.include_blocks.len();
+        self.active_includes.push(i);
+        self.include_blocks.push(block);
+    }
+
+    pub fn new(
+        include_blocks: Vec< String >,
+        include_dependencies: HashMap< MorphismType, usize >
+    ) -> Self {
+        let mut m = LdmcCTargetMorph {
+            include_blocks,
+            include_dependencies,
+            active_includes: Vec::new(),
             active_instantiations: Vec::new(),
             active_types: Vec::new(),
             active_lenpfx_types: Vec::new(),
             typedefs: Vec::new(),
             macro_calls: Vec::new()
-        }
+        };
+
+        m.add_required_include_block(
+            "/* default ldmc includes */
+#include <stdint.h>
+#define FUSE(morph, src, dst) { int result = morph(src,dst); if(result) return result; }
+
+".into()
+        );
+        m
     }
 
     pub fn add_type(&mut self, dict: &mut impl TypeDict, ty: TypeTerm) {
@@ -106,15 +124,14 @@ impl LdmcCTargetMorph {
 
     pub fn into_c_source(mut self, dict: &mut impl TypeDict) -> String {
         let mut source = String::new();
-        self.includes.dedup();
+        self.active_includes.dedup();
+        self.typedefs.dedup();
         self.macro_calls.dedup();
-        self.active_types.dedup();
 
-        for inc in self.includes {
-            source.push_str(&inc);
+        for i in self.active_includes {
+            source.push_str( &self.include_blocks[i] );
             source.push('\n');
         }
-
         source.push('\n');
 
         for typedef in self.typedefs {
@@ -146,6 +163,11 @@ impl LdmcCTargetMorph {
 
         match &morph_inst {
             MorphismInstance::Primitive { ψ, σ, morph } => {
+                if let Some(i) = self.include_dependencies.get(&morph.get_type()) {
+                    self.active_includes.push(*i);
+                }
+
+
                 let mut c_source = String::new();
                 for (ty_id, kind) in morph.type_args.iter() {
                     if let laddertypes::TypeID::Var(var_id) = ty_id {
diff --git a/src/main.rs b/src/main.rs
index 5951618..8e8f40b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -9,15 +9,9 @@ use {
     crate::{
         morphism::LdmcPrimMorph,
         parser::morphism_base_parser,
-    },
-    laddertypes::{
-        morphism::MorphismType, BimapTypeDict
-    }, parser::morphism_type_parser,
-    ariadne::{Color, Label, Report, ReportKind, Source},
-    clap::Parser,
-    walkdir::WalkDir,
-    tiny_ansi::TinyAnsi,
-    std::{path::PathBuf, sync::{Arc, RwLock}, io::Write},
+    }, ariadne::{Color, Label, Report, ReportKind, Source}, clap::Parser, laddertypes::{
+        morphism::MorphismType, BimapTypeDict, Morphism
+    }, parser::morphism_type_parser, std::{io::Write, path::PathBuf, sync::{Arc, RwLock}}, tiny_ansi::TinyAnsi, walkdir::WalkDir
 };
 
 #[derive(Parser, Debug)]
@@ -66,6 +60,10 @@ fn main() {
     }
 
     // 1.2. read files
+
+    let mut include_blocks = Vec::new();
+    let mut include_dependencies = std::collections::HashMap::new();
+
     for mb_path in mb_paths {
         let src = std::fs::read_to_string(mb_path.clone()).expect("failed to read morphism base");
 
@@ -73,9 +71,16 @@ fn main() {
         let result = morphism_base_parser(type_dict.clone()).parse(src.clone());
         match result {
             Ok((includes, morphisms)) => {
-                println!("{}",includes);
                 eprintln!("[{}] parse ok.", mb_path.to_str().unwrap().bright_yellow());
+
+                let include_idx = include_blocks.len();
+
+                let mut includes_prefixed = format!("/* from `{}` */", mb_path.display());
+                includes_prefixed.push_str(&includes);
+                include_blocks.push(includes_prefixed);
+
                 for m in morphisms {
+                    include_dependencies.insert( m.get_type(), include_idx );
                     morphism_base.add_morphism(m);
                 }
             }
@@ -106,7 +111,7 @@ fn main() {
         }
     }
 
-    let c_source = crate::c_gen::gen_lib::generate_lib(&mut type_dict, instances).expect("failed to generate library");
+    let c_source = crate::c_gen::gen_lib::generate_lib(&mut type_dict, include_blocks, include_dependencies, instances).expect("failed to generate library");
     if let Some(out_path) = args.output {
         let mut file = std::fs::File::create(out_path).expect("failed to open output file");
         file.write_all(c_source.as_bytes()).expect("failed to write output file");