From 5e8945cab5fc7fa06641a69493f865a6b5e8205c Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 24 Jun 2024 04:02:44 -0400 Subject: [PATCH] Begin adding fields to map type --- .../src/abstract_tree/built_in_function.rs | 2 +- dust-lang/src/abstract_tree/map_index.rs | 8 ++++- dust-lang/src/abstract_tree/type.rs | 35 +++++++++++++++---- .../src/abstract_tree/type_constructor.rs | 21 +++++++++-- dust-lang/src/abstract_tree/value_node.rs | 20 ++++++++++- dust-lang/src/parser/mod.rs | 18 +++++++++- dust-lang/src/value.rs | 12 ++++++- 7 files changed, 101 insertions(+), 15 deletions(-) diff --git a/dust-lang/src/abstract_tree/built_in_function.rs b/dust-lang/src/abstract_tree/built_in_function.rs index 2ecbc17..7cdda64 100644 --- a/dust-lang/src/abstract_tree/built_in_function.rs +++ b/dust-lang/src/abstract_tree/built_in_function.rs @@ -423,7 +423,7 @@ impl FunctionLogic for JsonParse { Type::Integer => Value::integer(from_str::(input_string)?), Type::List { .. } => todo!(), Type::ListOf(_) => todo!(), - Type::Map => todo!(), + Type::Map(_) => todo!(), Type::Range => todo!(), Type::String => Value::string(from_str::(input_string)?), Type::Structure { .. } => todo!(), diff --git a/dust-lang/src/abstract_tree/map_index.rs b/dust-lang/src/abstract_tree/map_index.rs index a04b050..395014b 100644 --- a/dust-lang/src/abstract_tree/map_index.rs +++ b/dust-lang/src/abstract_tree/map_index.rs @@ -30,7 +30,13 @@ impl AbstractNode for MapIndex { } fn validate(&self, _context: &Context, _manage_memory: bool) -> Result<(), ValidationError> { - self.collection.validate(_context, _manage_memory) + self.collection.validate(_context, _manage_memory)?; + + if let Expression::Identifier(identifier) = &self.index { + Ok(()) + } else { + self.index.validate(_context, _manage_memory) + } } fn evaluate( diff --git a/dust-lang/src/abstract_tree/type.rs b/dust-lang/src/abstract_tree/type.rs index e45b648..6e9ecb3 100644 --- a/dust-lang/src/abstract_tree/type.rs +++ b/dust-lang/src/abstract_tree/type.rs @@ -1,4 +1,7 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + collections::BTreeMap, + fmt::{self, Display, Formatter}, +}; use clap::error::Result; use serde::{Deserialize, Serialize}; @@ -30,7 +33,7 @@ pub enum Type { item_type: Box, }, ListOf(Box), - Map, + Map(BTreeMap), Range, String, Structure { @@ -47,7 +50,6 @@ impl Type { | (Type::Boolean, Type::Boolean) | (Type::Float, Type::Float) | (Type::Integer, Type::Integer) - | (Type::Map, Type::Map) | (Type::Range, Type::Range) | (Type::String, Type::String) => return Ok(()), ( @@ -190,6 +192,11 @@ impl Type { return Ok(()); } } + (Type::Map(left), Type::Map(right)) => { + if left == right { + return Ok(()); + } + } _ => {} } @@ -236,8 +243,16 @@ impl Display for Type { } Type::Integer => write!(f, "int"), Type::List { length, item_type } => write!(f, "[{length}; {}]", item_type), - Type::ListOf(item_type) => write!(f, "list({})", item_type), - Type::Map => write!(f, "map"), + Type::ListOf(item_type) => write!(f, "[{}]", item_type), + Type::Map(item_types) => { + writeln!(f, "{{")?; + + for (identifier, r#type) in item_types { + writeln!(f, "{identifier}: {type}")?; + } + + write!(f, "}}") + } Type::Range => write!(f, "range"), Type::String => write!(f, "str"), Type::Function { @@ -300,7 +315,13 @@ mod tests { Ok(()) ); - assert_eq!(Type::Map.check(&Type::Map), Ok(())); + let mut map = BTreeMap::new(); + + map.insert(Identifier::new("x"), Type::Integer); + map.insert(Identifier::new("y"), Type::String); + map.insert(Identifier::new("z"), Type::Map(map.clone())); + + assert_eq!(Type::Map(map.clone()).check(&Type::Map(map)), Ok(())); assert_eq!(Type::Range.check(&Type::Range), Ok(())); assert_eq!(Type::String.check(&Type::String), Ok(())); } @@ -334,7 +355,7 @@ mod tests { item_type: Box::new(Type::Integer), }, Type::ListOf(Box::new(Type::Boolean)), - Type::Map, + Type::Map(BTreeMap::new()), Type::Range, Type::String, ]; diff --git a/dust-lang/src/abstract_tree/type_constructor.rs b/dust-lang/src/abstract_tree/type_constructor.rs index 2c80f82..c72d826 100644 --- a/dust-lang/src/abstract_tree/type_constructor.rs +++ b/dust-lang/src/abstract_tree/type_constructor.rs @@ -1,5 +1,9 @@ -use std::fmt::{self, Display, Formatter}; +use std::{ + collections::BTreeMap, + fmt::{self, Display, Formatter}, +}; +use chumsky::container::Container; use serde::{Deserialize, Serialize}; use crate::{context::Context, error::ValidationError, identifier::Identifier}; @@ -13,6 +17,7 @@ pub enum TypeConstructor { Invokation(TypeInvokationConstructor), List(WithPosition), ListOf(WithPosition>), + Map(WithPosition, TypeConstructor)>>), Raw(WithPosition), } @@ -22,7 +27,6 @@ pub enum RawTypeConstructor { Boolean, Float, Integer, - Map, Range, String, } @@ -47,6 +51,7 @@ impl TypeConstructor { } TypeConstructor::List(WithPosition { position, .. }) => *position, TypeConstructor::ListOf(WithPosition { position, .. }) => *position, + TypeConstructor::Map(WithPosition { position, .. }) => *position, TypeConstructor::Raw(WithPosition { position, .. }) => *position, } } @@ -176,12 +181,22 @@ impl TypeConstructor { Type::ListOf(Box::new(item_type)) } + TypeConstructor::Map(field_type_constructors) => { + let mut field_types = BTreeMap::with_capacity(field_type_constructors.node.len()); + + for (identifier, constructor) in &field_type_constructors.node { + let r#type = constructor.construct(context)?; + + field_types.insert(identifier.node.clone(), r#type); + } + + Type::Map(field_types) + } TypeConstructor::Raw(raw_type) => match raw_type.node { RawTypeConstructor::Any => Type::Any, RawTypeConstructor::Boolean => Type::Boolean, RawTypeConstructor::Float => Type::Float, RawTypeConstructor::Integer => Type::Integer, - RawTypeConstructor::Map => Type::Map, RawTypeConstructor::Range => Type::Range, RawTypeConstructor::String => Type::String, }, diff --git a/dust-lang/src/abstract_tree/value_node.rs b/dust-lang/src/abstract_tree/value_node.rs index 1ef51b8..9ae716d 100644 --- a/dust-lang/src/abstract_tree/value_node.rs +++ b/dust-lang/src/abstract_tree/value_node.rs @@ -402,7 +402,25 @@ impl AbstractNode for ValueNode { item_type: Box::new(item_type), } } - ValueNode::Map(_) => Type::Map, + ValueNode::Map(fields) => { + let mut field_types = BTreeMap::new(); + + for (identifier, constructor_option, expression) in fields { + let r#type = if let Some(constructor) = constructor_option { + constructor.construct(context)? + } else { + if let Some(r#type) = expression.expected_type(context)? { + r#type + } else { + return Err(ValidationError::CannotAssignToNone(expression.position())); + } + }; + + field_types.insert(identifier.clone(), r#type); + } + + Type::Map(field_types) + } ValueNode::Range(_) => Type::Range, ValueNode::String(_) => Type::String, ValueNode::Function(FunctionNode { diff --git a/dust-lang/src/parser/mod.rs b/dust-lang/src/parser/mod.rs index bd828e2..37d82a1 100644 --- a/dust-lang/src/parser/mod.rs +++ b/dust-lang/src/parser/mod.rs @@ -82,7 +82,6 @@ pub fn parser<'src>( just(Token::Keyword(Keyword::Bool)).to(RawTypeConstructor::Boolean), just(Token::Keyword(Keyword::Float)).to(RawTypeConstructor::Float), just(Token::Keyword(Keyword::Int)).to(RawTypeConstructor::Integer), - just(Token::Keyword(Keyword::Map)).to(RawTypeConstructor::Map), just(Token::Keyword(Keyword::Range)).to(RawTypeConstructor::Range), just(Token::Keyword(Keyword::Str)).to(RawTypeConstructor::String), )) @@ -196,7 +195,24 @@ pub fn parser<'src>( }) }); + let map_type = positioned_identifier + .clone() + .then_ignore(just(Token::Symbol(Symbol::Colon))) + .then(type_constructor.clone()) + .separated_by(just(Token::Symbol(Symbol::Comma))) + .collect() + .delimited_by( + just(Token::Symbol(Symbol::CurlyOpen)), + just(Token::Symbol(Symbol::CurlyClose)), + ) + .map_with( + |fields: Vec<(WithPosition, TypeConstructor)>, state| { + TypeConstructor::Map(fields.with_position(state.span())) + }, + ); + choice(( + map_type, type_invokation, function_type, list_type, diff --git a/dust-lang/src/value.rs b/dust-lang/src/value.rs index b276245..82e4b0d 100644 --- a/dust-lang/src/value.rs +++ b/dust-lang/src/value.rs @@ -592,7 +592,17 @@ impl ValueInner { item_type: Box::new(item_type), } } - ValueInner::Map(_) => Type::Map, + ValueInner::Map(value_map) => { + let mut type_map = BTreeMap::with_capacity(value_map.len()); + + for (identifier, value) in value_map { + let r#type = value.r#type(context)?; + + type_map.insert(identifier.clone(), r#type); + } + + Type::Map(type_map) + } ValueInner::Range(_) => Type::Range, ValueInner::String(_) => Type::String, ValueInner::Function(function) => {