Add two new tests and refactor to pass them
This commit is contained in:
parent
3addb767fa
commit
a02cee0b9f
@ -245,7 +245,7 @@ impl FunctionLogic for JsonParse {
|
||||
};
|
||||
|
||||
Type::Function {
|
||||
type_parameters: None,
|
||||
type_parameters: Some(vec![Identifier::from("T")]),
|
||||
value_parameters: Some(vec![(Identifier::from("input"), type_t.clone())]),
|
||||
return_type: Some(Box::new(type_t)),
|
||||
}
|
||||
|
@ -65,19 +65,38 @@ impl AbstractNode for FunctionCall {
|
||||
return_type: _,
|
||||
} = function_node_type
|
||||
{
|
||||
if let (Some(parameters), Some(arguments)) = (type_parameters, &self.type_arguments) {
|
||||
if parameters.len() != arguments.len() {
|
||||
match (type_parameters, &self.type_arguments) {
|
||||
(Some(parameters), Some(arguments)) => {
|
||||
if parameters.len() != arguments.len() {
|
||||
return Err(ValidationError::WrongTypeArguments {
|
||||
arguments: arguments.clone(),
|
||||
parameters: parameters.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
for (identifier, constructor) in parameters.into_iter().zip(arguments.iter()) {
|
||||
let r#type = constructor.construct(context)?;
|
||||
|
||||
context.set_type(
|
||||
identifier,
|
||||
r#type,
|
||||
self.function_expression.position(),
|
||||
)?;
|
||||
}
|
||||
}
|
||||
(Some(parameters), None) => {
|
||||
return Err(ValidationError::WrongTypeArguments {
|
||||
arguments: arguments.clone(),
|
||||
arguments: Vec::with_capacity(0),
|
||||
parameters: parameters.clone(),
|
||||
});
|
||||
}
|
||||
|
||||
for (identifier, constructor) in parameters.into_iter().zip(arguments.iter()) {
|
||||
let r#type = constructor.construct(context)?;
|
||||
|
||||
context.set_type(identifier, r#type, self.function_expression.position())?;
|
||||
(None, Some(arguments)) => {
|
||||
return Err(ValidationError::WrongTypeArguments {
|
||||
arguments: arguments.clone(),
|
||||
parameters: Vec::with_capacity(0),
|
||||
});
|
||||
}
|
||||
(None, None) => {}
|
||||
}
|
||||
|
||||
match (value_parameters, &self.value_arguments) {
|
||||
|
@ -43,8 +43,20 @@ pub enum 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> {
|
||||
match (self, other) {
|
||||
match (self.concrete_type(), other.concrete_type()) {
|
||||
(Type::Any, _)
|
||||
| (_, Type::Any)
|
||||
| (Type::Boolean, Type::Boolean)
|
||||
|
@ -124,6 +124,10 @@ pub struct InterpreterError {
|
||||
}
|
||||
|
||||
impl InterpreterError {
|
||||
pub fn new(source_id: Arc<str>, errors: Vec<DustError>) -> Self {
|
||||
InterpreterError { source_id, errors }
|
||||
}
|
||||
|
||||
pub fn errors(&self) -> &Vec<DustError> {
|
||||
&self.errors
|
||||
}
|
||||
@ -477,6 +481,8 @@ impl InterpreterError {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use abstract_tree::{AbstractNode, SourcePosition};
|
||||
|
||||
use self::standard_library::std_full_compiled;
|
||||
|
||||
use super::*;
|
||||
@ -486,6 +492,9 @@ mod tests {
|
||||
let context = Context::new();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,7 @@
|
||||
use abstract_tree::{Expression, ValueNode, WithPos};
|
||||
use dust_lang::*;
|
||||
use error::{DustError, ValidationError};
|
||||
use identifier::Identifier;
|
||||
|
||||
#[test]
|
||||
fn function_scope() {
|
||||
@ -109,3 +112,54 @@ fn recursion() {
|
||||
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()
|
||||
}]
|
||||
))
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user