Repository: huff-language/huff-rs
Pull request #168 (2022-07-15 19:11:32)

feat(huff_codegen): Finish Code Tables
## Overview

Finishes Code Table codegen



Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 8841e70..41c65e3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -718,6 +718,7 @@ dependencies = [
  "huff_lexer",
  "huff_utils",
  "proptest",
+ "regex",
  "tiny-keccak",
  "tracing",
 ]
@@ -1279,9 +1280,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.5.6"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
+checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1299,9 +1300,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.26"
+version = "0.6.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
+checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244"
 
 [[package]]
 name = "remove_dir_all"
diff --git a/huff_codegen/src/irgen/statements.rs b/huff_codegen/src/irgen/statements.rs
index 1a859d8..87a1e06 100644
--- a/huff_codegen/src/irgen/statements.rs
+++ b/huff_codegen/src/irgen/statements.rs
@@ -15,6 +15,7 @@ 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![];
@@ -73,6 +74,7 @@ pub fn statement_gen(
             }
             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;
@@ -173,12 +175,29 @@ 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 contract.find_table_by_name(bf.args[0].name.as_ref().unwrap()).is_none() {
+                    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);
+                        }
+
+                        bytes.push((*offset, Bytes(format!("{}xxxx", Opcode::Push2))));
+                        *offset += 3;
+                    } else {
                         tracing::error!(
                             target: "codegen",
                             "MISSING TABLE PASSED TO __tablestart \"{}\"",
@@ -191,16 +210,7 @@ pub fn statement_gen(
                             span: bf.span.clone(),
                             token: None,
                         })
-                    };
-
-                    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;
+                    }
                 }
                 BuiltinFunctionKind::FunctionSignature => {
                     if bf.args.len() != 1 {
diff --git a/huff_codegen/src/lib.rs b/huff_codegen/src/lib.rs
index e633fe8..425f567 100644
--- a/huff_codegen/src/lib.rs
+++ b/huff_codegen/src/lib.rs
@@ -68,7 +68,7 @@ impl Codegen {
         )?;
 
         // Generate the fully baked bytecode
-        Codegen::gen_table_bytecode(bytecode_res, contract)
+        Codegen::gen_table_bytecode(bytecode_res)
     }
 
     /// Generates constructor bytecode from a Contract AST
@@ -85,8 +85,7 @@ impl Codegen {
             &mut Vec::default(),
         )?;
 
-        // Generate the bytecode return string
-        Codegen::gen_table_bytecode(bytecode_res, contract)
+        Codegen::gen_table_bytecode(bytecode_res)
     }
 
     /// Helper function to find a macro or generate a CodegenError
@@ -108,10 +107,7 @@ impl Codegen {
 
     /// Appends table bytecode to the end of the BytecodeRes output.
     /// Fills table JUMPDEST placeholders.
-    pub(crate) fn gen_table_bytecode(
-        res: BytecodeRes,
-        contract: &Contract,
-    ) -> Result<String, CodegenError> {
+    pub(crate) fn gen_table_bytecode(res: BytecodeRes) -> Result<String, CodegenError> {
         if !res.unmatched_jumps.is_empty() {
             tracing::error!(
                 target: "codegen",
@@ -136,9 +132,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) = contract.tables.iter().try_for_each(|jt| {
+        if let Err(e) = res.utilized_tables.iter().try_for_each(|jt| {
             table_offsets.insert(jt.name.to_string(), table_offset);
-            let size = match bytes32_to_string(&jt.size, false).parse::<usize>() {
+            let size = match bytes32_to_string(&jt.size, false).as_str().parse::<usize>() {
                 Ok(s) => s,
                 Err(_) => return Err(CodegenError {
                     kind: CodegenErrorKind::UsizeConversion(format!("{:?}", jt.size)),
@@ -155,28 +151,49 @@ impl Codegen {
                 .statements
                 .iter()
                 .try_for_each(|s| {
-                    if let StatementType::LabelCall(label) = &s.ty {
-                        let offset = match res.label_indices.get(label) {
-                            Some(l) => l,
-                            None => {
-                                tracing::error!(
+                    match &s.ty {
+                        StatementType::LabelCall(label) => {
+                            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::UnmatchedJumpLabel,
+                                    kind: CodegenErrorKind::InvalidCodeLength(code.len()),
                                     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 },
-                        ));
+                            table_code = format!("{}{}", table_code, code);
+                        }
+                        _ => {
+                            return Err(CodegenError {
+                                kind: CodegenErrorKind::InvalidMacroStatement,
+                                span: jt.span.clone(),
+                                token: None
+                            })
+                        }
                     }
                     Ok(())
                 });
@@ -245,6 +262,7 @@ 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() {
@@ -271,6 +289,7 @@ impl Codegen {
                         &mut jump_table,
                         &mut label_indices,
                         &mut table_instances,
+                        &mut utilized_tables,
                         starting_offset,
                     )?;
                     bytes.append(&mut push_bytes);
@@ -303,7 +322,7 @@ impl Codegen {
         // Fill JUMPDEST placeholders
         let (bytes, unmatched_jumps) = Codegen::fill_unmatched(bytes, &jump_table, &label_indices)?;
 
-        Ok(BytecodeRes { bytes, label_indices, unmatched_jumps, table_instances })
+        Ok(BytecodeRes { bytes, label_indices, unmatched_jumps, table_instances, utilized_tables })
     }
 
     /// Helper associated function to fill unmatched jump dests.
diff --git a/huff_lexer/src/lib.rs b/huff_lexer/src/lib.rs
index 3c9216b..d4cbbd8 100644
--- a/huff_lexer/src/lib.rs
+++ b/huff_lexer/src/lib.rs
@@ -32,6 +32,8 @@ pub enum Context {
     AbiArgs,
     /// constant context
     Constant,
+    /// Code table context
+    CodeTableBody,
 }
 
 /// ## Lexer
@@ -420,6 +422,7 @@ impl<'a> Iterator for Lexer<'a> {
                             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,
                             _ => (),
                         }
                     }
@@ -575,7 +578,15 @@ 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"
-                    TokenKind::Literal(str_to_bytes32(self.slice().as_ref()))
+
+                    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::Assign,
                 '(' => {
@@ -603,7 +614,7 @@ impl<'a> Iterator for Lexer<'a> {
                     TokenKind::OpenBrace
                 }
                 '}' => {
-                    if self.context == Context::MacroBody {
+                    if matches!(self.context, Context::MacroBody | Context::CodeTableBody) {
                         self.context = Context::Global;
                     }
                     TokenKind::CloseBrace
diff --git a/huff_parser/Cargo.toml b/huff_parser/Cargo.toml
index 031d06b..8706b56 100644
--- a/huff_parser/Cargo.toml
+++ b/huff_parser/Cargo.toml
@@ -18,3 +18,4 @@ 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/src/lib.rs b/huff_parser/src/lib.rs
index 96e4325..f671113 100644
--- a/huff_parser/src/lib.rs
+++ b/huff_parser/src/lib.rs
@@ -11,6 +11,7 @@ use huff_utils::{
     token::{Token, TokenKind},
     types::*,
 };
+use regex::Regex;
 use std::path::Path;
 use tiny_keccak::{Hasher, Keccak};
 
@@ -776,6 +777,7 @@ 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();
@@ -786,7 +788,7 @@ impl Parser {
         let _ = self.match_kind(TokenKind::Assign);
 
         // Parse the core table
-        let table_statements: Vec<Statement> = self.parse_table_body()?;
+        let table_statements: Vec<Statement> = self.parse_table_body(is_code_table)?;
         let size = match kind {
             TableKind::JumpTablePacked => table_statements.len() * 0x02,
             TableKind::JumpTable => table_statements.len() * 0x20,
@@ -794,13 +796,13 @@ impl Parser {
                 table_statements
                     .iter()
                     .map(|s| {
-                        if let StatementType::LabelCall(l) = &s.ty {
-                            l.len()
+                        if let StatementType::Code(c) = &s.ty {
+                            c.len()
                         } else {
                             // TODO: Throw an error here.
                             tracing::error!(
                                 target: "parser",
-                                "Invalid table statement. Must be a label call. Got: {:?}",
+                                "Invalid table statement. Must be valid hex bytecode. Got: {:?}",
                                 s
                             );
                             0_usize
@@ -815,30 +817,49 @@ impl Parser {
             table_name,
             kind,
             table_statements,
-            str_to_bytes32(size.to_string().as_str()),
+            str_to_bytes32(format!("{:02x}", size).as_str()),
             AstSpan(self.spans.clone()),
         ))
     }
 
     /// Parse the body of a table.
     ///
-    /// Only `LabelCall`s should be authorized.
-    /// TODO: Code tables are not yet supported.
-    pub fn parse_table_body(&mut self) -> Result<Vec<Statement>, ParserError> {
+    /// Only `LabelCall` and `Code` Statements should be authorized.
+    pub fn parse_table_body(&mut self, is_code_table: bool) -> 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: StatementType::LabelCall(ident_str.to_string()),
+                        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())
+                        },
                         span: AstSpan(new_spans),
                     });
                     self.consume();
                 }
                 kind => {
-                    tracing::error!("Invalid Table Body Token: {:?}", self.current_token.kind);
+                    tracing::error!("Invalid Table Body 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 5a010ee..9c6209d 100644
--- a/huff_utils/src/ast.rs
+++ b/huff_utils/src/ast.rs
@@ -470,6 +470,12 @@ 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 {
@@ -482,14 +488,14 @@ impl MacroDefinition {
                 StatementType::Constant(name) => {
                     // Constant needs to be evaluated at the top-level
                     inner_irbytes.push(IRBytes {
-                        ty: IRByteType::Constant(name.to_string()),
+                        ty: IRByteType::Constant(name.to_owned()),
                         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_string()),
+                        ty: IRByteType::ArgCall(arg_name.to_owned()),
                         span: statement.span.clone(),
                     });
                 }
@@ -646,6 +652,8 @@ pub enum StatementType {
     Literal(Literal),
     /// An Opcode Statement
     Opcode(Opcode),
+    /// A Code Statement
+    Code(String),
     /// A Macro Invocation Statement
     MacroInvocation(MacroInvocation),
     /// A Constant Push
@@ -665,6 +673,7 @@ 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 1f8e82b..9612c93 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};
+use crate::prelude::{AstSpan, Statement, TableDefinition};
 use std::{
     collections::BTreeMap,
     fmt::{self, Display},
@@ -76,6 +76,8 @@ 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 ded95ef..f24de3c 100644
--- a/huff_utils/src/error.rs
+++ b/huff_utils/src/error.rs
@@ -157,6 +157,10 @@ pub enum CodegenErrorKind {
     UsizeConversion(String),
     /// Invalid Arguments
     InvalidArguments(String),
+    /// Invalid Table Statement
+    InvalidTableStatement(String),
+    /// Invalid Code Length
+    InvalidCodeLength(usize),
 }
 
 impl Spanned for CodegenError {
@@ -200,6 +204,12 @@ 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)
+            }
         }
     }
 }
@@ -489,6 +499,12 @@ 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| {


Test patch:
diff --git a/huff_core/tests/builtins.rs b/huff_core/tests/builtins.rs
index 8851dd7..9c5914c 100644
--- a/huff_core/tests/builtins.rs
+++ b/huff_core/tests/builtins.rs
@@ -58,6 +58,10 @@ 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
         }
@@ -66,8 +70,14 @@ 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
@@ -108,7 +118,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("60085b60006000f35b60006000f35b60006000f35b60006000f300020008000e001400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000014"));
+    assert_eq!(mbytes, String::from("6008608061002c60003960205b60006000f35b60006000f35b60006000f35b60006000f3000c00120018001e000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001eDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"));
 }
 
 #[test]
@@ -125,7 +135,7 @@ fn test_tablestart_builtin() {
             lab_3 // 3 00011
         }
 
-        #define macro BUILTIN_TEST() = takes(0) returns(1) {
+        #define macro BUILTIN_TEST() = takes(0) returns(2) {
             __tablestart(PACKED_JUMPTABLE)
             __tablestart(STANDARD_JUMPTABLE)
         }
@@ -235,7 +245,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("61012861004160003960003560e01c8063a9059cbb1461001a575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010000000000000000000000000000000000000000000000000000000000000029000000000000000000000000000000000000000000000000000000000000002f0000000000000000000000000000000000000000000000000000000000000035000000000000000000000000000000000000000000000000000000000000003b"));
+    assert_eq!(mbytes, String::from("608061004060003960003560e01c8063a9059cbb14610019575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003a"));
 }
 
 #[test]
@@ -362,7 +372,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("600861004960003961012861005160003960003560e01c8063a9059cbb14610022575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b602060200100310037003d004300000000000000000000000000000000000000000000000000000000000000310000000000000000000000000000000000000000000000000000000000000037000000000000000000000000000000000000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000043"));
+    assert_eq!(mbytes, String::from("6008610048600039608061005060003960003560e01c8063a9059cbb14610021575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b602060200100300036003c004200000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000042"));
 }
 
 #[test]
diff --git a/huff_parser/tests/table.rs b/huff_parser/tests/table.rs
index 5f04835..11008ae 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, "96"), (TokenKind::JumpTablePacked, "06")];
+    let table_kinds = [(TokenKind::JumpTable, "60"), (TokenKind::JumpTablePacked, "06")];
 
     for (kind, expected_size) in table_kinds {
         let source = &format!(