Add type arguments to enum instances
This commit is contained in:
parent
ad409b69f3
commit
790438d1e3
@ -25,8 +25,9 @@ pub enum ValueNode {
|
||||
BuiltInFunction(BuiltInFunction),
|
||||
EnumInstance {
|
||||
type_name: WithPosition<Identifier>,
|
||||
type_arguments: Option<Vec<TypeConstructor>>,
|
||||
variant: WithPosition<Identifier>,
|
||||
content: Option<Vec<Expression>>,
|
||||
content: Option<Box<Expression>>,
|
||||
},
|
||||
Float(f64),
|
||||
Integer(i64),
|
||||
@ -101,14 +102,13 @@ impl AbstractNode for ValueNode {
|
||||
|
||||
if let ValueNode::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content,
|
||||
} = self
|
||||
{
|
||||
if let Some(expressions) = content {
|
||||
for expression in expressions {
|
||||
expression.define_and_validate(context, _manage_memory, scope)?;
|
||||
}
|
||||
if let Some(expression) = content {
|
||||
expression.define_and_validate(context, _manage_memory, scope)?;
|
||||
}
|
||||
|
||||
if let Some(Type::Enum { name, variants, .. }) = context.get_type(&type_name.node)? {
|
||||
@ -296,30 +296,39 @@ impl AbstractNode for ValueNode {
|
||||
ValueNode::Boolean(boolean) => Value::boolean(boolean),
|
||||
ValueNode::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content: expressions,
|
||||
} => {
|
||||
let content = if let Some(expressions) = expressions {
|
||||
let mut values = Vec::with_capacity(expressions.len());
|
||||
let content = if let Some(expression) = expressions {
|
||||
let position = expression.position();
|
||||
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||
|
||||
for expression in expressions {
|
||||
let position = expression.position();
|
||||
let evaluation = expression.evaluate(context, manage_memory, scope)?;
|
||||
|
||||
if let Some(Evaluation::Return(value)) = evaluation {
|
||||
values.push(value);
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedValueStatement(position),
|
||||
));
|
||||
}
|
||||
if let Some(Evaluation::Return(value)) = evaluation {
|
||||
Some(value)
|
||||
} else {
|
||||
return Err(RuntimeError::ValidationFailure(
|
||||
ValidationError::ExpectedValueStatement(position),
|
||||
));
|
||||
}
|
||||
Some(values)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let type_arguments = if let Some(arguments) = type_arguments {
|
||||
let mut types = Vec::with_capacity(arguments.len());
|
||||
|
||||
for constructor in arguments {
|
||||
let r#type = constructor.construct(context)?;
|
||||
|
||||
types.push(r#type);
|
||||
}
|
||||
|
||||
Some(types)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Value::enum_instance(type_name.node, variant.node, content)
|
||||
Value::enum_instance(type_name.node, type_arguments, variant.node, content)
|
||||
}
|
||||
ValueNode::Float(float) => Value::float(float),
|
||||
ValueNode::Integer(integer) => Value::integer(integer),
|
||||
@ -577,11 +586,13 @@ impl Ord for ValueNode {
|
||||
(
|
||||
EnumInstance {
|
||||
type_name: left_name,
|
||||
type_arguments: left_type_args,
|
||||
variant: left_variant,
|
||||
content: left_content,
|
||||
},
|
||||
EnumInstance {
|
||||
type_name: right_name,
|
||||
type_arguments: right_type_args,
|
||||
variant: right_variant,
|
||||
content: right_content,
|
||||
},
|
||||
@ -589,12 +600,18 @@ impl Ord for ValueNode {
|
||||
let name_cmp = left_name.cmp(right_name);
|
||||
|
||||
if name_cmp.is_eq() {
|
||||
let variant_cmp = left_variant.cmp(right_variant);
|
||||
let type_arg_cmp = left_type_args.cmp(right_type_args);
|
||||
|
||||
if variant_cmp.is_eq() {
|
||||
left_content.cmp(right_content)
|
||||
if type_arg_cmp.is_eq() {
|
||||
let variant_cmp = left_variant.cmp(right_variant);
|
||||
|
||||
if variant_cmp.is_eq() {
|
||||
left_content.cmp(right_content)
|
||||
} else {
|
||||
variant_cmp
|
||||
}
|
||||
} else {
|
||||
variant_cmp
|
||||
type_arg_cmp
|
||||
}
|
||||
} else {
|
||||
name_cmp
|
||||
@ -670,15 +687,14 @@ impl Display for ValueNode {
|
||||
ValueNode::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"),
|
||||
ValueNode::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content,
|
||||
} => {
|
||||
write!(f, "{}::{}", type_name.node, variant.node)?;
|
||||
|
||||
if let Some(content) = content {
|
||||
for expression in content {
|
||||
write!(f, "{expression}")?;
|
||||
}
|
||||
if let Some(expression) = content {
|
||||
write!(f, "{expression}")?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -267,6 +267,18 @@ pub fn parser<'src>(
|
||||
type ValueParameters = Vec<(Identifier, TypeConstructor)>;
|
||||
type FunctionParameters = (Option<TypeParameters>, ValueParameters);
|
||||
|
||||
let turbofish = just(Token::Symbol(Symbol::DoubleColon)).ignore_then(
|
||||
type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Symbol(Symbol::Comma)))
|
||||
.at_least(1)
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Symbol(Symbol::Less)),
|
||||
just(Token::Symbol(Symbol::Greater)),
|
||||
),
|
||||
);
|
||||
|
||||
let function = just(Token::Keyword(Keyword::Fn))
|
||||
.ignore_then(
|
||||
identifier
|
||||
@ -323,25 +335,17 @@ pub fn parser<'src>(
|
||||
);
|
||||
|
||||
let enum_instance = positioned_identifier
|
||||
.then(turbofish.clone().or_not())
|
||||
.then_ignore(just(Token::Symbol(Symbol::DoubleColon)))
|
||||
.then(positioned_identifier)
|
||||
.then(
|
||||
expression
|
||||
.clone()
|
||||
.separated_by(just(Token::Symbol(Symbol::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Symbol(Symbol::ParenOpen)),
|
||||
just(Token::Symbol(Symbol::ParenClose)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.map_with(|((type_name, variant), content), state| {
|
||||
.then(expression.clone().or_not())
|
||||
.map_with(|(((type_name, type_arguments), variant), content), state| {
|
||||
Expression::Value(
|
||||
ValueNode::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content,
|
||||
content: content.map(|expression| Box::new(expression)),
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
@ -403,18 +407,6 @@ pub fn parser<'src>(
|
||||
expression
|
||||
});
|
||||
|
||||
let turbofish = just(Token::Symbol(Symbol::DoubleColon)).ignore_then(
|
||||
type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Symbol(Symbol::Comma)))
|
||||
.at_least(1)
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Symbol(Symbol::Less)),
|
||||
just(Token::Symbol(Symbol::Greater)),
|
||||
),
|
||||
);
|
||||
|
||||
let atom = choice((
|
||||
built_in_function,
|
||||
enum_instance.clone(),
|
||||
|
@ -49,10 +49,11 @@ fn type_invokation() {
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::EnumInstance {
|
||||
type_name: Identifier::new("Foo").with_position((14, 17)),
|
||||
type_arguments: None,
|
||||
variant: Identifier::new("Bar").with_position((19, 22)),
|
||||
content: Some(vec![Expression::Value(
|
||||
content: Some(Box::new(Expression::Value(
|
||||
ValueNode::Integer(42).with_position((23, 25))
|
||||
)])
|
||||
)))
|
||||
}
|
||||
.with_position((14, 26))
|
||||
))
|
||||
@ -69,10 +70,11 @@ fn enum_instance() {
|
||||
Statement::Expression(Expression::Value(
|
||||
ValueNode::EnumInstance {
|
||||
type_name: Identifier::new("Foo").with_position((0, 3)),
|
||||
type_arguments: None,
|
||||
variant: Identifier::new("Bar").with_position((5, 8)),
|
||||
content: Some(vec![Expression::Value(
|
||||
content: Some(Box::new(Expression::Value(
|
||||
ValueNode::Integer(42).with_position((9, 11))
|
||||
)])
|
||||
)))
|
||||
}
|
||||
.with_position((0, 12))
|
||||
))
|
||||
|
@ -41,11 +41,13 @@ impl Value {
|
||||
|
||||
pub fn enum_instance(
|
||||
type_name: Identifier,
|
||||
type_arguments: Option<Vec<Type>>,
|
||||
variant: Identifier,
|
||||
content: Option<Vec<Value>>,
|
||||
content: Option<Value>,
|
||||
) -> Self {
|
||||
Value(Arc::new(ValueInner::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content,
|
||||
}))
|
||||
@ -128,20 +130,29 @@ impl Display for Value {
|
||||
ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
|
||||
ValueInner::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content,
|
||||
} => {
|
||||
if let Some(values) = content {
|
||||
write!(f, "{type_name}::{variant}(")?;
|
||||
write!(f, "{type_name}::")?;
|
||||
|
||||
for value in values {
|
||||
write!(f, "{value}")?;
|
||||
if let Some(types) = type_arguments {
|
||||
write!(f, "::<")?;
|
||||
|
||||
for r#type in types {
|
||||
write!(f, "{type}, ")?;
|
||||
}
|
||||
|
||||
write!(f, ")")
|
||||
} else {
|
||||
write!(f, "{type_name}::{variant}")
|
||||
write!(f, ">")?;
|
||||
}
|
||||
|
||||
write!(f, "::{variant}(")?;
|
||||
|
||||
if let Some(value) = content {
|
||||
write!(f, "{value}")?;
|
||||
}
|
||||
|
||||
write!(f, ")")
|
||||
}
|
||||
ValueInner::Float(float) => {
|
||||
write!(f, "{float}")?;
|
||||
@ -257,12 +268,14 @@ impl Serialize for Value {
|
||||
ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean),
|
||||
ValueInner::EnumInstance {
|
||||
type_name,
|
||||
type_arguments,
|
||||
variant,
|
||||
content,
|
||||
} => {
|
||||
let mut struct_ser = serializer.serialize_struct("EnumInstance", 3)?;
|
||||
|
||||
struct_ser.serialize_field("type_name", type_name)?;
|
||||
struct_ser.serialize_field("type_arguments", type_arguments)?;
|
||||
struct_ser.serialize_field("variant", variant)?;
|
||||
struct_ser.serialize_field("content", content)?;
|
||||
|
||||
@ -574,8 +587,9 @@ pub enum ValueInner {
|
||||
BuiltInFunction(BuiltInFunction),
|
||||
EnumInstance {
|
||||
type_name: Identifier,
|
||||
type_arguments: Option<Vec<Type>>,
|
||||
variant: Identifier,
|
||||
content: Option<Vec<Value>>,
|
||||
content: Option<Value>,
|
||||
},
|
||||
Float(f64),
|
||||
Function(Function),
|
||||
@ -691,11 +705,13 @@ impl Ord for ValueInner {
|
||||
(
|
||||
EnumInstance {
|
||||
type_name: left_name,
|
||||
type_arguments: left_arguments,
|
||||
variant: left_variant,
|
||||
content: left_content,
|
||||
},
|
||||
EnumInstance {
|
||||
type_name: right_name,
|
||||
type_arguments: right_arguments,
|
||||
variant: right_variant,
|
||||
content: right_content,
|
||||
},
|
||||
@ -703,12 +719,18 @@ impl Ord for ValueInner {
|
||||
let name_cmp = left_name.cmp(right_name);
|
||||
|
||||
if name_cmp.is_eq() {
|
||||
let variant_cmp = left_variant.cmp(right_variant);
|
||||
let argument_cmp = left_arguments.cmp(right_arguments);
|
||||
|
||||
if variant_cmp.is_eq() {
|
||||
left_content.cmp(right_content)
|
||||
if argument_cmp.is_eq() {
|
||||
let variant_cmp = left_variant.cmp(right_variant);
|
||||
|
||||
if variant_cmp.is_eq() {
|
||||
left_content.cmp(right_content)
|
||||
} else {
|
||||
variant_cmp
|
||||
}
|
||||
} else {
|
||||
variant_cmp
|
||||
argument_cmp
|
||||
}
|
||||
} else {
|
||||
name_cmp
|
||||
|
@ -16,6 +16,7 @@ fn simple_enum() {
|
||||
),
|
||||
Ok(Some(Value::enum_instance(
|
||||
Identifier::new("FooBar"),
|
||||
None,
|
||||
Identifier::new("Foo"),
|
||||
None
|
||||
)))
|
||||
@ -34,13 +35,14 @@ fn big_enum() {
|
||||
Baz(V),
|
||||
}
|
||||
|
||||
FooBarBaz::Baz(42.0)
|
||||
FooBarBaz::<int, str, float>::Baz(42.0)
|
||||
"
|
||||
),
|
||||
Ok(Some(Value::enum_instance(
|
||||
Identifier::new("FooBarBaz"),
|
||||
None,
|
||||
Identifier::new("Baz"),
|
||||
Some(vec![Value::float(42.0)]),
|
||||
Some(Value::float(42.0)),
|
||||
)))
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user