diff --git a/src/abstract_tree/as.rs b/src/abstract_tree/as.rs index e13de8f..91ed54d 100644 --- a/src/abstract_tree/as.rs +++ b/src/abstract_tree/as.rs @@ -37,9 +37,9 @@ impl AbstractTree for As { fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> { let initial_type = self.expression.expected_type(context)?; - if let Type::List(item_type) = &self.r#type { + if let Type::ListOf(item_type) = &self.r#type { match &initial_type { - Type::List(expected_item_type) => { + Type::ListOf(expected_item_type) => { if !item_type.accepts(&expected_item_type) { return Err(ValidationError::TypeCheck { expected: self.r#type.clone(), @@ -77,7 +77,7 @@ impl AbstractTree for As { fn run(&self, source: &str, context: &Context) -> Result { let value = self.expression.run(source, context)?; - let converted_value = if let Type::List(_) = self.r#type { + let converted_value = if let Type::ListOf(_) = self.r#type { match value { Value::List(list) => Value::List(list), Value::String(string) => { diff --git a/src/abstract_tree/assignment.rs b/src/abstract_tree/assignment.rs index e9cfec9..0a09c95 100644 --- a/src/abstract_tree/assignment.rs +++ b/src/abstract_tree/assignment.rs @@ -78,7 +78,7 @@ impl AbstractTree for Assignment { } } AssignmentOperator::PlusEqual => { - if let Type::List(expected) = type_specification.inner() { + if let Type::ListOf(expected) = type_specification.inner() { let actual = self.identifier.expected_type(context)?; if !expected.accepts(&actual) { @@ -107,7 +107,7 @@ impl AbstractTree for Assignment { match self.operator { AssignmentOperator::Equal => {} AssignmentOperator::PlusEqual => { - if let Type::List(expected) = self.identifier.expected_type(context)? { + if let Type::ListOf(expected) = self.identifier.expected_type(context)? { let actual = self.statement.expected_type(context)?; if !expected.accepts(&actual) { diff --git a/src/abstract_tree/enum_defintion.rs b/src/abstract_tree/enum_defintion.rs index 6504d08..014218d 100644 --- a/src/abstract_tree/enum_defintion.rs +++ b/src/abstract_tree/enum_defintion.rs @@ -9,11 +9,11 @@ use crate::{ #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] pub struct EnumDefinition { identifier: Identifier, - variants: Vec<(Identifier, Option)>, + variants: Vec<(Identifier, Vec)>, } impl EnumDefinition { - pub fn new(identifier: Identifier, variants: Vec<(Identifier, Option)>) -> Self { + pub fn new(identifier: Identifier, variants: Vec<(Identifier, Vec)>) -> Self { Self { identifier, variants, @@ -27,6 +27,10 @@ impl EnumDefinition { pub fn identifier(&self) -> &Identifier { &self.identifier } + + pub fn variants(&self) -> &Vec<(Identifier, Vec)> { + &self.variants + } } impl AbstractTree for EnumDefinition { @@ -37,21 +41,25 @@ impl AbstractTree for EnumDefinition { let identifier = Identifier::from_syntax(identifier_node, source, context)?; let mut variants = Vec::new(); - let mut current_identifier = None; + let mut current_identifier: Option = None; + let mut types = Vec::new(); for index in 3..node.child_count() - 1 { let child = node.child(index).unwrap(); if child.kind() == "identifier" { + if let Some(identifier) = ¤t_identifier { + variants.push((identifier.clone(), types)); + } + current_identifier = Some(Identifier::from_syntax(child, source, context)?); + types = Vec::new(); } - if let Some(identifier) = ¤t_identifier { - if child.kind() == "type" { - let r#type = Type::from_syntax(child, source, context)?; + if child.kind() == "type" { + let r#type = Type::from_syntax(child, source, context)?; - variants.push((identifier.clone(), Some(r#type))); - } + types.push(r#type); } } @@ -65,13 +73,14 @@ impl AbstractTree for EnumDefinition { Ok(Type::None) } - fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> { + fn validate(&self, _source: &str, context: &Context) -> Result<(), ValidationError> { + context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?; + self.identifier.validate(_source, context)?; + Ok(()) } - fn run(&self, _source: &str, context: &Context) -> Result { - context.set_definition(self.identifier.clone(), TypeDefinition::Enum(self.clone()))?; - + fn run(&self, _source: &str, _context: &Context) -> Result { Ok(Value::none()) } } diff --git a/src/abstract_tree/for.rs b/src/abstract_tree/for.rs index 3527bd9..5ede5af 100644 --- a/src/abstract_tree/for.rs +++ b/src/abstract_tree/for.rs @@ -66,7 +66,7 @@ impl AbstractTree for For { self.collection.validate(_source, context)?; let collection_type = self.collection.expected_type(context)?; - let item_type = if let Type::List(item_type) = collection_type { + let item_type = if let Type::ListOf(item_type) = collection_type { item_type.as_ref().clone() } else if let Type::Range = collection_type { Type::Integer diff --git a/src/abstract_tree/index.rs b/src/abstract_tree/index.rs index 0424376..f45a6ac 100644 --- a/src/abstract_tree/index.rs +++ b/src/abstract_tree/index.rs @@ -35,7 +35,7 @@ impl AbstractTree for Index { fn expected_type(&self, context: &Context) -> Result { match self.collection.expected_type(context)? { - Type::List(item_type) => Ok(*item_type.clone()), + Type::ListOf(item_type) => Ok(*item_type.clone()), Type::Map(map_types_option) => { if let (Some(map_type), IndexExpression::Identifier(identifier)) = (map_types_option, &self.index) diff --git a/src/abstract_tree/type.rs b/src/abstract_tree/type.rs index f033bc9..f0edf15 100644 --- a/src/abstract_tree/type.rs +++ b/src/abstract_tree/type.rs @@ -19,7 +19,7 @@ pub enum Type { Collection, Custom { name: Identifier, - argument: Option>, + arguments: Vec, }, Float, Function { @@ -27,20 +27,19 @@ pub enum Type { return_type: Box, }, Integer, - List(Box), + List, + ListOf(Box), + ListExact(Vec), Map(Option>), + None, Number, String, Range, - None, } impl Type { - pub fn custom(name: Identifier, argument: Option) -> Self { - Type::Custom { - name, - argument: argument.map(|r#type| Box::new(r#type)), - } + pub fn custom(name: Identifier, arguments: Vec) -> Self { + Type::Custom { name, arguments } } pub fn option(inner_type: Option) -> Self { @@ -48,7 +47,7 @@ impl Type { } pub fn list(item_type: Type) -> Self { - Type::List(Box::new(item_type)) + Type::ListOf(Box::new(item_type)) } pub fn function(parameter_types: Vec, return_type: Type) -> Self { @@ -70,14 +69,15 @@ impl Type { | (_, Type::Any) | (Type::Boolean, Type::Boolean) | (Type::Collection, Type::Collection) - | (Type::Collection, Type::List(_)) - | (Type::List(_), Type::Collection) + | (Type::Collection, Type::ListOf(_)) + | (Type::ListOf(_), Type::Collection) | (Type::Collection, Type::Map(_)) | (Type::Map(_), Type::Collection) | (Type::Collection, Type::String) | (Type::String, Type::Collection) | (Type::Float, Type::Float) | (Type::Integer, Type::Integer) + | (Type::List, Type::List) | (Type::Map(None), Type::Map(None)) | (Type::Number, Type::Number) | (Type::Number, Type::Integer) @@ -90,22 +90,25 @@ impl Type { ( Type::Custom { name: left_name, - argument: left_argument, + arguments: left_arguments, }, Type::Custom { name: right_name, - argument: right_argument, + arguments: right_arguments, }, - ) => { - if left_name != right_name { - false - } else { - left_argument == right_argument - } - } - (Type::List(self_item_type), Type::List(other_item_type)) => { + ) => left_name == right_name && left_arguments == right_arguments, + (Type::ListOf(self_item_type), Type::ListOf(other_item_type)) => { self_item_type.accepts(&other_item_type) } + (Type::ListExact(self_types), Type::ListExact(other_types)) => { + for (left, right) in self_types.iter().zip(other_types.iter()) { + if !left.accepts(right) { + return false; + } + } + + true + } ( Type::Function { parameter_types: self_parameter_types, @@ -137,7 +140,7 @@ impl Type { } pub fn is_list(&self) -> bool { - matches!(self, Type::List(_)) + matches!(self, Type::ListOf(_)) } pub fn is_map(&self) -> bool { @@ -158,13 +161,19 @@ impl AbstractTree for Type { let r#type = match type_node.kind() { "identifier" => { let name = Identifier::from_syntax(type_node, _source, context)?; - let argument = if let Some(child) = node.child(2) { - Some(Type::from_syntax(child, _source, context)?) - } else { - None - }; + let mut arguments = Vec::new(); - Type::custom(name, argument) + for index in 2..node.child_count() - 1 { + let child = node.child(index).unwrap(); + + if child.is_named() { + let r#type = Type::from_syntax(child, _source, context)?; + + arguments.push(r#type); + } + } + + Type::custom(name, arguments) } "{" => { let mut type_map = BTreeMap::new(); @@ -191,7 +200,7 @@ impl AbstractTree for Type { let item_type_node = node.child(1).unwrap(); let item_type = Type::from_syntax(item_type_node, _source, context)?; - Type::List(Box::new(item_type)) + Type::ListOf(Box::new(item_type)) } "any" => Type::Any, "bool" => Type::Boolean, @@ -261,7 +270,7 @@ impl Format for Type { Type::Collection => output.push_str("collection"), Type::Custom { name: _, - argument: _, + arguments: _, } => todo!(), Type::Float => output.push_str("float"), Type::Function { @@ -282,11 +291,13 @@ impl Format for Type { return_type.format(output, indent_level); } Type::Integer => output.push_str("int"), - Type::List(item_type) => { + Type::List => todo!(), + Type::ListOf(item_type) => { output.push('['); item_type.format(output, indent_level); output.push(']'); } + Type::ListExact(_) => todo!(), Type::Map(_) => { output.push_str("map"); } @@ -304,9 +315,19 @@ impl Display for Type { Type::Any => write!(f, "any"), Type::Boolean => write!(f, "bool"), Type::Collection => write!(f, "collection"), - Type::Custom { name, argument } => { - if let Some(argument) = argument { - write!(f, "{name}<{argument}>") + Type::Custom { name, arguments } => { + if !arguments.is_empty() { + write!(f, "<")?; + + for (index, r#type) in arguments.into_iter().enumerate() { + if index == arguments.len() - 1 { + write!(f, "{}", r#type)?; + } else { + write!(f, "{}, ", r#type)?; + } + } + + write!(f, ">") } else { write!(f, "{name}") } @@ -330,7 +351,21 @@ impl Display for Type { write!(f, " -> {return_type}") } Type::Integer => write!(f, "int"), - Type::List(item_type) => write!(f, "[{item_type}]"), + Type::List => write!(f, "list"), + Type::ListOf(item_type) => write!(f, "[{item_type}]"), + Type::ListExact(types) => { + write!(f, "[")?; + + for (index, r#type) in types.into_iter().enumerate() { + if index == types.len() - 1 { + write!(f, "{}", r#type)?; + } else { + write!(f, "{}, ", r#type)?; + } + } + + write!(f, "]") + } Type::Map(_) => write!(f, "map"), Type::Number => write!(f, "num"), Type::None => write!(f, "none"), diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 1f78a84..b16e1da 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -124,43 +124,47 @@ impl AbstractTree for ValueNode { ValueNode::Integer(_) => Type::Integer, ValueNode::String(_) => Type::String, ValueNode::List(expressions) => { - let mut previous_type = None; + let mut item_types = Vec::new(); for expression in expressions { let expression_type = expression.expected_type(context)?; - if let Some(previous) = previous_type { - if expression_type != previous { - return Ok(Type::List(Box::new(Type::Any))); - } - } - - previous_type = Some(expression_type); + item_types.push(expression_type); } - if let Some(previous) = previous_type { - Type::List(Box::new(previous)) - } else { - Type::List(Box::new(Type::Any)) - } + Type::ListExact(item_types) } ValueNode::Map(map_node) => map_node.expected_type(context)?, ValueNode::Struct { name, .. } => { - Type::Custom { name: name.clone(), argument: None } + Type::custom(name.clone(), Vec::with_capacity(0)) } ValueNode::Range(_) => Type::Range, - ValueNode::Enum { name, variant: _, expression } => { - if let Some(expression) = expression { - Type::Custom { - name: name.clone(), - argument: Some(Box::new(expression.expected_type(context)?)) + ValueNode::Enum { name, variant, expression: _ } => { + let types: Vec = if let Some(type_definition) = context.get_definition(name)? { + if let TypeDefinition::Enum(enum_definition) = type_definition { + let types = enum_definition.variants().into_iter().find_map(|(identifier, types)| { + if identifier == variant { + Some(types.clone()) + } else { + None + } + }); + + if let Some(types) = types { + types + } else { + return Err(ValidationError::VariableIdentifierNotFound(variant.clone())); + } + + } else { + return Err(ValidationError::ExpectedEnumDefintion { actual: type_definition.clone() }); } } else { - Type::Custom{ - name: name.clone(), - argument: None, - } - } + return Err(ValidationError::VariableIdentifierNotFound(name.clone())); + }; + + Type::custom(name.clone(), types.clone()) + }, }; diff --git a/src/built_in_functions/mod.rs b/src/built_in_functions/mod.rs index ec4cdd8..3535c44 100644 --- a/src/built_in_functions/mod.rs +++ b/src/built_in_functions/mod.rs @@ -73,13 +73,7 @@ impl Callable for BuiltInFunction { fn r#type(&self) -> Type { match self { - BuiltInFunction::AssertEqual => Type::function( - vec![Type::Any, Type::Any], - Type::Custom { - name: Identifier::new("Result"), - argument: None, - }, - ), + BuiltInFunction::AssertEqual => Type::function(vec![Type::Any, Type::Any], Type::None), BuiltInFunction::Fs(fs_function) => fs_function.r#type(), BuiltInFunction::Json(json_function) => json_function.r#type(), BuiltInFunction::Length => Type::function(vec![Type::Collection], Type::Integer), diff --git a/src/built_in_type_definitions.rs b/src/built_in_type_definitions.rs index 05ae41c..1eaf791 100644 --- a/src/built_in_type_definitions.rs +++ b/src/built_in_type_definitions.rs @@ -33,8 +33,8 @@ impl BuiltInTypeDefinition { let definition = TypeDefinition::Enum(EnumDefinition::new( Identifier::new(self.name()), vec![ - (Identifier::new("Some"), Some(Type::Any)), - (Identifier::new("None"), None), + (Identifier::new("Some"), vec![Type::Any]), + (Identifier::new("None"), Vec::with_capacity(0)), ], )); @@ -44,8 +44,8 @@ impl BuiltInTypeDefinition { let definition = TypeDefinition::Enum(EnumDefinition::new( Identifier::new(self.name()), vec![ - (Identifier::new("Ok"), Some(Type::Any)), - (Identifier::new("Err"), Some(Type::Any)), + (Identifier::new("Ok"), vec![Type::Any]), + (Identifier::new("Error"), vec![Type::Any]), ], )); diff --git a/src/built_in_types.rs b/src/built_in_types.rs index 3181299..61e1251 100644 --- a/src/built_in_types.rs +++ b/src/built_in_types.rs @@ -19,15 +19,9 @@ impl BuiltInType { match self { BuiltInType::Option(content_type) => OPTION.get_or_init(|| { if let Some(content_type) = content_type { - Type::Custom { - name: Identifier::new("Option"), - argument: Some(Box::new(content_type.clone())), - } + Type::custom(Identifier::new("Option"), vec![content_type.clone()]) } else { - Type::Custom { - name: Identifier::new("Option"), - argument: None, - } + Type::custom(Identifier::new("Option"), Vec::with_capacity(0)) } }), } diff --git a/src/context/mod.rs b/src/context/mod.rs index eb7d29f..07fee6c 100644 --- a/src/context/mod.rs +++ b/src/context/mod.rs @@ -270,7 +270,7 @@ impl Context { let old_data = map.remove(&key); if let Some((_, old_counter)) = old_data { - map.insert(key, (ValueData::Value(value), old_counter.clone())); + map.insert(key, (ValueData::Value(value), old_counter)); } else { map.insert(key, (ValueData::Value(value), UsageCounter::new())); } diff --git a/src/error/mod.rs b/src/error/mod.rs index 16a6bc1..969be96 100644 --- a/src/error/mod.rs +++ b/src/error/mod.rs @@ -16,7 +16,7 @@ use tree_sitter::LanguageError; use std::fmt::{self, Formatter}; -#[derive(PartialEq)] +#[derive(Debug, PartialEq)] pub enum Error { Syntax(SyntaxError), @@ -95,12 +95,6 @@ impl From for Error { impl std::error::Error for Error {} -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{self}") - } -} - impl fmt::Display for Error { fn fmt(&self, f: &mut Formatter) -> fmt::Result { use Error::*; diff --git a/src/value/mod.rs b/src/value/mod.rs index a0d8873..e7dc0ef 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -74,25 +74,15 @@ impl Value { pub fn r#type(&self) -> Result { let r#type = match self { Value::List(list) => { - let mut previous_type = None; + let mut item_types = Vec::new(); for value in list.items()?.iter() { - let value_type = value.r#type(); + let r#type = value.r#type()?; - if let Some(previous) = &previous_type { - if &value_type != previous { - return Ok(Type::List(Box::new(Type::Any))); - } - } - - previous_type = Some(value_type); + item_types.push(r#type); } - if let Some(previous) = previous_type { - Type::List(Box::new(previous?)) - } else { - Type::List(Box::new(Type::Any)) - } + Type::ListExact(item_types) } Value::Map(map) => { if map.inner().is_empty() { diff --git a/tests/as.rs b/tests/as.rs index a5097ea..bb40bb1 100644 --- a/tests/as.rs +++ b/tests/as.rs @@ -24,7 +24,7 @@ fn string_as_list_error() { interpret("'foobar' as [float]"), Err(Error::Validation(ValidationError::ConversionImpossible { initial_type: Type::String, - target_type: Type::List(Box::new(Type::Float)) + target_type: Type::ListOf(Box::new(Type::Float)) })) ) } @@ -39,7 +39,7 @@ fn conversion_runtime_error() { interpret(&format!("json:parse('{JSON}') as [map]")), Err(Error::Runtime(RuntimeError::ConversionImpossible { from: json_value.r#type().unwrap(), - to: Type::List(Box::new(Type::Map(None))), + to: Type::ListOf(Box::new(Type::Map(None))), position: SourcePosition { start_byte: 0, end_byte: 33, diff --git a/tests/built_in_type_definitions.rs b/tests/built_in_type_definitions.rs index c91a70b..10a78cc 100644 --- a/tests/built_in_type_definitions.rs +++ b/tests/built_in_type_definitions.rs @@ -1,5 +1,26 @@ use dust_lang::*; +#[test] +fn override_built_ins() { + assert_eq!( + interpret( + " + enum Option { + Some + None + } + + my_option