Implement basic enum instantiation
This commit is contained in:
parent
b8c54ea8bd
commit
89a4c09307
@ -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)?);
|
||||
}
|
||||
|
||||
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<Type, ValidationError> {
|
||||
todo!()
|
||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||
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<Value, RuntimeError> {
|
||||
todo!()
|
||||
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!()
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
}
|
||||
|
@ -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!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user