Add two new tests and refactor to pass them

This commit is contained in:
Jeff 2024-07-13 10:47:24 -04:00
parent 3addb767fa
commit a02cee0b9f
5 changed files with 104 additions and 10 deletions

View File

@ -245,7 +245,7 @@ impl FunctionLogic for JsonParse {
}; };
Type::Function { Type::Function {
type_parameters: None, type_parameters: Some(vec![Identifier::from("T")]),
value_parameters: Some(vec![(Identifier::from("input"), type_t.clone())]), value_parameters: Some(vec![(Identifier::from("input"), type_t.clone())]),
return_type: Some(Box::new(type_t)), return_type: Some(Box::new(type_t)),
} }

View File

@ -65,7 +65,8 @@ impl AbstractNode for FunctionCall {
return_type: _, return_type: _,
} = function_node_type } = function_node_type
{ {
if let (Some(parameters), Some(arguments)) = (type_parameters, &self.type_arguments) { match (type_parameters, &self.type_arguments) {
(Some(parameters), Some(arguments)) => {
if parameters.len() != arguments.len() { if parameters.len() != arguments.len() {
return Err(ValidationError::WrongTypeArguments { return Err(ValidationError::WrongTypeArguments {
arguments: arguments.clone(), arguments: arguments.clone(),
@ -76,9 +77,27 @@ impl AbstractNode for FunctionCall {
for (identifier, constructor) in parameters.into_iter().zip(arguments.iter()) { for (identifier, constructor) in parameters.into_iter().zip(arguments.iter()) {
let r#type = constructor.construct(context)?; let r#type = constructor.construct(context)?;
context.set_type(identifier, r#type, self.function_expression.position())?; context.set_type(
identifier,
r#type,
self.function_expression.position(),
)?;
} }
} }
(Some(parameters), None) => {
return Err(ValidationError::WrongTypeArguments {
arguments: Vec::with_capacity(0),
parameters: parameters.clone(),
});
}
(None, Some(arguments)) => {
return Err(ValidationError::WrongTypeArguments {
arguments: arguments.clone(),
parameters: Vec::with_capacity(0),
});
}
(None, None) => {}
}
match (value_parameters, &self.value_arguments) { match (value_parameters, &self.value_arguments) {
(Some(parameters), Some(arguments)) => { (Some(parameters), Some(arguments)) => {

View File

@ -43,8 +43,20 @@ pub enum Type {
} }
impl Type { impl Type {
/// Returns a concrete type, either the type itself or the concrete type of a generic type.
pub fn concrete_type(&self) -> &Type {
match self {
Type::Generic {
concrete_type: Some(concrete_type),
..
} => concrete_type.concrete_type(),
_ => self,
}
}
/// Checks that the type is compatible with another type.
pub fn check(&self, other: &Type) -> Result<(), TypeConflict> { pub fn check(&self, other: &Type) -> Result<(), TypeConflict> {
match (self, other) { match (self.concrete_type(), other.concrete_type()) {
(Type::Any, _) (Type::Any, _)
| (_, Type::Any) | (_, Type::Any)
| (Type::Boolean, Type::Boolean) | (Type::Boolean, Type::Boolean)

View File

@ -124,6 +124,10 @@ pub struct InterpreterError {
} }
impl InterpreterError { impl InterpreterError {
pub fn new(source_id: Arc<str>, errors: Vec<DustError>) -> Self {
InterpreterError { source_id, errors }
}
pub fn errors(&self) -> &Vec<DustError> { pub fn errors(&self) -> &Vec<DustError> {
&self.errors &self.errors
} }
@ -477,6 +481,8 @@ impl InterpreterError {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use abstract_tree::{AbstractNode, SourcePosition};
use self::standard_library::std_full_compiled; use self::standard_library::std_full_compiled;
use super::*; use super::*;
@ -486,6 +492,9 @@ mod tests {
let context = Context::new(); let context = Context::new();
for abstract_tree in std_full_compiled() { for abstract_tree in std_full_compiled() {
abstract_tree
.define_and_validate(&context, true, SourcePosition(0, usize::MAX))
.unwrap();
abstract_tree.run(&context, true).unwrap(); abstract_tree.run(&context, true).unwrap();
} }
} }

View File

@ -1,4 +1,7 @@
use abstract_tree::{Expression, ValueNode, WithPos};
use dust_lang::*; use dust_lang::*;
use error::{DustError, ValidationError};
use identifier::Identifier;
#[test] #[test]
fn function_scope() { fn function_scope() {
@ -109,3 +112,54 @@ fn recursion() {
Ok(Some(Value::integer(13))) Ok(Some(Value::integer(13)))
); );
} }
#[test]
fn value_argument_error() {
assert_eq!(
interpret(
"test",
"
foobar = fn (a: int, b: int) -> int { a + b }
foobar(1)
"
),
Err(InterpreterError::new(
"test".into(),
vec![DustError::Validation {
error: ValidationError::WrongValueArguments {
parameters: vec![
(Identifier::new("a"), Type::Integer),
(Identifier::new("b"), Type::Integer),
],
arguments: vec![Expression::Value(
ValueNode::Integer(1).with_position((78, 79)),
)],
},
position: (71, 80).into()
}]
))
);
}
#[test]
fn type_argument_error() {
assert_eq!(
interpret(
"test",
"
foobar = fn <T> (a: T) -> T { a }
foobar(1)
"
),
Err(InterpreterError::new(
"test".into(),
vec![DustError::Validation {
error: ValidationError::WrongTypeArguments {
parameters: vec![Identifier::new("T")],
arguments: vec![]
},
position: (59, 68).into()
}]
))
);
}