Add type arguments to enum instances
This commit is contained in:
parent
ad409b69f3
commit
790438d1e3
@ -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(())
|
||||||
|
@ -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(),
|
||||||
|
@ -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))
|
||||||
))
|
))
|
||||||
|
@ -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
|
||||||
|
@ -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)),
|
||||||
)))
|
)))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user