diff --git a/src/assembler/AST.rs b/src/assembler/ast.rs similarity index 100% rename from src/assembler/AST.rs rename to src/assembler/ast.rs diff --git a/src/assembler/encoder.rs b/src/assembler/encoder.rs index 8d69697..65fe08f 100644 --- a/src/assembler/encoder.rs +++ b/src/assembler/encoder.rs @@ -1,9 +1,8 @@ -use super::AST::*; +use super::ast::*; use crate::cpu::get_num; use log::{trace, warn}; - /// Trait to represent a format we can translate our assembly to. pub trait CodeFormat { fn encode_op(op: &Operation, sy: &SymbolTable, current_pc: u16) -> Option @@ -36,7 +35,7 @@ impl SymbolTable { // query, sy // ); warn!("Symbol {} not found in symbol table.", query); - return None + return None; } } diff --git a/src/assembler/mod.rs b/src/assembler/mod.rs index 6f69161..4ee9ed7 100644 --- a/src/assembler/mod.rs +++ b/src/assembler/mod.rs @@ -1,14 +1,13 @@ -mod AST; +mod ast; pub mod encoder; pub mod parser; -mod tests; use encoder::CodeFormat; use encoder::SymbolTable; -pub use AST::print_op; +pub use ast::print_op; -use log::{trace, debug}; +use log::{debug, trace}; use parser::Section; @@ -26,7 +25,7 @@ impl Section { // UTF-8 strings are collections of 8-bit chunks, but they're // packed into words of 16 bits + 16 bit NULL. // - // If there's an uneven number of bytes in a string, + // If there's an uneven number of bytes in a string, // we add a 8 bit empty padding and then the NULL byte. SectionContent::CString(s) => { let c = s.len(); @@ -41,7 +40,7 @@ impl Section { } /// Converts this section to binary. Needs symbol table to - /// resolve labels, and to quickly get the address of + /// resolve labels, and to quickly get the address of /// this own section. fn to_binary(&self, sy: &SymbolTable) -> Option { let own_address = sy.lookup(&self.name)?; @@ -63,17 +62,19 @@ impl Section { return Some(crate::loader::Section::new(self.name.clone(), &res)); } SectionContent::CString(s) => { - return Some(crate::loader::Section::new(self.name.clone(), &make_string(s))); + return Some(crate::loader::Section::new( + self.name.clone(), + &make_string(s), + )); } SectionContent::CVec() => todo!(), } } } - /// Sorts a list of sections. /// All .text sections containing code are -/// put at the beginning of the binary file, in the order they +/// put at the beginning of the binary file, in the order they /// appear in the assembly file, except the "main" section, /// which is the entrypoint of our program and must be put /// at the very beginning. diff --git a/src/assembler/parser.rs b/src/assembler/parser.rs index c2a0edb..2a3b591 100644 --- a/src/assembler/parser.rs +++ b/src/assembler/parser.rs @@ -1,4 +1,4 @@ -use super::AST::{Const, Operation}; +use super::ast::{Const, Operation}; use Operation::*; use log::*; @@ -16,14 +16,12 @@ pub enum ParseError { /// represents the state of our parser. /// Sadly parsing is stateless, pub struct Parser { - input: Vec, // input file + input: Vec, // input file } impl Parser { pub fn new(i: String) -> Self { - Parser { - input: sanitize(i), - } + Parser { input: sanitize(i) } } } @@ -89,19 +87,20 @@ fn take_between(i: &str, start: &str, stop: &str) -> Option<(String, String)> { return take_alpha_till(&s1, stop); } -/// finds special escaped characters in a string -/// (such as \n) and replaces them with the actual special -/// character -fn escaped_codes() {} - #[test] -fn take_between_test() { +fn take_between_test1() { assert_eq!( take_between("\"wow\" etc", "\"", "\""), Some(("wow".to_string(), " etc".to_string())) ); } +/// finds special escaped characters in a string +/// (such as \n) and replaces them with the actual special +/// character +/// #TODO: do we need this? I forgot. +fn _escaped_codes() {} + //// SECTION PARSING /// Enum to represent possible section content. @@ -121,7 +120,6 @@ pub struct Section { pub content: SectionContent, } - impl Parser { pub fn parse_sections(&self) -> Result, ParseError> { let mut res = vec![]; @@ -151,8 +149,12 @@ impl Parser { }) } "asciiz" => { - let Some(s) = lines.next() else {return Err(ParseError::UnexpectedEOF)}; - let Some((s, _)) = take_between(s.trim(), "\"", "\"") else {return Err(ParseError::BadSectionContent)}; + let Some(s) = lines.next() else { + return Err(ParseError::UnexpectedEOF); + }; + let Some((s, _)) = take_between(s.trim(), "\"", "\"") else { + return Err(ParseError::BadSectionContent); + }; res.push(Section { name: name.trim().to_owned(), content: CString(s), @@ -200,7 +202,9 @@ fn parse_code_line(i: &str) -> Result { // every operation has at most 3 arguments let mut bits = i.split_whitespace(); trace!("current parse code line: {}", i); - let Some(op) = bits.next() else {return Err(ParseError::BadInstruction)}; + let Some(op) = bits.next() else { + return Err(ParseError::BadInstruction); + }; // no type match op { @@ -214,8 +218,12 @@ fn parse_code_line(i: &str) -> Result { }; // I-type - let Some(r1) = bits.next() else {return Err(ParseError::BadInstruction)}; - let Some(r2) = bits.next() else {return Err(ParseError::BadInstruction)}; + let Some(r1) = bits.next() else { + return Err(ParseError::BadInstruction); + }; + let Some(r2) = bits.next() else { + return Err(ParseError::BadInstruction); + }; match op { "addi" => { @@ -230,7 +238,9 @@ fn parse_code_line(i: &str) -> Result { _ => {} } - let Some(r3) = bits.next() else {return Err(ParseError::BadInstruction)}; + let Some(r3) = bits.next() else { + return Err(ParseError::BadInstruction); + }; // R-type match op { @@ -277,3 +287,17 @@ fn parse_const(i: &str) -> Result { }; return Ok(Const::C(num)); } + +/// TESTS + +#[test] +fn parser_test() { + let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); + + let parser = Parser::new(code); + + let _r = parser.parse_sections(); + + // #TODO: WRITE PARSER TEST SUITE! + //assert_eq!(r, Ok(vec![])); +} diff --git a/src/assembler/tests.rs b/src/assembler/tests.rs deleted file mode 100644 index 5fa7853..0000000 --- a/src/assembler/tests.rs +++ /dev/null @@ -1,18 +0,0 @@ -// use super::*; - -#[cfg(test)] -mod tests { - use crate::assembler::parser; - - #[test] - fn parser_test() { - println!("Parser test begins"); - let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); - - let parser = parser::Parser::new(code); - - let r = parser.parse_sections().unwrap(); - - println!("Parsed sections: {:?}", r); - } -} diff --git a/src/lib.rs b/src/lib.rs index db9a45e..267feb1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ pub mod cpu; pub mod jit; pub mod loader; pub mod pretty_printers; -// pub fn interpret_as_signed(x: u16) -> i16 { // the two types have the same size. @@ -28,8 +27,8 @@ pub fn transmute_to_vecu16_as_is(x: Vec) -> Vec { // let bytes: Vec = { let mut res = vec![]; - // highly cursed: depends on the order in which the arguments of a tuple are - // evaluated. Does its job! + // Depends on the order in which the arguments of a tuple are + // evaluated. Rust guarantees to be left-to-right. while let (Some(word0), Some(word1)) = (rb.next(), rb.next()) { // println!("Pair: {}, {}, word: {:?}", word0, word1, raw_bytes); res.push(((*word0 as u16) << 8) + (*word1 as u16)); diff --git a/src/main.rs b/src/main.rs index adc9348..1081d11 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,3 @@ - use dekejit::assembler::parser; use dekejit::cli::{Cli, Subc::*}; use dekejit::cpu::IOBuffer; @@ -6,10 +5,10 @@ use dekejit::cpu::CPU; use dekejit::pretty_printers::*; use clap::Parser; -use dekejit::loader::loader::{prepare_memory, self}; use dekejit::loader::loader::read_binary; +use dekejit::loader::loader::{self, prepare_memory}; use dekejit::transmute_to_vecu8_as_is; -use log::{info, debug}; +use log::{debug, info}; fn main() { let cli: Cli = Cli::parse(); @@ -27,7 +26,6 @@ fn main() { match cli.comm { Some(Run { filename }) => { - info!("Trying to read {}", filename); let Ok(content) = std::fs::read(&filename) else { @@ -35,7 +33,6 @@ fn main() { return; }; - let bytes = dekejit::transmute_to_vecu16_as_is(content.to_vec()); info!("Begin parsing file {}", &filename); @@ -63,23 +60,21 @@ fn main() { }; } Some(Build { filename, output }) => { - let Ok(inp_content) = std::fs::read_to_string(filename.clone()) else { println!("Could not read file {}", &filename); return; }; - let prs = dekejit::assembler::parser::Parser::new(inp_content); + let prs = dekejit::assembler::parser::Parser::new(inp_content); let sections = match prs.parse_sections() { Ok(s) => s, Err(p_err) => { println!("Parser error: {:?}", p_err); return; - }, + } }; - let Some(bin) = dekejit::assembler::to_binary(sections) else { println!("Unspecified error while converting file to binary. Must fix."); return; @@ -93,18 +88,16 @@ fn main() { let out_bin = transmute_to_vecu8_as_is(out_bin); - info!("{:?}", out_bin); match std::fs::write(output.clone(), out_bin) { - Ok(_) => {}, + Ok(_) => {} Err(_) => { - println!("could not write file {}", output);}, + println!("could not write file {}", output); + } }; - } - Some(View {filename, format}) => { - + Some(View { filename, format }) => { info!("Trying to read {}", filename); let Ok(content) = std::fs::read_to_string(&filename) else { @@ -114,10 +107,12 @@ fn main() { let p = parser::Parser::new(content); - let s = p.parse_sections().unwrap(); - println!("{}", format_code(dekejit::pretty_printers::CodeWrapper::Asm(s), format).unwrap()); + println!( + "{}", + format_code(dekejit::pretty_printers::CodeWrapper::Asm(s), format).unwrap() + ); // let Ok(content) = std::fs::read(&filename) else { // println!("File {} does not exist or cannot be read.", &filename); @@ -139,15 +134,11 @@ fn main() { // }; // // println!("{:?}", sections); - - } - Some(Debug) => {}, + Some(Debug) => {} None => {} } - - // let parser = parser::Parser::new(code); // // let r = parser.parse_sections().unwrap();