From bcc89f2c7d6e206620166f42433d62fbdd8f715d Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 19 Mar 2024 18:31:52 -0400 Subject: [PATCH] Implement structure parsing --- src/abstract_tree/function_call.rs | 2 +- src/abstract_tree/if_else.rs | 10 ++--- src/abstract_tree/list_index.rs | 10 ++--- src/abstract_tree/logic.rs | 8 ++-- src/abstract_tree/map_index.rs | 22 +++++----- src/abstract_tree/value_node.rs | 10 +---- src/context.rs | 6 +-- src/error.rs | 6 +++ src/parser.rs | 58 ++++++++++++++++++++++++- src/value.rs | 68 +++++++++++++++++++++++++++--- 10 files changed, 153 insertions(+), 47 deletions(-) diff --git a/src/abstract_tree/function_call.rs b/src/abstract_tree/function_call.rs index fb22762..793da23 100644 --- a/src/abstract_tree/function_call.rs +++ b/src/abstract_tree/function_call.rs @@ -65,7 +65,7 @@ impl AbstractTree for FunctionCall { } else { return Err(RuntimeError::ValidationFailure( ValidationError::ExpectedFunction { - actual: value.r#type(), + actual: value.r#type(context)?, position: self.function.position, }, )); diff --git a/src/abstract_tree/if_else.rs b/src/abstract_tree/if_else.rs index 027a1e2..cf2790e 100644 --- a/src/abstract_tree/if_else.rs +++ b/src/abstract_tree/if_else.rs @@ -63,8 +63,8 @@ impl AbstractTree for IfElse { } } - fn run(self, _context: &Context) -> Result { - let action = self.if_expression.node.run(_context)?; + fn run(self, context: &Context) -> Result { + let action = self.if_expression.node.run(context)?; let value = if let Action::Return(value) = action { value } else { @@ -75,16 +75,16 @@ impl AbstractTree for IfElse { if let ValueInner::Boolean(if_boolean) = value.inner().as_ref() { if *if_boolean { - self.if_block.run(_context) + self.if_block.run(context) } else if let Some(else_statement) = self.else_block { - else_statement.run(_context) + else_statement.run(context) } else { Ok(Action::None) } } else { Err(RuntimeError::ValidationFailure( ValidationError::ExpectedBoolean { - actual: value.r#type(), + actual: value.r#type(context)?, position: self.if_expression.position, }, )) diff --git a/src/abstract_tree/list_index.rs b/src/abstract_tree/list_index.rs index a6cc62a..3ad35ed 100644 --- a/src/abstract_tree/list_index.rs +++ b/src/abstract_tree/list_index.rs @@ -68,8 +68,8 @@ impl AbstractTree for ListIndex { } } - fn run(self, _context: &Context) -> Result { - let left_action = self.left.node.run(_context)?; + fn run(self, context: &Context) -> Result { + let left_action = self.left.node.run(context)?; let left_value = if let Action::Return(value) = left_action { value } else { @@ -77,7 +77,7 @@ impl AbstractTree for ListIndex { ValidationError::InterpreterExpectedReturn(self.left.position), )); }; - let right_action = self.right.node.run(_context)?; + let right_action = self.right.node.run(context)?; let right_value = if let Action::Return(value) = right_action { value } else { @@ -97,9 +97,9 @@ impl AbstractTree for ListIndex { } else { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndexWith { - collection_type: left_value.r#type(), + collection_type: left_value.r#type(context)?, collection_position: self.left.position, - index_type: right_value.r#type(), + index_type: right_value.r#type(context)?, index_position: self.right.position, }, )) diff --git a/src/abstract_tree/logic.rs b/src/abstract_tree/logic.rs index 32650f0..2cd7d08 100644 --- a/src/abstract_tree/logic.rs +++ b/src/abstract_tree/logic.rs @@ -83,10 +83,10 @@ impl AbstractTree for Logic { } } - fn run(self, _context: &Context) -> Result { + fn run(self, context: &Context) -> Result { let run_and_expect_value = |expression: WithPosition| -> Result { - let action = expression.node.run(_context)?; + let action = expression.node.run(context)?; let value = if let Action::Return(value) = action { value } else { @@ -100,7 +100,7 @@ impl AbstractTree for Logic { let run_and_expect_boolean = |expression: WithPosition| -> Result { - let action = expression.node.run(_context)?; + let action = expression.node.run(context)?; let value = if let Action::Return(value) = action { value } else { @@ -114,7 +114,7 @@ impl AbstractTree for Logic { } else { return Err(RuntimeError::ValidationFailure( ValidationError::ExpectedBoolean { - actual: value.r#type(), + actual: value.r#type(context)?, position: expression.position, }, )); diff --git a/src/abstract_tree/map_index.rs b/src/abstract_tree/map_index.rs index 8f25736..d966fd8 100644 --- a/src/abstract_tree/map_index.rs +++ b/src/abstract_tree/map_index.rs @@ -19,15 +19,15 @@ impl MapIndex { } impl AbstractTree for MapIndex { - fn expected_type(&self, _context: &Context) -> Result { - let left_type = self.left.node.expected_type(_context)?; + fn expected_type(&self, context: &Context) -> Result { + let left_type = self.left.node.expected_type(context)?; if let ( Expression::Identifier(collection_identifier), Expression::Identifier(index_identifier), ) = (&self.left.node, &self.right.node) { - let collection = if let Some(collection) = _context.get_value(collection_identifier)? { + let collection = if let Some(collection) = context.get_value(collection_identifier)? { collection } else { return Err(ValidationError::VariableNotFound( @@ -37,7 +37,7 @@ impl AbstractTree for MapIndex { if let ValueInner::Map(map) = collection.inner().as_ref() { return if let Some(value) = map.get(index_identifier) { - Ok(value.r#type()) + Ok(value.r#type(context)?) } else { Err(ValidationError::PropertyNotFound { identifier: index_identifier.clone(), @@ -56,9 +56,9 @@ impl AbstractTree for MapIndex { .find_map(|(property, type_option, expression)| { if property == identifier { if let Some(r#type) = type_option { - Some(r#type.node.expected_type(_context)) + Some(r#type.node.expected_type(context)) } else { - Some(expression.node.expected_type(_context)) + Some(expression.node.expected_type(context)) } } else { None @@ -74,7 +74,7 @@ impl AbstractTree for MapIndex { Err(ValidationError::CannotIndexWith { collection_type: left_type, collection_position: self.left.position, - index_type: self.right.node.expected_type(_context)?, + index_type: self.right.node.expected_type(context)?, index_position: self.right.position, }) } @@ -100,8 +100,8 @@ impl AbstractTree for MapIndex { } } - fn run(self, _context: &Context) -> Result { - let action = self.left.node.run(_context)?; + fn run(self, context: &Context) -> Result { + let action = self.left.node.run(context)?; let collection = if let Action::Return(value) = action { value } else { @@ -122,9 +122,9 @@ impl AbstractTree for MapIndex { } else { Err(RuntimeError::ValidationFailure( ValidationError::CannotIndexWith { - collection_type: collection.r#type(), + collection_type: collection.r#type(context)?, collection_position: self.left.position, - index_type: self.right.node.expected_type(_context)?, + index_type: self.right.node.expected_type(context)?, index_position: self.right.position, }, )) diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 766e957..a183b66 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -25,7 +25,7 @@ pub enum ValueNode { String(String), Structure { name: Identifier, - fields: Vec<(Identifier, Type)>, + fields: Vec<(Identifier, WithPosition)>, }, Function { parameters: Vec<(Identifier, WithPosition)>, @@ -244,14 +244,6 @@ impl Ord for ValueNode { fields: right_fields, }, ) => todo!(), - ( - Structure { name, fields }, - Function { - parameters, - return_type, - body, - }, - ) => todo!(), (Structure { name, fields }, _) => todo!(), } } diff --git a/src/context.rs b/src/context.rs index 74e3193..bf8c37f 100644 --- a/src/context.rs +++ b/src/context.rs @@ -5,7 +5,7 @@ use std::{ use crate::{ abstract_tree::{Identifier, Type}, - error::RwLockPoisonError, + error::{RwLockPoisonError, ValidationError}, value::{BUILT_IN_FUNCTIONS, BUILT_IN_MODULES}, Value, }; @@ -72,11 +72,11 @@ impl Context { } } - pub fn get_type(&self, identifier: &Identifier) -> Result, RwLockPoisonError> { + pub fn get_type(&self, identifier: &Identifier) -> Result, ValidationError> { if let Some(value_data) = self.inner.read()?.get(identifier) { let r#type = match value_data { ValueData::Type(r#type) => r#type.clone(), - ValueData::Value(value) => value.r#type(), + ValueData::Value(value) => value.r#type(self)?, }; return Ok(Some(r#type.clone())); diff --git a/src/error.rs b/src/error.rs index 0cd2056..20f015f 100644 --- a/src/error.rs +++ b/src/error.rs @@ -291,6 +291,12 @@ impl From for ValidationError { } } +impl From> for ValidationError { + fn from(_: PoisonError) -> Self { + ValidationError::RwLockPoison(RwLockPoisonError) + } +} + #[derive(Debug, PartialEq)] pub struct RwLockPoisonError; diff --git a/src/parser.rs b/src/parser.rs index e3b7e6b..3a3330d 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -336,7 +336,30 @@ pub fn parser<'src>() -> impl Parser< ), )); + let structure_field = identifier + .clone() + .then_ignore(just(Token::Operator(Operator::Assign))) + .then(positioned_expression.clone()); + + let structure_instance = identifier + .clone() + .then( + structure_field + .separated_by(just(Token::Control(Control::Comma))) + .allow_trailing() + .collect() + .delimited_by( + just(Token::Control(Control::CurlyOpen)), + just(Token::Control(Control::CurlyClose)), + ), + ) + .map_with(|(name, fields), state| { + Expression::Value(ValueNode::Structure { name, fields }) + .with_position(state.span()) + }); + choice(( + structure_instance, range, logic_math_indexes_and_function_calls, function, @@ -417,12 +440,12 @@ pub fn parser<'src>() -> impl Parser< .with_position(state.span()) }); - let structure_field = identifier.clone().then(type_specification.clone()); + let structure_field_definition = identifier.clone().then(type_specification.clone()); let structure_definition = just(Token::Keyword("struct")) .ignore_then(identifier.clone()) .then( - structure_field + structure_field_definition .separated_by(just(Token::Control(Control::Comma))) .allow_trailing() .collect() @@ -458,6 +481,37 @@ mod tests { use super::*; + #[test] + fn structure_instance() { + assert_eq!( + parse( + &lex(" + Foo { + bar = 42, + baz = 'hiya', + } + ") + .unwrap() + ) + .unwrap()[0] + .node, + Statement::Expression(Expression::Value(ValueNode::Structure { + name: Identifier::new("Foo"), + fields: vec![ + ( + Identifier::new("bar"), + Expression::Value(ValueNode::Integer(42)).with_position((57, 59)) + ), + ( + Identifier::new("baz"), + Expression::Value(ValueNode::String("hiya".to_string())) + .with_position((91, 97)) + ), + ] + })) + ) + } + #[test] fn structure_definition() { assert_eq!( diff --git a/src/value.rs b/src/value.rs index ae69c08..2eef0be 100644 --- a/src/value.rs +++ b/src/value.rs @@ -15,7 +15,7 @@ use stanza::{ }; use crate::{ - abstract_tree::{AbstractTree, Action, Block, Identifier, Type, WithPosition}, + abstract_tree::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosition}, context::Context, error::{RuntimeError, ValidationError}, }; @@ -74,8 +74,8 @@ impl Value { Value(Arc::new(ValueInner::Function(Function::BuiltIn(function)))) } - pub fn r#type(&self) -> Type { - match self.0.as_ref() { + pub fn r#type(&self, context: &Context) -> Result { + let r#type = match self.0.as_ref() { ValueInner::Boolean(_) => Type::Boolean, ValueInner::Float(_) => Type::Float, ValueInner::Integer(_) => Type::Integer, @@ -83,7 +83,7 @@ impl Value { let mut types = Vec::with_capacity(values.len()); for value in values { - types.push(value.r#type()); + types.push(value.r#type(context)?); } Type::ListExact(types) @@ -102,7 +102,29 @@ impl Value { }, Function::BuiltIn(built_in_function) => built_in_function.r#type(), }, - } + ValueInner::Structure { + name, + fields: expressions, + } => { + let mut fields = Vec::with_capacity(expressions.len()); + + for (identifier, expression) in expressions { + let r#type = expression + .node + .expected_type(context)? + .with_position(expression.position); + + fields.push((identifier.clone(), r#type)); + } + + Type::Structure { + name: name.clone(), + fields, + } + } + }; + + Ok(r#type) } pub fn as_boolean(&self) -> Option { @@ -176,6 +198,7 @@ impl Display for Value { ValueInner::Function(Function::BuiltIn(built_in_function)) => { write!(f, "{built_in_function}") } + ValueInner::Structure { name, fields } => todo!(), } } } @@ -204,6 +227,10 @@ pub enum ValueInner { Map(BTreeMap), Range(Range), String(String), + Structure { + name: Identifier, + fields: Vec<(Identifier, WithPosition)>, + }, } impl Eq for ValueInner {} @@ -243,6 +270,25 @@ impl Ord for ValueInner { (String(_), _) => Ordering::Greater, (Function(left), Function(right)) => left.cmp(right), (Function(_), _) => Ordering::Greater, + ( + Structure { + name: left_name, + fields: left_fields, + }, + Structure { + name: right_name, + fields: right_fields, + }, + ) => { + let name_cmp = left_name.cmp(right_name); + + if name_cmp.is_eq() { + left_fields.cmp(right_fields) + } else { + name_cmp + } + } + (Structure { .. }, _) => Ordering::Greater, } } } @@ -347,7 +393,7 @@ impl BuiltInFunction { } } - pub fn call(&self, arguments: Vec, _context: &Context) -> Result { + pub fn call(&self, arguments: Vec, context: &Context) -> Result { match self { BuiltInFunction::IntParse => { let string = arguments.get(0).unwrap(); @@ -359,10 +405,18 @@ impl BuiltInFunction { // Ok(Action::Return(Value::integer(integer))) } else { + let mut actual = Vec::with_capacity(arguments.len()); + + for value in arguments { + let r#type = value.r#type(context)?; + + actual.push(r#type); + } + Err(RuntimeError::ValidationFailure( ValidationError::WrongArguments { expected: vec![Type::String], - actual: arguments.iter().map(|value| value.r#type()).collect(), + actual, }, )) }