Skip to content

Commit

Permalink
add undefined error, line numbers and other stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
Glyphack committed Sep 9, 2023
1 parent a24f7e3 commit ae527b4
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 17 deletions.
13 changes: 11 additions & 2 deletions typechecker/src/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,11 @@ impl BuildManager {
for stmt in &state.1.file.body {
checker.type_check(stmt);
}
self.errors.append(&mut checker.errors);
for error in checker.errors {
let line = get_line_number_of_character_position(&state.1.file.source, error.start);
let error = format!("{} line {}: {}", state.0, line, error.msg);
self.errors.push(error);
}
}
}
}
Expand All @@ -99,7 +103,7 @@ fn get_line_number_of_character_position(source: &str, pos: usize) -> usize {
}
}
line_number
}
}

#[cfg(test)]
mod tests {
Expand Down Expand Up @@ -189,4 +193,9 @@ mod tests {
test_type_check_list,
"../testdata/inputs/type_check_list.py"
);

snap_type!(
test_type_check_undefined,
"../testdata/inputs/type_check_undefined.py"
);
}
37 changes: 28 additions & 9 deletions typechecker/src/type_check/checker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,19 @@ use super::{type_evaluator::TypeEvaluator, type_inference::type_check_bin_op, ty

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

pub struct TypeCheckError {
pub msg: String,
pub start: usize,
pub end: usize,
}

#[allow(unused)]
impl<'a> TypeChecker<'a> {
pub fn new(module: &'a State, options: &'a Settings) -> Self {
Expand All @@ -38,8 +44,7 @@ impl<'a> TypeChecker<'a> {
Ok(t) => t,
Err(e) => {
self.make_error(
&format!("Failed to infer type for expression: {}", e),
&format!("{:?}", expr),
e.to_string().as_str(),
expr.get_node().start,
expr.get_node().end,
);
Expand All @@ -48,8 +53,12 @@ impl<'a> TypeChecker<'a> {
}
}

fn make_error(&mut self, msg: &str, code: &str, start: usize, end: usize) {
let error = format!("{}: {} at ({})", msg, code, start);
fn make_error(&mut self, msg: &str, start: usize, end: usize) {
let error = TypeCheckError {
msg: msg.to_string(),
start,
end,
};
self.errors.push(error);
}
}
Expand Down Expand Up @@ -237,10 +246,15 @@ impl<'a> TraversalVisitor for TypeChecker<'a> {
let r_type = self.infer_expr_type(&b.right);

if !type_check_bin_op(&l_type, &r_type, &b.op) {
self.errors.push(format!(
let msg = format!(
"Operator '{}' not supported for types '{}' and '{}'",
b.op, l_type, r_type
));
);
self.errors.push(TypeCheckError {
msg,
start: b.node.start,
end: b.node.end,
});
}
}

Expand Down Expand Up @@ -300,10 +314,15 @@ impl<'a> TraversalVisitor for TypeChecker<'a> {
.get_symbol_node_type(symbol, n.node.start).unwrap_or(Type::Unknown);
let value_type = self.infer_expr_type(&_a.value);
if !is_reassignment_valid(&prev_target_type, &value_type) {
self.errors.push(format!(
let msg = format!(
"Cannot assign type '{}' to variable of type '{}'",
value_type, prev_target_type
));
);
self.errors.push(TypeCheckError {
msg,
start: n.node.start,
end: n.node.end,
});
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions typechecker/src/type_check/type_inference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ pub fn type_check_bin_op(t1: &Type, t2: &Type, op: &BinaryOperator) -> bool {
};

for (t1_, t2_) in check_table {
if matches!(t1, Type::Unknown) || matches!(t2, Type::Unknown) {
return true;
}
if type_equal(t1, &t1_) && type_equal(t2, &t2_) {
return true;
}
Expand Down
4 changes: 4 additions & 0 deletions typechecker/testdata/inputs/type_check_undefined.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
a = b + 1

a = c()

Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ source: typechecker/src/build.rs
description: "def function() -> int:\n return 1\n\na = function()\nb = function() + \"1\"\nc = a + 1\nd = function() + 1\n\nfunction + 1\n"
expression: result
---
Operator '+' not supported for types 'Int' and 'Str'
Operator '+' not supported for types 'function' and 'Int'
test line 5: Operator '+' not supported for types 'Int' and 'Str'
test line 9: Operator '+' not supported for types 'function' and 'Int'
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ source: typechecker/src/build.rs
description: "a: list[int] = [1, 2, 3]\n\nb = a[0] + 1\n\nc = a[0] + a[1]\n\n# invalid usage of types\nd = a[0] + \"str\"\n\n# valid reassignment\na = [1]\n# invalid reassignment\na = [1, 2, \"str\"]\n"
expression: result
---
Operator '+' not supported for types 'Int' and 'Str'
Cannot assign type 'builtins.list[Unknown]' to variable of type 'builtins.list[Int]'
test line 8: Operator '+' not supported for types 'Int' and 'Str'
test line 13: Cannot assign type 'builtins.list[Unknown]' to variable of type 'builtins.list[Int]'
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
source: typechecker/src/build.rs
description: "a = b + 1\n\na = c()\n\n"
expression: result
---
test line 1: symbol b is not defined
test line 1: symbol b is not defined
test line 3: symbol c is not defined
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
source: typechecker/src/build.rs
description: "a: int = 1\n\na + \"str\"\n"
description: "a: int = 1\n\na + \"str\"\n\nb = a + 1\n\nc = b + b\n"
expression: result
---
Operator '+' not supported for types 'Int' and 'Str'
test line 3: Operator '+' not supported for types 'Int' and 'Str'

0 comments on commit ae527b4

Please sign in to comment.