Implement enums
This commit is contained in:
parent
9f98617f6a
commit
087d926c3d
@ -43,13 +43,13 @@ impl AbstractTree for EnumDefinition {
|
|||||||
Ok(Type::None)
|
Ok(Type::None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self, _context: &Context) -> Result<(), ValidationError> {
|
fn validate(&self, context: &Context) -> Result<(), ValidationError> {
|
||||||
|
context.set_enum_definition(self.name.clone(), self.clone())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run(self, context: &Context) -> Result<Action, RuntimeError> {
|
fn run(self, _context: &Context) -> Result<Action, RuntimeError> {
|
||||||
context.set_enum_definition(self.name.clone(), self)?;
|
|
||||||
|
|
||||||
Ok(Action::None)
|
Ok(Action::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use crate::{
|
|||||||
error::{RuntimeError, TypeConflict, ValidationError},
|
error::{RuntimeError, TypeConflict, ValidationError},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{AbstractTree, Action};
|
use super::{AbstractTree, Action, WithPosition};
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||||
pub enum Type {
|
pub enum Type {
|
||||||
@ -16,7 +16,7 @@ pub enum Type {
|
|||||||
Enum {
|
Enum {
|
||||||
name: Identifier,
|
name: Identifier,
|
||||||
type_arguments: Option<Vec<Type>>,
|
type_arguments: Option<Vec<Type>>,
|
||||||
variants: Vec<(Identifier, Option<Type>)>,
|
variants: Vec<(Identifier, Option<WithPosition<Type>>)>,
|
||||||
},
|
},
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
|
@ -42,12 +42,7 @@ impl AbstractTree for ValueNode {
|
|||||||
let r#type = match self {
|
let r#type = match self {
|
||||||
ValueNode::Boolean(_) => Type::Boolean,
|
ValueNode::Boolean(_) => Type::Boolean,
|
||||||
|
|
||||||
ValueNode::EnumInstance {
|
ValueNode::EnumInstance { name, .. } => {
|
||||||
name,
|
|
||||||
variant: _,
|
|
||||||
type_arguments,
|
|
||||||
expression: _,
|
|
||||||
} => {
|
|
||||||
if let Some(r#type) = context.get_type(name)? {
|
if let Some(r#type) = context.get_type(name)? {
|
||||||
r#type
|
r#type
|
||||||
} else {
|
} else {
|
||||||
@ -130,13 +125,34 @@ impl AbstractTree for ValueNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let ValueNode::EnumInstance {
|
if let ValueNode::EnumInstance {
|
||||||
name,
|
|
||||||
variant,
|
|
||||||
type_arguments,
|
|
||||||
expression,
|
expression,
|
||||||
|
variant,
|
||||||
|
..
|
||||||
} = self
|
} = self
|
||||||
{
|
{
|
||||||
let r#type = self.expected_type(context)?;
|
let r#type = self.expected_type(context)?;
|
||||||
|
|
||||||
|
if let Type::Enum { variants, .. } = r#type {
|
||||||
|
let expected_type_option = variants.iter().find_map(|(identifier, type_option)| {
|
||||||
|
if identifier == variant {
|
||||||
|
type_option.clone()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(expected_type) = expected_type_option {
|
||||||
|
let actual_type = expression.node.expected_type(context)?;
|
||||||
|
|
||||||
|
expected_type.node.check(&actual_type).map_err(|conflict| {
|
||||||
|
ValidationError::TypeCheck {
|
||||||
|
conflict,
|
||||||
|
actual_position: expression.position,
|
||||||
|
expected_position: expected_type.position,
|
||||||
|
}
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -88,26 +88,16 @@ impl Context {
|
|||||||
.map(|identifier| Type::Parameter(identifier.clone()))
|
.map(|identifier| Type::Parameter(identifier.clone()))
|
||||||
.collect()
|
.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 {
|
Type::Enum {
|
||||||
name: enum_definition.name().clone(),
|
name: enum_definition.name().clone(),
|
||||||
type_arguments,
|
type_arguments,
|
||||||
variants,
|
variants: enum_definition.variants().clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return Ok(Some(r#type.clone()));
|
return Ok(Some(r#type));
|
||||||
}
|
}
|
||||||
|
|
||||||
for module in BUILT_IN_MODULES {
|
for module in BUILT_IN_MODULES {
|
||||||
|
@ -522,7 +522,7 @@ mod tests {
|
|||||||
parse(
|
parse(
|
||||||
&lex("
|
&lex("
|
||||||
enum FooBar {
|
enum FooBar {
|
||||||
Foo,
|
Foo(int),
|
||||||
Bar,
|
Bar,
|
||||||
}
|
}
|
||||||
")
|
")
|
||||||
@ -534,7 +534,10 @@ mod tests {
|
|||||||
Identifier::new("FooBar"),
|
Identifier::new("FooBar"),
|
||||||
None,
|
None,
|
||||||
vec![
|
vec![
|
||||||
(Identifier::new("Foo"), None),
|
(
|
||||||
|
Identifier::new("Foo"),
|
||||||
|
Some(Type::Integer.with_position((55, 58)))
|
||||||
|
),
|
||||||
(Identifier::new("Bar"), None)
|
(Identifier::new("Bar"), None)
|
||||||
]
|
]
|
||||||
))
|
))
|
||||||
|
@ -24,10 +24,10 @@ fn simple_enum_type_check() {
|
|||||||
actual: Type::String,
|
actual: Type::String,
|
||||||
expected: Type::Integer,
|
expected: Type::Integer,
|
||||||
},
|
},
|
||||||
actual_position: (0, 0).into(),
|
actual_position: (123, 127).into(),
|
||||||
expected_position: (0, 0).into()
|
expected_position: (47, 50).into()
|
||||||
},
|
},
|
||||||
position: (0, 0).into()
|
position: (105, 141).into()
|
||||||
}])
|
}])
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user