Add enum parsing; Add assets for examples
This commit is contained in:
parent
51dd918789
commit
c2d8bd299f
@ -43,7 +43,9 @@ pub use self::{
|
||||
statement::Statement,
|
||||
structure_definition::StructureDefinition,
|
||||
type_alias::TypeAssignment,
|
||||
type_constructor::{FunctionTypeConstructor, ListTypeConstructor, TypeConstructor},
|
||||
type_constructor::{
|
||||
EnumTypeConstructor, FunctionTypeConstructor, ListTypeConstructor, TypeConstructor,
|
||||
},
|
||||
value_node::ValueNode,
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,9 @@ use super::{Evaluate, Evaluation};
|
||||
pub enum Type {
|
||||
Any,
|
||||
Boolean,
|
||||
Enum {
|
||||
variants: Vec<(Identifier, Vec<Type>)>,
|
||||
},
|
||||
Float,
|
||||
Function {
|
||||
type_parameters: Option<Vec<Identifier>>,
|
||||
@ -226,6 +229,21 @@ impl Display for Type {
|
||||
match self {
|
||||
Type::Any => write!(f, "any"),
|
||||
Type::Boolean => write!(f, "bool"),
|
||||
Type::Enum { variants } => {
|
||||
write!(f, "enum {{")?;
|
||||
|
||||
for (identifier, types) in variants {
|
||||
writeln!(f, "{identifier}(")?;
|
||||
|
||||
for r#type in types {
|
||||
write!(f, "{}", r#type)?
|
||||
}
|
||||
|
||||
write!(f, ")")?;
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
Type::Float => write!(f, "float"),
|
||||
Type::Generic { concrete_type, .. } => {
|
||||
if let Some(r#type) = concrete_type {
|
||||
|
@ -8,6 +8,7 @@ use super::{SourcePosition, Type, WithPosition};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub enum TypeConstructor {
|
||||
Enum(WithPosition<EnumTypeConstructor>),
|
||||
Function(WithPosition<FunctionTypeConstructor>),
|
||||
Identifier(WithPosition<Identifier>),
|
||||
List(WithPosition<ListTypeConstructor>),
|
||||
@ -15,22 +16,10 @@ pub enum TypeConstructor {
|
||||
Type(WithPosition<Type>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct FunctionTypeConstructor {
|
||||
pub type_parameters: Option<Vec<WithPosition<Identifier>>>,
|
||||
pub value_parameters: Vec<TypeConstructor>,
|
||||
pub return_type: Box<TypeConstructor>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct ListTypeConstructor {
|
||||
pub length: usize,
|
||||
pub item_type: Box<TypeConstructor>,
|
||||
}
|
||||
|
||||
impl TypeConstructor {
|
||||
pub fn position(&self) -> SourcePosition {
|
||||
match self {
|
||||
TypeConstructor::Enum(WithPosition { position, .. }) => *position,
|
||||
TypeConstructor::Function(WithPosition { position, .. }) => *position,
|
||||
TypeConstructor::Identifier(WithPosition { position, .. }) => *position,
|
||||
TypeConstructor::List(WithPosition { position, .. }) => *position,
|
||||
@ -41,6 +30,28 @@ impl TypeConstructor {
|
||||
|
||||
pub fn construct(self, context: &Context) -> Result<Type, ValidationError> {
|
||||
let r#type = match self {
|
||||
TypeConstructor::Enum(enum_type_constructor) => {
|
||||
let EnumTypeConstructor { variants, .. } = enum_type_constructor.node;
|
||||
let mut type_variants = Vec::with_capacity(variants.len());
|
||||
|
||||
for (variant_name, constructors) in variants {
|
||||
if let Some(constructors) = constructors {
|
||||
let mut types = Vec::with_capacity(constructors.len());
|
||||
|
||||
for constructor in constructors {
|
||||
let r#type = constructor.construct(context)?;
|
||||
|
||||
types.push(r#type);
|
||||
}
|
||||
|
||||
type_variants.push((variant_name.node, types));
|
||||
}
|
||||
}
|
||||
|
||||
Type::Enum {
|
||||
variants: type_variants,
|
||||
}
|
||||
}
|
||||
TypeConstructor::Function(function_type_constructor) => {
|
||||
let FunctionTypeConstructor {
|
||||
type_parameters: declared_type_parameters,
|
||||
@ -111,3 +122,22 @@ impl Display for TypeConstructor {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct EnumTypeConstructor {
|
||||
pub type_parameters: Option<Vec<WithPosition<Identifier>>>,
|
||||
pub variants: Vec<(WithPosition<Identifier>, Option<Vec<TypeConstructor>>)>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct FunctionTypeConstructor {
|
||||
pub type_parameters: Option<Vec<WithPosition<Identifier>>>,
|
||||
pub value_parameters: Vec<TypeConstructor>,
|
||||
pub return_type: Box<TypeConstructor>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct ListTypeConstructor {
|
||||
pub length: usize,
|
||||
pub item_type: Box<TypeConstructor>,
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ pub enum Keyword {
|
||||
Bool,
|
||||
Break,
|
||||
Else,
|
||||
Enum,
|
||||
Float,
|
||||
Fn,
|
||||
Int,
|
||||
@ -74,6 +75,7 @@ impl Display for Keyword {
|
||||
Keyword::Bool => write!(f, "bool"),
|
||||
Keyword::Break => write!(f, "break"),
|
||||
Keyword::Else => write!(f, "else"),
|
||||
Keyword::Enum => write!(f, "enum"),
|
||||
Keyword::Float => write!(f, "float"),
|
||||
Keyword::Fn => write!(f, "fn"),
|
||||
Keyword::Int => write!(f, "int"),
|
||||
@ -268,6 +270,7 @@ pub fn lexer<'src>() -> impl Parser<
|
||||
"as" => Token::Keyword(Keyword::As),
|
||||
"bool" => Token::Keyword(Keyword::Bool),
|
||||
"break" => Token::Keyword(Keyword::Break),
|
||||
"enum" => Token::Keyword(Keyword::Enum),
|
||||
"else" => Token::Keyword(Keyword::Else),
|
||||
"float" => Token::Keyword(Keyword::Float),
|
||||
"fn" => Token::Keyword(Keyword::Fn),
|
||||
|
@ -151,12 +151,58 @@ pub fn parser<'src>(
|
||||
.clone()
|
||||
.map(|identifier| TypeConstructor::Identifier(identifier));
|
||||
|
||||
let enum_variant = positioned_identifier.clone().then(
|
||||
type_constructor
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::ParenOpen)),
|
||||
just(Token::Control(Control::ParenClose)),
|
||||
)
|
||||
.or_not(),
|
||||
);
|
||||
|
||||
let enum_type = just(Token::Keyword(Keyword::Enum))
|
||||
.ignore_then(
|
||||
positioned_identifier
|
||||
.clone()
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::Pipe)),
|
||||
just(Token::Control(Control::Pipe)),
|
||||
)
|
||||
.or_not(),
|
||||
)
|
||||
.then(
|
||||
enum_variant
|
||||
.separated_by(just(Token::Control(Control::Comma)))
|
||||
.at_least(1)
|
||||
.allow_trailing()
|
||||
.collect()
|
||||
.delimited_by(
|
||||
just(Token::Control(Control::CurlyOpen)),
|
||||
just(Token::Control(Control::CurlyClose)),
|
||||
),
|
||||
)
|
||||
.map_with(|(type_parameters, variants), state| {
|
||||
TypeConstructor::Enum(
|
||||
EnumTypeConstructor {
|
||||
type_parameters,
|
||||
variants,
|
||||
}
|
||||
.with_position(state.span()),
|
||||
)
|
||||
});
|
||||
|
||||
choice((
|
||||
function_type,
|
||||
list_type,
|
||||
list_of_type,
|
||||
primitive_type,
|
||||
identifier_type,
|
||||
enum_type,
|
||||
))
|
||||
});
|
||||
|
||||
@ -651,6 +697,101 @@ mod tests {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn enum_type_empty() {
|
||||
assert_eq!(
|
||||
parse(&lex("type MyEnum = enum { X, Y }").unwrap()).unwrap()[0],
|
||||
Statement::TypeAssignment(
|
||||
TypeAssignment::new(
|
||||
Identifier::new("MyEnum").with_position((5, 11)),
|
||||
TypeConstructor::Enum(
|
||||
EnumTypeConstructor {
|
||||
type_parameters: None,
|
||||
variants: vec![
|
||||
(Identifier::new("X").with_position((21, 22)), None),
|
||||
(Identifier::new("Y").with_position((24, 25)), None)
|
||||
],
|
||||
}
|
||||
.with_position((14, 27))
|
||||
)
|
||||
)
|
||||
.with_position((0, 27))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_type_with_contents() {
|
||||
assert_eq!(
|
||||
parse(&lex("type MyEnum = enum { X(str, int), Y(int) }").unwrap()).unwrap()[0],
|
||||
Statement::TypeAssignment(
|
||||
TypeAssignment::new(
|
||||
Identifier::new("MyEnum").with_position((5, 11)),
|
||||
TypeConstructor::Enum(
|
||||
EnumTypeConstructor {
|
||||
type_parameters: None,
|
||||
variants: vec![
|
||||
(
|
||||
Identifier::new("X").with_position((21, 22)),
|
||||
Some(vec![
|
||||
TypeConstructor::Type(Type::String.with_position((23, 26))),
|
||||
TypeConstructor::Type(
|
||||
Type::Integer.with_position((28, 31))
|
||||
)
|
||||
])
|
||||
),
|
||||
(
|
||||
Identifier::new("Y").with_position((34, 35)),
|
||||
Some(vec![TypeConstructor::Type(
|
||||
Type::Integer.with_position((36, 39))
|
||||
)])
|
||||
)
|
||||
],
|
||||
}
|
||||
.with_position((14, 42))
|
||||
)
|
||||
)
|
||||
.with_position((0, 42))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_type_with_type_parameters() {
|
||||
assert_eq!(
|
||||
parse(&lex("type MyEnum = enum |T, U| { X(T), Y(U) }").unwrap()).unwrap()[0],
|
||||
Statement::TypeAssignment(
|
||||
TypeAssignment::new(
|
||||
Identifier::new("MyEnum").with_position((5, 11)),
|
||||
TypeConstructor::Enum(
|
||||
EnumTypeConstructor {
|
||||
type_parameters: Some(vec![
|
||||
Identifier::new("T").with_position((20, 21)),
|
||||
Identifier::new("U").with_position((23, 24)),
|
||||
]),
|
||||
variants: vec![
|
||||
(
|
||||
Identifier::new("X").with_position((28, 29)),
|
||||
Some(vec![TypeConstructor::Identifier(
|
||||
Identifier::new("T").with_position((30, 31))
|
||||
)])
|
||||
),
|
||||
(
|
||||
Identifier::new("Y").with_position((34, 35)),
|
||||
Some(vec![TypeConstructor::Identifier(
|
||||
Identifier::new("U").with_position((36, 37))
|
||||
)])
|
||||
),
|
||||
],
|
||||
}
|
||||
.with_position((14, 40))
|
||||
)
|
||||
)
|
||||
.with_position((0, 40))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Reuse these tests when structures are reimplemented
|
||||
// #[test]
|
||||
// fn structure_instance() {
|
||||
|
7883
examples/assets/jq_data.json
Normal file
7883
examples/assets/jq_data.json
Normal file
File diff suppressed because it is too large
Load Diff
6
examples/assets/seaCreatures.json
Normal file
6
examples/assets/seaCreatures.json
Normal file
@ -0,0 +1,6 @@
|
||||
[
|
||||
{ "name": "Sammy", "type": "shark", "clams": 5 },
|
||||
{ "name": "Bubbles", "type": "orca", "clams": 3 },
|
||||
{ "name": "Splish", "type": "dolphin", "clams": 2 },
|
||||
{ "name": "Splash", "type": "dolphin", "clams": 2 }
|
||||
]
|
Loading…
Reference in New Issue
Block a user