sbpf_assembler/
lib.rs

1use anyhow::Result;
2
3// Parser
4pub mod parser;
5
6// Error handling and diagnostics
7pub mod errors;
8pub mod macros;
9pub mod messages;
10
11// Intermediate Representation
12pub mod ast;
13pub mod astnode;
14pub mod dynsym;
15pub mod syscall;
16
17// ELF header, program, section
18pub mod header;
19pub mod program;
20pub mod section;
21
22// Debug info
23pub mod debuginfo;
24
25// WASM bindings
26#[cfg(target_arch = "wasm32")]
27pub mod wasm;
28
29pub use self::{
30    errors::CompileError,
31    parser::{ParseResult, Token, parse},
32    program::Program,
33};
34
35pub fn assemble(source: &str) -> Result<Vec<u8>, Vec<CompileError>> {
36    let parse_result = match parse(source) {
37        Ok(result) => result,
38        Err(errors) => {
39            return Err(errors);
40        }
41    };
42    let program = Program::from_parse_result(parse_result);
43    let bytecode = program.emit_bytecode();
44    Ok(bytecode)
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn test_assemble_success() {
53        let source = "exit";
54        let result = assemble(source);
55        assert!(result.is_ok());
56        let bytecode = result.unwrap();
57        assert!(!bytecode.is_empty());
58    }
59
60    #[test]
61    fn test_assemble_parse_error() {
62        let source = "invalid_xyz";
63        let result = assemble(source);
64        assert!(result.is_err());
65    }
66
67    #[test]
68    fn test_assemble_with_equ_directive() {
69        let source = r#"
70        .globl entrypoint
71        .equ MY_CONST, 42
72        entrypoint:
73            mov64 r1, MY_CONST
74            exit
75        "#;
76        let result = assemble(source);
77        assert!(result.is_ok());
78    }
79
80    #[test]
81    fn test_assemble_duplicate_label_error() {
82        let source = r#"
83        .globl entrypoint
84        entrypoint:
85            mov64 r1, 1
86        entrypoint:
87            exit
88        "#;
89        let result = assemble(source);
90        assert!(result.is_err());
91        let errors = result.unwrap_err();
92        assert!(!errors.is_empty());
93    }
94
95    #[test]
96    fn test_assemble_extern_directive() {
97        let source = r#"
98        .globl entrypoint
99        .extern my_extern_symbol
100        entrypoint:
101            exit
102        "#;
103        let result = assemble(source);
104        assert!(result.is_ok());
105    }
106
107    #[test]
108    fn test_assemble_rodata_section() {
109        let source = r#"
110        .globl entrypoint
111        .rodata
112        my_data: .ascii "hello"
113        .text
114        entrypoint:
115            exit
116        "#;
117        let result = assemble(source);
118        assert!(result.is_ok());
119    }
120
121    #[test]
122    fn test_assemble_rodata_byte() {
123        let source = r#"
124        .globl entrypoint
125        .rodata
126        my_byte: .byte 0x42
127        .text
128        entrypoint:
129            exit
130        "#;
131        let result = assemble(source);
132        assert!(result.is_ok());
133    }
134
135    #[test]
136    fn test_assemble_rodata_multiple_bytes() {
137        let source = r#"
138        .globl entrypoint
139        .rodata
140        my_bytes: .byte 0x01, 0x02, 0x03, 0x04
141        .text
142        entrypoint:
143            exit
144        "#;
145        let result = assemble(source);
146        assert!(result.is_ok());
147    }
148
149    #[test]
150    fn test_assemble_rodata_mixed() {
151        let source = r#"
152        .globl entrypoint
153        .rodata
154        data1: .byte 0x42
155        data2: .ascii "test"
156        .text
157        entrypoint:
158            exit
159        "#;
160        let result = assemble(source);
161        assert!(result.is_ok());
162    }
163
164    #[test]
165    fn test_assemble_jump_operations() {
166        let source = r#"
167        .globl entrypoint
168        entrypoint:
169            jeq r1, 0, +1
170            ja +2
171        target:
172            jne r1, r2, target
173            exit
174        "#;
175        let result = assemble(source);
176        assert!(result.is_ok());
177    }
178
179    #[test]
180    fn test_assemble_offset_expression() {
181        let source = r#"
182        .globl entrypoint
183        .equ BASE, 100
184        entrypoint:
185            mov64 r1, BASE+10
186            exit
187        "#;
188        let result = assemble(source);
189        assert!(result.is_ok());
190    }
191
192    #[test]
193    fn test_assemble_equ_expression() {
194        let source = r#"
195        .globl entrypoint
196        .equ BASE, 100
197        .equ OFFSET, 20
198        .equ COMPUTED, BASE
199        entrypoint:
200            mov64 r1, BASE
201            mov64 r2, OFFSET
202            mov64 r3, COMPUTED
203            exit
204        "#;
205        let result = assemble(source);
206        assert!(result.is_ok());
207    }
208}