From 43b12de5080e43811e1c23523acbeb370f6edc53 Mon Sep 17 00:00:00 2001
From: itycodes <dev@itycodes.org>
Date: Fri, 7 Mar 2025 11:36:07 +0100
Subject: [PATCH] Replace the :void type expr with :<>

`void` collides with the simplistic type parser, which expects single
char types. `()` collides with the S-expression parser.

Specifically, it hits the `v` for vector case. This could be fixed by
rewriting the type parser, but I like to keep the whole compiler as
simple as possible for now.
---
 src/compiler/backend/mod.rs   | 35 ++++++++++++++++++++++++++++++++++-
 src/compiler/backend/tests.rs |  2 +-
 src/compiler/meta_compile.rs  |  2 +-
 src/compiler/tests.rs         |  6 +++---
 src/parser/tests.rs           |  4 ++--
 5 files changed, 41 insertions(+), 8 deletions(-)

diff --git a/src/compiler/backend/mod.rs b/src/compiler/backend/mod.rs
index e896a23..a53e767 100644
--- a/src/compiler/backend/mod.rs
+++ b/src/compiler/backend/mod.rs
@@ -14,11 +14,13 @@ pub enum Type {
     Float(u32),
     Int(u32),
     Unsigned(u32),
+    Void,
 }
 
 impl fmt::Display for Type {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
+            Type::Void => write!(f, "<>"),
             Type::Pointer(typ, storage_class) => match storage_class {
                 StorageClass::Input => write!(f, "*{}i", typ),
                 StorageClass::Output => write!(f, "*{}o", typ),
@@ -42,6 +44,10 @@ pub fn parse_type(typ: &String) -> Type {
 
     let c = typ.chars().next().unwrap();
     match c {
+        '<' => {
+            assert_eq!(typ.as_str(), "<>");
+            Type::Void
+        }
         '*' => {
             let mut chars = typ.chars();
             chars.next();
@@ -79,6 +85,9 @@ pub fn parse_type(typ: &String) -> Type {
 
 fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
     match &typ {
+        Type::Void => {
+            ops.push(("%void".to_string(), "OpTypeVoid".to_string()));
+        }
         Type::Unsigned(size) => {
             ops.push((
                 format!("%u{}", size).to_string(),
@@ -129,7 +138,13 @@ fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
 }
 
 fn fix_name(name: &String) -> String {
-    format!("%{}", name.clone().replace("-", "_").replace("*", "p"))
+    format!(
+        "%{}",
+        name.clone()
+            .replace("-", "_")
+            .replace("*", "p")
+            .replace("<>", "void")
+    )
 }
 
 fn has_id(name: String, ops: &Vec<(Option<String>, Vec<String>)>) -> bool {
@@ -248,6 +263,24 @@ pub fn spirv_meta(module: Module) -> String {
         }
     }
 
+    for fun in module.functions {
+        let name = fix_name(&fun.name);
+        let return_type = fix_name(&fun.return_type);
+        let mut type_ops = Vec::new();
+        emit_type(parse_type(&fun.return_type), &mut type_ops);
+        for op in type_ops {
+            if has_id(op.0.clone(), &ops) {
+                continue;
+            }
+            ops.push((Some(op.0), vec![op.1]));
+        }
+        // Push OpFunctionType
+        ops.push((
+            Some(name.clone()),
+            vec!["OpTypeFunction".to_string(), return_type.clone()],
+        ));
+    }
+
     for op in ops {
         if op.0.is_some() {
             write!(spirv_asm, "{} = ", op.0.unwrap()).unwrap();
diff --git a/src/compiler/backend/tests.rs b/src/compiler/backend/tests.rs
index 4a90b07..2f0cce5 100644
--- a/src/compiler/backend/tests.rs
+++ b/src/compiler/backend/tests.rs
@@ -11,7 +11,7 @@ fn test_emit() {
 (dec frag-coord:*v4f32i Input)
 (dec out-color:*v4f32o Output)
 (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
-(fun (main) :void
+(fun (main) :<>
   (store-ptr (out-color)
     (v4f32i (/ (.xy (load-ptr frag-coord))
                (v2f32 1920.0 1080.0)) 
diff --git a/src/compiler/meta_compile.rs b/src/compiler/meta_compile.rs
index 7e8f937..d305239 100644
--- a/src/compiler/meta_compile.rs
+++ b/src/compiler/meta_compile.rs
@@ -181,7 +181,7 @@ pub fn compile_fun<I: Iterator<Item = Ast>>(
     let mut name_it = name.into_iter();
     let name = expect_symbol(name_it.next(), &name_loc)?;
     expect_empty(name_it, name_loc)?;
-    let _return_type = expect_one_of(&[":void"], expect_symbol(list.next(), &loc)?)?;
+    let _return_type = expect_one_of(&[":<>"], expect_symbol(list.next(), &loc)?)?;
     let return_type = _return_type.into_inner().replace(":", "");
     let body = list.collect::<Vec<_>>();
     let location = if let (Some(s), Some(e)) = (
diff --git a/src/compiler/tests.rs b/src/compiler/tests.rs
index cb47ba9..8064ea8 100644
--- a/src/compiler/tests.rs
+++ b/src/compiler/tests.rs
@@ -14,7 +14,7 @@ fn test_compile() {
 (dec frag-coord:*v4f32i Input)
 (dec out-color:*v4f32o Output)
 (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
-(fun (main) :void
+(fun (main) :<>
   (store-ptr (out-color)
     (v4f32i (/ (.xy (load-ptr frag-coord))
                (v2f32 1920.0 1080.0)) 
@@ -49,7 +49,7 @@ fn test_compile() {
         ],
         functions: vec![Function {
             name: "main".to_string(),
-            return_type: "void".to_string(),
+            return_type: "<>".to_string(),
             arguments: vec![],
             body: Some(vec![]),
             ast: Some(Ast::List(Localised::dummy_location(vec![Ast::List(
@@ -107,7 +107,7 @@ fn expected_symbol() {
 (dec frag-coord:*v4f32i Input)
 (dec out-color:*v4f32o Output)
 (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
-(fun (main) :void
+(fun (main) :<>
   (store-ptr (out-color)
     (v4f32i (/ (.xy (load-ptr frag-coord))
                (v2f32 1920.0 1080.0)) 
diff --git a/src/parser/tests.rs b/src/parser/tests.rs
index 2dff458..8e94147 100644
--- a/src/parser/tests.rs
+++ b/src/parser/tests.rs
@@ -43,7 +43,7 @@ fn test_parse() {
 (dec frag-coord:*v4f32i Input)
 (dec out-color:*v4f32o Output)
 (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
-(fun (main) :void
+(fun (main) :<>
   (store-ptr (out-color)
     (v4f32i (/ (.xy (load-ptr frag-coord))
                (v2f32 1920.0 1080.0)) 
@@ -108,7 +108,7 @@ fn test_parse() {
             Ast::List(Localised::dummy_location(vec![Ast::Symbol(
                 Localised::dummy_location("main".to_string()),
             )])),
-            Ast::Symbol(Localised::dummy_location(":void".to_string())),
+            Ast::Symbol(Localised::dummy_location(":<>".to_string())),
             Ast::List(Localised::dummy_location(vec![
                 Ast::Symbol(Localised::dummy_location("store-ptr".to_string())),
                 Ast::List(Localised::dummy_location(vec![Ast::Symbol(