Explorar o código

chore: fix clippy lints, apply cargo fmt, add licenses

Sonic hai 1 mes
pai
achega
ad486f2706

+ 1 - 1
CONTRIBUTING.md

@@ -1,5 +1,5 @@
 # Contributing to SBPF
-sBPF is the first fully independant Solana BPF assembler. It enables users to quickly get started developing sBPF Assembly projects, skipping the heavy build requirements of solana-rust and solana-llvm and translating assembly code directly into SVM-compatible bytecode, handling just the assembler-linker pipeline without the heavy burden of code generation from higher level languages. We aim to provide comprehensive tooling and support for sBPF assembly proejcts, as well as to improve upon it with additional features to make it composable and user-friendly. Any [Pull Request](https://github.com/blueshift-gg/sbpf/pulls) or [Issue](https://github.com/blueshift-gg/sbpf/issues) that does not align with our roadmap will be closed as unplanned.
+sBPF is the first fully independent Solana BPF assembler. It enables users to quickly get started developing sBPF Assembly projects, skipping the heavy build requirements of solana-rust and solana-llvm and translating assembly code directly into SVM-compatible bytecode, handling just the assembler-linker pipeline without the heavy burden of code generation from higher level languages. We aim to provide comprehensive tooling and support for sBPF assembly projects, as well as to improve upon it with additional features to make it composable and user-friendly. Any [Pull Request](https://github.com/blueshift-gg/sbpf/pulls) or [Issue](https://github.com/blueshift-gg/sbpf/issues) that does not align with our roadmap will be closed as unplanned.
 
 ## Vibe Coding
 We are humans who write our own tooling because machines have inferior reasoning capabilities and make stupid decisions resulting in inefficient bytecode. We encourage the use of LLMs to help you understand issues, catch bugs and author high quality PRs, however we do not accept PRs that are purely or excessively AI-generated. Trust me when I say that if an LLM could have done it, we wouldn't have wasted our precious time waiting for a community PR. 

+ 176 - 0
LICENSE-APACHE

@@ -0,0 +1,176 @@
+         Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS

+ 21 - 0
LICENSE-MIT

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024-present Dean Little <dean@blueshift.gg> and Claire Fan <claire@blueshift.gg>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 20 - 8
README.md

@@ -1,13 +1,16 @@
 ## Table of Contents
 
--   [sbpf](#sbpf)
--   [Dependencies](#dependencies)
--   [Installation](#installation)
--   [Usage](#usage)
--   [Command Details](#command-details)
--   [Examples](#examples)
--   [Advanced Usage](#advanced-usage)
--   [Contributing](#contributing)
+- [sbpf](#sbpf)
+    - [Installation](#installation)
+    - [Usage](#usage)
+    - [Command Details](#command-details)
+      - [Initialize a Project](#initialize-a-project)
+        - [Examples](#examples)
+          - [Create a new project with Rust tests (default)](#create-a-new-project-with-rust-tests-default)
+          - [Create a new project with TypeScript tests](#create-a-new-project-with-typescript-tests)
+    - [Advanced Usage](#advanced-usage)
+    - [License](#license)
+    - [Contributing](#contributing)
 
 # sbpf
 
@@ -94,6 +97,15 @@ src/example/example.s
 src/example/example.ld
 ```
 
+### License
+
+Licensed under either of
+
+ * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+ * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
+
+at your option.
+
 ### Contributing
 
 PRs welcome!

+ 1 - 0
crates/assembler/Cargo.toml

@@ -18,6 +18,7 @@ num-traits = { workspace = true }
 thiserror = { workspace = true }
 anyhow = { workspace = true }
 object = { workspace = true }
+sbpf-common = { workspace = true }
 phf = "0.13.1"
 phf_macros = "0.13.1"
 

+ 106 - 73
crates/assembler/src/ast.rs

@@ -1,14 +1,15 @@
+use crate::CompileError;
 use crate::astnode::{ASTNode, ROData};
+use crate::dynsym::{DynamicSymbolMap, RelDynMap, RelocationType};
 use crate::instruction::Instruction;
-use crate::dynsym::{RelDynMap, DynamicSymbolMap, RelocationType};
 use crate::lexer::{ImmediateValue, Token};
-use crate::opcode::Opcode;
 use crate::parser::ParseResult;
-use crate::section::{DataSection, CodeSection};
-use crate::CompileError;
+use crate::section::{CodeSection, DataSection};
+use sbpf_common::opcode::Opcode;
 
 use std::collections::HashMap;
 
+#[derive(Default)]
 pub struct AST {
     pub nodes: Vec<ASTNode>,
     pub rodata_nodes: Vec<ASTNode>,
@@ -20,57 +21,70 @@ pub struct AST {
 
 impl AST {
     pub fn new() -> Self {
-        Self { nodes: Vec::new(), rodata_nodes: Vec::new(), entry_label: None, text_size: 0, rodata_size: 0 }
+        Self::default()
     }
+
     //
     pub fn set_text_size(&mut self, text_size: u64) {
         self.text_size = text_size;
     }
+
     //
     pub fn set_rodata_size(&mut self, rodata_size: u64) {
         self.rodata_size = rodata_size;
     }
+
     //
     pub fn get_instruction_at_offset(&mut self, offset: u64) -> Option<&mut Instruction> {
-        self.nodes.iter_mut().find(|node| match node {
-            ASTNode::Instruction { instruction: _, offset: inst_offset, .. } => offset == *inst_offset,
-            _ => false,
-        }).map(|node| match node {
-            ASTNode::Instruction { instruction, .. } => instruction,
-            _ => panic!("Expected Instruction node"),
-        })
+        self.nodes
+            .iter_mut()
+            .find(|node| match node {
+                ASTNode::Instruction {
+                    instruction: _,
+                    offset: inst_offset,
+                    ..
+                } => offset == *inst_offset,
+                _ => false,
+            })
+            .map(|node| match node {
+                ASTNode::Instruction { instruction, .. } => instruction,
+                _ => panic!("Expected Instruction node"),
+            })
     }
+
     //
     pub fn get_rodata_at_offset(&self, offset: u64) -> Option<&ROData> {
-        self.rodata_nodes.iter().find(|node| match node {
-            ASTNode::ROData { rodata: _, offset: rodata_offset, .. } => offset == *rodata_offset,
-            _ => false,
-        }).map(|node| match node {
-            ASTNode::ROData { rodata, .. } => rodata,
-            _ => panic!("Expected ROData node"),
-        })
+        self.rodata_nodes
+            .iter()
+            .find(|node| match node {
+                ASTNode::ROData {
+                    rodata: _,
+                    offset: rodata_offset,
+                    ..
+                } => offset == *rodata_offset,
+                _ => false,
+            })
+            .map(|node| match node {
+                ASTNode::ROData { rodata, .. } => rodata,
+                _ => panic!("Expected ROData node"),
+            })
     }
+
     //
     pub fn build_program(&mut self) -> Result<ParseResult, Vec<CompileError>> {
-        let mut label_offset_map : HashMap<String, u64> = HashMap::new();
+        let mut label_offset_map: HashMap<String, u64> = HashMap::new();
 
         // iterate through text labels and rodata labels and find the pair
         // of each label and offset
         for node in &self.nodes {
-            match node {
-                ASTNode::Label { label, offset } => {
-                    label_offset_map.insert(label.name.clone(), *offset);
-                }
-                _ => {}
+            if let ASTNode::Label { label, offset } = node {
+                label_offset_map.insert(label.name.clone(), *offset);
             }
         }
 
         for node in &self.rodata_nodes {
-            match node {
-                ASTNode::ROData { rodata, offset } => {
-                    label_offset_map.insert(rodata.name.clone(), *offset + self.text_size);
-                }
-                _ => {}
+            if let ASTNode::ROData { rodata, offset } = node {
+                label_offset_map.insert(rodata.name.clone(), *offset + self.text_size);
             }
         }
 
@@ -84,52 +98,68 @@ impl AST {
         let mut errors = Vec::new();
 
         for node in &mut self.nodes {
-            match node {
-                ASTNode::Instruction { instruction: inst, offset, .. } => {
-                    // For jump/call instructions, replace label with relative offsets
-                    if inst.is_jump() || inst.opcode == Opcode::Call {
-                        if let Some(Token::Identifier(label, span)) = inst.operands.last() {
-                            let label = label.clone();
-                            if let Some(target_offset) = label_offset_map.get(&label) {
-                                let rel_offset = (*target_offset as i64 - *offset as i64) / 8 - 1;
-                                let last_idx = inst.operands.len() - 1;
-                                inst.operands[last_idx] = Token::ImmediateValue(ImmediateValue::Int(rel_offset), span.clone());
-                            } else if inst.is_jump() {
-                                // only error out unresolved jump labels, since call 
-                                // labels could exist externally
-                                errors.push(CompileError::UndefinedLabel { label: label.clone(), span: span.clone(), custom_label: None });
-                            }
+            if let ASTNode::Instruction {
+                instruction: inst,
+                offset,
+                ..
+            } = node
+            {
+                // For jump/call instructions, replace label with relative offsets
+                if inst.is_jump() || inst.opcode == Opcode::Call {
+                    if let Some(Token::Identifier(label, span)) = inst.operands.last() {
+                        let label = label.clone();
+                        if let Some(target_offset) = label_offset_map.get(&label) {
+                            let rel_offset = (*target_offset as i64 - *offset as i64) / 8 - 1;
+                            let last_idx = inst.operands.len() - 1;
+                            inst.operands[last_idx] = Token::ImmediateValue(
+                                ImmediateValue::Int(rel_offset),
+                                span.clone(),
+                            );
+                        } else if inst.is_jump() {
+                            // only error out unresolved jump labels, since call
+                            // labels could exist externally
+                            errors.push(CompileError::UndefinedLabel {
+                                label: label.clone(),
+                                span: span.clone(),
+                                custom_label: None,
+                            });
                         }
                     }
-                    // This has to be done before resolving lddw labels since lddw 
-                    // operand needs to be absolute offset values
-                    if inst.needs_relocation() {
-                        program_is_static = false;
-                        let (reloc_type, label) = inst.get_relocation_info();
-                        relocations.add_rel_dyn(*offset, reloc_type, label.clone());
-                        if reloc_type == RelocationType::RSbfSyscall {
-                            dynamic_symbols.add_call_target(label.clone(), *offset);
-                        }
+                }
+                // This has to be done before resolving lddw labels since lddw
+                // operand needs to be absolute offset values
+                if inst.needs_relocation() {
+                    program_is_static = false;
+                    let (reloc_type, label) = inst.get_relocation_info();
+                    relocations.add_rel_dyn(*offset, reloc_type, label.clone());
+                    if reloc_type == RelocationType::RSbfSyscall {
+                        dynamic_symbols.add_call_target(label.clone(), *offset);
                     }
-                    if inst.opcode == Opcode::Lddw {
-                        if let Some(Token::Identifier(name, span)) = inst.operands.last() {
-                            let label = name.clone();
-                            if let Some(target_offset) = label_offset_map.get(&label) {
-                                // actually lddw with label makes a program dynamic, so
-                                // we should be able to hard code ph_offset
-                                let ph_count = if program_is_static { 1 } else { 3 };
-                                let ph_offset = 64 + (ph_count as u64 * 56) as i64;
-                                let abs_offset = *target_offset as i64 + ph_offset;
-                                // Replace label with immediate value
-                                let last_idx = inst.operands.len() - 1;
-                                inst.operands[last_idx] = Token::ImmediateValue(ImmediateValue::Addr(abs_offset), span.clone());
-                            }  else {
-                                errors.push(CompileError::UndefinedLabel { label: name.clone(), span: span.clone(), custom_label: None });
-                            }
+                }
+                if inst.opcode == Opcode::Lddw {
+                    if let Some(Token::Identifier(name, span)) = inst.operands.last() {
+                        let label = name.clone();
+                        if let Some(target_offset) = label_offset_map.get(&label) {
+                            // actually lddw with label makes a program dynamic, so
+                            // we should be able to hard code ph_offset
+                            let ph_count = if program_is_static { 1 } else { 3 };
+                            let ph_offset = 64 + (ph_count as u64 * 56) as i64;
+                            let abs_offset = *target_offset as i64 + ph_offset;
+                            // Replace label with immediate value
+                            let last_idx = inst.operands.len() - 1;
+                            inst.operands[last_idx] = Token::ImmediateValue(
+                                ImmediateValue::Addr(abs_offset),
+                                span.clone(),
+                            );
+                        } else {
+                            errors.push(CompileError::UndefinedLabel {
+                                label: name.clone(),
+                                span: span.clone(),
+                                custom_label: None,
+                            });
                         }
                     }
                 }
-                _ => {}
             }
         }
 
@@ -141,12 +171,15 @@ impl AST {
         }
 
         if !errors.is_empty() {
-            return Err(errors);
+            Err(errors)
         } else {
             Ok(ParseResult {
                 code_section: CodeSection::new(std::mem::take(&mut self.nodes), self.text_size),
-                data_section: DataSection::new(std::mem::take(&mut self.rodata_nodes), self.rodata_size),
-                dynamic_symbols: dynamic_symbols,
+                data_section: DataSection::new(
+                    std::mem::take(&mut self.rodata_nodes),
+                    self.rodata_size,
+                ),
+                dynamic_symbols,
                 relocation_data: relocations,
                 prog_is_static: program_is_static,
             })

+ 140 - 93
crates/assembler/src/astnode.rs

@@ -1,10 +1,10 @@
-use crate::opcode::Opcode;
-use crate::instruction::Instruction;
-use crate::lexer::{Token, ImmediateValue};
 use crate::debuginfo::{DebugInfo, RegisterHint, RegisterType};
+use crate::errors::CompileError;
+use crate::instruction::Instruction;
+use crate::lexer::{ImmediateValue, Token};
+use sbpf_common::opcode::Opcode;
 use std::collections::HashMap;
 use std::ops::Range;
-use crate::errors::CompileError;
 
 #[derive(Debug, Clone)]
 pub enum ASTNode {
@@ -37,7 +37,6 @@ pub enum ASTNode {
         instruction: Instruction,
         offset: u64,
     },
-
 }
 
 #[derive(Debug, Clone)]
@@ -113,12 +112,18 @@ impl ROData {
         match value {
             ImmediateValue::Int(val) => {
                 if *val < min || *val > max {
-                    return Err(CompileError::OutOfRangeLiteral { span, custom_label: None });
+                    return Err(CompileError::OutOfRangeLiteral {
+                        span,
+                        custom_label: None,
+                    });
                 }
             }
             ImmediateValue::Addr(val) => {
                 if *val < min || *val > max {
-                    return Err(CompileError::OutOfRangeLiteral { span, custom_label: None });
+                    return Err(CompileError::OutOfRangeLiteral {
+                        span,
+                        custom_label: None,
+                    });
                 }
             }
         }
@@ -127,17 +132,14 @@ impl ROData {
 
     pub fn get_size(&self) -> u64 {
         let size: u64;
-        match (
-            &self.args[0],
-            &self.args[1],
-        ) {
+        match (&self.args[0], &self.args[1]) {
             (Token::Directive(_, _), Token::StringLiteral(s, _)) => {
                 size = s.len() as u64;
             }
             (Token::Directive(directive, _), Token::VectorLiteral(values, _)) => {
                 match directive.as_str() {
                     "byte" => {
-                        size = values.len() as u64 * 1;
+                        size = values.len() as u64;
                     }
                     "short" => {
                         size = values.len() as u64 * 2;
@@ -156,44 +158,71 @@ impl ROData {
         size
     }
     pub fn verify(&self) -> Result<(), CompileError> {
-        match (
-            &self.args[0],
-            &self.args[1],
-        ) {
+        match (&self.args[0], &self.args[1]) {
             (Token::Directive(directive, directive_span), Token::StringLiteral(_, _)) => {
                 if directive.as_str() != "ascii" {
-                    return Err(CompileError::InvalidRODataDirective { span: directive_span.clone(), custom_label: None });
+                    return Err(CompileError::InvalidRODataDirective {
+                        span: directive_span.clone(),
+                        custom_label: None,
+                    });
                 }
             }
-            (Token::Directive(directive, directive_span), Token::VectorLiteral(values, vector_literal_span)) => {
-                match directive.as_str() {
-                    "byte" => {
-                        for value in values {
-                            Self::validate_immediate_range(value, i8::MIN as i64, i8::MAX as i64, vector_literal_span.clone())?;
-                        }
+            (
+                Token::Directive(directive, directive_span),
+                Token::VectorLiteral(values, vector_literal_span),
+            ) => match directive.as_str() {
+                "byte" => {
+                    for value in values {
+                        Self::validate_immediate_range(
+                            value,
+                            i8::MIN as i64,
+                            i8::MAX as i64,
+                            vector_literal_span.clone(),
+                        )?;
                     }
-                    "short" => {
-                        for value in values {
-                            Self::validate_immediate_range(value, i16::MIN as i64, i16::MAX as i64, vector_literal_span.clone())?;
-                        }
+                }
+                "short" => {
+                    for value in values {
+                        Self::validate_immediate_range(
+                            value,
+                            i16::MIN as i64,
+                            i16::MAX as i64,
+                            vector_literal_span.clone(),
+                        )?;
                     }
-                    "int" | "long" => {
-                        for value in values {
-                            Self::validate_immediate_range(value, i32::MIN as i64, i32::MAX as i64, vector_literal_span.clone())?;
-                        }
+                }
+                "int" | "long" => {
+                    for value in values {
+                        Self::validate_immediate_range(
+                            value,
+                            i32::MIN as i64,
+                            i32::MAX as i64,
+                            vector_literal_span.clone(),
+                        )?;
                     }
-                    "quad" => {
-                        for value in values {
-                            Self::validate_immediate_range(value, i64::MIN as i64, i64::MAX as i64, vector_literal_span.clone())?;
-                        }
+                }
+                "quad" => {
+                    for value in values {
+                        Self::validate_immediate_range(
+                            value,
+                            i64::MIN,
+                            i64::MAX,
+                            vector_literal_span.clone(),
+                        )?;
                     }
+                }
                 _ => {
-                        return Err(CompileError::InvalidRODataDirective { span: directive_span.clone(), custom_label: None });
-                    }
+                    return Err(CompileError::InvalidRODataDirective {
+                        span: directive_span.clone(),
+                        custom_label: None,
+                    });
                 }
-            }
+            },
             _ => {
-                return Err(CompileError::InvalidRodataDecl { span: self.span.clone(), custom_label: None });
+                return Err(CompileError::InvalidRodataDecl {
+                    span: self.span.clone(),
+                    custom_label: None,
+                });
             }
         }
         Ok(())
@@ -203,12 +232,20 @@ impl ROData {
 impl ASTNode {
     pub fn bytecode_with_debug_map(&self) -> Option<(Vec<u8>, HashMap<u64, DebugInfo>)> {
         match self {
-            ASTNode::Instruction { instruction: Instruction { opcode, operands, span }, offset } => {
+            ASTNode::Instruction {
+                instruction:
+                    Instruction {
+                        opcode,
+                        operands,
+                        span,
+                    },
+                offset,
+            } => {
                 let mut bytes = Vec::new();
                 let mut debug_map = HashMap::new();
                 let mut debug_info = DebugInfo::new(span.clone());
-                bytes.push(opcode.to_bytecode());  // 1 byte opcode
-                
+                bytes.push(opcode.to_bytecode()); // 1 byte opcode
+
                 if *opcode == Opcode::Call {
                     bytes.extend_from_slice(&[0x10, 0x00, 0x00]);
                     if let Some(Token::ImmediateValue(imm, _)) = operands.last() {
@@ -220,33 +257,31 @@ impl ASTNode {
                     } else {
                         // external calls
                         bytes.extend_from_slice(&[0xFF, 0xFF, 0xFF, 0xFF]);
-                    } 
+                    }
                 } else if *opcode == Opcode::Lddw {
-                    match &operands[..] {
-                        [Token::Register(reg, _), Token::ImmediateValue(imm, _)] => {
-                            // 1 byte register number (strip 'r' prefix)
-                            bytes.push(*reg);
-                            
-                            // 2 bytes of zeros (offset/reserved)
-                            bytes.extend_from_slice(&[0, 0]);
+                    if let [Token::Register(reg, _), Token::ImmediateValue(imm, _)] = &operands[..]
+                    {
+                        // 1 byte register number (strip 'r' prefix)
+                        bytes.push(*reg);
 
-                            // 8 bytes immediate value in little-endian
-                            let imm64 = match imm {
-                                ImmediateValue::Int(val) => *val as i64,
-                                ImmediateValue::Addr(val) => *val as i64,
-                            };
-                            bytes.extend_from_slice(&imm64.to_le_bytes()[..4]);
-                            bytes.extend_from_slice(&[0, 0, 0, 0]);
-                            bytes.extend_from_slice(&imm64.to_le_bytes()[4..8]);
-                        }
-                        _ => {}
+                        // 2 bytes of zeros (offset/reserved)
+                        bytes.extend_from_slice(&[0, 0]);
+
+                        // 8 bytes immediate value in little-endian
+                        let imm64 = match imm {
+                            ImmediateValue::Int(val) => *val,
+                            ImmediateValue::Addr(val) => *val,
+                        };
+                        bytes.extend_from_slice(&imm64.to_le_bytes()[..4]);
+                        bytes.extend_from_slice(&[0, 0, 0, 0]);
+                        bytes.extend_from_slice(&imm64.to_le_bytes()[4..8]);
                     }
                 } else {
                     match &operands[..] {
                         [Token::ImmediateValue(imm, _)] => {
                             // 1 byte of zeros (no register)
                             bytes.push(0);
-                            
+
                             if *opcode == Opcode::Ja {
                                 // 2 bytes immediate value in little-endian for 'ja'
                                 let imm16 = match imm {
@@ -262,7 +297,7 @@ impl ASTNode {
                                 };
                                 bytes.extend_from_slice(&imm32.to_le_bytes());
                             }
-                        },
+                        }
 
                         [Token::Register(reg, _)] => {
                             if *opcode == Opcode::Callx {
@@ -273,80 +308,92 @@ impl ASTNode {
                                 bytes.push(*reg);
                                 bytes.extend_from_slice(&[0, 0, 0, 0, 0, 0]);
                             }
-                        },
+                        }
 
                         [Token::Register(reg, _), Token::ImmediateValue(imm, _)] => {
                             // 1 byte register number (strip 'r' prefix)
                             bytes.push(*reg);
-                            
+
                             // 2 bytes of zeros (offset/reserved)
                             bytes.extend_from_slice(&[0, 0]);
-                            
+
                             // 4 bytes immediate value in little-endian
                             let imm32 = match imm {
                                 ImmediateValue::Int(val) => *val as i32,
                                 ImmediateValue::Addr(val) => {
                                     debug_info.register_hint = RegisterHint {
                                         register: *reg as usize,
-                                        register_type: RegisterType::Addr
+                                        register_type: RegisterType::Addr,
                                     };
                                     *val as i32
                                 }
                             };
                             bytes.extend_from_slice(&imm32.to_le_bytes());
-                        },
+                        }
 
-                        [Token::Register(reg, _), Token::ImmediateValue(imm, _), Token::ImmediateValue(offset, _)] => {
+                        [
+                            Token::Register(reg, _),
+                            Token::ImmediateValue(imm, _),
+                            Token::ImmediateValue(offset, _),
+                        ] => {
                             // 1 byte register number (strip 'r' prefix)
                             bytes.push(*reg);
-                            
+
                             // 2 bytes of offset in little-endian
                             let offset16 = match offset {
                                 ImmediateValue::Int(val) => *val as u16,
                                 ImmediateValue::Addr(val) => *val as u16,
                             };
                             bytes.extend_from_slice(&offset16.to_le_bytes());
-                            
+
                             // 4 bytes immediate value in little-endianß
                             let imm32 = match imm {
                                 ImmediateValue::Int(val) => *val as i32,
                                 ImmediateValue::Addr(val) => {
                                     debug_info.register_hint = RegisterHint {
                                         register: *reg as usize,
-                                        register_type: RegisterType::Addr
+                                        register_type: RegisterType::Addr,
                                     };
                                     *val as i32
                                 }
                             };
                             bytes.extend_from_slice(&imm32.to_le_bytes());
-                        },                    
-                        
+                        }
+
                         [Token::Register(dst, _), Token::Register(src, _)] => {
                             // Convert register strings to numbers
                             let dst_num = dst;
                             let src_num = src;
-                            
+
                             // Combine src and dst into a single byte (src in high nibble, dst in low nibble)
                             let reg_byte = (src_num << 4) | dst_num;
                             bytes.push(reg_byte);
-                        },
-                        [Token::Register(dst, _), Token::Register(reg, _), Token::ImmediateValue(offset, _)] => {
+                        }
+                        [
+                            Token::Register(dst, _),
+                            Token::Register(reg, _),
+                            Token::ImmediateValue(offset, _),
+                        ] => {
                             // Combine base register and destination register into a single byte
                             let reg_byte = (reg << 4) | dst;
                             bytes.push(reg_byte);
-                            
+
                             // Add the offset as a 16-bit value in little-endian
                             let offset16 = match offset {
                                 ImmediateValue::Int(val) => *val as u16,
                                 ImmediateValue::Addr(val) => *val as u16,
                             };
                             bytes.extend_from_slice(&offset16.to_le_bytes());
-                        },
-                        [Token::Register(reg, _), Token::ImmediateValue(offset, _), Token::Register(dst, _)] => {
+                        }
+                        [
+                            Token::Register(reg, _),
+                            Token::ImmediateValue(offset, _),
+                            Token::Register(dst, _),
+                        ] => {
                             // Combine base register and destination register into a single byte
                             let reg_byte = (dst << 4) | reg;
                             bytes.push(reg_byte);
-                            
+
                             // Add the offset as a 16-bit value in little-endian
                             let offset16 = match offset {
                                 ImmediateValue::Int(val) => *val as u16,
@@ -354,7 +401,7 @@ impl ASTNode {
                             };
                             bytes.extend_from_slice(&offset16.to_le_bytes());
                         }
-                        
+
                         _ => {}
                     }
                 }
@@ -366,20 +413,20 @@ impl ASTNode {
                 }
 
                 debug_map.insert(*offset, debug_info);
-                
+
                 Some((bytes, debug_map))
-            },
-            ASTNode::ROData { rodata: ROData { name: _, args, .. }, .. } => {
+            }
+            ASTNode::ROData {
+                rodata: ROData { name: _, args, .. },
+                ..
+            } => {
                 let mut bytes = Vec::new();
                 let debug_map = HashMap::<u64, DebugInfo>::new();
-                match (
-                    &args[0],
-                    &args[1],
-                ) {
+                match (&args[0], &args[1]) {
                     (Token::Directive(_, _), Token::StringLiteral(str_literal, _)) => {
                         let str_bytes = str_literal.as_bytes().to_vec();
                         bytes.extend(str_bytes);
-                    } 
+                    }
                     (Token::Directive(directive, _), Token::VectorLiteral(values, _)) => {
                         if directive == "byte" {
                             for value in values {
@@ -408,8 +455,8 @@ impl ASTNode {
                         } else if directive == "quad" {
                             for value in values {
                                 let imm64 = match value {
-                                    ImmediateValue::Int(val) => *val as i64,
-                                    ImmediateValue::Addr(val) => *val as i64,
+                                    ImmediateValue::Int(val) => *val,
+                                    ImmediateValue::Addr(val) => *val,
                                 };
                                 bytes.extend(imm64.to_le_bytes());
                             }
@@ -421,8 +468,8 @@ impl ASTNode {
                     _ => panic!("Invalid ROData declaration"),
                 }
                 Some((bytes, debug_map))
-            },
-            _ => None
+            }
+            _ => None,
         }
     }
 

+ 4 - 3
crates/assembler/src/debuginfo.rs

@@ -40,8 +40,9 @@ pub struct DebugInfo {
 
 impl DebugInfo {
     pub fn new(code_span: Range<usize>) -> Self {
-        Self { code_span, register_hint: RegisterHint::default() }
+        Self {
+            code_span,
+            register_hint: RegisterHint::default(),
+        }
     }
 }
-
-

+ 47 - 29
crates/assembler/src/dynsym.rs

@@ -2,17 +2,24 @@ use std::collections::BTreeMap;
 
 #[derive(Debug)]
 pub struct DynamicSymbol {
-    name: u32,      // index into .dynstr section
-    info: u8,       // symbol binding and type
-    other: u8,      // symbol visibility
-    shndx: u16,     // section index
-    value: u64,     // symbol value
-    size: u64,      // symbol size
+    name: u32,  // index into .dynstr section
+    info: u8,   // symbol binding and type
+    other: u8,  // symbol visibility
+    shndx: u16, // section index
+    value: u64, // symbol value
+    size: u64,  // symbol size
 }
 
 impl DynamicSymbol {
     pub fn new(name: u32, info: u8, other: u8, shndx: u16, value: u64, size: u64) -> Self {
-        Self { name, info, other, shndx, value, size }
+        Self {
+            name,
+            info,
+            other,
+            shndx,
+            value,
+            size,
+        }
     }
 
     pub fn bytecode(&self) -> Vec<u8> {
@@ -37,31 +44,24 @@ pub enum SymbolKind {
     CallTarget,
 }
 
-
-
-#[derive(Debug)]
+#[derive(Debug, Default)]
 pub struct DynamicSymbolMap {
     symbols: BTreeMap<String, Vec<(SymbolKind, u64)>>,
 }
 
 impl DynamicSymbolMap {
     pub fn new() -> Self {
-        Self {
-            symbols: BTreeMap::new(),
-        }
+        Self::default()
     }
 
     pub fn copy(&self) -> Self {
         Self {
-            symbols: self.symbols.clone()
+            symbols: self.symbols.clone(),
         }
     }
 
     pub fn add_symbol(&mut self, name: String, kind: SymbolKind, offset: u64) {
-        self.symbols
-            .entry(name)
-            .or_default()
-            .push((kind, offset));
+        self.symbols.entry(name).or_default().push((kind, offset));
     }
 
     pub fn add_entry_point(&mut self, name: String, offset: u64) {
@@ -81,9 +81,15 @@ impl DynamicSymbolMap {
     }
 
     fn get_symbols_by_kind(&self, kind: SymbolKind) -> Vec<(String, u64)> {
-        self.symbols.iter()
+        self.symbols
+            .iter()
             .filter(|(_, symbols)| symbols.iter().any(|(k, _)| *k == kind))
-            .map(|(name, symbols)| (name.clone(), symbols.iter().find(|(k, _)| *k == kind).unwrap().1))
+            .map(|(name, symbols)| {
+                (
+                    name.clone(),
+                    symbols.iter().find(|(k, _)| *k == kind).unwrap().1,
+                )
+            })
             .collect()
     }
 
@@ -108,11 +114,15 @@ pub struct RelDyn {
     offset: u64,
     rel_type: u64,
     dynstr_offset: u64,
-}  
+}
 
 impl RelDyn {
     pub fn new(offset: u64, rel_type: u64, dynstr_offset: u64) -> Self {
-        Self { offset, rel_type, dynstr_offset }
+        Self {
+            offset,
+            rel_type,
+            dynstr_offset,
+        }
     }
 
     pub fn bytecode(&self) -> Vec<u8> {
@@ -133,29 +143,37 @@ impl RelDyn {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Default)]
 pub struct RelDynMap {
     rel_dyns: BTreeMap<u64, Vec<(RelocationType, String)>>,
 }
 
 impl RelDynMap {
     pub fn new() -> Self {
-        Self { rel_dyns: BTreeMap::new() }
+        Self::default()
     }
 
     pub fn add_rel_dyn(&mut self, offset: u64, rel_type: RelocationType, name: String) {
-        self.rel_dyns.entry(offset).or_default().push((rel_type, name));
+        self.rel_dyns
+            .entry(offset)
+            .or_default()
+            .push((rel_type, name));
     }
 
     pub fn get_rel_dyns(&self) -> Vec<(u64, RelocationType, String)> {
-        self.rel_dyns.iter()
+        self.rel_dyns
+            .iter()
             .flat_map(|(offset, rel_types)| {
-                rel_types.iter().map(move |(rel_type, name)| (*offset, *rel_type, name.clone()))
+                rel_types
+                    .iter()
+                    .map(move |(rel_type, name)| (*offset, *rel_type, name.clone()))
             })
             .collect()
     }
 
     pub fn copy(&self) -> Self {
-        Self { rel_dyns: self.rel_dyns.clone() }
+        Self {
+            rel_dyns: self.rel_dyns.clone(),
+        }
     }
-}
+}

+ 1 - 1
crates/assembler/src/errors.rs

@@ -87,4 +87,4 @@ define_compile_errors! {
         label = "Label redefined",
         fields = { label: String, span: Range<usize>, original_span: Range<usize> }
     },
-}
+}

+ 54 - 45
crates/assembler/src/header.rs

@@ -1,51 +1,35 @@
 #[derive(Debug)]
 pub struct ElfHeader {
-    pub e_ident: [u8; 16],      // ELF identification bytes = [127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
-    pub e_type: u16,            // Object file type = 3 (ET_DYN)
-    pub e_machine: u16,         // Machine architecture = 247 (BPF)
-    pub e_version: u32,         // Object file version = 1
-    pub e_entry: u64,           // Entry point address
-    pub e_phoff: u64,           // Program header offset
-    pub e_shoff: u64,           // Section header offset
-    pub e_flags: u32,           // Processor-specific flags
-    pub e_ehsize: u16,          // ELF header size = 64
-    pub e_phentsize: u16,       // Size of program header entry = 56
-    pub e_phnum: u16,           // Number of program header entries
-    pub e_shentsize: u16,       // Size of section header entry = 64
-    pub e_shnum: u16,           // Number of section header entries
-    pub e_shstrndx: u16,        // Section name string table index
+    pub e_ident: [u8; 16], // ELF identification bytes = [127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
+    pub e_type: u16,       // Object file type = 3 (ET_DYN)
+    pub e_machine: u16,    // Machine architecture = 247 (BPF)
+    pub e_version: u32,    // Object file version = 1
+    pub e_entry: u64,      // Entry point address
+    pub e_phoff: u64,      // Program header offset
+    pub e_shoff: u64,      // Section header offset
+    pub e_flags: u32,      // Processor-specific flags
+    pub e_ehsize: u16,     // ELF header size = 64
+    pub e_phentsize: u16,  // Size of program header entry = 56
+    pub e_phnum: u16,      // Number of program header entries
+    pub e_shentsize: u16,  // Size of section header entry = 64
+    pub e_shnum: u16,      // Number of section header entries
+    pub e_shstrndx: u16,   // Section name string table index
 }
 
 #[derive(Debug)]
 pub struct ProgramHeader {
-    pub p_type: u32,      // Type of segment
-    pub p_flags: u32,     // Segment attributes
-    pub p_offset: u64,    // Offset in file
-    pub p_vaddr: u64,     // Virtual address in memory
-    pub p_paddr: u64,     // Physical address (reserved)
-    pub p_filesz: u64,    // Size of segment in file
-    pub p_memsz: u64,     // Size of segment in memory
-    pub p_align: u64,     // Alignment of segment
+    pub p_type: u32,   // Type of segment
+    pub p_flags: u32,  // Segment attributes
+    pub p_offset: u64, // Offset in file
+    pub p_vaddr: u64,  // Virtual address in memory
+    pub p_paddr: u64,  // Physical address (reserved)
+    pub p_filesz: u64, // Size of segment in file
+    pub p_memsz: u64,  // Size of segment in memory
+    pub p_align: u64,  // Alignment of segment
 }
 
-impl ElfHeader {
-    const SOLANA_IDENT: [u8; 16] = [
-        0x7f, 0x45, 0x4c, 0x46,  // EI_MAG0..EI_MAG3 ("\x7FELF")
-        0x02,                     // EI_CLASS (64-bit)
-        0x01,                     // EI_DATA (little endian)
-        0x01,                     // EI_VERSION
-        0x00,                     // EI_OSABI
-        0x00,                     // EI_ABIVERSION
-        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  // EI_PAD
-    ];
-    const SOLANA_TYPE: u16 = 3;      // ET_DYN
-    const SOLANA_MACHINE: u16 = 247;  // BPF
-    const SOLANA_VERSION: u32 = 1;    // EV_CURRENT
-    const ELF64_HEADER_SIZE: u16 = 64;
-    const PROGRAM_HEADER_SIZE: u16 = 56;
-    const SECTION_HEADER_SIZE: u16 = 64;
-
-    pub fn new() -> Self {
+impl Default for ElfHeader {
+    fn default() -> Self {
         Self {
             e_ident: Self::SOLANA_IDENT,
             e_type: Self::SOLANA_TYPE,
@@ -63,13 +47,35 @@ impl ElfHeader {
             e_shstrndx: 0,
         }
     }
+}
+
+impl ElfHeader {
+    const SOLANA_IDENT: [u8; 16] = [
+        0x7f, 0x45, 0x4c, 0x46, // EI_MAG0..EI_MAG3 ("\x7FELF")
+        0x02, // EI_CLASS (64-bit)
+        0x01, // EI_DATA (little endian)
+        0x01, // EI_VERSION
+        0x00, // EI_OSABI
+        0x00, // EI_ABIVERSION
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // EI_PAD
+    ];
+    const SOLANA_TYPE: u16 = 3; // ET_DYN
+    const SOLANA_MACHINE: u16 = 247; // BPF
+    const SOLANA_VERSION: u32 = 1; // EV_CURRENT
+    const ELF64_HEADER_SIZE: u16 = 64;
+    const PROGRAM_HEADER_SIZE: u16 = 56;
+    const SECTION_HEADER_SIZE: u16 = 64;
+
+    pub fn new() -> Self {
+        Self::default()
+    }
 
     pub fn bytecode(&self) -> Vec<u8> {
         let mut bytecode = Vec::with_capacity(Self::ELF64_HEADER_SIZE as usize);
-        
+
         // e_ident (16 bytes)
         bytecode.extend_from_slice(&self.e_ident);
-        
+
         // Emit remaining fields in little-endian order
         bytecode.extend_from_slice(&self.e_type.to_le_bytes());
         bytecode.extend_from_slice(&self.e_machine.to_le_bytes());
@@ -89,6 +95,7 @@ impl ElfHeader {
     }
 }
 
+#[rustfmt::skip]
 impl ProgramHeader {
 
     const PT_LOAD: u32 = 1;      // Loadable segment
@@ -161,21 +168,23 @@ pub struct SectionHeader {
     sh_entsize: u64,   // Entry size if section holds table
 }
 
+#[rustfmt::skip]
 impl SectionHeader {
     // Section types
     pub const SHT_NULL: u32 = 0;          // Section header table entry unused
     pub const SHT_PROGBITS: u32 = 1;      // Program data
     pub const SHT_STRTAB: u32 = 3;        // String table
     pub const SHT_NOBITS: u32 = 8;        // Program space with no data (bss)
-    pub const SHT_DYNAMIC: u32 = 6;      // Dynamic section
-    pub const SHT_DYNSYM: u32 = 11;      // Dynamic symbol table
-    pub const SHT_REL: u32 = 9;          // Relocation table
+    pub const SHT_DYNAMIC: u32 = 6;       // Dynamic section
+    pub const SHT_DYNSYM: u32 = 11;       // Dynamic symbol table
+    pub const SHT_REL: u32 = 9;           // Relocation table
     
     // Section flags
     pub const SHF_WRITE: u64 = 0x1;       // Writable
     pub const SHF_ALLOC: u64 = 0x2;       // Occupies memory during execution
     pub const SHF_EXECINSTR: u64 = 0x4;   // Executable
     
+    #[allow(clippy::too_many_arguments)]
     pub fn new(name_offset: u32, sh_type: u32, flags: u64, addr: u64, offset: u64, size: u64, link: u32, info: u32, addralign: u64, entsize: u64) -> Self {
         Self {
             sh_name: name_offset,

+ 151 - 72
crates/assembler/src/instruction.rs

@@ -1,7 +1,7 @@
-use crate::opcode::Opcode;
-use crate::lexer::{Token, ImmediateValue};
 use crate::dynsym::RelocationType;
+use crate::lexer::{ImmediateValue, Token};
 use crate::syscall::SYSCALLS;
+use sbpf_common::opcode::Opcode;
 
 use std::ops::Range;
 
@@ -24,44 +24,55 @@ impl Instruction {
     pub fn needs_relocation(&self) -> bool {
         match self.opcode {
             Opcode::Call | Opcode::Lddw => {
-                match &self.operands.last() {
-                    Some(Token::Identifier(_, _)) => true,
-                    _ => false,
-                }
-            },
+                matches!(&self.operands.last(), Some(Token::Identifier(_, _)))
+            }
             _ => false,
         }
     }
+
     //
     pub fn is_jump(&self) -> bool {
-        match self.opcode {
-            Opcode::Ja | Opcode::JeqImm | Opcode::JgtImm | Opcode::JgeImm   //
-            | Opcode::JltImm | Opcode::JleImm | Opcode::JsetImm             // 
-            | Opcode::JneImm | Opcode::JsgtImm | Opcode::JsgeImm            // 
-            | Opcode::JsltImm | Opcode::JsleImm | Opcode::JeqReg            // 
-            | Opcode::JgtReg | Opcode::JgeReg | Opcode::JltReg              // 
-            | Opcode::JleReg | Opcode::JsetReg | Opcode::JneReg             // 
-            | Opcode::JsgtReg | Opcode::JsgeReg | Opcode::JsltReg           // 
-            | Opcode::JsleReg => true,
-            _ => false,
-        }
+        matches!(
+            self.opcode,
+            Opcode::Ja
+                | Opcode::JeqImm
+                | Opcode::JgtImm
+                | Opcode::JgeImm
+                | Opcode::JltImm
+                | Opcode::JleImm
+                | Opcode::JsetImm
+                | Opcode::JneImm
+                | Opcode::JsgtImm
+                | Opcode::JsgeImm
+                | Opcode::JsltImm
+                | Opcode::JsleImm
+                | Opcode::JeqReg
+                | Opcode::JgtReg
+                | Opcode::JgeReg
+                | Opcode::JltReg
+                | Opcode::JleReg
+                | Opcode::JsetReg
+                | Opcode::JneReg
+                | Opcode::JsgtReg
+                | Opcode::JsgeReg
+                | Opcode::JsltReg
+                | Opcode::JsleReg
+        )
     }
     //
     pub fn get_relocation_info(&self) -> (RelocationType, String) {
         match self.opcode {
-            Opcode::Lddw => {
-                match &self.operands[1] {
-                    Token::Identifier(name, _) => (RelocationType::RSbf64Relative, name.clone()),
-                    _ => panic!("Expected label operand"),
-                }
+            Opcode::Lddw => match &self.operands[1] {
+                Token::Identifier(name, _) => (RelocationType::RSbf64Relative, name.clone()),
+                _ => panic!("Expected label operand"),
             },
             _ => {
                 if let Token::Identifier(name, _) = &self.operands[0] {
-                    (RelocationType::RSbfSyscall, name.clone()) 
+                    (RelocationType::RSbfSyscall, name.clone())
                 } else {
                     panic!("Expected label operand")
                 }
-            },
+            }
         }
     }
     //
@@ -76,28 +87,25 @@ impl Instruction {
         let off = i16::from_le_bytes([bytes[2], bytes[3]]);
         let imm = match opcode {
             Opcode::Lddw => {
-                let imm_low =   // 
-                    i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
-                let imm_high =  // 
-                    i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
-                let imm64 = ((imm_high as i64) << 32) | (imm_low as u32 as i64);
-                imm64
+                let imm_low = i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]);
+                let imm_high = i32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]);
+
+                ((imm_high as i64) << 32) | (imm_low as u32 as i64)
             }
             _ => i32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]) as i64,
         };
 
-
         match opcode {
             Opcode::Lddw => {
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..12));
             }
-        
+
             Opcode::Call => {
                 if let Some(name) = SYSCALLS.get(&(imm as u32)) {
                     operands.push(Token::Identifier(name.to_string(), 4..8));
                 } else {
-                    operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
+                    operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
                 }
             }
 
@@ -105,53 +113,125 @@ impl Instruction {
                 // callx source register is encoded in the src field
                 operands.push(Token::Register(src, 1..2));
             }
-        
+
             Opcode::Ja => {
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
-        
-            Opcode::JeqImm | Opcode::JgtImm | Opcode::JgeImm | Opcode::JltImm | 
-            Opcode::JleImm | Opcode::JsetImm | Opcode::JneImm | Opcode::JsgtImm | 
-            Opcode::JsgeImm | Opcode::JsltImm | Opcode::JsleImm => {
+
+            Opcode::JeqImm
+            | Opcode::JgtImm
+            | Opcode::JgeImm
+            | Opcode::JltImm
+            | Opcode::JleImm
+            | Opcode::JsetImm
+            | Opcode::JneImm
+            | Opcode::JsgtImm
+            | Opcode::JsgeImm
+            | Opcode::JsltImm
+            | Opcode::JsleImm => {
                 operands.push(Token::Register(dst, 1..2));
-                operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
+                operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
-        
-            Opcode::JeqReg | Opcode::JgtReg | Opcode::JgeReg | Opcode::JltReg | 
-            Opcode::JleReg | Opcode::JsetReg | Opcode::JneReg | Opcode::JsgtReg | 
-            Opcode::JsgeReg | Opcode::JsltReg | Opcode::JsleReg => {
+
+            Opcode::JeqReg
+            | Opcode::JgtReg
+            | Opcode::JgeReg
+            | Opcode::JltReg
+            | Opcode::JleReg
+            | Opcode::JsetReg
+            | Opcode::JneReg
+            | Opcode::JsgtReg
+            | Opcode::JsgeReg
+            | Opcode::JsltReg
+            | Opcode::JsleReg => {
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::Register(src, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
-        
+
             // Arithmetic instructions with immediate values
-            Opcode::Add32Imm | Opcode::Sub32Imm | Opcode::Mul32Imm | Opcode::Div32Imm |
-            Opcode::Or32Imm | Opcode::And32Imm | Opcode::Lsh32Imm | Opcode::Rsh32Imm |
-            Opcode::Mod32Imm | Opcode::Xor32Imm | Opcode::Mov32Imm | Opcode::Arsh32Imm |
-            Opcode::Lmul32Imm | Opcode::Udiv32Imm | Opcode::Urem32Imm | Opcode::Sdiv32Imm |
-            Opcode::Srem32Imm | Opcode::Add64Imm | Opcode::Sub64Imm | Opcode::Mul64Imm |
-            Opcode::Div64Imm | Opcode::Or64Imm | Opcode::And64Imm | Opcode::Lsh64Imm |
-            Opcode::Rsh64Imm | Opcode::Mod64Imm | Opcode::Xor64Imm | Opcode::Mov64Imm |
-            Opcode::Arsh64Imm | Opcode::Hor64Imm | Opcode::Lmul64Imm | Opcode::Uhmul64Imm |
-            Opcode::Udiv64Imm | Opcode::Urem64Imm | Opcode::Shmul64Imm | Opcode::Sdiv64Imm |
-            Opcode::Srem64Imm | Opcode::Be | Opcode::Le => {
+            Opcode::Add32Imm
+            | Opcode::Sub32Imm
+            | Opcode::Mul32Imm
+            | Opcode::Div32Imm
+            | Opcode::Or32Imm
+            | Opcode::And32Imm
+            | Opcode::Lsh32Imm
+            | Opcode::Rsh32Imm
+            | Opcode::Mod32Imm
+            | Opcode::Xor32Imm
+            | Opcode::Mov32Imm
+            | Opcode::Arsh32Imm
+            | Opcode::Lmul32Imm
+            | Opcode::Udiv32Imm
+            | Opcode::Urem32Imm
+            | Opcode::Sdiv32Imm
+            | Opcode::Srem32Imm
+            | Opcode::Add64Imm
+            | Opcode::Sub64Imm
+            | Opcode::Mul64Imm
+            | Opcode::Div64Imm
+            | Opcode::Or64Imm
+            | Opcode::And64Imm
+            | Opcode::Lsh64Imm
+            | Opcode::Rsh64Imm
+            | Opcode::Mod64Imm
+            | Opcode::Xor64Imm
+            | Opcode::Mov64Imm
+            | Opcode::Arsh64Imm
+            | Opcode::Hor64Imm
+            | Opcode::Lmul64Imm
+            | Opcode::Uhmul64Imm
+            | Opcode::Udiv64Imm
+            | Opcode::Urem64Imm
+            | Opcode::Shmul64Imm
+            | Opcode::Sdiv64Imm
+            | Opcode::Srem64Imm
+            | Opcode::Be
+            | Opcode::Le => {
                 operands.push(Token::Register(dst, 1..2));
-                operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
+                operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
             }
-        
+
             // Arithmetic instructions with register operands
-            Opcode::Add32Reg | Opcode::Sub32Reg | Opcode::Mul32Reg | Opcode::Div32Reg |
-            Opcode::Or32Reg | Opcode::And32Reg | Opcode::Lsh32Reg | Opcode::Rsh32Reg |
-            Opcode::Mod32Reg | Opcode::Xor32Reg | Opcode::Mov32Reg | Opcode::Arsh32Reg |
-            Opcode::Lmul32Reg | Opcode::Udiv32Reg | Opcode::Urem32Reg | Opcode::Sdiv32Reg |
-            Opcode::Srem32Reg | Opcode::Add64Reg | Opcode::Sub64Reg | Opcode::Mul64Reg |
-            Opcode::Div64Reg | Opcode::Or64Reg | Opcode::And64Reg | Opcode::Lsh64Reg |
-            Opcode::Rsh64Reg | Opcode::Mod64Reg | Opcode::Xor64Reg | Opcode::Mov64Reg |
-            Opcode::Arsh64Reg | Opcode::Lmul64Reg | Opcode::Uhmul64Reg | Opcode::Udiv64Reg |
-            Opcode::Urem64Reg | Opcode::Shmul64Reg | Opcode::Sdiv64Reg | Opcode::Srem64Reg => {
-                operands.push(Token::Register(dst   , 1..2));
+            Opcode::Add32Reg
+            | Opcode::Sub32Reg
+            | Opcode::Mul32Reg
+            | Opcode::Div32Reg
+            | Opcode::Or32Reg
+            | Opcode::And32Reg
+            | Opcode::Lsh32Reg
+            | Opcode::Rsh32Reg
+            | Opcode::Mod32Reg
+            | Opcode::Xor32Reg
+            | Opcode::Mov32Reg
+            | Opcode::Arsh32Reg
+            | Opcode::Lmul32Reg
+            | Opcode::Udiv32Reg
+            | Opcode::Urem32Reg
+            | Opcode::Sdiv32Reg
+            | Opcode::Srem32Reg
+            | Opcode::Add64Reg
+            | Opcode::Sub64Reg
+            | Opcode::Mul64Reg
+            | Opcode::Div64Reg
+            | Opcode::Or64Reg
+            | Opcode::And64Reg
+            | Opcode::Lsh64Reg
+            | Opcode::Rsh64Reg
+            | Opcode::Mod64Reg
+            | Opcode::Xor64Reg
+            | Opcode::Mov64Reg
+            | Opcode::Arsh64Reg
+            | Opcode::Lmul64Reg
+            | Opcode::Uhmul64Reg
+            | Opcode::Udiv64Reg
+            | Opcode::Urem64Reg
+            | Opcode::Shmul64Reg
+            | Opcode::Sdiv64Reg
+            | Opcode::Srem64Reg => {
+                operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::Register(src, 1..2));
             }
 
@@ -160,11 +240,11 @@ impl Instruction {
                 operands.push(Token::Register(src, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
-            
+
             Opcode::Stw | Opcode::Sth | Opcode::Stb | Opcode::Stdw => {
                 operands.push(Token::Register(dst, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
-                operands.push(Token::ImmediateValue(ImmediateValue::Int(imm as i64), 4..8));
+                operands.push(Token::ImmediateValue(ImmediateValue::Int(imm), 4..8));
             }
 
             Opcode::Stxb | Opcode::Stxh | Opcode::Stxw | Opcode::Stxdw => {
@@ -172,12 +252,12 @@ impl Instruction {
                 operands.push(Token::Register(src, 1..2));
                 operands.push(Token::ImmediateValue(ImmediateValue::Int(off as i64), 2..4));
             }
-            
+
             // Unary operations
             Opcode::Neg32 | Opcode::Neg64 | Opcode::Exit => {
                 operands.push(Token::Register(dst, 1..2));
             }
-        
+
             _ => {
                 return None;
             }
@@ -190,4 +270,3 @@ impl Instruction {
         })
     }
 }
-

+ 60 - 27
crates/assembler/src/lexer.rs

@@ -1,7 +1,6 @@
-use crate::bug;
 use crate::errors::CompileError;
-use crate::opcode::Opcode;
-use std::ops::Range;
+use sbpf_common::opcode::Opcode;
+use std::{ops::Range, str::FromStr as _};
 
 #[derive(Debug, Clone)]
 pub enum Op {
@@ -92,7 +91,7 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
     let mut errors = Vec::new();
     let mut byte_offset = 0;
 
-    let mut paren_stack : Vec<Token> = Vec::new();
+    let mut paren_stack: Vec<Token> = Vec::new();
 
     for line in source.lines() {
         if line.is_empty() {
@@ -107,12 +106,20 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                     let mut number = String::new();
                     let mut is_addr = false;
                     while let Some((_, c)) = chars.peek() {
-                        if c.is_digit(10) {
+                        if c.is_ascii_digit() {
                             number.push(chars.next().unwrap().1);
                         } else if number == "0" && *c == 'x' {
                             chars.next();
-                            is_addr = true; /*  */ number = String::new();
-                        } else if is_addr && (*c == 'a' || *c == 'b' || *c == 'c' || *c == 'd' || *c == 'e' || *c == 'f') {
+                            is_addr = true; /*  */
+                            number = String::new();
+                        } else if is_addr
+                            && (*c == 'a'
+                                || *c == 'b'
+                                || *c == 'c'
+                                || *c == 'd'
+                                || *c == 'e'
+                                || *c == 'f')
+                        {
                             number.push(chars.next().unwrap().1);
                         } else {
                             break;
@@ -122,23 +129,35 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                     if is_addr {
                         if let Ok(value) = u64::from_str_radix(&number, 16) {
                             let value = value as i64;
-                            tokens.push(Token::ImmediateValue(ImmediateValue::Addr(value), span.clone()));
+                            tokens.push(Token::ImmediateValue(
+                                ImmediateValue::Addr(value),
+                                span.clone(),
+                            ));
                         } else {
-                            errors.push(CompileError::InvalidNumber { number, span: span.clone(), custom_label: None });
+                            errors.push(CompileError::InvalidNumber {
+                                number,
+                                span: span.clone(),
+                                custom_label: None,
+                            });
                         }
+                    } else if let Ok(value) = number.parse::<i64>() {
+                        tokens.push(Token::ImmediateValue(
+                            ImmediateValue::Int(value),
+                            span.clone(),
+                        ));
                     } else {
-                        if let Ok(value) = number.parse::<i64>() {
-                            tokens.push(Token::ImmediateValue(ImmediateValue::Int(value), span.clone()));
-                        } else {
-                            errors.push(CompileError::InvalidNumber { number, span: span.clone(), custom_label: None });
-                        }
-                    }      
+                        errors.push(CompileError::InvalidNumber {
+                            number,
+                            span: span.clone(),
+                            custom_label: None,
+                        });
+                    }
                 }
 
                 c if c.is_ascii_alphanumeric() || *c == '_' => {
                     let mut identifier = String::new();
                     while let Some((_, c)) = chars.peek() {
-                        if *c == '_' || *c == ':' || *c == '.' || c.is_ascii_alphanumeric() { 
+                        if *c == '_' || *c == ':' || *c == '.' || c.is_ascii_alphanumeric() {
                             identifier.push(chars.next().unwrap().1);
                         } else {
                             break;
@@ -148,12 +167,18 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                     if identifier.ends_with(':') {
                         let label_name = identifier.trim_end_matches(':').to_string();
                         tokens.push(Token::Label(label_name, span));
-                    } else if identifier.starts_with('r') && identifier[1..].chars().all(|c| c.is_ascii_digit()) {
+                    } else if identifier.starts_with('r')
+                        && identifier[1..].chars().all(|c| c.is_ascii_digit())
+                    {
                         // TODO: label name can be "r"
                         if let Ok(value) = identifier[1..].parse::<u8>() {
                             tokens.push(Token::Register(value, span.clone()));
                         } else {
-                            errors.push(CompileError::InvalidRegister { register: identifier, span: span.clone(), custom_label: None });
+                            errors.push(CompileError::InvalidRegister {
+                                register: identifier,
+                                span: span.clone(),
+                                custom_label: None,
+                            });
                         }
                     } else if let Ok(opcode) = Opcode::from_str(&identifier) {
                         tokens.push(Token::Opcode(opcode, span));
@@ -181,7 +206,8 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                 }
                 '.' => {
                     chars.next();
-                    let directive: String = chars.by_ref()
+                    let directive: String = chars
+                        .by_ref()
                         .take_while(|(_, c)| c.is_ascii_alphanumeric() || *c == '_')
                         .map(|(_, c)| c)
                         .collect();
@@ -198,7 +224,10 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                             tokens.push(Token::StringLiteral(string_literal, span));
                             break;
                         } else if *c == '\n' {
-                            errors.push(CompileError::UnterminatedStringLiteral { span: token_start..token_start + 1, custom_label: None });
+                            errors.push(CompileError::UnterminatedStringLiteral {
+                                span: token_start..token_start + 1,
+                                custom_label: None,
+                            });
                         }
                         string_literal.push(chars.next().unwrap().1);
                     }
@@ -249,7 +278,11 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
                 }
                 _ => {
                     let span = token_start..token_start + 1;
-                    errors.push(CompileError::UnexpectedCharacter { character: *c, span, custom_label: None });
+                    errors.push(CompileError::UnexpectedCharacter {
+                        character: *c,
+                        span,
+                        custom_label: None,
+                    });
                     chars.next();
                 }
             }
@@ -259,13 +292,13 @@ pub fn tokenize(source: &str) -> Result<Vec<Token>, Vec<CompileError>> {
         byte_offset += 1;
     }
 
-    while !paren_stack.is_empty() {
-        let Token::LeftParen(span) = paren_stack.pop().unwrap() else {
-            bug!("this stack should only contain left paren tokens")
-        };
-        errors.push(CompileError::UnmatchedParen { span, custom_label: None });
+    while let Some(Token::LeftParen(span)) = paren_stack.pop() {
+        errors.push(CompileError::UnmatchedParen {
+            span,
+            custom_label: None,
+        });
     }
-    
+
     if errors.is_empty() {
         Ok(tokens)
     } else {

+ 5 - 12
crates/assembler/src/lib.rs

@@ -1,13 +1,12 @@
 use anyhow::Result;
 
 // Tokenizer and parser
-pub mod parser;
 pub mod lexer;
-pub mod opcode;
+pub mod parser;
 
 // Error handling and diagnostics
-pub mod macros;
 pub mod errors;
+pub mod macros;
 pub mod messages;
 
 // Intermediate Representation
@@ -29,15 +28,10 @@ pub mod debuginfo;
 #[cfg(target_arch = "wasm32")]
 pub mod wasm;
 
-pub use self::{
-    errors::CompileError,
-    parser::parse_tokens,
-    program::Program,
-    lexer::tokenize,
-};
+pub use self::{errors::CompileError, lexer::tokenize, parser::parse_tokens, program::Program};
 
-pub fn assemble(source: &str) -> Result<Vec<u8>, Vec<CompileError>>{
-    let tokens = match tokenize(&source) {
+pub fn assemble(source: &str) -> Result<Vec<u8>, Vec<CompileError>> {
+    let tokens = match tokenize(source) {
         Ok(tokens) => tokens,
         Err(errors) => {
             return Err(errors);
@@ -52,5 +46,4 @@ pub fn assemble(source: &str) -> Result<Vec<u8>, Vec<CompileError>>{
     let program = Program::from_parse_result(parse_result);
     let bytecode = program.emit_bytecode();
     Ok(bytecode)
-    
 }

+ 0 - 2
crates/assembler/src/macros.rs

@@ -50,5 +50,3 @@ macro_rules! bug {
         panic!("{}", format!("Internal error: {}\n", format!($($arg)*)));
     }};
 }
-
-

+ 9 - 6
crates/assembler/src/messages.rs

@@ -1,9 +1,8 @@
-
 /* A central place to store all the label messages to avoid duplication
  * and make it easier to update or translate. We could move error messages here too
  */
 
- pub const LABEL_REDEFINED: &str = "Label is redefined";
+pub const LABEL_REDEFINED: &str = "Label is redefined";
 
 // we can do a more fine-grained error message by pointing out the exact token that caused the error
 // with a special error pattern parser, but for now we just provide expected patterns
@@ -15,7 +14,11 @@ pub const EXPECTS_REG: &str = "expects <register>";
 pub const EXPECTS_REG_COM_IMM: &str = "expects <register>, <immediate value>";
 pub const EXPECTS_REG_COM_REG: &str = "expects <register>, <register>";
 pub const EXPECTS_REG_COM_IMM_OR_IDEN: &str = "expects <register>, <immediate value>/<identifier>";
-pub const EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN: &str = "expects <register>, <immediate value>, <immediate value>/<identifier>";
-pub const EXPECTS_REG_COM_LB_REG_BIOP_IMM_RB: &str = "expects <register>, [<register> <binary operator> <immediate value>]";
-pub const EXPECTS_LB_REG_BIOP_IMM_RB_COM_REG: &str = "expects [<register> <binary operator> <immediate value>], <register>";
-pub const EXPECTS_LB_REG_BIOP_IMM_RB_COM_IMM: &str = "expects [<register> <binary operator> <immediate value>], <immediate value>";
+pub const EXPECTS_REG_COM_IMM_COM_IMM_OR_IDEN: &str =
+    "expects <register>, <immediate value>, <immediate value>/<identifier>";
+pub const EXPECTS_REG_COM_LB_REG_BIOP_IMM_RB: &str =
+    "expects <register>, [<register> <binary operator> <immediate value>]";
+pub const EXPECTS_LB_REG_BIOP_IMM_RB_COM_REG: &str =
+    "expects [<register> <binary operator> <immediate value>], <register>";
+pub const EXPECTS_LB_REG_BIOP_IMM_RB_COM_IMM: &str =
+    "expects [<register> <binary operator> <immediate value>], <immediate value>";

+ 0 - 615
crates/assembler/src/opcode.rs

@@ -1,615 +0,0 @@
-use num_derive::FromPrimitive;
-
-#[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
-#[repr(u8)]
-pub enum Opcode {
-    Lddw,
-    Ldxb,
-    Ldxh,
-    Ldxw,
-    Ldxdw,
-    Stb,
-    Sth,
-    Stw,
-    Stdw,
-    Stxb,
-    Stxh,
-    Stxw,
-    Stxdw,
-    Add32,
-    Add32Imm,
-    Add32Reg,
-    Sub32,
-    Sub32Imm,
-    Sub32Reg,
-    Mul32,
-    Mul32Imm,
-    Mul32Reg,
-    Div32,
-    Div32Imm,
-    Div32Reg,
-    Or32,
-    Or32Imm,
-    Or32Reg,
-    And32,
-    And32Imm,
-    And32Reg,
-    Lsh32,
-    Lsh32Imm,
-    Lsh32Reg,
-    Rsh32,
-    Rsh32Imm,
-    Rsh32Reg,
-    Mod32,
-    Mod32Imm,
-    Mod32Reg,
-    Xor32,
-    Xor32Imm,
-    Xor32Reg,
-    Mov32,
-    Mov32Imm,
-    Mov32Reg,
-    Arsh32,
-    Arsh32Imm,
-    Arsh32Reg,
-    Lmul32,
-    Lmul32Imm,
-    Lmul32Reg,
-    Udiv32,
-    Udiv32Imm,
-    Udiv32Reg,
-    Urem32,
-    Urem32Imm,
-    Urem32Reg,
-    Sdiv32,
-    Sdiv32Imm,
-    Sdiv32Reg,
-    Srem32,
-    Srem32Imm,
-    Srem32Reg,
-    Le,
-    Be,
-    Add64,
-    Add64Imm,
-    Add64Reg,
-    Sub64,
-    Sub64Imm,
-    Sub64Reg,
-    Mul64,
-    Mul64Imm,
-    Mul64Reg,
-    Div64,
-    Div64Imm,
-    Div64Reg,
-    Or64,
-    Or64Imm,
-    Or64Reg,
-    And64,
-    And64Imm,
-    And64Reg,
-    Lsh64,
-    Lsh64Imm,
-    Lsh64Reg,
-    Rsh64,
-    Rsh64Imm,
-    Rsh64Reg,
-    Mod64,
-    Mod64Imm,
-    Mod64Reg,
-    Xor64,
-    Xor64Imm,
-    Xor64Reg,
-    Mov64,
-    Mov64Imm,
-    Mov64Reg,
-    Arsh64,
-    Arsh64Imm,
-    Arsh64Reg,
-    Hor64Imm,
-    Lmul64,
-    Lmul64Imm,
-    Lmul64Reg,
-    Uhmul64,
-    Uhmul64Imm,
-    Uhmul64Reg,
-    Udiv64,
-    Udiv64Imm,
-    Udiv64Reg,
-    Urem64,
-    Urem64Imm,
-    Urem64Reg,
-    Shmul64,
-    Shmul64Imm,
-    Shmul64Reg,
-    Sdiv64,
-    Sdiv64Imm,
-    Sdiv64Reg,
-    Srem64,
-    Srem64Imm,
-    Srem64Reg,
-    Neg32,
-    Neg64,
-    Ja,
-    Jeq,
-    JeqImm,
-    JeqReg,
-    Jgt,
-    JgtImm,
-    JgtReg,
-    Jge,
-    JgeImm,
-    JgeReg,
-    Jlt,
-    JltImm,
-    JltReg,
-    Jle,
-    JleImm,
-    JleReg,
-    Jset,
-    JsetImm,
-    JsetReg,
-    Jne,
-    JneImm,
-    JneReg,
-    Jsgt,
-    JsgtImm,
-    JsgtReg,
-    Jsge,
-    JsgeImm,
-    JsgeReg,
-    Jslt,
-    JsltImm,
-    JsltReg,
-    Jsle,
-    JsleImm,
-    JsleReg,
-    Call,
-    Callx,
-    Exit,
-}
-
-impl Opcode {
-    pub fn from_str(s: &str) -> Result<Self, &'static str> {
-        match s.to_lowercase().as_str() {
-            "lddw" => Ok(Opcode::Lddw),
-            "ldxb" => Ok(Opcode::Ldxb),
-            "ldxh" => Ok(Opcode::Ldxh),
-            "ldxw" => Ok(Opcode::Ldxw),
-            "ldxdw" => Ok(Opcode::Ldxdw),
-            "stb" => Ok(Opcode::Stb),
-            "sth" => Ok(Opcode::Sth),
-            "stw" => Ok(Opcode::Stw),
-            "stdw" => Ok(Opcode::Stdw),
-            "stxb" => Ok(Opcode::Stxb),
-            "stxh" => Ok(Opcode::Stxh),
-            "stxw" => Ok(Opcode::Stxw),
-            "stxdw" => Ok(Opcode::Stxdw),
-            "add32" => Ok(Opcode::Add32),
-            "sub32" => Ok(Opcode::Sub32),
-            "mul32" => Ok(Opcode::Mul32),
-            "div32" => Ok(Opcode::Div32),
-            "or32" => Ok(Opcode::Or32),
-            "and32" => Ok(Opcode::And32),
-            "lsh32" => Ok(Opcode::Lsh32),
-            "rsh32" => Ok(Opcode::Rsh32),
-            "neg32" => Ok(Opcode::Neg32),
-            "mod32" => Ok(Opcode::Mod32),
-            "xor32" => Ok(Opcode::Xor32),
-            "mov32" => Ok(Opcode::Mov32),
-            "arsh32" => Ok(Opcode::Arsh32),
-            "lmul32" => Ok(Opcode::Lmul32),
-            "udiv32" => Ok(Opcode::Udiv32),
-            "urem32" => Ok(Opcode::Urem32),
-            "sdiv32" => Ok(Opcode::Sdiv32),
-            "srem32" => Ok(Opcode::Srem32),
-            "le" => Ok(Opcode::Le),
-            "be" => Ok(Opcode::Be),
-            "add64" => Ok(Opcode::Add64),
-            "sub64" => Ok(Opcode::Sub64),
-            "mul64" => Ok(Opcode::Mul64),
-            "div64" => Ok(Opcode::Div64),
-            "or64" => Ok(Opcode::Or64),
-            "and64" => Ok(Opcode::And64),
-            "lsh64" => Ok(Opcode::Lsh64),
-            "rsh64" => Ok(Opcode::Rsh64),
-            "neg64" => Ok(Opcode::Neg64),
-            "mod64" => Ok(Opcode::Mod64),
-            "xor64" => Ok(Opcode::Xor64),
-            "mov64" => Ok(Opcode::Mov64),
-            "arsh64" => Ok(Opcode::Arsh64),
-            "hor64" => Ok(Opcode::Hor64Imm),
-            "lmul64" => Ok(Opcode::Lmul64),
-            "uhmul64" => Ok(Opcode::Uhmul64),
-            "udiv64" => Ok(Opcode::Udiv64),
-            "urem64" => Ok(Opcode::Urem64),
-            "shmul64" => Ok(Opcode::Shmul64),
-            "sdiv64" => Ok(Opcode::Sdiv64),
-            "srem64" => Ok(Opcode::Srem64),
-            "ja" => Ok(Opcode::Ja),
-            "jeq" => Ok(Opcode::Jeq),
-            "jgt" => Ok(Opcode::Jgt),
-            "jge" => Ok(Opcode::Jge),
-            "jlt" => Ok(Opcode::Jlt),
-            "jle" => Ok(Opcode::Jle),
-            "jset" => Ok(Opcode::Jset),
-            "jne" => Ok(Opcode::Jne),
-            "jsgt" => Ok(Opcode::Jsgt),
-            "jsge" => Ok(Opcode::Jsge),
-            "jslt" => Ok(Opcode::Jslt),
-            "jsle" => Ok(Opcode::Jsle),
-            "call" => Ok(Opcode::Call),
-            "callx" => Ok(Opcode::Callx),
-            "exit" => Ok(Opcode::Exit),
-            _ => Err("Invalid opcode"),
-        }
-    }
-
-    pub fn from_u8(u: u8) -> Option<Self> {
-        match u {
-            0x18 => Some(Opcode::Lddw),
-            0x71 => Some(Opcode::Ldxb),
-            0x69 => Some(Opcode::Ldxh),
-            0x61 => Some(Opcode::Ldxw),
-            0x79 => Some(Opcode::Ldxdw),
-            0x72 => Some(Opcode::Stb),
-            0x6a => Some(Opcode::Sth),
-            0x62 => Some(Opcode::Stw),
-            0x7a => Some(Opcode::Stdw),
-            0x73 => Some(Opcode::Stxb),
-            0x6b => Some(Opcode::Stxh),
-            0x63 => Some(Opcode::Stxw),
-            0x7b => Some(Opcode::Stxdw),
-            0x04 => Some(Opcode::Add32Imm),
-            0x0c => Some(Opcode::Add32Reg),
-            0x14 => Some(Opcode::Sub32Imm),
-            0x1c => Some(Opcode::Sub32Reg),
-            0x24 => Some(Opcode::Mul32Imm),
-            0x2c => Some(Opcode::Mul32Reg),
-            0x34 => Some(Opcode::Div32Imm),
-            0x3c => Some(Opcode::Div32Reg),
-            0x44 => Some(Opcode::Or32Imm),
-            0x4c => Some(Opcode::Or32Reg),
-            0x54 => Some(Opcode::And32Imm),
-            0x5c => Some(Opcode::And32Reg),
-            0x64 => Some(Opcode::Lsh32Imm),
-            0x6c => Some(Opcode::Lsh32Reg),
-            0x74 => Some(Opcode::Rsh32Imm),
-            0x7c => Some(Opcode::Rsh32Reg),
-            0x94 => Some(Opcode::Mod32Imm),
-            0x9c => Some(Opcode::Mod32Reg),
-            0xa4 => Some(Opcode::Xor32Imm),
-            0xac => Some(Opcode::Xor32Reg),
-            0xb4 => Some(Opcode::Mov32Imm),
-            0xbc => Some(Opcode::Mov32Reg),
-            0xc4 => Some(Opcode::Arsh32Imm),
-            0xcc => Some(Opcode::Arsh32Reg),
-            0x86 => Some(Opcode::Lmul32Imm),
-            0x8e => Some(Opcode::Lmul32Reg),
-            0x46 => Some(Opcode::Udiv32Imm),
-            0x4e => Some(Opcode::Udiv32Reg),
-            0x66 => Some(Opcode::Urem32Imm),
-            0x6e => Some(Opcode::Urem32Reg),
-            0xc6 => Some(Opcode::Sdiv32Imm),
-            0xce => Some(Opcode::Sdiv32Reg),
-            0xe6 => Some(Opcode::Srem32Imm),
-            0xee => Some(Opcode::Srem32Reg),
-            0xd4 => Some(Opcode::Le),
-            0xdc => Some(Opcode::Be),
-            0x07 => Some(Opcode::Add64Imm),
-            0x0f => Some(Opcode::Add64Reg),
-            0x17 => Some(Opcode::Sub64Imm),
-            0x1f => Some(Opcode::Sub64Reg),
-            0x27 => Some(Opcode::Mul64Imm),
-            0x2f => Some(Opcode::Mul64Reg),
-            0x37 => Some(Opcode::Div64Imm),
-            0x3f => Some(Opcode::Div64Reg),
-            0x47 => Some(Opcode::Or64Imm),
-            0x4f => Some(Opcode::Or64Reg),
-            0x57 => Some(Opcode::And64Imm),
-            0x5f => Some(Opcode::And64Reg),
-            0x67 => Some(Opcode::Lsh64Imm),
-            0x6f => Some(Opcode::Lsh64Reg),
-            0x77 => Some(Opcode::Rsh64Imm),
-            0x7f => Some(Opcode::Rsh64Reg),
-            0x97 => Some(Opcode::Mod64Imm),
-            0x9f => Some(Opcode::Mod64Reg),
-            0xa7 => Some(Opcode::Xor64Imm),
-            0xaf => Some(Opcode::Xor64Reg),
-            0xb7 => Some(Opcode::Mov64Imm),
-            0xbf => Some(Opcode::Mov64Reg),
-            0xc7 => Some(Opcode::Arsh64Imm),
-            0xcf => Some(Opcode::Arsh64Reg),
-            0xf7 => Some(Opcode::Hor64Imm),
-            0x96 => Some(Opcode::Lmul64Imm),
-            0x9e => Some(Opcode::Lmul64Reg),
-            0x36 => Some(Opcode::Uhmul64Imm),
-            0x3e => Some(Opcode::Uhmul64Reg),
-            0x56 => Some(Opcode::Udiv64Imm),
-            0x5e => Some(Opcode::Udiv64Reg),
-            0x76 => Some(Opcode::Urem64Imm),
-            0x7e => Some(Opcode::Urem64Reg),
-            0xb6 => Some(Opcode::Shmul64Imm),
-            0xbe => Some(Opcode::Shmul64Reg),
-            0xd6 => Some(Opcode::Sdiv64Imm),
-            0xde => Some(Opcode::Sdiv64Reg),
-            0xf6 => Some(Opcode::Srem64Imm),
-            0xfe => Some(Opcode::Srem64Reg),
-            0x84 => Some(Opcode::Neg32),
-            0x87 => Some(Opcode::Neg64),
-            0x05 => Some(Opcode::Ja),
-            0x15 => Some(Opcode::JeqImm),
-            0x1d => Some(Opcode::JeqReg),
-            0x25 => Some(Opcode::JgtImm),
-            0x2d => Some(Opcode::JgtReg),
-            0x35 => Some(Opcode::JgeImm),
-            0x3d => Some(Opcode::JgeReg),
-            0xa5 => Some(Opcode::JltImm),
-            0xad => Some(Opcode::JltReg),
-            0xb5 => Some(Opcode::JleImm),
-            0xbd => Some(Opcode::JleReg),
-            0x45 => Some(Opcode::JsetImm),
-            0x4d => Some(Opcode::JsetReg),
-            0x55 => Some(Opcode::JneImm),
-            0x5d => Some(Opcode::JneReg),
-            0x65 => Some(Opcode::JsgtImm),
-            0x6d => Some(Opcode::JsgtReg),
-            0x75 => Some(Opcode::JsgeImm),
-            0x7d => Some(Opcode::JsgeReg),
-            0xc5 => Some(Opcode::JsltImm),
-            0xcd => Some(Opcode::JsltReg),
-            0xd5 => Some(Opcode::JsleImm),
-            0xdd => Some(Opcode::JsleReg),
-            0x85 => Some(Opcode::Call),
-            0x8d => Some(Opcode::Callx),
-            0x95 => Some(Opcode::Exit),
-            _ => None,
-        }
-    }
-
-    pub fn to_bytecode(&self) -> u8 {
-        match self {
-            Opcode::Lddw => 0x18,
-            Opcode::Ldxb => 0x71,
-            Opcode::Ldxh => 0x69,
-            Opcode::Ldxw => 0x61,
-            Opcode::Ldxdw => 0x79,
-            Opcode::Stb => 0x72,
-            Opcode::Sth => 0x6a,
-            Opcode::Stw => 0x62,
-            Opcode::Stdw => 0x7a,
-            Opcode::Stxb => 0x73,
-            Opcode::Stxh => 0x6b,
-            Opcode::Stxw => 0x63,
-            Opcode::Stxdw => 0x7b,
-            // Opcode::Add32 => 0x04,
-            Opcode::Add32Imm => 0x04,
-            Opcode::Add32Reg => 0x0c,
-            // Opcode::Sub32 => 0x14,
-            Opcode::Sub32Imm => 0x14,
-            Opcode::Sub32Reg => 0x1c,
-            // Opcode::Mul32 => 0x24,
-            Opcode::Mul32Imm => 0x24,
-            Opcode::Mul32Reg => 0x2c,
-            // Opcode::Div32 => 0x34,
-            Opcode::Div32Imm => 0x34,
-            Opcode::Div32Reg => 0x3c,
-            // Opcode::Or32 => 0x44,
-            Opcode::Or32Imm => 0x44,
-            Opcode::Or32Reg => 0x4c,
-            // Opcode::And32 => 0x54,
-            Opcode::And32Imm => 0x54,
-            Opcode::And32Reg => 0x5c,
-            // Opcode::Lsh32 => 0x64,
-            Opcode::Lsh32Imm => 0x64,
-            Opcode::Lsh32Reg => 0x6c,
-            // Opcode::Rsh32 => 0x74,
-            Opcode::Rsh32Imm => 0x74,
-            Opcode::Rsh32Reg => 0x7c,
-            // Opcode::Mod32 => 0x94,
-            Opcode::Mod32Imm => 0x94,
-            Opcode::Mod32Reg => 0x9c,
-            // Opcode::Xor32 => 0xa4,
-            Opcode::Xor32Imm => 0xa4,
-            Opcode::Xor32Reg => 0xac,
-            // Opcode::Mov32 => 0xb4,
-            Opcode::Mov32Imm => 0xb4,
-            Opcode::Mov32Reg => 0xbc,
-            // Opcode::Arsh32 => 0xc4,
-            Opcode::Arsh32Imm => 0xc4,
-            Opcode::Arsh32Reg => 0xcc,
-            // Opcode::Lmul32 => 0x86,
-            Opcode::Lmul32Imm => 0x86,
-            Opcode::Lmul32Reg => 0x8e,
-            // Opcode::Udiv32 => 0x46,
-            Opcode::Udiv32Imm => 0x46,
-            Opcode::Udiv32Reg => 0x4e,
-            // Opcode::Urem32 => 0x66,
-            Opcode::Urem32Imm => 0x66,
-            Opcode::Urem32Reg => 0x6e,
-            // Opcode::Sdiv32 => 0xc6,
-            Opcode::Sdiv32Imm => 0xc6,
-            Opcode::Sdiv32Reg => 0xce,
-            // Opcode::Srem32 => 0xe6,
-            Opcode::Srem32Imm => 0xe6,
-            Opcode::Srem32Reg => 0xee,
-            Opcode::Le => 0xd4,
-            Opcode::Be => 0xdc,
-            // Opcode::Add64 => 0x07,
-            Opcode::Add64Imm => 0x07,
-            Opcode::Add64Reg => 0x0f,
-            // Opcode::Sub64 => 0x17,
-            Opcode::Sub64Imm => 0x17,
-            Opcode::Sub64Reg => 0x1f,
-            // Opcode::Mul64 => 0x27,
-            Opcode::Mul64Imm => 0x27,
-            Opcode::Mul64Reg => 0x2f,
-            // Opcode::Div64 => 0x37,
-            Opcode::Div64Imm => 0x37,
-            Opcode::Div64Reg => 0x3f,
-            // Opcode::Or64 => 0x47,
-            Opcode::Or64Imm => 0x47,
-            Opcode::Or64Reg => 0x4f,
-            // Opcode::And64 => 0x57,
-            Opcode::And64Imm => 0x57,
-            Opcode::And64Reg => 0x5f,
-            // Opcode::Lsh64 => 0x67,
-            Opcode::Lsh64Imm => 0x67,
-            Opcode::Lsh64Reg => 0x6f,
-            // Opcode::Rsh64 => 0x77,
-            Opcode::Rsh64Imm => 0x77,
-            Opcode::Rsh64Reg => 0x7f,
-            // Opcode::Mod64 => 0x97,
-            Opcode::Mod64Imm => 0x97,
-            Opcode::Mod64Reg => 0x9f,
-            // Opcode::Xor64 => 0xa7,
-            Opcode::Xor64Imm => 0xa7,
-            Opcode::Xor64Reg => 0xaf,
-            // Opcode::Mov64 => 0xb7,
-            Opcode::Mov64Imm => 0xb7,
-            Opcode::Mov64Reg => 0xbf,
-            // Opcode::Arsh64 => 0xc7,
-            Opcode::Arsh64Imm => 0xc7,
-            Opcode::Arsh64Reg => 0xcf,
-            Opcode::Hor64Imm => 0xf7,
-            // Opcode::Lmul64 => 0x87,
-            Opcode::Lmul64Imm => 0x96,
-            Opcode::Lmul64Reg => 0x9e,
-            // Opcode::Uhmul64 => 0x36,
-            Opcode::Uhmul64Imm => 0x36,
-            Opcode::Uhmul64Reg => 0x3e,
-            // Opcode::Udiv64 => 0x56,
-            Opcode::Udiv64Imm => 0x56,
-            Opcode::Udiv64Reg => 0x5e,
-            // Opcode::Urem64 => 0x76,
-            Opcode::Urem64Imm => 0x76,
-            Opcode::Urem64Reg => 0x7e,
-            // Opcode::Shmul64 => 0xb6,
-            Opcode::Shmul64Imm => 0xb6,
-            Opcode::Shmul64Reg => 0xbe,
-            // Opcode::Sdiv64 => 0xd6,
-            Opcode::Sdiv64Imm => 0xd6,
-            Opcode::Sdiv64Reg => 0xde,
-            // Opcode::Srem64 => 0xf6,
-            Opcode::Srem64Imm => 0xf6,
-            Opcode::Srem64Reg => 0xfe,
-            Opcode::Neg32 => 0x84,
-            Opcode::Neg64 => 0x87,
-            Opcode::Ja => 0x05,
-            // Opcode::Jeq => 0x15,
-            Opcode::JeqImm => 0x15,
-            Opcode::JeqReg => 0x1d,
-            // Opcode::Jgt => 0x25,
-            Opcode::JgtImm => 0x25,
-            Opcode::JgtReg => 0x2d,
-            // Opcode::Jge => 0x35,
-            Opcode::JgeImm => 0x35,
-            Opcode::JgeReg => 0x3d,
-            // Opcode::Jlt => 0xa5,
-            Opcode::JltImm => 0xa5,
-            Opcode::JltReg => 0xad,
-            // Opcode::Jle => 0xb5,
-            Opcode::JleImm => 0xb5,
-            Opcode::JleReg => 0xbd,
-            // Opcode::Jset => 0x45,
-            Opcode::JsetImm => 0x45,
-            Opcode::JsetReg => 0x4d,
-            // Opcode::Jne => 0x55,
-            Opcode::JneImm => 0x55,
-            Opcode::JneReg => 0x5d,
-            // Opcode::Jsgt => 0x65,
-            Opcode::JsgtImm => 0x65,
-            Opcode::JsgtReg => 0x6d,
-            // Opcode::Jsge => 0x75,
-            Opcode::JsgeImm => 0x75,
-            Opcode::JsgeReg => 0x7d,
-            // Opcode::Jslt => 0xc5,
-            Opcode::JsltImm => 0xc5,
-            Opcode::JsltReg => 0xcd,
-            // Opcode::Jsle => 0xd5,
-            Opcode::JsleImm => 0xd5,
-            Opcode::JsleReg => 0xdd,
-            Opcode::Call => 0x85,
-            Opcode::Callx => 0x8d,
-            Opcode::Exit => 0x95,
-            
-            _ => 0x00,
-
-        }
-    }
-    
-    pub fn to_str(&self) -> &'static str {
-        match self {
-            Opcode::Lddw => "lddw",
-            Opcode::Ldxb => "ldxb",
-            Opcode::Ldxh => "ldxh",
-            Opcode::Ldxw => "ldxw",
-            Opcode::Ldxdw => "ldxdw",
-            Opcode::Stb => "stb",
-            Opcode::Sth => "sth",
-            Opcode::Stw => "stw",
-            Opcode::Stdw => "stdw",
-            Opcode::Stxb => "stxb",
-            Opcode::Stxh => "stxh",
-            Opcode::Stxw => "stxw",
-            Opcode::Stxdw => "stxdw",
-            Opcode::Add32 | Opcode::Add32Imm | Opcode::Add32Reg => "add32",
-            Opcode::Sub32 | Opcode::Sub32Imm | Opcode::Sub32Reg => "sub32",
-            Opcode::Mul32 | Opcode::Mul32Imm | Opcode::Mul32Reg => "mul32",
-            Opcode::Div32 | Opcode::Div32Imm | Opcode::Div32Reg => "div32",
-            Opcode::Or32 | Opcode::Or32Imm | Opcode::Or32Reg => "or32",
-            Opcode::And32 | Opcode::And32Imm | Opcode::And32Reg => "and32",
-            Opcode::Lsh32 | Opcode::Lsh32Imm | Opcode::Lsh32Reg => "lsh32",
-            Opcode::Rsh32 | Opcode::Rsh32Imm | Opcode::Rsh32Reg => "rsh32",
-            Opcode::Neg32 => "neg32",
-            Opcode::Mod32 | Opcode::Mod32Imm | Opcode::Mod32Reg => "mod32",
-            Opcode::Xor32 | Opcode::Xor32Imm | Opcode::Xor32Reg => "xor32",
-            Opcode::Mov32 | Opcode::Mov32Imm | Opcode::Mov32Reg => "mov32",
-            Opcode::Arsh32 | Opcode::Arsh32Imm | Opcode::Arsh32Reg => "arsh32",
-            Opcode::Lmul32 | Opcode::Lmul32Imm | Opcode::Lmul32Reg => "lmul32",
-            Opcode::Udiv32 | Opcode::Udiv32Imm | Opcode::Udiv32Reg => "udiv32",
-            Opcode::Urem32 | Opcode::Urem32Imm | Opcode::Urem32Reg => "urem32",
-            Opcode::Sdiv32 | Opcode::Sdiv32Imm | Opcode::Sdiv32Reg => "sdiv32",
-            Opcode::Srem32 | Opcode::Srem32Imm | Opcode::Srem32Reg => "srem32",
-            Opcode::Le => "le",
-            Opcode::Be => "be",
-            Opcode::Add64 | Opcode::Add64Imm | Opcode::Add64Reg => "add64",
-            Opcode::Sub64 | Opcode::Sub64Imm | Opcode::Sub64Reg => "sub64",
-            Opcode::Mul64 | Opcode::Mul64Imm | Opcode::Mul64Reg => "mul64",
-            Opcode::Div64 | Opcode::Div64Imm | Opcode::Div64Reg => "div64",
-            Opcode::Or64 | Opcode::Or64Imm | Opcode::Or64Reg => "or64",
-            Opcode::And64 | Opcode::And64Imm | Opcode::And64Reg => "and64",
-            Opcode::Lsh64 | Opcode::Lsh64Imm | Opcode::Lsh64Reg => "lsh64",
-            Opcode::Rsh64 | Opcode::Rsh64Imm | Opcode::Rsh64Reg => "rsh64",
-            Opcode::Neg64 => "neg64",
-            Opcode::Mod64 | Opcode::Mod64Imm | Opcode::Mod64Reg => "mod64",
-            Opcode::Xor64 | Opcode::Xor64Imm | Opcode::Xor64Reg => "xor64",
-            Opcode::Mov64 | Opcode::Mov64Imm | Opcode::Mov64Reg => "mov64",
-            Opcode::Arsh64 | Opcode::Arsh64Imm | Opcode::Arsh64Reg => "arsh64",
-            Opcode::Hor64Imm => "hor64",
-            Opcode::Lmul64 | Opcode::Lmul64Imm | Opcode::Lmul64Reg => "lmul64",
-            Opcode::Uhmul64 | Opcode::Uhmul64Imm | Opcode::Uhmul64Reg => "uhmul64",
-            Opcode::Udiv64 | Opcode::Udiv64Imm | Opcode::Udiv64Reg => "udiv64",
-            Opcode::Urem64 | Opcode::Urem64Imm | Opcode::Urem64Reg => "urem64",
-            Opcode::Shmul64 | Opcode::Shmul64Imm | Opcode::Shmul64Reg => "shmul64",
-            Opcode::Sdiv64 | Opcode::Sdiv64Imm | Opcode::Sdiv64Reg => "sdiv64",
-            Opcode::Srem64 | Opcode::Srem64Imm | Opcode::Srem64Reg => "srem64",
-            Opcode::Ja | Opcode::Jeq | Opcode::JeqImm | Opcode::JeqReg => "jeq",
-            Opcode::Jgt | Opcode::JgtImm | Opcode::JgtReg => "jgt",
-            Opcode::Jge | Opcode::JgeImm | Opcode::JgeReg => "jge",
-            Opcode::Jlt | Opcode::JltImm | Opcode::JltReg => "jlt",
-            Opcode::Jle | Opcode::JleImm | Opcode::JleReg => "jle",
-            Opcode::Jset | Opcode::JsetImm | Opcode::JsetReg => "jset",
-            Opcode::Jne | Opcode::JneImm | Opcode::JneReg => "jne",
-            Opcode::Jsgt | Opcode::JsgtImm | Opcode::JsgtReg => "jsgt",
-            Opcode::Jsge | Opcode::JsgeImm | Opcode::JsgeReg => "jsge",
-            Opcode::Jslt | Opcode::JsltImm | Opcode::JsltReg => "jslt",
-            Opcode::Jsle | Opcode::JsleImm | Opcode::JsleReg => "jsle",
-            Opcode::Call => "call",
-            Opcode::Callx => "callx",
-            Opcode::Exit => "exit",
-        }
-    }
-    pub fn to_string(&self) -> String {
-        self.to_str().to_string()
-    }
-}

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 408 - 299
crates/assembler/src/parser.rs


+ 90 - 33
crates/assembler/src/program.rs

@@ -1,13 +1,17 @@
+use crate::debuginfo::DebugInfo;
+use crate::dynsym::{DynamicSymbol, RelDyn, RelocationType};
 use crate::header::ElfHeader;
 use crate::header::ProgramHeader;
-use crate::section::{Section, NullSection, DynamicSection, ShStrTabSection, SectionType, DynStrSection, DynSymSection, RelDynSection};
-use crate::dynsym::{DynamicSymbol, RelDyn, RelocationType};
 use crate::parser::ParseResult;
-use crate::debuginfo::DebugInfo;
+use crate::section::{
+    DynStrSection, DynSymSection, DynamicSection, NullSection, RelDynSection, Section, SectionType,
+    ShStrTabSection,
+};
+use std::collections::HashMap;
 use std::fs::File;
 use std::io::Write;
 use std::path::Path;
-use std::collections::HashMap;
+
 #[derive(Debug)]
 pub struct Program {
     pub elf_header: ElfHeader,
@@ -27,11 +31,11 @@ impl Program {
     ) -> Self {
         let mut elf_header = ElfHeader::new();
         let mut program_headers = None;
-        
+
         // omit program headers if static
         let ph_count = if prog_is_static { 0 } else { 3 };
         elf_header.e_phnum = ph_count;
-        
+
         // save read + execute size for program header before
         // ownership of code/data sections is transferred
         let text_size = code_section.size() + data_section.size();
@@ -45,7 +49,7 @@ impl Program {
         sections.push(SectionType::Default(NullSection::new()));
 
         let mut section_names = Vec::new();
-        
+
         // Code section
         let mut text_section = SectionType::Code(code_section);
         text_section.set_offset(current_offset);
@@ -61,7 +65,7 @@ impl Program {
             section_names.push(rodata_section.name().to_string());
             sections.push(rodata_section);
         }
-        
+
         let padding = (8 - (current_offset % 8)) % 8;
         current_offset += padding;
 
@@ -69,18 +73,25 @@ impl Program {
             let mut symbol_names = Vec::new();
             let mut dyn_syms = Vec::new();
             let mut dyn_str_offset = 1;
-            
+
             dyn_syms.push(DynamicSymbol::new(0, 0, 0, 0, 0, 0));
 
             // all symbols handled right now are all global symbols
             for (name, _) in dynamic_symbols.get_entry_points() {
                 symbol_names.push(name.clone());
-                dyn_syms.push(DynamicSymbol::new(dyn_str_offset as u32, 0x10, 0, 1, elf_header.e_entry, 0));
+                dyn_syms.push(DynamicSymbol::new(
+                    dyn_str_offset as u32,
+                    0x10,
+                    0,
+                    1,
+                    elf_header.e_entry,
+                    0,
+                ));
                 dyn_str_offset += name.len() + 1;
             }
 
             for (name, _) in dynamic_symbols.get_call_targets() {
-                symbol_names.push(name.clone());                 
+                symbol_names.push(name.clone());
                 dyn_syms.push(DynamicSymbol::new(dyn_str_offset as u32, 0x10, 0, 0, 0, 0));
                 dyn_str_offset += name.len() + 1;
             }
@@ -90,7 +101,11 @@ impl Program {
             for (offset, rel_type, name) in relocation_data.get_rel_dyns() {
                 if rel_type == RelocationType::RSbfSyscall {
                     if let Some(index) = symbol_names.iter().position(|n| *n == name) {
-                        rel_dyns.push(RelDyn::new(offset + elf_header.e_entry, rel_type as u64, index as u64 + 1));
+                        rel_dyns.push(RelDyn::new(
+                            offset + elf_header.e_entry,
+                            rel_type as u64,
+                            index as u64 + 1,
+                        ));
                     } else {
                         panic!("Symbol {} not found in symbol_names", name);
                     }
@@ -99,7 +114,13 @@ impl Program {
                     rel_dyns.push(RelDyn::new(offset + elf_header.e_entry, rel_type as u64, 0));
                 }
             }
-            let mut dynamic_section = SectionType::Dynamic(DynamicSection::new((section_names.iter().map(|name| name.len() + 1).sum::<usize>() + 1) as u32));
+            let mut dynamic_section = SectionType::Dynamic(DynamicSection::new(
+                (section_names
+                    .iter()
+                    .map(|name| name.len() + 1)
+                    .sum::<usize>()
+                    + 1) as u32,
+            ));
             dynamic_section.set_offset(current_offset);
             if let SectionType::Dynamic(ref mut dynamic_section) = dynamic_section {
                 dynamic_section.set_rel_count(rel_count);
@@ -107,17 +128,38 @@ impl Program {
             current_offset += dynamic_section.size();
             section_names.push(dynamic_section.name().to_string());
 
-            let mut dynsym_section = SectionType::DynSym(DynSymSection::new((section_names.iter().map(|name| name.len() + 1).sum::<usize>() + 1) as u32, dyn_syms));
+            let mut dynsym_section = SectionType::DynSym(DynSymSection::new(
+                (section_names
+                    .iter()
+                    .map(|name| name.len() + 1)
+                    .sum::<usize>()
+                    + 1) as u32,
+                dyn_syms,
+            ));
             dynsym_section.set_offset(current_offset);
             current_offset += dynsym_section.size();
             section_names.push(dynsym_section.name().to_string());
 
-            let mut dynstr_section = SectionType::DynStr(DynStrSection::new((section_names.iter().map(|name| name.len() + 1).sum::<usize>() + 1) as u32, symbol_names));
+            let mut dynstr_section = SectionType::DynStr(DynStrSection::new(
+                (section_names
+                    .iter()
+                    .map(|name| name.len() + 1)
+                    .sum::<usize>()
+                    + 1) as u32,
+                symbol_names,
+            ));
             dynstr_section.set_offset(current_offset);
             current_offset += dynstr_section.size();
             section_names.push(dynstr_section.name().to_string());
 
-            let mut rel_dyn_section = SectionType::RelDyn(RelDynSection::new((section_names.iter().map(|name| name.len() + 1).sum::<usize>() + 1) as u32, rel_dyns));
+            let mut rel_dyn_section = SectionType::RelDyn(RelDynSection::new(
+                (section_names
+                    .iter()
+                    .map(|name| name.len() + 1)
+                    .sum::<usize>()
+                    + 1) as u32,
+                rel_dyns,
+            ));
             rel_dyn_section.set_offset(current_offset);
             current_offset += rel_dyn_section.size();
             section_names.push(rel_dyn_section.name().to_string());
@@ -130,7 +172,14 @@ impl Program {
                 dynamic_section.set_dynstr_size(dynstr_section.size());
             }
 
-            let mut shstrtab_section = SectionType::ShStrTab(ShStrTabSection::new((section_names.iter().map(|name| name.len() + 1).sum::<usize>() + 1) as u32, section_names));
+            let mut shstrtab_section = SectionType::ShStrTab(ShStrTabSection::new(
+                (section_names
+                    .iter()
+                    .map(|name| name.len() + 1)
+                    .sum::<usize>()
+                    + 1) as u32,
+                section_names,
+            ));
             shstrtab_section.set_offset(current_offset);
             current_offset += shstrtab_section.size();
 
@@ -138,17 +187,14 @@ impl Program {
                 ProgramHeader::new_load(
                     elf_header.e_entry,
                     text_size,
-                    true,   // executable
+                    true, // executable
                 ),
                 ProgramHeader::new_load(
                     dynsym_section.offset(),
                     dynsym_section.size() + dynstr_section.size() + rel_dyn_section.size(),
                     false,
                 ),
-                ProgramHeader::new_dynamic(
-                    dynamic_section.offset(),
-                    dynamic_section.size(),
-                )
+                ProgramHeader::new_dynamic(dynamic_section.offset(), dynamic_section.size()),
             ]);
 
             sections.push(dynamic_section);
@@ -163,7 +209,13 @@ impl Program {
                 section_names.push(section.name().to_string());
             }
 
-            let mut shstrtab_section = ShStrTabSection::new(section_names.iter().map(|name| name.len() + 1).sum::<usize>() as u32, section_names);
+            let mut shstrtab_section = ShStrTabSection::new(
+                section_names
+                    .iter()
+                    .map(|name| name.len() + 1)
+                    .sum::<usize>() as u32,
+                section_names,
+            );
             shstrtab_section.set_offset(current_offset);
             current_offset += shstrtab_section.size();
             sections.push(SectionType::ShStrTab(shstrtab_section));
@@ -174,17 +226,17 @@ impl Program {
         elf_header.e_shoff = current_offset + padding;
         elf_header.e_shnum = sections.len() as u16;
         elf_header.e_shstrndx = sections.len() as u16 - 1;
-        
+
         Self {
             elf_header,
             program_headers,
             sections,
         }
     }
-    
+
     pub fn emit_bytecode(&self) -> Vec<u8> {
         let mut bytes = Vec::new();
-        
+
         // Emit ELF Header bytes
         bytes.extend(self.elf_header.bytecode());
 
@@ -213,7 +265,11 @@ impl Program {
     }
 
     pub fn parse_rodata(&self) -> Vec<(String, usize, String)> {
-        let rodata = self.sections.iter().find(|s| s.name() == ".rodata").unwrap();
+        let rodata = self
+            .sections
+            .iter()
+            .find(|s| s.name() == ".rodata")
+            .unwrap();
         if let SectionType::Data(data_section) = rodata {
             data_section.rodata()
         } else {
@@ -229,24 +285,25 @@ impl Program {
             panic!("Code section not found");
         }
     }
-    
+
     pub fn save_to_file(&self, input_path: &str) -> std::io::Result<()> {
         // Get the file stem (name without extension) from input path
         let path = Path::new(input_path);
-        let file_stem = path.file_stem()
+        let file_stem = path
+            .file_stem()
             .and_then(|s| s.to_str())
             .unwrap_or("output");
-        
+
         // Create the output file name with .so extension
         let output_path = format!("{}.so", file_stem);
-        
+
         // Get the bytecode
         let bytes = self.emit_bytecode();
-        
+
         // Write bytes to file
         let mut file = File::create(output_path)?;
         file.write_all(&bytes)?;
-        
+
         Ok(())
     }
 }

+ 68 - 85
crates/assembler/src/section.rs

@@ -1,22 +1,22 @@
 use crate::astnode::ASTNode;
-use crate::header::SectionHeader;
+use crate::astnode::ROData;
+use crate::debuginfo::DebugInfo;
 use crate::dynsym::DynamicSymbol;
 use crate::dynsym::RelDyn;
+use crate::header::SectionHeader;
 use crate::lexer::Token;
-use crate::debuginfo::DebugInfo;
 use std::collections::HashMap;
-use crate::astnode::ROData;
 
 // Base Section trait
 pub trait Section {
     fn name(&self) -> &str {
-        ".unknown"  // Default section name
+        ".unknown" // Default section name
     }
-    
+
     fn bytecode(&self) -> Vec<u8> {
-        Vec::new()  // Default empty bytecode
+        Vec::new() // Default empty bytecode
     }
-    
+
     // fn get_size(&self) -> u64
     fn size(&self) -> u64 {
         self.bytecode().len() as u64
@@ -70,7 +70,6 @@ impl CodeSection {
         self.offset = offset;
     }
 
-
     pub fn section_header_bytecode(&self) -> Vec<u8> {
         let flags = SectionHeader::SHF_ALLOC | SectionHeader::SHF_EXECINSTR;
         SectionHeader::new(
@@ -83,8 +82,9 @@ impl CodeSection {
             0,
             0,
             4,
-            0
-        ).bytecode()
+            0,
+        )
+        .bytecode()
     }
 }
 
@@ -141,10 +141,14 @@ impl DataSection {
 
     pub fn rodata(&self) -> Vec<(String, usize, String)> {
         let mut ro_data_labels = Vec::new();
-        for node in &self.nodes {    
-            if let ASTNode::ROData { rodata: ROData { name, args, .. }, offset } = node {
+        for node in &self.nodes {
+            if let ASTNode::ROData {
+                rodata: ROData { name, args, .. },
+                offset,
+            } = node
+            {
                 if let Some(Token::StringLiteral(str_literal, _)) = args.get(1) {
-                    ro_data_labels.push((name.clone(), offset.clone() as usize, str_literal.clone()));
+                    ro_data_labels.push((name.clone(), *offset as usize, str_literal.clone()));
                 }
             }
         }
@@ -152,7 +156,7 @@ impl DataSection {
     }
 
     pub fn section_header_bytecode(&self) -> Vec<u8> {
-        let flags = SectionHeader::SHF_ALLOC;  // Read-only data
+        let flags = SectionHeader::SHF_ALLOC; // Read-only data
         SectionHeader::new(
             7,
             SectionHeader::SHT_PROGBITS,
@@ -163,8 +167,9 @@ impl DataSection {
             0,
             0,
             1,
-            0
-        ).bytecode()
+            0,
+        )
+        .bytecode()
     }
 }
 
@@ -193,7 +198,7 @@ impl Section for DataSection {
     }
 }
 
-#[derive(Debug)]
+#[derive(Debug, Default)]
 pub struct NullSection {
     name: String,
     offset: u64,
@@ -201,27 +206,12 @@ pub struct NullSection {
 
 impl NullSection {
     pub fn new() -> Self {
-        Self {
-            name: String::from(""),
-            offset: 0,
-        }
+        Self::default()
     }
 
     pub fn section_header_bytecode(&self) -> Vec<u8> {
-        SectionHeader::new(
-            0,
-            SectionHeader::SHT_NULL,
-            0,
-            0,
-            0,
-            0,
-            0,
-            0,
-            0,
-            0
-        ).bytecode()
+        SectionHeader::new(0, SectionHeader::SHT_NULL, 0, 0, 0, 0, 0, 0, 0, 0).bytecode()
     }
-
 }
 
 impl Section for NullSection {
@@ -265,10 +255,10 @@ impl ShStrTabSection {
             0,
             0,
             1,
-            0
-        ).bytecode()
+            0,
+        )
+        .bytecode()
     }
-
 }
 
 impl Section for ShStrTabSection {
@@ -280,7 +270,7 @@ impl Section for ShStrTabSection {
         let mut bytes = Vec::new();
         // First byte is null
         bytes.push(0);
-        
+
         // Add each non-empty section name with null terminator
         for name in &self.section_names {
             if !name.is_empty() {
@@ -293,14 +283,14 @@ impl Section for ShStrTabSection {
         while bytes.len() % 8 != 0 {
             bytes.push(0);
         }
-        
+
         bytes
     }
-    
+
     fn size(&self) -> u64 {
         // Calculate section header offset
         let mut section_name_size = 0;
-        
+
         for name in &self.section_names {
             if !name.is_empty() {
                 section_name_size += 1 + name.len();
@@ -308,8 +298,8 @@ impl Section for ShStrTabSection {
         }
 
         section_name_size += 1; // null section
-        
-        section_name_size as u64  // Return the calculated size
+
+        section_name_size as u64 // Return the calculated size
     }
 }
 
@@ -380,10 +370,10 @@ impl DynamicSection {
             5,
             0,
             8,
-            16
-        ).bytecode()
+            16,
+        )
+        .bytecode()
     }
-
 }
 
 impl Section for DynamicSection {
@@ -393,62 +383,58 @@ impl Section for DynamicSection {
 
     fn bytecode(&self) -> Vec<u8> {
         let mut bytes = Vec::new();
-        
+
         // DT_FLAGS (DF_TEXTREL)
         bytes.extend_from_slice(&0x1e_u64.to_le_bytes());
         bytes.extend_from_slice(&0x04_u64.to_le_bytes());
-        
+
         // DT_REL
         bytes.extend_from_slice(&0x11_u64.to_le_bytes());
         bytes.extend_from_slice(&self.rel_offset.to_le_bytes());
-        
+
         // DT_RELSZ
         bytes.extend_from_slice(&0x12_u64.to_le_bytes());
         bytes.extend_from_slice(&self.rel_size.to_le_bytes());
-        
+
         // DT_RELENT
         bytes.extend_from_slice(&0x13_u64.to_le_bytes());
-        bytes.extend_from_slice(&0x10_u64.to_le_bytes());  // Constant: 16 bytes per entry
-        
+        bytes.extend_from_slice(&0x10_u64.to_le_bytes()); // Constant: 16 bytes per entry
+
         // DT_RELCOUNT: number of relative relocation entries
         if self.rel_count > 0 {
-            bytes.extend_from_slice(&0x6fffff_fa_u64.to_le_bytes());
+            bytes.extend_from_slice(&0x6fff_fffa_u64.to_le_bytes());
             bytes.extend_from_slice(&self.rel_count.to_le_bytes());
         }
-        
+
         // DT_SYMTAB
         bytes.extend_from_slice(&0x06_u64.to_le_bytes());
         bytes.extend_from_slice(&self.dynsym_offset.to_le_bytes());
-        
+
         // DT_SYMENT
         bytes.extend_from_slice(&0x0b_u64.to_le_bytes());
-        bytes.extend_from_slice(&0x18_u64.to_le_bytes());  // Constant: 24 bytes per symbol
-        
+        bytes.extend_from_slice(&0x18_u64.to_le_bytes()); // Constant: 24 bytes per symbol
+
         // DT_STRTAB
         bytes.extend_from_slice(&0x05_u64.to_le_bytes());
         bytes.extend_from_slice(&self.dynstr_offset.to_le_bytes());
-        
+
         // DT_STRSZ
         bytes.extend_from_slice(&0x0a_u64.to_le_bytes());
         bytes.extend_from_slice(&self.dynstr_size.to_le_bytes());
-        
+
         // DT_TEXTREL
         bytes.extend_from_slice(&0x16_u64.to_le_bytes());
         bytes.extend_from_slice(&0x00_u64.to_le_bytes());
-        
+
         // DT_NULL
         bytes.extend_from_slice(&0x00_u64.to_le_bytes());
         bytes.extend_from_slice(&0x00_u64.to_le_bytes());
-        
+
         bytes
     }
 
     fn size(&self) -> u64 {
-        if self.rel_count > 0 {
-            return 11 * 16;
-        } else {
-            return 10 * 16;
-        }
+        if self.rel_count > 0 { 11 * 16 } else { 10 * 16 }
     }
 }
 
@@ -478,17 +464,17 @@ impl DynStrSection {
         SectionHeader::new(
             self.name_offset,
             SectionHeader::SHT_STRTAB,
-            SectionHeader::SHF_ALLOC,  // Allocatable section
+            SectionHeader::SHF_ALLOC, // Allocatable section
             self.offset,
             self.offset,
             self.size(),
             0,
             0,
             1,
-            0
-        ).bytecode()
+            0,
+        )
+        .bytecode()
     }
-
 }
 
 impl Section for DynStrSection {
@@ -500,7 +486,7 @@ impl Section for DynStrSection {
         let mut bytes = Vec::new();
         // First byte is null
         bytes.push(0);
-        
+
         // Add each symbol name with null terminator
         for name in &self.symbol_names {
             bytes.extend(name.as_bytes());
@@ -512,10 +498,12 @@ impl Section for DynStrSection {
         }
         bytes
     }
-    
+
     fn size(&self) -> u64 {
         // Calculate total size: initial null byte + sum of (name lengths + null terminators)
-        let mut size = 1 + self.symbol_names.iter()
+        let mut size = 1 + self
+            .symbol_names
+            .iter()
             .map(|name| name.len() + 1)
             .sum::<usize>();
         // add padding to make size multiple of 8
@@ -560,10 +548,10 @@ impl DynSymSection {
             5,
             1,
             8,
-            24
-        ).bytecode()
+            24,
+        )
+        .bytecode()
     }
-
 }
 
 impl Section for DynSymSection {
@@ -583,8 +571,7 @@ impl Section for DynSymSection {
         }
         bytes
     }
-    
-}   
+}
 
 #[derive(Debug)]
 pub struct RelDynSection {
@@ -624,10 +611,10 @@ impl RelDynSection {
             4,
             0,
             8,
-            16
-        ).bytecode()
+            16,
+        )
+        .bytecode()
     }
-
 }
 
 impl Section for RelDynSection {
@@ -646,8 +633,6 @@ impl Section for RelDynSection {
         }
         bytes
     }
-
-
 }
 
 #[derive(Debug)]
@@ -741,5 +726,3 @@ impl SectionType {
         }
     }
 }
-
-

+ 30 - 25
crates/assembler/src/wasm.rs

@@ -1,10 +1,10 @@
-use wasm_bindgen::prelude::*;
-use serde::Serialize;
-use serde_wasm_bindgen::to_value;
-use std::ops::Range;
 use crate::lexer::tokenize;
 use crate::parser::Parser;
 use crate::program::Program;
+use serde::Serialize;
+use serde_wasm_bindgen::to_value;
+use std::ops::Range;
+use wasm_bindgen::prelude::*;
 
 #[derive(Serialize)]
 struct CompileErrorInfo {
@@ -18,7 +18,7 @@ fn span_to_line_col(source_code: &str, span: &Range<usize>) -> (usize, usize) {
     // Convert byte position to line number (1-based)
     let mut line = 1;
     let mut current_pos = 0;
-    
+
     for (i, c) in source_code.char_indices() {
         if i >= span.start {
             break;
@@ -28,26 +28,29 @@ fn span_to_line_col(source_code: &str, span: &Range<usize>) -> (usize, usize) {
             current_pos = i + 1;
         }
     }
-    
+
     // Calculate column number (1-based) by finding the start of the line
     let column = span.start - current_pos + 1;
-    
+
     (line, column)
-} 
+}
 
 #[wasm_bindgen]
 pub fn assemble(source: &str) -> Result<Vec<u8>, JsValue> {
     let tokens = match tokenize(source) {
         Ok(tokens) => tokens,
         Err(errors) => {
-            let compile_errors : Vec<CompileErrorInfo> = errors.iter().map(|e| {
-                let (line, col) = span_to_line_col(source, e.span());
-                CompileErrorInfo { 
-                    error: e.to_string(), 
-                    line: line.to_string(), 
-                    col: col.to_string() 
-                }
-            }).collect();
+            let compile_errors: Vec<CompileErrorInfo> = errors
+                .iter()
+                .map(|e| {
+                    let (line, col) = span_to_line_col(source, e.span());
+                    CompileErrorInfo {
+                        error: e.to_string(),
+                        line: line.to_string(),
+                        col: col.to_string(),
+                    }
+                })
+                .collect();
             return Err(to_value(&compile_errors).unwrap());
         }
     };
@@ -55,19 +58,21 @@ pub fn assemble(source: &str) -> Result<Vec<u8>, JsValue> {
     let parse_result = match parser.parse() {
         Ok(program) => program,
         Err(errors) => {
-            let compile_errors : Vec<CompileErrorInfo> = errors.iter().map(|e| {
-                let (line, col) = span_to_line_col(source, e.span());
-                CompileErrorInfo { 
-                    error: e.to_string(), 
-                    line: line.to_string(), 
-                    col: col.to_string() 
-                }
-            }).collect();
+            let compile_errors: Vec<CompileErrorInfo> = errors
+                .iter()
+                .map(|e| {
+                    let (line, col) = span_to_line_col(source, e.span());
+                    CompileErrorInfo {
+                        error: e.to_string(),
+                        line: line.to_string(),
+                        col: col.to_string(),
+                    }
+                })
+                .collect();
             return Err(to_value(&compile_errors).unwrap());
         }
     };
     let program = Program::from_parse_result(parse_result);
     let bytecode = program.emit_bytecode();
     Ok(bytecode)
-
 }

+ 0 - 1
crates/assembler/tests/regression.rs

@@ -3,7 +3,6 @@ use std::env;
 use std::fs;
 use std::path::PathBuf;
 
-use blake3;
 use serde::{Deserialize, Serialize};
 
 #[derive(Debug, Deserialize, Serialize)]

+ 5 - 4
crates/common/src/instruction.rs

@@ -1,15 +1,16 @@
 use crate::opcode::Opcode;
 
-use std::ops::Range;
+use core::fmt;
+use core::ops::Range;
 
 #[derive(Debug, Clone)]
 pub struct Register {
     pub n: u8,
 }
 
-impl Register {
-    pub fn to_string(&self) -> String {
-        format!("r{}", self.n)
+impl fmt::Display for Register {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        write!(f, "r{}", self.n)
     }
 }
 

+ 15 - 5
crates/common/src/opcode.rs

@@ -1,3 +1,6 @@
+use core::fmt;
+use core::str::FromStr;
+
 use num_derive::FromPrimitive;
 
 #[derive(Debug, Clone, Copy, PartialEq, FromPrimitive)]
@@ -168,8 +171,10 @@ pub enum Opcode {
     Exit,
 }
 
-impl Opcode {
-    pub fn from_str(s: &str) -> Result<Self, &'static str> {
+impl FromStr for Opcode {
+    type Err = &'static str;
+
+    fn from_str(s: &str) -> Result<Self, Self::Err> {
         match s.to_lowercase().as_str() {
             "lddw" => Ok(Opcode::Lddw),
             "ldxb" => Ok(Opcode::Ldxb),
@@ -243,7 +248,15 @@ impl Opcode {
             _ => Err("Invalid opcode"),
         }
     }
+}
 
+impl fmt::Display for Opcode {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        write!(f, "{}", self.to_str())
+    }
+}
+
+impl Opcode {
     pub fn from_u8(u: u8) -> Option<Self> {
         match u {
             0x18 => Some(Opcode::Lddw),
@@ -607,7 +620,4 @@ impl Opcode {
             Opcode::Exit => "exit",
         }
     }
-    pub fn to_string(&self) -> String {
-        self.to_str().to_string()
-    }
 }

+ 3 - 3
crates/disassembler/src/program.rs

@@ -17,8 +17,8 @@ pub struct Program {
 
 impl Program {
     pub fn from_bytes(b: &[u8]) -> Result<Self, DisassemblerError> {
-        let elf_file =
-            ElfFile64::<Endianness>::parse(b).map_err(|_| DisassemblerError::NonStandardElfHeader)?;
+        let elf_file = ElfFile64::<Endianness>::parse(b)
+            .map_err(|_| DisassemblerError::NonStandardElfHeader)?;
 
         // Parse elf header.
         let elf_header = ELFHeader::from_elf_file(&elf_file)?;
@@ -30,7 +30,7 @@ impl Program {
         let (section_headers, section_header_entries) = SectionHeader::from_elf_file(&elf_file)?;
 
         Ok(Self {
-            elf_header: elf_header,
+            elf_header,
             program_headers,
             section_headers,
             section_header_entries,

+ 24 - 19
src/commands/build.rs

@@ -6,12 +6,12 @@ use rand::rngs::OsRng;
 use std::fs;
 
 use anyhow::{Error, Result};
-use std::path::Path;
-use std::time::Instant;
-use std::fs::create_dir_all;
+use codespan_reporting::diagnostic::{Diagnostic, Label};
 use codespan_reporting::files::SimpleFile;
 use codespan_reporting::term;
-use codespan_reporting::diagnostic::{Diagnostic, Label};
+use std::fs::create_dir_all;
+use std::path::Path;
+use std::time::Instant;
 use termcolor::{ColorChoice, StandardStream};
 
 pub trait AsDiagnostic {
@@ -23,17 +23,21 @@ impl AsDiagnostic for CompileError {
     fn to_diagnostic(&self) -> Diagnostic<()> {
         match self {
             // Show both the redefinition and the original definition
-            CompileError::DuplicateLabel { span, original_span, .. } => {
-                Diagnostic::error()
-                    .with_message(self.to_string())
-                    .with_labels(vec![
-                        Label::primary((), span.start..span.end).with_message(self.label()),
-                        Label::secondary((), original_span.start..original_span.end).with_message("previous definition is here"),
-                    ])
-            }
+            CompileError::DuplicateLabel {
+                span,
+                original_span,
+                ..
+            } => Diagnostic::error()
+                .with_message(self.to_string())
+                .with_labels(vec![
+                    Label::primary((), span.start..span.end).with_message(self.label()),
+                    Label::secondary((), original_span.start..original_span.end)
+                        .with_message("previous definition is here"),
+                ]),
             _ => Diagnostic::error()
                 .with_message(self.to_string())
-                .with_labels(vec![Label::primary((), self.span().start..self.span().end).with_message(self.label())]),
+                .with_labels(vec![Label::primary((), self.span().start..self.span().end)
+                    .with_message(self.label())]),
         }
     }
 }
@@ -50,8 +54,8 @@ pub fn build() -> Result<()> {
     fn compile_assembly(src: &str, deploy: &str) -> Result<()> {
         let source_code = std::fs::read_to_string(src).unwrap();
         let file = SimpleFile::new(src.to_string(), source_code.clone());
-        
-        // assemble <filename>.s to bytecode 
+
+        // assemble <filename>.s to bytecode
         let bytecode = match assemble(&source_code) {
             Ok(bytecode) => bytecode,
             Err(errors) => {
@@ -64,15 +68,16 @@ pub fn build() -> Result<()> {
                 return Err(Error::msg("Compilation failed"));
             }
         };
-        
+
         // write bytecode to <filename>.so
-        let output_path = Path::new(deploy)
-            .join(Path::new(src)
+        let output_path = Path::new(deploy).join(
+            Path::new(src)
                 .file_name()
                 .unwrap()
                 .to_str()
                 .unwrap()
-                .replace(".s", ".so"));
+                .replace(".s", ".so"),
+        );
 
         std::fs::write(output_path, bytecode)?;
         Ok(())

+ 17 - 14
tests/test_memo.rs

@@ -1,26 +1,29 @@
 mod utils;
 
-use utils::{TestEnv, init_project, verify_project_structure, verify_so_files, run_tests, update_assembly_file, run_build};
+use utils::{
+    init_project, run_build, update_assembly_file, verify_project_structure, verify_so_files,
+    TestEnv,
+};
 
 #[test]
 fn test_memo_project_e2e() {
     let env = TestEnv::new("memo");
-    
+
     // Step 1: Initialize the memo project
     init_project(&env, "memo");
-    
+
     // Step 2: Verify project structure
     verify_project_structure(&env, "memo");
-    
+
     // Step 3: Run build
     run_build(&env);
-    
+
     // Step 4: Verify .so files were created
     verify_so_files(&env);
-    
+
     // Step 5: Run tests
     // run_tests(&env);
-    
+
     // Step 6: Clean up
     env.cleanup();
     println!("🎉 All tests passed! Memo project E2E test completed successfully.");
@@ -29,13 +32,13 @@ fn test_memo_project_e2e() {
 #[test]
 fn test_memo_project_e2e_second() {
     let env = TestEnv::new("memo2");
-    
+
     // Step 1: Initialize the memo2 project
     init_project(&env, "memo2");
-    
+
     // Step 2: Verify project structure
     verify_project_structure(&env, "memo2");
-    
+
     // Step 3: Update the memo2.s content to the specified content
     let new_memo_content = r#".equ NUM_ACCOUNTS, 0x00
 .equ DATA_LEN, 0x08
@@ -49,16 +52,16 @@ entrypoint:
   call sol_log_
   exit"#;
     update_assembly_file(&env, "memo2", new_memo_content);
-    
+
     // Step 4: Run build
     run_build(&env);
-    
+
     // Step 5: Verify .so files were created
     verify_so_files(&env);
-    
+
     // Step 6: Run tests
     // run_tests(&env);
-    
+
     // Step 7: Clean up
     env.cleanup();
     println!("🎉 Second test passed! Memo2 project E2E test completed successfully.");

+ 67 - 33
tests/utils.rs

@@ -23,9 +23,9 @@ impl Drop for EnvVarGuard {
     }
 }
 
-use std::process::{Command, Output};
 use std::fs;
 use std::path::PathBuf;
+use std::process::{Command, Output};
 
 /// Test environment setup for SBPF tests
 pub struct TestEnv {
@@ -42,18 +42,18 @@ impl TestEnv {
         let sbpf_path = current_dir.join("target").join("debug").join("sbpf");
         let guard = EnvVarGuard::new("SBPF_BIN", sbpf_path.to_string_lossy());
         let sbpf_bin = std::env::var("SBPF_BIN").expect("SBPF_BIN not set");
-        
+
         let temp_dir = std::env::temp_dir().join(format!("sbpf_test_{}_e2e", project_name));
         if temp_dir.exists() {
             fs::remove_dir_all(&temp_dir).expect("Failed to remove existing test directory");
         }
         fs::create_dir_all(&temp_dir).expect("Failed to create test directory");
-        
+
         let project_dir = temp_dir.join(project_name);
-        
+
         println!("Using test directory: {:?}", temp_dir);
         println!("Using project directory: {:?}", project_dir);
-        
+
         Self {
             sbpf_bin,
             temp_dir,
@@ -61,7 +61,7 @@ impl TestEnv {
             _guard: guard,
         }
     }
-    
+
     /// Clean up the test environment
     pub fn cleanup(self) {
         fs::remove_dir_all(&self.temp_dir).expect("Failed to remove test directory");
@@ -70,32 +70,37 @@ impl TestEnv {
 
 /// Run a command and return the output, panicking on failure
 pub fn run_command(cmd: &mut Command, operation_name: &str) -> Output {
-    let output = cmd.output().expect(&format!("Failed to execute {}", operation_name));
-    
+    let output = cmd
+        .output()
+        .unwrap_or_else(|_| panic!("Failed to execute {}", operation_name));
+
     if !output.status.success() {
         let stderr = String::from_utf8_lossy(&output.stderr);
         let stdout = String::from_utf8_lossy(&output.stdout);
-        panic!("{} failed:\nSTDOUT: {}\nSTDERR: {}", operation_name, stdout, stderr);
+        panic!(
+            "{} failed:\nSTDOUT: {}\nSTDERR: {}",
+            operation_name, stdout, stderr
+        );
     }
-    
+
     println!("✅ {} completed successfully", operation_name);
     println!("STDOUT: {}", String::from_utf8_lossy(&output.stdout));
-    
+
     output
 }
 
 /// Initialize a new SBPF project
 pub fn init_project(env: &TestEnv, project_name: &str) {
     println!("Step 1: Initializing {} project...", project_name);
-    
+
     let init_output = run_command(
         Command::new(&env.sbpf_bin)
             .current_dir(&env.temp_dir)
             .arg("init")
             .arg(project_name),
-        &format!("target/debug/sbpf init {}", project_name)
+        &format!("target/debug/sbpf init {}", project_name),
     );
-    
+
     println!("✅ Project initialized successfully");
     println!("STDOUT: {}", String::from_utf8_lossy(&init_output.stdout));
 }
@@ -103,26 +108,47 @@ pub fn init_project(env: &TestEnv, project_name: &str) {
 /// Verify that the project structure is correct
 pub fn verify_project_structure(env: &TestEnv, project_name: &str) {
     let project_dir = &env.project_dir;
-    
-    assert!(project_dir.join("src").exists(), "src directory should exist");
-    assert!(project_dir.join("deploy").exists(), "deploy directory should exist");
-    assert!(project_dir.join(format!("src/{}", project_name)).exists(), 
-            "src/{} directory should exist", project_name);
-    assert!(project_dir.join(format!("src/{}/{}.s", project_name, project_name)).exists(), 
-            "src/{}/{}.s should exist", project_name, project_name);
-    assert!(project_dir.join("src/lib.rs").exists(), "src/lib.rs should exist");
-    assert!(project_dir.join("Cargo.toml").exists(), "Cargo.toml should exist");
+
+    assert!(
+        project_dir.join("src").exists(),
+        "src directory should exist"
+    );
+    assert!(
+        project_dir.join("deploy").exists(),
+        "deploy directory should exist"
+    );
+    assert!(
+        project_dir.join(format!("src/{}", project_name)).exists(),
+        "src/{} directory should exist",
+        project_name
+    );
+    assert!(
+        project_dir
+            .join(format!("src/{}/{}.s", project_name, project_name))
+            .exists(),
+        "src/{}/{}.s should exist",
+        project_name,
+        project_name
+    );
+    assert!(
+        project_dir.join("src/lib.rs").exists(),
+        "src/lib.rs should exist"
+    );
+    assert!(
+        project_dir.join("Cargo.toml").exists(),
+        "Cargo.toml should exist"
+    );
 }
 
 /// Run build on the project
 pub fn run_build(env: &TestEnv) {
     println!("Step 3: Running build...");
-    
+
     run_command(
         Command::new(&env.sbpf_bin)
             .current_dir(&env.project_dir)
             .arg("build"),
-        "target/debug/sbpf build"
+        "target/debug/sbpf build",
     );
 }
 
@@ -130,38 +156,46 @@ pub fn run_build(env: &TestEnv) {
 pub fn verify_so_files(env: &TestEnv) {
     let deploy_dir = env.project_dir.join("deploy");
     assert!(deploy_dir.exists(), "deploy directory should exist");
-    
+
     let so_files: Vec<_> = fs::read_dir(&deploy_dir)
         .expect("Failed to read deploy directory")
         .filter_map(|entry| entry.ok())
         .filter(|entry| {
-            entry.path()
+            entry
+                .path()
                 .extension()
                 .and_then(|ext| ext.to_str())
                 .map(|ext| ext == "so")
                 .unwrap_or(false)
         })
         .collect();
-    
-    assert!(!so_files.is_empty(), "At least one .so file should be created in deploy directory");
+
+    assert!(
+        !so_files.is_empty(),
+        "At least one .so file should be created in deploy directory"
+    );
     println!("Found {} .so file(s) in deploy directory", so_files.len());
 }
 
 /// Run tests on the project
+#[allow(dead_code)]
 pub fn run_tests(env: &TestEnv) {
     println!("Step 4: Running tests...");
-    
+
     run_command(
         Command::new(&env.sbpf_bin)
             .current_dir(&env.project_dir)
             .arg("test"),
-        "target/debug/sbpf test"
+        "target/debug/sbpf test",
     );
 }
 
 /// Update the project's assembly file content
 pub fn update_assembly_file(env: &TestEnv, project_name: &str, content: &str) {
-    let assembly_path = env.project_dir.join(format!("src/{}/{}.s", project_name, project_name));
-    fs::write(&assembly_path, content).expect(&format!("Failed to write new {}.s content", project_name));
+    let assembly_path = env
+        .project_dir
+        .join(format!("src/{}/{}.s", project_name, project_name));
+    fs::write(&assembly_path, content)
+        .unwrap_or_else(|_| panic!("Failed to write new {}.s content", project_name));
     println!("✅ Updated {}.s with specified content", project_name);
 }

Algúns arquivos non se mostraron porque demasiados arquivos cambiaron neste cambio