@@ -3,18 +3,15 @@ use std::fs::{self, File};
33use std:: io:: { self , BufRead , Write } ;
44use std:: path:: Path ;
55use std:: process;
6-
76use cranelift:: prelude:: * ;
87use cranelift_codegen:: ir:: Function ;
98use cranelift_codegen:: isa;
109use cranelift_codegen:: settings;
1110use cranelift_frontend:: { FunctionBuilder , FunctionBuilderContext } ;
12- use cranelift_module:: { DataContext , Linkage , Module } ;
11+ use cranelift_module:: { DataDescription , Linkage , Module } ;
1312use cranelift_object:: { ObjectBuilder , ObjectModule } ;
1413use subprocess:: { Exec , PopenError } ;
15-
1614const HACKER_DIR : & str = "~/.hacker-lang" ;
17-
1815fn expand_home ( path : & str ) -> String {
1916 if path. starts_with ( "~/" ) {
2017 if let Some ( home) = std:: env:: var_os ( "HOME" ) {
@@ -23,7 +20,6 @@ fn expand_home(path: &str) -> String {
2320 }
2421 path. to_string ( )
2522}
26-
2723fn parse_hacker_file ( path : & Path , verbose : bool ) -> io:: Result < ( Vec < String > , Vec < String > , Vec < ( String , String ) > , Vec < String > , Vec < String > , Vec < String > ) > {
2824 let file = File :: open ( path) ?;
2925 let mut deps = Vec :: new ( ) ;
@@ -35,15 +31,13 @@ fn parse_hacker_file(path: &Path, verbose: bool) -> io::Result<(Vec<String>, Vec
3531 let mut in_config = false ;
3632 let mut config_lines = Vec :: new ( ) ;
3733 let mut line_num = 0 ;
38-
3934 for line in io:: BufReader :: new ( file) . lines ( ) {
4035 line_num += 1 ;
4136 let line = line?;
4237 let line = line. trim ( ) . to_string ( ) ;
4338 if line. is_empty ( ) {
4439 continue ;
4540 }
46-
4741 if line == "[" {
4842 if in_config {
4943 errors. push ( format ! ( "Line {}: Nested config section" , line_num) ) ;
@@ -58,12 +52,10 @@ fn parse_hacker_file(path: &Path, verbose: bool) -> io::Result<(Vec<String>, Vec
5852 in_config = false ;
5953 continue ;
6054 }
61-
6255 if in_config {
6356 config_lines. push ( line) ;
6457 continue ;
6558 }
66-
6759 if line. starts_with ( "//" ) {
6860 let dep = line[ 2 ..] . trim ( ) . to_string ( ) ;
6961 if dep. is_empty ( ) {
@@ -117,10 +109,6 @@ fn parse_hacker_file(path: &Path, verbose: bool) -> io::Result<(Vec<String>, Vec
117109 let parts: Vec < String > = line[ 1 ..] . split ( '>' ) . map ( |s| s. trim ( ) . to_string ( ) ) . collect ( ) ;
118110 if parts. len ( ) == 2 {
119111 if let Ok ( num) = parts[ 0 ] . parse :: < usize > ( ) {
120- if num < 0 {
121- errors. push ( format ! ( "Line {}: Negative loop count" , line_num) ) ;
122- continue ;
123- }
124112 let cmd_parts: Vec < String > = parts[ 1 ] . split ( '!' ) . map ( |s| s. trim ( ) . to_string ( ) ) . collect ( ) ;
125113 let cmd = cmd_parts[ 0 ] . clone ( ) ;
126114 if cmd. is_empty ( ) {
@@ -164,11 +152,9 @@ fn parse_hacker_file(path: &Path, verbose: bool) -> io::Result<(Vec<String>, Vec
164152 errors. push ( format ! ( "Line {}: Invalid syntax" , line_num) ) ;
165153 }
166154 }
167-
168155 if in_config {
169156 errors. push ( "Unclosed config section" . to_string ( ) ) ;
170157 }
171-
172158 if verbose {
173159 println ! ( "System Deps: {:?}" , deps) ;
174160 println ! ( "Custom Libs: {:?}" , libs) ;
@@ -179,135 +165,119 @@ fn parse_hacker_file(path: &Path, verbose: bool) -> io::Result<(Vec<String>, Vec
179165 println ! ( "Errors: {:?}" , errors) ;
180166 }
181167 }
182-
183168 Ok ( ( deps, libs, vars, cmds, includes, errors) )
184169}
185-
186170fn generate_check_cmd ( dep : & str ) -> String {
187171 if dep == "sudo" {
188172 return String :: new ( ) ;
189173 }
190174 format ! ( "command -v {} &> /dev/null || (sudo apt update && sudo apt install -y {})" , dep, dep)
191175}
192-
193176fn main ( ) -> io:: Result < ( ) > {
194- let mut args: Vec < String > = env:: args ( ) . collect ( ) ;
177+ let args: Vec < String > = env:: args ( ) . collect ( ) ;
195178 if args. len ( ) < 3 || args. len ( ) > 4 {
196179 eprintln ! ( "Usage: hacker-compiler <input.hacker> <output> [--verbose]" ) ;
197180 process:: exit ( 1 ) ;
198181 }
199182 let verbose = args. len ( ) == 4 && args[ 3 ] == "--verbose" ;
200183 let input_path = Path :: new ( & args[ 1 ] ) ;
201184 let output_path = Path :: new ( & args[ 2 ] ) ;
202-
203- let ( mut deps, _libs, vars, mut cmds, _includes, errors) = parse_hacker_file ( input_path, verbose) ?;
185+ let ( deps, _libs, vars, cmds, _includes, errors) = parse_hacker_file ( input_path, verbose) ?;
204186 if !errors. is_empty ( ) {
205187 for err in errors {
206188 eprintln ! ( "{}" , err) ;
207189 }
208190 process:: exit ( 1 ) ;
209191 }
210-
192+ let mut final_cmds = Vec :: new ( ) ;
211193 for dep in deps {
212194 let check = generate_check_cmd ( & dep) ;
213195 if !check. is_empty ( ) {
214- cmds . insert ( 0 , check) ;
196+ final_cmds . push ( check) ;
215197 }
216198 }
217-
199+ final_cmds . extend ( cmds ) ;
218200 let flag_builder = settings:: builder ( ) ;
219201 let flags = settings:: Flags :: new ( flag_builder) ;
220-
221202 let triple = target_lexicon:: Triple :: host ( ) ;
222203 let isa_builder = isa:: lookup ( triple) . expect ( "Host not supported" ) ;
223204 let isa = isa_builder. finish ( flags) . expect ( "ISA build failed" ) ;
224-
225- let builder = ObjectBuilder :: new ( isa, output_path. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_vec ( ) , cranelift_module:: default_libcall_names ( ) ) . expect ( "Failed to create ObjectBuilder" ) ;
205+ let builder = ObjectBuilder :: new (
206+ isa,
207+ output_path. file_stem ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . as_bytes ( ) . to_vec ( ) ,
208+ cranelift_module:: default_libcall_names ( ) ,
209+ ) . expect ( "Failed to create ObjectBuilder" ) ;
226210 let mut module = ObjectModule :: new ( builder) ;
227-
228211 let pointer_type = module. target_config ( ) . pointer_type ( ) ;
229212 let mut sig_system = module. make_signature ( ) ;
230213 sig_system. params . push ( AbiParam :: new ( pointer_type) ) ;
231214 sig_system. returns . push ( AbiParam :: new ( types:: I32 ) ) ;
232215 sig_system. call_conv = module. target_config ( ) . default_call_conv ;
233216 let system_id = module. declare_function ( "system" , Linkage :: Import , & sig_system) . unwrap ( ) ;
234-
235217 let mut sig_putenv = module. make_signature ( ) ;
236218 sig_putenv. params . push ( AbiParam :: new ( pointer_type) ) ;
237219 sig_putenv. returns . push ( AbiParam :: new ( types:: I32 ) ) ;
238220 sig_putenv. call_conv = module. target_config ( ) . default_call_conv ;
239221 let putenv_id = module. declare_function ( "putenv" , Linkage :: Import , & sig_putenv) . unwrap ( ) ;
240-
241222 let mut sig_main = module. make_signature ( ) ;
242223 sig_main. returns . push ( AbiParam :: new ( types:: I32 ) ) ;
243224 sig_main. call_conv = module. target_config ( ) . default_call_conv ;
244225 let main_id = module. declare_function ( "main" , Linkage :: Export , & sig_main) . unwrap ( ) ;
245-
246226 let mut ctx = cranelift_codegen:: Context :: for_function ( Function :: with_name_signature ( Default :: default ( ) , sig_main. clone ( ) ) ) ;
247227 let mut func_builder_ctx = FunctionBuilderContext :: new ( ) ;
248228 let mut builder = FunctionBuilder :: new ( & mut ctx. func , & mut func_builder_ctx) ;
249-
250229 let entry_block = builder. create_block ( ) ;
251230 builder. switch_to_block ( entry_block) ;
252231 builder. seal_block ( entry_block) ;
253-
254232 let local_system = module. declare_func_in_func ( system_id, & mut builder. func ) ;
255233 let local_putenv = module. declare_func_in_func ( putenv_id, & mut builder. func ) ;
256-
257234 let mut var_data_ids = Vec :: new ( ) ;
258235 for ( var, value) in & vars {
259236 let env_str = format ! ( "{}={}" , var, value) ;
260237 let data_name = format ! ( "env_{}" , var_data_ids. len( ) ) ;
261238 let data_id = module. declare_data ( & data_name, Linkage :: Local , true , false ) . unwrap ( ) ;
262- let mut data_ctx = DataContext :: new ( ) ;
239+ let mut data_ctx = DataDescription :: new ( ) ;
263240 let mut bytes: Vec < u8 > = env_str. into_bytes ( ) ;
264241 bytes. push ( 0 ) ;
265242 data_ctx. define ( bytes. into_boxed_slice ( ) ) ;
266243 module. define_data ( data_id, & data_ctx) . unwrap ( ) ;
267244 var_data_ids. push ( data_id) ;
268245 }
269-
270246 for data_id in var_data_ids {
271247 let global = module. declare_data_in_func ( data_id, & mut builder. func ) ;
272248 let ptr = builder. ins ( ) . global_value ( pointer_type, global) ;
273249 let _ = builder. ins ( ) . call ( local_putenv, & [ ptr] ) ;
274250 }
275-
276251 let mut cmd_data_ids = Vec :: new ( ) ;
277- for ( i, cmd) in cmds . iter ( ) . enumerate ( ) {
252+ for ( i, cmd) in final_cmds . iter ( ) . enumerate ( ) {
278253 let data_name = format ! ( "cmd_{i}" ) ;
279254 let data_id = module. declare_data ( & data_name, Linkage :: Local , true , false ) . unwrap ( ) ;
280- let mut data_ctx = DataContext :: new ( ) ;
255+ let mut data_ctx = DataDescription :: new ( ) ;
281256 let mut bytes: Vec < u8 > = cmd. as_bytes ( ) . to_vec ( ) ;
282257 bytes. push ( 0 ) ;
283258 data_ctx. define ( bytes. into_boxed_slice ( ) ) ;
284259 module. define_data ( data_id, & data_ctx) . unwrap ( ) ;
285260 cmd_data_ids. push ( data_id) ;
286261 }
287-
288262 for data_id in cmd_data_ids {
289263 let global = module. declare_data_in_func ( data_id, & mut builder. func ) ;
290264 let ptr = builder. ins ( ) . global_value ( pointer_type, global) ;
291265 let _ = builder. ins ( ) . call ( local_system, & [ ptr] ) ;
292266 }
293-
294267 let zero = builder. ins ( ) . iconst ( types:: I32 , 0 ) ;
295268 builder. ins ( ) . return_ ( & [ zero] ) ;
296269 builder. finalize ( ) ;
297-
298270 module. define_function ( main_id, & mut ctx) . unwrap ( ) ;
299- let obj = module. finish ( ) ;
300-
271+ let obj = module. finish ( ) . object . write ( ) . expect ( "Failed to write object" ) ;
301272 let temp_obj_path = output_path. with_extension ( "o" ) ;
302273 let mut file = File :: create ( & temp_obj_path) ?;
303274 file. write_all ( & obj) ?;
304-
305- let status = Exec :: shell ( format ! ( "gcc -o {} {}" , output_path. display( ) , temp_obj_path. display( ) ) ) . join ( ) . map_err ( |e : PopenError | io:: Error :: new ( io:: ErrorKind :: Other , e. to_string ( ) ) ) ?;
275+ let status = Exec :: shell ( format ! ( "gcc -o {} {}" , output_path. display( ) , temp_obj_path. display( ) ) )
276+ . join ( )
277+ . map_err ( |e : PopenError | io:: Error :: new ( io:: ErrorKind :: Other , e. to_string ( ) ) ) ?;
306278 if !status. success ( ) {
307279 return Err ( io:: Error :: new ( io:: ErrorKind :: Other , "Linking failed" ) ) ;
308280 }
309-
310281 fs:: remove_file ( temp_obj_path) ?;
311-
312282 Ok ( ( ) )
313283}
0 commit comments