diff --git a/src/assembler/mod.rs b/src/assembler/mod.rs index ae8c913..d77a6b5 100644 --- a/src/assembler/mod.rs +++ b/src/assembler/mod.rs @@ -1,5 +1,5 @@ mod AST; -mod tests; mod parser; +mod tests; struct Assembler {} diff --git a/src/assembler/parser.rs b/src/assembler/parser.rs index 9261d9f..5c9592b 100644 --- a/src/assembler/parser.rs +++ b/src/assembler/parser.rs @@ -1,6 +1,4 @@ -use crate::cpu::Registers; - -use super::AST::{Operation, Const}; +use super::AST::{Const, Operation}; use Operation::*; type Loc = u16; @@ -11,14 +9,14 @@ pub enum ParseError { UnknownSectionKind, UnexpectedEOF, BadSectionContent, - BadInstruction + BadInstruction, } /// represents the state of our parser. pub struct Parser { loc: u16, // current number of operations parsed. symtable: Vec<(String, u16)>, // symbols encountered, position. - pub input: Vec, // input file + pub input: Vec, // input file } impl Parser { @@ -47,29 +45,25 @@ fn remove_comments(i: &str) -> &str { } else { return i; } -} - +} /// Checks if the string i starts with pat. /// Returns the rest of the input string on success /// else, returns None fn match_string(i: &str, pat: &str) -> Option { - let mut in_chars = i.chars(); for pat_c in pat.chars() { if let Some(c) = in_chars.next() { if c != pat_c { - return None + return None; } }; - } let rest = in_chars.collect(); return Some(rest); - } /// Matches till the "stop" string is found. @@ -79,33 +73,30 @@ fn match_string(i: &str, pat: &str) -> Option { /// Ex: assert_eq!(Ok("Lorem ", " Ipsum"), match_alpha_till("Lorem X Ipsum", "X") ); /// fn take_alpha_till(i: &str, stop: &str) -> Option<(String, String)> { - // if let Some((matched, rest)) = i.split_once(stop) { - return Some((matched.to_string(), rest.to_string())) + return Some((matched.to_string(), rest.to_string())); } else { - return None + return None; } - - } /// Matches inside the `start` and `stop` delimiters. /// Return a tuple with the string in between the two /// togheter with the rest of the string. fn take_between(i: &str, start: &str, stop: &str) -> Option<(String, String)> { - let s1 = match_string(i, start)?; return take_alpha_till(&s1, stop); - } #[test] fn take_between_test() { - assert_eq!(take_between("\"wow\" etc", "\"", "\""), Some(("wow".to_string(), " etc".to_string()))); -} - + assert_eq!( + take_between("\"wow\" etc", "\"", "\""), + Some(("wow".to_string(), " etc".to_string())) + ); +} //// SECTION PARSING @@ -113,7 +104,7 @@ fn take_between_test() { enum SectionContent { Code(Vec), CString(String), - CVec() + CVec(), } use SectionContent::*; @@ -121,19 +112,18 @@ use SectionContent::*; #[derive(Debug)] pub struct Section { name: String, - content: SectionContent, + content: SectionContent, } // A .section has a name and variable content. impl Parser { - pub fn parse_sections(&mut self) -> Result, ParseError> { let mut res = vec![]; let mut lines = self.input.iter().map(|x| x.as_str()).into_iter(); - while let Some(l) = lines.next() { - println!("Examing line: {}", l); + while let Some(l) = lines.next() { + println!("Examing line: {}", l); if l.starts_with(".") { let Some((kind, name)) = take_alpha_till(&l[1..], " ") else { return Err(ParseError::BadSectionHeader); @@ -141,50 +131,48 @@ impl Parser { match kind.as_str() { "text" => { - let s : Vec<&str> = lines.clone().take_while(|&x| !(x).starts_with(".")).map(|x| x).collect(); - res.push(Section { name: name.trim().to_owned(), content: Code(parse_code(&s)?)}) + let s: Vec<&str> = lines + .clone() + .take_while(|&x| !(x).starts_with(".")) + .map(|x| x) + .collect(); + res.push(Section { + name: name.trim().to_owned(), + content: Code(parse_code(&s)?), + }) } "asciiz" => { 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)}) - + res.push(Section { + name: name.trim().to_owned(), + content: CString(s), + }) } "i16" => { - let s = lines.next(); - + let _s = lines.next(); } "u16" => { - let s = lines.next(); - + let _s = lines.next(); } "vi16" => { - let s = lines.next(); - + let _s = lines.next(); } "vu16" => { - let s = lines.next(); - + let _s = lines.next(); } _ => { return Err(ParseError::UnknownSectionKind); } } } - - - - }; - + } return Ok(res); } - } - fn parse_code(i: &[&str]) -> Result, ParseError> { - let mut res = vec![]; for line in i { @@ -194,53 +182,47 @@ fn parse_code(i: &[&str]) -> Result, ParseError> { return Ok(res); } - fn parse_code_line(i: &str) -> Result { - - // every operation has at most 3 arguments - let mut bits = i.split_whitespace(); - println!("current parse code line: {}", i); - let Some(op) = bits.next() else {return Err(ParseError::BadSectionContent)}; + // every operation has at most 3 arguments + let mut bits = i.split_whitespace(); + println!("current parse code line: {}", i); + let Some(op) = bits.next() else {return Err(ParseError::BadSectionContent)}; - // no type - match op { - "nop" => {return Ok(NOP);}, - "halt" => {return Ok(HALT);}, - _ => {} + // no type + match op { + "nop" => { + return Ok(NOP); + } + "halt" => { + return Ok(HALT); + } + _ => {} }; - // I-type - let Some(r1) = bits.next() else {return Err(ParseError::BadSectionHeader)}; - let Some(r2) = bits.next() else {return Err(ParseError::BadSectionHeader)}; + // I-type + let Some(r1) = bits.next() else {return Err(ParseError::BadSectionHeader)}; + let Some(r2) = bits.next() else {return Err(ParseError::BadSectionHeader)}; - match op { - "addi" => { - return Ok(ADDI(r1.to_owned(), parse_const(r2)?)); - } - "sli" => { - return Ok(SLI(r1.to_owned(), parse_const(r2)?)); - - } - "call" => { - - return Ok(CALL(r1.to_owned(), parse_const(r2)?)); - - } - _ => {} - } - - - return Err(ParseError::BadInstruction); + match op { + "addi" => { + return Ok(ADDI(r1.to_owned(), parse_const(r2)?)); + } + "sli" => { + return Ok(SLI(r1.to_owned(), parse_const(r2)?)); + } + "call" => { + return Ok(CALL(r1.to_owned(), parse_const(r2)?)); + } + _ => {} + } + return Err(ParseError::BadInstruction); } fn parse_const(i: &str) -> Result { - // we try to parse the number, if we fail, we treat it as a string. let Ok(num) = i.parse() else { return Ok(Const::CS(i.to_owned())); }; return Ok(Const::C(num)); - } - diff --git a/src/assembler/tests.rs b/src/assembler/tests.rs index 604f462..907f0ee 100644 --- a/src/assembler/tests.rs +++ b/src/assembler/tests.rs @@ -1,16 +1,18 @@ // use super::*; -use crate::assembler::parser; +#[cfg(test)] +mod tests { + use crate::assembler::parser; -#[test] -fn parser_test() { + #[test] + fn parser_test() { + println!("Parser test begins"); + let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); - println!("Parser test begins"); - let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap(); + let mut parser = parser::Parser::new(code); - let mut parser = parser::Parser::new(code); + let r = parser.parse_sections().unwrap(); - let r = parser.parse_sections().unwrap(); - - println!("Parsed sections: {:?}", r); + println!("Parsed sections: {:?}", r); + } } diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index d1baf22..00e1394 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -2,7 +2,9 @@ mod decoder; mod ram; mod registers; mod sysenv; + mod tests; + pub use sysenv::*; pub use registers::*; diff --git a/src/cpu/sysenv/io_vec.rs b/src/cpu/sysenv/io_vec.rs index 3f5c1ac..7ad4e54 100644 --- a/src/cpu/sysenv/io_vec.rs +++ b/src/cpu/sysenv/io_vec.rs @@ -70,7 +70,7 @@ impl Sys for IOBuffer { .slice(pos, MAX_MEM as Word - 1) .ok_or(ExecErr::InvalidMemoryAddr)?; let (s, _) = find_and_read_string(&data) - .map_err(|p| ExecErr::SyscallError("parse error!".to_owned()))?; + .map_err(|_p| ExecErr::SyscallError("parse error!".to_owned()))?; cpu.env.output.push_str(&s); } diff --git a/src/cpu/tests.rs b/src/cpu/tests.rs index fb92155..e42b977 100644 --- a/src/cpu/tests.rs +++ b/src/cpu/tests.rs @@ -1,35 +1,35 @@ +#[cfg(test)] +mod tests { -use super::*; + use crate::{ + cpu::{IOBuffer, CPU}, + loader::unloader::make_string, + }; -use crate::loader::unloader::*; + #[test] + fn hello_world_binary_test() { + let hw = String::from("Hello world!"); + let mut k = make_string(&hw); -#[test] -fn hello_world_binary_test() { + let mut code: Vec = vec![ + 0b0111000100000011, // addi ra 3 + 0b1110000100000011, // ecall ra 3 + 0b1111000000000000, // HALT. + ]; - let hw = String::from("Hello world!"); + code.append(&mut k); - let mut k = make_string(&hw); + let mut env = IOBuffer::default(); - let mut code: Vec = vec![ - 0b0111000100000011, // addi ra 3 - 0b1110000100000011, // ecall ra 3 - 0b1111000000000000, // HALT. - ]; + let mut cpu = CPU::new(&mut env); - code.append(&mut k); + for c in &code[..] { + println!("{:#018b}", c); + } - let mut env = IOBuffer::default(); + cpu.run_code_raw(&code); - let mut cpu = CPU::new(&mut env); - - for c in &code[..] { - println!("{:#018b}", c); + assert_eq!(hw, cpu.env.output); } - - cpu.run_code_raw(&code); - - assert_eq!(hw, cpu.env.output); } - - diff --git a/src/lib.rs b/src/lib.rs index aa3720e..8acb777 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ pub mod loader; pub mod assembler; // - pub fn interpret_as_signed(x: u16) -> i16 { // the two types have the same size. unsafe { diff --git a/src/loader/loader.rs b/src/loader/loader.rs index 949f830..1b301cf 100644 --- a/src/loader/loader.rs +++ b/src/loader/loader.rs @@ -1,6 +1,6 @@ use crate::cpu::Word; -use super::{constants::MAGIC, Section}; +use super::Section; #[derive(Debug)] pub enum ParseError { @@ -71,7 +71,7 @@ pub fn read_binary(b: &[u16]) -> Result, ParseError> { /// Parses binary headers fn parse_header(b: &[Word]) -> Result, ParseError> { - let Some([m, s]) = b.get(0..2) else {return Err(ParseError::EmptyHeader)}; + let Some([_m, s]) = b.get(0..2) else {return Err(ParseError::EmptyHeader)}; // Magic number check. Can go unchecked, check spec. // if (*m != MAGIC) { diff --git a/src/loader/tests.rs b/src/loader/tests.rs index 5b2befd..ec150b4 100644 --- a/src/loader/tests.rs +++ b/src/loader/tests.rs @@ -1,61 +1,65 @@ -use super::loader::*; -use super::unloader::*; -use super::*; +#[cfg(test)] +mod tests { + use crate::loader::Section; -// fuzzable, TODO -fn write_read_str_identity(s: &str) { - let mut bytes = make_string(s); + use super::super::loader::*; + use super::super::unloader::*; - // pop null-terminator; - // bytes.pop().expect("String doesn't even have a single byte?"); - // println!("w-r s: {:?}, b: {:?}", s, bytes); - let (s0, _) = find_and_read_string(&bytes).unwrap(); - assert_eq!(s, &s0); -} + // fuzzable, TODO + fn write_read_str_identity(s: &str) { + let bytes = make_string(s); -fn read_write_str_identity(b: Vec) { - let (string, _) = find_and_read_string(&b).unwrap(); - let mut n_term = b.clone(); - // n_term.push(0); - // println!("r-w s: {:?}, b: {:?}", string, n_term); - assert_eq!(n_term, make_string(&string)); -} + // pop null-terminator; + // bytes.pop().expect("String doesn't even have a single byte?"); + // println!("w-r s: {:?}, b: {:?}", s, bytes); + let (s0, _) = find_and_read_string(&bytes).unwrap(); + assert_eq!(s, &s0); + } -#[test] -fn label_parse_identity() { - let testwords = vec!["Hello,", "main", "è", "Hello,,", "v", "main", "pi"]; // should support utf-8 - // - for word in testwords { - println!("\nTEST {}\n", word); + fn read_write_str_identity(b: Vec) { + let (string, _) = find_and_read_string(&b).unwrap(); + let n_term = b.clone(); + // n_term.push(0); + // println!("r-w s: {:?}, b: {:?}", string, n_term); + assert_eq!(n_term, make_string(&string)); + } - write_read_str_identity(word); - let bytes = make_string(word); - // bytes.pop(); - println!( - "word: {:?}, bytes: {:?}, length: {:?}", - word, - bytes, - bytes.len() - ); - read_write_str_identity(bytes); - println!("Done with {:?}", word); + #[test] + fn label_parse_identity() { + let testwords = vec!["Hello,", "main", "è", "Hello,,", "v", "main", "pi"]; // should support utf-8 + // + for word in testwords { + println!("\nTEST {}\n", word); + + write_read_str_identity(word); + let bytes = make_string(word); + // bytes.pop(); + println!( + "word: {:?}, bytes: {:?}, length: {:?}", + word, + bytes, + bytes.len() + ); + read_write_str_identity(bytes); + println!("Done with {:?}", word); + } + } + + // Symbol table test + + #[test] + fn sy_test() { + let fake_symbol_table: Vec
= vec![ + Section::new("v".to_owned(), &[1, 2, 3]), + Section::new("pi".to_owned(), &[3]), + Section::new("main".to_owned(), &[231, 323, 433]), // Section { name: todo!(), content: todo!() }, + // Section { name: todo!(), content: todo!() } + ]; + + let bin = make_binary(&fake_symbol_table); + println!("{:?}", bin); + + let parsed_symbol_table = read_binary(&bin).expect("Wtf! We got error!"); + println!("{:?}", parsed_symbol_table); } } - -// Symbol table test - -#[test] -fn sy_test() { - let fake_symbol_table: Vec
= vec![ - Section::new("v".to_owned(), &[1, 2, 3]), - Section::new("pi".to_owned(), &[3]), - Section::new("main".to_owned(), &[231, 323, 433]), // Section { name: todo!(), content: todo!() }, - // Section { name: todo!(), content: todo!() } - ]; - - let bin = make_binary(&fake_symbol_table); - println!("{:?}", bin); - - let parsed_symbol_table = read_binary(&bin).expect("Wtf! We got error!"); - println!("{:?}", parsed_symbol_table); -} diff --git a/src/main.rs b/src/main.rs index 8237ab5..5b02822 100644 --- a/src/main.rs +++ b/src/main.rs @@ -27,6 +27,4 @@ fn main() { } Err(e) => println!("Err: {:?}", e), }; - - }