Repository: huff-language/huff-rs
Pull request #169 (2022-07-18 18:27:29)

fix(huff_lexer): opcode lexing bug
I ran into an interesting edge case today when naming a jump label `return_uint`. Because of the way opcodes are parsed, attempting to push this label to the stack mistakenly gets parsed as a `return` opcode. This small change handles this case by including underscores when peeking for an opcode.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 41c65e3..8841e70 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -718,7 +718,6 @@ dependencies = [
  "huff_lexer",
  "huff_utils",
  "proptest",
- "regex",
  "tiny-keccak",
  "tracing",
 ]
@@ -1280,9 +1279,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.6.0"
+version = "1.5.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
+checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1300,9 +1299,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.27"
+version = "0.6.26"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
+checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
 
 [[package]]
 name = "remove_dir_all"
diff --git a/huff_codegen/README.md b/huff_codegen/README.md
index a46ec3c..cc9ad30 100644
--- a/huff_codegen/README.md
+++ b/huff_codegen/README.md
@@ -81,7 +81,6 @@ let contract = Contract {
       takes: 0,
       returns: 0,
       span: AstSpan(vec![]),
-      outlined: false,
     }
   ],
   invocations: vec![],
@@ -133,7 +132,6 @@ let contract = Contract {
       takes: 0,
       returns: 0,
       span: AstSpan(vec![]),
-      outlined: false,
     }
   ],
   invocations: vec![],
diff --git a/huff_codegen/src/irgen/statements.rs b/huff_codegen/src/irgen/statements.rs
index 6e85671..21a881b 100644
--- a/huff_codegen/src/irgen/statements.rs
+++ b/huff_codegen/src/irgen/statements.rs
@@ -15,7 +15,6 @@ pub fn statement_gen(
     jump_table: &mut JumpTable,
     label_indices: &mut LabelIndices,
     table_instances: &mut Jumps,
-    utilized_tables: &mut Vec<TableDefinition>,
     starting_offset: usize,
 ) -> Result<Vec<(usize, Bytes)>, CodegenError> {
     let mut bytes = vec![];
@@ -42,57 +41,12 @@ pub fn statement_gen(
 
             tracing::info!(target: "codegen", "FOUND INNER MACRO: {}", ir_macro.name);
 
-            // If invoked macro is a function (outlined), insert a jump to the function's code and a
-            // jumpdest to return to. If it is inlined, insert the macro's code at the
-            // current offset.
-            if ir_macro.outlined {
-                // Get necessary swap ops to reorder stack
-                // PC of the return jumpdest should be below the function's stack inputs
-                let stack_swaps = (0..ir_macro.takes)
-                    .rev()
-                    .map(|i| format!("{:02x}", 0x90 + i))
-                    .collect::<Vec<_>>();
+            // Recurse into macro invocation
+            scope.push(ir_macro.clone());
+            mis.push((*offset, mi.clone()));
 
-                // Insert a jump to the outlined macro's code
-                jump_table.insert(
-                    *offset + stack_swaps.len() + 3, // PUSH2 + 2 bytes + stack_swaps.len()
-                    vec![Jump {
-                        label: format!("goto_{}", &ir_macro.name),
-                        bytecode_index: 0,
-                        span: s.span.clone(),
-                    }],
-                );
-
-                // Store return JUMPDEST PC on the stack and re-order the stack so that
-                // the return JUMPDEST PC is below the function's stack inputs
-                bytes.push((
-                    *offset,
-                    Bytes(format!(
-                        "{}{:04x}{}",
-                        Opcode::Push2,
-                        *offset + stack_swaps.len() + 7,
-                        stack_swaps.join("")
-                    )),
-                ));
-                // Insert jump to outlined macro + jumpdest to return to
-                bytes.push((
-                    *offset + stack_swaps.len() + 3, // PUSH2 + 2 bytes + stack_swaps.len()
-                    Bytes(format!("{}xxxx{}{}", Opcode::Push2, Opcode::Jump, Opcode::Jumpdest)),
-                ));
-                // PUSH2 + 2 bytes + stack_swaps.len() + PUSH2 + 2 bytes + JUMP + JUMPDEST
-                *offset += stack_swaps.len() + 8;
-            } else {
-                // Recurse into macro invocation
-                scope.push(ir_macro.clone());
-                mis.push((*offset, mi.clone()));
-
-                let mut res: BytecodeRes = match Codegen::macro_to_bytecode(
-                    ir_macro.clone(),
-                    contract,
-                    scope,
-                    *offset,
-                    mis,
-                ) {
+            let mut res: BytecodeRes =
+                match Codegen::macro_to_bytecode(ir_macro.clone(), contract, scope, *offset, mis) {
                     Ok(r) => r,
                     Err(e) => {
                         tracing::error!(
@@ -104,28 +58,26 @@ pub fn statement_gen(
                     }
                 };
 
-                // Set jump table values
-                tracing::debug!(target: "codegen", "Unmatched jumps: {:?}", res.unmatched_jumps.iter().map(|uj| uj.label.clone()).collect::<Vec<String>>());
-                for j in res.unmatched_jumps.iter_mut() {
-                    let new_index = j.bytecode_index;
-                    j.bytecode_index = 0;
-                    let mut new_jumps = if let Some(jumps) = jump_table.get(&new_index) {
-                        jumps.clone()
-                    } else {
-                        vec![]
-                    };
-                    new_jumps.push(j.clone());
-                    jump_table.insert(new_index, new_jumps);
-                }
-                table_instances.extend(res.table_instances);
-                label_indices.extend(res.label_indices);
-                utilized_tables.extend(res.utilized_tables);
-
-                // Increase offset by byte length of recursed macro
-                *offset += res.bytes.iter().map(|(_, b)| b.0.len()).sum::<usize>() / 2;
-                // Add the macro's bytecode to the final result
-                bytes = [bytes, res.bytes].concat()
+            // Set jump table values
+            tracing::debug!(target: "codegen", "Unmatched jumps: {:?}", res.unmatched_jumps.iter().map(|uj| uj.label.clone()).collect::<Vec<String>>());
+            for j in res.unmatched_jumps.iter_mut() {
+                let new_index = j.bytecode_index;
+                j.bytecode_index = 0;
+                let mut new_jumps = if let Some(jumps) = jump_table.get(&new_index) {
+                    jumps.clone()
+                } else {
+                    vec![]
+                };
+                new_jumps.push(j.clone());
+                jump_table.insert(new_index, new_jumps);
             }
+            table_instances.extend(res.table_instances);
+            label_indices.extend(res.label_indices);
+
+            // Increase offset by byte length of recursed macro
+            *offset += res.bytes.iter().map(|(_, b)| b.0.len()).sum::<usize>() / 2;
+            // Add the macro's bytecode to the final result
+            bytes = [bytes, res.bytes].concat()
         }
         StatementType::Label(label) => {
             // Add JUMPDEST opcode to final result and add to label_indices
@@ -136,7 +88,8 @@ pub fn statement_gen(
         }
         StatementType::LabelCall(label) => {
             // Generate code for a `LabelCall`
-            // PUSH2 + 2 byte destination (placeholder for now, filled in `Codegen::fill_unmatched`
+            // PUSH2 + 2 byte destination (placeholder for now, filled at the bottom
+            // of this function)
             tracing::info!(target: "codegen", "RECURSE BYTECODE GOT LABEL CALL: {}", label);
             jump_table.insert(
                 *offset,
@@ -209,7 +162,7 @@ pub fn statement_gen(
                             bf.args[0].name.as_ref().unwrap()
                         );
                         return Err(CodegenError {
-                            kind: CodegenErrorKind::InvalidMacroInvocation(
+                            kind: CodegenErrorKind::MissingMacroDefinition(
                                 bf.args[0].name.as_ref().unwrap().to_string(), /* yuck */
                             ),
                             span: bf.span.clone(),
@@ -220,42 +173,18 @@ pub fn statement_gen(
                     let size = bytes32_to_string(&ir_table.size, false);
                     let push_bytes = format!("{:02x}{}", 95 + size.len() / 2, size);
 
-                    if !utilized_tables.contains(&ir_table) {
-                        utilized_tables.push(ir_table);
-                    }
-
                     *offset += push_bytes.len() / 2;
                     bytes.push((starting_offset, Bytes(push_bytes)));
                 }
                 BuiltinFunctionKind::Tablestart => {
-                    // Make sure the table exists
-                    if let Some(t) = contract.find_table_by_name(bf.args[0].name.as_ref().unwrap())
-                    {
-                        table_instances.push(Jump {
-                            label: bf.args[0].name.as_ref().unwrap().to_owned(),
-                            bytecode_index: *offset,
-                            span: bf.span.clone(),
-                        });
-                        if !utilized_tables.contains(&t) {
-                            utilized_tables.push(t);
-                        }
+                    table_instances.push(Jump {
+                        label: bf.args[0].name.as_ref().unwrap().to_owned(),
+                        bytecode_index: *offset,
+                        span: bf.span.clone(),
+                    });
 
-                        bytes.push((*offset, Bytes(format!("{}xxxx", Opcode::Push2))));
-                        *offset += 3;
-                    } else {
-                        tracing::error!(
-                            target: "codegen",
-                            "MISSING TABLE PASSED TO __tablestart \"{}\"",
-                            bf.args[0].name.as_ref().unwrap()
-                        );
-                        return Err(CodegenError {
-                            kind: CodegenErrorKind::InvalidMacroInvocation(
-                                bf.args[0].name.as_ref().unwrap().to_string(),
-                            ),
-                            span: bf.span.clone(),
-                            token: None,
-                        })
-                    }
+                    bytes.push((*offset, Bytes(format!("{}xxxx", Opcode::Push2))));
+                    *offset += 3;
                 }
                 BuiltinFunctionKind::FunctionSignature => {
                     if bf.args.len() != 1 {
diff --git a/huff_codegen/src/lib.rs b/huff_codegen/src/lib.rs
index 73ffbf9..e633fe8 100644
--- a/huff_codegen/src/lib.rs
+++ b/huff_codegen/src/lib.rs
@@ -10,7 +10,6 @@ use huff_utils::{
     ast::*,
     bytecode::*,
     error::CodegenError,
-    evm::Opcode,
     prelude::{
         bytes32_to_string, format_even_bytes, pad_n_bytes, CodegenErrorKind, FileSource, Span,
     },
@@ -69,7 +68,7 @@ impl Codegen {
         )?;
 
         // Generate the fully baked bytecode
-        Codegen::gen_table_bytecode(bytecode_res)
+        Codegen::gen_table_bytecode(bytecode_res, contract)
     }
 
     /// Generates constructor bytecode from a Contract AST
@@ -86,7 +85,8 @@ impl Codegen {
             &mut Vec::default(),
         )?;
 
-        Codegen::gen_table_bytecode(bytecode_res)
+        // Generate the bytecode return string
+        Codegen::gen_table_bytecode(bytecode_res, contract)
     }
 
     /// Helper function to find a macro or generate a CodegenError
@@ -108,7 +108,10 @@ impl Codegen {
 
     /// Appends table bytecode to the end of the BytecodeRes output.
     /// Fills table JUMPDEST placeholders.
-    pub(crate) fn gen_table_bytecode(res: BytecodeRes) -> Result<String, CodegenError> {
+    pub(crate) fn gen_table_bytecode(
+        res: BytecodeRes,
+        contract: &Contract,
+    ) -> Result<String, CodegenError> {
         if !res.unmatched_jumps.is_empty() {
             tracing::error!(
                 target: "codegen",
@@ -133,9 +136,9 @@ impl Codegen {
         let mut table_offsets: HashMap<String, usize> = HashMap::new(); // table name -> bytecode offset
         let mut table_offset = bytecode.len() / 2;
 
-        if let Err(e) = res.utilized_tables.iter().try_for_each(|jt| {
+        if let Err(e) = contract.tables.iter().try_for_each(|jt| {
             table_offsets.insert(jt.name.to_string(), table_offset);
-            let size = match bytes32_to_string(&jt.size, false).as_str().parse::<usize>() {
+            let size = match bytes32_to_string(&jt.size, false).parse::<usize>() {
                 Ok(s) => s,
                 Err(_) => return Err(CodegenError {
                     kind: CodegenErrorKind::UsizeConversion(format!("{:?}", jt.size)),
@@ -152,49 +155,28 @@ impl Codegen {
                 .statements
                 .iter()
                 .try_for_each(|s| {
-                    match &s.ty {
-                        StatementType::LabelCall(label) => {
-                            let offset = match res.label_indices.get(label) {
-                                Some(l) => l,
-                                None => {
-                                    tracing::error!(
+                    if let StatementType::LabelCall(label) = &s.ty {
+                        let offset = match res.label_indices.get(label) {
+                            Some(l) => l,
+                            None => {
+                                tracing::error!(
                                     target: "codegen",
                                     "Definition not found for Jump Table Label: \"{}\"",
                                     label
                                 );
-                                    return Err(CodegenError {
-                                        kind: CodegenErrorKind::UnmatchedJumpLabel,
-                                        span: s.span.clone(),
-                                        token: None,
-                                    });
-                                }
-                            };
-                            let hex = format_even_bytes(format!("{:02x}", offset));
-
-                            table_code = format!("{}{}", table_code, pad_n_bytes(
-                                hex.as_str(),
-                                if matches!(jt.kind, TableKind::JumpTablePacked) { 0x02 } else { 0x20 },
-                            ));
-                        }
-                        StatementType::Code(code) => {
-                            // Check if code length is even
-                            if code.len() % 2 != 0 {
                                 return Err(CodegenError {
-                                    kind: CodegenErrorKind::InvalidCodeLength(code.len()),
+                                    kind: CodegenErrorKind::UnmatchedJumpLabel,
                                     span: s.span.clone(),
                                     token: None,
                                 });
                             }
+                        };
+                        let hex = format_even_bytes(format!("{:02x}", offset));
 
-                            table_code = format!("{}{}", table_code, code);
-                        }
-                        _ => {
-                            return Err(CodegenError {
-                                kind: CodegenErrorKind::InvalidMacroStatement,
-                                span: jt.span.clone(),
-                                token: None
-                            })
-                        }
+                        table_code = format!("{}{}", table_code, pad_n_bytes(
+                            hex.as_str(),
+                            if matches!(jt.kind, TableKind::JumpTablePacked) { 0x02 } else { 0x20 },
+                        ));
                     }
                     Ok(())
                 });
@@ -263,7 +245,6 @@ impl Codegen {
         let mut jump_table = JumpTable::new();
         let mut label_indices = LabelIndices::new();
         let mut table_instances = Jumps::new();
-        let mut utilized_tables: Vec<TableDefinition> = Vec::new();
 
         // Loop through all intermediate bytecode representations generated from the AST
         for (_ir_bytes_index, ir_byte) in ir_bytes.into_iter().enumerate() {
@@ -290,7 +271,6 @@ impl Codegen {
                         &mut jump_table,
                         &mut label_indices,
                         &mut table_instances,
-                        &mut utilized_tables,
                         starting_offset,
                     )?;
                     bytes.append(&mut push_bytes);
@@ -317,29 +297,13 @@ impl Codegen {
             tracing::warn!(target: "codegen", "ATTEMPTED MACRO INVOCATION POP FAILED AT SCOPE: {}", scope.len());
         }
 
-        // Add functions (outlined macros) to the end of the bytecode if the scope length == 1
-        // (i.e., we're at the top level of recursion)
-        if scope.len() == 1 {
-            bytes = Codegen::append_functions(
-                contract,
-                scope,
-                &mut offset,
-                mis,
-                &mut jump_table,
-                &mut label_indices,
-                &mut table_instances,
-                bytes,
-            )?;
-        } else {
-            // If the scope length is > 1, we're processing a child macro. Since we're done
-            // with it, it can be popped.
-            scope.pop();
-        }
+        let bytecode: String = bytes.iter().map(|byte| byte.0.to_string()).collect();
+        tracing::info!(target: "codegen", "MACRO \"{}\" GENERATED BYTECODE EXCLUDING JUMPS: {}", macro_def.name, bytecode);
 
         // Fill JUMPDEST placeholders
         let (bytes, unmatched_jumps) = Codegen::fill_unmatched(bytes, &jump_table, &label_indices)?;
 
-        Ok(BytecodeRes { bytes, label_indices, unmatched_jumps, table_instances, utilized_tables })
+        Ok(BytecodeRes { bytes, label_indices, unmatched_jumps, table_instances })
     }
 
     /// Helper associated function to fill unmatched jump dests.
@@ -409,70 +373,6 @@ impl Codegen {
         Ok((bytes, unmatched_jumps))
     }
 
-    /// Helper associated function to append functions to the end of the bytecode.
-    ///
-    /// ## Overview
-    ///
-    /// Iterates over the contract's functions, generates their bytecode, fills unmatched jumps &
-    /// label indices, and appends the functions' bytecode to the end of the contract's bytecode.
-    ///
-    /// On success, passes ownership of `bytes` back to the caller.
-    /// On failure, returns a CodegenError.
-    #[allow(clippy::too_many_arguments)]
-    pub fn append_functions(
-        contract: &Contract,
-        scope: &mut Vec<MacroDefinition>,
-        offset: &mut usize,
-        mis: &mut Vec<(usize, MacroInvocation)>,
-        jump_table: &mut JumpTable,
-        label_indices: &mut LabelIndices,
-        table_instances: &mut Jumps,
-        mut bytes: Vec<(usize, Bytes)>,
-    ) -> Result<Vec<(usize, Bytes)>, CodegenError> {
-        for macro_def in contract.macros.iter().filter(|m| m.outlined) {
-            // Push the function to the scope
-            scope.push(macro_def.clone());
-
-            // Add 1 to starting offset to account for the JUMPDEST opcode
-            let mut res =
-                Codegen::macro_to_bytecode(macro_def.clone(), contract, scope, *offset + 1, mis)?;
-
-            for j in res.unmatched_jumps.iter_mut() {
-                let new_index = j.bytecode_index;
-                j.bytecode_index = 0;
-                let mut new_jumps = if let Some(jumps) = jump_table.get(&new_index) {
-                    jumps.clone()
-                } else {
-                    vec![]
-                };
-                new_jumps.push(j.clone());
-                jump_table.insert(new_index, new_jumps);
-            }
-            table_instances.extend(res.table_instances);
-            label_indices.extend(res.label_indices);
-
-            let macro_code_len = res.bytes.iter().map(|(_, b)| b.0.len()).sum::<usize>() / 2;
-
-            // Get necessary swap ops to reorder stack
-            // PC of the return jumpdest should be above the function's outputs on the stack
-            let stack_swaps =
-                (0..macro_def.returns).map(|i| format!("{:02x}", 0x90 + i)).collect::<Vec<_>>();
-
-            // Insert JUMPDEST, stack swaps, and final JUMP back to the location of invocation.
-            bytes.push((*offset, Bytes(Opcode::Jumpdest.to_string())));
-            res.bytes.push((
-                *offset + macro_code_len + 1,
-                Bytes(format!("{}{}", stack_swaps.join(""), Opcode::Jump)),
-            ));
-            bytes = [bytes, res.bytes].concat();
-            // Add the jumpdest to the beginning of the outlined macro.
-            label_indices.insert(format!("goto_{}", macro_def.name.clone()), *offset);
-            *offset += macro_code_len + stack_swaps.len() + 2; // JUMPDEST + MACRO_CODE_LEN +
-                                                               // stack_swaps.len() + JUMP
-        }
-        Ok(bytes)
-    }
-
     /// Generate a codegen artifact
     ///
     /// # Arguments
diff --git a/huff_core/src/lib.rs b/huff_core/src/lib.rs
index 4003086..90a80f7 100644
--- a/huff_core/src/lib.rs
+++ b/huff_core/src/lib.rs
@@ -238,7 +238,6 @@ impl<'a> Compiler {
         let main_bytecode = match Codegen::generate_main_bytecode(&contract) {
             Ok(mb) => mb,
             Err(mut e) => {
-                tracing::error!(target: "codegen", "FAILED TO GENERATE MAIN BYTECODE FOR CONTRACT");
                 // Add File Source to Span
                 e.span = AstSpan(
                     e.span
@@ -259,28 +258,21 @@ impl<'a> Compiler {
         let constructor_bytecode = match Codegen::generate_constructor_bytecode(&contract) {
             Ok(mb) => mb,
             Err(mut e) => {
-                // Return any errors except if the inputs is empty and the constructor definition is
-                // missing
-                if e.kind != CodegenErrorKind::MissingMacroDefinition("CONSTRUCTOR".to_string()) ||
-                    !inputs.is_empty()
-                {
+                if !inputs.is_empty() {
                     // Add File Source to Span
-                    let mut errs = e
-                        .span
-                        .0
-                        .into_iter()
-                        .map(|mut s| {
-                            s.file = Some(Arc::clone(&file));
-                            s
-                        })
-                        .collect::<Vec<Span>>();
-                    errs.dedup();
-                    e.span = AstSpan(errs);
+                    e.span = AstSpan(
+                        e.span
+                            .0
+                            .into_iter()
+                            .map(|mut s| {
+                                s.file = Some(Arc::clone(&file));
+                                s
+                            })
+                            .collect::<Vec<Span>>(),
+                    );
                     tracing::error!(target: "codegen", "Constructor inputs provided, but contract missing \"CONSTRUCTOR\" macro!");
                     return Err(CompilerError::CodegenError(e))
                 }
-
-                // If the kind is a missing constructor we can ignore it
                 tracing::warn!(target: "codegen", "Contract has no \"CONSTRUCTOR\" macro definition!");
                 "".to_string()
             }
diff --git a/huff_lexer/src/lib.rs b/huff_lexer/src/lib.rs
index fe39412..55282eb 100644
--- a/huff_lexer/src/lib.rs
+++ b/huff_lexer/src/lib.rs
@@ -32,8 +32,6 @@ pub enum Context {
     AbiArgs,
     /// constant context
     Constant,
-    /// Code table context
-    CodeTableBody,
 }
 
 /// ## Lexer
@@ -268,7 +266,7 @@ impl<'a> Lexer<'a> {
     /// `TokenKind::Ident`.
     ///
     /// Rules:
-    /// - The `macro`, `fn`, `function`, `constant`, `event`, `jumptable`, `jumptable__packed`, and
+    /// - The `macro`, `function`, `constant`, `event`, `jumptable`, `jumptable__packed`, and
     ///   `table` keywords must be preceded by a `#define` keyword.
     /// - The `takes` keyword must be preceded by an assignment operator: `=`.
     /// - The `nonpayable`, `payable`, `view`, and `pure` keywords must be preceeded by one of these
@@ -278,7 +276,6 @@ impl<'a> Lexer<'a> {
     pub fn check_keyword_rules(&mut self, found_kind: &Option<TokenKind>) -> bool {
         match found_kind {
             Some(TokenKind::Macro) |
-            Some(TokenKind::Fn) |
             Some(TokenKind::Function) |
             Some(TokenKind::Constant) |
             Some(TokenKind::Event) |
@@ -380,7 +377,6 @@ impl<'a> Iterator for Lexer<'a> {
 
                     let keys = [
                         TokenKind::Macro,
-                        TokenKind::Fn,
                         TokenKind::Function,
                         TokenKind::Constant,
                         TokenKind::Takes,
@@ -421,12 +417,9 @@ impl<'a> Iterator for Lexer<'a> {
 
                     if let Some(kind) = &found_kind {
                         match kind {
-                            TokenKind::Macro | TokenKind::Fn => {
-                                self.context = Context::MacroDefinition
-                            }
+                            TokenKind::Macro => self.context = Context::MacroDefinition,
                             TokenKind::Function | TokenKind::Event => self.context = Context::Abi,
                             TokenKind::Constant => self.context = Context::Constant,
-                            TokenKind::CodeTable => self.context = Context::CodeTableBody,
                             _ => (),
                         }
                     }
@@ -461,7 +454,7 @@ impl<'a> Iterator for Lexer<'a> {
                         }
                     }
 
-                    let pot_op = self.dyn_peek(|c| c.is_alphanumeric());
+                    let pot_op = self.dyn_peek(|c| c.is_alphanumeric() || c == &'_');
 
                     // Syntax sugar: true evaluates to 0x01, false evaluates to 0x00
                     if matches!(pot_op.as_str(), "true" | "false") {
@@ -582,15 +575,7 @@ impl<'a> Iterator for Lexer<'a> {
                             matches!(c, '\u{0041}'..='\u{0046}' | '\u{0061}'..='\u{0066}')
                     });
                     self.current_span_mut().start += 2; // Ignore the "0x"
-
-                    if self.context == Context::CodeTableBody {
-                        // In codetables, the bytecode provided is of arbitrary length. We pass
-                        // the code as an Ident, and it is appended to the end of the runtime
-                        // bytecode in codegen.
-                        TokenKind::Ident(self.slice())
-                    } else {
-                        TokenKind::Literal(str_to_bytes32(self.slice().as_ref()))
-                    }
+                    TokenKind::Literal(str_to_bytes32(self.slice().as_ref()))
                 }
                 '=' => TokenKind::Assign,
                 '(' => {
@@ -618,7 +603,7 @@ impl<'a> Iterator for Lexer<'a> {
                     TokenKind::OpenBrace
                 }
                 '}' => {
-                    if matches!(self.context, Context::MacroBody | Context::CodeTableBody) {
+                    if self.context == Context::MacroBody {
                         self.context = Context::Global;
                     }
                     TokenKind::CloseBrace
diff --git a/huff_parser/Cargo.toml b/huff_parser/Cargo.toml
index 8706b56..031d06b 100644
--- a/huff_parser/Cargo.toml
+++ b/huff_parser/Cargo.toml
@@ -18,4 +18,3 @@ proptest = "1.0.0"
 tiny-keccak = { version = "2.0.2", features = ["keccak"] }
 tracing = "0.1.34"
 hex = "0.4.3"
-regex = "1.6.0"
\ No newline at end of file
diff --git a/huff_parser/README.md b/huff_parser/README.md
index 1258ced..904c072 100644
--- a/huff_parser/README.md
+++ b/huff_parser/README.md
@@ -45,7 +45,6 @@ let expected_contract = Contract {
       takes: 0,
       returns: 0,
       span: AstSpan(vec![Span { start: 0, end: 7, file: None }, Span { start: 8, end: 13, file: None }, Span { start: 14, end: 25, file: None }, Span { start: 25, end: 26, file: None }, Span { start: 26, end: 27, file: None }, Span { start: 28, end: 29, file: None }, Span { start: 30, end: 35, file: None }, Span { start: 35, end: 36, file: None }, Span { start: 36, end: 37, file: None }, Span { start: 37, end: 38, file: None }, Span { start: 39, end: 46, file: None }, Span { start: 46, end: 47, file: None }, Span { start: 47, end: 48, file: None }, Span { start: 48, end: 49, file: None }, Span { start: 50, end: 51, file: None }, Span { start: 51, end: 52, file: None }]),
-      outlined: false,
     }
   ],
   invocations: vec![],
diff --git a/huff_parser/src/lib.rs b/huff_parser/src/lib.rs
index 5101a0a..96e4325 100644
--- a/huff_parser/src/lib.rs
+++ b/huff_parser/src/lib.rs
@@ -11,7 +11,6 @@ use huff_utils::{
     token::{Token, TokenKind},
     types::*,
 };
-use regex::Regex;
 use std::path::Path;
 use tiny_keccak::{Hasher, Keccak};
 
@@ -88,7 +87,7 @@ impl Parser {
                     tracing::info!(target: "parser", "SUCCESSFULLY PARSED CONSTANT {}", c.name);
                     contract.constants.push(c);
                 }
-                TokenKind::Macro | TokenKind::Fn => {
+                TokenKind::Macro => {
                     let m = self.parse_macro()?;
                     tracing::info!(target: "parser", "SUCCESSFULLY PARSED MACRO {}", m.name);
                     contract.macros.push(m);
@@ -104,7 +103,7 @@ impl Parser {
                     );
                     return Err(ParserError {
                         kind: ParserErrorKind::InvalidDefinition(self.current_token.kind.clone()),
-                        hint: Some("Definition must be one of: `function`, `event`, `constant`, `macro`, or `fn`.".to_string()),
+                        hint: Some("Definition must be one of: `function`, `event`, `constant`, or `macro`.".to_string()),
                         spans: AstSpan(vec![self.current_token.span.clone()]),
                     })
                 }
@@ -378,8 +377,7 @@ impl Parser {
     ///
     /// It should parse the following : macro MACRO_NAME(args...) = takes (x) returns (n) {...}
     pub fn parse_macro(&mut self) -> Result<MacroDefinition, ParserError> {
-        let outlined = self.check(TokenKind::Fn);
-        self.match_kind(if outlined { TokenKind::Fn } else { TokenKind::Macro })?;
+        self.match_kind(TokenKind::Macro)?;
         let macro_name: String =
             self.match_kind(TokenKind::Ident("MACRO_NAME".to_string()))?.to_string();
         tracing::info!(target: "parser", "PARSING MACRO: \"{}\"", macro_name);
@@ -399,7 +397,6 @@ impl Parser {
             macro_takes,
             macro_returns,
             self.spans.clone(),
-            outlined,
         ))
     }
 
@@ -779,7 +776,6 @@ impl Parser {
     ///
     /// It should parse the following : (jumptable|jumptable__packed|table) NAME() {...}
     pub fn parse_table(&mut self) -> Result<TableDefinition, ParserError> {
-        let is_code_table = self.current_token.kind == TokenKind::CodeTable;
         let kind = TableKind::from(self.match_kind(self.current_token.kind.clone())?);
         let table_name: String =
             self.match_kind(TokenKind::Ident("TABLE_NAME".to_string()))?.to_string();
@@ -790,7 +786,7 @@ impl Parser {
         let _ = self.match_kind(TokenKind::Assign);
 
         // Parse the core table
-        let table_statements: Vec<Statement> = self.parse_table_body(is_code_table)?;
+        let table_statements: Vec<Statement> = self.parse_table_body()?;
         let size = match kind {
             TableKind::JumpTablePacked => table_statements.len() * 0x02,
             TableKind::JumpTable => table_statements.len() * 0x20,
@@ -798,13 +794,13 @@ impl Parser {
                 table_statements
                     .iter()
                     .map(|s| {
-                        if let StatementType::Code(c) = &s.ty {
-                            c.len()
+                        if let StatementType::LabelCall(l) = &s.ty {
+                            l.len()
                         } else {
                             // TODO: Throw an error here.
                             tracing::error!(
                                 target: "parser",
-                                "Invalid table statement. Must be valid hex bytecode. Got: {:?}",
+                                "Invalid table statement. Must be a label call. Got: {:?}",
                                 s
                             );
                             0_usize
@@ -819,49 +815,30 @@ impl Parser {
             table_name,
             kind,
             table_statements,
-            str_to_bytes32(format!("{:02x}", size).as_str()),
+            str_to_bytes32(size.to_string().as_str()),
             AstSpan(self.spans.clone()),
         ))
     }
 
     /// Parse the body of a table.
     ///
-    /// Only `LabelCall` and `Code` Statements should be authorized.
-    pub fn parse_table_body(&mut self, is_code_table: bool) -> Result<Vec<Statement>, ParserError> {
+    /// Only `LabelCall`s should be authorized.
+    /// TODO: Code tables are not yet supported.
+    pub fn parse_table_body(&mut self) -> Result<Vec<Statement>, ParserError> {
         let mut statements: Vec<Statement> = Vec::new();
-        let code_statement_regex = Regex::new(r"^([a-fA-F\d]+)$").unwrap();
-
         self.match_kind(TokenKind::OpenBrace)?;
         while !self.check(TokenKind::CloseBrace) {
             let new_spans = vec![self.current_token.span.clone()];
             match &self.current_token.kind {
                 TokenKind::Ident(ident_str) => {
                     statements.push(Statement {
-                        ty: if is_code_table {
-                            if code_statement_regex.is_match(ident_str) {
-                                StatementType::Code(ident_str.to_string())
-                            } else {
-                                tracing::error!(
-                                    "Invalid CodeTable Body Token: {:?}",
-                                    self.current_token.kind
-                                );
-                                return Err(ParserError {
-                                    kind: ParserErrorKind::InvalidTableBodyToken(
-                                        self.current_token.kind.clone(),
-                                    ),
-                                    hint: Some("Expected valid hex bytecode.".to_string()),
-                                    spans: AstSpan(new_spans),
-                                })
-                            }
-                        } else {
-                            StatementType::LabelCall(ident_str.to_string())
-                        },
+                        ty: StatementType::LabelCall(ident_str.to_string()),
                         span: AstSpan(new_spans),
                     });
                     self.consume();
                 }
                 kind => {
-                    tracing::error!("Invalid Table Body Token: {:?}", kind);
+                    tracing::error!("Invalid Table Body Token: {:?}", self.current_token.kind);
                     return Err(ParserError {
                         kind: ParserErrorKind::InvalidTableBodyToken(kind.clone()),
                         hint: Some("Expected an identifier string.".to_string()),
diff --git a/huff_utils/src/ast.rs b/huff_utils/src/ast.rs
index 70ee54b..5a010ee 100644
--- a/huff_utils/src/ast.rs
+++ b/huff_utils/src/ast.rs
@@ -427,8 +427,6 @@ pub struct MacroDefinition {
     pub returns: usize,
     /// The Span of the Macro Definition
     pub span: AstSpan,
-    /// Is the macro a function (outlined)?
-    pub outlined: bool,
 }
 
 impl ToIRBytecode<CodegenError> for MacroDefinition {
@@ -447,17 +445,8 @@ impl MacroDefinition {
         takes: usize,
         returns: usize,
         spans: Vec<Span>,
-        outlined: bool,
     ) -> Self {
-        MacroDefinition {
-            name,
-            parameters,
-            statements,
-            takes,
-            returns,
-            span: AstSpan(spans),
-            outlined,
-        }
+        MacroDefinition { name, parameters, statements, takes, returns, span: AstSpan(spans) }
     }
 
     /// Translate statements into IRBytes
@@ -481,12 +470,6 @@ impl MacroDefinition {
                         span: statement.span.clone(),
                     });
                 }
-                StatementType::Code(c) => {
-                    inner_irbytes.push(IRBytes {
-                        ty: IRByteType::Bytes(Bytes(c.to_owned())),
-                        span: statement.span.clone(),
-                    });
-                }
                 StatementType::MacroInvocation(mi) => {
                     inner_irbytes.push(IRBytes {
                         ty: IRByteType::Statement(Statement {
@@ -499,19 +482,19 @@ impl MacroDefinition {
                 StatementType::Constant(name) => {
                     // Constant needs to be evaluated at the top-level
                     inner_irbytes.push(IRBytes {
-                        ty: IRByteType::Constant(name.to_owned()),
+                        ty: IRByteType::Constant(name.to_string()),
                         span: statement.span.clone(),
                     });
                 }
                 StatementType::ArgCall(arg_name) => {
                     // Arg call needs to use a destination defined in the calling macro context
                     inner_irbytes.push(IRBytes {
-                        ty: IRByteType::ArgCall(arg_name.to_owned()),
+                        ty: IRByteType::ArgCall(arg_name.to_string()),
                         span: statement.span.clone(),
                     });
                 }
                 StatementType::LabelCall(jump_to) => {
-                    /* Jump To doesn't translate directly to bytecode */
+                    /* Jump To doesn't translate directly to bytecode ? */
                     inner_irbytes.push(IRBytes {
                         ty: IRByteType::Statement(Statement {
                             ty: StatementType::LabelCall(jump_to.to_string()),
@@ -521,7 +504,7 @@ impl MacroDefinition {
                     });
                 }
                 StatementType::Label(l) => {
-                    /* Jump Dests don't translate directly to bytecode */
+                    /* Jump Dests don't translate directly to bytecode ? */
                     inner_irbytes.push(IRBytes {
                         ty: IRByteType::Statement(Statement {
                             ty: StatementType::Label(l.clone()),
@@ -663,8 +646,6 @@ pub enum StatementType {
     Literal(Literal),
     /// An Opcode Statement
     Opcode(Opcode),
-    /// A Code Statement
-    Code(String),
     /// A Macro Invocation Statement
     MacroInvocation(MacroInvocation),
     /// A Constant Push
@@ -684,7 +665,6 @@ impl Display for StatementType {
         match self {
             StatementType::Literal(l) => write!(f, "LITERAL: {}", bytes32_to_string(l, true)),
             StatementType::Opcode(o) => write!(f, "OPCODE: {}", o),
-            StatementType::Code(s) => write!(f, "CODE: {}", s),
             StatementType::MacroInvocation(m) => {
                 write!(f, "MACRO INVOCATION: {}", m.macro_name)
             }
diff --git a/huff_utils/src/bytecode.rs b/huff_utils/src/bytecode.rs
index 9612c93..1f8e82b 100644
--- a/huff_utils/src/bytecode.rs
+++ b/huff_utils/src/bytecode.rs
@@ -2,7 +2,7 @@
 //!
 //! Abstract translating state into bytecode.
 
-use crate::prelude::{AstSpan, Statement, TableDefinition};
+use crate::prelude::{AstSpan, Statement};
 use std::{
     collections::BTreeMap,
     fmt::{self, Display},
@@ -76,8 +76,6 @@ pub struct BytecodeRes {
     pub unmatched_jumps: Jumps,
     /// Table Instances
     pub table_instances: Jumps,
-    /// Utilized Tables
-    pub utilized_tables: Vec<TableDefinition>,
 }
 
 impl Display for BytecodeRes {
diff --git a/huff_utils/src/error.rs b/huff_utils/src/error.rs
index f24de3c..ded95ef 100644
--- a/huff_utils/src/error.rs
+++ b/huff_utils/src/error.rs
@@ -157,10 +157,6 @@ pub enum CodegenErrorKind {
     UsizeConversion(String),
     /// Invalid Arguments
     InvalidArguments(String),
-    /// Invalid Table Statement
-    InvalidTableStatement(String),
-    /// Invalid Code Length
-    InvalidCodeLength(usize),
 }
 
 impl Spanned for CodegenError {
@@ -204,12 +200,6 @@ impl<W: Write> Report<W> for CodegenError {
             CodegenErrorKind::InvalidArguments(msg) => {
                 write!(f.out, "Invalid arguments: \"{}\"", msg)
             }
-            CodegenErrorKind::InvalidTableStatement(msg) => {
-                write!(f.out, "Invalid table statement: \"{}\"", msg)
-            }
-            CodegenErrorKind::InvalidCodeLength(len) => {
-                write!(f.out, "Invalid code length: {}", len)
-            }
         }
     }
 }
@@ -499,12 +489,6 @@ impl<'a> fmt::Display for CompilerError<'a> {
                 CodegenErrorKind::InvalidArguments(_) => {
                     write!(f, "\nError: Invalid Arguments\n{}\n", ce.span.error(None))
                 }
-                CodegenErrorKind::InvalidTableStatement(_) => {
-                    write!(f, "\nError: Invalid Table Statement\n{}\n", ce.span.error(None))
-                }
-                CodegenErrorKind::InvalidCodeLength(_) => {
-                    write!(f, "\nError: Invalid Code Length\n{}\n", ce.span.error(None))
-                }
             },
             CompilerError::FailedCompiles(v) => {
                 v.iter().for_each(|ce| {
diff --git a/huff_utils/src/token.rs b/huff_utils/src/token.rs
index c572a7b..67a8a71 100644
--- a/huff_utils/src/token.rs
+++ b/huff_utils/src/token.rs
@@ -35,8 +35,6 @@ pub enum TokenKind {
     Include,
     /// "macro" keyword
     Macro,
-    /// "fn" keyword
-    Fn,
     /// "function" keyword
     Function,
     /// "event" keyword
@@ -128,7 +126,6 @@ impl fmt::Display for TokenKind {
             TokenKind::Define => "#define",
             TokenKind::Include => "#include",
             TokenKind::Macro => "macro",
-            TokenKind::Fn => "fn",
             TokenKind::Function => "function",
             TokenKind::Event => "event",
             TokenKind::Constant => "constant",


Test patch:
diff --git a/huff_codegen/tests/abigen.rs b/huff_codegen/tests/abigen.rs
index b05bc6a..7473956 100644
--- a/huff_codegen/tests/abigen.rs
+++ b/huff_codegen/tests/abigen.rs
@@ -12,7 +12,6 @@ fn constructs_valid_abi() {
         takes: 0,
         returns: 0,
         span: AstSpan(vec![]),
-        outlined: false,
     };
     let contract = Contract {
         macros: vec![constructor],
@@ -48,7 +47,6 @@ fn missing_constructor_fails() {
         takes: 0,
         returns: 0,
         span: AstSpan(vec![]),
-        outlined: false,
     };
     let contract = Contract {
         macros: vec![],
diff --git a/huff_core/tests/builtins.rs b/huff_core/tests/builtins.rs
index 9c5914c..8851dd7 100644
--- a/huff_core/tests/builtins.rs
+++ b/huff_core/tests/builtins.rs
@@ -58,10 +58,6 @@ fn test_tablesize_builtin() {
             lab_3 // 3 00011
         }
 
-        #define table CODE_TABLE {
-            0xDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF
-        }
-
         #define macro TEST_INIT_JUMP_TABLE() = takes(0) returns(1) {
             __tablesize(STANDARD_JUMPTABLE) __tablestart(STANDARD_JUMPTABLE) 0x00 codecopy
         }
@@ -70,14 +66,8 @@ fn test_tablesize_builtin() {
             __tablesize(PACKED_JUMPTABLE)
         }
 
-        #define macro BUILTIN_TEST_2() = takes(0) returns(1) {
-            __tablesize(CODE_TABLE)
-        }
-
         #define macro MAIN() = takes(0) returns (0) {
             BUILTIN_TEST()
-            TEST_INIT_JUMP_TABLE()
-            BUILTIN_TEST_2()
 
             lab_0:
                 0x00
@@ -118,7 +108,7 @@ fn test_tablesize_builtin() {
 
     // Have the Codegen create the constructor bytecode
     let mbytes = Codegen::generate_main_bytecode(&contract).unwrap();
-    assert_eq!(mbytes, String::from("6008608061002c60003960205b60006000f35b60006000f35b60006000f35b60006000f3000c00120018001e000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001eDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"));
+    assert_eq!(mbytes, String::from("60085b60006000f35b60006000f35b60006000f35b60006000f300020008000e001400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014"));
 }
 
 #[test]
@@ -135,7 +125,7 @@ fn test_tablestart_builtin() {
             lab_3 // 3 00011
         }
 
-        #define macro BUILTIN_TEST() = takes(0) returns(2) {
+        #define macro BUILTIN_TEST() = takes(0) returns(1) {
             __tablestart(PACKED_JUMPTABLE)
             __tablestart(STANDARD_JUMPTABLE)
         }
@@ -245,7 +235,7 @@ fn test_jump_table_exhaustive_usage() {
 
     // Have the Codegen create the constructor bytecode
     let mbytes = Codegen::generate_main_bytecode(&contract).unwrap();
-    assert_eq!(mbytes, String::from("608061004060003960003560e01c8063a9059cbb14610019575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003a"));
+    assert_eq!(mbytes, String::from("61012861004160003960003560e01c8063a9059cbb1461001a575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b"));
 }
 
 #[test]
@@ -372,7 +362,7 @@ fn test_label_clashing() {
 
     // Have the Codegen create the main macro bytecode
     let mbytes = Codegen::generate_main_bytecode(&contract).unwrap();
-    assert_eq!(mbytes, String::from("6008610048600039608061005060003960003560e01c8063a9059cbb14610021575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b602060200100300036003c004200000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000042"));
+    assert_eq!(mbytes, String::from("600861004960003961012861005160003960003560e01c8063a9059cbb14610022575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b602060200100310037003d004300000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000037000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000043"));
 }
 
 #[test]
diff --git a/huff_core/tests/functions.rs b/huff_core/tests/functions.rs
deleted file mode 100644
index 555e4db..0000000
--- a/huff_core/tests/functions.rs
+++ /dev/null
@@ -1,213 +0,0 @@
-use huff_codegen::Codegen;
-use huff_lexer::Lexer;
-use huff_parser::Parser;
-use huff_utils::prelude::{FileSource, FullFileSource, Token};
-use std::sync::Arc;
-
-#[test]
-fn test_function() {
-    let source: &str = r#"
-        #define function test1(uint256,uint256,uint256) pure returns(uint256)
-        #define function test2(uint256,uint256,uint256) pure returns(uint256)
-        #define function test3(uint256,uint256,uint256) pure returns(uint256)
-
-        #define fn MUL_DIV_DOWN() = takes (3) returns (1) {
-            // Input stack:      [x, y, denominator]
-            dup3              // [denominator, x, y, denominator]
-            dup3              // [y, denominator, x, y, denominator]
-            dup3              // [x, y, denominator, x, y, denominator]
-
-            mul               // [x * y, denominator, x, y, denominator]
-            0x00 mstore       // [denominator, x, y, denominator]
-
-            iszero iszero     // [denominator != 0, x, y, denominator]
-
-            swap1             // [x, denominator != 0, y, denominator]
-            dup1              // [x, x, denominator != 0, y, denominator]
-            iszero            // [x == 0, x, denominator != 0, y, denominator]
-
-            swap1             // [x, x == 0, denominator != 0, y, denominator]
-            0x00 mload        // [x * y, x, x == 0, denominator != 0, y, denominator]
-            div               // [(x * y) / x, x == 0, denominator != 0, y, denominator]
-
-            dup4              // [y, (x * y) / x, x == 0, denominator != 0, y, denominator]
-            eq                // [y == (x * y) / x, x == 0, denominator != 0, y, denominator]
-            or                // [y == (x * y) / x | x == 0, denominator != 0, y, denominator]
-            and               // [(y == (x * y) / x | x == 0) & denominator != 0, y, denominator]
-
-            iszero fail jumpi // Revert if (y == (x * y) / x | x == 0) & denominator != 0 is not satisfied
-
-            pop               // [denominator]
-            0x00 mload        // [x * y, denominator]
-            div               // [(x * y) / denominator]
-
-            0x01 finish jumpi
-
-            fail:
-                0x00 0x00 revert
-            finish:
-            // Return stack:     [(x * y) / denominator]
-        }
-
-        #define macro TEST_1() = takes(0) returns(0) {
-            0x44 calldataload // [denominator]
-            0x24 calldataload // [y, denominator]
-            0x04 calldataload // [x, y, denominator]
-            MUL_DIV_DOWN()
-            0x00 mstore
-            0x20 0x00 return
-        }
-
-        #define macro TEST_2() = takes(0) returns(0) {
-            0x44 calldataload // [denominator]
-            0x24 calldataload // [y, denominator]
-            0x04 calldataload // [x, y, denominator]
-            MUL_DIV_DOWN()
-            0x00 mstore
-            0x20 0x00 return
-        }
-
-        #define macro TEST_3() = takes(0) returns(0) {
-            0x44 calldataload // [denominator]
-            0x24 calldataload // [y, denominator]
-            0x04 calldataload // [x, y, denominator]
-            MUL_DIV_DOWN()
-            0x00 mstore
-            0x20 0x00 return
-        }
-
-        #define macro MAIN() = takes (0) returns (0) {
-            0x00 calldataload 0xE0 shr
-            dup1 __FUNC_SIG(test1) eq test_one jumpi
-            dup1 __FUNC_SIG(test2) eq test_two jumpi
-            dup1 __FUNC_SIG(test3) eq test_three jumpi
-
-            test_one:
-                TEST_1()
-            test_two:
-                TEST_2()
-            test_three:
-                TEST_3()
-        }
-    "#;
-
-    // Parse tokens
-    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
-    let lexer = Lexer::new(flattened_source);
-    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
-    let mut parser = Parser::new(tokens, None);
-
-    // Parse the AST
-    let mut contract = parser.parse().unwrap();
-
-    // Derive storage pointers
-    contract.derive_storage_pointers();
-
-    // Instantiate Codegen
-    let cg = Codegen::new();
-
-    // The codegen instance should have no artifact
-    assert!(cg.artifact.is_none());
-
-    // Have the Codegen create the runtime bytecode
-    let rbytes = Codegen::generate_main_bytecode(&contract).unwrap();
-    // Churn
-    let mut cg = Codegen::new();
-    let artifact =
-        cg.churn(Arc::clone(&Arc::new(FileSource::default())), vec![], &rbytes, "").unwrap();
-    assert_eq!(artifact.bytecode, String::from("60ad8060093d393df360003560e01c8063075900201461002757806319715c0d1461004457806327902d6914610061575b60443560243560043561003b92919061007e565b60005260206000f35b60443560243560043561005892919061007e565b60005260206000f35b60443560243560043561007592919061007e565b60005260206000f35b828282026000521515908015906000510483141716156100a457506000510460016100aa575b60006000fd5b9056"));
-}
-
-#[test]
-fn test_nested_function() {
-    let source: &str = r#"
-        #define function test1(uint256,uint256,uint256) pure returns(uint256)
-        #define function test2(uint256,uint256,uint256) pure returns(uint256)
-        #define function test3(uint256,uint256,uint256) pure returns(uint256)
-
-        #define fn MUL_DIV_DOWN() = takes (3) returns (1) {
-            // Input stack:      [x, y, denominator]
-            dup3              // [denominator, x, y, denominator]
-            dup3              // [y, denominator, x, y, denominator]
-            dup3              // [x, y, denominator, x, y, denominator]
-
-            mul               // [x * y, denominator, x, y, denominator]
-            0x00 mstore       // [denominator, x, y, denominator]
-
-            iszero iszero     // [denominator != 0, x, y, denominator]
-
-            swap1             // [x, denominator != 0, y, denominator]
-            dup1              // [x, x, denominator != 0, y, denominator]
-            iszero            // [x == 0, x, denominator != 0, y, denominator]
-
-            swap1             // [x, x == 0, denominator != 0, y, denominator]
-            0x00 mload        // [x * y, x, x == 0, denominator != 0, y, denominator]
-            div               // [(x * y) / x, x == 0, denominator != 0, y, denominator]
-
-            dup4              // [y, (x * y) / x, x == 0, denominator != 0, y, denominator]
-            eq                // [y == (x * y) / x, x == 0, denominator != 0, y, denominator]
-            or                // [y == (x * y) / x | x == 0, denominator != 0, y, denominator]
-            and               // [(y == (x * y) / x | x == 0) & denominator != 0, y, denominator]
-
-            iszero fail jumpi // Revert if (y == (x * y) / x | x == 0) & denominator != 0 is not satisfied
-
-            pop               // [denominator]
-            0x00 mload        // [x * y, denominator]
-            div               // [(x * y) / denominator]
-
-            0x01 finish jumpi
-
-            fail:
-                0x00 0x00 revert
-            finish:
-            // Return stack:     [(x * y) / denominator]
-        }
-
-        #define fn MUL_DIV_DOWN_2() = takes (3) returns (1) {
-            MUL_DIV_DOWN()
-        }
-
-        #define macro TEST_1() = takes(0) returns(0) {
-            0x44 calldataload // [denominator]
-            0x24 calldataload // [y, denominator]
-            0x04 calldataload // [x, y, denominator]
-            MUL_DIV_DOWN_2()
-            0x00 mstore
-            0x20 0x00 return
-        }
-
-        #define macro MAIN() = takes (0) returns (0) {
-            0x00 calldataload 0xE0 shr
-            dup1 __FUNC_SIG(test1) eq test_one jumpi
-
-            test_one:
-                TEST_1()
-        }
-    "#;
-
-    // Parse tokens
-    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
-    let lexer = Lexer::new(flattened_source);
-    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
-    let mut parser = Parser::new(tokens, None);
-
-    // Parse the AST
-    let mut contract = parser.parse().unwrap();
-
-    // Derive storage pointers
-    contract.derive_storage_pointers();
-
-    // Instantiate Codegen
-    let cg = Codegen::new();
-
-    // The codegen instance should have no artifact
-    assert!(cg.artifact.is_none());
-
-    // Have the Codegen create the runtime bytecode
-    let rbytes = Codegen::generate_main_bytecode(&contract).unwrap();
-    // Churn
-    let mut cg = Codegen::new();
-    let artifact =
-        cg.churn(Arc::clone(&Arc::new(FileSource::default())), vec![], &rbytes, "").unwrap();
-    assert_eq!(artifact.bytecode, String::from("606b8060093d393df360003560e01c80630759002014610011575b60443560243560043561002592919061005d565b60005260206000f35b82828202600052151590801590600051048314171615610054575060005104600161005a575b60006000fd5b90565b61006892919061002e565b9056"));
-}
diff --git a/huff_core/tests/parser_errors.rs b/huff_core/tests/parser_errors.rs
index 18831bd..dd8a150 100644
--- a/huff_core/tests/parser_errors.rs
+++ b/huff_core/tests/parser_errors.rs
@@ -1,6 +1,7 @@
 use huff_lexer::*;
 use huff_parser::*;
 use huff_utils::prelude::*;
+use rand::prelude::*;
 
 #[test]
 fn test_invalid_macro_statement() {
@@ -95,7 +96,7 @@ fn test_invalid_definition() {
                 ParserError {
                     kind: ParserErrorKind::InvalidDefinition(TokenKind::Ident("test".to_string())),
                     hint: Some(
-                        "Definition must be one of: `function`, `event`, `constant`, `macro`, or `fn`."
+                        "Definition must be one of: `function`, `event`, `constant`, or `macro`."
                             .to_string()
                     ),
                     spans: AstSpan(vec![Span {
diff --git a/huff_lexer/tests/keywords.rs b/huff_lexer/tests/keywords.rs
index 5f9554d..f235a66 100644
--- a/huff_lexer/tests/keywords.rs
+++ b/huff_lexer/tests/keywords.rs
@@ -34,38 +34,6 @@ fn parses_macro_keyword() {
     assert!(lexer.eof);
 }
 
-#[test]
-fn parses_fn_keyword() {
-    let source = "#define fn";
-    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
-    let mut lexer = Lexer::new(flattened_source);
-
-    // Define Identifier first
-    let tok = lexer.next();
-    let unwrapped = tok.unwrap().unwrap();
-    let define_span = Span::new(0..7, None);
-    assert_eq!(unwrapped, Token::new(TokenKind::Define, define_span.clone()));
-    assert_eq!(lexer.current_span().deref(), &define_span);
-
-    // The next token should be the whitespace
-    let tok = lexer.next();
-    let unwrapped = tok.unwrap().unwrap();
-    let whitespace_span = Span::new(7..8, None);
-    assert_eq!(unwrapped, Token::new(TokenKind::Whitespace, whitespace_span.clone()));
-    assert_eq!(lexer.current_span().deref(), &whitespace_span);
-
-    // Lastly we should parse the fn keyword
-    let tok = lexer.next();
-    let unwrapped = tok.unwrap().unwrap();
-    let macro_span = Span::new(8..10, None);
-    assert_eq!(unwrapped, Token::new(TokenKind::Fn, macro_span.clone()));
-    assert_eq!(lexer.current_span().deref(), &macro_span);
-
-    // We covered the whole source
-    assert_eq!(lexer.current_span().end, source.len());
-    assert!(lexer.eof);
-}
-
 #[test]
 fn parses_function_keyword() {
     let source = "#define function";
@@ -302,7 +270,6 @@ fn parses_function_type_keywords() {
 fn parses_function_definition_with_keyword_name() {
     let key_words = [
         "macro",
-        "fn",
         "function",
         "constant",
         "takes",
@@ -365,7 +332,6 @@ fn parses_function_definition_with_keyword_name() {
 fn parses_label_with_keyword_name() {
     let key_words = [
         "macro",
-        "fn",
         "function",
         "constant",
         "takes",
@@ -423,7 +389,6 @@ fn parses_label_with_keyword_name() {
 fn parses_function_with_keyword_name() {
     let key_words = [
         "macro",
-        "fn",
         "function",
         "constant",
         "takes",
@@ -472,7 +437,6 @@ fn parses_function_with_keyword_name() {
 fn parses_function_with_keyword_name_in_macro() {
     let key_words = [
         "macro",
-        "fn",
         "function",
         "constant",
         "takes",
@@ -572,7 +536,6 @@ fn parses_keyword_arbitrary_whitespace() {
     // Macro, constant, and function keywords first- they are all preceded by "#define"
     let key_words = [
         ("macro", TokenKind::Macro),
-        ("fn", TokenKind::Fn),
         ("constant", TokenKind::Constant),
         ("function", TokenKind::Function),
     ];
diff --git a/huff_lexer/tests/labels.rs b/huff_lexer/tests/labels.rs
index d34a371..ab6cb94 100644
--- a/huff_lexer/tests/labels.rs
+++ b/huff_lexer/tests/labels.rs
@@ -19,3 +19,22 @@ fn parse_label() {
     );
     assert_eq!(tokens.get(tokens.len() - 4).unwrap().kind, TokenKind::Colon);
 }
+
+#[test]
+fn parse_label_with_opcode_name() {
+    let source =
+        "#define macro HELLO_WORLD() = takes(3) returns(0) {\n0x00 mstore\n 0x01 0x02 add cool_label_return_swap1_mload:\n0x01\n}";
+    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
+    let lexer = Lexer::new(flattened_source);
+    let tokens = lexer
+        .into_iter()
+        .map(|x| x.unwrap())
+        .filter(|x| !matches!(x.kind, TokenKind::Whitespace))
+        .collect::<Vec<Token>>();
+
+    assert_eq!(
+        tokens.get(tokens.len() - 5).unwrap().kind,
+        TokenKind::Label("cool_label_return_swap1_mload".to_string())
+    );
+    assert_eq!(tokens.get(tokens.len() - 4).unwrap().kind, TokenKind::Colon);
+}
diff --git a/huff_parser/tests/labels.rs b/huff_parser/tests/labels.rs
index c73a86b..c162434 100644
--- a/huff_parser/tests/labels.rs
+++ b/huff_parser/tests/labels.rs
@@ -160,7 +160,6 @@ fn multiline_labels() {
             // "}"
             Span { start: 158, end: 159, file: None },
         ]),
-        outlined: false,
     };
     assert_eq!(macro_definition.name, md_expected.name);
     assert_eq!(macro_definition.parameters, md_expected.parameters);
diff --git a/huff_parser/tests/macro.rs b/huff_parser/tests/macro.rs
index 34aacae..dcf45e9 100644
--- a/huff_parser/tests/macro.rs
+++ b/huff_parser/tests/macro.rs
@@ -36,7 +36,6 @@ fn empty_macro() {
             Span { start: 50, end: 51, file: None },
             Span { start: 51, end: 52, file: None },
         ]),
-        outlined: false,
     };
     assert_eq!(macro_definition, expected);
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
@@ -103,7 +102,6 @@ fn macro_with_simple_body() {
             Span { start: 75, end: 78, file: None },
             Span { start: 79, end: 80, file: None },
         ]),
-        outlined: false,
     };
     assert_eq!(macro_definition, expected);
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
@@ -282,7 +280,6 @@ fn macro_with_arg_calls() {
             Span { start: 1028, end: 1029, file: None },
             Span { start: 1055, end: 1056, file: None },
         ]),
-        outlined: false,
     };
     assert_eq!(macro_definition, expected);
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
@@ -456,7 +453,6 @@ fn macro_labels() {
             Span { start: 205, end: 211, file: None },
             Span { start: 216, end: 217, file: None },
         ]),
-        outlined: false,
     };
     assert_eq!(macro_definition, expected);
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
@@ -599,7 +595,6 @@ fn macro_invocation_with_arg_call() {
             Span { start: 173, end: 179, file: None },
             Span { start: 184, end: 185, file: None },
         ]),
-        outlined: false,
     };
     assert_eq!(macro_definition, expected);
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
@@ -668,115 +663,6 @@ fn macro_with_builtin_fn_call() {
             Span { start: 81, end: 82, file: None },
             Span { start: 87, end: 88, file: None },
         ]),
-        outlined: false,
-    };
-    assert_eq!(macro_definition, expected);
-    assert_eq!(parser.current_token.kind, TokenKind::Eof);
-}
-
-// Outlined macros (functions) are parsed the same way as inlined macros, so there should be no
-// difference besides the spans as well as the outlined flag.
-#[test]
-fn empty_outlined_macro() {
-    let source = "#define fn HELLO_WORLD() = takes(0) returns(4) {}";
-    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
-    let lexer = Lexer::new(flattened_source);
-    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
-    let mut parser = Parser::new(tokens, None);
-
-    // Grab the first macro
-    let macro_definition = parser.parse().unwrap().macros[0].clone();
-    let expected = MacroDefinition {
-        name: "HELLO_WORLD".to_string(),
-        parameters: vec![],
-        statements: vec![],
-        takes: 0,
-        returns: 4,
-        span: AstSpan(vec![
-            Span { start: 0, end: 7, file: None },
-            Span { start: 8, end: 10, file: None },
-            Span { start: 11, end: 22, file: None },
-            Span { start: 22, end: 23, file: None },
-            Span { start: 23, end: 24, file: None },
-            Span { start: 25, end: 26, file: None },
-            Span { start: 27, end: 32, file: None },
-            Span { start: 32, end: 33, file: None },
-            Span { start: 33, end: 34, file: None },
-            Span { start: 34, end: 35, file: None },
-            Span { start: 36, end: 43, file: None },
-            Span { start: 43, end: 44, file: None },
-            Span { start: 44, end: 45, file: None },
-            Span { start: 45, end: 46, file: None },
-            Span { start: 47, end: 48, file: None },
-            Span { start: 48, end: 49, file: None },
-        ]),
-        outlined: true,
-    };
-    assert_eq!(macro_definition, expected);
-    assert_eq!(parser.current_token.kind, TokenKind::Eof);
-}
-
-#[test]
-fn outlined_macro_with_simple_body() {
-    let source = "#define fn HELLO_WORLD() = takes(3) returns(0) {\n0x00 mstore\n 0x01 0x02 add\n}";
-    let flattened_source = FullFileSource { source, file: None, spans: vec![] };
-    let lexer = Lexer::new(flattened_source);
-    let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
-    let mut parser = Parser::new(tokens, None);
-
-    // Grab the first macro
-    let macro_definition = parser.parse().unwrap().macros[0].clone();
-    let expected = MacroDefinition {
-        name: "HELLO_WORLD".to_string(),
-        parameters: vec![],
-        statements: vec![
-            Statement {
-                ty: StatementType::Literal(str_to_bytes32("00")),
-                span: AstSpan(vec![Span { start: 51, end: 53, file: None }]),
-            },
-            Statement {
-                ty: StatementType::Opcode(Opcode::Mstore),
-                span: AstSpan(vec![Span { start: 54, end: 60, file: None }]),
-            },
-            Statement {
-                ty: StatementType::Literal(str_to_bytes32("01")),
-                span: AstSpan(vec![Span { start: 64, end: 66, file: None }]),
-            },
-            Statement {
-                ty: StatementType::Literal(str_to_bytes32("02")),
-                span: AstSpan(vec![Span { start: 69, end: 71, file: None }]),
-            },
-            Statement {
-                ty: StatementType::Opcode(Opcode::Add),
-                span: AstSpan(vec![Span { start: 72, end: 75, file: None }]),
-            },
-        ],
-        takes: 3,
-        returns: 0,
-        span: AstSpan(vec![
-            Span { start: 0, end: 7, file: None },
-            Span { start: 8, end: 10, file: None },
-            Span { start: 11, end: 22, file: None },
-            Span { start: 22, end: 23, file: None },
-            Span { start: 23, end: 24, file: None },
-            Span { start: 25, end: 26, file: None },
-            Span { start: 27, end: 32, file: None },
-            Span { start: 32, end: 33, file: None },
-            Span { start: 33, end: 34, file: None },
-            Span { start: 34, end: 35, file: None },
-            Span { start: 36, end: 43, file: None },
-            Span { start: 43, end: 44, file: None },
-            Span { start: 44, end: 45, file: None },
-            Span { start: 45, end: 46, file: None },
-            Span { start: 47, end: 48, file: None },
-            Span { start: 51, end: 53, file: None },
-            Span { start: 54, end: 60, file: None },
-            Span { start: 64, end: 66, file: None },
-            Span { start: 69, end: 71, file: None },
-            Span { start: 72, end: 75, file: None },
-            Span { start: 76, end: 77, file: None },
-        ]),
-        outlined: true,
     };
     assert_eq!(macro_definition, expected);
     assert_eq!(parser.current_token.kind, TokenKind::Eof);
diff --git a/huff_parser/tests/table.rs b/huff_parser/tests/table.rs
index 11008ae..5f04835 100644
--- a/huff_parser/tests/table.rs
+++ b/huff_parser/tests/table.rs
@@ -43,7 +43,7 @@ fn table_with_no_body() {
 #[test]
 fn table_with_body() {
     // TODO: Code tables are not yet supported
-    let table_kinds = [(TokenKind::JumpTable, "60"), (TokenKind::JumpTablePacked, "06")];
+    let table_kinds = [(TokenKind::JumpTable, "96"), (TokenKind::JumpTablePacked, "06")];
 
     for (kind, expected_size) in table_kinds {
         let source = &format!(