From 49f4d11987ff11c45aaf1f2ccdf63518ae0c5d29 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Fri, 8 Apr 2022 15:39:16 +1000 Subject: [PATCH 01/20] Read sugar for product types Change-Id: I2e5072e202a054f6bb92058ebd05620e0a2d0ae4 --- ibis/src/type_parser.rs | 74 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 4 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index a76daaab1..d0d2d64ce 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -7,9 +7,9 @@ extern crate nom; use nom::{ bytes::complete::{tag, take_while}, - character::complete::space0, + character::complete::{space0, space1}, combinator::opt, - multi::separated_list0, + multi::{separated_list0, separated_list1}, sequence::tuple, Finish, IResult, }; @@ -17,7 +17,11 @@ use nom::{ use crate::type_struct::Type; fn is_name_char(c: char) -> bool { - c != '(' && c != ')' && c != ',' && c != ':' + match c { + '(' | ')' | ',' | ':' => false, // Symbols + ' ' | '\n' | '\r' | '\t' => false, // Whitespace + _ => true // Name char + } } fn name(input: &str) -> IResult<&str, &str> { @@ -35,7 +39,7 @@ fn type_args(input: &str) -> IResult<&str, Vec> { Ok((input, args)) } -fn type_structure(input: &str) -> IResult<&str, Type> { +fn simple_type_structure(input: &str) -> IResult<&str, Type> { let (input, (mut name, args)) = tuple((name, opt(type_args)))(input)?; if name == "*" { name = "ibis.UniversalType"; @@ -43,6 +47,19 @@ fn type_structure(input: &str) -> IResult<&str, Type> { Ok((input, Type::new(name, args.unwrap_or_default()))) } +fn type_structure(input: &str) -> IResult<&str, Type> { + let (input, mut types) = separated_list1(space1, simple_type_structure)(input)?; + let mut ty = None; + for new_ty in types.drain(0..).rev() { + ty = Some(if let Some(ty) = ty { + Type::new("ibis.ProductType", vec![new_ty, ty]) + } else { + new_ty + }); + } + Ok((input, ty.expect("Should have a type"))) +} + fn type_parser(input: &str) -> IResult<&str, Type> { let (input, (label, mut structure)) = tuple((opt(label), type_structure))(input)?; if let Some(label) = label { @@ -79,6 +96,55 @@ mod tests { ); } + #[test] + fn read_a_type_with_a_single_capabilities() { + assert_eq!( + read_type("read Type"), + Type { + name: "ibis.ProductType", + args: vec![ + Type { + name: "read", + args: vec![] + }, + Type { + name: "Type", + args: vec![] + } + ] + } + ); + } + + #[test] + fn read_a_type_with_multiple_capabilities() { + assert_eq!( + read_type("read write Type"), + Type { + name: "ibis.ProductType", + args: vec![ + Type { + name: "read", + args: vec![] + }, + Type { + name: "ibis.ProductType", + args: vec![ + Type { + name: "write", + args: vec![] + }, + Type { + name: "Type", + args: vec![] + } + ] + } + ] + } + ); + } + #[test] fn read_a_type_with_arguments() { assert_eq!( From 2430639aebf8069fbdcfd4722ce8431e5b8cb51a Mon Sep 17 00:00:00 2001 From: J Pratt Date: Fri, 8 Apr 2022 16:09:12 +1000 Subject: [PATCH 02/20] Move labels into type structures to avoid ambiguous structures Change-Id: I1276c086531634e09fd8b3ca39d4e9c7753bd8d6 --- ibis/src/type_parser.rs | 36 ++++++++++++++++++++++++++---------- ibis/src/type_struct.rs | 5 ++--- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index d0d2d64ce..62cc816d5 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -47,8 +47,16 @@ fn simple_type_structure(input: &str) -> IResult<&str, Type> { Ok((input, Type::new(name, args.unwrap_or_default()))) } -fn type_structure(input: &str) -> IResult<&str, Type> { - let (input, mut types) = separated_list1(space1, simple_type_structure)(input)?; +fn labelled_simple_type_structure(input: &str) -> IResult<&str, Type> { + let (input, (label, mut structure)) = tuple((opt(label), simple_type_structure))(input)?; + if let Some(label) = label { + structure = Type::new("ibis.Labelled", vec![Type::named(label), structure]); + } + Ok((input, structure)) +} + +fn type_parser(input: &str) -> IResult<&str, Type> { + let (input, mut types) = separated_list1(space1, labelled_simple_type_structure)(input)?; let mut ty = None; for new_ty in types.drain(0..).rev() { ty = Some(if let Some(ty) = ty { @@ -60,14 +68,6 @@ fn type_structure(input: &str) -> IResult<&str, Type> { Ok((input, ty.expect("Should have a type"))) } -fn type_parser(input: &str) -> IResult<&str, Type> { - let (input, (label, mut structure)) = tuple((opt(label), type_structure))(input)?; - if let Some(label) = label { - structure = Type::new("ibis.Labelled", vec![Type::named(label), structure]); - } - Ok((input, structure)) -} - pub fn read_type(input: &str) -> Type { // TODO: return errors instead of panics let (input, ty) = type_parser(input).finish().expect("Could not parse type"); @@ -145,6 +145,22 @@ mod tests { ); } + #[test] + fn read_a_product_type_using_syntactic_sugar() { + let name_string = read_type("name: String"); + let age_number = read_type("age: Number"); + assert_eq!( + read_type("name: String age: Number"), + Type { + name: "ibis.ProductType", + args: vec![ + name_string, + age_number + ] + } + ); + } + #[test] fn read_a_type_with_arguments() { assert_eq!( diff --git a/ibis/src/type_struct.rs b/ibis/src/type_struct.rs index 30c0890b7..9e4eb10f7 100644 --- a/ibis/src/type_struct.rs +++ b/ibis/src/type_struct.rs @@ -42,9 +42,8 @@ impl<'a> std::fmt::Display for Type<'a> { if self.name == "ibis.Labelled" && self.args.len() > 1 { write!(f, "{}: ", self.args[0])?; format_arg_set(f, ", ", &self.args[1..]) - // } else if self.name == "ibis.ProductType" && self.args.len() > 1 { - // write!(f, "{}: ", self.args[0])?; - // format_arg_set(f, " & ", &self.args[1..]) + } else if self.name == "ibis.ProductType" && self.args.len() > 0 { + format_arg_set(f, " ", &self.args) } else { let res = write!( f, From 0871973e56ba17c91a2cf55c64ce31436808d464 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Fri, 8 Apr 2022 16:09:50 +1000 Subject: [PATCH 03/20] Use products Change-Id: I3d23aa949a3d2ed658dfd4403665ece4180ee8cf --- ibis/demo.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ibis/demo.json b/ibis/demo.json index 9cfa31023..6cc86cb59 100644 --- a/ibis/demo.json +++ b/ibis/demo.json @@ -30,9 +30,9 @@ ["p_c", "c", "write", "String"], ["p_de", "d", "read", "Serializable"], ["p_de", "e", "read", "ibis.UnionType(Number, String)"], - ["p_f", "f", "write", "ibis.ProductType(name: String, age: Int)"], + ["p_f", "f", "write", "name: String age: Int"], ["p_g", "g", "read", "name: *"], - ["p_h", "h", "read", "ibis.ProductType(name: String, age: Int)"], + ["p_h", "h", "read", "name: String age: Int"], ["p_i", "i", "read", "name: String"], ["p_j", "j", "read", "age: Int"] ], From a6272336ce78d643be1c02f2e89a45fada46da95 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Fri, 8 Apr 2022 16:32:05 +1000 Subject: [PATCH 04/20] Fixes for nested types and round trips (handling parens) Change-Id: I56af6c8436b21b6e1e3b8d6c641d18a6d5a9afc8 --- ibis/src/type_parser.rs | 119 +++++++++++++++++++--------------------- ibis/src/type_struct.rs | 9 ++- 2 files changed, 64 insertions(+), 64 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index 62cc816d5..965f52bd4 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -40,6 +40,9 @@ fn type_args(input: &str) -> IResult<&str, Vec> { } fn simple_type_structure(input: &str) -> IResult<&str, Type> { + if let Ok((input, (_, ty, _))) = tuple((tag("("), type_parser, tag(")")))(input) { + return Ok((input, ty)); + } let (input, (mut name, args)) = tuple((name, opt(type_args)))(input)?; if name == "*" { name = "ibis.UniversalType"; @@ -85,32 +88,29 @@ pub fn read_type(input: &str) -> Type { mod tests { use super::*; + fn parse_and_round_trip(s: &str, t: Type) { + let ty = read_type(s); + assert_eq!(ty, t); + assert_eq!(format!("{}", ty), s); + } + #[test] fn read_a_simple_type_name() { - assert_eq!( - read_type("Type"), - Type { - name: "Type", - args: vec![] - } + parse_and_round_trip( + "Type", + Type::named("Type") ); } #[test] fn read_a_type_with_a_single_capabilities() { - assert_eq!( - read_type("read Type"), + parse_and_round_trip( + "read Type", Type { name: "ibis.ProductType", args: vec![ - Type { - name: "read", - args: vec![] - }, - Type { - name: "Type", - args: vec![] - } + Type::named("read"), + Type::named("Type") ] } ); @@ -118,26 +118,17 @@ mod tests { #[test] fn read_a_type_with_multiple_capabilities() { - assert_eq!( - read_type("read write Type"), + parse_and_round_trip( + "read write Type", Type { name: "ibis.ProductType", args: vec![ - Type { - name: "read", - args: vec![] - }, + Type::named("read"), Type { name: "ibis.ProductType", args: vec![ - Type { - name: "write", - args: vec![] - }, - Type { - name: "Type", - args: vec![] - } + Type::named("write"), + Type::named("Type") ] } ] @@ -149,8 +140,8 @@ mod tests { fn read_a_product_type_using_syntactic_sugar() { let name_string = read_type("name: String"); let age_number = read_type("age: Number"); - assert_eq!( - read_type("name: String age: Number"), + parse_and_round_trip( + "name: String age: Number", Type { name: "ibis.ProductType", args: vec![ @@ -161,21 +152,37 @@ mod tests { ); } + #[test] + fn read_nested_type() { + let json = read_type("JSON"); + let age_number = read_type("age: Number"); + parse_and_round_trip( + "name: (JSON age: Number)", + Type { + name: "ibis.Labelled", + args: vec![ + Type::named("name"), + Type { + name: "ibis.ProductType", + args: vec![ + json, + age_number + ] + } + ] + } + ); + } + #[test] fn read_a_type_with_arguments() { - assert_eq!( - read_type("Type(a, b)"), + parse_and_round_trip( + "Type(a, b)", Type { name: "Type", args: vec![ - Type { - name: "a", - args: vec![] - }, - Type { - name: "b", - args: vec![] - }, + Type::named("a"), + Type::named("b") ] } ); @@ -183,22 +190,16 @@ mod tests { #[test] fn read_a_type_with_nested_arguments() { - assert_eq!( - read_type("Type(a(c), b)"), + parse_and_round_trip( + "Type(a(c), b)", Type { name: "Type", args: vec![ Type { name: "a", - args: vec![Type { - name: "c", - args: vec![] - }] - }, - Type { - name: "b", - args: vec![] + args: vec![Type::named("c")] }, + Type::named("b") ] } ); @@ -206,19 +207,13 @@ mod tests { #[test] fn read_type_with_label() { - assert_eq!( - read_type("name: Type"), + parse_and_round_trip( + "name: Type", Type { name: "ibis.Labelled", args: vec![ - Type { - name: "name", - args: vec![], - }, - Type { - name: "Type", - args: vec![] - }, + Type::named("name"), + Type::named("Type") ] } ); diff --git a/ibis/src/type_struct.rs b/ibis/src/type_struct.rs index 9e4eb10f7..527887799 100644 --- a/ibis/src/type_struct.rs +++ b/ibis/src/type_struct.rs @@ -14,7 +14,6 @@ impl<'a> Type<'a> { pub fn new(name: &'a str, args: Vec>) -> Self { Self { name, args } } - pub fn named(name: &'a str) -> Self { Self::new(name, vec![]) } @@ -41,7 +40,13 @@ impl<'a> std::fmt::Display for Type<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.name == "ibis.Labelled" && self.args.len() > 1 { write!(f, "{}: ", self.args[0])?; - format_arg_set(f, ", ", &self.args[1..]) + if self.args[1].name == "ibis.ProductType" { + write!(f, "(")?; + format_arg_set(f, ", ", &self.args[1..])?; + write!(f, ")") + } else { + format_arg_set(f, ", ", &self.args[1..]) + } } else if self.name == "ibis.ProductType" && self.args.len() > 0 { format_arg_set(f, " ", &self.args) } else { From 020e3cd9546622a7174298f9b3afcab33da435de Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 11:58:06 +1000 Subject: [PATCH 05/20] Update tests to use merged capability and type Change-Id: I1b094519b14aab1563d06bda816f2967c839842a --- ibis/tests/checks_and_claims.rs | 10 +++++----- ibis/tests/generics.rs | 28 ++++++++++++++-------------- ibis/tests/graphs.rs | 26 +++++++++++++------------- ibis/tests/product_types.rs | 24 ++++++++++++------------ ibis/tests/subtyping.rs | 8 ++++---- ibis/tests/union_types.rs | 24 ++++++++++++------------ 6 files changed, 60 insertions(+), 60 deletions(-) diff --git a/ibis/tests/checks_and_claims.rs b/ibis/tests/checks_and_claims.rs index 11b713ae3..b75eb85e6 100644 --- a/ibis/tests/checks_and_claims.rs +++ b/ibis/tests/checks_and_claims.rs @@ -42,11 +42,11 @@ fn create_tagged_type_checked_graphs() { ["d", "public"] ], "nodes": [ - ["p_a", "a", "any", "Int"], - ["p_b", "b", "any", "Number"], - ["p_c", "c", "any", "String"], - ["p_de", "d", "any", "Serializable"], - ["p_de", "e", "any", "Or(Number, String)"] + ["p_a", "a", "any Int"], + ["p_b", "b", "any Number"], + ["p_c", "c", "any String"], + ["p_de", "d", "any Serializable"], + ["p_de", "e", "any Or(Number, String)"] ] } ] diff --git a/ibis/tests/generics.rs b/ibis/tests/generics.rs index c9b44bdb3..ebbb2ff7c 100644 --- a/ibis/tests/generics.rs +++ b/ibis/tests/generics.rs @@ -30,10 +30,10 @@ fn precomputed_subtypes() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "List(Man)"], - ["p_b", "b", "any", "List(Mortal)"], - ["p_c", "c", "any", "Iterable(Man)"], - ["p_d", "d", "any", "Iterable(Mortal)"] + ["p_a", "a", "any List(Man)"], + ["p_b", "b", "any List(Mortal)"], + ["p_c", "c", "any Iterable(Man)"], + ["p_d", "d", "any Iterable(Mortal)"] ] } ] @@ -65,8 +65,8 @@ fn generics_are_not_necessarily_abstractable() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "List(Man)"], - ["p_b", "b", "any", "List"] + ["p_a", "a", "any List(Man)"], + ["p_b", "b", "any List"] ] } ] @@ -96,12 +96,12 @@ fn dynamic_subtypes() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "List(Man)"], - ["p_b", "b", "any", "List(Mortal)"], - ["p_c", "c", "any", "Iterable(Man)"], - ["p_d", "d", "any", "Iterable(Mortal)"], - ["p_e", "e", "any", "List(ibis.UniversalType)"], - ["p_f", "f", "any", "List"] + ["p_a", "a", "any List(Man)"], + ["p_b", "b", "any List(Mortal)"], + ["p_c", "c", "any Iterable(Man)"], + ["p_d", "d", "any Iterable(Mortal)"], + ["p_e", "e", "any List(ibis.UniversalType)"], + ["p_f", "f", "any List"] ] } ] @@ -132,8 +132,8 @@ fn all_subtype_the_universal_type() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "List(Man)"], - ["p_b", "b", "any", "List(ibis.UniversalType)"] + ["p_a", "a", "any List(Man)"], + ["p_b", "b", "any List(ibis.UniversalType)"] ] } ] diff --git a/ibis/tests/graphs.rs b/ibis/tests/graphs.rs index 183af7414..c65d3da41 100644 --- a/ibis/tests/graphs.rs +++ b/ibis/tests/graphs.rs @@ -22,10 +22,10 @@ fn create_combinations() { "recipes": [ { "nodes": [ - ["p_a", "a", "write", "Unit"], - ["p_b", "b", "write", "Unit"], - ["p_c", "c", "write", "Unit"], - ["p_out", "out", "read", "Unit"] + ["p_a", "a", "write"], + ["p_b", "b", "write"], + ["p_c", "c", "write"], + ["p_out", "out", "read"] ] } ] @@ -60,8 +60,8 @@ fn create_edges() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "Char"], - ["p_b", "b", "any", "Char"] + ["p_a", "a", "any Char"], + ["p_b", "b", "any Char"] ] } ] @@ -88,9 +88,9 @@ fn create_typed_edges() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "Char"], - ["p_b", "b", "any", "Char"], - ["p_c", "c", "any", "Int"] + ["p_a", "a", "any Char"], + ["p_b", "b", "any Char"], + ["p_c", "c", "any Int"] ] } ] @@ -124,10 +124,10 @@ fn create_all_directed_graphs_with_4_nodes() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "Char"], - ["p_b", "b", "any", "Char"], - ["p_c", "c", "any", "Char"], - ["p_d", "d", "any", "Char"] + ["p_a", "a", "any Char"], + ["p_b", "b", "any Char"], + ["p_c", "c", "any Char"], + ["p_d", "d", "any Char"] ] } ] diff --git a/ibis/tests/product_types.rs b/ibis/tests/product_types.rs index f868ab288..fad6311a7 100644 --- a/ibis/tests/product_types.rs +++ b/ibis/tests/product_types.rs @@ -22,9 +22,9 @@ fn a_product_is_a_subtype_of_its_arguments() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "ibis.ProductType(Man, Mortal)"], - ["p_b", "b", "any", "Mortal"], - ["p_c", "c", "any", "Man"] + ["p_a", "a", "any Man Mortal"], + ["p_b", "b", "any Mortal"], + ["p_c", "c", "any Man"] ] } ] @@ -52,8 +52,8 @@ fn a_type_is_a_subtype_of_products_of_its_super_types() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "ibis.ProductType(Human, Mortal)"], - ["p_b", "b", "any", "Man"] + ["p_a", "a", "any Human Mortal"], + ["p_b", "b", "any Man"] ] } ] @@ -80,8 +80,8 @@ fn a_type_is_equal_to_the_product_of_it_and_its_super_types() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "ibis.ProductType(Man, Mortal)"], - ["p_b", "b", "any", "Man"] + ["p_a", "a", "any Man Mortal"], + ["p_b", "b", "any Man"] ] } ] @@ -105,11 +105,11 @@ fn product_of_products() { "recipes": [ { "nodes": [ - ["p_abc", "abc", "any", "ibis.ProductType(A, ibis.ProductType(B, C))"], - ["p_acb", "acb", "any", "ibis.ProductType(ibis.ProductType(A, C), B)"], - ["p_a", "a", "any", "A"], - ["p_b", "b", "any", "B"], - ["p_c", "c", "any", "C"] + ["p_abc", "abc", "any ibis.ProductType(A, ibis.ProductType(B, C))"], + ["p_acb", "acb", "any ibis.ProductType(ibis.ProductType(A, C), B)"], + ["p_a", "a", "any A"], + ["p_b", "b", "any B"], + ["p_c", "c", "any C"] ] } ] diff --git a/ibis/tests/subtyping.rs b/ibis/tests/subtyping.rs index 8ab767e2f..c91b9cff8 100644 --- a/ibis/tests/subtyping.rs +++ b/ibis/tests/subtyping.rs @@ -27,10 +27,10 @@ fn static_subtyping_socretes_is_mortal() { "recipes": [ { "nodes": [ - ["p_a", "socretes", "any", "socretes"], - ["p_b", "plato", "any", "plato"], - ["p_c", "man", "any", "man"], - ["p_out", "mortal", "any", "mortal"] + ["p_a", "socretes", "any socretes"], + ["p_b", "plato", "any plato"], + ["p_c", "man", "any man"], + ["p_out", "mortal", "any mortal"] ] } ] diff --git a/ibis/tests/union_types.rs b/ibis/tests/union_types.rs index 5ca5aa63f..2f10fa6ed 100644 --- a/ibis/tests/union_types.rs +++ b/ibis/tests/union_types.rs @@ -22,9 +22,9 @@ fn a_union_is_a_subtype_of_its_arguments() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "ibis.UnionType(Man, Dog)"], - ["p_b", "b", "any", "Dog"], - ["p_c", "c", "any", "Man"] + ["p_a", "a", "any ibis.UnionType(Man, Dog)"], + ["p_b", "b", "any Dog"], + ["p_c", "c", "any Man"] ] } ] @@ -52,8 +52,8 @@ fn a_union_is_a_subtype_of_its_arguments_shared_super_types() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "ibis.UnionType(TallMan, ShortMan)"], - ["p_b", "b", "any", "Man"] + ["p_a", "a", "any ibis.UnionType(TallMan, ShortMan)"], + ["p_b", "b", "any Man"] ] } ] @@ -80,8 +80,8 @@ fn a_type_is_equal_to_the_union_of_it_and_its_super_types() { "recipes": [ { "nodes": [ - ["p_a", "a", "any", "ibis.UnionType(Man, Mortal)"], - ["p_b", "b", "any", "Man"] + ["p_a", "a", "any ibis.UnionType(Man, Mortal)"], + ["p_b", "b", "any Man"] ] } ] @@ -105,11 +105,11 @@ fn union_of_unions() { "recipes": [ { "nodes": [ - ["p_abc", "abc", "any", "ibis.UnionType(A, ibis.UnionType(B, C))"], - ["p_acb", "acb", "any", "ibis.UnionType(ibis.UnionType(A, C), B)"], - ["p_a", "a", "any", "A"], - ["p_b", "b", "any", "B"], - ["p_c", "c", "any", "C"] + ["p_abc", "abc", "any ibis.UnionType(A, ibis.UnionType(B, C))"], + ["p_acb", "acb", "any ibis.UnionType(ibis.UnionType(A, C), B)"], + ["p_a", "a", "any A"], + ["p_b", "b", "any B"], + ["p_c", "c", "any C"] ] } ] From 169457a6cf0a745dbb2f11f4094441529fba9263 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 11:58:59 +1000 Subject: [PATCH 06/20] Add support for capabilities in type structures Change-Id: I5584527223ffaa0ae567c3613407404d24b6f2d1 --- ibis/src/type_parser.rs | 103 ++++++++++++++-------------------------- ibis/src/type_struct.rs | 32 +++++++++---- 2 files changed, 58 insertions(+), 77 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index 965f52bd4..6f0c415f1 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -47,13 +47,15 @@ fn simple_type_structure(input: &str) -> IResult<&str, Type> { if name == "*" { name = "ibis.UniversalType"; } - Ok((input, Type::new(name, args.unwrap_or_default()))) + Ok((input, Type::with_args(name, args.unwrap_or_default()))) } fn labelled_simple_type_structure(input: &str) -> IResult<&str, Type> { let (input, (label, mut structure)) = tuple((opt(label), simple_type_structure))(input)?; if let Some(label) = label { - structure = Type::new("ibis.Labelled", vec![Type::named(label), structure]); + structure = Type::new("ibis.Labelled") + .with_arg(Type::new(label)) + .with_arg(structure); } Ok((input, structure)) } @@ -63,7 +65,9 @@ fn type_parser(input: &str) -> IResult<&str, Type> { let mut ty = None; for new_ty in types.drain(0..).rev() { ty = Some(if let Some(ty) = ty { - Type::new("ibis.ProductType", vec![new_ty, ty]) + Type::new("ibis.ProductType") + .with_arg(new_ty) + .with_arg(ty) } else { new_ty }); @@ -98,7 +102,7 @@ mod tests { fn read_a_simple_type_name() { parse_and_round_trip( "Type", - Type::named("Type") + Type::new("Type") ); } @@ -106,13 +110,8 @@ mod tests { fn read_a_type_with_a_single_capabilities() { parse_and_round_trip( "read Type", - Type { - name: "ibis.ProductType", - args: vec![ - Type::named("read"), - Type::named("Type") - ] - } + Type::new("Type") + .with_capability("read") ); } @@ -120,19 +119,9 @@ mod tests { fn read_a_type_with_multiple_capabilities() { parse_and_round_trip( "read write Type", - Type { - name: "ibis.ProductType", - args: vec![ - Type::named("read"), - Type { - name: "ibis.ProductType", - args: vec![ - Type::named("write"), - Type::named("Type") - ] - } - ] - } + Type::new("Type") + .with_capability("read") + .with_capability("write") ); } @@ -142,13 +131,9 @@ mod tests { let age_number = read_type("age: Number"); parse_and_round_trip( "name: String age: Number", - Type { - name: "ibis.ProductType", - args: vec![ - name_string, - age_number - ] - } + Type::new("ibis.ProductType") + .with_arg(name_string) + .with_arg(age_number) ); } @@ -158,19 +143,13 @@ mod tests { let age_number = read_type("age: Number"); parse_and_round_trip( "name: (JSON age: Number)", - Type { - name: "ibis.Labelled", - args: vec![ - Type::named("name"), - Type { - name: "ibis.ProductType", - args: vec![ - json, - age_number - ] - } - ] - } + Type::new("ibis.Labelled") + .with_arg(Type::new("name")) + .with_arg( + Type::new("ibis.ProductType") + .with_arg(json) + .with_arg(age_number) + ) ); } @@ -178,13 +157,9 @@ mod tests { fn read_a_type_with_arguments() { parse_and_round_trip( "Type(a, b)", - Type { - name: "Type", - args: vec![ - Type::named("a"), - Type::named("b") - ] - } + Type::new("Type") + .with_arg(Type::new("a")) + .with_arg(Type::new("b")) ); } @@ -192,16 +167,12 @@ mod tests { fn read_a_type_with_nested_arguments() { parse_and_round_trip( "Type(a(c), b)", - Type { - name: "Type", - args: vec![ - Type { - name: "a", - args: vec![Type::named("c")] - }, - Type::named("b") - ] - } + Type::new("Type") + .with_arg( + Type::new("a") + .with_arg(Type::new("c")), + ) + .with_arg(Type::new("b")) ); } @@ -209,13 +180,9 @@ mod tests { fn read_type_with_label() { parse_and_round_trip( "name: Type", - Type { - name: "ibis.Labelled", - args: vec![ - Type::named("name"), - Type::named("Type") - ] - } + Type::new("ibis.Labelled") + .with_arg(Type::new("name")) + .with_arg(Type::new("Type")) ); } diff --git a/ibis/src/type_struct.rs b/ibis/src/type_struct.rs index 527887799..5c092c972 100644 --- a/ibis/src/type_struct.rs +++ b/ibis/src/type_struct.rs @@ -6,16 +6,25 @@ #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Type<'a> { + pub capabilities: Vec<&'a str>, pub name: &'a str, pub args: Vec>, } impl<'a> Type<'a> { - pub fn new(name: &'a str, args: Vec>) -> Self { - Self { name, args } + pub fn with_args(name: &'a str, args: Vec>) -> Self { + Self { capabilities: vec![], name, args } } - pub fn named(name: &'a str) -> Self { - Self::new(name, vec![]) + pub fn new(name: &'a str) -> Self { + Self::with_args(name, vec![]) + } + pub fn with_capability(mut self, cap: &'a str) -> Self { + self.capabilities.push(cap); + self + } + pub fn with_arg(mut self, arg: Type<'a>) -> Self { + self.args.push(arg); + self } } @@ -38,15 +47,20 @@ fn format_arg_set<'a>( impl<'a> std::fmt::Display for Type<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + for cap in &self.capabilities { + write!(f, "{} ", cap)?; + } if self.name == "ibis.Labelled" && self.args.len() > 1 { write!(f, "{}: ", self.args[0])?; - if self.args[1].name == "ibis.ProductType" { + let is_product = self.args[1].name == "ibis.ProductType"; + if is_product { write!(f, "(")?; - format_arg_set(f, ", ", &self.args[1..])?; - write!(f, ")") - } else { - format_arg_set(f, ", ", &self.args[1..]) } + format_arg_set(f, ", ", &self.args[1..])?; + if is_product { + write!(f, ")")?; + } + Ok(()) } else if self.name == "ibis.ProductType" && self.args.len() > 0 { format_arg_set(f, " ", &self.args) } else { From 50f7e1ca60e5dc0155cfbafc965f2d1814de4fd4 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 12:00:12 +1000 Subject: [PATCH 07/20] Update to_dot impls for merged capability & node type Change-Id: I9075c9f07cdaae6ce8c777948d192b81d9e34938 --- ibis/src/to_dot_impls.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ibis/src/to_dot_impls.rs b/ibis/src/to_dot_impls.rs index ee8ef74e1..6288f5e45 100644 --- a/ibis/src/to_dot_impls.rs +++ b/ibis/src/to_dot_impls.rs @@ -73,7 +73,7 @@ impl ToDot for (&Ibis, &Recipe) { let node_id = |node| format!("{}_h_{}", &s_id, node).replace('.', "_"); let mut sol_graph = DotGraph::default(); let mut particles = HashMap::new(); - for Node(particle, node, cap, ty) in &ibis.shared.nodes { + for Node(particle, node, ty) in &ibis.shared.nodes { let mut extras: Vec = vec![]; for HasTag(_hts, source, sink, tag) in &recipe.feedback.has_tags { if sink == node && source != node { @@ -103,7 +103,7 @@ impl ToDot for (&Ibis, &Recipe) { .map(|ex| format!("{}", ex)) .collect(); let particle_g = particles.entry(particle).or_insert_with(DotGraph::default); - particle_g.add_node(format!("{node_id} [shape=record label=< {extras}
{cap} {node} : {ty}
>]", node_id=node_id(node), node=node, cap=cap, ty=ty, extras=extras.join(""))); + particle_g.add_node(format!("{node_id} [shape=record label=< {extras}
{node} : {ty}
>]", node_id=node_id(node), node=node, ty=ty, extras=extras.join(""))); } for (particle, particle_g) in particles { sol_graph.add_child( From 2b36b10fe3085a0834113995699e0b861a400806 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 12:00:30 +1000 Subject: [PATCH 08/20] Update demo for merged capability and node type Change-Id: I4f9c33ab7367f92343c4ce8f87fff0c837fb66fc --- ibis/demo.json | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/ibis/demo.json b/ibis/demo.json index 6cc86cb59..9ad102f56 100644 --- a/ibis/demo.json +++ b/ibis/demo.json @@ -25,26 +25,20 @@ "name": "demo" }, "nodes": [ - ["p_a", "a", "write", "Int"], - ["p_b", "b", "any", "Number"], - ["p_c", "c", "write", "String"], - ["p_de", "d", "read", "Serializable"], - ["p_de", "e", "read", "ibis.UnionType(Number, String)"], - ["p_f", "f", "write", "name: String age: Int"], - ["p_g", "g", "read", "name: *"], - ["p_h", "h", "read", "name: String age: Int"], - ["p_i", "i", "read", "name: String"], - ["p_j", "j", "read", "age: Int"] + ["p_a", "a", "write private Int"], + ["p_b", "b", "any Number"], + ["p_c", "c", "write String"], + ["p_de", "d", "read Serializable"], + ["p_de", "e", "read public ibis.UnionType(Number, String)"], + ["p_f", "f", "write name: String age: Int"], + ["p_g", "g", "read name: *"], + ["p_h", "h", "read name: String age: Int"], + ["p_i", "i", "read name: String"], + ["p_j", "j", "read age: Int"] ], "edges": [ ["b", "e"] ], - "claims": [ - ["a", "private"] - ], - "checks": [ - ["e", "public"] - ], "trusted_to_remove_tag": [ ["b", "private"] ] From a25a666dbdd14511af9095e3e6390e78ec80c012 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 12:49:26 +1000 Subject: [PATCH 09/20] TMP Change-Id: I7f4179fecd38174b648a6d87f466f20f941fb91b --- ibis/src/lib.rs | 4 +-- ibis/src/recipes.rs | 36 ++++++++++++++++--------- ibis/src/type_parser.rs | 58 +++++++++++++++++------------------------ ibis/src/type_struct.rs | 51 +++++++++++++++++++++++++++++------- 4 files changed, 92 insertions(+), 57 deletions(-) diff --git a/ibis/src/lib.rs b/ibis/src/lib.rs index 820819e3e..8ce0b1fb1 100644 --- a/ibis/src/lib.rs +++ b/ibis/src/lib.rs @@ -61,7 +61,7 @@ macro_rules! is_a { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ty.name == $parent.name() + ty.structure.name == $parent.name() }}; } @@ -71,7 +71,7 @@ macro_rules! arg { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ent!(&format!("{}", ty.args[$ind])) + ent!(&format!("{}", ty.structure.args[$ind])) }}; } diff --git a/ibis/src/recipes.rs b/ibis/src/recipes.rs index 0dcf2c1fa..367317cfe 100644 --- a/ibis/src/recipes.rs +++ b/ibis/src/recipes.rs @@ -10,7 +10,8 @@ ibis! { LessPrivateThan(Ent, Ent); // tag, tag Capability(Ent, Ent); // cap from, cap to Subtype(Ent, Ent); // sub, super - Node(Ent, Ent, Ent, Ent); // particle-identifier, identifier, capability, type + CompatibleWith(Ent, Ent); // from, to + Node(Ent, Ent, Ent); // particle-identifier, identifier, capability, type Claim(Ent, Ent); // identifier, tag Check(Ent, Ent); // identifier, tag TrustedToRemoveTag(Ent, Ent); // node, tag @@ -24,12 +25,20 @@ ibis! { UncheckedSolution(parent.add_edge(from, to)) <- PlanningIsEnabled(true), Capability(from_capability, to_capability), - Node(from_particle, from, from_capability, from_type), - Subtype(from_type, to_type), - Node(to_particle, to, to_capability, to_type), + Node(from_particle, from, from_type), + Node(to_particle, to, to_type), + ({eprintln!("{}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), + Subtype(from_type, from_capability), + ({eprintln!(" {}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), + Subtype(to_type, to_capability), + ({eprintln!(" {}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), + CompatibleWith(from_type, to_type), + ({eprintln!(" {}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), (from != to), UncheckedSolution(parent); + CompatibleWith(x, y) <- Subtype(x, y); + Subtype( x, prod @@ -115,8 +124,8 @@ ibis! { HasTag(s, source, down, tag) <- // Propagate tags 'across stream' (i.e. inside a particle) HasTag(s, source, curr, tag), - Node(particle, curr, _, _), - Node(particle, down, _, _), + Node(particle, curr, _), + Node(particle, down, _), !TrustedToRemoveTag(down, tag); Leak(s, n, t1, source, t2) <- @@ -127,16 +136,18 @@ ibis! { TypeError(s, *from, from_ty, *to, to_ty) <- UncheckedSolution(s), for (from, to) in &s.solution().edges, - Node(_from_p, *from, _, from_ty), - Node(_to_p, *to, _, to_ty), + Node(_from_p, *from, from_ty), + Node(_to_p, *to, to_ty), !Subtype(from_ty, to_ty); // Check failed, from writes an incompatible type into to CapabilityError(s, *from, from_capability, *to, to_capability) <- UncheckedSolution(s), for (from, to) in &s.solution().edges, - Node(_from_p, *from, from_capability, _), - Node(_to_p, *to, to_capability, _), - !Capability(from_capability, to_capability); // Check failed, from writes an incompatible type into to + Node(_from_p, *from, from_type), + Node(_to_p, *to, to_type), + Capability(from_capability, to_capability), + !Subtype(from_type, from_capability), + !Subtype(to_type, to_capability); // Check failed, from writes an incompatible type into to Solution(s) <- UncheckedSolution(s), @@ -144,7 +155,7 @@ ibis! { !CapabilityError(s, _, _, _, _), !Leak(s, _, _, _, _); - KnownType(x) <- Node(_par, _node, _cap, x); // Infer types that are used in the recipes. + KnownType(x) <- Node(_par, _node, x); // Infer types that are used in the recipes. KnownType(x) <- Subtype(x, _); KnownType(y) <- Subtype(_, y); Subtype(x, ent!("ibis.UniversalType")) <- KnownType(x); // Create a universal type. @@ -381,6 +392,7 @@ impl Ibis { mut less_private_than, mut capabilities, mut subtypes, + _compatible_with, nodes, claims, checks, diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index 6f0c415f1..3f901c379 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -14,7 +14,7 @@ use nom::{ Finish, IResult, }; -use crate::type_struct::Type; +use crate::type_struct::{Type, Structure}; fn is_name_char(c: char) -> bool { match c { @@ -33,46 +33,36 @@ fn label(input: &str) -> IResult<&str, &str> { Ok((input, name)) } -fn type_args(input: &str) -> IResult<&str, Vec> { +fn type_args(input: &str) -> IResult<&str, Vec> { let (input, (_, args, _)) = - tuple((tag("("), separated_list0(tag(", "), type_parser), tag(")")))(input)?; + tuple((tag("("), separated_list0(tag(", "), labelled_simple_type_structure), tag(")")))(input)?; Ok((input, args)) } -fn simple_type_structure(input: &str) -> IResult<&str, Type> { - if let Ok((input, (_, ty, _))) = tuple((tag("("), type_parser, tag(")")))(input) { +fn simple_type_structure(input: &str) -> IResult<&str, Structure> { + if let Ok((input, (_, ty, _))) = tuple((tag("("), labelled_simple_type_structure, tag(")")))(input) { return Ok((input, ty)); } let (input, (mut name, args)) = tuple((name, opt(type_args)))(input)?; if name == "*" { name = "ibis.UniversalType"; } - Ok((input, Type::with_args(name, args.unwrap_or_default()))) + Ok((input, Structure::with_args(name, args.unwrap_or_default()))) } -fn labelled_simple_type_structure(input: &str) -> IResult<&str, Type> { +fn labelled_simple_type_structure(input: &str) -> IResult<&str, Structure> { let (input, (label, mut structure)) = tuple((opt(label), simple_type_structure))(input)?; if let Some(label) = label { - structure = Type::new("ibis.Labelled") - .with_arg(Type::new(label)) + structure = Structure::new("ibis.Labelled") + .with_arg(Structure::new(label)) .with_arg(structure); } Ok((input, structure)) } fn type_parser(input: &str) -> IResult<&str, Type> { - let (input, mut types) = separated_list1(space1, labelled_simple_type_structure)(input)?; - let mut ty = None; - for new_ty in types.drain(0..).rev() { - ty = Some(if let Some(ty) = ty { - Type::new("ibis.ProductType") - .with_arg(new_ty) - .with_arg(ty) - } else { - new_ty - }); - } - Ok((input, ty.expect("Should have a type"))) + let (input, (capabilities, _, ty)) = tuple((separated_list1(space1, name), space0, labelled_simple_type_structure))(input)?; + Ok((input, Type::from_structure(ty, capabilities))) } pub fn read_type(input: &str) -> Type { @@ -127,8 +117,8 @@ mod tests { #[test] fn read_a_product_type_using_syntactic_sugar() { - let name_string = read_type("name: String"); - let age_number = read_type("age: Number"); + let name_string = read_type("name: String").structure; + let age_number = read_type("age: Number").structure; parse_and_round_trip( "name: String age: Number", Type::new("ibis.ProductType") @@ -139,14 +129,14 @@ mod tests { #[test] fn read_nested_type() { - let json = read_type("JSON"); - let age_number = read_type("age: Number"); + let json = read_type("JSON").structure; + let age_number = read_type("age: Number").structure; parse_and_round_trip( "name: (JSON age: Number)", Type::new("ibis.Labelled") - .with_arg(Type::new("name")) + .with_arg(Structure::new("name")) .with_arg( - Type::new("ibis.ProductType") + Structure::new("ibis.ProductType") .with_arg(json) .with_arg(age_number) ) @@ -158,8 +148,8 @@ mod tests { parse_and_round_trip( "Type(a, b)", Type::new("Type") - .with_arg(Type::new("a")) - .with_arg(Type::new("b")) + .with_arg(Structure::new("a")) + .with_arg(Structure::new("b")) ); } @@ -169,10 +159,10 @@ mod tests { "Type(a(c), b)", Type::new("Type") .with_arg( - Type::new("a") - .with_arg(Type::new("c")), + Structure::new("a") + .with_arg(Structure::new("c")), ) - .with_arg(Type::new("b")) + .with_arg(Structure::new("b")) ); } @@ -181,8 +171,8 @@ mod tests { parse_and_round_trip( "name: Type", Type::new("ibis.Labelled") - .with_arg(Type::new("name")) - .with_arg(Type::new("Type")) + .with_arg(Structure::new("name")) + .with_arg(Structure::new("Type")) ); } diff --git a/ibis/src/type_struct.rs b/ibis/src/type_struct.rs index 5c092c972..20147ef81 100644 --- a/ibis/src/type_struct.rs +++ b/ibis/src/type_struct.rs @@ -7,22 +7,49 @@ #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Type<'a> { pub capabilities: Vec<&'a str>, - pub name: &'a str, - pub args: Vec>, + pub structure: Structure<'a>, } impl<'a> Type<'a> { - pub fn with_args(name: &'a str, args: Vec>) -> Self { - Self { capabilities: vec![], name, args } + pub fn with_capability(mut self, cap: &'a str) -> Self { + self.capabilities.push(cap); + self + } + pub fn with_args(name: &'a str, args: Vec>) -> Self { + Structure::with_args(name, args).into() + } + pub fn from_structure(structure: Structure<'a>, capabilities: Vec<&'a str>) -> Self { + Type { structure, capabilities } } pub fn new(name: &'a str) -> Self { - Self::with_args(name, vec![]) + Structure::new(name).into() } - pub fn with_capability(mut self, cap: &'a str) -> Self { - self.capabilities.push(cap); + pub fn with_arg(mut self, arg: Structure<'a>) -> Self { + self.structure = self.structure.with_arg(arg); self } - pub fn with_arg(mut self, arg: Type<'a>) -> Self { +} + +impl <'a> From> for Type<'a> { + fn from(structure: Structure<'a>) -> Self { + Type::from_structure(structure, vec![]) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct Structure<'a> { + pub name: &'a str, + pub args: Vec>, +} + +impl<'a> Structure<'a> { + pub fn with_args(name: &'a str, args: Vec>) -> Self { + Self { name, args } + } + pub fn new(name: &'a str) -> Self { + Self::with_args(name, vec![]) + } + pub fn with_arg(mut self, arg: Structure<'a>) -> Self { self.args.push(arg); self } @@ -31,7 +58,7 @@ impl<'a> Type<'a> { fn format_arg_set<'a>( f: &mut std::fmt::Formatter<'_>, joiner: &str, - args: &[Type<'a>], + args: &[Structure<'a>], ) -> std::fmt::Result { let mut first = true; for arg in args { @@ -50,6 +77,12 @@ impl<'a> std::fmt::Display for Type<'a> { for cap in &self.capabilities { write!(f, "{} ", cap)?; } + write!(f, "{}", self.structure) + } +} + +impl<'a> std::fmt::Display for Structure<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if self.name == "ibis.Labelled" && self.args.len() > 1 { write!(f, "{}: ", self.args[0])?; let is_product = self.args[1].name == "ibis.ProductType"; From 47efa6f51228f3b7532b95edd8b1be643cf553cf Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 15:57:40 +1000 Subject: [PATCH 10/20] Use a short hand for product types Change-Id: Ie8db368ac666682671786075feb30745b99812a9 --- ibis/benches/checking_and_planning.rs | 10 +-- ibis/benches/checking_only.rs | 10 +-- ibis/demo.json | 14 +-- ibis/src/lib.rs | 4 +- ibis/src/type_parser.rs | 117 +++++++++++++++++--------- ibis/src/type_struct.rs | 90 +++++++------------- 6 files changed, 127 insertions(+), 118 deletions(-) diff --git a/ibis/benches/checking_and_planning.rs b/ibis/benches/checking_and_planning.rs index b6780b88c..f2bccd55c 100644 --- a/ibis/benches/checking_and_planning.rs +++ b/ibis/benches/checking_and_planning.rs @@ -39,11 +39,11 @@ pub fn criterion_benchmark_noop_planning(c: &mut Criterion) { ["p_c", "c", "write", "String"], ["p_de", "d", "read", "Serializable"], ["p_de", "e", "read", "ibis.UnionType(Number, String)"], - ["p_f", "f", "write", "ibis.ProductType(name: String, age: Int)"], - ["p_g", "g", "read", "name: *"], - ["p_h", "h", "read", "ibis.ProductType(name: String, age: Int)"], - ["p_i", "i", "read", "name: String"], - ["p_j", "j", "read", "age: Int"] + ["p_f", "f", "write", "{name: String, age: Int}"], + ["p_g", "g", "read", "{name: *}"], + ["p_h", "h", "read", "{name: String, age: Int}"], + ["p_i", "i", "read", "{name: String}"], + ["p_j", "j", "read", "{age: Int}"] ], "claims": [ ["a", "private"] diff --git a/ibis/benches/checking_only.rs b/ibis/benches/checking_only.rs index 1fc57fa0f..56132632c 100644 --- a/ibis/benches/checking_only.rs +++ b/ibis/benches/checking_only.rs @@ -39,11 +39,11 @@ pub fn criterion_benchmark_checking_only(c: &mut Criterion) { ["p_c", "c", "write", "String"], ["p_de", "d", "read", "Serializable"], ["p_de", "e", "read", "ibis.UnionType(Number, String)"], - ["p_f", "f", "write", "ibis.ProductType(name: String, age: Int)"], - ["p_g", "g", "read", "name: *"], - ["p_h", "h", "read", "ibis.ProductType(name: String, age: Int)"], - ["p_i", "i", "read", "name: String"], - ["p_j", "j", "read", "age: Int"] + ["p_f", "f", "write", "{name: String, age: Int}"], + ["p_g", "g", "read", "{name: *"], + ["p_h", "h", "read", "{name: String, age: Int}"], + ["p_i", "i", "read", "{name: String}"], + ["p_j", "j", "read", "{age: Int}"] ], "claims": [ ["a", "private"] diff --git a/ibis/demo.json b/ibis/demo.json index 9ad102f56..900266b38 100644 --- a/ibis/demo.json +++ b/ibis/demo.json @@ -25,16 +25,16 @@ "name": "demo" }, "nodes": [ - ["p_a", "a", "write private Int"], + ["p_a", "a", "write Int + private"], ["p_b", "b", "any Number"], ["p_c", "c", "write String"], ["p_de", "d", "read Serializable"], - ["p_de", "e", "read public ibis.UnionType(Number, String)"], - ["p_f", "f", "write name: String age: Int"], - ["p_g", "g", "read name: *"], - ["p_h", "h", "read name: String age: Int"], - ["p_i", "i", "read name: String"], - ["p_j", "j", "read age: Int"] + ["p_de", "e", "read ibis.UnionType(Number, String) + public"], + ["p_f", "f", "write {name: String, age: Int}"], + ["p_g", "g", "read {name: *}"], + ["p_h", "h", "read {name: String, age: Int}"], + ["p_i", "i", "read {name: String}"], + ["p_j", "j", "read {age: Int}"] ], "edges": [ ["b", "e"] diff --git a/ibis/src/lib.rs b/ibis/src/lib.rs index 8ce0b1fb1..820819e3e 100644 --- a/ibis/src/lib.rs +++ b/ibis/src/lib.rs @@ -61,7 +61,7 @@ macro_rules! is_a { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ty.structure.name == $parent.name() + ty.name == $parent.name() }}; } @@ -71,7 +71,7 @@ macro_rules! arg { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ent!(&format!("{}", ty.structure.args[$ind])) + ent!(&format!("{}", ty.args[$ind])) }}; } diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index 3f901c379..b21d904d6 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -6,26 +6,40 @@ extern crate nom; use nom::{ - bytes::complete::{tag, take_while}, + bytes::complete::{tag, take_while1}, character::complete::{space0, space1}, - combinator::opt, + combinator::{opt, cut}, multi::{separated_list0, separated_list1}, sequence::tuple, Finish, IResult, }; -use crate::type_struct::{Type, Structure}; +use crate::type_struct::Type; fn is_name_char(c: char) -> bool { match c { - '(' | ')' | ',' | ':' => false, // Symbols + '(' | ')' | '{' | '}' | ',' | ':' => false, // Symbols ' ' | '\n' | '\r' | '\t' => false, // Whitespace _ => true // Name char } } +fn is_lower_char(c: char) -> bool { + match c { + 'a'..='z' => true, // a to z + '_' => true, // underscore + _ => false // Name char + } +} + fn name(input: &str) -> IResult<&str, &str> { - take_while(is_name_char)(input) + let (input, _) = space0(input)?; + take_while1(is_name_char)(input) +} + +fn capability(input: &str) -> IResult<&str, &str> { + let (input, (_, cap, _)) = tuple((space0, take_while1(is_lower_char), space1))(input)?; + Ok((input, cap)) } fn label(input: &str) -> IResult<&str, &str> { @@ -33,46 +47,69 @@ fn label(input: &str) -> IResult<&str, &str> { Ok((input, name)) } -fn type_args(input: &str) -> IResult<&str, Vec> { +fn type_args(input: &str) -> IResult<&str, Vec> { let (input, (_, args, _)) = - tuple((tag("("), separated_list0(tag(", "), labelled_simple_type_structure), tag(")")))(input)?; + tuple((tag("("), cut(separated_list0(tag(","), structure)), tag(")")))(input)?; Ok((input, args)) } -fn simple_type_structure(input: &str) -> IResult<&str, Structure> { - if let Ok((input, (_, ty, _))) = tuple((tag("("), labelled_simple_type_structure, tag(")")))(input) { - return Ok((input, ty)); +fn parenthesized(input: &str) -> IResult<&str, Type> { + let (input, (_, _, ty, _)) = tuple((opt(space0), tag("("), cut(structure), tag(")")))(input)?; + Ok((input, ty)) +} + +fn structure(input: &str) -> IResult<&str, Type> { + if let Ok(res) = labelled_type(input) { + return Ok(res); + } + if let Ok(res) = entity(input) { + return Ok(res); + } + if let Ok(res) = parenthesized(input) { + return Ok(res); } let (input, (mut name, args)) = tuple((name, opt(type_args)))(input)?; if name == "*" { name = "ibis.UniversalType"; } - Ok((input, Structure::with_args(name, args.unwrap_or_default()))) + Ok((input, Type::with_args(name, args.unwrap_or_default()))) +} + +fn labelled_type(input: &str) -> IResult<&str, Type> { + let (input, (label, structure)) = tuple((label, structure))(input)?; + Ok(( input, + Type::new("ibis.Labelled") + .with_arg(Type::new(label)) + .with_arg(structure) + )) } -fn labelled_simple_type_structure(input: &str) -> IResult<&str, Structure> { - let (input, (label, mut structure)) = tuple((opt(label), simple_type_structure))(input)?; - if let Some(label) = label { - structure = Structure::new("ibis.Labelled") - .with_arg(Structure::new(label)) - .with_arg(structure); +fn entity(input: &str) -> IResult<&str, Type> { + let (input, (_, mut types, _)) = tuple((tag("{"), cut(separated_list1(tag(","), structure)), tag("}")))(input)?; + let mut types: Vec = types.drain(0..).rev().collect(); + let mut ty = types.pop().expect("A structure requires at least one labelled type"); + for new_ty in types { + ty = Type::with_args("ibis.ProductType", vec![ty, new_ty]); } - Ok((input, structure)) + Ok((input, ty)) } fn type_parser(input: &str) -> IResult<&str, Type> { - let (input, (capabilities, _, ty)) = tuple((separated_list1(space1, name), space0, labelled_simple_type_structure))(input)?; - Ok((input, Type::from_structure(ty, capabilities))) + if let Ok((input, (cap, _, ty))) = tuple((capability, space0, type_parser))(input) { + return Ok((input, ty.with_capability(cap))); + } + structure(input) } -pub fn read_type(input: &str) -> Type { +pub fn read_type(og_input: &str) -> Type { // TODO: return errors instead of panics - let (input, ty) = type_parser(input).finish().expect("Could not parse type"); + let (input, ty) = type_parser(og_input).finish().expect("Could not parse type"); if !input.is_empty() { todo!( - "Did not reach end of input. Read {:?}. Left over {}", + "Did not reach end of input. Read {:?}. Left over '{}' from '{}'", ty, - input + input, + og_input ); } ty @@ -110,17 +147,17 @@ mod tests { parse_and_round_trip( "read write Type", Type::new("Type") - .with_capability("read") .with_capability("write") + .with_capability("read") ); } #[test] fn read_a_product_type_using_syntactic_sugar() { - let name_string = read_type("name: String").structure; - let age_number = read_type("age: Number").structure; + let name_string = read_type("{name: String}"); + let age_number = read_type("{age: Number}"); parse_and_round_trip( - "name: String age: Number", + "{name: String, age: Number}", Type::new("ibis.ProductType") .with_arg(name_string) .with_arg(age_number) @@ -129,14 +166,14 @@ mod tests { #[test] fn read_nested_type() { - let json = read_type("JSON").structure; - let age_number = read_type("age: Number").structure; + let json = read_type("JSON"); + let age_number = read_type("{age: Number}"); parse_and_round_trip( - "name: (JSON age: Number)", + "name: {JSON, age: Number}", Type::new("ibis.Labelled") - .with_arg(Structure::new("name")) + .with_arg(Type::new("name")) .with_arg( - Structure::new("ibis.ProductType") + Type::new("ibis.ProductType") .with_arg(json) .with_arg(age_number) ) @@ -148,8 +185,8 @@ mod tests { parse_and_round_trip( "Type(a, b)", Type::new("Type") - .with_arg(Structure::new("a")) - .with_arg(Structure::new("b")) + .with_arg(Type::new("a")) + .with_arg(Type::new("b")) ); } @@ -159,10 +196,10 @@ mod tests { "Type(a(c), b)", Type::new("Type") .with_arg( - Structure::new("a") - .with_arg(Structure::new("c")), + Type::new("a") + .with_arg(Type::new("c")), ) - .with_arg(Structure::new("b")) + .with_arg(Type::new("b")) ); } @@ -171,8 +208,8 @@ mod tests { parse_and_round_trip( "name: Type", Type::new("ibis.Labelled") - .with_arg(Structure::new("name")) - .with_arg(Structure::new("Type")) + .with_arg(Type::new("name")) + .with_arg(Type::new("Type")) ); } diff --git a/ibis/src/type_struct.rs b/ibis/src/type_struct.rs index 20147ef81..186cdb1d7 100644 --- a/ibis/src/type_struct.rs +++ b/ibis/src/type_struct.rs @@ -6,96 +6,68 @@ #[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct Type<'a> { - pub capabilities: Vec<&'a str>, - pub structure: Structure<'a>, -} - -impl<'a> Type<'a> { - pub fn with_capability(mut self, cap: &'a str) -> Self { - self.capabilities.push(cap); - self - } - pub fn with_args(name: &'a str, args: Vec>) -> Self { - Structure::with_args(name, args).into() - } - pub fn from_structure(structure: Structure<'a>, capabilities: Vec<&'a str>) -> Self { - Type { structure, capabilities } - } - pub fn new(name: &'a str) -> Self { - Structure::new(name).into() - } - pub fn with_arg(mut self, arg: Structure<'a>) -> Self { - self.structure = self.structure.with_arg(arg); - self - } -} - -impl <'a> From> for Type<'a> { - fn from(structure: Structure<'a>) -> Self { - Type::from_structure(structure, vec![]) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Structure<'a> { pub name: &'a str, - pub args: Vec>, + pub args: Vec>, } -impl<'a> Structure<'a> { - pub fn with_args(name: &'a str, args: Vec>) -> Self { +impl<'a> Type<'a> { + pub fn with_args(name: &'a str, args: Vec>) -> Self { Self { name, args } } pub fn new(name: &'a str) -> Self { Self::with_args(name, vec![]) } - pub fn with_arg(mut self, arg: Structure<'a>) -> Self { + pub fn with_arg(mut self, arg: Type<'a>) -> Self { self.args.push(arg); self } + pub fn with_capability(self, cap: &'a str) -> Self { + Type::new("ibis.WithCapability") + .with_arg(Type::new(cap)) + .with_arg(self) + } } fn format_arg_set<'a>( f: &mut std::fmt::Formatter<'_>, joiner: &str, - args: &[Structure<'a>], + args: &[Type<'a>], ) -> std::fmt::Result { - let mut first = true; - for arg in args { - if first { - first = false; - } else { - write!(f, "{}", joiner)?; - } - write!(f, "{}", arg)?; + if let Some(first) = args.first() { + write!(f, "{}", first)?; + } + for arg in args[1..].iter() { + write!(f, "{}{}", joiner, arg)?; } Ok(()) } impl<'a> std::fmt::Display for Type<'a> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - for cap in &self.capabilities { - write!(f, "{} ", cap)?; - } - write!(f, "{}", self.structure) - } -} - -impl<'a> std::fmt::Display for Structure<'a> { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if self.name == "ibis.Labelled" && self.args.len() > 1 { + if self.name == "ibis.WithCapability" && self.args.len() > 1 { + write!(f, "{} ", self.args[0])?; + if self.args.len() > 2 { + write!(f, "(")?; + } + format_arg_set(f, ", ", &self.args[1..])?; + if self.args.len() > 2 { + write!(f, ")")?; + } + Ok(()) + } else if self.name == "ibis.Labelled" && self.args.len() > 1 { write!(f, "{}: ", self.args[0])?; - let is_product = self.args[1].name == "ibis.ProductType"; - if is_product { + if self.args.len() > 2 { write!(f, "(")?; } format_arg_set(f, ", ", &self.args[1..])?; - if is_product { + if self.args.len() > 2 { write!(f, ")")?; } Ok(()) } else if self.name == "ibis.ProductType" && self.args.len() > 0 { - format_arg_set(f, " ", &self.args) + write!(f, "{{")?; + format_arg_set(f, ", ", &self.args)?; + write!(f, "}}") } else { let res = write!( f, From 8b3b2d9df957a6fa138c0ab02e9c7f08dc4c296c Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 16:01:51 +1000 Subject: [PATCH 11/20] Use or_else and reorder for clarity Change-Id: I7024bac672a844338c23d0cb73a85514b19b62ed --- ibis/src/type_parser.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index b21d904d6..0d8709d2a 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -58,16 +58,7 @@ fn parenthesized(input: &str) -> IResult<&str, Type> { Ok((input, ty)) } -fn structure(input: &str) -> IResult<&str, Type> { - if let Ok(res) = labelled_type(input) { - return Ok(res); - } - if let Ok(res) = entity(input) { - return Ok(res); - } - if let Ok(res) = parenthesized(input) { - return Ok(res); - } +fn simple_structure(input: &str) -> IResult<&str, Type> { let (input, (mut name, args)) = tuple((name, opt(type_args)))(input)?; if name == "*" { name = "ibis.UniversalType"; @@ -75,6 +66,19 @@ fn structure(input: &str) -> IResult<&str, Type> { Ok((input, Type::with_args(name, args.unwrap_or_default()))) } +fn structure(input: &str) -> IResult<&str, Type> { + parenthesized(input) + .or_else(|_| { + entity(input) + }) + .or_else(|_| { + labelled_type(input) + }) + .or_else(|_| { + simple_structure(input) + }) +} + fn labelled_type(input: &str) -> IResult<&str, Type> { let (input, (label, structure)) = tuple((label, structure))(input)?; Ok(( input, From 1927f043991031778d1381dff0f9b958da62bba6 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 16:02:27 +1000 Subject: [PATCH 12/20] Fmt Change-Id: I411a4dbe399f053876a5f34164e1265895f8b8bb --- ibis/src/type_parser.rs | 80 ++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 42 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index 0d8709d2a..72d87af03 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -8,7 +8,7 @@ extern crate nom; use nom::{ bytes::complete::{tag, take_while1}, character::complete::{space0, space1}, - combinator::{opt, cut}, + combinator::{cut, opt}, multi::{separated_list0, separated_list1}, sequence::tuple, Finish, IResult, @@ -19,16 +19,16 @@ use crate::type_struct::Type; fn is_name_char(c: char) -> bool { match c { '(' | ')' | '{' | '}' | ',' | ':' => false, // Symbols - ' ' | '\n' | '\r' | '\t' => false, // Whitespace - _ => true // Name char + ' ' | '\n' | '\r' | '\t' => false, // Whitespace + _ => true, // Name char } } fn is_lower_char(c: char) -> bool { match c { 'a'..='z' => true, // a to z - '_' => true, // underscore - _ => false // Name char + '_' => true, // underscore + _ => false, // Name char } } @@ -48,8 +48,11 @@ fn label(input: &str) -> IResult<&str, &str> { } fn type_args(input: &str) -> IResult<&str, Vec> { - let (input, (_, args, _)) = - tuple((tag("("), cut(separated_list0(tag(","), structure)), tag(")")))(input)?; + let (input, (_, args, _)) = tuple(( + tag("("), + cut(separated_list0(tag(","), structure)), + tag(")"), + ))(input)?; Ok((input, args)) } @@ -68,30 +71,31 @@ fn simple_structure(input: &str) -> IResult<&str, Type> { fn structure(input: &str) -> IResult<&str, Type> { parenthesized(input) - .or_else(|_| { - entity(input) - }) - .or_else(|_| { - labelled_type(input) - }) - .or_else(|_| { - simple_structure(input) - }) + .or_else(|_| entity(input)) + .or_else(|_| labelled_type(input)) + .or_else(|_| simple_structure(input)) } fn labelled_type(input: &str) -> IResult<&str, Type> { let (input, (label, structure)) = tuple((label, structure))(input)?; - Ok(( input, - Type::new("ibis.Labelled") + Ok(( + input, + Type::new("ibis.Labelled") .with_arg(Type::new(label)) - .with_arg(structure) + .with_arg(structure), )) } fn entity(input: &str) -> IResult<&str, Type> { - let (input, (_, mut types, _)) = tuple((tag("{"), cut(separated_list1(tag(","), structure)), tag("}")))(input)?; + let (input, (_, mut types, _)) = tuple(( + tag("{"), + cut(separated_list1(tag(","), structure)), + tag("}"), + ))(input)?; let mut types: Vec = types.drain(0..).rev().collect(); - let mut ty = types.pop().expect("A structure requires at least one labelled type"); + let mut ty = types + .pop() + .expect("A structure requires at least one labelled type"); for new_ty in types { ty = Type::with_args("ibis.ProductType", vec![ty, new_ty]); } @@ -107,7 +111,9 @@ fn type_parser(input: &str) -> IResult<&str, Type> { pub fn read_type(og_input: &str) -> Type { // TODO: return errors instead of panics - let (input, ty) = type_parser(og_input).finish().expect("Could not parse type"); + let (input, ty) = type_parser(og_input) + .finish() + .expect("Could not parse type"); if !input.is_empty() { todo!( "Did not reach end of input. Read {:?}. Left over '{}' from '{}'", @@ -131,19 +137,12 @@ mod tests { #[test] fn read_a_simple_type_name() { - parse_and_round_trip( - "Type", - Type::new("Type") - ); + parse_and_round_trip("Type", Type::new("Type")); } #[test] fn read_a_type_with_a_single_capabilities() { - parse_and_round_trip( - "read Type", - Type::new("Type") - .with_capability("read") - ); + parse_and_round_trip("read Type", Type::new("Type").with_capability("read")); } #[test] @@ -152,7 +151,7 @@ mod tests { "read write Type", Type::new("Type") .with_capability("write") - .with_capability("read") + .with_capability("read"), ); } @@ -164,7 +163,7 @@ mod tests { "{name: String, age: Number}", Type::new("ibis.ProductType") .with_arg(name_string) - .with_arg(age_number) + .with_arg(age_number), ); } @@ -179,8 +178,8 @@ mod tests { .with_arg( Type::new("ibis.ProductType") .with_arg(json) - .with_arg(age_number) - ) + .with_arg(age_number), + ), ); } @@ -190,7 +189,7 @@ mod tests { "Type(a, b)", Type::new("Type") .with_arg(Type::new("a")) - .with_arg(Type::new("b")) + .with_arg(Type::new("b")), ); } @@ -199,11 +198,8 @@ mod tests { parse_and_round_trip( "Type(a(c), b)", Type::new("Type") - .with_arg( - Type::new("a") - .with_arg(Type::new("c")), - ) - .with_arg(Type::new("b")) + .with_arg(Type::new("a").with_arg(Type::new("c"))) + .with_arg(Type::new("b")), ); } @@ -213,7 +209,7 @@ mod tests { "name: Type", Type::new("ibis.Labelled") .with_arg(Type::new("name")) - .with_arg(Type::new("Type")) + .with_arg(Type::new("Type")), ); } From 9767548ff4738c4b7e5522a05cf8e142b6710c9a Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 16:11:57 +1000 Subject: [PATCH 13/20] A little renaming and re-ordering and use of or_else Change-Id: Ie6b5ca4fecf586702cba62ec9aaedbef8b81d027 --- ibis/src/type_parser.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index 72d87af03..bd3310f18 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -69,15 +69,8 @@ fn simple_structure(input: &str) -> IResult<&str, Type> { Ok((input, Type::with_args(name, args.unwrap_or_default()))) } -fn structure(input: &str) -> IResult<&str, Type> { - parenthesized(input) - .or_else(|_| entity(input)) - .or_else(|_| labelled_type(input)) - .or_else(|_| simple_structure(input)) -} - fn labelled_type(input: &str) -> IResult<&str, Type> { - let (input, (label, structure)) = tuple((label, structure))(input)?; + let (input, (label, structure)) = tuple((label, cut(structure)))(input)?; Ok(( input, Type::new("ibis.Labelled") @@ -86,7 +79,7 @@ fn labelled_type(input: &str) -> IResult<&str, Type> { )) } -fn entity(input: &str) -> IResult<&str, Type> { +fn product_type(input: &str) -> IResult<&str, Type> { let (input, (_, mut types, _)) = tuple(( tag("{"), cut(separated_list1(tag(","), structure)), @@ -102,11 +95,20 @@ fn entity(input: &str) -> IResult<&str, Type> { Ok((input, ty)) } +fn structure(input: &str) -> IResult<&str, Type> { + parenthesized(input) + .or_else(|_| product_type(input)) + .or_else(|_| labelled_type(input)) + .or_else(|_| simple_structure(input)) +} + +fn structure_with_capability(input: &str) -> IResult<&str, Type> { + let (input, (cap, _, ty)) = tuple((capability, space0, type_parser))(input)?; + Ok((input, ty.with_capability(cap))) +} + fn type_parser(input: &str) -> IResult<&str, Type> { - if let Ok((input, (cap, _, ty))) = tuple((capability, space0, type_parser))(input) { - return Ok((input, ty.with_capability(cap))); - } - structure(input) + structure_with_capability(input).or_else(|_| structure(input)) } pub fn read_type(og_input: &str) -> Type { From 4043c525351de9a824aa2cbf6b7415e40424f29f Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 16:53:32 +1000 Subject: [PATCH 14/20] Bug fixes Change-Id: I42f2e1dc786c42f1f3045a4f2181c79eb7694b16 --- ibis/src/lib.rs | 26 ++++++++++++++++++++++++-- ibis/src/recipes.rs | 44 ++++++++++++++++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/ibis/src/lib.rs b/ibis/src/lib.rs index 820819e3e..0e539594d 100644 --- a/ibis/src/lib.rs +++ b/ibis/src/lib.rs @@ -61,7 +61,17 @@ macro_rules! is_a { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ty.name == $parent.name() + ty.name == $parent.name() && ty.args.len() > 0 + }}; +} + +#[macro_export] +macro_rules! name { + ($type: expr) => {{ + use crate::type_parser::read_type; + let name = $type.name(); + let ty = read_type(&name); + ent!(&format!("{}", ty.name)) }}; } @@ -71,7 +81,19 @@ macro_rules! arg { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ent!(&format!("{}", ty.args[$ind])) + let ind = $ind; + if ind >= ty.args.len() { + panic!("Cannot access argument {} of {}", ind, name); + } + ent!(&format!("{}", ty.args[ind])) + }}; +} + +#[macro_export] +macro_rules! args { + ($type: expr) => {{ + use crate::type_parser::read_type; + read_type(&$type.name()).args.iter().map(|arg| ent!(&format!("{}", arg))) }}; } diff --git a/ibis/src/recipes.rs b/ibis/src/recipes.rs index 367317cfe..ee4745ffa 100644 --- a/ibis/src/recipes.rs +++ b/ibis/src/recipes.rs @@ -1,5 +1,5 @@ use crate::util::make; -use crate::{apply, arg, ent, ibis, is_a, Ent, Sol, SolutionData, ToInput}; +use crate::{apply, arg, args, name, ent, ibis, is_a, Ent, Sol, SolutionData, ToInput}; use serde::{Deserialize, Serialize}; ibis! { @@ -11,6 +11,7 @@ ibis! { Capability(Ent, Ent); // cap from, cap to Subtype(Ent, Ent); // sub, super CompatibleWith(Ent, Ent); // from, to + HasCapability(Ent, Ent); // cap, ty Node(Ent, Ent, Ent); // particle-identifier, identifier, capability, type Claim(Ent, Ent); // identifier, tag Check(Ent, Ent); // identifier, tag @@ -27,17 +28,41 @@ ibis! { Capability(from_capability, to_capability), Node(from_particle, from, from_type), Node(to_particle, to, to_type), - ({eprintln!("{}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), - Subtype(from_type, from_capability), - ({eprintln!(" {}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), - Subtype(to_type, to_capability), - ({eprintln!(" {}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), CompatibleWith(from_type, to_type), - ({eprintln!(" {}, {}, {}. {}, {}, {}. {} to {}", &from_particle, &from, &from_type, &to_particle, &to, &to_type, &from_capability, &to_capability);true}), (from != to), UncheckedSolution(parent); - CompatibleWith(x, y) <- Subtype(x, y); + HasCapability(arg!(ty, 0), ty) <- + KnownType(ty), + (is_a!(ty, ent!("ibis.WithCapability"))); + + HasCapability(cap, ty) <- + KnownType(ty), + (is_a!(ty, ent!("ibis.WithCapability"))), + HasCapability(cap, arg!(ty, 1)); // Has all the child capabilities too. + + // Base case: just types. + CompatibleWith(x, y) <- + KnownType(x), + (!is_a!(x, ent!("ibis.WithCapability"))), + KnownType(y), + (!is_a!(y, ent!("ibis.WithCapability"))), + Subtype(x, y); + + CompatibleWith(x, y) <- // Check that y has the capabilities required by x. + KnownType(x), + (is_a!(x, ent!("ibis.WithCapability"))), + KnownType(y), + HasCapability(cap, y), // For each of the capabilities y supports + Capability(arg!(x, 0), cap), // If this one is supported we can continue. + CompatibleWith(arg!(x, 1), y); + + CompatibleWith(x, y) <- // If a type has no capabilities, discard the capabilities of it's possible super type. + KnownType(x), + (!is_a!(x, ent!("ibis.WithCapability"))), + KnownType(y), + (is_a!(y, ent!("ibis.WithCapability"))), + Subtype(x, arg!(y, 1)); Subtype( x, @@ -155,6 +180,8 @@ ibis! { !CapabilityError(s, _, _, _, _), !Leak(s, _, _, _, _); + KnownType(name!(ty)) <- KnownType(ty); // Types without their arguments are still types + KnownType(arg) <- KnownType(ty), for arg in args!(ty); // Types arguments are types KnownType(x) <- Node(_par, _node, x); // Infer types that are used in the recipes. KnownType(x) <- Subtype(x, _); KnownType(y) <- Subtype(_, y); @@ -393,6 +420,7 @@ impl Ibis { mut capabilities, mut subtypes, _compatible_with, + _has_capability, nodes, claims, checks, From 5965967430315068cbbbfa01444b12010802efb8 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 17:25:16 +1000 Subject: [PATCH 15/20] Working again Change-Id: I2ebdc5f06f99489612b9ebdb8aebbcdb16d84f6e --- ibis/demo.json | 10 ++++++++-- ibis/src/recipes.rs | 30 +++++++----------------------- ibis/src/type_parser.rs | 28 +++++++++++++--------------- ibis/tests/graphs.rs | 8 ++++---- ibis/tests/product_types.rs | 6 +++--- 5 files changed, 35 insertions(+), 47 deletions(-) diff --git a/ibis/demo.json b/ibis/demo.json index 900266b38..32a7dbe15 100644 --- a/ibis/demo.json +++ b/ibis/demo.json @@ -25,17 +25,23 @@ "name": "demo" }, "nodes": [ - ["p_a", "a", "write Int + private"], + ["p_a", "a", "write Int"], ["p_b", "b", "any Number"], ["p_c", "c", "write String"], ["p_de", "d", "read Serializable"], - ["p_de", "e", "read ibis.UnionType(Number, String) + public"], + ["p_de", "e", "read ibis.UnionType(Number, String)"], ["p_f", "f", "write {name: String, age: Int}"], ["p_g", "g", "read {name: *}"], ["p_h", "h", "read {name: String, age: Int}"], ["p_i", "i", "read {name: String}"], ["p_j", "j", "read {age: Int}"] ], + "claims": [ + ["a", "private"] + ], + "checks": [ + ["e", "pubic"] + ], "edges": [ ["b", "e"] ], diff --git a/ibis/src/recipes.rs b/ibis/src/recipes.rs index ee4745ffa..72c325602 100644 --- a/ibis/src/recipes.rs +++ b/ibis/src/recipes.rs @@ -21,15 +21,14 @@ ibis! { HasTag(Sol, Ent, Ent, Ent); // solution, source node, node with tag, tag Leak(Sol, Ent, Ent, Ent, Ent); // sol, node, expected_tag, source, tag2 TypeError(Sol, Ent, Ent, Ent, Ent); // sol, node, ty, source, ty - CapabilityError(Sol, Ent, Ent, Ent, Ent); // sol, node, cap, source, cap UncheckedSolution(parent.add_edge(from, to)) <- PlanningIsEnabled(true), - Capability(from_capability, to_capability), Node(from_particle, from, from_type), Node(to_particle, to, to_type), - CompatibleWith(from_type, to_type), (from != to), + CompatibleWith(from_type, to_type), + // ({eprintln!("Connecting {}: {} to {}: {}", from, from_type, to, to_type); true}), UncheckedSolution(parent); HasCapability(arg!(ty, 0), ty) <- @@ -47,6 +46,7 @@ ibis! { (!is_a!(x, ent!("ibis.WithCapability"))), KnownType(y), (!is_a!(y, ent!("ibis.WithCapability"))), + // ({eprintln!("checking subtyping ({}) ({})", x, y); true}), Subtype(x, y); CompatibleWith(x, y) <- // Check that y has the capabilities required by x. @@ -54,6 +54,7 @@ ibis! { (is_a!(x, ent!("ibis.WithCapability"))), KnownType(y), HasCapability(cap, y), // For each of the capabilities y supports + // ({eprintln!("checking y has cap ({}) ({})", x, y); true}), Capability(arg!(x, 0), cap), // If this one is supported we can continue. CompatibleWith(arg!(x, 1), y); @@ -62,7 +63,8 @@ ibis! { (!is_a!(x, ent!("ibis.WithCapability"))), KnownType(y), (is_a!(y, ent!("ibis.WithCapability"))), - Subtype(x, arg!(y, 1)); + // ({eprintln!("discarding capability from y ({}) ({})", x, y); true}), + CompatibleWith(x, arg!(y, 1)); Subtype( x, @@ -163,21 +165,11 @@ ibis! { for (from, to) in &s.solution().edges, Node(_from_p, *from, from_ty), Node(_to_p, *to, to_ty), - !Subtype(from_ty, to_ty); // Check failed, from writes an incompatible type into to - - CapabilityError(s, *from, from_capability, *to, to_capability) <- - UncheckedSolution(s), - for (from, to) in &s.solution().edges, - Node(_from_p, *from, from_type), - Node(_to_p, *to, to_type), - Capability(from_capability, to_capability), - !Subtype(from_type, from_capability), - !Subtype(to_type, to_capability); // Check failed, from writes an incompatible type into to + !CompatibleWith(from_ty, to_ty); // Check failed, from writes an incompatible type into to Solution(s) <- UncheckedSolution(s), !TypeError(s, _, _, _, _), - !CapabilityError(s, _, _, _, _), !Leak(s, _, _, _, _); KnownType(name!(ty)) <- KnownType(ty); // Types without their arguments are still types @@ -226,8 +218,6 @@ pub struct Feedback { #[serde(default, skip_serializing_if = "is_default")] pub type_errors: Vec, #[serde(default, skip_serializing_if = "is_default")] - pub capability_errors: Vec, - #[serde(default, skip_serializing_if = "is_default")] pub has_tags: Vec, } @@ -428,7 +418,6 @@ impl Ibis { has_tags, leaks, type_errors, - capability_errors, ) = runtime.run(); let recipes: Vec = if self.config.flags.planning { solutions.iter().map(|Solution(s)| *s).collect() @@ -452,11 +441,6 @@ impl Ibis { .filter(|TypeError(type_s, _, _, _, _)| type_s == s) .cloned() .collect(), - capability_errors: capability_errors - .iter() - .filter(|CapabilityError(cap_s, _, _, _, _)| cap_s == s) - .cloned() - .collect(), has_tags: has_tags .iter() .filter(|HasTag(has_tag_s, _, _, _)| has_tag_s == s) diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index bd3310f18..abe877f42 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -50,14 +50,14 @@ fn label(input: &str) -> IResult<&str, &str> { fn type_args(input: &str) -> IResult<&str, Vec> { let (input, (_, args, _)) = tuple(( tag("("), - cut(separated_list0(tag(","), structure)), + cut(separated_list0(tag(","), type_parser)), tag(")"), ))(input)?; Ok((input, args)) } fn parenthesized(input: &str) -> IResult<&str, Type> { - let (input, (_, _, ty, _)) = tuple((opt(space0), tag("("), cut(structure), tag(")")))(input)?; + let (input, (_, _, ty, _)) = tuple((opt(space0), tag("("), cut(type_parser), tag(")")))(input)?; Ok((input, ty)) } @@ -70,45 +70,43 @@ fn simple_structure(input: &str) -> IResult<&str, Type> { } fn labelled_type(input: &str) -> IResult<&str, Type> { - let (input, (label, structure)) = tuple((label, cut(structure)))(input)?; + let (input, (label, ty)) = tuple((label, cut(type_parser)))(input)?; Ok(( input, Type::new("ibis.Labelled") .with_arg(Type::new(label)) - .with_arg(structure), + .with_arg(ty), )) } fn product_type(input: &str) -> IResult<&str, Type> { let (input, (_, mut types, _)) = tuple(( tag("{"), - cut(separated_list1(tag(","), structure)), + cut(separated_list1(tag(","), type_parser)), tag("}"), ))(input)?; let mut types: Vec = types.drain(0..).rev().collect(); let mut ty = types .pop() - .expect("A structure requires at least one labelled type"); + .expect("A product type requires at least one type"); for new_ty in types { ty = Type::with_args("ibis.ProductType", vec![ty, new_ty]); } Ok((input, ty)) } -fn structure(input: &str) -> IResult<&str, Type> { - parenthesized(input) - .or_else(|_| product_type(input)) - .or_else(|_| labelled_type(input)) - .or_else(|_| simple_structure(input)) -} - fn structure_with_capability(input: &str) -> IResult<&str, Type> { - let (input, (cap, _, ty)) = tuple((capability, space0, type_parser))(input)?; + let (input, (cap, _, ty)) = tuple((capability, space0, cut(type_parser)))(input)?; Ok((input, ty.with_capability(cap))) } fn type_parser(input: &str) -> IResult<&str, Type> { - structure_with_capability(input).or_else(|_| structure(input)) + let (input, _) = space0(input)?; + parenthesized(input) + .or_else(|_| product_type(input)) + .or_else(|_| labelled_type(input)) + .or_else(|_| structure_with_capability(input)) + .or_else(|_| simple_structure(input)) } pub fn read_type(og_input: &str) -> Type { diff --git a/ibis/tests/graphs.rs b/ibis/tests/graphs.rs index c65d3da41..ca12fee7b 100644 --- a/ibis/tests/graphs.rs +++ b/ibis/tests/graphs.rs @@ -22,10 +22,10 @@ fn create_combinations() { "recipes": [ { "nodes": [ - ["p_a", "a", "write"], - ["p_b", "b", "write"], - ["p_c", "c", "write"], - ["p_out", "out", "read"] + ["p_a", "a", "write Unit"], + ["p_b", "b", "write Unit"], + ["p_c", "c", "write Unit"], + ["p_out", "out", "read Unit"] ] } ] diff --git a/ibis/tests/product_types.rs b/ibis/tests/product_types.rs index fad6311a7..37013f4dc 100644 --- a/ibis/tests/product_types.rs +++ b/ibis/tests/product_types.rs @@ -22,7 +22,7 @@ fn a_product_is_a_subtype_of_its_arguments() { "recipes": [ { "nodes": [ - ["p_a", "a", "any Man Mortal"], + ["p_a", "a", "any {Man, Mortal}"], ["p_b", "b", "any Mortal"], ["p_c", "c", "any Man"] ] @@ -52,7 +52,7 @@ fn a_type_is_a_subtype_of_products_of_its_super_types() { "recipes": [ { "nodes": [ - ["p_a", "a", "any Human Mortal"], + ["p_a", "a", "any {Human, Mortal}"], ["p_b", "b", "any Man"] ] } @@ -80,7 +80,7 @@ fn a_type_is_equal_to_the_product_of_it_and_its_super_types() { "recipes": [ { "nodes": [ - ["p_a", "a", "any Man Mortal"], + ["p_a", "a", "any {Man, Mortal}"], ["p_b", "b", "any Man"] ] } From 37211ee33c54f58e871da25a868828f1fe809fcd Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 17:29:45 +1000 Subject: [PATCH 16/20] Show JSON in error and also update tests Change-Id: Ie40c1449f06a48800692d1df10ab7006054f4cdb --- ibis/benches/checking_only.rs | 20 ++++++++++---------- ibis/src/lib.rs | 5 ++++- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/ibis/benches/checking_only.rs b/ibis/benches/checking_only.rs index 56132632c..5c643a4da 100644 --- a/ibis/benches/checking_only.rs +++ b/ibis/benches/checking_only.rs @@ -34,16 +34,16 @@ pub fn criterion_benchmark_checking_only(c: &mut Criterion) { "recipes": [ { "nodes": [ - ["p_a", "a", "write", "Int"], - ["p_b", "b", "any", "Number"], - ["p_c", "c", "write", "String"], - ["p_de", "d", "read", "Serializable"], - ["p_de", "e", "read", "ibis.UnionType(Number, String)"], - ["p_f", "f", "write", "{name: String, age: Int}"], - ["p_g", "g", "read", "{name: *"], - ["p_h", "h", "read", "{name: String, age: Int}"], - ["p_i", "i", "read", "{name: String}"], - ["p_j", "j", "read", "{age: Int}"] + ["p_a", "a", "write Int"], + ["p_b", "b", "any Number"], + ["p_c", "c", "write String"], + ["p_de", "d", "read Serializable"], + ["p_de", "e", "read ibis.UnionType(Number, String)"], + ["p_f", "f", "write {name: String, age: Int}"], + ["p_g", "g", "read {name: *"], + ["p_h", "h", "read {name: String, age: Int}"], + ["p_i", "i", "read {name: String}"], + ["p_j", "j", "read {age: Int}"] ], "claims": [ ["a", "private"] diff --git a/ibis/src/lib.rs b/ibis/src/lib.rs index 0e539594d..10c3d8e1a 100644 --- a/ibis/src/lib.rs +++ b/ibis/src/lib.rs @@ -114,7 +114,10 @@ pub fn get_solutions(data: &str, loss: Option) -> Ibis { let mut runtime = Ibis::new(); // TODO: Use ibis::Error and https://serde.rs/error-handling.html instead of expect. - let recipes: Ibis = serde_json::from_str(data).expect("JSON Error?"); + let recipes: Ibis = serde_json::from_str(data).map_err(|e| { + eprintln!("{}", data); + e + }).expect("JSON Error?"); runtime.add_recipes(recipes); runtime.extract_solutions_with_loss(loss) From 4cb0fd3613286898ed7de878eb38bcdc4352bfd9 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Mon, 11 Apr 2022 17:35:22 +1000 Subject: [PATCH 17/20] Update benches Change-Id: I10c6614d358226c1263118d9cd909c8a51017800 --- ibis/benches/checking_and_planning.rs | 20 ++++++++++---------- ibis/benches/checking_only.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/ibis/benches/checking_and_planning.rs b/ibis/benches/checking_and_planning.rs index f2bccd55c..d6f6fedea 100644 --- a/ibis/benches/checking_and_planning.rs +++ b/ibis/benches/checking_and_planning.rs @@ -34,16 +34,16 @@ pub fn criterion_benchmark_noop_planning(c: &mut Criterion) { "recipes": [ { "nodes": [ - ["p_a", "a", "write", "Int"], - ["p_b", "b", "any", "Number"], - ["p_c", "c", "write", "String"], - ["p_de", "d", "read", "Serializable"], - ["p_de", "e", "read", "ibis.UnionType(Number, String)"], - ["p_f", "f", "write", "{name: String, age: Int}"], - ["p_g", "g", "read", "{name: *}"], - ["p_h", "h", "read", "{name: String, age: Int}"], - ["p_i", "i", "read", "{name: String}"], - ["p_j", "j", "read", "{age: Int}"] + ["p_a", "a", "write Int"], + ["p_b", "b", "any Number"], + ["p_c", "c", "write String"], + ["p_de", "d", "read Serializable"], + ["p_de", "e", "read ibis.UnionType(Number, String)"], + ["p_f", "f", "write {name: String, age: Int}"], + ["p_g", "g", "read {name: *}"], + ["p_h", "h", "read {name: String, age: Int}"], + ["p_i", "i", "read {name: String}"], + ["p_j", "j", "read {age: Int}"] ], "claims": [ ["a", "private"] diff --git a/ibis/benches/checking_only.rs b/ibis/benches/checking_only.rs index 5c643a4da..c535222ad 100644 --- a/ibis/benches/checking_only.rs +++ b/ibis/benches/checking_only.rs @@ -40,7 +40,7 @@ pub fn criterion_benchmark_checking_only(c: &mut Criterion) { ["p_de", "d", "read Serializable"], ["p_de", "e", "read ibis.UnionType(Number, String)"], ["p_f", "f", "write {name: String, age: Int}"], - ["p_g", "g", "read {name: *"], + ["p_g", "g", "read {name: *}"], ["p_h", "h", "read {name: String, age: Int}"], ["p_i", "i", "read {name: String}"], ["p_j", "j", "read {age: Int}"] From dafb2246c990abb1b4160f738c0ac0cd26230683 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Tue, 12 Apr 2022 11:18:23 +1000 Subject: [PATCH 18/20] Add ebnf doc Change-Id: I3273077e28cb3d783abd58d1e5c60409a98e31a3 --- ibis/docs/idealised_grammar.md | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 ibis/docs/idealised_grammar.md diff --git a/ibis/docs/idealised_grammar.md b/ibis/docs/idealised_grammar.md new file mode 100644 index 000000000..cce59cdd1 --- /dev/null +++ b/ibis/docs/idealised_grammar.md @@ -0,0 +1,45 @@ +# Idealised language EBNF + +The follow can be used with ebnf tooling like https://matthijsgroen.github.io/ebnf2railroad/try-yourself.html + +```ebnf +grammar = type; +type = {capability, " " }, structure, {" + ", tag}; + +tag=label; +capability = label; +structure = "*" | parenthesized | product | simple; + +simple = type_name, [args]; +args = "(", type, {",", type}, ")"; + +named = label, ": ", type; + +parenthesized = "(", type, ")"; + +product = "{", (named | type), {",", (named | type)}, "}"; +union = "(", type, {"|", type }, ")"; + +label = lower_letter , { letter | digit | "_" }; +type_name = upper_letter , { letter | digit | "_" }; + +(* + Basic components + ---------------- + These are low level components, the small building blocks. +*) + +letter = upper_letter | lower_letter ; + +upper_letter = "A" | "B" | "C" | "D" | "E" | "F" | "G" + | "H" | "I" | "J" | "K" | "L" | "M" | "N" + | "O" | "P" | "Q" | "R" | "S" | "T" | "U" + | "V" | "W" | "X" | "Y" | "Z"; +lower_letter = "a" | "b" + | "c" | "d" | "e" | "f" | "g" | "h" | "i" + | "j" | "k" | "l" | "m" | "n" | "o" | "p" + | "q" | "r" | "s" | "t" | "u" | "v" | "w" + | "x" | "y" | "z" ; + +digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; +``` From 4625590a71b8b806fa142bda0078262617219224 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Wed, 13 Apr 2022 15:01:27 +1000 Subject: [PATCH 19/20] Fmt Change-Id: I4df4794eba7ab9ffe120d2896e704ca3f886dad1 --- ibis/src/lib.rs | 15 ++++++++++----- ibis/src/recipes.rs | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/ibis/src/lib.rs b/ibis/src/lib.rs index 10c3d8e1a..d4a4ce309 100644 --- a/ibis/src/lib.rs +++ b/ibis/src/lib.rs @@ -93,7 +93,10 @@ macro_rules! arg { macro_rules! args { ($type: expr) => {{ use crate::type_parser::read_type; - read_type(&$type.name()).args.iter().map(|arg| ent!(&format!("{}", arg))) + read_type(&$type.name()) + .args + .iter() + .map(|arg| ent!(&format!("{}", arg))) }}; } @@ -114,10 +117,12 @@ pub fn get_solutions(data: &str, loss: Option) -> Ibis { let mut runtime = Ibis::new(); // TODO: Use ibis::Error and https://serde.rs/error-handling.html instead of expect. - let recipes: Ibis = serde_json::from_str(data).map_err(|e| { - eprintln!("{}", data); - e - }).expect("JSON Error?"); + let recipes: Ibis = serde_json::from_str(data) + .map_err(|e| { + eprintln!("{}", data); + e + }) + .expect("JSON Error?"); runtime.add_recipes(recipes); runtime.extract_solutions_with_loss(loss) diff --git a/ibis/src/recipes.rs b/ibis/src/recipes.rs index 72c325602..c79e220c8 100644 --- a/ibis/src/recipes.rs +++ b/ibis/src/recipes.rs @@ -1,5 +1,5 @@ use crate::util::make; -use crate::{apply, arg, args, name, ent, ibis, is_a, Ent, Sol, SolutionData, ToInput}; +use crate::{apply, arg, args, ent, ibis, is_a, name, Ent, Sol, SolutionData, ToInput}; use serde::{Deserialize, Serialize}; ibis! { From de9dcc92a3083d9b2df446fc6bd1349c584651b5 Mon Sep 17 00:00:00 2001 From: J Pratt Date: Wed, 13 Apr 2022 15:04:06 +1000 Subject: [PATCH 20/20] Fmt Change-Id: I8a5dbb71a902b5436b02152d7ea50140109c565a --- ibis/src/lib.rs | 2 +- ibis/src/type_parser.rs | 15 +++++---------- ibis/src/type_struct.rs | 2 +- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/ibis/src/lib.rs b/ibis/src/lib.rs index d4a4ce309..a18ceef08 100644 --- a/ibis/src/lib.rs +++ b/ibis/src/lib.rs @@ -61,7 +61,7 @@ macro_rules! is_a { use crate::type_parser::read_type; let name = $type.name(); let ty = read_type(&name); - ty.name == $parent.name() && ty.args.len() > 0 + ty.name == $parent.name() && !ty.args.is_empty() }}; } diff --git a/ibis/src/type_parser.rs b/ibis/src/type_parser.rs index abe877f42..b805d3b71 100644 --- a/ibis/src/type_parser.rs +++ b/ibis/src/type_parser.rs @@ -17,19 +17,14 @@ use nom::{ use crate::type_struct::Type; fn is_name_char(c: char) -> bool { - match c { - '(' | ')' | '{' | '}' | ',' | ':' => false, // Symbols - ' ' | '\n' | '\r' | '\t' => false, // Whitespace - _ => true, // Name char - } + !matches!( + c, + '(' | ')' | '{' | '}' | ',' | ':' | ' ' | '\n' | '\r' | '\t' + ) } fn is_lower_char(c: char) -> bool { - match c { - 'a'..='z' => true, // a to z - '_' => true, // underscore - _ => false, // Name char - } + matches!(c, 'a'..='z' | '_') } fn name(input: &str) -> IResult<&str, &str> { diff --git a/ibis/src/type_struct.rs b/ibis/src/type_struct.rs index 186cdb1d7..4ff0ae0a0 100644 --- a/ibis/src/type_struct.rs +++ b/ibis/src/type_struct.rs @@ -64,7 +64,7 @@ impl<'a> std::fmt::Display for Type<'a> { write!(f, ")")?; } Ok(()) - } else if self.name == "ibis.ProductType" && self.args.len() > 0 { + } else if self.name == "ibis.ProductType" && !self.args.is_empty() { write!(f, "{{")?; format_arg_set(f, ", ", &self.args)?; write!(f, "}}")