From 89a4c093079dc7854a918e484d0e4a795fe6fa50 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 14 Feb 2024 22:38:45 -0500 Subject: [PATCH] Implement basic enum instantiation --- src/abstract_tree/enum_defintion.rs | 77 ++++++++++++++++++++++---- src/abstract_tree/statement.rs | 5 +- src/abstract_tree/type_definition.rs | 25 ++++++--- src/abstract_tree/value_node.rs | 81 ++++++++++++++++++++++++++-- src/context.rs | 28 +++++++++- src/error/runtime_error.rs | 4 +- src/error/validation_error.rs | 10 +++- src/main.rs | 1 + src/value/enum.rs | 12 +++-- src/value/mod.rs | 22 +++----- tests/enums.rs | 6 ++- 11 files changed, 224 insertions(+), 47 deletions(-) diff --git a/src/abstract_tree/enum_defintion.rs b/src/abstract_tree/enum_defintion.rs index 2301d00..c44e6a0 100644 --- a/src/abstract_tree/enum_defintion.rs +++ b/src/abstract_tree/enum_defintion.rs @@ -3,32 +3,89 @@ use tree_sitter::Node as SyntaxNode; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, Context, Format, Type, Value, + AbstractTree, Context, EnumInstance, Format, Identifier, Type, TypeDefinition, Value, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] -pub struct EnumDefinition; +pub struct EnumDefinition { + identifier: Identifier, + variants: Vec<(Identifier, VariantContent)>, +} + +#[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq, PartialOrd, Ord)] +enum VariantContent { + Type(Type), + TypeDefinition(TypeDefinition), + None, +} + +impl EnumDefinition { + pub fn instantiate(&self, variant: String, content: Value) -> EnumInstance { + EnumInstance::new(self.identifier.inner().clone(), variant, content) + } +} impl AbstractTree for EnumDefinition { fn from_syntax(node: SyntaxNode, source: &str, context: &Context) -> Result { - todo!() + SyntaxError::expect_syntax_node(source, "enum_definition", node)?; + + let identifier_node = node.child(1).unwrap(); + let identifier = Identifier::from_syntax(identifier_node, source, context)?; + + let mut variants = Vec::new(); + let mut current_identifier = None; + + for index in 3..node.child_count() - 1 { + let child = node.child(index).unwrap(); + + if child.kind() == "identifier" { + current_identifier = Some(Identifier::from_syntax(child, source, context)?); + } + + if let Some(identifier) = ¤t_identifier { + if child.kind() == "type" { + let r#type = Type::from_syntax(child, source, context)?; + + variants.push((identifier.clone(), VariantContent::Type(r#type))); + } + + if child.kind() == "type_definition" { + let type_definition = TypeDefinition::from_syntax(child, source, context)?; + + variants.push(( + identifier.clone(), + VariantContent::TypeDefinition(type_definition), + )); + } + } + } + + Ok(EnumDefinition { + identifier, + variants, + }) } - fn expected_type(&self, context: &Context) -> Result { - todo!() + fn expected_type(&self, _context: &Context) -> Result { + Ok(Type::None) } - fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> { - todo!() + fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> { + Ok(()) } - fn run(&self, source: &str, context: &Context) -> Result { - todo!() + fn run(&self, _source: &str, context: &Context) -> Result { + context.set_definition( + self.identifier.inner().clone(), + TypeDefinition::Enum(self.clone()), + )?; + + Ok(Value::none()) } } impl Format for EnumDefinition { - fn format(&self, output: &mut String, indent_level: u8) { + fn format(&self, _output: &mut String, _indent_level: u8) { todo!() } } diff --git a/src/abstract_tree/statement.rs b/src/abstract_tree/statement.rs index b993c9b..fbec2f6 100644 --- a/src/abstract_tree/statement.rs +++ b/src/abstract_tree/statement.rs @@ -57,9 +57,12 @@ impl AbstractTree for Statement { Ok(Statement::Return(Box::new(Statement::from_syntax(statement_node, source, context)?))) }, + "type_definition" => Ok(Statement::TypeDefinition(TypeDefinition::from_syntax( + child, source, context + )?)), _ => Err(SyntaxError::UnexpectedSyntaxNode { expected: - "assignment, index assignment, expression, block, return, if...else, while, for or match".to_string(), + "assignment, index assignment, expression, type_definition, block, return, if...else, while, for or match".to_string(), actual: child.kind().to_string(), location: child.start_position(), relevant_source: source[child.byte_range()].to_string(), diff --git a/src/abstract_tree/type_definition.rs b/src/abstract_tree/type_definition.rs index b050704..41f7446 100644 --- a/src/abstract_tree/type_definition.rs +++ b/src/abstract_tree/type_definition.rs @@ -34,21 +34,32 @@ impl AbstractTree for TypeDefinition { } } - fn expected_type(&self, context: &Context) -> Result { - todo!() + fn expected_type(&self, _context: &Context) -> Result { + match self { + TypeDefinition::Enum(enum_definition) => enum_definition.expected_type(_context), + TypeDefinition::Struct(struct_definition) => struct_definition.expected_type(_context), + } } - fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> { - todo!() + fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> { + match self { + TypeDefinition::Enum(enum_definition) => enum_definition.validate(_source, _context), + TypeDefinition::Struct(struct_definition) => { + struct_definition.validate(_source, _context) + } + } } - fn run(&self, source: &str, context: &Context) -> Result { - todo!() + fn run(&self, _source: &str, _context: &Context) -> Result { + match self { + TypeDefinition::Enum(enum_definition) => enum_definition.run(_source, _context), + TypeDefinition::Struct(struct_definition) => struct_definition.run(_source, _context), + } } } impl Format for TypeDefinition { - fn format(&self, output: &mut String, indent_level: u8) { + fn format(&self, _output: &mut String, _indent_level: u8) { todo!() } } diff --git a/src/abstract_tree/value_node.rs b/src/abstract_tree/value_node.rs index 1a15b9d..4539877 100644 --- a/src/abstract_tree/value_node.rs +++ b/src/abstract_tree/value_node.rs @@ -1,11 +1,13 @@ use std::{cmp::Ordering, collections::BTreeMap, ops::RangeInclusive}; use serde::{Deserialize, Serialize}; +use tree_sitter::Node as SyntaxNode; use crate::{ error::{RuntimeError, SyntaxError, ValidationError}, - AbstractTree, BuiltInValue, Context, Expression, Format, Function, FunctionNode, Identifier, - List, Map, SourcePosition, Statement, Structure, SyntaxNode, Type, TypeSpecification, Value, + AbstractTree, BuiltInValue, Context, Expression, Format, Function, FunctionNode, + Identifier, List, Map, SourcePosition, Statement, Structure, Type, + TypeSpecification, Value, TypeDefinition, }; #[derive(Debug, Clone, Serialize, Deserialize, Eq, PartialEq)] @@ -19,8 +21,13 @@ pub enum ValueNode { Option(Option>), Map(BTreeMap)>, SourcePosition), BuiltInValue(BuiltInValue), - Structure(BTreeMap, Type)>), Range(RangeInclusive), + Structure(BTreeMap, Type)>), + Enum { + name: Identifier, + variant: Identifier, + expression: Option>, + }, } impl AbstractTree for ValueNode { @@ -167,10 +174,25 @@ impl AbstractTree for ValueNode { ValueNode::Range(start..=end) } + "enum_instance" => { + let name_node = child.child(1).unwrap(); + let name = Identifier::from_syntax(name_node, source, context)?; + + let variant_node = child.child(3).unwrap(); + let variant = Identifier::from_syntax(variant_node, source, context)?; + + let expression = if let Some(expression_node) = child.child(5) { + Some(Box::new(Expression::from_syntax(expression_node, source, context)?)) + } else { + None + }; + + ValueNode::Enum { name, variant , expression } + } _ => { return Err(SyntaxError::UnexpectedSyntaxNode { expected: - "string, integer, float, boolean, range, list, map, option, function or structure" + "string, integer, float, boolean, range, list, map, option, function, structure or enum" .to_string(), actual: child.kind().to_string(), location: child.start_position(), @@ -229,6 +251,7 @@ impl AbstractTree for ValueNode { Type::Map(Some(Structure::new(value_map))) } ValueNode::Range(_) => Type::Range, + ValueNode::Enum { name, .. } => Type::Custom(name.clone()), }; Ok(r#type) @@ -256,7 +279,7 @@ impl AbstractTree for ValueNode { } } } - _ => {} + _ => {}, } Ok(()) @@ -323,6 +346,30 @@ impl AbstractTree for ValueNode { Value::Structure(Structure::new(value_map)) } ValueNode::Range(range) => Value::Range(range.clone()), + ValueNode::Enum { name, variant, expression } => { + let value = if let Some(expression) = expression { + expression.run(source, context)? + } else { + Value::none() + }; + let instance = if let Some(definition) = context.get_definition(name.inner())? { + if let TypeDefinition::Enum(enum_defintion) = definition { + enum_defintion.instantiate(variant.inner().clone(), value) + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::ExpectedEnumDefintion { + actual: definition.clone() + } + )); + } + } else { + return Err(RuntimeError::ValidationFailure( + ValidationError::TypeDefinitionNotFound(name.inner().clone()) + )); + }; + + Value::Enum(instance) + }, }; Ok(value) @@ -407,6 +454,7 @@ impl Format for ValueNode { output.push('}'); } ValueNode::Range(_) => todo!(), + ValueNode::Enum { .. } => todo!(), } } } @@ -434,6 +482,29 @@ impl Ord for ValueNode { (ValueNode::BuiltInValue(_), _) => Ordering::Greater, (ValueNode::Structure(left), ValueNode::Structure(right)) => left.cmp(right), (ValueNode::Structure(_), _) => Ordering::Greater, + ( + ValueNode::Enum { + name: left_name, variant: left_variant, expression: left_expression + }, + ValueNode::Enum { + name: right_name, variant: right_variant, expression: right_expression + } + ) => { + let name_cmp = left_name.cmp(right_name); + + if name_cmp.is_eq() { + let variant_cmp = left_variant.cmp(right_variant); + + if variant_cmp.is_eq() { + left_expression.cmp(right_expression) + } else { + variant_cmp + } + } else { + name_cmp + } + }, + (ValueNode::Enum { .. }, _) => Ordering::Greater, (ValueNode::Range(left), ValueNode::Range(right)) => left.clone().cmp(right.clone()), (ValueNode::Range(_), _) => Ordering::Less, } diff --git a/src/context.rs b/src/context.rs index 7c362e6..443a814 100644 --- a/src/context.rs +++ b/src/context.rs @@ -4,7 +4,7 @@ use std::{ sync::{Arc, RwLock, RwLockReadGuard}, }; -use crate::{error::rw_lock_error::RwLockError, Type, Value}; +use crate::{error::rw_lock_error::RwLockError, Type, TypeDefinition, Value}; #[derive(Clone, Debug)] pub struct Context { @@ -65,12 +65,23 @@ impl Context { match value_data { ValueData::Value { inner, .. } => Ok(Some(inner.r#type())), ValueData::ExpectedType { inner, .. } => Ok(Some(inner.clone())), + ValueData::TypeDefinition(_) => todo!(), } } else { Ok(None) } } + pub fn get_definition(&self, key: &str) -> Result, RwLockError> { + if let Some(value_data) = self.inner.read()?.get(key) { + if let ValueData::TypeDefinition(definition) = value_data { + return Ok(Some(definition.clone())); + } + } + + Ok(None) + } + pub fn set_value(&self, key: String, value: Value) -> Result<(), RwLockError> { self.inner.write()?.insert( key, @@ -91,6 +102,18 @@ impl Context { Ok(()) } + pub fn set_definition( + &self, + key: String, + definition: TypeDefinition, + ) -> Result<(), RwLockError> { + self.inner + .write()? + .insert(key, ValueData::TypeDefinition(definition)); + + Ok(()) + } + pub fn unset(&self, key: &str) -> Result<(), RwLockError> { self.inner.write()?.remove(key); @@ -151,6 +174,7 @@ pub enum ValueData { ExpectedType { inner: Type, }, + TypeDefinition(TypeDefinition), } impl Eq for ValueData {} @@ -207,6 +231,8 @@ impl Ord for ValueData { ValueData::ExpectedType { inner: inner_left }, ValueData::ExpectedType { inner: inner_right }, ) => inner_left.cmp(inner_right), + (ValueData::TypeDefinition(left), ValueData::TypeDefinition(right)) => left.cmp(right), + (ValueData::TypeDefinition(_), _) => Greater, (ValueData::ExpectedType { .. }, _) => Less, } } diff --git a/src/error/runtime_error.rs b/src/error/runtime_error.rs index 94ff109..8c6821d 100644 --- a/src/error/runtime_error.rs +++ b/src/error/runtime_error.rs @@ -9,7 +9,7 @@ use std::{ use crate::{Type, Value}; -use super::rw_lock_error::RwLockError; +use super::{rw_lock_error::RwLockError, ValidationError}; #[derive(Debug, PartialEq)] pub enum RuntimeError { @@ -114,6 +114,8 @@ pub enum RuntimeError { expected: usize, actual: usize, }, + + ValidationFailure(ValidationError), } impl RuntimeError { diff --git a/src/error/validation_error.rs b/src/error/validation_error.rs index efea76a..133ca0c 100644 --- a/src/error/validation_error.rs +++ b/src/error/validation_error.rs @@ -2,7 +2,7 @@ use std::fmt::{self, Display, Formatter}; use serde::{Deserialize, Serialize}; -use crate::{Identifier, SourcePosition, Type, Value}; +use crate::{Identifier, SourcePosition, Type, TypeDefinition, Value}; use super::rw_lock_error::RwLockError; @@ -61,8 +61,14 @@ pub enum ValidationError { position: SourcePosition, }, - /// Failed to find a variable with a value for this key. + /// Failed to find a value with this key. VariableIdentifierNotFound(Identifier), + + /// Failed to find a type definition with this key. + TypeDefinitionNotFound(String), + + /// Failed to find a type definition with this key. + ExpectedEnumDefintion { actual: TypeDefinition }, } impl ValidationError { diff --git a/src/main.rs b/src/main.rs index e5c20ae..f9069b6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -310,6 +310,7 @@ impl Completer for DustCompleter { let value = match value_data { ValueData::Value { inner, .. } => inner, ValueData::ExpectedType { .. } => continue, + ValueData::TypeDefinition(_) => continue, }; if key.contains(last_word) { diff --git a/src/value/enum.rs b/src/value/enum.rs index 556780a..c9bfa46 100644 --- a/src/value/enum.rs +++ b/src/value/enum.rs @@ -1,14 +1,16 @@ -use crate::{Identifier, Value}; +use crate::Value; -#[derive(Debug, Clone)] -pub struct Enum { +#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)] +pub struct EnumInstance { + name: String, variant_name: String, value: Box, } -impl Enum { - pub fn new(variant_name: String, value: Value) -> Self { +impl EnumInstance { + pub fn new(name: String, variant_name: String, value: Value) -> Self { Self { + name, variant_name, value: Box::new(value), } diff --git a/src/value/mod.rs b/src/value/mod.rs index b3085f0..c7931ba 100644 --- a/src/value/mod.rs +++ b/src/value/mod.rs @@ -16,7 +16,9 @@ use std::{ ops::{Add, AddAssign, Div, Mul, RangeInclusive, Rem, Sub, SubAssign}, }; -pub use self::{function::Function, list::List, map::Map, r#enum::Enum, structure::Structure}; +pub use self::{ + function::Function, list::List, map::Map, r#enum::EnumInstance, structure::Structure, +}; pub mod r#enum; pub mod function; @@ -41,7 +43,7 @@ pub enum Value { Range(RangeInclusive), Option(Option>), Structure(Structure), - Enum(Enum), + Enum(EnumInstance), } impl Default for Value { @@ -443,8 +445,9 @@ impl PartialEq for Value { (Value::Map(left), Value::Map(right)) => left == right, (Value::Function(left), Value::Function(right)) => left == right, (Value::Option(left), Value::Option(right)) => left == right, - (Value::Structure(left), Value::Structure(right)) => left == right, (Value::Range(left), Value::Range(right)) => left == right, + (Value::Structure(left), Value::Structure(right)) => left == right, + (Value::Enum(left), Value::Enum(right)) => left == right, _ => false, } } @@ -483,6 +486,8 @@ impl Ord for Value { (Value::Function(_), _) => Ordering::Greater, (Value::Structure(left), Value::Structure(right)) => left.cmp(right), (Value::Structure(_), _) => Ordering::Greater, + (Value::Enum(left), Value::Enum(right)) => left.cmp(right), + (Value::Enum(_), _) => Ordering::Greater, (Value::Range(left), Value::Range(right)) => { let left_len = left.end() - left.start(); let right_len = right.end() - right.start(); @@ -492,17 +497,6 @@ impl Ord for Value { (Value::Range(_), _) => Ordering::Greater, (Value::Option(left), Value::Option(right)) => left.cmp(right), (Value::Option(_), _) => Ordering::Less, - (Value::Enum(_), Value::List(_)) => todo!(), - (Value::Enum(_), Value::Map(_)) => todo!(), - (Value::Enum(_), Value::Function(_)) => todo!(), - (Value::Enum(_), Value::String(_)) => todo!(), - (Value::Enum(_), Value::Float(_)) => todo!(), - (Value::Enum(_), Value::Integer(_)) => todo!(), - (Value::Enum(_), Value::Boolean(_)) => todo!(), - (Value::Enum(_), Value::Range(_)) => todo!(), - (Value::Enum(_), Value::Option(_)) => todo!(), - (Value::Enum(_), Value::Structure(_)) => todo!(), - (Value::Enum(_), Value::Enum(_)) => todo!(), } } } diff --git a/tests/enums.rs b/tests/enums.rs index b18b5b6..046c1a1 100644 --- a/tests/enums.rs +++ b/tests/enums.rs @@ -15,6 +15,10 @@ fn simple_enum() { assert_eq!( result, - Ok(Value::Enum(Enum::new("Foo".to_string(), Value::none()))) + Ok(Value::Enum(EnumInstance::new( + "Foobar".to_string(), + "Foo".to_string(), + Value::none() + ))) ); }