Skip to content

Commit

Permalink
Merge pull request #166 from Glyphack/move-type-evaluator-tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Glyphack authored Sep 6, 2023
2 parents 8d071f8 + 7a75bc5 commit 17f981b
Show file tree
Hide file tree
Showing 7 changed files with 97 additions and 83 deletions.
2 changes: 1 addition & 1 deletion cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ fn symbols(path: &PathBuf) -> std::result::Result<(), anyhow::Error> {
manager.build();
let module = manager.modules.values().last().unwrap();

println!("{}", module.symbol_table);
println!("{}", module.get_symbol_table());

Ok(())
}
Expand Down
75 changes: 5 additions & 70 deletions typechecker/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl BuildManager {
let file = Box::new(Self::parse_file(&build_source.source, build_source.module));
let symbol_table = SymbolTable::new(crate::symbol_table::SymbolTableType::Module, 0);

modules.insert(mod_name, State { file, symbol_table });
modules.insert(mod_name, State::new(file));
}

BuildManager {
Expand Down Expand Up @@ -75,24 +75,21 @@ impl BuildManager {
}
}

// TODO: separate this can build to be able to test pre analysis and type checking separately
// Performs type checking passes over the code
pub fn type_check(&mut self) {
self.pre_analysis();
for state in self.modules.iter_mut() {
let mut checker = TypeChecker::new(state.1, &self.options);
checker.type_check();
for stmt in &state.1.file.body {
checker.type_check(stmt);
}
self.errors.append(&mut checker.errors);
}
}
}

#[cfg(test)]
mod tests {
use parser::ast::GetNode;

use crate::type_check::type_evaluator::TypeEvaluator;

use super::*;
fn snapshot_symbol_table(source: &str) -> String {
let mut manager = BuildManager::new(
Expand All @@ -108,7 +105,7 @@ mod tests {

let module = manager.modules.values().last().unwrap();

format!("{}", module.symbol_table)
format!("{}", module.get_symbol_table())
}

fn snapshot_type_check(source: &str) -> String {
Expand All @@ -126,50 +123,6 @@ mod tests {
manager.errors.join("\n").to_string()
}

// TODO: refactor and move the test to type check mod
fn snapshot_type_eval(source: &str) -> String {
let mut manager = BuildManager::new(
vec![BuildSource {
path: PathBuf::from("test.py"),
module: String::from("test"),
source: source.to_string(),
followed: false,
}],
Settings::test_settings(),
);

manager.build();

let module = manager.modules.values().last().unwrap();
let symbol_table = module.symbol_table.clone();
let enderpy_file = module.file.clone();

let type_eval = TypeEvaluator::new(symbol_table);

let mut result = HashMap::new();

for stmt in enderpy_file.body {
match stmt {
parser::ast::Statement::ExpressionStatement(e) => {
let t = type_eval.get_type(&e);
match e {
parser::ast::Expression::Name(n) => {
result.insert(n.id, t.to_string());
}
_ => panic!("don't use this test for other expressions"),
}
}
_ => {}
}
}

// sort result by key
let mut result_sorted = result.clone().into_iter().collect::<Vec<_>>();
result_sorted.sort_by(|a, b| a.0.cmp(&b.0));

return format!("{:#?}", result_sorted);
}

macro_rules! snap {
($name:tt, $path:tt) => {
#[test]
Expand Down Expand Up @@ -202,22 +155,6 @@ mod tests {
};
}

macro_rules! snap_type_eval {
($name:tt, $path:tt) => {
#[test]
fn $name() {
let contents = include_str!($path);
let result = snapshot_type_eval(contents);
let mut settings = insta::Settings::clone_current();
settings.set_snapshot_path("../testdata/output/");
settings.set_description(contents);
settings.bind(|| {
insta::assert_snapshot!(result);
});
}
};
}

snap!(
test_simple_var_assignments,
"../testdata/inputs/simple_var_assignment.py"
Expand All @@ -239,6 +176,4 @@ mod tests {
test_type_check_list,
"../testdata/inputs/type_check_list.py"
);

snap_type_eval!(test_type_eval_vars, "../testdata/inputs/type_eval_vars.py");
}
12 changes: 11 additions & 1 deletion typechecker/src/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ use crate::{

pub struct State {
pub file: Box<EnderpyFile>,
pub symbol_table: SymbolTable,
symbol_table: SymbolTable,
}

impl State {
pub fn new(file: Box<EnderpyFile>) -> Self {
Self {
file,
symbol_table: SymbolTable::new(crate::symbol_table::SymbolTableType::Module, 0),
}
}
/// entry point to fill up the symbol table from the global definitions
pub fn populate_symbol_table(&mut self) {
let mut sem_anal = SemanticAnalyzer::new(self.file.clone());
Expand All @@ -17,4 +23,8 @@ impl State {
}
self.symbol_table = sem_anal.globals
}

pub fn get_symbol_table(&self) -> SymbolTable {
self.symbol_table.clone()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
source: typechecker/src/build.rs
source: typechecker/src/type_check/type_evaluator.rs
description: "# define variables with various types for testing\na = 1\nb = 2\nc = True\nd = False\ne = \"hello\"\nf = \"world\"\n# g = [1,2,3]\n# h = (1,2,3)\n# i = {1,2,3}\n# j = {\"a\":1,\"b\":2,\"c\":3}\n# k = None\n\na\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk\n\n"
expression: result
---
Expand Down
24 changes: 14 additions & 10 deletions typechecker/src/type_check/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,39 @@ use ast::{Expression, Statement};
use parser::ast::{self, *};

use crate::{
ast_visitor::TraversalVisitor, settings::Settings, state::State,
ast_visitor::TraversalVisitor, settings::Settings, state::State, symbol_table::SymbolTable,
type_check::rules::is_reassignment_valid,
};

use super::{type_evaluator::TypeEvaluator, type_inference::type_check_bin_op, types::Type};

// TODO: currently only supporting a single file
pub struct TypeChecker<'a> {
pub errors: Vec<String>,
// TODO: currently only supporting a single file
pub module: &'a State,
// The symbol table of the module being type checked
symbol_table: SymbolTable,
// statements to type check
statements: Vec<Statement>,
pub options: &'a Settings,
type_evaluator: TypeEvaluator,
}

#[allow(unused)]
impl<'a> TypeChecker<'a> {
pub fn new(module: &'a State, options: &'a Settings) -> Self {
let symbol_table = module.get_symbol_table();
let statements = module.file.body.clone();
TypeChecker {
errors: vec![],
module,
symbol_table,
statements,
options,
type_evaluator: TypeEvaluator::new(module.symbol_table.clone()),
type_evaluator: TypeEvaluator::new(module.get_symbol_table()),
}
}

pub fn type_check(&mut self) {
for stmt in &self.module.file.body {
self.visit_stmt(stmt);
}
pub fn type_check(&mut self, statement: &Statement) {
self.visit_stmt(statement);
}

fn infer_expr_type(&mut self, expr: &Expression) -> Type {
Expand Down Expand Up @@ -325,7 +329,7 @@ impl<'a> TraversalVisitor for TypeChecker<'a> {
for target in &_a.targets {
match target {
ast::Expression::Name(n) => {
let symbol = self.module.symbol_table.lookup_in_scope(&n.id);
let symbol = self.symbol_table.lookup_in_scope(&n.id);
if let Some(symbol) = symbol {
let prev_target_type = self
.type_evaluator
Expand Down
65 changes: 65 additions & 0 deletions typechecker/src/type_check/type_evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,3 +421,68 @@ impl TraversalVisitorImmutGeneric<Type> for TypeEvaluator {
todo!()
}
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;

use super::*;
// TODO: refactor and move the test to type check mod
fn snapshot_type_eval(source: &str) -> String {
use crate::nodes::EnderpyFile;
use crate::state::State;
use parser::Parser;

let mut parser = Parser::new(source.to_string());
let ast_module = parser.parse();

let enderpy_file = EnderpyFile::from(ast_module, "test".to_string());

let mut module = State::new(Box::new(enderpy_file));
module.populate_symbol_table();
let symbol_table = module.get_symbol_table();

let type_eval = TypeEvaluator::new(symbol_table);

let mut result = HashMap::new();

for stmt in module.file.body {
match stmt {
parser::ast::Statement::ExpressionStatement(e) => {
let t = type_eval.get_type(&e);
match e {
parser::ast::Expression::Name(n) => {
result.insert(n.id, t.to_string());
}
_ => panic!("don't use this test for other expressions"),
}
}
_ => {}
}
}

// sort result by key
let mut result_sorted = result.clone().into_iter().collect::<Vec<_>>();
result_sorted.sort_by(|a, b| a.0.cmp(&b.0));

return format!("{:#?}", result_sorted);
}

macro_rules! snap_type_eval {
($name:tt, $path:tt) => {
#[test]
fn $name() {
let contents = include_str!($path);
let result = snapshot_type_eval(contents);
let mut settings = insta::Settings::clone_current();
settings.set_snapshot_path("../testdata/output/");
settings.set_description(contents);
settings.bind(|| {
insta::assert_snapshot!(result);
});
}
};
}

snap_type_eval!(test_type_eval_vars, "./testdata/inputs/type_eval_vars.py");
}

0 comments on commit 17f981b

Please sign in to comment.