Refine enums
This commit is contained in:
parent
40efafb163
commit
9f98617f6a
@ -8,15 +8,15 @@ use super::{AbstractTree, Action, Identifier, Type, WithPosition};
|
|||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub struct EnumDefinition {
|
pub struct EnumDefinition {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
type_parameters: Vec<Identifier>,
|
type_parameters: Option<Vec<Identifier>>,
|
||||||
variants: Vec<(Identifier, Option<Vec<WithPosition<Type>>>)>,
|
variants: Vec<(Identifier, Option<WithPosition<Type>>)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumDefinition {
|
impl EnumDefinition {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
type_parameters: Vec<Identifier>,
|
type_parameters: Option<Vec<Identifier>>,
|
||||||
variants: Vec<(Identifier, Option<Vec<WithPosition<Type>>>)>,
|
variants: Vec<(Identifier, Option<WithPosition<Type>>)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
@ -24,6 +24,18 @@ impl EnumDefinition {
|
|||||||
variants,
|
variants,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name(&self) -> &Identifier {
|
||||||
|
&self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_parameters(&self) -> &Option<Vec<Identifier>> {
|
||||||
|
&self.type_parameters
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn variants(&self) -> &Vec<(Identifier, Option<WithPosition<Type>>)> {
|
||||||
|
&self.variants
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for EnumDefinition {
|
impl AbstractTree for EnumDefinition {
|
||||||
|
@ -12,7 +12,12 @@ use super::{AbstractTree, Action};
|
|||||||
pub enum Type {
|
pub enum Type {
|
||||||
Any,
|
Any,
|
||||||
Boolean,
|
Boolean,
|
||||||
Custom(Identifier),
|
Parameter(Identifier),
|
||||||
|
Enum {
|
||||||
|
name: Identifier,
|
||||||
|
type_arguments: Option<Vec<Type>>,
|
||||||
|
variants: Vec<(Identifier, Option<Type>)>,
|
||||||
|
},
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
parameter_types: Vec<Type>,
|
parameter_types: Vec<Type>,
|
||||||
@ -45,7 +50,7 @@ impl Type {
|
|||||||
| (Type::None, Type::None)
|
| (Type::None, Type::None)
|
||||||
| (Type::Range, Type::Range)
|
| (Type::Range, Type::Range)
|
||||||
| (Type::String, Type::String) => Ok(()),
|
| (Type::String, Type::String) => Ok(()),
|
||||||
(Type::Custom(left), Type::Custom(right)) => {
|
(Type::Parameter(left), Type::Parameter(right)) => {
|
||||||
if left == right {
|
if left == right {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -113,7 +118,26 @@ impl Display for Type {
|
|||||||
match self {
|
match self {
|
||||||
Type::Any => write!(f, "any"),
|
Type::Any => write!(f, "any"),
|
||||||
Type::Boolean => write!(f, "boolean"),
|
Type::Boolean => write!(f, "boolean"),
|
||||||
Type::Custom(name) => write!(f, "{name}"),
|
Type::Parameter(name) => write!(f, "{name}"),
|
||||||
|
Type::Enum {
|
||||||
|
name,
|
||||||
|
type_arguments,
|
||||||
|
variants: _,
|
||||||
|
} => {
|
||||||
|
write!(f, "{name}(")?;
|
||||||
|
|
||||||
|
if let Some(type_arguments) = type_arguments {
|
||||||
|
for (index, r#type) in type_arguments.into_iter().enumerate() {
|
||||||
|
if index == type_arguments.len() - 1 {
|
||||||
|
write!(f, "{}", r#type)?;
|
||||||
|
} else {
|
||||||
|
write!(f, "{}, ", r#type)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
Type::Float => write!(f, "float"),
|
Type::Float => write!(f, "float"),
|
||||||
Type::Integer => write!(f, "integer"),
|
Type::Integer => write!(f, "integer"),
|
||||||
Type::List => write!(f, "list"),
|
Type::List => write!(f, "list"),
|
||||||
@ -160,7 +184,7 @@ mod tests {
|
|||||||
assert_eq!(Type::Any.check(&Type::Any), Ok(()));
|
assert_eq!(Type::Any.check(&Type::Any), Ok(()));
|
||||||
assert_eq!(Type::Boolean.check(&Type::Boolean), Ok(()));
|
assert_eq!(Type::Boolean.check(&Type::Boolean), Ok(()));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Type::Custom(Identifier::new("foo")).check(&Type::Custom(Identifier::new("foo"))),
|
Type::Parameter(Identifier::new("foo")).check(&Type::Parameter(Identifier::new("foo"))),
|
||||||
Ok(())
|
Ok(())
|
||||||
);
|
);
|
||||||
assert_eq!(Type::Float.check(&Type::Float), Ok(()));
|
assert_eq!(Type::Float.check(&Type::Float), Ok(()));
|
||||||
@ -183,8 +207,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn errors() {
|
fn errors() {
|
||||||
let foo = Type::Custom(Identifier::new("foo"));
|
let foo = Type::Parameter(Identifier::new("foo"));
|
||||||
let bar = Type::Custom(Identifier::new("bar"));
|
let bar = Type::Parameter(Identifier::new("bar"));
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
foo.check(&bar),
|
foo.check(&bar),
|
||||||
|
@ -15,7 +15,8 @@ pub enum ValueNode {
|
|||||||
EnumInstance {
|
EnumInstance {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
variant: Identifier,
|
variant: Identifier,
|
||||||
expressions: Vec<WithPosition<Expression>>,
|
type_arguments: Option<Vec<WithPosition<Type>>>,
|
||||||
|
expression: Box<WithPosition<Expression>>,
|
||||||
},
|
},
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
@ -37,18 +38,29 @@ pub enum ValueNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AbstractTree for ValueNode {
|
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::EnumInstance {
|
||||||
|
name,
|
||||||
|
variant: _,
|
||||||
|
type_arguments,
|
||||||
|
expression: _,
|
||||||
|
} => {
|
||||||
|
if let Some(r#type) = context.get_type(name)? {
|
||||||
|
r#type
|
||||||
|
} else {
|
||||||
|
Type::None
|
||||||
|
}
|
||||||
|
}
|
||||||
ValueNode::Float(_) => Type::Float,
|
ValueNode::Float(_) => Type::Float,
|
||||||
ValueNode::Integer(_) => Type::Integer,
|
ValueNode::Integer(_) => Type::Integer,
|
||||||
ValueNode::List(items) => {
|
ValueNode::List(items) => {
|
||||||
let mut item_types = Vec::with_capacity(items.len());
|
let mut item_types = Vec::with_capacity(items.len());
|
||||||
|
|
||||||
for expression in items {
|
for expression in items {
|
||||||
item_types.push(expression.node.expected_type(_context)?);
|
item_types.push(expression.node.expected_type(context)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type::ListExact(item_types)
|
Type::ListExact(item_types)
|
||||||
@ -117,6 +129,16 @@ impl AbstractTree for ValueNode {
|
|||||||
})?;
|
})?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let ValueNode::EnumInstance {
|
||||||
|
name,
|
||||||
|
variant,
|
||||||
|
type_arguments,
|
||||||
|
expression,
|
||||||
|
} = self
|
||||||
|
{
|
||||||
|
let r#type = self.expected_type(context)?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,11 +148,9 @@ impl AbstractTree for ValueNode {
|
|||||||
ValueNode::EnumInstance {
|
ValueNode::EnumInstance {
|
||||||
name,
|
name,
|
||||||
variant,
|
variant,
|
||||||
expressions,
|
type_arguments: _,
|
||||||
|
expression,
|
||||||
} => {
|
} => {
|
||||||
let mut values = Vec::with_capacity(expressions.len());
|
|
||||||
|
|
||||||
for expression in expressions {
|
|
||||||
let action = expression.node.run(_context)?;
|
let action = expression.node.run(_context)?;
|
||||||
let value = if let Action::Return(value) = action {
|
let value = if let Action::Return(value) = action {
|
||||||
value
|
value
|
||||||
@ -138,10 +158,7 @@ impl AbstractTree for ValueNode {
|
|||||||
todo!()
|
todo!()
|
||||||
};
|
};
|
||||||
|
|
||||||
values.push(value);
|
Value::enum_instance(EnumInstance::new(name, variant, 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),
|
||||||
@ -213,12 +230,14 @@ impl Ord for ValueNode {
|
|||||||
EnumInstance {
|
EnumInstance {
|
||||||
name: left_name,
|
name: left_name,
|
||||||
variant: left_variant,
|
variant: left_variant,
|
||||||
expressions: left_expressions,
|
type_arguments: left_types,
|
||||||
|
expression: left_expression,
|
||||||
},
|
},
|
||||||
EnumInstance {
|
EnumInstance {
|
||||||
name: right_name,
|
name: right_name,
|
||||||
variant: right_variant,
|
variant: right_variant,
|
||||||
expressions: right_expressions,
|
type_arguments: right_types,
|
||||||
|
expression: right_expression,
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
let name_cmp = left_name.cmp(right_name);
|
let name_cmp = left_name.cmp(right_name);
|
||||||
@ -227,7 +246,13 @@ impl Ord for ValueNode {
|
|||||||
let variant_cmp = left_variant.cmp(right_variant);
|
let variant_cmp = left_variant.cmp(right_variant);
|
||||||
|
|
||||||
if variant_cmp.is_eq() {
|
if variant_cmp.is_eq() {
|
||||||
left_expressions.cmp(right_expressions)
|
let type_cmp = left_types.cmp(right_types);
|
||||||
|
|
||||||
|
if type_cmp.is_eq() {
|
||||||
|
left_expression.cmp(right_expression)
|
||||||
|
} else {
|
||||||
|
type_cmp
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
variant_cmp
|
variant_cmp
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,34 @@ impl Context {
|
|||||||
let r#type = match value_data {
|
let r#type = match value_data {
|
||||||
ValueData::Type(r#type) => r#type.clone(),
|
ValueData::Type(r#type) => r#type.clone(),
|
||||||
ValueData::Value(value) => value.r#type(),
|
ValueData::Value(value) => value.r#type(),
|
||||||
ValueData::EnumDefinition(_) => return Ok(None),
|
ValueData::EnumDefinition(enum_definition) => {
|
||||||
|
let type_arguments =
|
||||||
|
enum_definition
|
||||||
|
.type_parameters()
|
||||||
|
.as_ref()
|
||||||
|
.map(|identifier_list| {
|
||||||
|
identifier_list
|
||||||
|
.into_iter()
|
||||||
|
.map(|identifier| Type::Parameter(identifier.clone()))
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
let variants = enum_definition
|
||||||
|
.variants()
|
||||||
|
.into_iter()
|
||||||
|
.map(|(identifier, type_option)| {
|
||||||
|
(
|
||||||
|
identifier.clone(),
|
||||||
|
type_option.clone().map(|r#type| r#type.node),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Type::Enum {
|
||||||
|
name: enum_definition.name().clone(),
|
||||||
|
type_arguments,
|
||||||
|
variants,
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Some(r#type.clone()));
|
return Ok(Some(r#type.clone()));
|
||||||
|
@ -107,7 +107,7 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
just(Token::Keyword("list")).to(Type::List),
|
just(Token::Keyword("list")).to(Type::List),
|
||||||
identifier
|
identifier
|
||||||
.clone()
|
.clone()
|
||||||
.map(|identifier| Type::Custom(identifier)),
|
.map(|identifier| Type::Parameter(identifier)),
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
.map_with(|r#type, state| r#type.with_position(state.span()));
|
.map_with(|r#type, state| r#type.with_position(state.span()));
|
||||||
@ -345,10 +345,8 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
|
|
||||||
let enum_instance = identifier
|
let enum_instance = identifier
|
||||||
.clone()
|
.clone()
|
||||||
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
|
||||||
.then(identifier.clone())
|
|
||||||
.then(
|
.then(
|
||||||
positioned_expression
|
r#type
|
||||||
.clone()
|
.clone()
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
.separated_by(just(Token::Control(Control::Comma)))
|
||||||
.allow_trailing()
|
.allow_trailing()
|
||||||
@ -356,13 +354,21 @@ 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)),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.map_with(|((name, variant), expressions), state| {
|
.or_not(),
|
||||||
|
)
|
||||||
|
.then_ignore(just(Token::Control(Control::DoubleColon)))
|
||||||
|
.then(identifier.clone())
|
||||||
|
.then(positioned_expression.delimited_by(
|
||||||
|
just(Token::Control(Control::ParenOpen)),
|
||||||
|
just(Token::Control(Control::ParenClose)),
|
||||||
|
))
|
||||||
|
.map_with(|(((name, type_arguments), variant), expression), state| {
|
||||||
Expression::Value(ValueNode::EnumInstance {
|
Expression::Value(ValueNode::EnumInstance {
|
||||||
name,
|
name,
|
||||||
|
type_arguments,
|
||||||
variant,
|
variant,
|
||||||
expressions,
|
expression: Box::new(expression),
|
||||||
})
|
})
|
||||||
.with_position(state.span())
|
.with_position(state.span())
|
||||||
});
|
});
|
||||||
@ -452,9 +458,6 @@ pub fn parser<'src>() -> DustParser<'src> {
|
|||||||
let enum_variant = identifier.clone().then(
|
let enum_variant = identifier.clone().then(
|
||||||
r#type
|
r#type
|
||||||
.clone()
|
.clone()
|
||||||
.separated_by(just(Token::Control(Control::Comma)))
|
|
||||||
.allow_trailing()
|
|
||||||
.collect()
|
|
||||||
.delimited_by(
|
.delimited_by(
|
||||||
just(Token::Control(Control::ParenOpen)),
|
just(Token::Control(Control::ParenOpen)),
|
||||||
just(Token::Control(Control::ParenClose)),
|
just(Token::Control(Control::ParenClose)),
|
||||||
@ -473,7 +476,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(),
|
||||||
)
|
)
|
||||||
.then(
|
.then(
|
||||||
enum_variant
|
enum_variant
|
||||||
@ -517,9 +521,9 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
parse(
|
parse(
|
||||||
&lex("
|
&lex("
|
||||||
enum FooBar (F, B) {
|
enum FooBar {
|
||||||
Foo(F),
|
Foo,
|
||||||
Bar(B),
|
Bar,
|
||||||
}
|
}
|
||||||
")
|
")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -528,20 +532,10 @@ mod tests {
|
|||||||
.node,
|
.node,
|
||||||
Statement::EnumDefinition(EnumDefinition::new(
|
Statement::EnumDefinition(EnumDefinition::new(
|
||||||
Identifier::new("FooBar"),
|
Identifier::new("FooBar"),
|
||||||
vec![Identifier::new("F"), Identifier::new("B")],
|
None,
|
||||||
vec![
|
vec![
|
||||||
(
|
(Identifier::new("Foo"), None),
|
||||||
Identifier::new("Foo"),
|
(Identifier::new("Bar"), None)
|
||||||
Some(vec![
|
|
||||||
Type::Custom(Identifier::new("F")).with_position((62, 63))
|
|
||||||
]),
|
|
||||||
),
|
|
||||||
(
|
|
||||||
Identifier::new("Bar"),
|
|
||||||
Some(vec![
|
|
||||||
Type::Custom(Identifier::new("B")).with_position((90, 91))
|
|
||||||
])
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
);
|
);
|
||||||
|
20
src/value.rs
20
src/value.rs
@ -81,7 +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::EnumInstance(EnumInstance { name, .. }) => Type::Parameter(name.clone()),
|
||||||
ValueInner::Float(_) => Type::Float,
|
ValueInner::Float(_) => Type::Float,
|
||||||
ValueInner::Integer(_) => Type::Integer,
|
ValueInner::Integer(_) => Type::Integer,
|
||||||
ValueInner::List(values) => {
|
ValueInner::List(values) => {
|
||||||
@ -146,19 +146,9 @@ impl Display for Value {
|
|||||||
ValueInner::EnumInstance(EnumInstance {
|
ValueInner::EnumInstance(EnumInstance {
|
||||||
name,
|
name,
|
||||||
variant,
|
variant,
|
||||||
value: content,
|
value,
|
||||||
}) => {
|
}) => {
|
||||||
write!(f, "{name}::{variant}(")?;
|
write!(f, "{name}::{variant}({value})")
|
||||||
|
|
||||||
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}"),
|
||||||
@ -276,11 +266,11 @@ impl Ord for ValueInner {
|
|||||||
pub struct EnumInstance {
|
pub struct EnumInstance {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
variant: Identifier,
|
variant: Identifier,
|
||||||
value: Vec<Value>,
|
value: Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnumInstance {
|
impl EnumInstance {
|
||||||
pub fn new(name: Identifier, variant: Identifier, value: Vec<Value>) -> Self {
|
pub fn new(name: Identifier, variant: Identifier, value: Value) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
variant,
|
variant,
|
||||||
|
@ -1,11 +1,43 @@
|
|||||||
use dust_lang::*;
|
use dust_lang::{
|
||||||
|
abstract_tree::Type,
|
||||||
|
error::{Error, TypeConflict, ValidationError},
|
||||||
|
*,
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn define_enum() {
|
fn simple_enum_type_check() {
|
||||||
|
assert_eq!(
|
||||||
interpret(
|
interpret(
|
||||||
"
|
"
|
||||||
enum FooBar(F) {
|
enum FooBar {
|
||||||
Foo(F),
|
Foo(int),
|
||||||
|
Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
foo = FooBar::Foo('yo')
|
||||||
|
foo
|
||||||
|
",
|
||||||
|
),
|
||||||
|
Err(vec![Error::Validation {
|
||||||
|
error: ValidationError::TypeCheck {
|
||||||
|
conflict: TypeConflict {
|
||||||
|
actual: Type::String,
|
||||||
|
expected: Type::Integer,
|
||||||
|
},
|
||||||
|
actual_position: (0, 0).into(),
|
||||||
|
expected_position: (0, 0).into()
|
||||||
|
},
|
||||||
|
position: (0, 0).into()
|
||||||
|
}])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_enum() {
|
||||||
|
interpret(
|
||||||
|
"
|
||||||
|
enum FooBar {
|
||||||
|
Foo(int),
|
||||||
Bar,
|
Bar,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,3 +47,35 @@ fn define_enum() {
|
|||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn simple_enum_with_type_argument() {
|
||||||
|
interpret(
|
||||||
|
"
|
||||||
|
enum FooBar(F) {
|
||||||
|
Foo(F),
|
||||||
|
Bar,
|
||||||
|
}
|
||||||
|
|
||||||
|
foo = FooBar(int)::Foo(1)
|
||||||
|
foo
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn complex_enum_with_type_arguments() {
|
||||||
|
interpret(
|
||||||
|
"
|
||||||
|
enum FooBar(F, B) {
|
||||||
|
Foo(F),
|
||||||
|
Bar(B),
|
||||||
|
}
|
||||||
|
|
||||||
|
bar = FooBar(int, str)::Bar('bar')
|
||||||
|
bar
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user