test: typing of function calls
This commit is contained in:
parent
462b45ee51
commit
f7168f1d09
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user