use std::{collections::HashMap, fs::File, io::{BufWriter, Write}};
use crate::{lexer::{Token, tokenize}, serial::ByteSized, vm::execute};
mod lexer;
mod vm;
mod types;
mod serial;
const VERSION: u32 = 40;
pub fn compile_file(filepath: &str) {
let source = match std::fs::read_to_string(filepath) {
Ok(s) => s,
Err(e) => {
eprintln!("Error reading file '{}': {}", filepath, e);
return;
}
};
compile_string(source, filepath);
}
pub fn compile_string(source: String, libname: &str) {
let mut functions: HashMap<String, Vec<Token>> = HashMap::new();
if let Err(error) = tokenize(&source, None, &mut functions) {
let pos = error.position();
print_error(&source, &error.to_string(), pos.row, pos.col);
return;
}
let filename = libname.to_string() + ".lib";
let library = match File::create(filename) {
Ok(file) => file,
Err(e) => {
eprintln!("Error making library file: {}", e);
return;
}
};
let mut writer = BufWriter::new(library);
let mut buffer = Vec::new();
buffer.extend_from_slice(b"STKL");
buffer.extend_from_slice(&VERSION.to_be_bytes());
buffer.extend_from_slice(&(functions.len() as u32).to_be_bytes());
for function in functions {
let key_length = function.0.len();
buffer.extend_from_slice(&(key_length as u32).to_be_bytes());
buffer.extend_from_slice(function.0.as_bytes());
let data_length = function.1.len();
buffer.extend_from_slice(&(data_length as u32).to_be_bytes());
for token in function.1 {
buffer.extend_from_slice(&token.to_bytes());
}
}
if let Err(error) = writer.write_all(&buffer) {
eprintln!("Error writing library to file: {}", error);
return;
}
if let Err(error) = writer.flush() {
eprintln!("Error flushing data to file: {}", error);
return;
}
}
pub fn run_file(filepath: &str) {
let source = match std::fs::read_to_string(filepath) {
Ok(s) => s,
Err(e) => {
eprintln!("Error reading file '{}': {}", filepath, e);
return;
}
};
run_string(source);
}
pub fn run_string(source: String) {
let mut functions: HashMap<String, Vec<Token>> = HashMap::new();
let tokens = match tokenize(&source, None, &mut functions) {
Ok(t) => t,
Err(error) => {
let pos = error.position();
print_error(&source, &error.to_string(), pos.row, pos.col);
return;
}
};
let mut stack = vm::Stack::new();
if let Err(e) = execute(&tokens, &mut stack, &functions) {
let pos = e.position();
print_error(&source, &e.to_string(), pos.row, pos.col);
}
}
fn print_error(source: &str, error_description: &str, error_row: usize, error_col: usize) {
eprintln!("{}", error_description);
eprintln!("{}", source.lines().nth(error_row - 1).unwrap());
eprintln!("{}\x1b[38;5;196m^\x1b[0m", " ".repeat(error_col - 1));
return;
}