1use anyhow::Result;
2
3pub mod parser;
5
6pub mod errors;
8pub mod macros;
9pub mod messages;
10
11pub mod ast;
13pub mod astnode;
14pub mod dynsym;
15pub mod syscall;
16
17pub mod header;
19pub mod program;
20pub mod section;
21
22pub mod debuginfo;
24
25#[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}