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,
|
statement::Statement,
|
||||||
structure_definition::StructureDefinition,
|
structure_definition::StructureDefinition,
|
||||||
type_alias::TypeAssignment,
|
type_alias::TypeAssignment,
|
||||||
type_constructor::{FunctionTypeConstructor, ListTypeConstructor, TypeConstructor},
|
type_constructor::{
|
||||||
|
EnumTypeConstructor, FunctionTypeConstructor, ListTypeConstructor, TypeConstructor,
|
||||||
|
},
|
||||||
value_node::ValueNode,
|
value_node::ValueNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ use super::{Evaluate, Evaluation};
|
|||||||
pub enum Type {
|
pub enum Type {
|
||||||
Any,
|
Any,
|
||||||
Boolean,
|
Boolean,
|
||||||
|
Enum {
|
||||||
|
variants: Vec<(Identifier, Vec<Type>)>,
|
||||||
|
},
|
||||||
Float,
|
Float,
|
||||||
Function {
|
Function {
|
||||||
type_parameters: Option<Vec<Identifier>>,
|
type_parameters: Option<Vec<Identifier>>,
|
||||||
@ -226,6 +229,21 @@ impl Display for Type {
|
|||||||
match self {
|
match self {
|
||||||
Type::Any => write!(f, "any"),
|
Type::Any => write!(f, "any"),
|
||||||
Type::Boolean => write!(f, "bool"),
|
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::Float => write!(f, "float"),
|
||||||
Type::Generic { concrete_type, .. } => {
|
Type::Generic { concrete_type, .. } => {
|
||||||
if let Some(r#type) = 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)]
|
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||||
pub enum TypeConstructor {
|
pub enum TypeConstructor {
|
||||||
|
Enum(WithPosition<EnumTypeConstructor>),
|
||||||
Function(WithPosition<FunctionTypeConstructor>),
|
Function(WithPosition<FunctionTypeConstructor>),
|
||||||
Identifier(WithPosition<Identifier>),
|
Identifier(WithPosition<Identifier>),
|
||||||
List(WithPosition<ListTypeConstructor>),
|
List(WithPosition<ListTypeConstructor>),
|
||||||
@ -15,22 +16,10 @@ pub enum TypeConstructor {
|
|||||||
Type(WithPosition<Type>),
|
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 {
|
impl TypeConstructor {
|
||||||
pub fn position(&self) -> SourcePosition {
|
pub fn position(&self) -> SourcePosition {
|
||||||
match self {
|
match self {
|
||||||
|
TypeConstructor::Enum(WithPosition { position, .. }) => *position,
|
||||||
TypeConstructor::Function(WithPosition { position, .. }) => *position,
|
TypeConstructor::Function(WithPosition { position, .. }) => *position,
|
||||||
TypeConstructor::Identifier(WithPosition { position, .. }) => *position,
|
TypeConstructor::Identifier(WithPosition { position, .. }) => *position,
|
||||||
TypeConstructor::List(WithPosition { position, .. }) => *position,
|
TypeConstructor::List(WithPosition { position, .. }) => *position,
|
||||||
@ -41,6 +30,28 @@ impl TypeConstructor {
|
|||||||
|
|
||||||
pub fn construct(self, context: &Context) -> Result<Type, ValidationError> {
|
pub fn construct(self, context: &Context) -> Result<Type, ValidationError> {
|
||||||
let r#type = match self {
|
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) => {
|
TypeConstructor::Function(function_type_constructor) => {
|
||||||
let FunctionTypeConstructor {
|
let FunctionTypeConstructor {
|
||||||
type_parameters: declared_type_parameters,
|
type_parameters: declared_type_parameters,
|
||||||
@ -111,3 +122,22 @@ impl Display for TypeConstructor {
|
|||||||
todo!()
|
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,
|
Bool,
|
||||||
Break,
|
Break,
|
||||||
Else,
|
Else,
|
||||||
|
Enum,
|
||||||
Float,
|
Float,
|
||||||
Fn,
|
Fn,
|
||||||
Int,
|
Int,
|
||||||
@ -74,6 +75,7 @@ impl Display for Keyword {
|
|||||||
Keyword::Bool => write!(f, "bool"),
|
Keyword::Bool => write!(f, "bool"),
|
||||||
Keyword::Break => write!(f, "break"),
|
Keyword::Break => write!(f, "break"),
|
||||||
Keyword::Else => write!(f, "else"),
|
Keyword::Else => write!(f, "else"),
|
||||||
|
Keyword::Enum => write!(f, "enum"),
|
||||||
Keyword::Float => write!(f, "float"),
|
Keyword::Float => write!(f, "float"),
|
||||||
Keyword::Fn => write!(f, "fn"),
|
Keyword::Fn => write!(f, "fn"),
|
||||||
Keyword::Int => write!(f, "int"),
|
Keyword::Int => write!(f, "int"),
|
||||||
@ -268,6 +270,7 @@ pub fn lexer<'src>() -> impl Parser<
|
|||||||
"as" => Token::Keyword(Keyword::As),
|
"as" => Token::Keyword(Keyword::As),
|
||||||
"bool" => Token::Keyword(Keyword::Bool),
|
"bool" => Token::Keyword(Keyword::Bool),
|
||||||
"break" => Token::Keyword(Keyword::Break),
|
"break" => Token::Keyword(Keyword::Break),
|
||||||
|
"enum" => Token::Keyword(Keyword::Enum),
|
||||||
"else" => Token::Keyword(Keyword::Else),
|
"else" => Token::Keyword(Keyword::Else),
|
||||||
"float" => Token::Keyword(Keyword::Float),
|
"float" => Token::Keyword(Keyword::Float),
|
||||||
"fn" => Token::Keyword(Keyword::Fn),
|
"fn" => Token::Keyword(Keyword::Fn),
|
||||||
|
@ -151,12 +151,58 @@ pub fn parser<'src>(
|
|||||||
.clone()
|
.clone()
|
||||||
.map(|identifier| TypeConstructor::Identifier(identifier));
|
.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((
|
choice((
|
||||||
function_type,
|
function_type,
|
||||||
list_type,
|
list_type,
|
||||||
list_of_type,
|
list_of_type,
|
||||||
primitive_type,
|
primitive_type,
|
||||||
identifier_type,
|
identifier_type,
|
||||||
|
enum_type,
|
||||||
))
|
))
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -651,6 +697,101 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
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
|
// Reuse these tests when structures are reimplemented
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn structure_instance() {
|
// 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