use itsy::*;
use std::{env, path::PathBuf, collections::HashMap};
itsy_api!(MyAPI, (), {
fn print(&mut context, value: String) {
print!("{}", value);
}
fn println(&mut context, value: String) {
println!("{}", value);
}
});
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() < 2 {
println!("usage: run <filename>");
} else {
let mut files: HashMap<String, (PathBuf, String)> = HashMap::new();
let write_logs = std::path::Path::new("./logs/").is_dir();
match build(&args[1], &mut files, write_logs) {
Ok(program) => {
let mut vm = runtime::VM::new(&program);
if write_logs {
log("logs/bytecode.ini", false, &vm.format_program());
log("logs/run.ini", false, "");
}
loop {
let mut instruction = None;
if write_logs {
instruction = Some(vm.format_instruction().unwrap_or("-".to_string()));
log("logs/run.ini", true, &format!("{}", instruction.as_ref().unwrap()));
}
let vmstate = vm.step(&mut ());
if let Some(instruction) = instruction {
if instruction.starts_with("[") == false && instruction.starts_with("\n") == false {
log("logs/run.ini", true, &format!("; stack {:?}\n; heap {:?}", vm.stack.frame(), vm.heap.data()));
}
}
if vmstate != runtime::VMState::Ready {
break;
}
}
}
Err(err) => {
let module_path = err.module_path();
let loc = err.loc(&files[module_path].1);
println!("{} in line {}, column {} in file {}.", err, loc.0, loc.1, files[module_path].0.to_str().unwrap());
}
}
}
}
fn log(filename: &str, append: bool, data: &str) {
use std::io::prelude::*;
if append {
let mut file = std::fs::OpenOptions::new().append(true).open(filename).unwrap();
writeln!(file, "{}", data).unwrap();
} else {
std::fs::write(filename, data).unwrap();
}
}
fn build<P: AsRef<std::path::Path>>(source_file: P, files: &mut HashMap<String, (PathBuf, String)>, write_logs: bool) -> Result<compiler::Program<MyAPI>, Error> {
let source_file = source_file.as_ref();
let parsed = parser::parse(|module_path| {
let filename = parser::module_filename(source_file, module_path);
let file = std::fs::read_to_string(&filename).unwrap();
let module = parser::parse_module(&file, module_path);
files.insert(module_path.to_string(), (filename, file));
module
})?;
let resolved = resolver::resolve::<MyAPI>(parsed, "main")?;
if write_logs {
log("logs/ast.c", false, &format!("{:?}", resolved.modules));
}
Ok(compiler::compile(resolved)?)
}