From 6343fdf1fc4b0ca895b48c90ca1dea15c7d7452f Mon Sep 17 00:00:00 2001
From: itycodes <tranquillitycodes@proton.me>
Date: Thu, 6 Mar 2025 11:25:52 +0100
Subject: [PATCH] Broken; Rust's Display trait is weird. Help.

---
 src/compiler/backend/mod.rs   | 118 ++++++++++++++++++++++++++++++++--
 src/compiler/backend/tests.rs |  14 ++++
 src/compiler/mod.rs           |  12 ++++
 src/compiler/tests.rs         |   2 +-
 4 files changed, 141 insertions(+), 5 deletions(-)

diff --git a/src/compiler/backend/mod.rs b/src/compiler/backend/mod.rs
index 77e4b81..74193c5 100644
--- a/src/compiler/backend/mod.rs
+++ b/src/compiler/backend/mod.rs
@@ -2,9 +2,114 @@
 mod tests;
 
 use crate::compiler::Module;
-use std::{fmt::Write, ops::Add};
+use std::fmt::Write;
+use std::fmt;
 
-pub fn fix_name(name: &String) -> String {
+use super::StorageClass;
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum Type {
+    Pointer(Box<Type>, StorageClass),
+    Vector(Box<Type>, u32),
+    Float(u32),
+    Int(u32),
+    Unsigned(u32),
+}
+
+impl fmt::Display for Type {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            Type::Pointer(typ, storage_class) => {
+                match storage_class {
+                    StorageClass::Input => write!(f, "*{}i", typ),
+                    StorageClass::Output => write!(f, "*{}o", typ),
+                    StorageClass::Undefined => panic!("Bound a non-declared variable"),
+                }
+            },
+            Type::Vector(typ, size) => write!(f, "v{}{}", size, typ),
+            Type::Float(size) => write!(f, "f{}", size),
+            Type::Int(size) => write!(f, "s{}", size),
+            Type::Unsigned(size) => write!(f, "u{}", size),
+        }
+    }
+}
+
+pub fn parse_type(typ: String) -> Type {
+    // pointers have the format *<t>i or *<t>o, for the storage class
+    // floats have the format f<size>, so f32, f64...
+    // ints have the format s<size>, so s32, s64...
+    // unsigned ints have the format u<size>, so u32, u64...
+    // So, *v4f32i is a pointer to a vector of 4 floats, with the storage class Input.
+    // *v4f32o is a pointer to a vector of 4 floats, with the storage class Output.
+
+    let c = typ.chars().next().unwrap();
+    match c {
+        '*' => {
+            let mut chars = typ.chars();
+            chars.next();
+            let typ = chars.collect::<String>();
+            let storage_class = match typ.chars().last().unwrap() {
+                'i' => StorageClass::Input,
+                'o' => StorageClass::Output,
+                _ => panic!("Invalid storage class"),
+            };
+            let typ = typ.chars().take(typ.len() - 1).collect::<String>();
+            Type::Pointer(Box::new(parse_type(typ)), storage_class)
+        },
+        'v' => {
+            let mut chars = typ.chars();
+            chars.next();
+            let size = chars.next().unwrap().to_digit(10).unwrap();
+            let typ = chars.collect::<String>();
+            Type::Vector(Box::new(parse_type(typ)), size)
+        },
+        'f' => {
+            let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
+            Type::Float(size)
+        },
+        's' => {
+            let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
+            Type::Int(size)
+        },
+        'u' => {
+            let size = typ.chars().skip(1).collect::<String>().parse().unwrap();
+            Type::Unsigned(size)
+        },
+        _ => panic!("Invalid type"),
+    }
+
+}
+
+fn emit_type(typ: Type, ops: &mut Vec<(String, String)>) {
+    match typ {
+        Type::Unsigned(size) => {
+            ops.push((format!("%u{}", size).to_string(), format!("OpTypeInt {}", size)));
+        },
+        Type::Int(size) => {
+            ops.push((format!("%s{}", size).to_string(), format!("OpTypeInt {}", size)));
+        },
+        Type::Float(size) => {
+            ops.push((format!("%f{}", size).to_string(), format!("OpTypeFloat {}", size)));
+        },
+        Type::Vector(typ, size) => {
+            emit_type(*typ.clone(), ops);
+            let typ_id = format!("%{}", *typ.clone());
+            ops.push((format!("%v{}{}", typ_id, size).to_string(), format!("OpTypeVector {} {}", typ_id, size)))
+        },
+        Type::Pointer(typ, storage_class) => {
+            emit_type(*typ.clone(), ops);
+            let typ_id = format!("%{}", *typ.clone());
+            let storage_class = match storage_class {
+                StorageClass::Input => "Input",
+                StorageClass::Output => "Output",
+                StorageClass::Undefined => panic!("Bound a non-declared variable"),
+            };
+            ops.push((format!("%{}{}", typ_id, storage_class).to_string(), format!("OpTypePointer {} {}", storage_class, typ_id)))
+        },
+    }
+}
+
+fn fix_name(name: &String) -> String {
     format!("%{}", name.clone().replace("-", "_"))
 }
 
@@ -51,13 +156,18 @@ pub fn spirv_meta(module: Module) -> String {
 
     for global in module.globals {
         let name = fix_name(&global.name);
-        let typ = global.typ;
+        let _typ = global.typ;
         let storage_class = match global.storage_class {
             crate::compiler::StorageClass::Input => "Input",
             crate::compiler::StorageClass::Output => "Output",
             crate::compiler::StorageClass::Undefined => panic!("Bound a non-declared variable"),
         };
-        let typ_id = "%undefined_type";
+        let typ_id = format!("%{}", _typ);
+        let mut type_ops = Vec::new();
+        emit_type(parse_type(_typ), &mut type_ops);
+        for op in type_ops {
+            ops.push((Some(op.0), vec![op.1]));
+        }
         ops.push((Some(name.clone()), vec!["OpVariable".to_string(), typ_id.to_string(), storage_class.to_string()]));
         for dec in global.decorations {
             // Decorations have the format Location 0, or Builtin FragCoord
diff --git a/src/compiler/backend/tests.rs b/src/compiler/backend/tests.rs
index 87c258d..e84c06b 100644
--- a/src/compiler/backend/tests.rs
+++ b/src/compiler/backend/tests.rs
@@ -22,4 +22,18 @@ fn test_emit() {
     let module = meta_compile(&mut ast);
     let res = spirv_meta(module);
     println!("{}", res);
+}
+
+#[test]
+fn test_type_parse() {
+    use crate::compiler::backend::*;
+    use Type::*;
+    assert_eq!(parse_type("*v4f32i".to_string()),
+        Pointer(Box::new(Vector(Box::new(Float(32)), 4)), StorageClass::Input));
+    assert_eq!(parse_type("*v4f32o".to_string()),
+        Pointer(Box::new(Vector(Box::new(Float(32)), 4)), StorageClass::Output));
+    assert_eq!(parse_type("v2f32".to_string()),
+        Vector(Box::new(Float(32)), 2));
+    assert_eq!(parse_type("f32".to_string()), Float(32));
+    assert_eq!(parse_type("s32".to_string()), Int(32));
 }
\ No newline at end of file
diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs
index 9a83957..140a57a 100644
--- a/src/compiler/mod.rs
+++ b/src/compiler/mod.rs
@@ -2,6 +2,8 @@ use crate::parser::Ast;
 
 pub mod backend;
 
+use std::fmt;
+
 #[cfg(test)]
 mod tests;
 
@@ -75,6 +77,16 @@ pub enum StorageClass {
     Output,
 }
 
+impl fmt::Display for StorageClass {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match self {
+            StorageClass::Undefined => write!(f, "Undefined"),
+            StorageClass::Input => write!(f, "Input"),
+            StorageClass::Output => write!(f, "Output"),
+        }
+    }
+}
+
 #[derive(Debug, PartialEq, Default, Clone)]
 pub struct GlobalVariable {
     pub name: String,
diff --git a/src/compiler/tests.rs b/src/compiler/tests.rs
index 08b18e9..33398bd 100644
--- a/src/compiler/tests.rs
+++ b/src/compiler/tests.rs
@@ -28,7 +28,7 @@ fn test_compile() {
             execution_model: ExecutionModel::Fragment,
             execution_mode: ExecutionMode::OriginUpperLeft,
             name: "main".to_string(),
-            interface: vec![":frag-coord".to_string(), ":out-color".to_string()],
+            interface: vec!["frag-coord".to_string(), "out-color".to_string()],
         }],
         globals: vec![
             GlobalVariable {