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 {
|
pub struct EnumDefinition {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
type_parameters: Vec<Identifier>,
|
type_parameters: Vec<Identifier>,
|
||||||
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
|
variants: Vec<(Identifier, Option<Vec<WithPosition<Type>>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumDefinition {
|
impl EnumDefinition {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
type_parameters: Vec<Identifier>,
|
type_parameters: Vec<Identifier>,
|
||||||
variants: Vec<(Identifier, Vec<WithPosition<Type>>)>,
|
variants: Vec<(Identifier, Option<Vec<WithPosition<Type>>>)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
|
@ -3,6 +3,7 @@ use std::{cmp::Ordering, collections::BTreeMap, ops::Range};
|
|||||||
use crate::{
|
use crate::{
|
||||||
context::Context,
|
context::Context,
|
||||||
error::{RuntimeError, ValidationError},
|
error::{RuntimeError, ValidationError},
|
||||||
|
value::EnumInstance,
|
||||||
Value,
|
Value,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -11,6 +12,11 @@ use super::{AbstractTree, Action, Block, Expression, Identifier, Type, WithPosit
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ValueNode {
|
pub enum ValueNode {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
|
EnumInstance {
|
||||||
|
name: Identifier,
|
||||||
|
variant: Identifier,
|
||||||
|
expressions: Vec<WithPosition<Expression>>,
|
||||||
|
},
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
List(Vec<WithPosition<Expression>>),
|
List(Vec<WithPosition<Expression>>),
|
||||||
@ -34,6 +40,8 @@ impl AbstractTree for ValueNode {
|
|||||||
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
fn expected_type(&self, _context: &Context) -> Result<Type, ValidationError> {
|
||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
ValueNode::Boolean(_) => Type::Boolean,
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
|
|
||||||
|
ValueNode::EnumInstance { name, .. } => Type::Custom(name.clone()),
|
||||||
ValueNode::Float(_) => Type::Float,
|
ValueNode::Float(_) => Type::Float,
|
||||||
ValueNode::Integer(_) => Type::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::List(items) => {
|
ValueNode::List(items) => {
|
||||||
@ -115,6 +123,26 @@ impl AbstractTree for ValueNode {
|
|||||||
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
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::Float(float) => Value::float(float),
|
||||||
ValueNode::Integer(integer) => Value::integer(integer),
|
ValueNode::Integer(integer) => Value::integer(integer),
|
||||||
ValueNode::List(expression_list) => {
|
ValueNode::List(expression_list) => {
|
||||||
@ -181,6 +209,33 @@ impl Ord for ValueNode {
|
|||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Boolean(left), Boolean(right)) => left.cmp(right),
|
(Boolean(left), Boolean(right)) => left.cmp(right),
|
||||||
(Boolean(_), _) => Ordering::Greater,
|
(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(left), Float(right)) => left.total_cmp(right),
|
||||||
(Float(_), _) => Ordering::Greater,
|
(Float(_), _) => Ordering::Greater,
|
||||||
(Integer(left), Integer(right)) => left.cmp(right),
|
(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((
|
choice((
|
||||||
|
enum_instance,
|
||||||
range,
|
range,
|
||||||
logic_math_indexes_and_function_calls,
|
logic_math_indexes_and_function_calls,
|
||||||
function,
|
function,
|
||||||
@ -433,7 +458,8 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
.delimited_by(
|
.delimited_by(
|
||||||
just(Token::Control(Control::ParenOpen)),
|
just(Token::Control(Control::ParenOpen)),
|
||||||
just(Token::Control(Control::ParenClose)),
|
just(Token::Control(Control::ParenClose)),
|
||||||
),
|
)
|
||||||
|
.or_not(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let enum_definition = just(Token::Keyword("enum"))
|
let enum_definition = just(Token::Keyword("enum"))
|
||||||
@ -506,11 +532,15 @@ mod tests {
|
|||||||
vec![
|
vec![
|
||||||
(
|
(
|
||||||
Identifier::new("Foo"),
|
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"),
|
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)))
|
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 {
|
pub fn float(float: f64) -> Self {
|
||||||
Value(Arc::new(ValueInner::Float(float)))
|
Value(Arc::new(ValueInner::Float(float)))
|
||||||
}
|
}
|
||||||
@ -77,6 +81,7 @@ impl Value {
|
|||||||
pub fn r#type(&self) -> Type {
|
pub fn r#type(&self) -> Type {
|
||||||
match self.0.as_ref() {
|
match self.0.as_ref() {
|
||||||
ValueInner::Boolean(_) => Type::Boolean,
|
ValueInner::Boolean(_) => Type::Boolean,
|
||||||
|
ValueInner::EnumInstance(EnumInstance { name, .. }) => Type::Custom(name.clone()),
|
||||||
ValueInner::Float(_) => Type::Float,
|
ValueInner::Float(_) => Type::Float,
|
||||||
ValueInner::Integer(_) => Type::Integer,
|
ValueInner::Integer(_) => Type::Integer,
|
||||||
ValueInner::List(values) => {
|
ValueInner::List(values) => {
|
||||||
@ -138,6 +143,23 @@ impl Display for Value {
|
|||||||
|
|
||||||
match self.inner().as_ref() {
|
match self.inner().as_ref() {
|
||||||
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
|
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::Float(float) => write!(f, "{float}"),
|
||||||
ValueInner::Integer(integer) => write!(f, "{integer}"),
|
ValueInner::Integer(integer) => write!(f, "{integer}"),
|
||||||
ValueInner::List(list) => {
|
ValueInner::List(list) => {
|
||||||
@ -197,6 +219,7 @@ impl Ord for Value {
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub enum ValueInner {
|
pub enum ValueInner {
|
||||||
Boolean(bool),
|
Boolean(bool),
|
||||||
|
EnumInstance(EnumInstance),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Function(Function),
|
Function(Function),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
@ -221,6 +244,8 @@ impl Ord for ValueInner {
|
|||||||
match (self, other) {
|
match (self, other) {
|
||||||
(Boolean(left), Boolean(right)) => left.cmp(right),
|
(Boolean(left), Boolean(right)) => left.cmp(right),
|
||||||
(Boolean(_), _) => Ordering::Greater,
|
(Boolean(_), _) => Ordering::Greater,
|
||||||
|
(EnumInstance(left), EnumInstance(right)) => left.cmp(right),
|
||||||
|
(EnumInstance(_), _) => Ordering::Greater,
|
||||||
(Float(left), Float(right)) => left.total_cmp(right),
|
(Float(left), Float(right)) => left.total_cmp(right),
|
||||||
(Float(_), _) => Ordering::Greater,
|
(Float(_), _) => Ordering::Greater,
|
||||||
(Integer(left), Integer(right)) => left.cmp(right),
|
(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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Function {
|
pub enum Function {
|
||||||
Parsed(ParsedFunction),
|
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