Skip to content

Commit

Permalink
improving compiler by writing some noob tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rigel-star committed Feb 7, 2024
1 parent fe912b6 commit 66c24ac
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 12 deletions.
1 change: 1 addition & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,7 @@ impl ASTTraverser {
value_containing_reg
}

// Refer to this page for explanation on '@PAGE' and '@PAGEOFF': https://stackoverflow.com/questions/65351533/apple-clang12-llvm-unknown-aarch64-fixup-kind
fn gen_load_reg_into_gid(&mut self, reg: usize, id: &LitType) -> usize {
let reg_name: String = self.reg_manager.borrow().name(reg);
let mut offset: usize = 0;
Expand Down
50 changes: 49 additions & 1 deletion src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,9 @@ impl<'a> Parser<'a> {
cond_ast
}

/*
TODO: Check type of the variable before assigning
*/
fn parse_assignment_stmt(&mut self) -> Option<ASTNode> {
let id_token: Token = self.token_match(TokenKind::T_IDENTIFIER).clone();
let _id_index_symt: usize = self.sym_table.borrow().find_symbol(&id_token.lexeme);
Expand Down Expand Up @@ -275,7 +278,7 @@ impl<'a> Parser<'a> {
(left.clone(), right, rt)
}
};
return Some(ASTNode::new(ASTNodeKind::from_token_kind(current_token_kind), Some(_left), Some(_right), None, _rtype));
return Some(ASTNode::new(ASTNodeKind::from_token_kind(current_token_kind), Some(_left), Some(_right), Some(LitType::I32(0)), _rtype));
} else {
panic!("Something unexpected happended with this token: '{:?}'", self.current_token);
}
Expand All @@ -299,6 +302,12 @@ impl<'a> Parser<'a> {
let symbol: Symbol = self.sym_table.borrow().get_symbol(id_index).clone();
Some(ASTNode::make_leaf(ASTNodeKind::AST_IDENT, LitType::I32(id_index as i32), symbol.lit_type))
},
TokenKind::T_LPAREN => { // group expression: e.g: (a * (b + c)))
let group_expr: Option<ASTNode> = self.parse_equality();
// Group expression terminates with ')'. Match and ignore ')'.
self.token_match(TokenKind::T_RPAREN);
group_expr
},
_ => {
println!("{:?}", current_token);
panic!("Unrecognized primitive type: {:?}", self.current_token);
Expand Down Expand Up @@ -335,6 +344,22 @@ impl<'a> Parser<'a> {
mod tests {
use super::*;

#[test]
fn test_group_expression_tree_structure() {
let mut tokener: Tokenizer = Tokenizer::new("(5 + (3 * 4))");
let tokens: Vec<Token> = tokener.start_scan();
let sym_table: Rc<RefCell<Symtable>> = Rc::new(RefCell::new(Symtable::new()));
let mut p: Parser = Parser::new(&tokens, Rc::clone(&sym_table));
let result: Option<ASTNode> = p.parse_equality();
matches!(result, Some(_));
let upvalue: ASTNode = result.unwrap();
let left_tree: &ASTNode = (*upvalue.left).as_ref().unwrap();
let right_tree: &ASTNode = (*upvalue.right).as_ref().unwrap();
assert_eq!(upvalue.operation, ASTNodeKind::AST_ADD);
assert_eq!(left_tree.operation, ASTNodeKind::AST_INTLIT);
assert_eq!(right_tree.operation, ASTNodeKind::AST_MULTIPLY);
}

// test addition operation
#[test]
fn test_depth_one_bin_tree() {
Expand All @@ -346,4 +371,27 @@ mod tests {
matches!(result, Some(_));
assert_eq!(result.unwrap().operation, ASTNodeKind::AST_ADD);
}

// test if-else block
#[test]
fn test_if_else_statement_block() {
let mut tokener: Tokenizer = Tokenizer::new("if (4 > 5) { global int a; } else { global int b; }");
let tokens: Vec<Token> = tokener.start_scan();
let sym_table: Rc<RefCell<Symtable>> = Rc::new(RefCell::new(Symtable::new()));
let mut p: Parser = Parser::new(&tokens, Rc::clone(&sym_table));
let result: Option<ASTNode> = p.parse_if_stmt();
matches!(result, Some(_));
let upvalue: &ASTNode = result.as_ref().unwrap();
// Global variable declaration statements produce None as result.
// So, both 'mid (if)' and 'right (else)' has to be None types
matches!(*upvalue.mid, None);
matches!(*upvalue.right, None);
assert_eq!(upvalue.operation, ASTNodeKind::AST_IF); // main AST node is of AST_IF type
assert_eq!((*upvalue.left).as_ref().unwrap().operation, ASTNodeKind::AST_GTHAN);
}

#[test]
fn test_while_statement_block() {

}
}
61 changes: 54 additions & 7 deletions src/symtable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::enums::*;
use crate::types::*;
use std::slice::Iter;

#[derive(Clone)]
#[derive(Clone, PartialEq, Debug)]
pub struct Symbol {
pub name: String,
pub lit_type: LitType, // What kind of value this symbol is
Expand Down Expand Up @@ -66,10 +66,8 @@ impl Symtable {
}

fn next(&mut self) -> usize {
assert!(self.counter < NSYMBOLS);
self.counter += 1;
if self.counter >= NSYMBOLS {
panic!("too many global symbols");
}
self.counter
}

Expand All @@ -84,9 +82,58 @@ impl Symtable {
}

pub fn get_symbol(&self, idx: usize) -> &Symbol {
if idx >= self.syms.len() {
panic!("index '{}' out of bounds for range '{}'", idx, self.syms.len());
}
assert!(self.counter < NSYMBOLS);
self.syms.get(idx).unwrap()
}

pub fn remove_symbol(&mut self, index: usize) -> Symbol {
assert!(self.counter < NSYMBOLS);
self.syms.remove(index)
}
}

#[cfg(test)]
mod tests {
use super::{Symbol, SymbolType, Symtable, NSYMBOLS};

#[test]
fn test_symbol_addition() {
let mut table: Symtable = Symtable::new();
assert_eq!(table.add_symbol(Symbol::new(String::from("number"), super::LitType::I32(0), SymbolType::Variable)), 0);
assert_eq!(table.syms.len(), 1);
assert_eq!(table.add_symbol(Symbol::new(String::from("number2"), super::LitType::I32(0), SymbolType::Variable)), 1);
assert_eq!(table.add_symbol(Symbol::new(String::from("number3"), super::LitType::I32(0), SymbolType::Variable)), 2);
assert_eq!(table.add_symbol(Symbol::new(String::from("number4"), super::LitType::I32(0), SymbolType::Variable)), 3);
assert_eq!(table.add_symbol(Symbol::new(String::from("number5"), super::LitType::I32(0), SymbolType::Variable)), 4);
assert_eq!(table.add_symbol(Symbol::new(String::from("number6"), super::LitType::I32(0), SymbolType::Variable)), 5);
}

// This test insures that no more than 1024 symbols are defined in program.
#[test]
#[should_panic(expected="assertion failed")]
fn test_more_than_1024_symbols_creates_panic_situation() {
let mut table: Symtable = Symtable::new();
table.counter = NSYMBOLS;
table.add_symbol(Symbol::new(String::from("number"), super::LitType::I32(0), SymbolType::Variable));
}

#[test]
fn test_find_symbol_index_from_it_name() {
let mut table: Symtable = Symtable::new();
table.add_symbol(Symbol::new(String::from("number2"), super::LitType::I32(0), SymbolType::Variable));
table.add_symbol(Symbol::new(String::from("number3"), super::LitType::I32(0), SymbolType::Variable));
table.add_symbol(Symbol::new(String::from("number4"), super::LitType::I32(0), SymbolType::Variable));
assert_eq!(table.find_symbol("number2"), 0);
assert_eq!(table.find_symbol("number3"), 1);
assert_eq!(table.find_symbol("number4"), 2);
}

#[test]
fn test_symbol_removal() {
let mut table: Symtable = Symtable::new();
table.add_symbol(Symbol::new(String::from("number2"), super::LitType::I32(0), SymbolType::Variable));
table.add_symbol(Symbol::new(String::from("number3"), super::LitType::I32(0), SymbolType::Variable));
table.add_symbol(Symbol::new(String::from("number4"), super::LitType::I32(0), SymbolType::Variable));
assert_eq!(table.remove_symbol(0), Symbol::new(String::from("number2"), crate::symtable::LitType::I32(0), SymbolType::Variable));
}
}
17 changes: 13 additions & 4 deletions src/tokenizer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ impl Tokenizer {
} else {
let _value: i64 = number.parse::<i64>().unwrap();
token.kind = if (0..256).contains(&_value) { TokenKind::T_CHAR }
else if (0..std::i64::MAX).contains(&_value) { TokenKind::T_LONG_NUM }
else if ((std::i32::MAX as i64)..std::i64::MAX).contains(&_value) { TokenKind::T_LONG_NUM }
else { TokenKind::T_INT_NUM }
}
token.lexeme = String::from(number);
Expand Down Expand Up @@ -554,15 +554,24 @@ mod tests {
fn test_empty_source() {
let mut tok: Tokenizer = Tokenizer::new("");
let tokens: Vec<Token> = tok.start_scan();
assert_eq!(tokens.len(), 1); // only EOF is present
assert_eq!(tokens[0].kind, TokenKind::T_EOF); // only EOF is present
assert_eq!(tokens.len(), 1); // only T_EOF is present
assert_eq!(tokens[0].kind, TokenKind::T_EOF); // only T_EOF is present
}

#[test]
fn test_only_whitespace_source() {
let mut tok: Tokenizer = Tokenizer::new(" ");
let tokens: Vec<Token> = tok.start_scan();
assert_eq!(tokens.len(), 1); // only EOF is present
assert_eq!(tokens.len(), 1); // only T_EOF is present
assert_eq!(tokens[0].kind, TokenKind::T_EOF); // only EOF is present
}

#[test]
fn test_while_if_else_statement() {
let mut tok: Tokenizer = Tokenizer::new("if (4 > 5) { } else { }");
let tokens: Vec<Token> = tok.start_scan();
assert_eq!(tokens.len(), 12); // including T_EOF
assert_eq!(tokens[0].kind, TokenKind::KW_IF);
assert_eq!(tokens[8].kind, TokenKind::KW_ELSE);
}
}

0 comments on commit 66c24ac

Please sign in to comment.