|  |  |  | @ -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
 | 
			
		
	
	
		
			
				
					|  |  |  | 
 |