Add enum definition and instance
This commit is contained in:
parent
b864a23960
commit
40efafb163
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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))
|
||||
])
|
||||
)
|
||||
]
|
||||
))
|
||||
|
42
src/value.rs
42
src/value.rs
@ -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
17
tests/enums.rs
Normal 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();
|
||||
}
|
Loading…
Reference in New Issue
Block a user