1
0

Add enum parsing; Add assets for examples

This commit is contained in:
Jeff 2024-06-19 09:48:01 -04:00
parent 51dd918789
commit c2d8bd299f
7 changed files with 8097 additions and 14 deletions

View File

@ -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,
};

View File

@ -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 {

View File

@ -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>,
}

View File

@ -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),

View File

@ -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

File diff suppressed because it is too large Load Diff

View 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 }
]