Add type arguments to enum instances

This commit is contained in:
Jeff 2024-07-12 11:08:53 -04:00
parent ad409b69f3
commit 790438d1e3
5 changed files with 106 additions and 72 deletions

View File

@ -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(())

View File

@ -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(),

View File

@ -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))
))

View File

@ -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

View File

@ -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)),
)))
);
}