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},
|
syntax::ast::{Expression, Positionable},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod funtion_call;
|
||||||
|
|
||||||
impl SemanticCheck for Expression<'_> {
|
impl SemanticCheck for Expression<'_> {
|
||||||
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
fn check_semantics(&self, scope: &SymbolTable) -> Result<(), MistiError> {
|
||||||
match self {
|
match self {
|
||||||
Expression::FunctionCall(f) => {
|
Expression::FunctionCall(f) => f.check_semantics(scope),
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// These are empty because they have nothing to check,
|
// These are empty because they have nothing to check,
|
||||||
// their existance alone is correct
|
// their existance alone is correct
|
||||||
Expression::Int(_) => Ok(()),
|
Expression::Int(_) => Ok(()),
|
||||||
@ -372,18 +294,7 @@ mod tests {
|
|||||||
fn should_error_on_undefined_symbol() {
|
fn should_error_on_undefined_symbol() {
|
||||||
// source code: `print()`
|
// source code: `print()`
|
||||||
let b = t("print()");
|
let b = t("print()");
|
||||||
let expr_function = exp(&b);
|
let expr = 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 scope = SymbolTable::new();
|
let scope = SymbolTable::new();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user