Begin adding fields to map type

This commit is contained in:
Jeff 2024-06-24 04:02:44 -04:00
parent 37d59f562d
commit 5e8945cab5
7 changed files with 101 additions and 15 deletions

View File

@ -423,7 +423,7 @@ impl FunctionLogic for JsonParse {
Type::Integer => Value::integer(from_str::<i64>(input_string)?),
Type::List { .. } => todo!(),
Type::ListOf(_) => todo!(),
Type::Map => todo!(),
Type::Map(_) => todo!(),
Type::Range => todo!(),
Type::String => Value::string(from_str::<String>(input_string)?),
Type::Structure { .. } => todo!(),

View File

@ -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(

View File

@ -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<Type>,
},
ListOf(Box<Type>),
Map,
Map(BTreeMap<Identifier, Type>),
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,
];

View File

@ -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<ListTypeConstructor>),
ListOf(WithPosition<Box<TypeConstructor>>),
Map(WithPosition<Vec<(WithPosition<Identifier>, TypeConstructor)>>),
Raw(WithPosition<RawTypeConstructor>),
}
@ -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,
},

View File

@ -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 {

View File

@ -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<Identifier>, TypeConstructor)>, state| {
TypeConstructor::Map(fields.with_position(state.span()))
},
);
choice((
map_type,
type_invokation,
function_type,
list_type,

View File

@ -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) => {