diff --git a/src/compiler/mod.rs b/src/compiler/mod.rs
new file mode 100644
index 0000000..2bf5e06
--- /dev/null
+++ b/src/compiler/mod.rs
@@ -0,0 +1,297 @@
+use crate::parser::Ast;
+
+#[cfg(test)]
+mod tests;
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum Capability {
+    #[default]
+    Shader
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum ExecutionMode {
+    #[default]
+    OriginUpperLeft
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum ExecutionModel {
+    #[default]
+    Fragment
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct EntryPoint {
+    pub execution_model: ExecutionModel,
+    pub execution_mode: ExecutionMode,
+    pub name: String,
+    pub interface: Vec<String>,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum AddressingModel {
+    #[default]
+    Logical,
+    Physical32,
+    Physical64,
+    PhysicalStorageBuffer64
+}
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum MemoryModel {
+    #[default]
+    GLSL450,
+    OpenCL,
+    VulkanKHR,
+    Simple
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct Memory {
+    pub addressing_model: AddressingModel,
+    pub memory_model: MemoryModel,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum BuiltinDecoration {
+    #[default]
+    FragCoord,
+}
+
+#[derive(Debug, PartialEq, Clone)]
+pub enum Decoration {
+    Builtin(BuiltinDecoration),
+    Location(u32),
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub enum StorageClass {
+    #[default]
+    Undefined,
+    Input,
+    Output,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct GlobalVariable {
+    pub name: String,
+    pub typ: String,
+    pub storage_class: StorageClass,
+    pub decorations: Vec<Decoration>,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct Instruction {
+    pub result_id: Option<String>,
+    pub op: String,
+    pub operands: Vec<String>,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct Function {
+    pub name: String,
+    pub return_type: String,
+    pub arguments: Vec<String>,
+    pub body: Option<Vec<Instruction>>,
+    pub ast: Option<Ast>,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct Import {
+    pub name: String,
+    pub value: String,
+}
+
+#[derive(Debug, PartialEq, Default, Clone)]
+pub struct Module {
+    pub capabilities: Vec<Capability>,
+    pub entry_points: Vec<EntryPoint>,
+    pub globals: Vec<GlobalVariable>,
+    pub functions: Vec<Function>,
+    pub memory_model: Memory,
+    pub imports: Vec<Import>,
+}
+
+pub fn meta_compile(ast: &mut Ast) -> Module {
+    let mut module: Module = Module::default();
+    match ast {
+        Ast::Root(root) => {
+            for node in root {
+                match node {
+                    Ast::List(list) => {
+                        let keyword = list[0].clone();
+                        match keyword {
+                            Ast::Symbol(sym) => {
+                                match sym.as_str() {
+                                    "module" => {
+                                        let cap = list[1].clone();
+                                        let exec = list[2].clone();
+                                        let memory = list[3].clone();
+                                        module.memory_model = Memory {
+                                            addressing_model: AddressingModel::Logical,
+                                            memory_model: MemoryModel::GLSL450,
+                                        };
+                                        module.capabilities.push(Capability::Shader);
+                                        assert_eq!(exec, Ast::Symbol("Logical".to_string()));
+                                        assert_eq!(memory, Ast::Symbol("GLSL450".to_string()));
+                                        assert_eq!(cap, Ast::Symbol("Shader".to_string()));
+                                    }
+                                    "import" => {
+                                        let name = match &list[1] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[1]),
+                                        };
+                                        let value = match &list[2] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[2]),
+                                        };
+                                        module.imports.push(Import {
+                                            name: name.to_string(),
+                                            value: value.to_string(),
+                                        });
+                                    }
+                                    "bind" => {
+                                        let name_and_type = match &list[1] {
+                                            Ast::List(l) => l,
+                                            _ => panic!("Expected list! {:?}", list[1]),
+                                        };
+                                        let name_and_type: String = name_and_type.iter().map(|x| {
+                                            match x {
+                                                Ast::Symbol(s) => s.to_string(),
+                                                _ => panic!("Expected symbol! {:?}", x),
+                                            }
+                                        }).collect();
+                                        // name_and_type is of the name:type format, like foo:f32
+                                        let name: String = name_and_type.split(":").collect::<Vec<&str>>()[0].to_string();
+                                        let typ: String = name_and_type.split(":").collect::<Vec<&str>>()[1].to_string();
+                                        let bind = match &list[2] {
+                                            Ast::List(l) => l,
+                                            _ => panic!("Expected list! {:?}", list[2]),
+                                        };
+                                        let bind: Vec<String> = bind.iter().map(|x| {
+                                            match x {
+                                                Ast::Symbol(s) => s.to_string(),
+                                                _ => panic!("Expected symbol! {:?}", x),
+                                            }
+                                        }).collect();
+                                        let bind_name = match bind[0].as_str() {
+                                            "Builtin" => Decoration::Builtin(BuiltinDecoration::FragCoord),
+                                            "Location" => Decoration::Location(bind[1].parse::<u32>().unwrap()),
+                                            _ => panic!("Unknown bind! {:?}", bind),
+                                        };
+                                        let mut exists = false;
+                                        for var in &module.globals {
+                                            if var.name == name {
+                                                exists = true;
+                                            }
+                                        }
+                                        if !exists {
+                                            module.globals.push(GlobalVariable {
+                                                name: name,
+                                                typ: typ,
+                                                storage_class: StorageClass::Undefined,
+                                                decorations: vec![bind_name],
+                                            });
+                                        }
+                                    }
+                                    "dec" => {
+                                        let name_and_type = match &list[1] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[1]),
+                                        };
+                                        let name: String = name_and_type.split(":").collect::<Vec<&str>>()[0].to_string();
+                                        let typ: String = name_and_type.split(":").collect::<Vec<&str>>()[1].to_string();
+                                        let storage_class = match &list[2] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[2]),
+                                        };
+                                        let mut exists = false;
+                                        for var in &module.globals {
+                                            if var.name.as_str() == name.as_str() {
+                                                exists = true;
+                                            }
+                                        }
+                                        let storage_class = match storage_class.as_str() {
+                                            "Input" => StorageClass::Input,
+                                            "Output" => StorageClass::Output,
+                                            _ => StorageClass::Undefined,
+                                        };
+                                        if !exists {
+                                            module.globals.push(GlobalVariable {
+                                                name: name.to_string(),
+                                                typ: typ.to_string(),
+                                                storage_class: storage_class.clone(),
+                                                decorations: vec![],
+                                            });
+                                        }
+                                        if exists {
+                                            module.globals.iter_mut()
+                                                .find(|x| x.name.as_str() == name.as_str())
+                                                .unwrap().storage_class = storage_class.clone();
+                                        }
+                                    }
+                                    "entry" => {
+                                        let name = match &list[1] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[1]),
+                                        };
+                                        let exec_model = match &list[2] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[2]),
+                                        };
+                                        let exec_mode = match &list[3] {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", list[3]),
+                                        };
+                                        let interface = match &list[4] {
+                                            Ast::List(l) => l,
+                                            _ => panic!("Expected list! {:?}", list[4]),
+                                        };
+                                        let interface: Vec<String> = interface.iter().map(|x| {
+                                            match x {
+                                                Ast::Symbol(s) => s.to_string(),
+                                                _ => panic!("Expected symbol! {:?}", x),
+                                            }
+                                        }).collect();
+                                        module.entry_points.push(EntryPoint {
+                                            execution_model: ExecutionModel::Fragment,
+                                            execution_mode: ExecutionMode::OriginUpperLeft,
+                                            name: name.to_string(),
+                                            interface: interface,
+                                        });
+                                        assert_eq!(exec_model, "Fragment");
+                                        assert_eq!(exec_mode, "OriginUpperLeft");
+                                    }
+                                    "fun" => {
+                                        let name = match &list[1] {
+                                            Ast::List(l) => l[0].clone(),
+                                            _ => panic!("Expected list! {:?}", list[1]),
+                                        };
+                                        let name = match name {
+                                            Ast::Symbol(s) => s,
+                                            _ => panic!("Expected symbol! {:?}", name),
+                                        };
+                                        let body = list[2..].to_vec();
+                                        let fun = Function {
+                                            name: name.to_string(),
+                                            return_type: "void".to_string(),
+                                            arguments: vec![],
+                                            body: Some(vec![]),
+                                            ast: Some(Ast::List(body)),
+                                        };
+                                        module.functions.push(fun);
+                                    }
+                                    _ => panic!("Unknown keyword! {:?}", sym),
+                                }
+                            }
+                            _ => panic!("List where a keyword was expected! {:?}", keyword),
+                        }
+                    }
+                    _ => panic!("Top-level symbol! {:?}", node),
+                }
+            }
+        }
+        _ => panic!("Non-root ast")
+    }
+    module
+}
\ No newline at end of file
diff --git a/src/compiler/tests.rs b/src/compiler/tests.rs
new file mode 100644
index 0000000..c8012a1
--- /dev/null
+++ b/src/compiler/tests.rs
@@ -0,0 +1,25 @@
+use crate::parser::{tokenize, parse};
+use crate::compiler::meta_compile;
+
+#[test]
+fn test_compile() {
+    let src = "
+(module Shader Logical GLSL450)
+(import :std GLSL.std.450)
+(bind (frag-coord:*v4f32i) (Builtin FragCoord))
+(bind (out-color:*v4f32o) (Location 0))
+(dec frag-coord:*v4f32i Input)
+(dec out-color:*v4f32o Output)
+(entry main Fragment OriginUpperLeft (:frag-coord :out-color))
+(fun (main)
+  (store-ptr (out-color)
+    (v4f32i (/ (.xy (load-ptr frag-coord))
+               (v2f32 1920.0 1080.0)) 
+            1.0 
+            1.0)))
+";
+    let mut ast = parse(tokenize(src));
+    println!("{:?}", ast);
+    let module = meta_compile(&mut ast);
+    println!("{:?}", module);
+}
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 49c0ece..ebebce3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,6 @@
 use std::fmt::Write;
 pub mod parser;
+pub mod compiler;
 
 fn main() {
     let mut ops: Vec<(Option<String>, Vec<String>)> = Vec::new();
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index c90444f..c56d16f 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -11,7 +11,7 @@ pub enum Token {
     Symbol(String),
 }
 
-#[derive(Debug, PartialEq)]
+#[derive(Debug, PartialEq, Clone)]
 pub enum Ast {
     Symbol(String),
     List(Vec<Ast>),
diff --git a/src/parser/tests.rs b/src/parser/tests.rs
index be5484b..6251515 100644
--- a/src/parser/tests.rs
+++ b/src/parser/tests.rs
@@ -22,15 +22,15 @@ fn test_parse() {
     let src = "
 (module Shader Logical GLSL450)
 (import :std GLSL.std.450)
-(bind (frag-coord:*v4fi) (Builtin FragCoord))
-(bind (out-color:*v4fo) (Location 0))
-(dec frag-coord:*v4fi Input)
-(dec out-color:*v4fo Output)
+(bind (frag-coord:*v4f32i) (Builtin FragCoord))
+(bind (out-color:*v4f32o) (Location 0))
+(dec frag-coord:*v4f32i Input)
+(dec out-color:*v4f32o Output)
 (entry main Fragment OriginUpperLeft (:frag-coord :out-color))
 (fun (main)
   (store-ptr (out-color)
-    (v4fi (/ (.xy (load-ptr frag-coord))
-               (v2f 1920.0 1080.0)) 
+    (v4f32i (/ (.xy (load-ptr frag-coord))
+               (v2f32 1920.0 1080.0)) 
             1.0 
             1.0)))
 ";
@@ -51,7 +51,7 @@ fn test_parse() {
         Ast::List(vec![
             Ast::Symbol("bind".to_string()),
             Ast::List(vec![
-                Ast::Symbol("frag-coord:*v4fi".to_string()),
+                Ast::Symbol("frag-coord:*v4f32i".to_string()),
             ]),
             Ast::List(vec![
                 Ast::Symbol("Builtin".to_string()),
@@ -61,7 +61,7 @@ fn test_parse() {
         Ast::List(vec![
             Ast::Symbol("bind".to_string()),
             Ast::List(vec![
-                Ast::Symbol("out-color:*v4fo".to_string()),
+                Ast::Symbol("out-color:*v4f32o".to_string()),
             ]),
             Ast::List(vec![
                 Ast::Symbol("Location".to_string()),
@@ -70,12 +70,12 @@ fn test_parse() {
         ]),
         Ast::List(vec![
             Ast::Symbol("dec".to_string()),
-            Ast::Symbol("frag-coord:*v4fi".to_string()),
+            Ast::Symbol("frag-coord:*v4f32i".to_string()),
             Ast::Symbol("Input".to_string()),
         ]),
         Ast::List(vec![
             Ast::Symbol("dec".to_string()),
-            Ast::Symbol("out-color:*v4fo".to_string()),
+            Ast::Symbol("out-color:*v4f32o".to_string()),
             Ast::Symbol("Output".to_string()),
         ]),
         Ast::List(vec![
@@ -99,7 +99,7 @@ fn test_parse() {
                     Ast::Symbol("out-color".to_string()),
                 ]),
                 Ast::List(vec![
-                    Ast::Symbol("v4fi".to_string()),
+                    Ast::Symbol("v4f32i".to_string()),
                     Ast::List(vec![
                         Ast::Symbol("/".to_string()),
                         Ast::List(vec![
@@ -110,7 +110,7 @@ fn test_parse() {
                             ]),
                         ]),
                         Ast::List(vec![
-                            Ast::Symbol("v2f".to_string()),
+                            Ast::Symbol("v2f32".to_string()),
                             Ast::Symbol("1920.0".to_string()),
                             Ast::Symbol("1080.0".to_string()),
                         ]),