#![allow(dead_code)]
mod directives;
mod encoder;
mod error;
mod expression;
mod generator;
mod inst;
mod parser;
mod reg;
mod scanner;
mod stanalyzer;
mod statement;
mod token;
use generator::Generator;
use parser::Parser;
use scanner::Scanner;
use stanalyzer::Analyzer;
use std::fs;
use std::path::PathBuf;
pub mod ffi {
use std::ffi::c_char;
use std::ffi::CStr;
#[no_mangle]
pub extern "C" fn rubble(source: *const c_char, bytes: *mut u8, size: *mut usize) -> bool {
let c_str = unsafe { CStr::from_ptr(source) };
let size_deref = unsafe { *size };
let str = match c_str.to_str() {
Ok(s) => s,
Err(e) => {
println!("[rubbler] {}", e);
return false;
}
};
match super::rubble(str) {
Ok(b) => {
for (i, byte) in b.iter().enumerate() {
if i == size_deref {
break;
}
unsafe { *bytes.add(i) = *byte }
unsafe { *size = i + 1 }
}
true
}
Err(e) => {
println!("[rubbler] {}", e);
false
}
}
}
#[no_mangle]
pub extern "C" fn rubble_file(path: *const c_char, bytes: *mut u8, size: *mut usize) -> bool {
let c_str = unsafe { CStr::from_ptr(path) };
let size_deref = unsafe { *size };
let str = match c_str.to_str() {
Ok(s) => s,
Err(e) => {
println!("[rubbler] {}", e);
return false;
}
};
match super::rubble_file(str) {
Ok(b) => {
for (i, byte) in b.iter().enumerate() {
if i == size_deref {
break;
}
unsafe { *bytes.add(i) = *byte }
unsafe { *size = i + 1 }
}
true
}
Err(e) => {
println!("[rubbler] {}", e);
false
}
}
}
#[no_mangle]
pub extern "C" fn rubble_inst(inst: *const c_char, result: *mut u32) -> bool {
let c_str = unsafe { CStr::from_ptr(inst) };
let str = match c_str.to_str() {
Ok(s) => s,
Err(e) => {
println!("[rubbler] {}", e);
return false;
}
};
match super::rubble_inst(str) {
Ok(code) => {
unsafe { *result = code };
true
}
Err(e) => {
println!("[rubbler] {}", e);
false
}
}
}
}
pub fn rubble(source: &str) -> Result<Vec<u8>, String> {
let scanner = Scanner::new(source.to_string());
let tokens = scanner.scan_tokens()?;
let parser = Parser::new(tokens);
let stmts = parser.parse()?;
let analyzer = Analyzer::new(stmts);
let (stmts, ctx) = analyzer.analyze()?;
let mut generator = Generator::new(stmts, ctx);
generator.generate_code()
}
pub fn rubble_file(path: &str) -> Result<Vec<u8>, String> {
let path = PathBuf::from(path);
let source = fs::read_to_string(path).map_err(|e| e.to_string())?;
rubble(&source)
}
pub fn rubble_inst(inst: &str) -> Result<u32, String> {
let lines: Vec<&str> = inst.lines().collect();
if lines.len() != 1 {
return Err("Found multiple lines".to_string());
}
let code = rubble(lines[0])?;
let mut result = 0;
for (i, byte) in code.iter().enumerate() {
result += (*byte as u32) << (8 * i);
}
Ok(result)
}
#[cfg(test)]
mod test {
use std::path::PathBuf;
fn u32_to_vecu8(value: u32) -> Vec<u8> {
let mut bytes = vec![];
for i in 0..4 {
bytes.push((value >> (8 * i)) as u8)
}
bytes
}
#[test]
fn rubble() {
let source = "lui t2, -3";
let expected_code: u32 = 0b11111111111111111111_00111_0110111;
let code = super::rubble(source).unwrap();
assert_eq!(code, u32_to_vecu8(expected_code));
}
#[test]
fn rubble_inst() {
let inst = "lui t2, -3";
let expected_code: u32 = 0b11111111111111111111_00111_0110111;
let code = super::rubble_inst(inst).unwrap();
assert_eq!(code, expected_code);
}
#[test]
fn rubble_path() {
let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
path.push("resources/test.asm");
let path = path.to_str().unwrap();
let expected_code: u32 = 0b11111111111111111111_00111_0110111;
let code = super::rubble_file(path).unwrap();
assert_eq!(code, u32_to_vecu8(expected_code));
}
}