Implement basic enum instantiation

This commit is contained in:
Jeff 2024-02-14 22:38:45 -05:00
parent b8c54ea8bd
commit 89a4c09307
11 changed files with 224 additions and 47 deletions

View File

@ -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<Self, SyntaxError> {
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)?);
}
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
todo!()
if let Some(identifier) = &current_identifier {
if child.kind() == "type" {
let r#type = Type::from_syntax(child, source, context)?;
variants.push((identifier.clone(), VariantContent::Type(r#type)));
}
fn validate(&self, source: &str, context: &Context) -> Result<(), ValidationError> {
todo!()
if child.kind() == "type_definition" {
let type_definition = TypeDefinition::from_syntax(child, source, context)?;
variants.push((
identifier.clone(),
VariantContent::TypeDefinition(type_definition),
));
}
}
}
fn run(&self, source: &str, context: &Context) -> Result<Value, RuntimeError> {
todo!()
Ok(EnumDefinition {
identifier,
variants,
})
}
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
Ok(Type::None)
}
fn validate(&self, _source: &str, _context: &Context) -> Result<(), ValidationError> {
Ok(())
}
fn run(&self, _source: &str, context: &Context) -> Result<Value, RuntimeError> {
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!()
}
}

View File

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

View File

@ -34,21 +34,32 @@ impl AbstractTree for TypeDefinition {
}
}
fn expected_type(&self, context: &Context) -> Result<Type, ValidationError> {
todo!()
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
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<Value, RuntimeError> {
todo!()
fn run(&self, _source: &str, _context: &Context) -> Result<Value, RuntimeError> {
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!()
}
}

View File

@ -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<Box<Expression>>),
Map(BTreeMap<String, (Statement, Option<Type>)>, SourcePosition),
BuiltInValue(BuiltInValue),
Structure(BTreeMap<String, (Option<Statement>, Type)>),
Range(RangeInclusive<i64>),
Structure(BTreeMap<String, (Option<Statement>, Type)>),
Enum {
name: Identifier,
variant: Identifier,
expression: Option<Box<Expression>>,
},
}
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,
}

View File

@ -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<Option<TypeDefinition>, 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,
}
}

View File

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

View File

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

View File

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

View File

@ -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<Value>,
}
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),
}

View File

@ -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<i64>),
Option(Option<Box<Value>>),
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!(),
}
}
}

View File

@ -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()
)))
);
}