diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs
index 508a75b1bb96d9c091b26b24e6f5f9627c621f5b..febb35e6beb593735b1132422976207e52411e04 100644
--- a/hercules_ir/src/ir.rs
+++ b/hercules_ir/src/ir.rs
@@ -1,25 +1,19 @@
-pub struct FunctionID(u32);
-
-pub struct NodeID(u32);
-const NULL_NODE: NodeID = NodeID(0xFFFFFFFF);
-
-pub struct ConstantID(u32);
-
-pub struct TypeID(u32);
-
+#[derive(Clone)]
 pub struct Module {
-    functions: Vec<Function>,
-    typed: Vec<Type>,
-    constants: Vec<Constant>,
+    pub functions: Vec<Function>,
+    pub types: Vec<Type>,
+    pub constants: Vec<Constant>,
 }
 
+#[derive(Clone)]
 pub struct Function {
-    name: String,
-    nodes: Vec<Node>,
+    pub name: String,
+    pub nodes: Vec<Node>,
 }
 
+#[derive(Clone)]
 pub enum Type {
-    Control,
+    Control(u64),
     Integer8,
     Integer16,
     Integer32,
@@ -28,6 +22,7 @@ pub enum Type {
     Float64,
 }
 
+#[derive(Clone)]
 pub enum Constant {
     Integer8(u8),
     Integer16(u16),
@@ -37,6 +32,7 @@ pub enum Constant {
     Float64(f64),
 }
 
+#[derive(Clone)]
 pub enum Node {
     Start,
     Region {
@@ -46,6 +42,14 @@ pub enum Node {
         control: NodeID,
         cond: NodeID,
     },
+    Fork {
+        control: NodeID,
+        factor: u64,
+    },
+    Join {
+        control: NodeID,
+        factor: u64,
+    },
     Phi {
         control: NodeID,
         data: Box<[NodeID]>,
@@ -54,6 +58,9 @@ pub enum Node {
         control: NodeID,
         value: NodeID,
     },
+    Parameter {
+        index: u64,
+    },
     Constant {
         id: ConstantID,
     },
@@ -82,56 +89,38 @@ pub enum Node {
     },
 }
 
-impl From<u32> for FunctionID {
-    fn from(v: u32) -> Self {
-        FunctionID(v)
-    }
-}
-
-impl From<u64> for FunctionID {
-    fn from(v: u64) -> Self {
-        FunctionID(v as u32)
-    }
-}
+#[derive(Clone)]
+pub struct FunctionID(u32);
 
-impl From<usize> for FunctionID {
-    fn from(v: usize) -> Self {
-        FunctionID(v as u32)
+impl FunctionID {
+    pub fn idx(&self) -> usize {
+        self.0 as usize
     }
 }
 
-impl From<u32> for NodeID {
-    fn from(v: u32) -> Self {
-        NodeID(v)
-    }
-}
+#[derive(Clone)]
+pub struct NodeID(u32);
 
-impl From<u64> for NodeID {
-    fn from(v: u64) -> Self {
-        NodeID(v as u32)
+impl NodeID {
+    pub fn idx(&self) -> usize {
+        self.0 as usize
     }
 }
 
-impl From<usize> for NodeID {
-    fn from(v: usize) -> Self {
-        NodeID(v as u32)
-    }
-}
+#[derive(Clone)]
+pub struct ConstantID(u32);
 
-impl From<u32> for ConstantID {
-    fn from(v: u32) -> Self {
-        ConstantID(v)
+impl ConstantID {
+    pub fn idx(&self) -> usize {
+        self.0 as usize
     }
 }
 
-impl From<u64> for ConstantID {
-    fn from(v: u64) -> Self {
-        ConstantID(v as u32)
-    }
-}
+#[derive(Clone)]
+pub struct TypeID(u32);
 
-impl From<usize> for ConstantID {
-    fn from(v: usize) -> Self {
-        ConstantID(v as u32)
+impl TypeID {
+    pub fn idx(&self) -> usize {
+        self.0 as usize
     }
 }
diff --git a/hercules_ir/src/lib.rs b/hercules_ir/src/lib.rs
index e02d1fce916146c48c276dd1f453d7ccfab99f53..227b47aa5cfdba28f4a64dd82b31e0e7a1c0ac54 100644
--- a/hercules_ir/src/lib.rs
+++ b/hercules_ir/src/lib.rs
@@ -1,3 +1,5 @@
 pub mod ir;
+pub mod parse;
 
 pub use crate::ir::*;
+pub use crate::parse::*;
diff --git a/hercules_ir/src/parse.rs b/hercules_ir/src/parse.rs
new file mode 100644
index 0000000000000000000000000000000000000000..0f27a411b810c7432bb0fd6bfbb3fe70fe77ef45
--- /dev/null
+++ b/hercules_ir/src/parse.rs
@@ -0,0 +1,55 @@
+extern crate nom;
+
+use std::collections::HashMap;
+
+use crate::*;
+
+fn parse(ir_test: &str) -> Module {
+    parse_module(ir_test, Context::default()).unwrap().1
+}
+
+#[derive(Default)]
+struct Context<'a> {
+    function_ids: HashMap<&'a str, FunctionID>,
+    node_ids: HashMap<&'a str, NodeID>,
+    interned_types: HashMap<Type, TypeID>,
+    interned_constants: HashMap<Constant, ConstantID>,
+}
+
+fn parse_module<'a>(ir_text: &'a str, mut context: Context<'a>) -> nom::IResult<&'a str, Module> {
+    let (rest, functions) = nom::multi::many0(|x| parse_function(x, &mut context))(ir_text)?;
+    nom::combinator::eof(rest)?;
+    let mut types = vec![Type::Control(0); context.interned_types.len()];
+    for (ty, id) in context.interned_types {
+        types[id.idx()] = ty;
+    }
+    let mut constants = vec![Constant::Integer8(0); context.interned_constants.len()];
+    for (constant, id) in context.interned_constants {
+        constants[id.idx()] = constant;
+    }
+    Ok((
+        rest,
+        Module {
+            functions,
+            types,
+            constants,
+        },
+    ))
+}
+
+fn parse_function<'a>(
+    ir_text: &'a str,
+    context: &mut Context<'a>,
+) -> nom::IResult<&'a str, Function> {
+    todo!()
+}
+
+mod tests {
+    #[allow(unused_imports)]
+    use super::*;
+
+    #[test]
+    fn parse_ir1() {
+        parse("fn add(x: i32, y: i32) -> i32 return(z) z = add(start, x, y)");
+    }
+}