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), BuiltInFunction(BuiltInFunction),
EnumInstance { EnumInstance {
type_name: WithPosition<Identifier>, type_name: WithPosition<Identifier>,
type_arguments: Option<Vec<TypeConstructor>>,
variant: WithPosition<Identifier>, variant: WithPosition<Identifier>,
content: Option<Vec<Expression>>, content: Option<Box<Expression>>,
}, },
Float(f64), Float(f64),
Integer(i64), Integer(i64),
@ -101,14 +102,13 @@ impl AbstractNode for ValueNode {
if let ValueNode::EnumInstance { if let ValueNode::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content, content,
} = self } = self
{ {
if let Some(expressions) = content { if let Some(expression) = content {
for expression in expressions { expression.define_and_validate(context, _manage_memory, scope)?;
expression.define_and_validate(context, _manage_memory, scope)?;
}
} }
if let Some(Type::Enum { name, variants, .. }) = context.get_type(&type_name.node)? { 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::Boolean(boolean) => Value::boolean(boolean),
ValueNode::EnumInstance { ValueNode::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content: expressions, content: expressions,
} => { } => {
let content = if let Some(expressions) = expressions { let content = if let Some(expression) = expressions {
let mut values = Vec::with_capacity(expressions.len()); let position = expression.position();
let evaluation = expression.evaluate(context, manage_memory, scope)?;
for expression in expressions { if let Some(Evaluation::Return(value)) = evaluation {
let position = expression.position(); Some(value)
let evaluation = expression.evaluate(context, manage_memory, scope)?; } else {
return Err(RuntimeError::ValidationFailure(
if let Some(Evaluation::Return(value)) = evaluation { ValidationError::ExpectedValueStatement(position),
values.push(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 { } else {
None 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::Float(float) => Value::float(float),
ValueNode::Integer(integer) => Value::integer(integer), ValueNode::Integer(integer) => Value::integer(integer),
@ -577,11 +586,13 @@ impl Ord for ValueNode {
( (
EnumInstance { EnumInstance {
type_name: left_name, type_name: left_name,
type_arguments: left_type_args,
variant: left_variant, variant: left_variant,
content: left_content, content: left_content,
}, },
EnumInstance { EnumInstance {
type_name: right_name, type_name: right_name,
type_arguments: right_type_args,
variant: right_variant, variant: right_variant,
content: right_content, content: right_content,
}, },
@ -589,12 +600,18 @@ impl Ord for ValueNode {
let name_cmp = left_name.cmp(right_name); let name_cmp = left_name.cmp(right_name);
if name_cmp.is_eq() { 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() { if type_arg_cmp.is_eq() {
left_content.cmp(right_content) let variant_cmp = left_variant.cmp(right_variant);
if variant_cmp.is_eq() {
left_content.cmp(right_content)
} else {
variant_cmp
}
} else { } else {
variant_cmp type_arg_cmp
} }
} else { } else {
name_cmp name_cmp
@ -670,15 +687,14 @@ impl Display for ValueNode {
ValueNode::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"), ValueNode::BuiltInFunction(built_in_function) => write!(f, "{built_in_function}"),
ValueNode::EnumInstance { ValueNode::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content, content,
} => { } => {
write!(f, "{}::{}", type_name.node, variant.node)?; write!(f, "{}::{}", type_name.node, variant.node)?;
if let Some(content) = content { if let Some(expression) = content {
for expression in content { write!(f, "{expression}")?;
write!(f, "{expression}")?;
}
} }
Ok(()) Ok(())

View File

@ -267,6 +267,18 @@ pub fn parser<'src>(
type ValueParameters = Vec<(Identifier, TypeConstructor)>; type ValueParameters = Vec<(Identifier, TypeConstructor)>;
type FunctionParameters = (Option<TypeParameters>, ValueParameters); 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)) let function = just(Token::Keyword(Keyword::Fn))
.ignore_then( .ignore_then(
identifier identifier
@ -323,25 +335,17 @@ pub fn parser<'src>(
); );
let enum_instance = positioned_identifier let enum_instance = positioned_identifier
.then(turbofish.clone().or_not())
.then_ignore(just(Token::Symbol(Symbol::DoubleColon))) .then_ignore(just(Token::Symbol(Symbol::DoubleColon)))
.then(positioned_identifier) .then(positioned_identifier)
.then( .then(expression.clone().or_not())
expression .map_with(|(((type_name, type_arguments), variant), content), state| {
.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| {
Expression::Value( Expression::Value(
ValueNode::EnumInstance { ValueNode::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content, content: content.map(|expression| Box::new(expression)),
} }
.with_position(state.span()), .with_position(state.span()),
) )
@ -403,18 +407,6 @@ pub fn parser<'src>(
expression 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(( let atom = choice((
built_in_function, built_in_function,
enum_instance.clone(), enum_instance.clone(),

View File

@ -49,10 +49,11 @@ fn type_invokation() {
Statement::Expression(Expression::Value( Statement::Expression(Expression::Value(
ValueNode::EnumInstance { ValueNode::EnumInstance {
type_name: Identifier::new("Foo").with_position((14, 17)), type_name: Identifier::new("Foo").with_position((14, 17)),
type_arguments: None,
variant: Identifier::new("Bar").with_position((19, 22)), 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)) ValueNode::Integer(42).with_position((23, 25))
)]) )))
} }
.with_position((14, 26)) .with_position((14, 26))
)) ))
@ -69,10 +70,11 @@ fn enum_instance() {
Statement::Expression(Expression::Value( Statement::Expression(Expression::Value(
ValueNode::EnumInstance { ValueNode::EnumInstance {
type_name: Identifier::new("Foo").with_position((0, 3)), type_name: Identifier::new("Foo").with_position((0, 3)),
type_arguments: None,
variant: Identifier::new("Bar").with_position((5, 8)), 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)) ValueNode::Integer(42).with_position((9, 11))
)]) )))
} }
.with_position((0, 12)) .with_position((0, 12))
)) ))

View File

@ -41,11 +41,13 @@ impl Value {
pub fn enum_instance( pub fn enum_instance(
type_name: Identifier, type_name: Identifier,
type_arguments: Option<Vec<Type>>,
variant: Identifier, variant: Identifier,
content: Option<Vec<Value>>, content: Option<Value>,
) -> Self { ) -> Self {
Value(Arc::new(ValueInner::EnumInstance { Value(Arc::new(ValueInner::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content, content,
})) }))
@ -128,20 +130,29 @@ impl Display for Value {
ValueInner::Boolean(boolean) => write!(f, "{boolean}"), ValueInner::Boolean(boolean) => write!(f, "{boolean}"),
ValueInner::EnumInstance { ValueInner::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content, content,
} => { } => {
if let Some(values) = content { write!(f, "{type_name}::")?;
write!(f, "{type_name}::{variant}(")?;
for value in values { if let Some(types) = type_arguments {
write!(f, "{value}")?; write!(f, "::<")?;
for r#type in types {
write!(f, "{type}, ")?;
} }
write!(f, ")") write!(f, ">")?;
} else {
write!(f, "{type_name}::{variant}")
} }
write!(f, "::{variant}(")?;
if let Some(value) = content {
write!(f, "{value}")?;
}
write!(f, ")")
} }
ValueInner::Float(float) => { ValueInner::Float(float) => {
write!(f, "{float}")?; write!(f, "{float}")?;
@ -257,12 +268,14 @@ impl Serialize for Value {
ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean), ValueInner::Boolean(boolean) => serializer.serialize_bool(*boolean),
ValueInner::EnumInstance { ValueInner::EnumInstance {
type_name, type_name,
type_arguments,
variant, variant,
content, content,
} => { } => {
let mut struct_ser = serializer.serialize_struct("EnumInstance", 3)?; let mut struct_ser = serializer.serialize_struct("EnumInstance", 3)?;
struct_ser.serialize_field("type_name", type_name)?; 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("variant", variant)?;
struct_ser.serialize_field("content", content)?; struct_ser.serialize_field("content", content)?;
@ -574,8 +587,9 @@ pub enum ValueInner {
BuiltInFunction(BuiltInFunction), BuiltInFunction(BuiltInFunction),
EnumInstance { EnumInstance {
type_name: Identifier, type_name: Identifier,
type_arguments: Option<Vec<Type>>,
variant: Identifier, variant: Identifier,
content: Option<Vec<Value>>, content: Option<Value>,
}, },
Float(f64), Float(f64),
Function(Function), Function(Function),
@ -691,11 +705,13 @@ impl Ord for ValueInner {
( (
EnumInstance { EnumInstance {
type_name: left_name, type_name: left_name,
type_arguments: left_arguments,
variant: left_variant, variant: left_variant,
content: left_content, content: left_content,
}, },
EnumInstance { EnumInstance {
type_name: right_name, type_name: right_name,
type_arguments: right_arguments,
variant: right_variant, variant: right_variant,
content: right_content, content: right_content,
}, },
@ -703,12 +719,18 @@ impl Ord for ValueInner {
let name_cmp = left_name.cmp(right_name); let name_cmp = left_name.cmp(right_name);
if name_cmp.is_eq() { 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() { if argument_cmp.is_eq() {
left_content.cmp(right_content) let variant_cmp = left_variant.cmp(right_variant);
if variant_cmp.is_eq() {
left_content.cmp(right_content)
} else {
variant_cmp
}
} else { } else {
variant_cmp argument_cmp
} }
} else { } else {
name_cmp name_cmp

View File

@ -16,6 +16,7 @@ fn simple_enum() {
), ),
Ok(Some(Value::enum_instance( Ok(Some(Value::enum_instance(
Identifier::new("FooBar"), Identifier::new("FooBar"),
None,
Identifier::new("Foo"), Identifier::new("Foo"),
None None
))) )))
@ -34,13 +35,14 @@ fn big_enum() {
Baz(V), Baz(V),
} }
FooBarBaz::Baz(42.0) FooBarBaz::<int, str, float>::Baz(42.0)
" "
), ),
Ok(Some(Value::enum_instance( Ok(Some(Value::enum_instance(
Identifier::new("FooBarBaz"), Identifier::new("FooBarBaz"),
None,
Identifier::new("Baz"), Identifier::new("Baz"),
Some(vec![Value::float(42.0)]), Some(Value::float(42.0)),
))) )))
); );
} }