refactor: move function call check to its own file
This commit is contained in:
parent
4760eea8f4
commit
3475b55db5
90
src/semantic/checks/expression/funtion_call.rs
Normal file
90
src/semantic/checks/expression/funtion_call.rs
Normal file
@ -0,0 +1,90 @@
|
||||
use crate::{
|
||||
error_handling::{
|
||||
error_messages::{SEMANTIC_MISMATCHED_ARGUMENT_COUNT, SEMANTIC_MISMATCHED_TYPES},
|
||||
ErrorContainer, ErrorLabel,
|
||||
},
|
||||
semantic::{
|
||||
impls::SemanticCheck,
|
||||
symbol_table::SymbolTable,
|
||||
types::{Type, Typed},
|
||||
},
|
||||
syntax::ast::{functions::FunctionCall, Positionable},
|
||||
};
|
||||
|
||||
impl SemanticCheck for FunctionCall<'_> {
|
||||
fn check_semantics(
|
||||
&self,
|
||||
scope: &SymbolTable,
|
||||
) -> Result<(), crate::error_handling::MistiError> {
|
||||
let fun = &*self.function;
|
||||
let arguments = &*self.arguments.arguments;
|
||||
|
||||
let function_datatype = fun.get_type(scope)?;
|
||||
let Type::Function(parameters, _) = function_datatype else {
|
||||
let (error_start, error_end) = fun.get_position();
|
||||
let label = ErrorLabel {
|
||||
message: format!("Expected a function type, got {:?}", function_datatype),
|
||||
start: error_start,
|
||||
end: error_end,
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||
error_offset: error_start,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(econtainer);
|
||||
};
|
||||
|
||||
// Check parameters length
|
||||
if parameters.len() != arguments.len() {
|
||||
let (error_start, error_end) = self.arguments.get_position();
|
||||
|
||||
let label = ErrorLabel {
|
||||
message: format!(
|
||||
"Expected {} arguments, got {}",
|
||||
parameters.len(),
|
||||
arguments.len(),
|
||||
),
|
||||
start: error_start,
|
||||
end: error_end,
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
||||
error_offset: error_start,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(econtainer);
|
||||
}
|
||||
|
||||
// Check that each argument matches the required datatype
|
||||
for i in 0..parameters.len() {
|
||||
let parameter = ¶meters[i];
|
||||
let argument = &arguments[i];
|
||||
|
||||
let argument_datatype = argument.get_type(scope)?;
|
||||
if !argument_datatype.is_value(parameter) {
|
||||
// The argument and the parameter have diferent types
|
||||
let (error_start, error_end) = argument.get_position();
|
||||
let label = ErrorLabel {
|
||||
message: format!("Expected a {}, got {:?}", parameter, argument_datatype),
|
||||
start: error_start,
|
||||
end: error_end,
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||
error_offset: error_start,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(econtainer);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
@ -14,90 +14,12 @@ use crate::{
|
||||
syntax::ast::{Expression, Positionable},
|
||||
};
|
||||
|
||||
mod funtion_call;
|
||||
|
||||
impl SemanticCheck for Expression<'_> {
|
||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
||||
match self {
|
||||
Expression::FunctionCall(f) => {
|
||||
let fun = &*f.function;
|
||||
let arguments = &*f.arguments.arguments;
|
||||
|
||||
let function_datatype = fun.get_type(scope)?;
|
||||
match function_datatype {
|
||||
Type::Function(parameters, _return_type) => {
|
||||
// Check parameters length
|
||||
if parameters.len() != arguments.len() {
|
||||
let (error_start, error_end) = f.arguments.get_position();
|
||||
|
||||
let label = ErrorLabel {
|
||||
message: format!(
|
||||
"Expected {} arguments, got {}",
|
||||
parameters.len(),
|
||||
arguments.len(),
|
||||
),
|
||||
start: error_start,
|
||||
end: error_end,
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SEMANTIC_MISMATCHED_ARGUMENT_COUNT,
|
||||
error_offset: error_start,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(econtainer);
|
||||
}
|
||||
|
||||
// Check that each argument matches the required datatype
|
||||
for i in 0..parameters.len() {
|
||||
let parameter = ¶meters[i];
|
||||
let argument = &arguments[i];
|
||||
|
||||
let argument_datatype = argument.get_type(scope)?;
|
||||
if !argument_datatype.is_value(parameter) {
|
||||
// The argument and the parameter have diferent types
|
||||
let (error_start, error_end) = argument.get_position();
|
||||
let label = ErrorLabel {
|
||||
message: format!(
|
||||
"Expected a {}, got {:?}",
|
||||
parameter, argument_datatype
|
||||
),
|
||||
start: error_start,
|
||||
end: error_end,
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||
error_offset: error_start,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(econtainer);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
let (error_start, error_end) = fun.get_position();
|
||||
let label = ErrorLabel {
|
||||
message: format!(
|
||||
"Expected a function type, got {:?}",
|
||||
function_datatype
|
||||
),
|
||||
start: error_start,
|
||||
end: error_end,
|
||||
};
|
||||
let econtainer = ErrorContainer {
|
||||
error_code: SEMANTIC_MISMATCHED_TYPES,
|
||||
error_offset: error_start,
|
||||
labels: vec![label],
|
||||
note: None,
|
||||
help: None,
|
||||
};
|
||||
return Err(econtainer);
|
||||
}
|
||||
}
|
||||
}
|
||||
Expression::FunctionCall(f) => f.check_semantics(scope),
|
||||
// These are empty because they have nothing to check,
|
||||
// their existance alone is correct
|
||||
Expression::Int(_) => Ok(()),
|
||||
@ -372,18 +294,7 @@ mod tests {
|
||||
fn should_error_on_undefined_symbol() {
|
||||
// source code: `print()`
|
||||
let b = t("print()");
|
||||
let expr_function = exp(&b);
|
||||
|
||||
let arguments = ArgumentsList {
|
||||
arguments: vec![],
|
||||
paren_open_pos: 5,
|
||||
paren_close_pos: 7,
|
||||
};
|
||||
|
||||
let expr = Expression::FunctionCall(FunctionCall {
|
||||
function: Box::new(expr_function),
|
||||
arguments: Box::new(arguments),
|
||||
});
|
||||
let expr = exp(&b);
|
||||
|
||||
let scope = SymbolTable::new();
|
||||
|
Loading…
Reference in New Issue
Block a user