use crate::lexer::Commands;
use crate::lexer::Token;
use std::fs;
use std::process::Command;
pub fn compile(tokens: &Vec<Token>) -> String {
let mut compiled_code = String::from(r#"fn eb(mem: &mut [u8; 30000],cell: i32, val: i32, et: char){if et=='+'{if (*mem)[cell as usize] as i32+val<256 {(*mem)[cell as usize]+=val as u8;}else{(*mem)[cell as usize]=(val%255) as u8;}}else{if (*mem)[cell as usize] as i32-val>=0{(*mem)[cell as usize]-=val as u8;}else{(*mem)[cell as usize]=(256-(val%255)) as u8;}}}"#);
compiled_code.push('\n');
compiled_code.push_str(r#"fn ac(cell: &mut i32, ext: i32, et: char){if et=='+'{if *cell+ext<=30000 {*cell+=ext;}else{*cell=ext%30000;}}else{if *cell-ext>=0 {*cell-=ext;}else{*cell=ext%30000;}}}"#);
compiled_code.push_str("\n#[allow(unused_assignments)]\nfn main(){let mut mem:[u8; 30000]=[0; 30000];let mut cc=0;");
for token in tokens.iter() {
match token.value {
Commands::AddByte => compiled_code = format!("{}eb(&mut mem,cc,{},'+');", compiled_code,token.repeats),
Commands::RemoveByte => compiled_code = format!("{}eb(&mut mem,cc,{},'-');", compiled_code,token.repeats),
Commands::GoNext => compiled_code = format!("{}ac(&mut cc,{},'+');", compiled_code,token.repeats),
Commands::GoLast => compiled_code = format!("{}ac(&mut cc,{},'-');", compiled_code,token.repeats),
Commands::LoopBegin => compiled_code.push_str("while mem[cc as usize]!=(0 as u8){"),
Commands::LoopEnd => compiled_code.push_str("};"),
Commands::WriteByte => compiled_code.push_str(r#"print!("{}",mem[cc as usize] as char);"#),
Commands::ReadByte => {
match compiled_code.find("use std::io;") {
Some(_) => compiled_code.push_str(r#"let mut input: [u8; 1]=[0; 1];io::stdin().read_exact(&mut input).expect("failed to read byte.");mem[cc as usize] = input[0];"#),
None => {
compiled_code = compiled_code.replace("fn eb", "use std::io;\nuse std::io::Read;\nfn eb");
compiled_code.push_str(r#"let mut input: [u8; 1]=[0; 1];io::stdin().read_exact(&mut input).expect("failed to read byte.");mem[cc as usize] = input[0];"#);
}
}
}
}
};
compiled_code.push('}');
compiled_code
}
pub fn build(tokens: &Vec<Token>, file_path: &str) -> bool {
let compiled_code = compile(tokens);
match fs::write(file_path, compiled_code.to_owned()) {
Ok(()) => match Command::new("rustc").arg(file_path).output() {
Ok(_) => return true,
Err(_) => return false
},
Err(_) => return false
}
}