test: typing of function calls

master
Araozu 2024-08-12 19:07:28 -05:00
parent 462b45ee51
commit f7168f1d09
1 changed files with 94 additions and 8 deletions

View File

@ -35,17 +35,29 @@ impl Typed for Expression<'_> {
// for this to work with any arbitrary expression. // for this to work with any arbitrary expression.
// for now it justs expects an identifier // for now it justs expects an identifier
// The type of a function call is the return type
// of the function
// TODO: Should this check that the type signature is correct?
// or is this done elsewhere?
match &*f.function { match &*f.function {
Expression::Identifier(id) => { Expression::Identifier(id) => {
match scope.get_type(&id.value) { match scope.get_type(&id.value) {
Some(t) => Ok(t), Some(Type::Function(_, return_type)) => {
// Return the return type of the function,
// not the function itself
Ok(Type::Value(return_type))
},
Some(_) => Err(MistiError::Semantic(SemanticError {
error_start: id.position,
error_end: id.get_end_position(),
reason: format!("Expected `{}` to be a function", &id.value),
})),
None => Err(MistiError::Semantic(SemanticError { None => Err(MistiError::Semantic(SemanticError {
// TODO: Actually find the start and end position error_start: id.position,
// this requires the token to be stored, rather than error_end: id.get_end_position(),
// just the string value reason: format!("Cannot find `{}` in this scope.", id.value),
error_start: 0,
error_end: 1,
reason: format!("Type not found for symbol {}", id.value),
})), })),
} }
} }
@ -118,7 +130,7 @@ impl Typed for Expression<'_> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{error_handling::MistiError, lexic::token::Token, semantic::{std::populate, symbol_table::SymbolTable, types::{Type, Typed}}, syntax::ast::Expression}; use crate::{error_handling::MistiError, lexic::token::Token, semantic::{std::populate, symbol_table::SymbolTable, types::{Type, Typed}}, syntax::ast::{functions::{ArgumentsList, FunctionCall}, Expression}};
#[test] #[test]
fn should_get_global_print_type() { fn should_get_global_print_type() {
@ -156,4 +168,78 @@ mod tests {
Err(e) => panic!("Expected a semantic error, got {:?}", e) Err(e) => panic!("Expected a semantic error, got {:?}", e)
} }
} }
#[test]
fn should_get_type_from_function_call() {
let mut scope = SymbolTable::new();
populate(&mut scope);
let id_token = Token::new_identifier("print".into(), 0);
let fn_expr = Expression::Identifier(&id_token);
let args = ArgumentsList{arguments: vec![]};
let fn_call = Expression::FunctionCall(FunctionCall {
function: Box::new(fn_expr),
arguments: Box::new(args),
});
match fn_call.get_type(&scope) {
Ok(Type::Value(v)) => assert_eq!(v, "Void"),
Ok(v) => panic!("Expected a value, got {:?}", v),
Err(e) => panic!("Expected a value, got Err {:?}", e),
}
}
#[test]
fn should_fail_if_a_function_is_expected() {
let scope = SymbolTable::new();
// Add `print` as a Int
scope.insert("print".into(), Type::Value("Int".into()));
let id_token = Token::new_identifier("print".into(), 0);
let fn_expr = Expression::Identifier(&id_token);
let args = ArgumentsList{arguments: vec![]};
let fn_call = Expression::FunctionCall(FunctionCall {
function: Box::new(fn_expr),
arguments: Box::new(args),
});
match fn_call.get_type(&scope) {
Ok(v) => panic!("Expected an error, got {:?}", v),
Err(MistiError::Semantic(e)) => {
assert_eq!(e.error_start, 0);
assert_eq!(e.error_end, 5);
assert_eq!(e.reason, "Expected `print` to be a function");
}
Err(e) => panic!("Expected a semantic error, got {:?}", e),
}
}
#[test]
fn should_fail_if_a_function_is_not_defined() {
let scope = SymbolTable::new();
let id_token = Token::new_identifier("print".into(), 0);
let fn_expr = Expression::Identifier(&id_token);
let args = ArgumentsList{arguments: vec![]};
let fn_call = Expression::FunctionCall(FunctionCall {
function: Box::new(fn_expr),
arguments: Box::new(args),
});
match fn_call.get_type(&scope) {
Ok(v) => panic!("Expected an error, got {:?}", v),
Err(MistiError::Semantic(e)) => {
assert_eq!(e.error_start, 0);
assert_eq!(e.error_end, 5);
assert_eq!(e.reason, "Cannot find `print` in this scope.");
}
Err(e) => panic!("Expected a semantic error, got {:?}", e),
}
}
} }