cargo fmt

This commit is contained in:
raphy 2023-04-28 12:24:28 +02:00
parent 18a5f17b80
commit 0186f99678
10 changed files with 161 additions and 174 deletions

View File

@ -1,5 +1,5 @@
mod AST; mod AST;
mod tests;
mod parser; mod parser;
mod tests;
struct Assembler {} struct Assembler {}

View File

@ -1,6 +1,4 @@
use crate::cpu::Registers; use super::AST::{Const, Operation};
use super::AST::{Operation, Const};
use Operation::*; use Operation::*;
type Loc = u16; type Loc = u16;
@ -11,14 +9,14 @@ pub enum ParseError {
UnknownSectionKind, UnknownSectionKind,
UnexpectedEOF, UnexpectedEOF,
BadSectionContent, BadSectionContent,
BadInstruction BadInstruction,
} }
/// represents the state of our parser. /// represents the state of our parser.
pub struct Parser { pub struct Parser {
loc: u16, // current number of operations parsed. loc: u16, // current number of operations parsed.
symtable: Vec<(String, u16)>, // symbols encountered, position. symtable: Vec<(String, u16)>, // symbols encountered, position.
pub input: Vec<String>, // input file pub input: Vec<String>, // input file
} }
impl Parser { impl Parser {
@ -47,29 +45,25 @@ fn remove_comments(i: &str) -> &str {
} else { } else {
return i; return i;
} }
} }
/// Checks if the string i starts with pat. /// Checks if the string i starts with pat.
/// Returns the rest of the input string on success /// Returns the rest of the input string on success
/// else, returns None /// else, returns None
fn match_string(i: &str, pat: &str) -> Option<String> { fn match_string(i: &str, pat: &str) -> Option<String> {
let mut in_chars = i.chars(); let mut in_chars = i.chars();
for pat_c in pat.chars() { for pat_c in pat.chars() {
if let Some(c) = in_chars.next() { if let Some(c) = in_chars.next() {
if c != pat_c { if c != pat_c {
return None return None;
} }
}; };
} }
let rest = in_chars.collect(); let rest = in_chars.collect();
return Some(rest); return Some(rest);
} }
/// Matches till the "stop" string is found. /// Matches till the "stop" string is found.
@ -79,33 +73,30 @@ fn match_string(i: &str, pat: &str) -> Option<String> {
/// Ex: assert_eq!(Ok("Lorem ", " Ipsum"), match_alpha_till("Lorem X Ipsum", "X") ); /// Ex: assert_eq!(Ok("Lorem ", " Ipsum"), match_alpha_till("Lorem X Ipsum", "X") );
/// ///
fn take_alpha_till(i: &str, stop: &str) -> Option<(String, String)> { fn take_alpha_till(i: &str, stop: &str) -> Option<(String, String)> {
// //
if let Some((matched, rest)) = i.split_once(stop) { 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 { } else {
return None return None;
} }
} }
/// Matches inside the `start` and `stop` delimiters. /// Matches inside the `start` and `stop` delimiters.
/// Return a tuple with the string in between the two /// Return a tuple with the string in between the two
/// togheter with the rest of the string. /// togheter with the rest of the string.
fn take_between(i: &str, start: &str, stop: &str) -> Option<(String, String)> { fn take_between(i: &str, start: &str, stop: &str) -> Option<(String, String)> {
let s1 = match_string(i, start)?; let s1 = match_string(i, start)?;
return take_alpha_till(&s1, stop); return take_alpha_till(&s1, stop);
} }
#[test] #[test]
fn take_between_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 //// SECTION PARSING
@ -113,7 +104,7 @@ fn take_between_test() {
enum SectionContent { enum SectionContent {
Code(Vec<Operation>), Code(Vec<Operation>),
CString(String), CString(String),
CVec() CVec(),
} }
use SectionContent::*; use SectionContent::*;
@ -121,19 +112,18 @@ use SectionContent::*;
#[derive(Debug)] #[derive(Debug)]
pub struct Section { pub struct Section {
name: String, name: String,
content: SectionContent, content: SectionContent,
} }
// A .section has a name and variable content. // A .section has a name and variable content.
impl Parser { impl Parser {
pub fn parse_sections(&mut self) -> Result<Vec<Section>, ParseError> { pub fn parse_sections(&mut self) -> Result<Vec<Section>, ParseError> {
let mut res = vec![]; let mut res = vec![];
let mut lines = self.input.iter().map(|x| x.as_str()).into_iter(); let mut lines = self.input.iter().map(|x| x.as_str()).into_iter();
while let Some(l) = lines.next() { while let Some(l) = lines.next() {
println!("Examing line: {}", l); println!("Examing line: {}", l);
if l.starts_with(".") { if l.starts_with(".") {
let Some((kind, name)) = take_alpha_till(&l[1..], " ") else { let Some((kind, name)) = take_alpha_till(&l[1..], " ") else {
return Err(ParseError::BadSectionHeader); return Err(ParseError::BadSectionHeader);
@ -141,50 +131,48 @@ impl Parser {
match kind.as_str() { match kind.as_str() {
"text" => { "text" => {
let s : Vec<&str> = lines.clone().take_while(|&x| !(x).starts_with(".")).map(|x| x).collect(); let s: Vec<&str> = lines
res.push(Section { name: name.trim().to_owned(), content: Code(parse_code(&s)?)}) .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" => { "asciiz" => {
let Some(s) = lines.next() else {return Err(ParseError::UnexpectedEOF)}; 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, _)) = 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" => { "i16" => {
let s = lines.next(); let _s = lines.next();
} }
"u16" => { "u16" => {
let s = lines.next(); let _s = lines.next();
} }
"vi16" => { "vi16" => {
let s = lines.next(); let _s = lines.next();
} }
"vu16" => { "vu16" => {
let s = lines.next(); let _s = lines.next();
} }
_ => { _ => {
return Err(ParseError::UnknownSectionKind); return Err(ParseError::UnknownSectionKind);
} }
} }
} }
}
};
return Ok(res); return Ok(res);
} }
} }
fn parse_code(i: &[&str]) -> Result<Vec<Operation>, ParseError> { fn parse_code(i: &[&str]) -> Result<Vec<Operation>, ParseError> {
let mut res = vec![]; let mut res = vec![];
for line in i { for line in i {
@ -194,53 +182,47 @@ fn parse_code(i: &[&str]) -> Result<Vec<Operation>, ParseError> {
return Ok(res); return Ok(res);
} }
fn parse_code_line(i: &str) -> Result<Operation, ParseError> { fn parse_code_line(i: &str) -> Result<Operation, ParseError> {
// every operation has at most 3 arguments
// every operation has at most 3 arguments let mut bits = i.split_whitespace();
let mut bits = i.split_whitespace(); println!("current parse code line: {}", i);
println!("current parse code line: {}", i); let Some(op) = bits.next() else {return Err(ParseError::BadSectionContent)};
let Some(op) = bits.next() else {return Err(ParseError::BadSectionContent)};
// no type // no type
match op { match op {
"nop" => {return Ok(NOP);}, "nop" => {
"halt" => {return Ok(HALT);}, return Ok(NOP);
_ => {} }
"halt" => {
return Ok(HALT);
}
_ => {}
}; };
// I-type // I-type
let Some(r1) = bits.next() else {return Err(ParseError::BadSectionHeader)}; let Some(r1) = bits.next() else {return Err(ParseError::BadSectionHeader)};
let Some(r2) = bits.next() else {return Err(ParseError::BadSectionHeader)}; let Some(r2) = bits.next() else {return Err(ParseError::BadSectionHeader)};
match op { match op {
"addi" => { "addi" => {
return Ok(ADDI(r1.to_owned(), parse_const(r2)?)); return Ok(ADDI(r1.to_owned(), parse_const(r2)?));
} }
"sli" => { "sli" => {
return Ok(SLI(r1.to_owned(), parse_const(r2)?)); return Ok(SLI(r1.to_owned(), parse_const(r2)?));
}
} "call" => {
"call" => { return Ok(CALL(r1.to_owned(), parse_const(r2)?));
}
return Ok(CALL(r1.to_owned(), parse_const(r2)?)); _ => {}
}
}
_ => {}
}
return Err(ParseError::BadInstruction);
return Err(ParseError::BadInstruction);
} }
fn parse_const(i: &str) -> Result<Const, ParseError> { fn parse_const(i: &str) -> Result<Const, ParseError> {
// we try to parse the number, if we fail, we treat it as a string. // we try to parse the number, if we fail, we treat it as a string.
let Ok(num) = i.parse() else { let Ok(num) = i.parse() else {
return Ok(Const::CS(i.to_owned())); return Ok(Const::CS(i.to_owned()));
}; };
return Ok(Const::C(num)); return Ok(Const::C(num));
} }

View File

@ -1,16 +1,18 @@
// use super::*; // use super::*;
use crate::assembler::parser; #[cfg(test)]
mod tests {
use crate::assembler::parser;
#[test] #[test]
fn parser_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 mut parser = parser::Parser::new(code);
let code = std::fs::read_to_string("./tests/assembly/hello_world.grasm").unwrap();
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);
} }

View File

@ -2,7 +2,9 @@ mod decoder;
mod ram; mod ram;
mod registers; mod registers;
mod sysenv; mod sysenv;
mod tests; mod tests;
pub use sysenv::*; pub use sysenv::*;
pub use registers::*; pub use registers::*;

View File

@ -70,7 +70,7 @@ impl Sys for IOBuffer {
.slice(pos, MAX_MEM as Word - 1) .slice(pos, MAX_MEM as Word - 1)
.ok_or(ExecErr::InvalidMemoryAddr)?; .ok_or(ExecErr::InvalidMemoryAddr)?;
let (s, _) = find_and_read_string(&data) 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); cpu.env.output.push_str(&s);
} }

View File

@ -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] let mut code: Vec<u16> = vec![
fn hello_world_binary_test() { 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<u16> = vec![ let mut cpu = CPU::new(&mut env);
0b0111000100000011, // addi ra 3
0b1110000100000011, // ecall ra 3
0b1111000000000000, // HALT.
];
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); assert_eq!(hw, cpu.env.output);
for c in &code[..] {
println!("{:#018b}", c);
} }
cpu.run_code_raw(&code);
assert_eq!(hw, cpu.env.output);
} }

View File

@ -7,7 +7,6 @@ pub mod loader;
pub mod assembler; pub mod assembler;
// //
pub fn interpret_as_signed(x: u16) -> i16 { pub fn interpret_as_signed(x: u16) -> i16 {
// the two types have the same size. // the two types have the same size.
unsafe { unsafe {

View File

@ -1,6 +1,6 @@
use crate::cpu::Word; use crate::cpu::Word;
use super::{constants::MAGIC, Section}; use super::Section;
#[derive(Debug)] #[derive(Debug)]
pub enum ParseError { pub enum ParseError {
@ -71,7 +71,7 @@ pub fn read_binary(b: &[u16]) -> Result<Vec<Section>, ParseError> {
/// Parses binary headers /// Parses binary headers
fn parse_header(b: &[Word]) -> Result<Vec<(u16, u16)>, ParseError> { fn parse_header(b: &[Word]) -> Result<Vec<(u16, u16)>, 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. // Magic number check. Can go unchecked, check spec.
// if (*m != MAGIC) { // if (*m != MAGIC) {

View File

@ -1,61 +1,65 @@
use super::loader::*; #[cfg(test)]
use super::unloader::*; mod tests {
use super::*; use crate::loader::Section;
// fuzzable, TODO use super::super::loader::*;
fn write_read_str_identity(s: &str) { use super::super::unloader::*;
let mut bytes = make_string(s);
// pop null-terminator; // fuzzable, TODO
// bytes.pop().expect("String doesn't even have a single byte?"); fn write_read_str_identity(s: &str) {
// println!("w-r s: {:?}, b: {:?}", s, bytes); let bytes = make_string(s);
let (s0, _) = find_and_read_string(&bytes).unwrap();
assert_eq!(s, &s0);
}
fn read_write_str_identity(b: Vec<u16>) { // pop null-terminator;
let (string, _) = find_and_read_string(&b).unwrap(); // bytes.pop().expect("String doesn't even have a single byte?");
let mut n_term = b.clone(); // println!("w-r s: {:?}, b: {:?}", s, bytes);
// n_term.push(0); let (s0, _) = find_and_read_string(&bytes).unwrap();
// println!("r-w s: {:?}, b: {:?}", string, n_term); assert_eq!(s, &s0);
assert_eq!(n_term, make_string(&string)); }
}
#[test] fn read_write_str_identity(b: Vec<u16>) {
fn label_parse_identity() { let (string, _) = find_and_read_string(&b).unwrap();
let testwords = vec!["Hello,", "main", "è", "Hello,,", "v", "main", "pi"]; // should support utf-8 let n_term = b.clone();
// // n_term.push(0);
for word in testwords { // println!("r-w s: {:?}, b: {:?}", string, n_term);
println!("\nTEST {}\n", word); assert_eq!(n_term, make_string(&string));
}
write_read_str_identity(word); #[test]
let bytes = make_string(word); fn label_parse_identity() {
// bytes.pop(); let testwords = vec!["Hello,", "main", "è", "Hello,,", "v", "main", "pi"]; // should support utf-8
println!( //
"word: {:?}, bytes: {:?}, length: {:?}", for word in testwords {
word, println!("\nTEST {}\n", word);
bytes,
bytes.len() write_read_str_identity(word);
); let bytes = make_string(word);
read_write_str_identity(bytes); // bytes.pop();
println!("Done with {:?}", word); 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<Section> = 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<Section> = 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);
}

View File

@ -27,6 +27,4 @@ fn main() {
} }
Err(e) => println!("Err: {:?}", e), Err(e) => println!("Err: {:?}", e),
}; };
} }