1
0

Add enum definition and instance

This commit is contained in:
Jeff 2024-03-18 12:21:42 -04:00
parent b864a23960
commit 40efafb163
5 changed files with 149 additions and 5 deletions

View File

@ -9,14 +9,14 @@ use super::{AbstractTree, Action, Identifier, Type, WithPosition};
pub struct EnumDefinition {
name: Identifier,
type_parameters: Vec<Identifier>,
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
variants: Vec<(Identifier, Option<Vec<WithPosition<Type>>>)>,
}
impl EnumDefinition {
pub fn new(
name: Identifier,
type_parameters: Vec<Identifier>,
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
variants: Vec<(Identifier, Option<Vec<WithPosition<Type>>>)>,
) -> Self {
Self {
name,

View File

@ -3,6 +3,7 @@ use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
use crate::{
context::Context,
error::{RuntimeError, ValidationError},
value::EnumInstance,
Value,
};
@ -11,6 +12,11 @@ use super::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosit
#[derive(Clone, Debug, PartialEq)]
pub enum ValueNode {
Boolean(bool),
EnumInstance {
name: Identifier,
variant: Identifier,
expressions: Vec<WithPosition<Expression>>,
},
Float(f64),
Integer(i64),
List(Vec<WithPosition<Expression>>),
@ -34,6 +40,8 @@ impl AbstractTree for ValueNode {
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
let r#type = match self {
ValueNode::Boolean(_) => Type::Boolean,
ValueNode::EnumInstance { name, .. } => Type::Custom(name.clone()),
ValueNode::Float(_) => Type::Float,
ValueNode::Integer(_) => Type::Integer,
ValueNode::List(items) => {
@ -115,6 +123,26 @@ impl AbstractTree for ValueNode {
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
let value = match self {
ValueNode::Boolean(boolean) => Value::boolean(boolean),
ValueNode::EnumInstance {
name,
variant,
expressions,
} => {
let mut values = Vec::with_capacity(expressions.len());
for expression in expressions {
let action = expression.node.run(_context)?;
let value = if let Action::Return(value) = action {
value
} else {
todo!()
};
values.push(value);
}
Value::enum_instance(EnumInstance::new(name, variant, values))
}
ValueNode::Float(float) => Value::float(float),
ValueNode::Integer(integer) => Value::integer(integer),
ValueNode::List(expression_list) => {
@ -181,6 +209,33 @@ impl Ord for ValueNode {
match (self, other) {
(Boolean(left), Boolean(right)) => left.cmp(right),
(Boolean(_), _) => Ordering::Greater,
(
EnumInstance {
name: left_name,
variant: left_variant,
expressions: left_expressions,
},
EnumInstance {
name: right_name,
variant: right_variant,
expressions: right_expressions,
},
) => {
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_expressions.cmp(right_expressions)
} else {
variant_cmp
}
} else {
name_cmp
}
}
(EnumInstance { .. }, _) => Ordering::Greater,
(Float(left), Float(right)) => left.total_cmp(right),
(Float(_), _) => Ordering::Greater,
(Integer(left), Integer(right)) => left.cmp(right),

View File

@ -343,7 +343,32 @@ pub fn parser<'src>() -> DustParser<'src> {
),
));
let enum_instance = identifier
.clone()
.then_ignore(just(Token::Control(Control::DoubleColon)))
.then(identifier.clone())
.then(
positioned_expression
.clone()
.separated_by(just(Token::Control(Control::Comma)))
.allow_trailing()
.collect()
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
),
)
.map_with(|((name, variant), expressions), state| {
Expression::Value(ValueNode::EnumInstance {
name,
variant,
expressions,
})
.with_position(state.span())
});
choice((
enum_instance,
range,
logic_math_indexes_and_function_calls,
function,
@ -433,7 +458,8 @@ pub fn parser<'src>() -> DustParser<'src> {
.delimited_by(
just(Token::Control(Control::ParenOpen)),
just(Token::Control(Control::ParenClose)),
),
)
.or_not(),
);
let enum_definition = just(Token::Keyword("enum"))
@ -506,11 +532,15 @@ mod tests {
vec![
(
Identifier::new("Foo"),
vec![Type::Custom(Identifier::new("F")).with_position((62, 63))],
Some(vec![
Type::Custom(Identifier::new("F")).with_position((62, 63))
]),
),
(
Identifier::new("Bar"),
vec![Type::Custom(Identifier::new("B")).with_position((90, 91))]
Some(vec![
Type::Custom(Identifier::new("B")).with_position((90, 91))
])
)
]
))

View File

@ -32,6 +32,10 @@ impl Value {
Value(Arc::new(ValueInner::Boolean(boolean)))
}
pub fn enum_instance(enum_instance: EnumInstance) -> Self {
Value(Arc::new(ValueInner::EnumInstance(enum_instance)))
}
pub fn float(float: f64) -> Self {
Value(Arc::new(ValueInner::Float(float)))
}
@ -77,6 +81,7 @@ impl Value {
pub fn r#type(&self) -> Type {
match self.0.as_ref() {
ValueInner::Boolean(_) => Type::Boolean,
ValueInner::EnumInstance(EnumInstance { name, .. }) => Type::Custom(name.clone()),
ValueInner::Float(_) => Type::Float,
ValueInner::Integer(_) => Type::Integer,
ValueInner::List(values) => {
@ -138,6 +143,23 @@ impl Display for Value {
match self.inner().as_ref() {
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
ValueInner::EnumInstance(EnumInstance {
name,
variant,
value: content,
}) => {
write!(f, "{name}::{variant}(")?;
for (index, value) in content.into_iter().enumerate() {
if index == content.len() - 1 {
write!(f, "{value}")?;
} else {
write!(f, "{value} ")?;
}
}
write!(f, ")")
}
ValueInner::Float(float) => write!(f, "{float}"),
ValueInner::Integer(integer) => write!(f, "{integer}"),
ValueInner::List(list) => {
@ -197,6 +219,7 @@ impl Ord for Value {
#[derive(Clone, Debug, PartialEq)]
pub enum ValueInner {
Boolean(bool),
EnumInstance(EnumInstance),
Float(f64),
Function(Function),
Integer(i64),
@ -221,6 +244,8 @@ impl Ord for ValueInner {
match (self, other) {
(Boolean(left), Boolean(right)) => left.cmp(right),
(Boolean(_), _) => Ordering::Greater,
(EnumInstance(left), EnumInstance(right)) => left.cmp(right),
(EnumInstance(_), _) => Ordering::Greater,
(Float(left), Float(right)) => left.total_cmp(right),
(Float(_), _) => Ordering::Greater,
(Integer(left), Integer(right)) => left.cmp(right),
@ -247,6 +272,23 @@ impl Ord for ValueInner {
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub struct EnumInstance {
name: Identifier,
variant: Identifier,
value: Vec<Value>,
}
impl EnumInstance {
pub fn new(name: Identifier, variant: Identifier, value: Vec<Value>) -> Self {
Self {
name,
variant,
value,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
pub enum Function {
Parsed(ParsedFunction),

17
tests/enums.rs Normal file
View File

@ -0,0 +1,17 @@
use dust_lang::*;
#[test]
fn define_enum() {
interpret(
"
enum FooBar(F) {
Foo(F),
Bar,
}
foo = FooBar::Foo(1)
foo
",
)
.unwrap();
}