From 71385038edcac3ad377d5393bcaec2df59146745 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Wed, 29 Sep 2021 17:20:09 -0400 Subject: [PATCH 01/24] initial faker module --- Cargo.toml | 4 +- src/faker.rs | 205 +++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 3 + 3 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 src/faker.rs diff --git a/Cargo.toml b/Cargo.toml index 2196da2c..56357403 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,8 @@ pest_vm = "2.1.0" displaydoc = { version = "0.2.3", default-features = false } log = "0.4.14" simplelog = "0.10.0" +fake = { version = "2.4.0", optional = true, features = ["derive", "chrono"] } +rand = { version = "0.8.0", optional = true } [dev-dependencies] indoc = "1.0.3" @@ -54,7 +56,7 @@ wasm-bindgen-test = "0.3.25" [features] default = ["std", "ast-span", "ast-comments", "json", "cbor", "additional-controls"] -std = ["base16/alloc", "base64/alloc", "serde_json", "ciborium", "serde", "chrono", "wasm-bindgen", "clap", "crossterm", "uriparse", "base64-url", "regex-syntax"] +std = ["base16/alloc", "base64/alloc", "serde_json", "ciborium", "serde", "chrono", "wasm-bindgen", "clap", "crossterm", "uriparse", "base64-url", "regex-syntax", "fake", "rand"] lsp = ["std"] additional-controls = [] ast-span = [] diff --git a/src/faker.rs b/src/faker.rs new file mode 100644 index 00000000..8fbaee10 --- /dev/null +++ b/src/faker.rs @@ -0,0 +1,205 @@ +use crate::{ + ast::*, + cddl_from_str, lexer_from_str, + token::{lookup_ident, Token}, + validator::{group_rule_from_ident, rule_from_ident}, + visitor::{self, walk_group, walk_memberkey, walk_type2, walk_value_member_key_entry, Visitor}, +}; + +use std::{collections::HashMap, fmt}; + +use displaydoc::Display; +use fake::{Dummy, Fake, Faker as FFaker}; +use rand::{rngs::StdRng, SeedableRng}; +use serde::Deserialize; +use serde_json::{self, Map, Value}; + +pub type Result = std::result::Result; + +#[derive(Debug, Display)] +pub enum Error { + #[displaydoc("no type rules found in the cddl document")] + MissingTypeRules, + #[displaydoc("{0}")] + Utf8Error(std::str::Utf8Error), + #[displaydoc("error parsing cddl: {0}")] + CDDLParsing(String), +} + +#[cfg(feature = "std")] +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + None + } +} + +pub struct Faker<'a> { + pub cddl: &'a CDDL<'a>, + pub faked_json: Option, + pub map_entries: Option, Type<'a>)>>, +} + +impl<'a> Faker<'a> { + pub fn new(cddl: &'a CDDL) -> Self { + Faker { + cddl, + faked_json: None, + map_entries: None, + } + } +} + +impl<'a> Visitor<'a, Error> for Faker<'a> { + fn visit_value_member_key_entry( + &mut self, + entry: &ValueMemberKeyEntry<'a>, + ) -> visitor::Result { + let occur = entry.occur.clone().map(|o| o.occur); + + if let Some(mk) = &entry.member_key { + match mk { + MemberKey::Bareword { ident, .. } => { + let mut map_entries = HashMap::new(); + map_entries.insert( + ident.ident.to_string(), + (occur.clone(), entry.entry_type.clone()), + ); + + self + .map_entries + .get_or_insert(map_entries) + .insert(ident.ident.to_string(), (occur, entry.entry_type.clone())); + } + MemberKey::Value { value, .. } => { + let mut map_entries = HashMap::new(); + map_entries.insert(value.to_string(), (occur.clone(), entry.entry_type.clone())); + + self + .map_entries + .get_or_insert(map_entries) + .insert(value.to_string(), (occur, entry.entry_type.clone())); + } + _ => return Ok(()), + } + } + + Ok(()) + } + + fn visit_type2(&mut self, t2: &Type2<'a>) -> visitor::Result { + match t2 { + Type2::TextValue { value, .. } => { + if let Some(Value::Array(array)) = self.faked_json.as_mut() { + array.push(value.as_ref().into()); + } else { + self.faked_json = Some(value.as_ref().into()); + } + } + Type2::UTF8ByteString { value, .. } => { + let value = std::str::from_utf8(value.as_ref()).map_err(Error::Utf8Error)?; + + if let Some(Value::Array(array)) = self.faked_json.as_mut() { + array.push(value.into()); + } else { + self.faked_json = Some(value.into()); + } + } + Type2::Array { group, .. } => { + let mut f = Faker::new(self.cddl); + f.faked_json = Some(Value::Array(Vec::new())); + f.visit_group(group)?; + + self.faked_json = f.faked_json; + } + Type2::Map { group, .. } => { + let mut f = Faker::new(self.cddl); + f.faked_json = Some(Value::Object(Map::new())); + f.visit_group(group)?; + + if let Some(map_entries) = f.map_entries { + let mut entries = Map::new(); + for (k, (occur, v)) in map_entries.iter() { + let generate = if let Some(Occur::Optional(_)) = occur { + FFaker.fake::() + } else { + true + }; + + if generate { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(v)?; + + if let Some(value) = entry_f.faked_json { + entries.insert(k.to_string(), value); + } + } + } + self.faked_json = Some(Value::Object(entries)); + } + + self.map_entries = None; + } + _ => walk_type2(self, t2)?, + } + + Ok(()) + } + + fn visit_identifier(&mut self, ident: &Identifier<'a>) -> visitor::Result { + match lookup_ident(ident.ident) { + Token::TSTR => { + let value = FFaker.fake::(); + + if let Some(Value::Array(array)) = self.faked_json.as_mut() { + array.push(value.into()); + } else { + self.faked_json = Some(value.into()); + } + } + _ => { + self.faked_json = Some(ident.ident.into()); + } + } + + Ok(()) + } +} + +pub fn fake_json_from_cddl_str(cddl_str: &str) -> Result { + let mut lexer = lexer_from_str(cddl_str); + let cddl = cddl_from_str(&mut lexer, cddl_str, true).map_err(Error::CDDLParsing)?; + let mut faker = Faker::new(&cddl); + + for rule in faker.cddl.rules.iter() { + if let Rule::Type { rule, .. } = rule { + faker.visit_type_rule(rule)?; + break; + } + } + + if let Some(faked_json) = faker.faked_json { + return Ok(faked_json.to_string()); + } + + Err(Error::MissingTypeRules) +} + +#[cfg(test)] +mod tests { + use super::*; + + use indoc::indoc; + + #[test] + fn test_faker() -> Result<()> { + let cddl = indoc!( + r#" + a = { 1: { a: { a: [ + tstr ] } } } + "# + ); + + println!("{}", fake_json_from_cddl_str(&cddl)?); + + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 856931c9..5bda9690 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -559,6 +559,9 @@ pub mod token; #[cfg(feature = "std")] pub mod validator; +#[cfg(feature = "std")] +pub mod faker; + /// CDDL AST visitor pub mod visitor; From b3797d166a4e143714efc3572c4a3698c20b8c1b Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Thu, 30 Sep 2021 13:10:52 -0400 Subject: [PATCH 02/24] faker updates and span refactor --- src/ast.rs | 63 ++++-- src/faker.rs | 201 ++++++++++++++----- src/parser.rs | 112 +++++------ src/parser_tests.rs | 480 ++++++++++++++++++++++---------------------- tests/parser.rs | 184 ++++++++--------- 5 files changed, 577 insertions(+), 463 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 6fd6b864..114a76b2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -20,7 +20,8 @@ use alloc::{ /// Starting index, ending index and line number #[cfg(feature = "ast-span")] -pub type Span = (usize, usize, usize); +#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] +pub struct Span(pub usize, pub usize, pub usize); #[cfg(feature = "ast-comments")] #[derive(Default, Debug, PartialEq, Clone)] @@ -179,7 +180,7 @@ impl<'a> From<&'static str> for Identifier<'a> { ident, socket: Some(SocketPlug::GROUP), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }; } } @@ -188,7 +189,7 @@ impl<'a> From<&'static str> for Identifier<'a> { ident, socket: Some(SocketPlug::TYPE), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }; } } @@ -197,7 +198,7 @@ impl<'a> From<&'static str> for Identifier<'a> { ident, socket: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), } } } @@ -513,7 +514,7 @@ impl<'a> Default for GenericParams<'a> { GenericParams { params: Vec::new(), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), } } } @@ -583,7 +584,7 @@ impl<'a> GenericArgs<'a> { GenericArgs { args: Vec::new(), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), } } } @@ -670,6 +671,28 @@ impl<'a> Type<'a> { } } +impl<'a> From<&Identifier<'a>> for Type<'a> { + fn from(ident: &Identifier<'a>) -> Self { + Type { + type_choices: vec![TypeChoice { + type1: Type1 { + type2: Type2::Typename { + ident: ident.clone(), + generic_args: None, + span: ident.span, + }, + operator: None, + span: ident.span, + comments_after_type: None, + }, + comments_before_type: None, + comments_after_type: None, + }], + span: ident.span, + } + } +} + /// Type choice #[cfg_attr(target_arch = "wasm32", derive(Serialize))] #[derive(Debug, Clone, PartialEq)] @@ -1521,7 +1544,7 @@ impl<'a> fmt::Display for Type2<'a> { impl<'a> From> for Type2<'a> { fn from(rv: RangeValue<'a>) -> Self { #[cfg(feature = "ast-span")] - let span = (0, 0, 0); + let span = Span::default(); match rv { RangeValue::IDENT(ident) => Type2::Typename { @@ -2877,7 +2900,7 @@ mod tests { leading_comments: None, trailing_comments: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), } .to_string(), "entry1".to_string() @@ -2899,7 +2922,7 @@ mod tests { comments: None, comments_after_colon: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -2907,24 +2930,24 @@ mod tests { type2: Type2::TextValue { value: "value1".into(), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, operator: None, comments_after_type: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, comments_before_type: None, comments_after_type: None, }], #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, }), leading_comments: None, trailing_comments: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, OptionalComma { optional_comma: true, @@ -2941,7 +2964,7 @@ mod tests { comments: None, comments_after_colon: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -2949,24 +2972,24 @@ mod tests { type2: Type2::TextValue { value: "value2".into(), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, operator: None, comments_after_type: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, comments_before_type: None, comments_after_type: None, }], #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, }), leading_comments: None, trailing_comments: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }, OptionalComma { optional_comma: true, @@ -2977,10 +3000,10 @@ mod tests { ], comments_before_grpchoice: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), }], #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span::default(), } .to_string(), " key1: \"value1\", key2: \"value2\", ".to_string() diff --git a/src/faker.rs b/src/faker.rs index 8fbaee10..066b0707 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -37,6 +37,7 @@ pub struct Faker<'a> { pub cddl: &'a CDDL<'a>, pub faked_json: Option, pub map_entries: Option, Type<'a>)>>, + pub array_entries: Option, Type<'a>)>>, } impl<'a> Faker<'a> { @@ -45,41 +46,43 @@ impl<'a> Faker<'a> { cddl, faked_json: None, map_entries: None, + array_entries: None, } } } impl<'a> Visitor<'a, Error> for Faker<'a> { + fn visit_type_groupname_entry( + &mut self, + entry: &TypeGroupnameEntry<'a>, + ) -> visitor::Result { + if let Some(entries) = self.array_entries.as_mut() { + entries.push(( + entry.occur.clone().map(|o| o.occur), + Type::from(&entry.name), + )); + } + + Ok(()) + } + fn visit_value_member_key_entry( &mut self, entry: &ValueMemberKeyEntry<'a>, ) -> visitor::Result { - let occur = entry.occur.clone().map(|o| o.occur); - - if let Some(mk) = &entry.member_key { - match mk { - MemberKey::Bareword { ident, .. } => { - let mut map_entries = HashMap::new(); - map_entries.insert( - ident.ident.to_string(), - (occur.clone(), entry.entry_type.clone()), - ); - - self - .map_entries - .get_or_insert(map_entries) - .insert(ident.ident.to_string(), (occur, entry.entry_type.clone())); - } - MemberKey::Value { value, .. } => { - let mut map_entries = HashMap::new(); - map_entries.insert(value.to_string(), (occur.clone(), entry.entry_type.clone())); - - self - .map_entries - .get_or_insert(map_entries) - .insert(value.to_string(), (occur, entry.entry_type.clone())); + if let Some(entries) = self.map_entries.as_mut() { + let occur = entry.occur.clone().map(|o| o.occur); + + if let Some(mk) = &entry.member_key { + match mk { + MemberKey::Bareword { ident, .. } => { + entries.insert(ident.ident.to_string(), (occur, entry.entry_type.clone())); + } + MemberKey::Value { value, .. } => { + entries.insert(value.to_string(), (occur.clone(), entry.entry_type.clone())); + } + _ => return Ok(()), } - _ => return Ok(()), } } @@ -105,36 +108,122 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } } Type2::Array { group, .. } => { - let mut f = Faker::new(self.cddl); - f.faked_json = Some(Value::Array(Vec::new())); - f.visit_group(group)?; + self.faked_json = Some(Value::Array(Vec::new())); + self.array_entries = Some(Vec::new()); + self.visit_group(group)?; + + if let Some(array_entries) = &self.array_entries { + if let Some(Value::Array(array)) = self.faked_json.as_mut() { + for (occur, entry) in array_entries.iter() { + if let Some(occur) = occur { + match occur { + Occur::Optional(_) => { + if FFaker.fake::() { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + + continue; + } + } + Occur::ZeroOrMore(_) => { + let lower = (0..2).fake::(); + let upper = (0..5).fake::(); + + // If the random lower >= random upper, the random array + // will be empty. + for _ in lower..upper { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + + // Break due to ambiguity + break; + } + Occur::OneOrMore(_) => { + for _ in 0..(1..5).fake::() { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + + // Break due to ambiguity + break; + } + Occur::Exact { lower, upper, .. } => { + if let Some(lower) = lower { + if let Some(upper) = upper { + for _ in *lower..*upper { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + } else { + for _ in *lower..(lower + (0..5).fake::()) { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + } + } else if let Some(upper) = upper { + for _ in 0..(upper - (0..=*upper).fake::()) { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + } + } + } + } + } + } + } - self.faked_json = f.faked_json; + self.array_entries = None; } Type2::Map { group, .. } => { - let mut f = Faker::new(self.cddl); - f.faked_json = Some(Value::Object(Map::new())); - f.visit_group(group)?; - - if let Some(map_entries) = f.map_entries { - let mut entries = Map::new(); - for (k, (occur, v)) in map_entries.iter() { - let generate = if let Some(Occur::Optional(_)) = occur { - FFaker.fake::() - } else { - true - }; - - if generate { - let mut entry_f = Faker::new(self.cddl); - entry_f.visit_type(v)?; - - if let Some(value) = entry_f.faked_json { - entries.insert(k.to_string(), value); + self.faked_json = Some(Value::Object(Map::default())); + self.map_entries = Some(HashMap::new()); + self.visit_group(group)?; + + if let Some(map_entries) = &self.map_entries { + if let Some(Value::Object(map)) = self.faked_json.as_mut() { + for (k, (occur, v)) in map_entries.iter() { + let generate = if let Some(Occur::Optional(_)) = occur { + FFaker.fake::() + } else { + true + }; + + if generate { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(v)?; + + if let Some(value) = entry_f.faked_json { + map.insert(k.to_string(), value); + } } } } - self.faked_json = Some(Value::Object(entries)); } self.map_entries = None; @@ -150,11 +239,13 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { Token::TSTR => { let value = FFaker.fake::(); - if let Some(Value::Array(array)) = self.faked_json.as_mut() { - array.push(value.into()); - } else { - self.faked_json = Some(value.into()); - } + // if let Some(Value::Array(array)) = self.faked_json.as_mut() { + // array.push(value.into()); + // } else { + // self.faked_json = Some(value.into()); + // } + + self.faked_json = Some(value.into()); } _ => { self.faked_json = Some(ident.ident.into()); @@ -194,7 +285,7 @@ mod tests { fn test_faker() -> Result<()> { let cddl = indoc!( r#" - a = { 1: { a: { a: [ + tstr ] } } } + a = { a: { a: [ *2 tstr ] } } "# ); diff --git a/src/parser.rs b/src/parser.rs index 90c2135c..2285c12b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -573,7 +573,7 @@ where self.advance_newline()?; #[cfg(feature = "ast-span")] - let span = ( + let span = Span( begin_rule_range, self.parser_position.range.1, begin_rule_line, @@ -604,7 +604,7 @@ where let t = self.parse_type(None)?; #[cfg(feature = "ast-span")] - let span = ( + let span = Span( begin_rule_range, self.parser_position.range.1, begin_rule_line, @@ -686,7 +686,7 @@ where #[cfg(feature = "ast-comments")] comments_after_type: comments_after_group.clone(), #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_pt_range, self.parser_position.range.1, begin_rule_line, @@ -714,7 +714,7 @@ where #[cfg(feature = "ast-comments")] comments_after_rule, #[cfg(feature = "ast-span")] - span: (begin_rule_range, end_rule_range, begin_rule_line), + span: Span(begin_rule_range, end_rule_range, begin_rule_line), }); } } @@ -741,7 +741,7 @@ where #[cfg(feature = "ast-comments")] comments_after_rule, #[cfg(feature = "ast-span")] - span: (begin_rule_range, end_rule_range, begin_rule_line), + span: Span(begin_rule_range, end_rule_range, begin_rule_line), }) } _ => { @@ -782,7 +782,7 @@ where } #[cfg(feature = "ast-span")] - let span = ( + let span = Span( begin_rule_range, self.parser_position.range.1, begin_rule_line, @@ -903,7 +903,7 @@ where #[cfg(feature = "ast-span")] { let end_range = self.lexer_position.range.1; - generic_params.span = (begin_range, end_range, self.lexer_position.line); + generic_params.span = Span(begin_range, end_range, self.lexer_position.line); } Ok(generic_params) @@ -973,7 +973,7 @@ where #[cfg(feature = "ast-span")] { - generic_args.span = ( + generic_args.span = Span( begin_generic_arg_range, self.parser_position.range.1, begin_generic_arg_line, @@ -1003,7 +1003,7 @@ where let mut t = Type { type_choices: Vec::new(), #[cfg(feature = "ast-span")] - span: (begin_type_range, 0, self.parser_position.line), + span: Span(begin_type_range, 0, self.parser_position.line), }; #[cfg(feature = "ast-comments")] @@ -1102,7 +1102,7 @@ where }; #[cfg(feature = "ast-span")] - let mut span = ( + let mut span = Span( begin_type1_range, self.lexer_position.range.1, begin_type1_line, @@ -1142,7 +1142,7 @@ where #[cfg(feature = "ast-span")] { - span = ( + span = Span( begin_type1_range, self.parser_position.range.1, begin_type1_line, @@ -1204,7 +1204,7 @@ where } #[cfg(feature = "ast-span")] - let span = ( + let span = Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -1291,7 +1291,7 @@ where ident, generic_args: Some(ga), #[cfg(feature = "ast-span")] - span: (begin_type2_range, end_type2_range, begin_type2_line), + span: Span(begin_type2_range, end_type2_range, begin_type2_line), }); } @@ -1305,7 +1305,7 @@ where ident: self.identifier_from_ident_token(*ident), generic_args: None, #[cfg(feature = "ast-span")] - span: ( + span: Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -1348,7 +1348,7 @@ where comments_after_type, pt, #[cfg(feature = "ast-span")] - span: ( + span: Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -1380,7 +1380,7 @@ where }; #[cfg(feature = "ast-span")] - let span = ( + let span = Span( begin_type2_range, self.lexer_position.range.1, begin_type2_line, @@ -1430,7 +1430,7 @@ where }; #[cfg(feature = "ast-span")] - let span = ( + let span = Span( begin_type2_range, self.lexer_position.range.1, begin_type2_line, @@ -1479,7 +1479,7 @@ where ident, generic_args: Some(self.parse_genericargs()?), #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span(0, 0, 0), }); } @@ -1489,7 +1489,7 @@ where ident, generic_args: None, #[cfg(feature = "ast-span")] - span: (0, 0, 0), + span: Span(0, 0, 0), }); } @@ -1542,7 +1542,7 @@ where #[cfg(feature = "ast-comments")] comments_after_group, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_type2_range, self.parser_position.range.1, begin_type2_line, @@ -1562,7 +1562,7 @@ where ident, generic_args, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_type2_range, self.parser_position.range.1, begin_type2_line, @@ -1581,7 +1581,7 @@ where ident, generic_args: None, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_type2_range, self.parser_position.range.1, begin_type2_line, @@ -1659,7 +1659,7 @@ where #[cfg(feature = "ast-comments")] comments_after_type, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_type2_range, self.parser_position.range.1, begin_type2_line, @@ -1671,14 +1671,14 @@ where mt, constraint, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_type2_range, self.lexer_position.range.1, begin_type2_line, ), }), #[cfg(feature = "ast-span")] - _ => Ok(Type2::Any(( + _ => Ok(Type2::Any(Span( begin_type2_range, self.lexer_position.range.1, begin_type2_line, @@ -1706,7 +1706,7 @@ where ident, generic_args: None, #[cfg(feature = "ast-span")] - span: ( + span: Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -1777,7 +1777,7 @@ where let mut group = Group { group_choices: Vec::new(), #[cfg(feature = "ast-span")] - span: (begin_group_range, 0, self.lexer_position.line), + span: Span(begin_group_range, 0, self.lexer_position.line), }; group.group_choices.push(self.parse_grpchoice()?); @@ -1813,7 +1813,7 @@ where #[cfg(feature = "ast-comments")] comments_before_grpchoice: None, #[cfg(feature = "ast-span")] - span: (self.lexer_position.range.0, 0, self.lexer_position.line), + span: Span(self.lexer_position.range.0, 0, self.lexer_position.line), }; if let Token::GCHOICE = &self.cur_token { @@ -1962,7 +1962,7 @@ where let group = self.parse_group()?; #[cfg(feature = "ast-span")] - let mut span = ( + let mut span = Span( begin_grpent_range, self.parser_position.range.1, begin_grpent_line, @@ -2007,7 +2007,7 @@ where } #[cfg(feature = "ast-span")] - let mut span = ( + let mut span = Span( begin_grpent_range, self.parser_position.range.1, begin_grpent_line, @@ -2426,7 +2426,7 @@ where let ident = self.identifier_from_ident_token((ident.0, ident.1)); #[cfg(feature = "ast-span")] { - ident.span = (begin_memberkey_range, end_t1_range, begin_memberkey_line); + ident.span = Span(begin_memberkey_range, end_t1_range, begin_memberkey_line); } self.next_token()?; @@ -2474,13 +2474,13 @@ where ident, generic_args: None, #[cfg(feature = "ast-span")] - span: (begin_memberkey_range, end_t1_range, begin_memberkey_line), + span: Span(begin_memberkey_range, end_t1_range, begin_memberkey_line), }, operator: None, #[cfg(feature = "ast-comments")] comments_after_type: None, #[cfg(feature = "ast-span")] - span: (begin_memberkey_range, end_t1_range, begin_memberkey_line), + span: Span(begin_memberkey_range, end_t1_range, begin_memberkey_line), }), #[cfg(feature = "ast-comments")] comments_before_cut, @@ -2490,7 +2490,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, end_memberkey_range, begin_memberkey_line, @@ -2522,13 +2522,13 @@ where ident, generic_args: None, #[cfg(feature = "ast-span")] - span: (begin_memberkey_range, end_t1_range, begin_memberkey_line), + span: Span(begin_memberkey_range, end_t1_range, begin_memberkey_line), }, operator: None, #[cfg(feature = "ast-comments")] comments_after_type: None, #[cfg(feature = "ast-span")] - span: (begin_memberkey_range, end_t1_range, begin_memberkey_line), + span: Span(begin_memberkey_range, end_t1_range, begin_memberkey_line), }), #[cfg(feature = "ast-comments")] comments_before_cut, @@ -2538,7 +2538,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, end_memberkey_range, begin_memberkey_line, @@ -2565,7 +2565,7 @@ where #[cfg(feature = "ast-comments")] comments_after_colon, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, self.parser_position.range.1, begin_memberkey_line, @@ -2667,7 +2667,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap: memberkey_comments, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, end_memberkey_range, begin_memberkey_line, @@ -2707,7 +2707,7 @@ where #[cfg(feature = "ast-comments")] comments_after_colon: memberkey_comments, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, self.parser_position.range.1, begin_memberkey_line, @@ -2874,7 +2874,7 @@ where #[cfg(feature = "ast-comments")] comments_after_type: comments_after_type_or_group, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, closing_parend_index, begin_memberkey_line, @@ -2884,7 +2884,7 @@ where comments_after_type: comments_before_cut.clone(), operator: None, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, closing_parend_index, begin_memberkey_line, @@ -2898,7 +2898,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap: None, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, end_memberkey_range, begin_memberkey_line, @@ -2930,7 +2930,7 @@ where #[cfg(feature = "ast-comments")] comments_after_type: comments_after_type_or_group, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, closing_parend_index, begin_memberkey_line, @@ -2940,7 +2940,7 @@ where comments_after_type: comments_before_cut.clone(), operator: None, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, closing_parend_index, begin_memberkey_line, @@ -2954,7 +2954,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap: memberkey_comments, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, self.lexer_position.range.0, begin_memberkey_line, @@ -2965,7 +2965,7 @@ where non_member_key: NonMemberKey::Type(Type { type_choices: t.type_choices, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, self.parser_position.range.1, begin_memberkey_line, @@ -3025,7 +3025,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap: memberkey_comments, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, end_memberkey_range, begin_memberkey_line, @@ -3056,7 +3056,7 @@ where #[cfg(feature = "ast-comments")] comments_after_arrowmap: memberkey_comments, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, self.parser_position.range.1, begin_memberkey_line, @@ -3073,7 +3073,7 @@ where type1: t1, }], #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_memberkey_range, self.parser_position.range.1, begin_memberkey_line, @@ -3118,7 +3118,7 @@ where Ok(Some(Occurrence { #[cfg(feature = "ast-span")] - occur: Occur::Optional(( + occur: Occur::Optional(Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -3145,7 +3145,7 @@ where Ok(Some(Occurrence { #[cfg(feature = "ast-span")] - occur: Occur::OneOrMore(( + occur: Occur::OneOrMore(Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -3169,7 +3169,7 @@ where lower: None, upper: Some(*u), #[cfg(feature = "ast-span")] - span: ( + span: Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -3179,7 +3179,7 @@ where #[cfg(feature = "ast-span")] { self.parser_position.range = self.lexer_position.range; - Occur::ZeroOrMore(( + Occur::ZeroOrMore(Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, @@ -3263,7 +3263,7 @@ where lower, upper, #[cfg(feature = "ast-span")] - span: ( + span: Span( begin_occur_range, self.parser_position.range.1, begin_occur_line, @@ -3303,7 +3303,7 @@ where ident: ident.0, socket: ident.1, #[cfg(feature = "ast-span")] - span: ( + span: Span( self.lexer_position.range.0, self.lexer_position.range.1, self.lexer_position.line, diff --git a/src/parser_tests.rs b/src/parser_tests.rs index 505956c0..ef242d0d 100644 --- a/src/parser_tests.rs +++ b/src/parser_tests.rs @@ -86,7 +86,7 @@ mod tests { param: Identifier { ident: "t".into(), socket: None, - span: (1, 2, 1), + span: Span(1, 2, 1), }, comments_before_ident: None, comments_after_ident: None, @@ -95,13 +95,13 @@ mod tests { param: Identifier { ident: "v".into(), socket: None, - span: (4, 5, 1), + span: Span(4, 5, 1), }, comments_before_ident: None, comments_after_ident: None, }, ], - span: (0, 6, 1), + span: Span(0, 6, 1), }; assert_eq!(gps, expected_output); @@ -249,11 +249,11 @@ mod tests { arg: Box::from(Type1 { type2: Type2::TextValue { value: "reboot".into(), - span: (1, 9, 1), + span: Span(1, 9, 1), }, operator: None, comments_after_type: None, - span: (1, 9, 1), + span: Span(1, 9, 1), }), comments_before_type: None, comments_after_type: None, @@ -262,17 +262,17 @@ mod tests { arg: Box::from(Type1 { type2: Type2::TextValue { value: "now".into(), - span: (11, 16, 1), + span: Span(11, 16, 1), }, operator: None, comments_after_type: None, - span: (11, 16, 1), + span: Span(11, 16, 1), }), comments_before_type: None, comments_after_type: None, }, ], - span: (0, 17, 1), + span: Span(0, 17, 1), }; assert_eq!(generic_args, expected_output); @@ -301,14 +301,14 @@ mod tests { ident: Identifier { ident: "tchoice1".into(), socket: None, - span: (2, 10, 1), + span: Span(2, 10, 1), }, generic_args: None, - span: (2, 10, 1), + span: Span(2, 10, 1), }, operator: None, comments_after_type: None, - span: (2, 10, 1), + span: Span(2, 10, 1), }, comments_before_type: None, comments_after_type: None, @@ -319,33 +319,33 @@ mod tests { ident: Identifier { ident: "tchoice2".into(), socket: None, - span: (13, 21, 1), + span: Span(13, 21, 1), }, generic_args: None, - span: (13, 21, 1), + span: Span(13, 21, 1), }, operator: None, comments_after_type: None, - span: (13, 21, 1), + span: Span(13, 21, 1), }, comments_before_type: None, comments_after_type: None, }, ], - span: (2, 21, 1), + span: Span(2, 21, 1), }, comments_before_type: None, comments_after_type: None, - span: (0, 23, 1), + span: Span(0, 23, 1), }, operator: None, comments_after_type: None, - span: (0, 23, 1), + span: Span(0, 23, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (0, 23, 1), + span: Span(0, 23, 1), }; assert_eq!(t, expected_output); @@ -369,122 +369,122 @@ mod tests { Type1 { type2: Type2::UintValue { value: 5, - span: (0, 1, 1), + span: Span(0, 1, 1), }, operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: true, - span: (1, 3, 1), + span: Span(1, 3, 1), }, type2: Type2::UintValue { value: 10, - span: (3, 5, 1), + span: Span(3, 5, 1), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (0, 5, 1), + span: Span(0, 5, 1), }, Type1 { type2: Type2::FloatValue { value: -10.5, - span: (0, 5, 1), + span: Span(0, 5, 1), }, operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: false, - span: (5, 8, 1), + span: Span(5, 8, 1), }, type2: Type2::FloatValue { value: 10.1, - span: (8, 12, 1), + span: Span(8, 12, 1), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (0, 12, 1), + span: Span(0, 12, 1), }, Type1 { type2: Type2::FloatValue { value: 1.5, - span: (0, 3, 1), + span: Span(0, 3, 1), }, operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: true, - span: (3, 5, 1), + span: Span(3, 5, 1), }, type2: Type2::FloatValue { value: 4.5, - span: (5, 8, 1), + span: Span(5, 8, 1), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (0, 8, 1), + span: Span(0, 8, 1), }, Type1 { type2: Type2::Typename { ident: Identifier { ident: "my..lower".into(), socket: None, - span: (0, 9, 1), + span: Span(0, 9, 1), }, generic_args: None, - span: (0, 9, 1), + span: Span(0, 9, 1), }, operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: false, - span: (10, 13, 1), + span: Span(10, 13, 1), }, type2: Type2::Typename { ident: Identifier { ident: "upper".into(), socket: None, - span: (14, 19, 1), + span: Span(14, 19, 1), }, generic_args: None, - span: (14, 19, 1), + span: Span(14, 19, 1), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (0, 19, 1), + span: Span(0, 19, 1), }, Type1 { type2: Type2::Typename { ident: Identifier { ident: "target".into(), socket: None, - span: (0, 6, 1), + span: Span(0, 6, 1), }, generic_args: None, - span: (0, 6, 1), + span: Span(0, 6, 1), }, operator: Some(Operator { operator: RangeCtlOp::CtlOp { ctrl: ".lt", - span: (7, 10, 1), + span: Span(7, 10, 1), }, type2: Type2::Typename { ident: Identifier { ident: "controller".into(), socket: None, - span: (11, 21, 1), + span: Span(11, 21, 1), }, generic_args: None, - span: (11, 21, 1), + span: Span(11, 21, 1), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (0, 21, 1), + span: Span(0, 21, 1), }, Type1 { type2: Type2::ParenthesizedType { @@ -496,14 +496,14 @@ mod tests { ident: Identifier { ident: "text".into(), socket: None, - span: (2, 6, 1), + span: Span(2, 6, 1), }, generic_args: None, - span: (2, 6, 1), + span: Span(2, 6, 1), }, operator: None, comments_after_type: None, - span: (2, 6, 1), + span: Span(2, 6, 1), }, comments_before_type: None, comments_after_type: None, @@ -514,40 +514,40 @@ mod tests { ident: Identifier { ident: "tstr".into(), socket: None, - span: (9, 13, 1), + span: Span(9, 13, 1), }, generic_args: None, - span: (9, 13, 1), + span: Span(9, 13, 1), }, operator: None, comments_after_type: None, - span: (9, 13, 1), + span: Span(9, 13, 1), }, comments_before_type: None, comments_after_type: None, }, ], - span: (2, 13, 1), + span: Span(2, 13, 1), }, comments_before_type: None, comments_after_type: None, - span: (0, 15, 1), + span: Span(0, 15, 1), }, operator: Some(Operator { operator: RangeCtlOp::CtlOp { ctrl: ".eq", - span: (16, 19, 1), + span: Span(16, 19, 1), }, type2: Type2::TextValue { value: "hello".into(), - span: (20, 27, 1), + span: Span(20, 27, 1), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (0, 27, 1), + span: Span(0, 27, 1), }, ]; @@ -583,13 +583,13 @@ mod tests { let expected_outputs = [ Type2::TextValue { value: "myvalue".into(), - span: (0, 9, 1), + span: Span(0, 9, 1), }, Type2::Typename { ident: Identifier { ident: "message".into(), socket: None, - span: (0, 7, 1), + span: Span(0, 7, 1), }, generic_args: Some(GenericArgs { args: vec![ @@ -597,11 +597,11 @@ mod tests { arg: Box::from(Type1 { type2: Type2::TextValue { value: "reboot".into(), - span: (8, 16, 1), + span: Span(8, 16, 1), }, operator: None, comments_after_type: None, - span: (8, 16, 1), + span: Span(8, 16, 1), }), comments_before_type: None, comments_after_type: None, @@ -610,38 +610,38 @@ mod tests { arg: Box::from(Type1 { type2: Type2::TextValue { value: "now".into(), - span: (18, 23, 1), + span: Span(18, 23, 1), }, operator: None, comments_after_type: None, - span: (18, 23, 1), + span: Span(18, 23, 1), }), comments_before_type: None, comments_after_type: None, }, ], - span: (7, 24, 1), + span: Span(7, 24, 1), }), - span: (0, 24, 1), + span: Span(0, 24, 1), }, Type2::Typename { ident: Identifier { ident: "tcp-option".into(), socket: Some(SocketPlug::GROUP), - span: (0, 12, 1), + span: Span(0, 12, 1), }, generic_args: None, - span: (0, 12, 1), + span: Span(0, 12, 1), }, Type2::Unwrap { ident: Identifier { ident: "group1".into(), socket: None, - span: (1, 7, 1), + span: Span(1, 7, 1), }, generic_args: None, comments: None, - span: (0, 0, 0), + span: Span(0, 0, 0), }, Type2::TaggedData { tag: Some(997), @@ -652,29 +652,29 @@ mod tests { ident: Identifier { ident: "tstr".into(), socket: None, - span: (7, 11, 1), + span: Span(7, 11, 1), }, generic_args: None, - span: (7, 11, 1), + span: Span(7, 11, 1), }, operator: None, comments_after_type: None, - span: (7, 11, 1), + span: Span(7, 11, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (7, 11, 1), + span: Span(7, 11, 1), }, comments_before_type: None, comments_after_type: None, - span: (0, 11, 1), + span: Span(0, 11, 1), }, Type2::FloatValue { value: 9.9, - span: (0, 3, 1), + span: Span(0, 3, 1), }, - Type2::Any((0, 1, 1)), + Type2::Any(Span(0, 1, 1)), Type2::Array { group: Group { group_choices: vec![GroupChoice { @@ -685,7 +685,7 @@ mod tests { occur: Occur::Exact { lower: None, upper: Some(3), - span: (1, 3, 1), + span: Span(1, 3, 1), }, comments: None, _a: PhantomData::default(), @@ -693,13 +693,13 @@ mod tests { name: Identifier { ident: "reputon".into(), socket: None, - span: (4, 11, 1), + span: Span(4, 11, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (1, 11, 1), + span: Span(1, 11, 1), }, OptionalComma { optional_comma: false, @@ -708,13 +708,13 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (1, 11, 1), + span: Span(1, 11, 1), }], - span: (1, 11, 1), + span: Span(1, 11, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 12, 1), + span: Span(0, 12, 1), }, Type2::Array { group: Group { @@ -723,20 +723,20 @@ mod tests { GroupEntry::TypeGroupname { ge: TypeGroupnameEntry { occur: Some(Occurrence { - occur: Occur::OneOrMore((1, 2, 1)), + occur: Occur::OneOrMore(Span(1, 2, 1)), comments: None, _a: PhantomData::default(), }), name: Identifier { ident: "reputon".into(), socket: None, - span: (3, 10, 1), + span: Span(3, 10, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (1, 10, 1), + span: Span(1, 10, 1), }, OptionalComma { optional_comma: false, @@ -745,23 +745,23 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (1, 10, 1), + span: Span(1, 10, 1), }], - span: (1, 10, 1), + span: Span(1, 10, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 11, 1), + span: Span(0, 11, 1), }, Type2::ChoiceFromGroup { ident: Identifier { ident: "groupname".into(), socket: None, - span: (1, 10, 1), + span: Span(1, 10, 1), }, generic_args: None, comments: None, - span: (0, 10, 1), + span: Span(0, 10, 1), }, Type2::ChoiceFromInlineGroup { group: Group { @@ -773,13 +773,13 @@ mod tests { name: Identifier { ident: "inlinegroup".into(), socket: None, - span: (3, 14, 1), + span: Span(3, 14, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (3, 14, 1), + span: Span(3, 14, 1), }, OptionalComma { optional_comma: false, @@ -788,14 +788,14 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (3, 14, 1), + span: Span(3, 14, 1), }], - span: (3, 14, 1), + span: Span(3, 14, 1), }, comments: None, comments_before_group: None, comments_after_group: None, - span: (0, 14, 1), + span: Span(0, 14, 1), }, Type2::Map { group: Group { @@ -804,7 +804,7 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: Some(Occurrence { - occur: Occur::Optional((2, 3, 1)), + occur: Occur::Optional(Span(2, 3, 1)), comments: None, _a: PhantomData::default(), }), @@ -812,17 +812,17 @@ mod tests { t1: Box::from(Type1 { type2: Type2::TextValue { value: "optional-key".into(), - span: (4, 18, 1), + span: Span(4, 18, 1), }, operator: None, comments_after_type: None, - span: (4, 18, 1), + span: Span(4, 18, 1), }), is_cut: true, comments_before_cut: None, comments_after_cut: None, comments_after_arrowmap: None, - span: (4, 23, 1), + span: Span(4, 23, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -831,24 +831,24 @@ mod tests { ident: Identifier { ident: "int".into(), socket: None, - span: (24, 27, 1), + span: Span(24, 27, 1), }, generic_args: None, - span: (24, 27, 1), + span: Span(24, 27, 1), }, operator: None, comments_after_type: None, - span: (24, 27, 1), + span: Span(24, 27, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (24, 27, 1), + span: Span(24, 27, 1), }, }), leading_comments: None, trailing_comments: None, - span: (2, 28, 1), + span: Span(2, 28, 1), }, OptionalComma { optional_comma: true, @@ -857,13 +857,13 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (2, 28, 1), + span: Span(2, 28, 1), }], - span: (2, 28, 1), + span: Span(2, 28, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 30, 1), + span: Span(0, 30, 1), }, Type2::Array { group: Group { @@ -881,11 +881,11 @@ mod tests { ident: Identifier { ident: "a".into(), socket: None, - span: (4, 5, 1), + span: Span(4, 5, 1), }, comments: None, comments_after_colon: None, - span: (4, 6, 1), + span: Span(4, 6, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -894,24 +894,24 @@ mod tests { ident: Identifier { ident: "int".into(), socket: None, - span: (7, 10, 1), + span: Span(7, 10, 1), }, generic_args: None, - span: (7, 10, 1), + span: Span(7, 10, 1), }, operator: None, comments_after_type: None, - span: (7, 10, 1), + span: Span(7, 10, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (7, 10, 1), + span: Span(7, 10, 1), }, }), leading_comments: None, trailing_comments: None, - span: (4, 11, 1), + span: Span(4, 11, 1), }, OptionalComma { optional_comma: true, @@ -927,11 +927,11 @@ mod tests { ident: Identifier { ident: "b".into(), socket: None, - span: (12, 13, 1), + span: Span(12, 13, 1), }, comments: None, comments_after_colon: None, - span: (12, 14, 1), + span: Span(12, 14, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -940,24 +940,24 @@ mod tests { ident: Identifier { ident: "tstr".into(), socket: None, - span: (15, 19, 1), + span: Span(15, 19, 1), }, generic_args: None, - span: (15, 19, 1), + span: Span(15, 19, 1), }, operator: None, comments_after_type: None, - span: (15, 19, 1), + span: Span(15, 19, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (15, 19, 1), + span: Span(15, 19, 1), }, }), leading_comments: None, trailing_comments: None, - span: (12, 19, 1), + span: Span(12, 19, 1), }, OptionalComma { optional_comma: false, @@ -967,14 +967,14 @@ mod tests { ), ], comments_before_grpchoice: None, - span: (4, 19, 1), + span: Span(4, 19, 1), }], - span: (4, 19, 1), + span: Span(4, 19, 1), }, occur: None, comments_before_group: None, comments_after_group: None, - span: (2, 21, 1), + span: Span(2, 21, 1), }, OptionalComma { optional_comma: false, @@ -983,13 +983,13 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (2, 21, 1), + span: Span(2, 21, 1), }], - span: (2, 21, 1), + span: Span(2, 21, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 23, 1), + span: Span(0, 23, 1), }, ]; @@ -1032,20 +1032,20 @@ mod tests { GroupEntry::TypeGroupname { ge: TypeGroupnameEntry { occur: Some(Occurrence { - occur: Occur::ZeroOrMore((3, 4, 1)), + occur: Occur::ZeroOrMore(Span(3, 4, 1)), comments: None, _a: PhantomData::default(), }), name: Identifier { ident: "file-entry".into(), socket: None, - span: (5, 15, 1), + span: Span(5, 15, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (3, 15, 1), + span: Span(3, 15, 1), }, OptionalComma { optional_comma: false, @@ -1054,27 +1054,27 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (3, 15, 1), + span: Span(3, 15, 1), }], - span: (3, 15, 1), + span: Span(3, 15, 1), }, comments_before_group: None, comments_after_group: None, - span: (2, 16, 1), + span: Span(2, 16, 1), }, operator: None, comments_after_type: None, - span: (2, 16, 1), + span: Span(2, 16, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (2, 16, 1), + span: Span(2, 16, 1), }, }), leading_comments: None, trailing_comments: None, - span: (2, 17, 1), + span: Span(2, 17, 1), }, OptionalComma { optional_comma: true, @@ -1097,20 +1097,20 @@ mod tests { GroupEntry::TypeGroupname { ge: TypeGroupnameEntry { occur: Some(Occurrence { - occur: Occur::ZeroOrMore((19, 20, 1)), + occur: Occur::ZeroOrMore(Span(19, 20, 1)), comments: None, _a: PhantomData::default(), }), name: Identifier { ident: "directory-entry".into(), socket: None, - span: (21, 36, 1), + span: Span(21, 36, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (19, 36, 1), + span: Span(19, 36, 1), }, OptionalComma { optional_comma: false, @@ -1119,27 +1119,27 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (19, 36, 1), + span: Span(19, 36, 1), }], - span: (19, 36, 1), + span: Span(19, 36, 1), }, comments_before_group: None, comments_after_group: None, - span: (18, 37, 1), + span: Span(18, 37, 1), }, operator: None, comments_after_type: None, - span: (18, 37, 1), + span: Span(18, 37, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (18, 37, 1), + span: Span(18, 37, 1), }, }), leading_comments: None, trailing_comments: None, - span: (18, 37, 1), + span: Span(18, 37, 1), }, OptionalComma { optional_comma: false, @@ -1149,13 +1149,13 @@ mod tests { ), ], comments_before_grpchoice: None, - span: (2, 37, 1), + span: Span(2, 37, 1), }], - span: (2, 37, 1), + span: Span(2, 37, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 39, 1), + span: Span(0, 39, 1), }, Type2::Map { group: Group { @@ -1169,13 +1169,13 @@ mod tests { name: Identifier { ident: "int".into(), socket: None, - span: (2, 5, 1), + span: Span(2, 5, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (2, 6, 1), + span: Span(2, 6, 1), }, OptionalComma { optional_comma: true, @@ -1190,13 +1190,13 @@ mod tests { name: Identifier { ident: "int".into(), socket: None, - span: (7, 10, 1), + span: Span(7, 10, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (7, 10, 1), + span: Span(7, 10, 1), }, OptionalComma { optional_comma: false, @@ -1206,7 +1206,7 @@ mod tests { ), ], comments_before_grpchoice: None, - span: (2, 10, 1), + span: Span(2, 10, 1), }, GroupChoice { group_entries: vec![ @@ -1217,13 +1217,13 @@ mod tests { name: Identifier { ident: "int".into(), socket: None, - span: (14, 17, 1), + span: Span(14, 17, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (14, 18, 1), + span: Span(14, 18, 1), }, OptionalComma { optional_comma: true, @@ -1238,13 +1238,13 @@ mod tests { name: Identifier { ident: "tstr".into(), socket: None, - span: (19, 23, 1), + span: Span(19, 23, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (19, 23, 1), + span: Span(19, 23, 1), }, OptionalComma { optional_comma: false, @@ -1254,14 +1254,14 @@ mod tests { ), ], comments_before_grpchoice: None, - span: (14, 23, 1), + span: Span(14, 23, 1), }, ], - span: (2, 23, 1), + span: Span(2, 23, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 25, 1), + span: Span(0, 25, 1), }, Type2::Map { group: Group { @@ -1274,13 +1274,13 @@ mod tests { name: Identifier { ident: "int".into(), socket: None, - span: (2, 5, 1), + span: Span(2, 5, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (2, 6, 1), + span: Span(2, 6, 1), }, OptionalComma { optional_comma: true, @@ -1295,13 +1295,13 @@ mod tests { name: Identifier { ident: "int".into(), socket: None, - span: (7, 10, 1), + span: Span(7, 10, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (7, 11, 1), + span: Span(7, 11, 1), }, OptionalComma { optional_comma: true, @@ -1316,13 +1316,13 @@ mod tests { name: Identifier { ident: "int".into(), socket: None, - span: (12, 15, 1), + span: Span(12, 15, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (12, 16, 1), + span: Span(12, 16, 1), }, OptionalComma { optional_comma: true, @@ -1337,13 +1337,13 @@ mod tests { name: Identifier { ident: "tstr".into(), socket: None, - span: (17, 21, 1), + span: Span(17, 21, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (17, 21, 1), + span: Span(17, 21, 1), }, OptionalComma { optional_comma: false, @@ -1353,13 +1353,13 @@ mod tests { ), ], comments_before_grpchoice: None, - span: (2, 21, 1), + span: Span(2, 21, 1), }], - span: (2, 21, 1), + span: Span(2, 21, 1), }, comments_before_group: None, comments_after_group: None, - span: (0, 23, 1), + span: Span(0, 23, 1), }, ]; @@ -1389,7 +1389,7 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: Some(Occurrence { - occur: Occur::ZeroOrMore((0, 1, 1)), + occur: Occur::ZeroOrMore(Span(0, 1, 1)), comments: None, _a: PhantomData::default(), }), @@ -1399,41 +1399,41 @@ mod tests { ident: Identifier { ident: "type1".into(), socket: None, - span: (2, 7, 1), + span: Span(2, 7, 1), }, generic_args: None, - span: (2, 7, 1), + span: Span(2, 7, 1), }, operator: None, comments_after_type: None, - span: (2, 7, 1), + span: Span(2, 7, 1), }), is_cut: true, comments_before_cut: None, comments_after_cut: None, comments_after_arrowmap: None, - span: (2, 12, 1), + span: Span(2, 12, 1), }), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { type2: Type2::TextValue { value: "value".into(), - span: (13, 20, 1), + span: Span(13, 20, 1), }, operator: None, comments_after_type: None, - span: (13, 20, 1), + span: Span(13, 20, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (13, 20, 1), + span: Span(13, 20, 1), }, }), leading_comments: None, trailing_comments: None, - span: (0, 20, 1), + span: Span(0, 20, 1), }, GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { @@ -1442,11 +1442,11 @@ mod tests { ident: Identifier { ident: "type1".into(), socket: None, - span: (0, 5, 1), + span: Span(0, 5, 1), }, comments: None, comments_after_colon: None, - span: (0, 6, 1), + span: Span(0, 6, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -1455,24 +1455,24 @@ mod tests { ident: Identifier { ident: "type2".into(), socket: None, - span: (7, 12, 1), + span: Span(7, 12, 1), }, generic_args: None, - span: (7, 12, 1), + span: Span(7, 12, 1), }, operator: None, comments_after_type: None, - span: (7, 12, 1), + span: Span(7, 12, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (7, 12, 1), + span: Span(7, 12, 1), }, }), leading_comments: None, trailing_comments: None, - span: (0, 12, 1), + span: Span(0, 12, 1), }, GroupEntry::TypeGroupname { ge: TypeGroupnameEntry { @@ -1480,18 +1480,18 @@ mod tests { name: Identifier { ident: "typename".into(), socket: None, - span: (0, 8, 1), + span: Span(0, 8, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (0, 8, 1), + span: Span(0, 8, 1), }, GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: Some(Occurrence { - occur: Occur::Optional((0, 1, 1)), + occur: Occur::Optional(Span(0, 1, 1)), comments: None, _a: PhantomData::default(), }), @@ -1499,7 +1499,7 @@ mod tests { value: token::Value::UINT(0), comments: None, comments_after_colon: None, - span: (2, 4, 1), + span: Span(2, 4, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -1508,24 +1508,24 @@ mod tests { ident: Identifier { ident: "addrdistr".into(), socket: None, - span: (5, 14, 1), + span: Span(5, 14, 1), }, generic_args: None, - span: (5, 14, 1), + span: Span(5, 14, 1), }, operator: None, comments_after_type: None, - span: (5, 14, 1), + span: Span(5, 14, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (5, 14, 1), + span: Span(5, 14, 1), }, }), leading_comments: None, trailing_comments: None, - span: (0, 14, 1), + span: Span(0, 14, 1), }, GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { @@ -1534,7 +1534,7 @@ mod tests { value: token::Value::UINT(0), comments: None, comments_after_colon: None, - span: (0, 2, 1), + span: Span(0, 2, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -1543,7 +1543,7 @@ mod tests { ident: Identifier { ident: "finite_set".into(), socket: None, - span: (3, 13, 1), + span: Span(3, 13, 1), }, generic_args: Some(GenericArgs { args: vec![GenericArg { @@ -1552,41 +1552,41 @@ mod tests { ident: Identifier { ident: "transaction_input".into(), socket: None, - span: (14, 31, 1), + span: Span(14, 31, 1), }, generic_args: None, - span: (14, 31, 1), + span: Span(14, 31, 1), }, operator: None, comments_after_type: None, - span: (14, 31, 1), + span: Span(14, 31, 1), }), comments_before_type: None, comments_after_type: None, }], - span: (13, 32, 1), + span: Span(13, 32, 1), }), - span: (3, 32, 1), + span: Span(3, 32, 1), }, operator: None, comments_after_type: None, - span: (3, 32, 1), + span: Span(3, 32, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (3, 32, 1), + span: Span(3, 32, 1), }, }), leading_comments: None, trailing_comments: None, - span: (0, 32, 1), + span: Span(0, 32, 1), }, GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: Some(Occurrence { - occur: Occur::ZeroOrMore((0, 1, 1)), + occur: Occur::ZeroOrMore(Span(0, 1, 1)), comments: None, _a: PhantomData::default(), }), @@ -1602,13 +1602,13 @@ mod tests { name: Identifier { ident: "credential".into(), socket: None, - span: (3, 13, 1), + span: Span(3, 13, 1), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (3, 13, 1), + span: Span(3, 13, 1), }, OptionalComma { optional_comma: false, @@ -1617,23 +1617,23 @@ mod tests { }, )], comments_before_grpchoice: None, - span: (3, 13, 1), + span: Span(3, 13, 1), }], - span: (3, 13, 1), + span: Span(3, 13, 1), }, comments_before_group: None, comments_after_group: None, - span: (2, 14, 1), + span: Span(2, 14, 1), }, operator: None, comments_after_type: None, - span: (2, 14, 1), + span: Span(2, 14, 1), }), is_cut: false, comments_before_cut: None, comments_after_cut: None, comments_after_arrowmap: None, - span: (2, 22, 1), + span: Span(2, 22, 1), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -1642,24 +1642,24 @@ mod tests { ident: Identifier { ident: "coin".into(), socket: None, - span: (18, 22, 1), + span: Span(18, 22, 1), }, generic_args: None, - span: (18, 22, 1), + span: Span(18, 22, 1), }, operator: None, comments_after_type: None, - span: (18, 22, 1), + span: Span(18, 22, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (18, 22, 1), + span: Span(18, 22, 1), }, }), leading_comments: None, trailing_comments: None, - span: (0, 22, 1), + span: Span(0, 22, 1), }, ]; @@ -1692,20 +1692,20 @@ mod tests { ident: Identifier { ident: "type1".into(), socket: None, - span: (0, 5, 1), + span: Span(0, 5, 1), }, generic_args: None, - span: (0, 5, 1), + span: Span(0, 5, 1), }, operator: None, comments_after_type: None, - span: (0, 5, 1), + span: Span(0, 5, 1), }), is_cut: false, comments_before_cut: None, comments_after_cut: None, comments_after_arrowmap: None, - span: (0, 8, 1), + span: Span(0, 8, 1), }, MemberKey::Type1 { t1: Box::from(Type1 { @@ -1716,10 +1716,10 @@ mod tests { type1: Type1 { type2: Type2::TextValue { value: "mytype1".into(), - span: (2, 11, 1), + span: Span(2, 11, 1), }, operator: None, - span: (2, 11, 1), + span: Span(2, 11, 1), comments_after_type: None, }, comments_after_type: None, @@ -1730,13 +1730,13 @@ mod tests { type2: Type2::Typename { ident: Identifier { ident: "int", - span: (14, 17, 1), + span: Span(14, 17, 1), socket: None, }, - span: (14, 17, 1), + span: Span(14, 17, 1), generic_args: None, }, - span: (14, 17, 1), + span: Span(14, 17, 1), comments_after_type: None, operator: None, }, @@ -1744,53 +1744,53 @@ mod tests { comments_after_type: None, }, ], - span: (2, 17, 1), + span: Span(2, 17, 1), }, - span: (0, 19, 1), + span: Span(0, 19, 1), comments_before_type: None, comments_after_type: None, }, operator: None, comments_after_type: None, - span: (0, 19, 1), + span: Span(0, 19, 1), }), is_cut: true, comments_before_cut: None, comments_after_cut: None, comments_after_arrowmap: None, - span: (0, 24, 1), + span: Span(0, 24, 1), }, MemberKey::Bareword { ident: Identifier { ident: "mybareword".into(), socket: None, - span: (0, 10, 1), + span: Span(0, 10, 1), }, comments: None, comments_after_colon: None, - span: (0, 11, 1), + span: Span(0, 11, 1), }, MemberKey::Bareword { ident: Identifier { ident: "my..bareword".into(), socket: None, - span: (0, 12, 1), + span: Span(0, 12, 1), }, comments: None, comments_after_colon: None, - span: (0, 13, 1), + span: Span(0, 13, 1), }, MemberKey::Value { value: token::Value::TEXT("myvalue".into()), comments: None, comments_after_colon: None, - span: (0, 10, 1), + span: Span(0, 10, 1), }, MemberKey::Value { value: token::Value::UINT(0), comments: None, comments_after_colon: None, - span: (0, 2, 1), + span: Span(0, 2, 1), }, ]; @@ -1816,18 +1816,18 @@ mod tests { occur: Occur::Exact { lower: Some(1), upper: Some(3), - span: (0, 3, 1), + span: Span(0, 3, 1), }, comments: None, _a: PhantomData::default(), }, Occurrence { - occur: Occur::ZeroOrMore((0, 1, 1)), + occur: Occur::ZeroOrMore(Span(0, 1, 1)), comments: None, _a: PhantomData::default(), }, Occurrence { - occur: Occur::OneOrMore((0, 1, 1)), + occur: Occur::OneOrMore(Span(0, 1, 1)), comments: None, _a: PhantomData::default(), }, @@ -1835,7 +1835,7 @@ mod tests { occur: Occur::Exact { lower: Some(5), upper: None, - span: (0, 2, 1), + span: Span(0, 2, 1), }, comments: None, _a: PhantomData::default(), @@ -1844,13 +1844,13 @@ mod tests { occur: Occur::Exact { lower: None, upper: Some(3), - span: (0, 2, 1), + span: Span(0, 2, 1), }, comments: None, _a: PhantomData::default(), }, Occurrence { - occur: Occur::Optional((0, 1, 1)), + occur: Occur::Optional(Span(0, 1, 1)), comments: None, _a: PhantomData::default(), }, diff --git a/tests/parser.rs b/tests/parser.rs index bb447f68..4bb852a6 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -40,7 +40,7 @@ fn verify_cddl() -> Result<()> { name: Identifier { ident: "myrule".into(), socket: None, - span: (0, 6, 1), + span: Span(0, 6, 1), }, generic_params: None, is_type_choice_alternate: false, @@ -51,33 +51,33 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "secondrule".into(), socket: None, - span: (9, 19, 1), + span: Span(9, 19, 1), }, generic_args: None, - span: (9, 19, 1), + span: Span(9, 19, 1), }, operator: None, comments_after_type: None, - span: (9, 19, 1), + span: Span(9, 19, 1), }, comments_before_type: None, comments_after_type: None, }], - span: (9, 19, 1), + span: Span(9, 19, 1), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (0, 19, 1), + span: Span(0, 19, 1), }, Rule::Type { rule: TypeRule { name: Identifier { ident: "myrange".into(), socket: None, - span: (20, 27, 2), + span: Span(20, 27, 2), }, generic_params: None, is_type_choice_alternate: false, @@ -86,45 +86,45 @@ fn verify_cddl() -> Result<()> { type1: Type1 { type2: Type2::UintValue { value: 10, - span: (30, 32, 2), + span: Span(30, 32, 2), }, operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: true, - span: (32, 34, 2), + span: Span(32, 34, 2), }, type2: Type2::Typename { ident: Identifier { ident: "upper".into(), socket: None, - span: (34, 39, 2), + span: Span(34, 39, 2), }, generic_args: None, - span: (34, 39, 2), + span: Span(34, 39, 2), }, comments_before_operator: None, comments_after_operator: None, }), comments_after_type: None, - span: (30, 39, 2), + span: Span(30, 39, 2), }, comments_before_type: None, comments_after_type: None, }], - span: (30, 39, 2), + span: Span(30, 39, 2), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (20, 39, 2), + span: Span(20, 39, 2), }, Rule::Type { rule: TypeRule { name: Identifier { ident: "upper".into(), socket: None, - span: (40, 45, 3), + span: Span(40, 45, 3), }, generic_params: None, is_type_choice_alternate: false, @@ -134,11 +134,11 @@ fn verify_cddl() -> Result<()> { type1: Type1 { type2: Type2::UintValue { value: 500, - span: (48, 51, 3), + span: Span(48, 51, 3), }, operator: None, comments_after_type: None, - span: (48, 51, 3), + span: Span(48, 51, 3), }, comments_before_type: None, comments_after_type: None, @@ -147,30 +147,30 @@ fn verify_cddl() -> Result<()> { type1: Type1 { type2: Type2::UintValue { value: 600, - span: (54, 57, 3), + span: Span(54, 57, 3), }, operator: None, comments_after_type: None, - span: (54, 57, 3), + span: Span(54, 57, 3), }, comments_before_type: None, comments_after_type: None, }, ], - span: (48, 57, 3), + span: Span(48, 57, 3), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (40, 57, 3), + span: Span(40, 57, 3), }, Rule::Group { rule: Box::from(GroupRule { name: Identifier { ident: "gr".into(), socket: None, - span: (58, 60, 4), + span: Span(58, 60, 4), }, generic_params: None, is_group_choice_alternate: false, @@ -179,7 +179,7 @@ fn verify_cddl() -> Result<()> { occur: Occur::Exact { lower: Some(2), upper: None, - span: (63, 65, 4), + span: Span(63, 65, 4), }, comments: None, _a: PhantomData::default(), @@ -193,13 +193,13 @@ fn verify_cddl() -> Result<()> { name: Identifier { ident: "test".into(), socket: None, - span: (68, 72, 4), + span: Span(68, 72, 4), }, generic_args: None, }, leading_comments: None, trailing_comments: None, - span: (68, 72, 4), + span: Span(68, 72, 4), }, OptionalComma { optional_comma: false, @@ -208,26 +208,26 @@ fn verify_cddl() -> Result<()> { }, )], comments_before_grpchoice: None, - span: (68, 72, 4), + span: Span(68, 72, 4), }], - span: (68, 72, 4), + span: Span(68, 72, 4), }, comments_before_group: None, comments_after_group: None, - span: (63, 74, 4), + span: Span(63, 74, 4), }, comments_before_assigng: None, comments_after_assigng: None, }), comments_after_rule: None, - span: (58, 74, 4), + span: Span(58, 74, 4), }, Rule::Type { rule: TypeRule { name: Identifier { ident: "messages".into(), socket: None, - span: (75, 83, 5), + span: Span(75, 83, 5), }, generic_params: None, is_type_choice_alternate: false, @@ -238,7 +238,7 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "message".into(), socket: None, - span: (86, 93, 5), + span: Span(86, 93, 5), }, generic_args: Some(GenericArgs { args: vec![ @@ -246,11 +246,11 @@ fn verify_cddl() -> Result<()> { arg: Box::from(Type1 { type2: Type2::TextValue { value: "reboot".into(), - span: (94, 102, 5), + span: Span(94, 102, 5), }, operator: None, comments_after_type: None, - span: (94, 102, 5), + span: Span(94, 102, 5), }), comments_before_type: None, comments_after_type: None, @@ -259,42 +259,42 @@ fn verify_cddl() -> Result<()> { arg: Box::from(Type1 { type2: Type2::TextValue { value: "now".into(), - span: (104, 109, 5), + span: Span(104, 109, 5), }, operator: None, comments_after_type: None, - span: (104, 109, 5), + span: Span(104, 109, 5), }), comments_before_type: None, comments_after_type: None, }, ], - span: (93, 110, 5), + span: Span(93, 110, 5), }), - span: (86, 110, 5), + span: Span(86, 110, 5), }, operator: None, comments_after_type: None, - span: (86, 110, 5), + span: Span(86, 110, 5), }, comments_before_type: None, comments_after_type: None, }], - span: (86, 110, 5), + span: Span(86, 110, 5), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (75, 110, 5), + span: Span(75, 110, 5), }, Rule::Type { rule: TypeRule { name: Identifier { ident: "message".into(), socket: None, - span: (111, 118, 6), + span: Span(111, 118, 6), }, generic_params: Some(GenericParams { params: vec![ @@ -302,7 +302,7 @@ fn verify_cddl() -> Result<()> { param: Identifier { ident: "t".into(), socket: None, - span: (119, 120, 6), + span: Span(119, 120, 6), }, comments_before_ident: None, comments_after_ident: None, @@ -311,13 +311,13 @@ fn verify_cddl() -> Result<()> { param: Identifier { ident: "v".into(), socket: None, - span: (122, 123, 6), + span: Span(122, 123, 6), }, comments_before_ident: None, comments_after_ident: None, }, ], - span: (118, 124, 6), + span: Span(118, 124, 6), }), is_type_choice_alternate: false, value: Type { @@ -335,32 +335,32 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "type".into(), socket: None, - span: (128, 132, 6), + span: Span(128, 132, 6), }, comments: None, comments_after_colon: None, - span: (128, 133, 6), + span: Span(128, 133, 6), }), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { type2: Type2::UintValue { value: 2, - span: (134, 135, 6), + span: Span(134, 135, 6), }, operator: None, comments_after_type: None, - span: (134, 135, 6), + span: Span(134, 135, 6), }, comments_before_type: None, comments_after_type: None, }], - span: (134, 135, 6), + span: Span(134, 135, 6), }, }), leading_comments: None, trailing_comments: None, - span: (128, 136, 6), + span: Span(128, 136, 6), }, OptionalComma { optional_comma: true, @@ -376,11 +376,11 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "value".into(), socket: None, - span: (137, 142, 6), + span: Span(137, 142, 6), }, comments: None, comments_after_colon: None, - span: (137, 143, 6), + span: Span(137, 143, 6), }), entry_type: Type { type_choices: vec![TypeChoice { @@ -389,24 +389,24 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "v".into(), socket: None, - span: (144, 145, 6), + span: Span(144, 145, 6), }, generic_args: None, - span: (144, 145, 6), + span: Span(144, 145, 6), }, operator: None, comments_after_type: None, - span: (144, 145, 6), + span: Span(144, 145, 6), }, comments_before_type: None, comments_after_type: None, }], - span: (144, 145, 6), + span: Span(144, 145, 6), }, }), leading_comments: None, trailing_comments: None, - span: (137, 145, 6), + span: Span(137, 145, 6), }, OptionalComma { optional_comma: false, @@ -416,35 +416,35 @@ fn verify_cddl() -> Result<()> { ), ], comments_before_grpchoice: None, - span: (128, 145, 6), + span: Span(128, 145, 6), }], - span: (128, 145, 6), + span: Span(128, 145, 6), }, comments_before_group: None, comments_after_group: None, - span: (127, 146, 6), + span: Span(127, 146, 6), }, operator: None, comments_after_type: None, - span: (127, 146, 6), + span: Span(127, 146, 6), }, comments_before_type: None, comments_after_type: None, }], - span: (127, 146, 6), + span: Span(127, 146, 6), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (111, 146, 6), + span: Span(111, 146, 6), }, Rule::Type { rule: TypeRule { name: Identifier { ident: "color".into(), socket: None, - span: (147, 152, 7), + span: Span(147, 152, 7), }, generic_params: None, is_type_choice_alternate: false, @@ -455,33 +455,33 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "colors".into(), socket: None, - span: (156, 162, 7), + span: Span(156, 162, 7), }, generic_args: None, comments: None, - span: (155, 162, 7), + span: Span(155, 162, 7), }, operator: None, comments_after_type: None, - span: (155, 162, 7), + span: Span(155, 162, 7), }, comments_before_type: None, comments_after_type: None, }], - span: (155, 162, 7), + span: Span(155, 162, 7), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (147, 162, 7), + span: Span(147, 162, 7), }, Rule::Group { rule: Box::from(GroupRule { name: Identifier { ident: "colors".into(), socket: None, - span: (163, 169, 8), + span: Span(163, 169, 8), }, generic_params: None, is_group_choice_alternate: false, @@ -497,32 +497,32 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "red".into(), socket: None, - span: (174, 177, 8), + span: Span(174, 177, 8), }, comments: None, comments_after_colon: None, - span: (174, 178, 8), + span: Span(174, 178, 8), }), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { type2: Type2::TextValue { value: "red".into(), - span: (179, 184, 8), + span: Span(179, 184, 8), }, operator: None, comments_after_type: None, - span: (179, 184, 8), + span: Span(179, 184, 8), }, comments_before_type: None, comments_after_type: None, }], - span: (179, 184, 8), + span: Span(179, 184, 8), }, }), leading_comments: None, trailing_comments: None, - span: (174, 184, 8), + span: Span(174, 184, 8), }, OptionalComma { optional_comma: false, @@ -531,26 +531,26 @@ fn verify_cddl() -> Result<()> { }, )], comments_before_grpchoice: None, - span: (174, 184, 8), + span: Span(174, 184, 8), }], - span: (174, 184, 8), + span: Span(174, 184, 8), }, comments_before_group: None, comments_after_group: None, - span: (172, 186, 8), + span: Span(172, 186, 8), }, comments_before_assigng: None, comments_after_assigng: None, }), comments_after_rule: None, - span: (163, 186, 8), + span: Span(163, 186, 8), }, Rule::Type { rule: TypeRule { name: Identifier { ident: "test".into(), socket: None, - span: (187, 191, 9), + span: Span(187, 191, 9), }, generic_params: None, is_type_choice_alternate: false, @@ -566,14 +566,14 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "int".into(), socket: None, - span: (196, 199, 9), + span: Span(196, 199, 9), }, generic_args: None, - span: (196, 199, 9), + span: Span(196, 199, 9), }, operator: None, comments_after_type: None, - span: (196, 199, 9), + span: Span(196, 199, 9), }, comments_before_type: None, comments_after_type: None, @@ -584,40 +584,40 @@ fn verify_cddl() -> Result<()> { ident: Identifier { ident: "float".into(), socket: None, - span: (202, 207, 9), + span: Span(202, 207, 9), }, generic_args: None, - span: (202, 207, 9), + span: Span(202, 207, 9), }, operator: None, comments_after_type: None, - span: (202, 207, 9), + span: Span(202, 207, 9), }, comments_before_type: None, comments_after_type: None, }, ], - span: (196, 207, 9), + span: Span(196, 207, 9), }, comments_before_type: None, comments_after_type: None, - span: (194, 209, 9), + span: Span(194, 209, 9), }, operator: None, comments_after_type: None, - span: (194, 210, 9), + span: Span(194, 210, 9), }, comments_before_type: None, comments_after_type: None, }], - span: (194, 210, 9), + span: Span(194, 210, 9), }, comments_before_assignt: None, comments_after_assignt: None, }, comments_after_rule: None, - span: (187, 210, 9), + span: Span(187, 210, 9), }, ], comments: None, From 98ba140cc5c177ec3cdff175fecccab6386c9a63 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Fri, 1 Oct 2021 12:55:35 -0400 Subject: [PATCH 03/24] rename nonmemberkey to parenthesizedtype for clarification --- src/ast.rs | 16 +++++++++------- src/parser.rs | 22 +++++++++++----------- src/visitor.rs | 29 +++++++++++++++++++++-------- 3 files changed, 41 insertions(+), 26 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 114a76b2..ff7d9a31 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2632,10 +2632,12 @@ pub enum MemberKey<'a> { comments_after_colon: Option>, }, + // Used while parsing a parenthesized type that is not followed by a cut nor + // an arrow map #[cfg_attr(target_arch = "wasm32", serde(skip))] #[doc(hidden)] - NonMemberKey { - non_member_key: NonMemberKey<'a>, + ParenthesizedType { + non_member_key: ParenthesizedType<'a>, #[cfg(feature = "ast-comments")] comments_before_type_or_group: Option>, #[cfg(feature = "ast-comments")] @@ -2645,7 +2647,7 @@ pub enum MemberKey<'a> { #[derive(Debug, Clone, PartialEq)] #[doc(hidden)] -pub enum NonMemberKey<'a> { +pub enum ParenthesizedType<'a> { Group(Group<'a>), Type(Type<'a>), } @@ -2751,8 +2753,8 @@ impl<'a> fmt::Display for MemberKey<'a> { write!(f, "{}", mk_str) } - MemberKey::NonMemberKey { - non_member_key: NonMemberKey::Group(g), + MemberKey::ParenthesizedType { + non_member_key: ParenthesizedType::Group(g), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] @@ -2774,8 +2776,8 @@ impl<'a> fmt::Display for MemberKey<'a> { write!(f, "{}", nmk_str) } - MemberKey::NonMemberKey { - non_member_key: NonMemberKey::Type(t), + MemberKey::ParenthesizedType { + non_member_key: ParenthesizedType::Type(t), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] diff --git a/src/parser.rs b/src/parser.rs index 2285c12b..327210ad 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2014,11 +2014,11 @@ where ); match member_key { - Some(MemberKey::NonMemberKey { + Some(MemberKey::ParenthesizedType { #[cfg(feature = "ast-comments")] - non_member_key: NonMemberKey::Type(mut entry_type), + non_member_key: ParenthesizedType::Type(mut entry_type), #[cfg(not(feature = "ast-comments"))] - non_member_key: NonMemberKey::Type(entry_type), + non_member_key: ParenthesizedType::Type(entry_type), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] @@ -2153,8 +2153,8 @@ where span, }) } - Some(MemberKey::NonMemberKey { - non_member_key: NonMemberKey::Group(group), + Some(MemberKey::ParenthesizedType { + non_member_key: ParenthesizedType::Group(group), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] @@ -2817,8 +2817,8 @@ where Err(e) => return Err(e), }; - return Ok(Some(MemberKey::NonMemberKey { - non_member_key: NonMemberKey::Group(group), + return Ok(Some(MemberKey::ParenthesizedType { + non_member_key: ParenthesizedType::Group(group), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] @@ -2961,8 +2961,8 @@ where ), }) } else { - Some(MemberKey::NonMemberKey { - non_member_key: NonMemberKey::Type(Type { + Some(MemberKey::ParenthesizedType { + non_member_key: ParenthesizedType::Type(Type { type_choices: t.type_choices, #[cfg(feature = "ast-span")] span: Span( @@ -3063,8 +3063,8 @@ where ), }) } else { - Some(MemberKey::NonMemberKey { - non_member_key: NonMemberKey::Type(Type { + Some(MemberKey::ParenthesizedType { + non_member_key: ParenthesizedType::Type(Type { type_choices: vec![TypeChoice { #[cfg(feature = "ast-comments")] comments_before_type: None, diff --git a/src/visitor.rs b/src/visitor.rs index cbce951d..be075c3a 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -1,6 +1,11 @@ #![cfg(feature = "std")] -use crate::{ast::*, token::ByteValue, token::Value}; +use crate::{ + ast::*, + token::Value, + token::{lookup_control_from_str, ByteValue}, + Token, +}; use std::error::Error; /// Visitor result @@ -67,7 +72,7 @@ pub trait Visitor<'a, E: Error> { fn visit_control_operator( &mut self, target: &Type2<'a>, - _ctrl: &str, + _ctrl: &Token<'a>, controller: &Type2<'a>, ) -> Result { walk_control_operator(self, target, controller) @@ -133,7 +138,7 @@ pub trait Visitor<'a, E: Error> { } /// Visit nonmemberkey - fn visit_nonmemberkey(&mut self, nmk: &NonMemberKey<'a>) -> Result { + fn visit_nonmemberkey(&mut self, nmk: &ParenthesizedType<'a>) -> Result { walk_nonmemberkey(self, nmk) } } @@ -213,7 +218,13 @@ where RangeCtlOp::RangeOp { is_inclusive, .. } => { visitor.visit_range(&target.type2, &o.type2, *is_inclusive) } - RangeCtlOp::CtlOp { ctrl, .. } => visitor.visit_control_operator(&target.type2, ctrl, &o.type2), + RangeCtlOp::CtlOp { ctrl, .. } => { + if let Some(token) = lookup_control_from_str(ctrl) { + visitor.visit_control_operator(&target.type2, &token, &o.type2) + } else { + Ok(()) + } + } } } @@ -401,7 +412,9 @@ where MemberKey::Type1 { t1, .. } => visitor.visit_type1(t1), MemberKey::Bareword { ident, .. } => visitor.visit_identifier(ident), MemberKey::Value { value, .. } => visitor.visit_value(value), - MemberKey::NonMemberKey { non_member_key, .. } => visitor.visit_nonmemberkey(non_member_key), + MemberKey::ParenthesizedType { non_member_key, .. } => { + visitor.visit_nonmemberkey(non_member_key) + } } } @@ -428,13 +441,13 @@ where } /// Walk nonmemberkey -pub fn walk_nonmemberkey<'a, E, V>(visitor: &mut V, nmk: &NonMemberKey<'a>) -> Result +pub fn walk_nonmemberkey<'a, E, V>(visitor: &mut V, nmk: &ParenthesizedType<'a>) -> Result where E: Error, V: Visitor<'a, E> + ?Sized, { match nmk { - NonMemberKey::Group(group) => visitor.visit_group(group), - NonMemberKey::Type(t) => visitor.visit_type(t), + ParenthesizedType::Group(group) => visitor.visit_group(group), + ParenthesizedType::Type(t) => visitor.visit_type(t), } } From b1144ffd6d37c26c6974a11ab89f4c70594658c0 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 12:46:46 -0400 Subject: [PATCH 04/24] faker updates --- src/ast.rs | 11 ++ src/faker.rs | 355 +++++++++++++++++++++++++++++++++++++----- src/lib.rs | 1 + src/validator/cbor.rs | 105 ++++++------- src/validator/json.rs | 89 +++++------ 5 files changed, 420 insertions(+), 141 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index ff7d9a31..28983036 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -633,6 +633,17 @@ impl<'a> fmt::Display for GenericArgs<'a> { } } +/// A generic rule that has undergone monomorphization +#[derive(Clone, Debug)] +pub struct GenericRule<'a> { + /// Name + pub name: &'a str, + /// Parameters + pub params: Vec<&'a str>, + /// Arguments + pub args: Vec>, +} + /// Type choices /// /// ```abnf diff --git a/src/faker.rs b/src/faker.rs index 066b0707..8e07c222 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -2,26 +2,31 @@ use crate::{ ast::*, cddl_from_str, lexer_from_str, token::{lookup_ident, Token}, - validator::{group_rule_from_ident, rule_from_ident}, - visitor::{self, walk_group, walk_memberkey, walk_type2, walk_value_member_key_entry, Visitor}, + validator::*, + visitor::{self, *}, }; -use std::{collections::HashMap, fmt}; +use std::collections::HashMap; use displaydoc::Display; -use fake::{Dummy, Fake, Faker as FFaker}; -use rand::{rngs::StdRng, SeedableRng}; -use serde::Deserialize; +use fake::{faker::name::raw::*, locales::EN, Fake, Faker as FFaker}; +use rand::{self, seq::SliceRandom}; use serde_json::{self, Map, Value}; +/// Result type from fake data generation pub type Result = std::result::Result; +/// Fake data generation error type #[derive(Debug, Display)] pub enum Error { + /// Data cannot be generated from a CDDL document that has no type rules + /// defined #[displaydoc("no type rules found in the cddl document")] MissingTypeRules, + /// UTF8 parsing error #[displaydoc("{0}")] Utf8Error(std::str::Utf8Error), + /// CDDL parsing error #[displaydoc("error parsing cddl: {0}")] CDDLParsing(String), } @@ -33,34 +38,197 @@ impl std::error::Error for Error { } } +/// JSON data faker for a given CDDL document pub struct Faker<'a> { - pub cddl: &'a CDDL<'a>, - pub faked_json: Option, - pub map_entries: Option, Type<'a>)>>, - pub array_entries: Option, Type<'a>)>>, + cddl: &'a CDDL<'a>, + faked_json: Option, + entries: Entries<'a>, + ctrl: Option<(Identifier<'a>, Token<'a>)>, + generic_rules: Vec>, + eval_generic_rule: Option<&'a str>, + is_group_to_choice_enum: bool, } impl<'a> Faker<'a> { + /// Construct a new faker from a given CDDL document pub fn new(cddl: &'a CDDL) -> Self { Faker { cddl, faked_json: None, - map_entries: None, - array_entries: None, + entries: Entries::None, + ctrl: None, + generic_rules: Vec::new(), + eval_generic_rule: None, + is_group_to_choice_enum: false, } } } +enum Entries<'a> { + None, + Map(HashMap, Type<'a>)>), + Array(Vec<(Option, Type<'a>)>), +} + impl<'a> Visitor<'a, Error> for Faker<'a> { + fn visit_type_rule(&mut self, tr: &TypeRule<'a>) -> visitor::Result { + if let Some(gp) = &tr.generic_params { + if let Some(gr) = self + .generic_rules + .iter_mut() + .find(|r| r.name == tr.name.ident) + { + gr.params = gp.params.iter().map(|p| p.param.ident).collect(); + } else { + self.generic_rules.push(GenericRule { + name: tr.name.ident, + params: gp.params.iter().map(|p| p.param.ident).collect(), + args: vec![], + }); + } + } + + walk_type_rule(self, tr) + } + + fn visit_group_rule(&mut self, gr: &GroupRule<'a>) -> visitor::Result { + if let Some(gp) = &gr.generic_params { + if let Some(gr) = self + .generic_rules + .iter_mut() + .find(|r| r.name == gr.name.ident) + { + gr.params = gp.params.iter().map(|p| p.param.ident).collect(); + } else { + self.generic_rules.push(GenericRule { + name: gr.name.ident, + params: gp.params.iter().map(|p| p.param.ident).collect(), + args: vec![], + }); + } + } + + walk_group_rule(self, gr) + } + + fn visit_group(&mut self, g: &Group<'a>) -> visitor::Result { + if let Some(gc) = g.group_choices.choose(&mut rand::thread_rng()) { + return self.visit_group_choice(gc); + } + + walk_group(self, g) + } + + fn visit_group_choice(&mut self, gc: &GroupChoice<'a>) -> visitor::Result { + if self.is_group_to_choice_enum { + if let Some(tc) = + type_choices_from_group_choice(self.cddl, gc).choose(&mut rand::thread_rng()) + { + return self.visit_type_choice(tc); + } + } + + walk_group_choice(self, gc) + } + + fn visit_type(&mut self, t: &Type<'a>) -> visitor::Result { + if let Some(tc) = t.type_choices.choose(&mut rand::thread_rng()) { + return self.visit_type_choice(tc); + } + + walk_type(self, t) + } + fn visit_type_groupname_entry( &mut self, entry: &TypeGroupnameEntry<'a>, ) -> visitor::Result { - if let Some(entries) = self.array_entries.as_mut() { + if let Entries::Array(entries) = &mut self.entries { entries.push(( entry.occur.clone().map(|o| o.occur), Type::from(&entry.name), )); + } else if let Entries::Map(_) = self.entries { + if let Some(rule) = group_rule_from_ident(self.cddl, &entry.name) { + return self.visit_group_rule(rule); + } + } + + Ok(()) + } + + fn visit_control_operator( + &mut self, + target: &Type2<'a>, + ctrl: &Token<'a>, + controller: &Type2<'a>, + ) -> visitor::Result { + if let Type2::Typename { + ident: target_ident, + .. + } = target + { + if let Type2::Typename { + ident: controller_ident, + .. + } = controller + { + if let Some(name) = self.eval_generic_rule { + if let Some(gr) = self + .generic_rules + .iter() + .cloned() + .find(|gr| gr.name == name) + { + for (idx, gp) in gr.params.iter().enumerate() { + if let Some(arg) = gr.args.get(idx) { + if *gp == target_ident.ident { + let t2 = Type2::from(arg.clone()); + + if *gp == controller_ident.ident { + return self.visit_control_operator(&t2, ctrl, &t2); + } + + return self.visit_control_operator(&arg.type2, ctrl, controller); + } + } + } + } + } + } + + if let Some(name) = self.eval_generic_rule { + if let Some(gr) = self + .generic_rules + .iter() + .cloned() + .find(|gr| gr.name == name) + { + for (idx, gp) in gr.params.iter().enumerate() { + if let Some(arg) = gr.args.get(idx) { + if *gp == target_ident.ident { + let t2 = Type2::from(arg.clone()); + return self.visit_control_operator(&t2, ctrl, controller); + } + } + } + } + } + } + + match ctrl { + Token::SIZE => match target { + Type2::Typename { ident, .. } + if is_ident_string_data_type(self.cddl, ident) + || is_ident_uint_data_type(self.cddl, ident) => + { + self.ctrl = Some((ident.clone(), ctrl.clone())); + self.visit_type2(controller)?; + self.ctrl = None; + } + _ => return Ok(()), + }, + _ => return Ok(()), } Ok(()) @@ -70,7 +238,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { &mut self, entry: &ValueMemberKeyEntry<'a>, ) -> visitor::Result { - if let Some(entries) = self.map_entries.as_mut() { + if let Entries::Map(entries) = &mut self.entries { let occur = entry.occur.clone().map(|o| o.occur); if let Some(mk) = &entry.member_key { @@ -79,11 +247,16 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { entries.insert(ident.ident.to_string(), (occur, entry.entry_type.clone())); } MemberKey::Value { value, .. } => { - entries.insert(value.to_string(), (occur.clone(), entry.entry_type.clone())); + entries.insert(value.to_string(), (occur, entry.entry_type.clone())); } _ => return Ok(()), } } + } else if let Entries::Array(entries) = &mut self.entries { + entries.push(( + entry.occur.clone().map(|o| o.occur), + entry.entry_type.clone(), + )); } Ok(()) @@ -107,12 +280,24 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { self.faked_json = Some(value.into()); } } + Type2::UintValue { value, .. } => match &self.ctrl { + Some((target, Token::SIZE)) => { + if is_ident_string_data_type(self.cddl, target) { + self.faked_json = Some(value.fake::().into()) + } else if is_ident_uint_data_type(self.cddl, target) { + self.faked_json = Some((0..256u64.pow(*value as u32)).fake::().into()); + } + } + _ => self.faked_json = Some((*value).into()), + }, + Type2::IntValue { value, .. } => self.faked_json = Some((*value).into()), + Type2::FloatValue { value, .. } => self.faked_json = Some((*value).into()), Type2::Array { group, .. } => { self.faked_json = Some(Value::Array(Vec::new())); - self.array_entries = Some(Vec::new()); + self.entries = Entries::Array(Vec::new()); self.visit_group(group)?; - if let Some(array_entries) = &self.array_entries { + if let Entries::Array(array_entries) = &mut self.entries { if let Some(Value::Array(array)) = self.faked_json.as_mut() { for (occur, entry) in array_entries.iter() { if let Some(occur) = occur { @@ -193,19 +378,26 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } } } + } else { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } } } } } - self.array_entries = None; + self.entries = Entries::None; } Type2::Map { group, .. } => { self.faked_json = Some(Value::Object(Map::default())); - self.map_entries = Some(HashMap::new()); + self.entries = Entries::Map(HashMap::new()); self.visit_group(group)?; - if let Some(map_entries) = &self.map_entries { + if let Entries::Map(map_entries) = &mut self.entries { if let Some(Value::Object(map)) = self.faked_json.as_mut() { for (k, (occur, v)) in map_entries.iter() { let generate = if let Some(Occur::Optional(_)) = occur { @@ -226,7 +418,72 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } } - self.map_entries = None; + self.entries = Entries::None; + } + Type2::Typename { + ident, + generic_args, + .. + } => { + if let Some(ga) = generic_args { + if let Some(rule) = rule_from_ident(self.cddl, ident) { + if let Some(gr) = self + .generic_rules + .iter_mut() + .find(|gr| gr.name == ident.ident) + { + for arg in ga.args.iter() { + gr.args.push((*arg.arg).clone()); + } + } else if let Some(params) = generic_params_from_rule(rule) { + self.generic_rules.push(GenericRule { + name: ident.ident, + params, + args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(), + }); + } + + self.eval_generic_rule = Some(ident.ident); + + return self.visit_rule(rule); + } + } + + return self.visit_identifier(ident); + } + Type2::ChoiceFromGroup { + ident, + generic_args, + .. + } => { + if let Some(ga) = generic_args { + if let Some(rule) = rule_from_ident(self.cddl, ident) { + if let Some(gr) = self + .generic_rules + .iter_mut() + .find(|gr| gr.name == ident.ident) + { + for arg in ga.args.iter() { + gr.args.push((*arg.arg).clone()); + } + } else if let Some(params) = generic_params_from_rule(rule) { + self.generic_rules.push(GenericRule { + name: ident.ident, + params, + args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(), + }); + } + + self.eval_generic_rule = Some(ident.ident); + self.is_group_to_choice_enum = true; + + return self.visit_rule(rule); + } + } + + self.is_group_to_choice_enum = true; + self.visit_identifier(ident)?; + self.is_group_to_choice_enum = false; } _ => walk_type2(self, t2)?, } @@ -235,27 +492,52 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } fn visit_identifier(&mut self, ident: &Identifier<'a>) -> visitor::Result { - match lookup_ident(ident.ident) { - Token::TSTR => { - let value = FFaker.fake::(); - - // if let Some(Value::Array(array)) = self.faked_json.as_mut() { - // array.push(value.into()); - // } else { - // self.faked_json = Some(value.into()); - // } - - self.faked_json = Some(value.into()); + if let Some(name) = self.eval_generic_rule { + if let Some(gr) = self + .generic_rules + .iter() + .cloned() + .find(|gr| gr.name == name) + { + for (idx, gp) in gr.params.iter().enumerate() { + if *gp == ident.ident { + if let Some(arg) = gr.args.get(idx) { + return self.visit_type1(arg); + } + } + } } - _ => { - self.faked_json = Some(ident.ident.into()); + } + + if is_ident_string_data_type(self.cddl, ident) { + self.faked_json = Some(Name(EN).fake::().into()); + } else if let Token::NUMBER = lookup_ident(ident.ident) { + if FFaker.fake::() { + self.faked_json = Some(FFaker.fake::().into()) + } else { + self.faked_json = Some(FFaker.fake::().into()) } + } else if is_ident_float_data_type(self.cddl, ident) { + self.faked_json = Some(FFaker.fake::().into()) + } else if is_ident_uint_data_type(self.cddl, ident) { + self.faked_json = Some(FFaker.fake::().into()) + } else if is_ident_nint_data_type(self.cddl, ident) { + self.faked_json = Some((..0).fake::().into()) + } else if is_ident_integer_data_type(self.cddl, ident) { + self.faked_json = Some(FFaker.fake::().into()) + } else if is_ident_bool_data_type(self.cddl, ident) { + self.faked_json = Some(FFaker.fake::().into()) + } else if let Some(rule) = rule_from_ident(self.cddl, ident) { + self.visit_rule(rule)?; + } else { + self.faked_json = Some(ident.ident.into()); } Ok(()) } } +/// Generate fake JSON from a given CDDL document string pub fn fake_json_from_cddl_str(cddl_str: &str) -> Result { let mut lexer = lexer_from_str(cddl_str); let cddl = cddl_from_str(&mut lexer, cddl_str, true).map_err(Error::CDDLParsing)?; @@ -285,7 +567,10 @@ mod tests { fn test_faker() -> Result<()> { let cddl = indoc!( r#" - a = { a: { a: [ *2 tstr ] } } + a = b / d + b = { c } + c = ( a: tstr ) + d = [ + tstr ] "# ); diff --git a/src/lib.rs b/src/lib.rs index 5bda9690..8a14ad5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -559,6 +559,7 @@ pub mod token; #[cfg(feature = "std")] pub mod validator; +/// Generate fake JSON data from CDDL #[cfg(feature = "std")] pub mod faker; diff --git a/src/validator/cbor.rs b/src/validator/cbor.rs index 512cb705..cef5cc57 100644 --- a/src/validator/cbor.rs +++ b/src/validator/cbor.rs @@ -196,13 +196,6 @@ pub struct CBORValidator<'a> { disabled_features: Option>, } -#[derive(Clone, Debug)] -struct GenericRule<'a> { - name: &'a str, - params: Vec<&'a str>, - args: Vec>, -} - impl<'a> CBORValidator<'a> { #[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "additional-controls")] @@ -954,7 +947,7 @@ where fn visit_control_operator( &mut self, target: &Type2<'a>, - ctrl: &str, + ctrl: &Token<'a>, controller: &Type2<'a>, ) -> visitor::Result> { if let Type2::Typename { @@ -1010,8 +1003,8 @@ where } } - match lookup_control_from_str(ctrl) { - t @ Some(Token::EQ) => { + match ctrl { + Token::EQ => { match target { Type2::Typename { ident, .. } => { if is_ident_string_data_type(self.cddl, ident) @@ -1035,7 +1028,7 @@ where } Type2::Map { .. } => { if let Value::Map(_) = &self.cbor { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; self.visit_type2(controller)?; self.ctrl = None; @@ -1050,13 +1043,13 @@ where } Ok(()) } - t @ Some(Token::NE) => { + Token::NE => { match target { Type2::Typename { ident, .. } => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; return Ok(()); @@ -1064,7 +1057,7 @@ where } Type2::Array { .. } => { if let Value::Array(_) = &self.cbor { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; return Ok(()); @@ -1072,7 +1065,7 @@ where } Type2::Map { .. } => { if let Value::Map(_) = &self.cbor { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; self.visit_type2(controller)?; self.ctrl = None; @@ -1087,30 +1080,28 @@ where } Ok(()) } - t @ Some(Token::LT) | t @ Some(Token::GT) | t @ Some(Token::GE) | t @ Some(Token::LE) => { - match target { - Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => { - self.ctrl = t; - self.visit_type2(controller)?; - self.ctrl = None; - Ok(()) - } - _ => { - self.add_error(format!( - "target for .lt, .gt, .ge or .le operator must be a numerical data type, got {}", - target - )); - Ok(()) - } + Token::LT | Token::GT | Token::GE | Token::LE => match target { + Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => { + self.ctrl = Some(ctrl.clone()); + self.visit_type2(controller)?; + self.ctrl = None; + Ok(()) } - } - t @ Some(Token::SIZE) => match target { + _ => { + self.add_error(format!( + "target for .lt, .gt, .ge or .le operator must be a numerical data type, got {}", + target + )); + Ok(()) + } + }, + Token::SIZE => match target { Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) || is_ident_uint_data_type(self.cddl, ident) || is_ident_byte_string_data_type(self.cddl, ident) => { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; Ok(()) @@ -1123,15 +1114,15 @@ where Ok(()) } }, - t @ Some(Token::AND) => { - self.ctrl = t; + Token::AND => { + self.ctrl = Some(ctrl.clone()); self.visit_type2(target)?; self.visit_type2(controller)?; self.ctrl = None; Ok(()) } - t @ Some(Token::WITHIN) => { - self.ctrl = t; + Token::WITHIN => { + self.ctrl = Some(ctrl.clone()); let error_count = self.errors.len(); self.visit_type2(target)?; let no_errors = self.errors.len() == error_count; @@ -1151,8 +1142,8 @@ where Ok(()) } - t @ Some(Token::DEFAULT) => { - self.ctrl = t; + Token::DEFAULT => { + self.ctrl = Some(ctrl.clone()); let error_count = self.errors.len(); self.visit_type2(target)?; if self.errors.len() != error_count { @@ -1174,8 +1165,8 @@ where self.ctrl = None; Ok(()) } - t @ Some(Token::REGEXP) | t @ Some(Token::PCRE) => { - self.ctrl = t; + Token::REGEXP | Token::PCRE => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { match self.cbor { @@ -1195,8 +1186,8 @@ where Ok(()) } - t @ Some(Token::CBOR) | t @ Some(Token::CBORSEQ) => { - self.ctrl = t; + Token::CBOR | Token::CBORSEQ => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) => { match &self.cbor { @@ -1216,8 +1207,8 @@ where Ok(()) } - t @ Some(Token::BITS) => { - self.ctrl = t; + Token::BITS => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) @@ -1242,8 +1233,8 @@ where Ok(()) } #[cfg(feature = "additional-controls")] - t @ Some(Token::CAT) => { - self.ctrl = t; + Token::CAT => { + self.ctrl = Some(ctrl.clone()); match cat_operation(self.cddl, target, controller, false) { Ok(values) => { @@ -1270,8 +1261,8 @@ where Ok(()) } #[cfg(feature = "additional-controls")] - t @ Some(Token::DET) => { - self.ctrl = t; + Token::DET => { + self.ctrl = Some(ctrl.clone()); match cat_operation(self.cddl, target, controller, true) { Ok(values) => { @@ -1298,8 +1289,8 @@ where Ok(()) } #[cfg(feature = "additional-controls")] - t @ Some(Token::PLUS) => { - self.ctrl = t; + Token::PLUS => { + self.ctrl = Some(ctrl.clone()); match plus_operation(self.cddl, target, controller) { Ok(values) => { @@ -1328,8 +1319,8 @@ where Ok(()) } #[cfg(feature = "additional-controls")] - t @ Some(Token::ABNF) => { - self.ctrl = t; + Token::ABNF => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { @@ -1376,8 +1367,8 @@ where Ok(()) } #[cfg(feature = "additional-controls")] - t @ Some(Token::ABNFB) => { - self.ctrl = t; + Token::ABNFB => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) => { @@ -1425,8 +1416,8 @@ where } #[cfg(feature = "additional-controls")] #[cfg(not(target_arch = "wasm32"))] - t @ Some(Token::FEATURE) => { - self.ctrl = t; + Token::FEATURE => { + self.ctrl = Some(ctrl.clone()); if let Some(ef) = self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); diff --git a/src/validator/json.rs b/src/validator/json.rs index 6a04c40c..5d285dea 100644 --- a/src/validator/json.rs +++ b/src/validator/json.rs @@ -212,13 +212,6 @@ pub struct JSONValidator<'a> { disabled_features: Option>, } -#[derive(Clone, Debug)] -struct GenericRule<'a> { - name: &'a str, - params: Vec<&'a str>, - args: Vec>, -} - impl<'a> JSONValidator<'a> { #[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "additional-controls")] @@ -1142,7 +1135,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { fn visit_control_operator( &mut self, target: &Type2<'a>, - ctrl: &str, + ctrl: &Token<'a>, controller: &Type2<'a>, ) -> visitor::Result { if let Type2::Typename { @@ -1198,8 +1191,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } } - match lookup_control_from_str(ctrl) { - t @ Some(Token::EQ) => match target { + match ctrl { + Token::EQ => match target { Type2::Typename { ident, .. } => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) @@ -1222,7 +1215,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } Type2::Map { .. } => { if let Value::Object(_) = &self.json { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; self.visit_type2(controller)?; self.ctrl = None; @@ -1235,12 +1228,12 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { target )), }, - t @ Some(Token::NE) => match target { + Token::NE => match target { Type2::Typename { ident, .. } => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; return Ok(()); @@ -1248,7 +1241,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } Type2::Array { .. } => { if let Value::Array(_) = &self.json { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; return Ok(()); @@ -1256,7 +1249,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } Type2::Map { .. } => { if let Value::Object(_) = &self.json { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; self.visit_type2(controller)?; self.ctrl = None; @@ -1269,27 +1262,25 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { target )), }, - t @ Some(Token::LT) | t @ Some(Token::GT) | t @ Some(Token::GE) | t @ Some(Token::LE) => { - match target { - Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => { - self.ctrl = t; - self.visit_type2(controller)?; - self.ctrl = None; - } - _ => { - self.add_error(format!( - "target for .lt, .gt, .ge or .le operator must be a numerical data type, got {}", - target - )); - } + Token::LT | Token::GT | Token::GE | Token::LE => match target { + Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => { + self.ctrl = Some(ctrl.clone()); + self.visit_type2(controller)?; + self.ctrl = None; } - } - t @ Some(Token::SIZE) => match target { + _ => { + self.add_error(format!( + "target for .lt, .gt, .ge or .le operator must be a numerical data type, got {}", + target + )); + } + }, + Token::SIZE => match target { Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) || is_ident_uint_data_type(self.cddl, ident) => { - self.ctrl = t; + self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; } @@ -1300,14 +1291,14 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { )); } }, - t @ Some(Token::AND) => { - self.ctrl = t; + Token::AND => { + self.ctrl = Some(ctrl.clone()); self.visit_type2(target)?; self.visit_type2(controller)?; self.ctrl = None; } - t @ Some(Token::WITHIN) => { - self.ctrl = t; + Token::WITHIN => { + self.ctrl = Some(ctrl.clone()); let error_count = self.errors.len(); self.visit_type2(target)?; let no_errors = self.errors.len() == error_count; @@ -1325,8 +1316,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.ctrl = None; } - t @ Some(Token::DEFAULT) => { - self.ctrl = t; + Token::DEFAULT => { + self.ctrl = Some(ctrl.clone()); let error_count = self.errors.len(); self.visit_type2(target)?; if self.errors.len() != error_count { @@ -1347,8 +1338,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } self.ctrl = None; } - t @ Some(Token::REGEXP) | t @ Some(Token::PCRE) => { - self.ctrl = t; + Token::REGEXP | Token::PCRE => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { match self.json { @@ -1367,8 +1358,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.ctrl = None; } #[cfg(feature = "additional-controls")] - t @ Some(Token::CAT) => { - self.ctrl = t; + Token::CAT => { + self.ctrl = Some(ctrl.clone()); match cat_operation(self.cddl, target, controller, false) { Ok(values) => { @@ -1394,8 +1385,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.ctrl = None; } #[cfg(feature = "additional-controls")] - t @ Some(Token::DET) => { - self.ctrl = t; + Token::DET => { + self.ctrl = Some(ctrl.clone()); match cat_operation(self.cddl, target, controller, true) { Ok(values) => { @@ -1421,8 +1412,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.ctrl = None; } #[cfg(feature = "additional-controls")] - t @ Some(Token::PLUS) => { - self.ctrl = t; + Token::PLUS => { + self.ctrl = Some(ctrl.clone()); match plus_operation(self.cddl, target, controller) { Ok(values) => { @@ -1447,8 +1438,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.ctrl = None; } #[cfg(feature = "additional-controls")] - t @ Some(Token::ABNF) => { - self.ctrl = t; + Token::ABNF => { + self.ctrl = Some(ctrl.clone()); match target { Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { @@ -1494,8 +1485,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } #[cfg(feature = "additional-controls")] #[cfg(not(target_arch = "wasm32"))] - t @ Some(Token::FEATURE) => { - self.ctrl = t; + Token::FEATURE => { + self.ctrl = Some(ctrl.clone()); if let Some(ef) = self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); From b551da81fc585d072181ef5386748b0a7c43342f Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:09:20 -0400 Subject: [PATCH 05/24] fix wasm compilation errors --- Cargo.toml | 1 + src/ast.rs | 1 + src/error.rs | 10 ++++++++ src/faker.rs | 60 ++++++++++++++++++++++++++++++++++++++++++- src/validator/cbor.rs | 4 +-- src/validator/json.rs | 4 +-- src/validator/mod.rs | 14 +++------- 7 files changed, 78 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 56357403..4147d378 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ log = "0.4.14" simplelog = "0.10.0" fake = { version = "2.4.0", optional = true, features = ["derive", "chrono"] } rand = { version = "0.8.0", optional = true } +getrandom = { version = "0.2.3", features = ["js"] } [dev-dependencies] indoc = "1.0.3" diff --git a/src/ast.rs b/src/ast.rs index 28983036..8772e474 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -20,6 +20,7 @@ use alloc::{ /// Starting index, ending index and line number #[cfg(feature = "ast-span")] +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] #[derive(Copy, Clone, Debug, PartialEq, Eq, Default)] pub struct Span(pub usize, pub usize, pub usize); diff --git a/src/error.rs b/src/error.rs index b6c2e88d..9feedb22 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,6 @@ +#[cfg(target_arch = "wasm32")] +use crate::lexer::Position; + use std::fmt; #[cfg(target_arch = "wasm32")] @@ -187,3 +190,10 @@ impl From for ErrorMsg { } } } + +#[cfg(target_arch = "wasm32")] +#[derive(Serialize)] +pub struct ParserError { + pub position: Position, + pub msg: ErrorMsg, +} diff --git a/src/faker.rs b/src/faker.rs index 8e07c222..70936d02 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -1,6 +1,5 @@ use crate::{ ast::*, - cddl_from_str, lexer_from_str, token::{lookup_ident, Token}, validator::*, visitor::{self, *}, @@ -13,6 +12,12 @@ use fake::{faker::name::raw::*, locales::EN, Fake, Faker as FFaker}; use rand::{self, seq::SliceRandom}; use serde_json::{self, Map, Value}; +#[cfg(not(target_arch = "wasm32"))] +use crate::{cddl_from_str, lexer_from_str}; + +#[cfg(target_arch = "wasm32")] +use wasm_bindgen::prelude::*; + /// Result type from fake data generation pub type Result = std::result::Result; @@ -537,6 +542,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } } +#[cfg(not(target_arch = "wasm32"))] /// Generate fake JSON from a given CDDL document string pub fn fake_json_from_cddl_str(cddl_str: &str) -> Result { let mut lexer = lexer_from_str(cddl_str); @@ -557,7 +563,59 @@ pub fn fake_json_from_cddl_str(cddl_str: &str) -> Result { Err(Error::MissingTypeRules) } +#[cfg(target_arch = "wasm32")] +#[wasm_bindgen] +/// Generate fake JSON from a given CDDL document string +pub fn fake_json_from_cddl_str(cddl_str: &str) -> std::result::Result { + use crate::{ + error::ParserError, + lexer::Lexer, + parser::{self, Parser}, + }; + + let mut l = Lexer::new(cddl_str); + let mut p = Parser::new((&mut l).iter(), cddl_str).map_err(|e| JsValue::from(e.to_string()))?; + let c = p.parse_cddl().map_err(|e| JsValue::from(e.to_string()))?; + if !p.errors.is_empty() { + return Err( + JsValue::from_serde( + &p.errors + .iter() + .filter_map(|e| { + if let parser::Error::PARSER { position, msg } = e { + Some(ParserError { + position: *position, + msg: msg.clone(), + }) + } else { + None + } + }) + .collect::>(), + ) + .map_err(|e| JsValue::from(e.to_string()))?, + ); + } + let mut faker = Faker::new(&c); + + for rule in faker.cddl.rules.iter() { + if let Rule::Type { rule, .. } = rule { + faker + .visit_type_rule(rule) + .map_err(|e| JsValue::from(e.to_string()))?; + break; + } + } + + if let Some(faked_json) = faker.faked_json { + return Ok(faked_json.to_string().into()); + } + + Err(Error::MissingTypeRules.to_string().into()) +} + #[cfg(test)] +#[cfg(not(target_arch = "wasm32"))] mod tests { use super::*; diff --git a/src/validator/cbor.rs b/src/validator/cbor.rs index cef5cc57..521391ce 100644 --- a/src/validator/cbor.rs +++ b/src/validator/cbor.rs @@ -1459,8 +1459,8 @@ where } #[cfg(feature = "additional-controls")] #[cfg(target_arch = "wasm32")] - t @ Some(Token::FEATURE) => { - self.ctrl = t; + Token::FEATURE => { + self.ctrl = Some(ctrl.clone()); if let Some(ef) = &self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); diff --git a/src/validator/json.rs b/src/validator/json.rs index 5d285dea..ea305dd5 100644 --- a/src/validator/json.rs +++ b/src/validator/json.rs @@ -1526,8 +1526,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } #[cfg(feature = "additional-controls")] #[cfg(target_arch = "wasm32")] - t @ Some(Token::FEATURE) => { - self.ctrl = t; + Token::FEATURE => { + self.ctrl = Some(ctrl.clone()); if let Some(ef) = &self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); diff --git a/src/validator/mod.rs b/src/validator/mod.rs index ac45027c..055612dd 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -28,25 +28,17 @@ use serde::de::Deserialize; #[cfg(target_arch = "wasm32")] use crate::{ - error::ErrorMsg, - lexer::{Lexer, Position}, + error::ParserError, + lexer::Lexer, parser::{self, Parser}, }; -#[cfg(target_arch = "wasm32")] -use serde::Serialize; + #[cfg(target_arch = "wasm32")] use wasm_bindgen::prelude::*; #[cfg(not(target_arch = "wasm32"))] use crate::{cddl_from_str, lexer_from_str}; -#[cfg(target_arch = "wasm32")] -#[derive(Serialize)] -struct ParserError { - position: Position, - msg: ErrorMsg, -} - trait Validator<'a, E: Error>: Visitor<'a, E> { fn validate(&mut self) -> std::result::Result<(), E>; fn add_error(&mut self, reason: String); From d8ebef7081b639977a09fb7d233ce0ab02ecf08b Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:17:46 -0400 Subject: [PATCH 06/24] update code scanning workflow --- .github/workflows/codeql-analysis.yml | 54 +++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 36543e02..840c472d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -41,6 +41,60 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + target: wasm32-unknown-unknown + + - name: Install Node.js + uses: actions/setup-node@v1 + with: + node-version: '16' + + - name: Install wasmpack + run: | + curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Build wasm for Node.js + run: | + wasm-pack build --target nodejs --scope anweiss --release + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + # queries: ./path/to/local/query, your-org/your-repo/queries@main + + # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). + # If this step fails, then you should remove it and run the build manually (see below) + - name: Autobuild + uses: github/codeql-action/autobuild@v1 + + # ℹ️ Command-line programs to run using the OS shell. + # 📚 https://git.io/JvXDl + + # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines + # and modify them (or add more) to build your code if your project + # uses a compiled language + + #- run: | + # make bootstrap + # make release + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + + - name: Build wasm for web + run: | + wasm-pack build --release + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 From 3f803ce1adc7f0583ad2b417519c2c07fcf0fc5e Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:17:52 -0400 Subject: [PATCH 07/24] fix feature compilation errors --- src/ast.rs | 6 ++++++ src/faker.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/ast.rs b/src/ast.rs index 8772e474..a90c3b1f 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -691,15 +691,21 @@ impl<'a> From<&Identifier<'a>> for Type<'a> { type2: Type2::Typename { ident: ident.clone(), generic_args: None, + #[cfg(feature = "ast-span")] span: ident.span, }, operator: None, + #[cfg(feature = "ast-span")] span: ident.span, + #[cfg(feature = "ast-comments")] comments_after_type: None, }, + #[cfg(feature = "ast-comments")] comments_before_type: None, + #[cfg(feature = "ast-comments")] comments_after_type: None, }], + #[cfg(feature = "ast-span")] span: ident.span, } } diff --git a/src/faker.rs b/src/faker.rs index 70936d02..1e662a53 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -307,6 +307,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { for (occur, entry) in array_entries.iter() { if let Some(occur) = occur { match occur { + #[cfg(feature = "ast-span")] Occur::Optional(_) => { if FFaker.fake::() { let mut entry_f = Faker::new(self.cddl); @@ -319,6 +320,20 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { continue; } } + #[cfg(not(feature = "ast-span"))] + Occur::Optional => { + if FFaker.fake::() { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + + continue; + } + } + #[cfg(feature = "ast-span")] Occur::ZeroOrMore(_) => { let lower = (0..2).fake::(); let upper = (0..5).fake::(); @@ -337,6 +352,26 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { // Break due to ambiguity break; } + #[cfg(not(feature = "ast-span"))] + Occur::ZeroOrMore => { + let lower = (0..2).fake::(); + let upper = (0..5).fake::(); + + // If the random lower >= random upper, the random array + // will be empty. + for _ in lower..upper { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + + // Break due to ambiguity + break; + } + #[cfg(feature = "ast-span")] Occur::OneOrMore(_) => { for _ in 0..(1..5).fake::() { let mut entry_f = Faker::new(self.cddl); @@ -350,6 +385,20 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { // Break due to ambiguity break; } + #[cfg(not(feature = "ast-span"))] + Occur::OneOrMore => { + for _ in 0..(1..5).fake::() { + let mut entry_f = Faker::new(self.cddl); + entry_f.visit_type(entry)?; + + if let Some(value) = entry_f.faked_json { + array.push(value); + } + } + + // Break due to ambiguity + break; + } Occur::Exact { lower, upper, .. } => { if let Some(lower) = lower { if let Some(upper) = upper { @@ -405,11 +454,18 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { if let Entries::Map(map_entries) = &mut self.entries { if let Some(Value::Object(map)) = self.faked_json.as_mut() { for (k, (occur, v)) in map_entries.iter() { + #[cfg(feature = "ast-span")] let generate = if let Some(Occur::Optional(_)) = occur { FFaker.fake::() } else { true }; + #[cfg(not(feature = "ast-span"))] + let generate = if let Some(Occur::Optional) = occur { + FFaker.fake::() + } else { + true + }; if generate { let mut entry_f = Faker::new(self.cddl); From 3d3625ef1fd73c63230810fcdf5bf5400396bdd5 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:19:27 -0400 Subject: [PATCH 08/24] docker image scan workflow --- .github/workflows/anchore-analysis.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/anchore-analysis.yml b/.github/workflows/anchore-analysis.yml index 97ce7a93..744bcdbb 100644 --- a/.github/workflows/anchore-analysis.yml +++ b/.github/workflows/anchore-analysis.yml @@ -9,9 +9,17 @@ name: Anchore Container Scan on: push: branches: [main] + paths: + - Dockerfile + - '.dockerignore' + - '.github/workflows/anchore-analysis.yml' pull_request: # The branches below must be a subset of the branches above branches: [main] + paths: + - Dockerfile + - '.dockerignore' + - '.github/workflows/anchore-analysis.yml' schedule: - cron: '0 2 * * 4' From 3819efb68487131f6df100fb14247b56f822fd21 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:21:00 -0400 Subject: [PATCH 09/24] remove beta from checks --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2b666c9..8a50add1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,7 +59,7 @@ jobs: wasm-compilation-check: strategy: matrix: - rust_toolchain: [stable, beta] + rust_toolchain: [stable] name: Compilation check for wasm target runs-on: ubuntu-latest steps: @@ -83,7 +83,7 @@ jobs: test-suite: strategy: matrix: - rust_toolchain: [stable, beta] + rust_toolchain: [stable] os: [ubuntu-latest, macOS-latest, windows-latest] name: Test suite runs-on: ${{ matrix.os }} From 6bf7ab1fe626ea65cd191313e80c138c8b87043f Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:25:10 -0400 Subject: [PATCH 10/24] fix codeql workflow --- .github/workflows/codeql-analysis.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 840c472d..2615a467 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -95,16 +95,6 @@ jobs: run: | wasm-pack build --release - # Initializes the CodeQL tools for scanning. - - name: Initialize CodeQL - uses: github/codeql-action/init@v1 - with: - languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild From 16b005cf6893ff5feea41494e97525609360d7c5 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:29:09 -0400 Subject: [PATCH 11/24] bump beta version --- Cargo.toml | 2 +- README.md | 6 +++--- src/lib.rs | 2 +- www/package-lock.json | 6 +++--- www/package.json | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4147d378..e8d8abba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ repository = "https://github.com/anweiss/cddl" homepage = "https://cddl.anweiss.tech" categories = ["parser-implementations", "encoding", "development-tools", "wasm"] license = "MIT" -version = "0.9.0-beta.0" +version = "0.9.0-beta.1" authors = ["Andrew Weiss "] readme = "README.md" edition = "2018" diff --git a/README.md b/README.md index 688b03ec..a73dafb2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # cddl-rs -[![crates.io](https://img.shields.io/crates/v/cddl.svg)](https://crates.io/crates/cddl) [![docs.rs](https://docs.rs/cddl/badge.svg)](https://docs.rs/cddl) [![Publish packages](https://github.com/anweiss/cddl/workflows/Publish%20packages/badge.svg?branch=0.9.0-beta.0&event=release)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Publish+packages%22) [![Build and Test](https://github.com/anweiss/cddl/workflows/Build%20and%20Test/badge.svg)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Build+and+Test%22) [![Active Development](https://img.shields.io/badge/Maintenance%20Level-Actively%20Developed-brightgreen.svg)](https://gist.github.com/cheerfulstoic/d107229326a01ff0f333a1d3476e068d) +[![crates.io](https://img.shields.io/crates/v/cddl.svg)](https://crates.io/crates/cddl) [![docs.rs](https://docs.rs/cddl/badge.svg)](https://docs.rs/cddl) [![Publish packages](https://github.com/anweiss/cddl/workflows/Publish%20packages/badge.svg?branch=0.9.0-beta.1&event=release)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Publish+packages%22) [![Build and Test](https://github.com/anweiss/cddl/workflows/Build%20and%20Test/badge.svg)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Build+and+Test%22) > This crate was originally developed as a personal learning exercise for getting acquainted with Rust and parsing in general. There are likely more performant and stable libraries out there for parsing CDDL. While there are some examples of this crate being used in production, careful consideration should be made prior to using this crate as such. @@ -140,7 +140,7 @@ Simply add the dependency to `Cargo.toml`: ```toml [dependencies] -cddl = "0.9.0-beta.0" +cddl = "0.9.0-beta.1" ``` Both JSON and CBOR validation require `std`. @@ -388,7 +388,7 @@ Only the lexer and parser can be used in a `no_std` context provided that a heap ```toml [dependencies] -cddl = { version = "0.9.0-beta.0", default-features = false } +cddl = { version = "0.9.0-beta.1", default-features = false } ``` Zero-copy parsing is implemented to the extent that is possible. Allocation is required for error handling and diagnostics. diff --git a/src/lib.rs b/src/lib.rs index 8a14ad5b..d23c9301 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,7 @@ //! [![crates.io](https://img.shields.io/crates/v/cddl.svg)](https://crates.io/crates/cddl) //! [![docs.rs](https://docs.rs/cddl/badge.svg)](https://docs.rs/cddl) //! [![Publish -//! packages](https://github.com/anweiss/cddl/workflows/Publish%20packages/badge.svg?branch=0.9.0-beta.0&event=release)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Publish+packages%22) +//! packages](https://github.com/anweiss/cddl/workflows/Publish%20packages/badge.svg?branch=0.9.0-beta.1&event=release)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Publish+packages%22) //! [![Build and //! Test](https://github.com/anweiss/cddl/workflows/Build%20and%20Test/badge.svg)](https://github.com/anweiss/cddl/actions?query=workflow%3A%22Build+and+Test%22) //! [![Active diff --git a/www/package-lock.json b/www/package-lock.json index 0fbc6593..154dd026 100644 --- a/www/package-lock.json +++ b/www/package-lock.json @@ -1,12 +1,12 @@ { "name": "cddl", - "version": "0.9.0-beta.0", + "version": "0.9.0-beta.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "cddl", - "version": "0.9.0-beta.0", + "version": "0.9.0-beta.1", "license": "MIT", "dependencies": { "cddl": "file:../pkg" @@ -25,7 +25,7 @@ }, "../pkg": { "name": "cddl", - "version": "0.9.0-beta.0", + "version": "0.9.0-beta.1", "license": "MIT" }, "node_modules/@discoveryjs/json-ext": { diff --git a/www/package.json b/www/package.json index c7ef1209..320f070e 100644 --- a/www/package.json +++ b/www/package.json @@ -1,6 +1,6 @@ { "name": "cddl", - "version": "0.9.0-beta.0", + "version": "0.9.0-beta.1", "description": "Parser for the Concise data definition language (CDDL)", "main": "index.js", "scripts": { From 5b27fe896bfdbd25760e29e3c39c9d20bed26981 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:34:46 -0400 Subject: [PATCH 12/24] caching --- .github/workflows/anchore-analysis.yml | 21 +++++++++++++++++++-- .github/workflows/codeql-analysis.yml | 7 +++++++ .github/workflows/release-cddl.yml | 7 +++++++ 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.github/workflows/anchore-analysis.yml b/.github/workflows/anchore-analysis.yml index 744bcdbb..58f89653 100644 --- a/.github/workflows/anchore-analysis.yml +++ b/.github/workflows/anchore-analysis.yml @@ -30,8 +30,25 @@ jobs: - name: Checkout repository uses: actions/checkout@v2 - - name: Build the Docker image - run: docker build -t ghcr.io/anweiss/cddl-cli:latest . + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Cache Docker layers + uses: actions/cache@v2 + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Build and push + uses: docker/build-push-action@v2 + with: + context: . + push: false + tags: ghcr.io/anweiss/cddl-cli:latest + cache-from: type=local,src=/tmp/.buildx-cache + cache-to: type=local,dest=/tmp/.buildx-cache-new - name: Run the Anchore scan action itself with GitHub Advanced Security code scanning integration enabled uses: anchore/scan-action@main diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 2615a467..ae96816f 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -113,3 +113,10 @@ jobs: - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 + + - uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- diff --git a/.github/workflows/release-cddl.yml b/.github/workflows/release-cddl.yml index 5f433b8d..92cbc363 100644 --- a/.github/workflows/release-cddl.yml +++ b/.github/workflows/release-cddl.yml @@ -107,6 +107,13 @@ jobs: npm install npm run build + - uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + draft-release: name: Draft Release needs: From cd9799383b6ee25720021a39678bc4754851c2af Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:38:03 -0400 Subject: [PATCH 13/24] fix codeql workflow --- .github/workflows/codeql-analysis.yml | 98 ++++++++++++++------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ae96816f..9db04ee1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -1,28 +1,16 @@ -# For most projects, this workflow file will not need changing; you simply need -# to commit it to your repository. -# -# You may wish to alter this file to override the set of languages analyzed, -# or to provide custom queries or build logic. -# -# ******** NOTE ******** -# We have attempted to detect the languages in your repository. Please check -# the `language` matrix defined below to confirm you have the correct set of -# supported CodeQL languages. -# name: 'CodeQL' on: push: branches: [main] pull_request: - # The branches below must be a subset of the branches above branches: [main] schedule: - cron: '35 17 * * 4' jobs: - analyze: - name: Analyze + analyze-node: + name: Analyze Node.js runs-on: ubuntu-latest permissions: actions: read @@ -33,9 +21,6 @@ jobs: fail-fast: false matrix: language: ['javascript'] - # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] - # Learn more: - # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository @@ -62,55 +47,74 @@ jobs: run: | wasm-pack build --target nodejs --scope anweiss --release - # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} - # If you wish to specify custom queries, you can do so here or in a config file. - # By default, queries listed here will override any specified in a config file. - # Prefix the list here with "+" to use these queries and those in the config file. - # queries: ./path/to/local/query, your-org/your-repo/queries@main - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v1 + + - uses: actions/cache@v2 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + analyze-web: + name: Analyze web + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language + strategy: + fail-fast: false + matrix: + language: ['javascript'] - #- run: | - # make bootstrap - # make release + steps: + - name: Checkout repository + uses: actions/checkout@v2 - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + - name: Install Rust + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + target: wasm32-unknown-unknown + + - name: Install Node.js + uses: actions/setup-node@v1 + with: + node-version: '16' + + - name: Install wasmpack + run: | + curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh + + - name: Build wasm for Node.js + run: | + wasm-pack build --target nodejs --scope anweiss --release + + - name: Initialize CodeQL + uses: github/codeql-action/init@v1 + with: + languages: ${{ matrix.language }} - name: Build wasm for web run: | wasm-pack build --release - # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). - # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 https://git.io/JvXDl - - # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines - # and modify them (or add more) to build your code if your project - # uses a compiled language - - #- run: | - # make bootstrap - # make release - - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 From 14a49cd4bce44ba014e0e989fdcd584abf3a318e Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 4 Oct 2021 13:40:20 -0400 Subject: [PATCH 14/24] fix workflows --- .github/workflows/anchore-analysis.yml | 2 +- .github/workflows/codeql-analysis.yml | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.github/workflows/anchore-analysis.yml b/.github/workflows/anchore-analysis.yml index 58f89653..64935e75 100644 --- a/.github/workflows/anchore-analysis.yml +++ b/.github/workflows/anchore-analysis.yml @@ -41,7 +41,7 @@ jobs: restore-keys: | ${{ runner.os }}-buildx- - - name: Build and push + - name: Build image uses: docker/build-push-action@v2 with: context: . diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9db04ee1..0ac58c12 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -99,10 +99,6 @@ jobs: run: | curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh - - name: Build wasm for Node.js - run: | - wasm-pack build --target nodejs --scope anweiss --release - - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: From ee8c3f86594ad1049329da2303de51cc6c545d4d Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:31:12 -0400 Subject: [PATCH 15/24] refactor parts of the library and additional faker implementation --- README.md | 2 +- src/faker.rs | 235 ++++++++++++---- src/lib.rs | 2 + src/util.rs | 634 ++++++++++++++++++++++++++++++++++++++++++ src/validator/cbor.rs | 4 +- src/validator/json.rs | 11 +- src/validator/mod.rs | 616 +--------------------------------------- 7 files changed, 836 insertions(+), 668 deletions(-) create mode 100644 src/util.rs diff --git a/README.md b/README.md index a73dafb2..55afdd15 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Also bundled into this repository is a basic language server implementation and - [x] Validate CBOR data structures - [x] Validate JSON documents - [x] Basic REPL -- [ ] Generate dummy JSON from conformant CDDL +- [x] Generate dummy JSON from conformant CDDL - [x] As close to zero-copy as possible - [x] Compile WebAssembly target for browser and Node.js - [x] `no_std` support (lexing and parsing only) diff --git a/src/faker.rs b/src/faker.rs index 1e662a53..3068a6cd 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -1,7 +1,7 @@ use crate::{ ast::*, token::{lookup_ident, Token}, - validator::*, + util::*, visitor::{self, *}, }; @@ -67,6 +67,41 @@ impl<'a> Faker<'a> { is_group_to_choice_enum: false, } } + + fn process_generic_args( + &mut self, + ident: &Identifier<'a>, + generic_args: &GenericArgs<'a>, + ) -> visitor::Result { + if let Some(rule) = rule_from_ident(self.cddl, ident) { + if let Some(gr) = self + .generic_rules + .iter_mut() + .find(|gr| gr.name == ident.ident) + { + for arg in generic_args.args.iter() { + gr.args.push((*arg.arg).clone()); + } + } else if let Some(params) = generic_params_from_rule(rule) { + self.generic_rules.push(GenericRule { + name: ident.ident, + params, + args: generic_args + .args + .iter() + .cloned() + .map(|arg| *arg.arg) + .collect(), + }); + } + + self.eval_generic_rule = Some(ident.ident); + + return self.visit_rule(rule); + } + + Ok(()) + } } enum Entries<'a> { @@ -188,7 +223,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { for (idx, gp) in gr.params.iter().enumerate() { if let Some(arg) = gr.args.get(idx) { if *gp == target_ident.ident { - let t2 = Type2::from(arg.clone()); + let t2 = Type2::from((*arg).clone()); if *gp == controller_ident.ident { return self.visit_control_operator(&t2, ctrl, &t2); @@ -212,7 +247,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { for (idx, gp) in gr.params.iter().enumerate() { if let Some(arg) = gr.args.get(idx) { if *gp == target_ident.ident { - let t2 = Type2::from(arg.clone()); + let t2 = Type2::from((*arg).clone()); return self.visit_control_operator(&t2, ctrl, controller); } } @@ -239,6 +274,115 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { Ok(()) } + fn visit_range( + &mut self, + lower: &Type2<'a>, + upper: &Type2<'a>, + is_inclusive: bool, + ) -> visitor::Result { + match lower { + Type2::IntValue { value: lower_v, .. } => match upper { + Type2::IntValue { value: upper, .. } => { + if is_inclusive { + self.faked_json = Some((*lower_v..=*upper).fake::().into()); + } else { + self.faked_json = Some((*lower_v..*upper).fake::().into()); + } + } + Type2::UintValue { value: upper, .. } => { + if is_inclusive { + self.faked_json = Some((*lower_v..=*upper as isize).fake::().into()); + } else { + self.faked_json = Some((*lower_v..*upper as isize).fake::().into()); + } + } + Type2::Typename { + ident, + generic_args, + .. + } => { + if let Some(ga) = generic_args { + return self.process_generic_args(ident, ga); + } + + if let Some(t2) = numeric_range_bound_from_ident(self.cddl, ident) { + return self.visit_range(lower, t2, is_inclusive); + } + } + _ => return Ok(()), + }, + Type2::UintValue { value: lower_v, .. } => match upper { + Type2::IntValue { value: upper, .. } => { + if is_inclusive { + self.faked_json = Some((*lower_v..=*upper as usize).fake::().into()); + } else { + self.faked_json = Some((*lower_v..*upper as usize).fake::().into()); + } + } + Type2::UintValue { value: upper, .. } => { + if is_inclusive { + self.faked_json = Some((*lower_v..=*upper).fake::().into()); + } else { + self.faked_json = Some((*lower_v..*upper).fake::().into()); + } + } + Type2::Typename { + ident, + generic_args, + .. + } => { + if let Some(ga) = generic_args { + return self.process_generic_args(ident, ga); + } + + if let Some(t2) = numeric_range_bound_from_ident(self.cddl, ident) { + return self.visit_range(lower, t2, is_inclusive); + } + } + _ => return Ok(()), + }, + Type2::FloatValue { value: lower_v, .. } => match upper { + Type2::FloatValue { value: upper, .. } => { + if is_inclusive { + self.faked_json = Some((*lower_v..=*upper).fake::().into()); + } else { + self.faked_json = Some((*lower_v..*upper).fake::().into()); + } + } + Type2::Typename { + ident, + generic_args, + .. + } => { + if let Some(ga) = generic_args { + return self.process_generic_args(ident, ga); + } + + if let Some(t2) = numeric_range_bound_from_ident(self.cddl, ident) { + return self.visit_range(lower, t2, is_inclusive); + } + } + _ => return Ok(()), + }, + Type2::Typename { + ident, + generic_args, + .. + } => { + if let Some(ga) = generic_args { + return self.process_generic_args(ident, ga); + } + + if let Some(t2) = numeric_range_bound_from_ident(self.cddl, ident) { + return self.visit_range(t2, upper, is_inclusive); + } + } + _ => return Ok(()), + } + + Ok(()) + } + fn visit_value_member_key_entry( &mut self, entry: &ValueMemberKeyEntry<'a>, @@ -311,6 +455,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { Occur::Optional(_) => { if FFaker.fake::() { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -324,6 +471,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { Occur::Optional => { if FFaker.fake::() { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -342,6 +492,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { // will be empty. for _ in lower..upper { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -361,6 +514,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { // will be empty. for _ in lower..upper { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -375,6 +531,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { Occur::OneOrMore(_) => { for _ in 0..(1..5).fake::() { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -389,6 +548,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { Occur::OneOrMore => { for _ in 0..(1..5).fake::() { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -404,6 +566,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { if let Some(upper) = upper { for _ in *lower..*upper { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -413,6 +578,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } else { for _ in *lower..(lower + (0..5).fake::()) { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -423,6 +591,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } else if let Some(upper) = upper { for _ in 0..(upper - (0..=*upper).fake::()) { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -434,6 +605,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } } else { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(entry)?; if let Some(value) = entry_f.faked_json { @@ -469,6 +643,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { if generate { let mut entry_f = Faker::new(self.cddl); + entry_f.eval_generic_rule = self.eval_generic_rule; + entry_f.generic_rules = self.generic_rules.clone(); + entry_f.ctrl = self.ctrl.clone(); entry_f.visit_type(v)?; if let Some(value) = entry_f.faked_json { @@ -487,27 +664,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { .. } => { if let Some(ga) = generic_args { - if let Some(rule) = rule_from_ident(self.cddl, ident) { - if let Some(gr) = self - .generic_rules - .iter_mut() - .find(|gr| gr.name == ident.ident) - { - for arg in ga.args.iter() { - gr.args.push((*arg.arg).clone()); - } - } else if let Some(params) = generic_params_from_rule(rule) { - self.generic_rules.push(GenericRule { - name: ident.ident, - params, - args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(), - }); - } - - self.eval_generic_rule = Some(ident.ident); - - return self.visit_rule(rule); - } + return self.process_generic_args(ident, ga); } return self.visit_identifier(ident); @@ -518,28 +675,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { .. } => { if let Some(ga) = generic_args { - if let Some(rule) = rule_from_ident(self.cddl, ident) { - if let Some(gr) = self - .generic_rules - .iter_mut() - .find(|gr| gr.name == ident.ident) - { - for arg in ga.args.iter() { - gr.args.push((*arg.arg).clone()); - } - } else if let Some(params) = generic_params_from_rule(rule) { - self.generic_rules.push(GenericRule { - name: ident.ident, - params, - args: ga.args.iter().cloned().map(|arg| *arg.arg).collect(), - }); - } + self.is_group_to_choice_enum = true; - self.eval_generic_rule = Some(ident.ident); - self.is_group_to_choice_enum = true; - - return self.visit_rule(rule); - } + return self.process_generic_args(ident, ga); } self.is_group_to_choice_enum = true; @@ -681,10 +819,9 @@ mod tests { fn test_faker() -> Result<()> { let cddl = indoc!( r#" - a = b / d - b = { c } - c = ( a: tstr ) - d = [ + tstr ] + messages = message<"reboot", "now"> / message<"sleep", a .. 5> + message = {type: t, value: v} + a = 1 / 2 / 3 "# ); diff --git a/src/lib.rs b/src/lib.rs index d23c9301..7ffb95b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -555,6 +555,8 @@ pub mod parser; pub mod repl; /// CDDL tokens for lexing pub mod token; +/// CDDL helper functions +pub mod util; /// Validators for JSON and CBOR data structures #[cfg(feature = "std")] pub mod validator; diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 00000000..9f05db1d --- /dev/null +++ b/src/util.rs @@ -0,0 +1,634 @@ +use crate::{ast::*, token::*}; + +/// Find non-choice alternate rule from a given identifier +pub fn rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Rule<'a>> { + cddl.rules.iter().find_map(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident && !rule.is_type_choice_alternate => Some(r), + Rule::Group { rule, .. } if rule.name == *ident && !rule.is_group_choice_alternate => Some(r), + _ => None, + }) +} + +/// Find text values from a given identifier +pub fn text_value_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Type2<'a>> { + cddl.rules.iter().find_map(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => { + rule.value.type_choices.iter().find_map(|tc| { + if tc.type1.operator.is_none() { + match &tc.type1.type2 { + Type2::TextValue { .. } | Type2::UTF8ByteString { .. } => Some(&tc.type1.type2), + Type2::Typename { ident, .. } => text_value_from_ident(cddl, ident), + Type2::ParenthesizedType { pt, .. } => pt.type_choices.iter().find_map(|tc| { + if tc.type1.operator.is_none() { + text_value_from_type2(cddl, &tc.type1.type2) + } else { + None + } + }), + _ => None, + } + } else { + None + } + }) + } + _ => None, + }) +} + +/// Find text values from a given Type2 +pub fn text_value_from_type2<'a>(cddl: &'a CDDL, t2: &'a Type2<'a>) -> Option<&'a Type2<'a>> { + match t2 { + Type2::TextValue { .. } | Type2::UTF8ByteString { .. } => Some(t2), + Type2::Typename { ident, .. } => text_value_from_ident(cddl, ident), + Type2::Array { group, .. } => group.group_choices.iter().find_map(|gc| { + if gc.group_entries.len() == 2 { + if let Some(ge) = gc.group_entries.first() { + if let GroupEntry::ValueMemberKey { ge, .. } = &ge.0 { + if ge.member_key.is_none() { + ge.entry_type.type_choices.iter().find_map(|tc| { + if tc.type1.operator.is_none() { + text_value_from_type2(cddl, &tc.type1.type2) + } else { + None + } + }) + } else { + None + } + } else { + None + } + } else { + None + } + } else { + None + } + }), + Type2::ParenthesizedType { pt, .. } => pt.type_choices.iter().find_map(|tc| { + if tc.type1.operator.is_none() { + text_value_from_type2(cddl, &tc.type1.type2) + } else { + None + } + }), + _ => None, + } +} + +/// Unwrap array, map or tag type rule from ident +pub fn unwrap_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Rule<'a>> { + cddl.rules.iter().find_map(|r| match r { + Rule::Type { + rule: + TypeRule { + name, + is_type_choice_alternate, + value: Type { type_choices, .. }, + .. + }, + .. + } if name == ident && !is_type_choice_alternate => { + let match_fn = |tc: &TypeChoice| { + matches!( + tc.type1.type2, + Type2::Map { .. } | Type2::Array { .. } | Type2::TaggedData { .. } + ) + }; + + if type_choices.iter().any(match_fn) { + Some(r) + } else if let Some(ident) = type_choices.iter().find_map(|tc| { + if let Type2::Typename { + ident, + generic_args: None, + .. + } = &tc.type1.type2 + { + Some(ident) + } else { + None + } + }) { + unwrap_rule_from_ident(cddl, ident) + } else { + None + } + } + _ => None, + }) +} + +/// Find non-group choice alternate rule from a given identifier +pub fn group_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a GroupRule<'a>> { + cddl.rules.iter().find_map(|r| match r { + Rule::Group { rule, .. } if rule.name == *ident && !rule.is_group_choice_alternate => { + Some(rule.as_ref()) + } + _ => None, + }) +} + +/// Find non-group choice alternate rule from a given identifier +pub fn type_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a TypeRule<'a>> { + cddl.rules.iter().find_map(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident && !rule.is_type_choice_alternate => Some(rule), + _ => None, + }) +} + +/// Retrieve a numeric value range bound from a given identifier +pub fn numeric_range_bound_from_ident<'a>( + cddl: &'a CDDL, + ident: &Identifier, +) -> Option<&'a Type2<'a>> { + cddl.rules.iter().find_map(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident && !rule.is_type_choice_alternate => { + match rule.value.type_choices.first() { + Some(TypeChoice { + type1: Type1 { + type2, operator, .. + }, + .. + }) if operator.is_none() => match type2 { + Type2::IntValue { .. } | Type2::UintValue { .. } | Type2::FloatValue { .. } => { + Some(type2) + } + Type2::Typename { ident, .. } => numeric_range_bound_from_ident(cddl, ident), + _ => None, + }, + _ => None, + } + } + _ => None, + }) +} + +/// Retrieve the list of generic parameters for a given rule +pub fn generic_params_from_rule<'a>(rule: &Rule<'a>) -> Option> { + match rule { + Rule::Type { rule, .. } => rule + .generic_params + .as_ref() + .map(|gp| gp.params.iter().map(|gp| gp.param.ident).collect()), + Rule::Group { rule, .. } => rule + .generic_params + .as_ref() + .map(|gp| gp.params.iter().map(|gp| gp.param.ident).collect()), + } +} + +/// Find all type choice alternate rules from a given identifier +pub fn type_choice_alternates_from_ident<'a>( + cddl: &'a CDDL, + ident: &Identifier, +) -> Vec<&'a Type<'a>> { + cddl + .rules + .iter() + .filter_map(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => Some(&rule.value), + _ => None, + }) + .collect::>() +} + +/// Find all group choice alternate rules from a given identifier +pub fn group_choice_alternates_from_ident<'a>( + cddl: &'a CDDL, + ident: &Identifier, +) -> Vec<&'a GroupEntry<'a>> { + cddl + .rules + .iter() + .filter_map(|r| match r { + Rule::Group { rule, .. } if &rule.name == ident => Some(&rule.entry), + _ => None, + }) + .collect::>() +} + +/// Convert a given group choice to a list of type choices +pub fn type_choices_from_group_choice<'a>( + cddl: &'a CDDL, + grpchoice: &GroupChoice<'a>, +) -> Vec> { + let mut type_choices = Vec::new(); + for ge in grpchoice.group_entries.iter() { + match &ge.0 { + GroupEntry::ValueMemberKey { ge, .. } => { + type_choices.append(&mut ge.entry_type.type_choices.clone()); + } + GroupEntry::TypeGroupname { ge, .. } => { + // TODO: parse generic args + if let Some(r) = rule_from_ident(cddl, &ge.name) { + match r { + Rule::Type { rule, .. } => type_choices.append(&mut rule.value.type_choices.clone()), + Rule::Group { rule, .. } => type_choices.append(&mut type_choices_from_group_choice( + cddl, + &GroupChoice::new(vec![rule.entry.clone()]), + )), + } + } + } + GroupEntry::InlineGroup { group, .. } => { + for gc in group.group_choices.iter() { + type_choices.append(&mut type_choices_from_group_choice(cddl, gc)); + } + } + } + } + + type_choices +} + +/// Is the given identifier associated with a null data type +pub fn is_ident_null_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::NULL | Token::NIL = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_null_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a boolean data type +pub fn is_ident_bool_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::BOOL = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_bool_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Does the given boolean identifier match the boolean value +pub fn ident_matches_bool_value(cddl: &CDDL, ident: &Identifier, value: bool) -> bool { + if let Token::TRUE = lookup_ident(ident.ident) { + if value { + return true; + } + } + + if let Token::FALSE = lookup_ident(ident.ident) { + if !value { + return true; + } + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + ident_matches_bool_value(cddl, ident, value) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a URI data type +pub fn is_ident_uri_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::URI = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_uri_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a b64url data type +pub fn is_ident_b64url_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::B64URL = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_b64url_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a tdate data type +pub fn is_ident_tdate_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::TDATE = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_tdate_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a time data type +pub fn is_ident_time_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::TIME = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_time_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a numeric data type +pub fn is_ident_numeric_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::UINT + | Token::NINT + | Token::INTEGER + | Token::INT + | Token::NUMBER + | Token::FLOAT + | Token::FLOAT16 + | Token::FLOAT32 + | Token::FLOAT64 + | Token::FLOAT1632 + | Token::FLOAT3264 + | Token::UNSIGNED = lookup_ident(ident.ident) + { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_numeric_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a uint data type +pub fn is_ident_uint_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::UINT = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_uint_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a nint data type +pub fn is_ident_nint_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::NINT = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_nint_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with an integer data type +pub fn is_ident_integer_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::INT | Token::INTEGER | Token::NINT | Token::UINT | Token::NUMBER | Token::UNSIGNED = + lookup_ident(ident.ident) + { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_integer_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a float data type +pub fn is_ident_float_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::FLOAT + | Token::FLOAT16 + | Token::FLOAT1632 + | Token::FLOAT32 + | Token::FLOAT3264 + | Token::FLOAT64 = lookup_ident(ident.ident) + { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_float_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a string data type +pub fn is_ident_string_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::TEXT | Token::TSTR = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_string_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with the any type +pub fn is_ident_any_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::ANY = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_any_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Is the given identifier associated with a byte string data type +pub fn is_ident_byte_string_data_type(cddl: &CDDL, ident: &Identifier) -> bool { + if let Token::BSTR | Token::BYTES = lookup_ident(ident.ident) { + return true; + } + + cddl.rules.iter().any(|r| match r { + Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { + if let Type2::Typename { ident, .. } = &tc.type1.type2 { + is_ident_byte_string_data_type(cddl, ident) + } else { + false + } + }), + _ => false, + }) +} + +/// Retrieve number of group entries from a group choice. This is currently only +/// used for determining map equality/inequality and for validating the number +/// of entries in arrays, but may be useful in other contexts. The occurrence is +/// only captured for the second element of the CDDL array to avoid ambiguity in +/// non-homogenous array definitions +pub fn entry_counts_from_group_choice(cddl: &CDDL, group_choice: &GroupChoice) -> EntryCount { + let mut count = 0; + let mut entry_occurrence = None; + + for (idx, ge) in group_choice.group_entries.iter().enumerate() { + match &ge.0 { + GroupEntry::ValueMemberKey { ge, .. } => { + if idx == 1 { + if let Some(occur) = &ge.occur { + entry_occurrence = Some(occur.occur.clone()) + } + } + + count += 1; + } + GroupEntry::InlineGroup { group, occur, .. } => { + if idx == 1 { + if let Some(occur) = occur { + entry_occurrence = Some(occur.occur.clone()) + } + } + for gc in group.group_choices.iter() { + count += entry_counts_from_group_choice(cddl, gc).count; + } + } + GroupEntry::TypeGroupname { ge, .. } => { + if idx == 1 { + if let Some(occur) = &ge.occur { + entry_occurrence = Some(occur.occur.clone()) + } + } + if let Some(gr) = group_rule_from_ident(cddl, &ge.name) { + count += + entry_counts_from_group_choice(cddl, &GroupChoice::new(vec![gr.entry.clone()])).count; + } else { + count += 1; + } + } + } + } + + EntryCount { + count, + entry_occurrence, + } +} + +/// Entry count +#[derive(Clone, Debug)] +pub struct EntryCount { + /// Count + pub count: u64, + /// Optional occurrence + pub entry_occurrence: Option, +} + +/// Regex needs to be formatted in a certain way so it can be parsed. See +/// +pub fn format_regex(input: &str) -> Option { + let mut formatted_regex = String::from(input); + let mut unescape = Vec::new(); + for (idx, c) in formatted_regex.char_indices() { + if c == '\\' { + if let Some(c) = formatted_regex.chars().nth(idx + 1) { + if !regex_syntax::is_meta_character(c) && c != 'd' { + unescape.push(format!("\\{}", c)); + } + } + } + } + + for replace in unescape.iter() { + formatted_regex = + formatted_regex.replace(replace, &replace.chars().nth(1).unwrap().to_string()); + } + + for find in ["?=", "?!", "?<=", "?>(); self.visit_group(group)?; diff --git a/src/validator/json.rs b/src/validator/json.rs index ea305dd5..c4c88700 100644 --- a/src/validator/json.rs +++ b/src/validator/json.rs @@ -2,10 +2,11 @@ #![cfg(feature = "json")] #![cfg(not(feature = "lsp"))] -use super::*; use crate::{ ast::*, - token::{self, Token}, + token::{self, lookup_ident, Token}, + util::*, + validator::*, visitor::{self, *}, }; @@ -15,7 +16,7 @@ use chrono::{TimeZone, Utc}; use serde_json::Value; #[cfg(feature = "additional-controls")] -use control::{abnf_from_complex_controller, cat_operation, plus_operation, validate_abnf}; +use super::control::{abnf_from_complex_controller, cat_operation, plus_operation, validate_abnf}; /// JSON validation Result pub type Result = std::result::Result<(), Error>; @@ -1578,6 +1579,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { Type2::TextValue { value, .. } => self.visit_value(&token::Value::TEXT(value.clone())), Type2::Map { group, .. } => match &self.json { Value::Object(o) => { + #[allow(clippy::needless_collect)] let o = o.keys().cloned().collect::>(); self.visit_group(group)?; @@ -2604,6 +2606,9 @@ mod tests { #![allow(unused_imports)] use super::*; + + use crate::{cddl_from_str, lexer_from_str, validator::json}; + use indoc::indoc; #[cfg(feature = "additional-controls")] diff --git a/src/validator/mod.rs b/src/validator/mod.rs index 055612dd..d6c6b804 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -7,14 +7,7 @@ pub mod json; mod control; -use crate::{ - ast::{ - GroupChoice, GroupEntry, GroupRule, Identifier, Occur, Rule, Type, Type2, TypeChoice, TypeRule, - CDDL, - }, - token::*, - visitor::Visitor, -}; +use crate::{ast::Occur, token::*, util::EntryCount, visitor::Visitor}; use std::error::Error; @@ -24,6 +17,7 @@ use cbor::CBORValidator; use ciborium; #[cfg(feature = "json")] use json::JSONValidator; + use serde::de::Deserialize; #[cfg(target_arch = "wasm32")] @@ -263,520 +257,6 @@ pub fn validate_cbor_from_slice( .map(|_| JsValue::default()) } -/// Find non-choice alternate rule from a given identifier -pub fn rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Rule<'a>> { - cddl.rules.iter().find_map(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident && !rule.is_type_choice_alternate => Some(r), - Rule::Group { rule, .. } if rule.name == *ident && !rule.is_group_choice_alternate => Some(r), - _ => None, - }) -} - -/// Find text values from a given identifier -pub fn text_value_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Type2<'a>> { - cddl.rules.iter().find_map(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => { - rule.value.type_choices.iter().find_map(|tc| { - if tc.type1.operator.is_none() { - match &tc.type1.type2 { - Type2::TextValue { .. } | Type2::UTF8ByteString { .. } => Some(&tc.type1.type2), - Type2::Typename { ident, .. } => text_value_from_ident(cddl, ident), - Type2::ParenthesizedType { pt, .. } => pt.type_choices.iter().find_map(|tc| { - if tc.type1.operator.is_none() { - text_value_from_type2(cddl, &tc.type1.type2) - } else { - None - } - }), - _ => None, - } - } else { - None - } - }) - } - _ => None, - }) -} - -/// Find text values from a given Type2 -pub fn text_value_from_type2<'a>(cddl: &'a CDDL, t2: &'a Type2<'a>) -> Option<&'a Type2<'a>> { - match t2 { - Type2::TextValue { .. } | Type2::UTF8ByteString { .. } => Some(t2), - Type2::Typename { ident, .. } => text_value_from_ident(cddl, ident), - Type2::Array { group, .. } => group.group_choices.iter().find_map(|gc| { - if gc.group_entries.len() == 2 { - if let Some(ge) = gc.group_entries.first() { - if let GroupEntry::ValueMemberKey { ge, .. } = &ge.0 { - if ge.member_key.is_none() { - ge.entry_type.type_choices.iter().find_map(|tc| { - if tc.type1.operator.is_none() { - text_value_from_type2(cddl, &tc.type1.type2) - } else { - None - } - }) - } else { - None - } - } else { - None - } - } else { - None - } - } else { - None - } - }), - Type2::ParenthesizedType { pt, .. } => pt.type_choices.iter().find_map(|tc| { - if tc.type1.operator.is_none() { - text_value_from_type2(cddl, &tc.type1.type2) - } else { - None - } - }), - _ => None, - } -} - -/// Unwrap array, map or tag type rule from ident -pub fn unwrap_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Rule<'a>> { - cddl.rules.iter().find_map(|r| match r { - Rule::Type { - rule: - TypeRule { - name, - is_type_choice_alternate, - value: Type { type_choices, .. }, - .. - }, - .. - } if name == ident && !is_type_choice_alternate => { - let match_fn = |tc: &TypeChoice| { - matches!( - tc.type1.type2, - Type2::Map { .. } | Type2::Array { .. } | Type2::TaggedData { .. } - ) - }; - - if type_choices.iter().any(match_fn) { - Some(r) - } else if let Some(ident) = type_choices.iter().find_map(|tc| { - if let Type2::Typename { - ident, - generic_args: None, - .. - } = &tc.type1.type2 - { - Some(ident) - } else { - None - } - }) { - unwrap_rule_from_ident(cddl, ident) - } else { - None - } - } - _ => None, - }) -} - -/// Find non-group choice alternate rule from a given identifier -pub fn group_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a GroupRule<'a>> { - cddl.rules.iter().find_map(|r| match r { - Rule::Group { rule, .. } if rule.name == *ident && !rule.is_group_choice_alternate => { - Some(rule.as_ref()) - } - _ => None, - }) -} - -/// Find non-group choice alternate rule from a given identifier -pub fn type_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a TypeRule<'a>> { - cddl.rules.iter().find_map(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident && !rule.is_type_choice_alternate => Some(rule), - _ => None, - }) -} - -/// Retrieve the list of generic parameters for a given rule -pub fn generic_params_from_rule<'a>(rule: &Rule<'a>) -> Option> { - match rule { - Rule::Type { rule, .. } => rule - .generic_params - .as_ref() - .map(|gp| gp.params.iter().map(|gp| gp.param.ident).collect()), - Rule::Group { rule, .. } => rule - .generic_params - .as_ref() - .map(|gp| gp.params.iter().map(|gp| gp.param.ident).collect()), - } -} - -/// Find all type choice alternate rules from a given identifier -pub fn type_choice_alternates_from_ident<'a>( - cddl: &'a CDDL, - ident: &Identifier, -) -> Vec<&'a Type<'a>> { - cddl - .rules - .iter() - .filter_map(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => Some(&rule.value), - _ => None, - }) - .collect::>() -} - -/// Find all group choice alternate rules from a given identifier -pub fn group_choice_alternates_from_ident<'a>( - cddl: &'a CDDL, - ident: &Identifier, -) -> Vec<&'a GroupEntry<'a>> { - cddl - .rules - .iter() - .filter_map(|r| match r { - Rule::Group { rule, .. } if &rule.name == ident => Some(&rule.entry), - _ => None, - }) - .collect::>() -} - -/// Convert a given group choice to a list of type choices -pub fn type_choices_from_group_choice<'a>( - cddl: &'a CDDL, - grpchoice: &GroupChoice<'a>, -) -> Vec> { - let mut type_choices = Vec::new(); - for ge in grpchoice.group_entries.iter() { - match &ge.0 { - GroupEntry::ValueMemberKey { ge, .. } => { - type_choices.append(&mut ge.entry_type.type_choices.clone()); - } - GroupEntry::TypeGroupname { ge, .. } => { - // TODO: parse generic args - if let Some(r) = rule_from_ident(cddl, &ge.name) { - match r { - Rule::Type { rule, .. } => type_choices.append(&mut rule.value.type_choices.clone()), - Rule::Group { rule, .. } => type_choices.append(&mut type_choices_from_group_choice( - cddl, - &GroupChoice::new(vec![rule.entry.clone()]), - )), - } - } - } - GroupEntry::InlineGroup { group, .. } => { - for gc in group.group_choices.iter() { - type_choices.append(&mut type_choices_from_group_choice(cddl, gc)); - } - } - } - } - - type_choices -} - -/// Is the given identifier associated with a null data type -pub fn is_ident_null_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::NULL | Token::NIL = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_null_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a boolean data type -pub fn is_ident_bool_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::BOOL = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_bool_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Does the given boolean identifier match the boolean value -pub fn ident_matches_bool_value(cddl: &CDDL, ident: &Identifier, value: bool) -> bool { - if let Token::TRUE = lookup_ident(ident.ident) { - if value { - return true; - } - } - - if let Token::FALSE = lookup_ident(ident.ident) { - if !value { - return true; - } - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - ident_matches_bool_value(cddl, ident, value) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a URI data type -pub fn is_ident_uri_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::URI = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_uri_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a b64url data type -pub fn is_ident_b64url_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::B64URL = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_b64url_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a tdate data type -pub fn is_ident_tdate_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::TDATE = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_tdate_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a time data type -pub fn is_ident_time_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::TIME = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_time_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a numeric data type -pub fn is_ident_numeric_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::UINT - | Token::NINT - | Token::INTEGER - | Token::INT - | Token::NUMBER - | Token::FLOAT - | Token::FLOAT16 - | Token::FLOAT32 - | Token::FLOAT64 - | Token::FLOAT1632 - | Token::FLOAT3264 - | Token::UNSIGNED = lookup_ident(ident.ident) - { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_numeric_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a uint data type -pub fn is_ident_uint_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::UINT = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_uint_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a nint data type -pub fn is_ident_nint_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::NINT = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_nint_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with an integer data type -pub fn is_ident_integer_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::INT | Token::INTEGER | Token::NINT | Token::UINT | Token::NUMBER | Token::UNSIGNED = - lookup_ident(ident.ident) - { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_integer_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a float data type -pub fn is_ident_float_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::FLOAT - | Token::FLOAT16 - | Token::FLOAT1632 - | Token::FLOAT32 - | Token::FLOAT3264 - | Token::FLOAT64 = lookup_ident(ident.ident) - { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_float_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a string data type -pub fn is_ident_string_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::TEXT | Token::TSTR = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_string_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with the any type -pub fn is_ident_any_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::ANY = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_any_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - -/// Is the given identifier associated with a byte string data type -pub fn is_ident_byte_string_data_type(cddl: &CDDL, ident: &Identifier) -> bool { - if let Token::BSTR | Token::BYTES = lookup_ident(ident.ident) { - return true; - } - - cddl.rules.iter().any(|r| match r { - Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { - is_ident_byte_string_data_type(cddl, ident) - } else { - false - } - }), - _ => false, - }) -} - /// Validate array length and \[non\]homogeneity based on a given optional /// occurrence indicator. The first bool in the returned tuple indicates whether /// or not a subsequent validation of the array's elements shouch be homogenous. @@ -892,58 +372,6 @@ pub fn validate_array_occurrence<'de, T: Deserialize<'de>>( Ok((iter_items, allow_empty_array)) } -/// Retrieve number of group entries from a group choice. This is currently only -/// used for determining map equality/inequality and for validating the number -/// of entries in arrays, but may be useful in other contexts. The occurrence is -/// only captured for the second element of the CDDL array to avoid ambiguity in -/// non-homogenous array definitions -pub fn entry_counts_from_group_choice(cddl: &CDDL, group_choice: &GroupChoice) -> EntryCount { - let mut count = 0; - let mut entry_occurrence = None; - - for (idx, ge) in group_choice.group_entries.iter().enumerate() { - match &ge.0 { - GroupEntry::ValueMemberKey { ge, .. } => { - if idx == 1 { - if let Some(occur) = &ge.occur { - entry_occurrence = Some(occur.occur.clone()) - } - } - - count += 1; - } - GroupEntry::InlineGroup { group, occur, .. } => { - if idx == 1 { - if let Some(occur) = occur { - entry_occurrence = Some(occur.occur.clone()) - } - } - for gc in group.group_choices.iter() { - count += entry_counts_from_group_choice(cddl, gc).count; - } - } - GroupEntry::TypeGroupname { ge, .. } => { - if idx == 1 { - if let Some(occur) = &ge.occur { - entry_occurrence = Some(occur.occur.clone()) - } - } - if let Some(gr) = group_rule_from_ident(cddl, &ge.name) { - count += - entry_counts_from_group_choice(cddl, &GroupChoice::new(vec![gr.entry.clone()])).count; - } else { - count += 1; - } - } - } - } - - EntryCount { - count, - entry_occurrence, - } -} - /// Validate the number of entries given an array of possible valid entry counts pub fn validate_entry_count(valid_entry_counts: &[EntryCount], num_entries: usize) -> bool { valid_entry_counts.iter().any(|ec| { @@ -974,43 +402,3 @@ pub fn validate_entry_count(valid_entry_counts: &[EntryCount], num_entries: usiz } }) } - -/// Entry count -#[derive(Clone, Debug)] -pub struct EntryCount { - /// Count - pub count: u64, - /// Optional occurrence - pub entry_occurrence: Option, -} - -/// Regex needs to be formatted in a certain way so it can be parsed. See -/// -pub fn format_regex(input: &str) -> Option { - let mut formatted_regex = String::from(input); - let mut unescape = Vec::new(); - for (idx, c) in formatted_regex.char_indices() { - if c == '\\' { - if let Some(c) = formatted_regex.chars().nth(idx + 1) { - if !regex_syntax::is_meta_character(c) && c != 'd' { - unescape.push(format!("\\{}", c)); - } - } - } - } - - for replace in unescape.iter() { - formatted_regex = - formatted_regex.replace(replace, &replace.chars().nth(1).unwrap().to_string()); - } - - for find in ["?=", "?!", "?<=", "? Date: Tue, 5 Oct 2021 16:40:54 -0400 Subject: [PATCH 16/24] fix no_std build --- src/util.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/util.rs b/src/util.rs index 9f05db1d..425dd736 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,5 +1,11 @@ use crate::{ast::*, token::*}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +#[cfg(feature = "std")] +use regex_syntax; + /// Find non-choice alternate rule from a given identifier pub fn rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<&'a Rule<'a>> { cddl.rules.iter().find_map(|r| match r { @@ -604,6 +610,7 @@ pub struct EntryCount { /// Regex needs to be formatted in a certain way so it can be parsed. See /// +#[cfg(feature = "std")] pub fn format_regex(input: &str) -> Option { let mut formatted_regex = String::from(input); let mut unescape = Vec::new(); From 36ea8b97d283696d1782516090cfb9b22e25cb75 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:42:28 -0400 Subject: [PATCH 17/24] lib cleanup --- src/lib.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7ffb95b5..a53e0a5e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -533,15 +533,6 @@ extern crate alloc; #[cfg(not(feature = "std"))] extern crate core as std; -#[cfg(feature = "std")] -extern crate serde_json; - -#[cfg(feature = "std")] -extern crate uriparse; - -#[cfg(feature = "std")] -extern crate base64_url; - /// Abstract syntax tree representing a CDDL definition pub mod ast; /// Static error messages From 350c597b21da4f9ff7023d5901ce1dbe8c51c39c Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Tue, 5 Oct 2021 16:46:19 -0400 Subject: [PATCH 18/24] bump pretty_assertions dep --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e8d8abba..6abe8a9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ getrandom = { version = "0.2.3", features = ["js"] } [dev-dependencies] indoc = "1.0.3" -pretty_assertions = "0.7.2" +pretty_assertions = "1.0.0" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] crossterm = { version = "0.21.0", optional = true } From 9f8025e3153f365d65100922682631a7e1841427 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Thu, 7 Oct 2021 11:14:32 -0400 Subject: [PATCH 19/24] ast refactor --- src/ast.rs | 1208 ++++++++++++++++++++------------------ src/faker.rs | 86 +-- src/parser.rs | 298 +++++----- src/parser_tests.rs | 508 +++++++--------- src/util.rs | 76 +-- src/validator/cbor.rs | 108 ++-- src/validator/control.rs | 174 +++--- src/validator/json.rs | 92 +-- src/visitor.rs | 50 +- tests/parser.rs | 207 +++---- 10 files changed, 1391 insertions(+), 1416 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index a90c3b1f..bbd9fd74 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -140,7 +140,7 @@ impl<'a> fmt::Display for CDDL<'a> { /// DIGIT = %x30-39 /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Default)] pub struct Identifier<'a> { /// Identifier pub ident: &'a str, @@ -180,8 +180,7 @@ impl<'a> From<&'static str> for Identifier<'a> { return Identifier { ident, socket: Some(SocketPlug::GROUP), - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() }; } } @@ -189,8 +188,7 @@ impl<'a> From<&'static str> for Identifier<'a> { return Identifier { ident, socket: Some(SocketPlug::TYPE), - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() }; } } @@ -198,8 +196,7 @@ impl<'a> From<&'static str> for Identifier<'a> { Identifier { ident, socket: None, - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() } } } @@ -385,7 +382,7 @@ impl<'a> Rule<'a> { /// typename [genericparm] S assignt S type /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct TypeRule<'a> { /// Type name identifier #[cfg_attr(target_arch = "wasm32", serde(borrow))] @@ -501,7 +498,7 @@ impl<'a> fmt::Display for GroupRule<'a> { /// genericparm = "<" S id S *("," S id S ) ">" /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct GenericParams<'a> { /// List of generic parameters pub params: Vec>, @@ -510,19 +507,9 @@ pub struct GenericParams<'a> { pub span: Span, } -impl<'a> Default for GenericParams<'a> { - fn default() -> Self { - GenericParams { - params: Vec::new(), - #[cfg(feature = "ast-span")] - span: Span::default(), - } - } -} - /// Generic parameter #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Clone, Default)] pub struct GenericParam<'a> { /// Generic parameter pub param: Identifier<'a>, @@ -570,7 +557,7 @@ impl<'a> fmt::Display for GenericParams<'a> { /// genericarg = "<" S type1 S *("," S type1 S ) ">" /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct GenericArgs<'a> { /// Generic arguments pub args: Vec>, @@ -579,20 +566,9 @@ pub struct GenericArgs<'a> { pub span: Span, } -impl<'a> GenericArgs<'a> { - /// Default `GenericArg` - pub fn default() -> Self { - GenericArgs { - args: Vec::new(), - #[cfg(feature = "ast-span")] - span: Span::default(), - } - } -} - /// Generic argument #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct GenericArg<'a> { /// Generic argument pub arg: Box>, @@ -635,7 +611,7 @@ impl<'a> fmt::Display for GenericArgs<'a> { } /// A generic rule that has undergone monomorphization -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Default)] pub struct GenericRule<'a> { /// Name pub name: &'a str, @@ -651,7 +627,7 @@ pub struct GenericRule<'a> { /// type = type1 *(S "/" S type1) /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct Type<'a> { /// Type choices pub type_choices: Vec>, @@ -688,12 +664,12 @@ impl<'a> From<&Identifier<'a>> for Type<'a> { Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: ident.clone(), generic_args: None, #[cfg(feature = "ast-span")] span: ident.span, - }, + }), operator: None, #[cfg(feature = "ast-span")] span: ident.span, @@ -713,7 +689,7 @@ impl<'a> From<&Identifier<'a>> for Type<'a> { /// Type choice #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct TypeChoice<'a> { /// Type choice @@ -774,11 +750,11 @@ impl<'a> Type<'a> { if self.type_choices.len() == 1 { if let Some(tc) = self.type_choices.first() { if tc.type1.operator.is_none() { - if let Type2::Typename { + if let Type2::Typename(Typename { ident, generic_args, span, - } = &tc.type1.type2 + }) = &tc.type1.type2 { return Some((ident.clone(), generic_args.clone(), *span)); } @@ -797,10 +773,10 @@ impl<'a> Type<'a> { if self.type_choices.len() == 1 { if let Some(tc) = self.type_choices.first() { if tc.type1.operator.is_none() { - if let Type2::Typename { + if let Type2::Typename(Typename { ident, generic_args, - } = &tc.type1.type2 + }) = &tc.type1.type2 { return Some((ident.clone(), generic_args.clone())); } @@ -818,7 +794,7 @@ impl<'a> Type<'a> { /// type1 = type2 [S (rangeop / ctlop) S type2] /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct Type1<'a> { /// Type pub type2: Type2<'a>, @@ -839,41 +815,41 @@ impl<'a> From> for Type1<'a> { #[cfg(feature = "ast-span")] let span = Span::default(); let type2 = match value { - Value::TEXT(value) => Type2::TextValue { + Value::TEXT(value) => Type2::TextValue(TextValue { value, #[cfg(feature = "ast-span")] span, - }, - Value::INT(value) => Type2::IntValue { + }), + Value::INT(value) => Type2::IntValue(IntValue { value, #[cfg(feature = "ast-span")] span, - }, - Value::FLOAT(value) => Type2::FloatValue { + }), + Value::FLOAT(value) => Type2::FloatValue(FloatValue { value, #[cfg(feature = "ast-span")] span, - }, - Value::UINT(value) => Type2::UintValue { + }), + Value::UINT(value) => Type2::UintValue(UintValue { value, #[cfg(feature = "ast-span")] span, - }, - Value::BYTE(ByteValue::B16(value)) => Type2::B16ByteString { + }), + Value::BYTE(ByteValue::B16(value)) => Type2::B16ByteString(B16ByteString { value, #[cfg(feature = "ast-span")] span, - }, - Value::BYTE(ByteValue::B64(value)) => Type2::B64ByteString { + }), + Value::BYTE(ByteValue::B64(value)) => Type2::B64ByteString(B64ByteString { value, #[cfg(feature = "ast-span")] span, - }, - Value::BYTE(ByteValue::UTF8(value)) => Type2::UTF8ByteString { + }), + Value::BYTE(ByteValue::UTF8(value)) => Type2::UTF8ByteString(Utf8ByteString { value, #[cfg(feature = "ast-span")] span, - }, + }), }; Type1 { @@ -1017,218 +993,53 @@ impl<'a> fmt::Display for RangeCtlOp<'a> { #[derive(Debug, Clone, PartialEq)] pub enum Type2<'a> { /// Integer value - IntValue { - /// Value - value: isize, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + IntValue(IntValue), /// Unsigned integer value - UintValue { - /// Value - value: usize, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + UintValue(UintValue), /// Float value - FloatValue { - /// Value - value: f64, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + FloatValue(FloatValue), /// Text string value (enclosed by '"') - TextValue { - /// Value - value: Cow<'a, str>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + TextValue(TextValue<'a>), /// UTF-8 encoded byte string (enclosed by '') - UTF8ByteString { - /// Value - value: Cow<'a, [u8]>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + UTF8ByteString(Utf8ByteString<'a>), /// Base 16 encoded prefixed byte string - B16ByteString { - /// Value - value: Cow<'a, [u8]>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + B16ByteString(B16ByteString<'a>), /// Base 64 encoded (URL safe) prefixed byte string - B64ByteString { - /// Value - value: Cow<'a, [u8]>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + B64ByteString(B64ByteString<'a>), /// Type name identifier with optional generic arguments - Typename { - /// Identifier - ident: Identifier<'a>, - /// Generic arguments - generic_args: Option>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + Typename(Typename<'a>), /// Parenthesized type expression (for operator precedence) - ParenthesizedType { - /// Type - pt: Type<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_before_type: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_type: Option>, - }, + ParenthesizedType(ParenthesizedType<'a>), /// Map expression - Map { - /// Group - group: Group<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_before_group: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_group: Option>, - }, + Map(Map<'a>), /// Array expression - Array { - /// Span - group: Group<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_before_group: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_group: Option>, - }, + Array(Array<'a>), /// Unwrapped group - Unwrap { - /// Identifier - ident: Identifier<'a>, - /// Generic arguments - generic_args: Option>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments: Option>, - }, + Unwrap(Unwrap<'a>), /// Enumeration expression over an inline group - ChoiceFromInlineGroup { - /// Group - group: Group<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_before_group: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_group: Option>, - }, + ChoiceFromInlineGroup(ChoiceFromInlineGroup<'a>), /// Enumeration expression over previously defined group - ChoiceFromGroup { - /// Identifier - ident: Identifier<'a>, - /// Generic arguments - generic_args: Option>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments: Option>, - }, + ChoiceFromGroup(ChoiceFromGroup<'a>), /// Tagged data item where the first element is an optional tag and the second /// is the type of the tagged value - TaggedData { - /// Tag - tag: Option, - /// Type - t: Type<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_before_type: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_type: Option>, - }, + TaggedData(TaggedData<'a>), /// Data item of a major type with optional data constraint - DataMajorType { - /// Major type - mt: u8, - /// Constraint - constraint: Option, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - }, + DataMajorType(DataMajorType), /// Any data item #[cfg(feature = "ast-span")] @@ -1239,44 +1050,311 @@ pub enum Type2<'a> { Any, } +#[cfg(feature = "ast-span")] +impl<'a> Default for Type2<'a> { + fn default() -> Self { + Type2::Any(Span::default()) + } +} + +#[cfg(not(feature = "ast-span"))] +impl<'a> Default for Type2<'a> { + fn default() -> Self { + Type2::Any + } +} + +/// Int value +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct IntValue { + /// Value + pub value: isize, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Uint value +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct UintValue { + /// Value + pub value: usize, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Float value +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct FloatValue { + /// Value + pub value: f64, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Text value +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct TextValue<'a> { + /// Value + pub value: Cow<'a, str>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Utf8 byte string +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct Utf8ByteString<'a> { + /// Value + pub value: Cow<'a, [u8]>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Base16 byte string +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct B16ByteString<'a> { + /// Value + pub value: Cow<'a, [u8]>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Base64 byte string +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct B64ByteString<'a> { + /// Value + pub value: Cow<'a, [u8]>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +/// Type name +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct Typename<'a> { + /// Identifier + pub ident: Identifier<'a>, + /// Generic arguments + pub generic_args: Option>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + +#[doc(hidden)] +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Clone, PartialEq)] +pub enum ParenthesizedTypeOrGroup<'a> { + Group(Group<'a>), + Type(ParenthesizedType<'a>), +} + +/// Parenthesized type +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct ParenthesizedType<'a> { + /// Type + pub pt: Type<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_type: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_type: Option>, +} + +/// Map +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct Map<'a> { + /// Group + pub group: Group<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_group: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_group: Option>, +} + +/// Array +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct Array<'a> { + /// Group + pub group: Group<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_group: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_group: Option>, +} + +/// Unwrap +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct Unwrap<'a> { + /// Identifier + pub ident: Identifier<'a>, + /// Generic arguments + pub generic_args: Option>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments: Option>, +} + +/// Choice from inline group +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct ChoiceFromInlineGroup<'a> { + /// Group + pub group: Group<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_group: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_group: Option>, +} + +/// Choice from group +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct ChoiceFromGroup<'a> { + /// Identifier + pub ident: Identifier<'a>, + /// Generic arguments + pub generic_args: Option>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments: Option>, +} + +/// Tagged data +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct TaggedData<'a> { + /// Tag + pub tag: Option, + /// Type + pub t: Type<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_type: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_type: Option>, +} + +/// Major data type +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Default, Clone, PartialEq)] +pub struct DataMajorType { + /// Major type + pub mt: u8, + /// Constraint + pub constraint: Option, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, +} + #[allow(clippy::cognitive_complexity)] impl<'a> fmt::Display for Type2<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Type2::IntValue { value, .. } => write!(f, "{}", value), - Type2::UintValue { value, .. } => write!(f, "{}", value), - Type2::FloatValue { value, .. } => write!(f, "{}", value), - Type2::TextValue { value, .. } => write!(f, "\"{}\"", value), - Type2::UTF8ByteString { value, .. } => write!( + Type2::IntValue(IntValue { value, .. }) => write!(f, "{}", value), + Type2::UintValue(UintValue { value, .. }) => write!(f, "{}", value), + Type2::FloatValue(FloatValue { value, .. }) => write!(f, "{}", value), + Type2::TextValue(TextValue { value, .. }) => write!(f, "\"{}\"", value), + Type2::UTF8ByteString(Utf8ByteString { value, .. }) => write!( f, "'{}'", std::str::from_utf8(value).map_err(|_| fmt::Error)? ), - Type2::B16ByteString { value, .. } => { + Type2::B16ByteString(B16ByteString { value, .. }) => { write!(f, "{}", std::str::from_utf8(value).map_err(|_| fmt::Error)?) } - Type2::B64ByteString { value, .. } => { + Type2::B64ByteString(B64ByteString { value, .. }) => { write!(f, "{}", std::str::from_utf8(value).map_err(|_| fmt::Error)?) } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(args) = generic_args { return write!(f, "{}{}", ident, args); } write!(f, "{}", ident) } - Type2::ParenthesizedType { + Type2::ParenthesizedType(ParenthesizedType { #[cfg(feature = "ast-comments")] comments_before_type, pt, #[cfg(feature = "ast-comments")] comments_after_type, .. - } => { + }) => { let mut pt_str = String::from("("); #[cfg(feature = "ast-comments")] @@ -1305,14 +1383,14 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", pt_str) } - Type2::Map { + Type2::Map(Map { #[cfg(feature = "ast-comments")] comments_before_group, group, #[cfg(feature = "ast-comments")] comments_after_group, .. - } => { + }) => { let mut t2_str = String::from("{"); #[cfg(feature = "ast-comments")] @@ -1360,14 +1438,14 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", t2_str) } - Type2::Array { + Type2::Array(Array { #[cfg(feature = "ast-comments")] comments_before_group, group, #[cfg(feature = "ast-comments")] comments_after_group, .. - } => { + }) => { let mut t2_str = String::from("["); #[cfg(feature = "ast-comments")] @@ -1424,13 +1502,13 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", t2_str) } - Type2::Unwrap { + Type2::Unwrap(Unwrap { #[cfg(feature = "ast-comments")] comments, ident, generic_args, .. - } => { + }) => { let mut t2_str = String::new(); #[cfg(feature = "ast-comments")] @@ -1446,7 +1524,7 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", t2_str) } - Type2::ChoiceFromInlineGroup { + Type2::ChoiceFromInlineGroup(ChoiceFromInlineGroup { #[cfg(feature = "ast-comments")] comments, #[cfg(feature = "ast-comments")] @@ -1455,7 +1533,7 @@ impl<'a> fmt::Display for Type2<'a> { #[cfg(feature = "ast-comments")] comments_after_group, .. - } => { + }) => { let mut t2_str = String::from("&"); #[cfg(feature = "ast-comments")] @@ -1485,13 +1563,13 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", t2_str) } - Type2::ChoiceFromGroup { + Type2::ChoiceFromGroup(ChoiceFromGroup { #[cfg(feature = "ast-comments")] comments, ident, generic_args, .. - } => { + }) => { let mut t2_str = String::from("&"); #[cfg(feature = "ast-comments")] @@ -1507,7 +1585,7 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", t2_str) } - Type2::TaggedData { + Type2::TaggedData(TaggedData { tag, #[cfg(feature = "ast-comments")] comments_before_type, @@ -1515,7 +1593,7 @@ impl<'a> fmt::Display for Type2<'a> { #[cfg(feature = "ast-comments")] comments_after_type, .. - } => { + }) => { let mut t2_str = String::from("#6"); if let Some(tag_uint) = tag { @@ -1544,7 +1622,7 @@ impl<'a> fmt::Display for Type2<'a> { write!(f, "{}", t2_str) } - Type2::DataMajorType { mt, constraint, .. } => { + Type2::DataMajorType(DataMajorType { mt, constraint, .. }) => { if let Some(c) = constraint { return write!(f, "{}.{}", mt, c); } @@ -1565,7 +1643,7 @@ impl<'a> From> for Type2<'a> { let span = Span::default(); match rv { - RangeValue::IDENT(ident) => Type2::Typename { + RangeValue::IDENT(ident) => Type2::Typename(Typename { ident: Identifier { ident: ident.0, socket: ident.1, @@ -1575,268 +1653,271 @@ impl<'a> From> for Type2<'a> { generic_args: None, #[cfg(feature = "ast-span")] span, - }, - RangeValue::INT(value) => Type2::IntValue { + }), + RangeValue::INT(value) => Type2::IntValue(IntValue { value, #[cfg(feature = "ast-span")] span, - }, - RangeValue::UINT(value) => Type2::UintValue { + }), + RangeValue::UINT(value) => Type2::UintValue(UintValue { value, #[cfg(feature = "ast-span")] span, - }, - RangeValue::FLOAT(value) => Type2::FloatValue { + }), + RangeValue::FLOAT(value) => Type2::FloatValue(FloatValue { value, #[cfg(feature = "ast-span")] span, - }, + }), } } } impl<'a> From> for Type2<'a> { fn from(type1: Type1<'a>) -> Self { - Type2::ParenthesizedType { + Type2::ParenthesizedType(ParenthesizedType { pt: Type { type_choices: vec![TypeChoice { type1, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-comments")] - comments_before_type: None, + ..Default::default() }], #[cfg(feature = "ast-span")] span: Span::default(), }, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - } + ..Default::default() + }) } } impl<'a> From for Type2<'a> { fn from(value: usize) -> Self { - Type2::UintValue { + Type2::UintValue(UintValue { value, - #[cfg(feature = "ast-span")] - span: Span::default(), - } + ..Default::default() + }) } } impl<'a> From for Type2<'a> { fn from(value: isize) -> Self { - Type2::IntValue { + Type2::IntValue(IntValue { value, - #[cfg(feature = "ast-span")] - span: Span::default(), - } + ..Default::default() + }) } } impl<'a> From for Type2<'a> { fn from(value: f64) -> Self { - Type2::FloatValue { + Type2::FloatValue(FloatValue { value, - #[cfg(feature = "ast-span")] - span: Span::default(), - } + ..Default::default() + }) } } impl<'a> From for Type2<'a> { fn from(value: String) -> Self { - Type2::TextValue { + Type2::TextValue(TextValue { value: value.into(), - #[cfg(feature = "ast-span")] - span: Span::default(), - } + ..Default::default() + }) } } // Convenience method for testing impl<'a> From<&'a str> for Type2<'a> { fn from(value: &'a str) -> Self { - Type2::UTF8ByteString { + Type2::UTF8ByteString(Utf8ByteString { value: value.as_bytes().into(), - #[cfg(feature = "ast-span")] - span: Span::default(), - } + ..Default::default() + }) } } impl<'a> From> for Type2<'a> { fn from(value: ByteValue<'a>) -> Self { match value { - ByteValue::UTF8(value) => Type2::UTF8ByteString { + ByteValue::UTF8(value) => Type2::UTF8ByteString(Utf8ByteString { value, - #[cfg(feature = "ast-span")] - span: Span::default(), - }, - ByteValue::B16(value) => Type2::B16ByteString { + ..Default::default() + }), + ByteValue::B16(value) => Type2::B16ByteString(B16ByteString { value, - #[cfg(feature = "ast-span")] - span: Span::default(), - }, - ByteValue::B64(value) => Type2::B64ByteString { + ..Default::default() + }), + ByteValue::B64(value) => Type2::B64ByteString(B64ByteString { value, - #[cfg(feature = "ast-span")] - span: Span::default(), - }, + ..Default::default() + }), } } } +fn decfrac_type<'a>() -> Type<'a> { + Type { + type_choices: vec![TypeChoice { + type1: Type1 { + type2: Type2::Array(Array { + group: Group { + group_choices: vec![GroupChoice { + group_entries: vec![ + ( + GroupEntry::ValueMemberKey { + ge: Box::from(ValueMemberKeyEntry { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { + ident: "e10".into(), + ..Default::default() + })), + entry_type: Type { + type_choices: vec![TypeChoice { + type1: Type1 { + type2: Type2::Typename(Typename { + ident: Token::INT.into(), + ..Default::default() + }), + ..Default::default() + }, + ..Default::default() + }], + ..Default::default() + }, + occur: None, + }), + #[cfg(feature = "ast-comments")] + leading_comments: None, + #[cfg(feature = "ast-span")] + span: Span::default(), + #[cfg(feature = "ast-comments")] + trailing_comments: None, + }, + OptionalComma::default(), + ), + ( + GroupEntry::ValueMemberKey { + ge: Box::from(ValueMemberKeyEntry { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { + ident: "m".into(), + ..Default::default() + })), + entry_type: Type { + type_choices: vec![TypeChoice { + type1: Type1 { + type2: Type2::Typename(Typename { + ident: Token::INTEGER.into(), + ..Default::default() + }), + ..Default::default() + }, + ..Default::default() + }], + ..Default::default() + }, + ..Default::default() + }), + #[cfg(feature = "ast-comments")] + leading_comments: None, + #[cfg(feature = "ast-span")] + span: Span::default(), + #[cfg(feature = "ast-comments")] + trailing_comments: None, + }, + OptionalComma::default(), + ), + ], + ..Default::default() + }], + ..Default::default() + }, + ..Default::default() + }), + ..Default::default() + }, + ..Default::default() + }], + ..Default::default() + } +} + /// Retrieve `Type2` from token if it is a tag type in the standard prelude pub fn tag_from_token<'a>(token: &Token) -> Option> { match token { - Token::TDATE => Some(Type2::TaggedData { + Token::TDATE => Some(Type2::TaggedData(TaggedData { tag: Some(0), t: type_from_token(Token::TSTR), - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::TIME => Some(Type2::TaggedData { + ..Default::default() + })), + Token::TIME => Some(Type2::TaggedData(TaggedData { tag: Some(1), t: type_from_token(Token::NUMBER), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::BIGUINT => Some(Type2::TaggedData { + ..Default::default() + })), + Token::BIGUINT => Some(Type2::TaggedData(TaggedData { tag: Some(2), t: type_from_token(Token::BSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::BIGNINT => Some(Type2::TaggedData { + ..Default::default() + })), + Token::BIGNINT => Some(Type2::TaggedData(TaggedData { tag: Some(3), t: type_from_token(Token::BSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::DECFRAC => unimplemented!(), + ..Default::default() + })), + Token::DECFRAC => Some(Type2::TaggedData(TaggedData { + tag: Some(4), + t: decfrac_type(), + ..Default::default() + })), Token::BIGFLOAT => unimplemented!(), - Token::EB64URL => Some(Type2::TaggedData { + Token::EB64URL => Some(Type2::TaggedData(TaggedData { tag: Some(21), t: type_from_token(Token::ANY), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::EB64LEGACY => Some(Type2::TaggedData { + ..Default::default() + })), + Token::EB64LEGACY => Some(Type2::TaggedData(TaggedData { tag: Some(22), t: type_from_token(Token::ANY), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::EB16 => Some(Type2::TaggedData { + ..Default::default() + })), + Token::EB16 => Some(Type2::TaggedData(TaggedData { tag: Some(23), t: type_from_token(Token::ANY), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::ENCODEDCBOR => Some(Type2::TaggedData { + ..Default::default() + })), + Token::ENCODEDCBOR => Some(Type2::TaggedData(TaggedData { tag: Some(24), t: type_from_token(Token::BSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::URI => Some(Type2::TaggedData { + ..Default::default() + })), + Token::URI => Some(Type2::TaggedData(TaggedData { tag: Some(32), t: type_from_token(Token::TSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::B64URL => Some(Type2::TaggedData { + ..Default::default() + })), + Token::B64URL => Some(Type2::TaggedData(TaggedData { tag: Some(33), t: type_from_token(Token::TSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::B64LEGACY => Some(Type2::TaggedData { + ..Default::default() + })), + Token::B64LEGACY => Some(Type2::TaggedData(TaggedData { tag: Some(34), t: type_from_token(Token::TSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::REGEXP => Some(Type2::TaggedData { + ..Default::default() + })), + Token::REGEXP => Some(Type2::TaggedData(TaggedData { tag: Some(35), t: type_from_token(Token::TSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::MIMEMESSAGE => Some(Type2::TaggedData { + ..Default::default() + })), + Token::MIMEMESSAGE => Some(Type2::TaggedData(TaggedData { tag: Some(36), t: type_from_token(Token::TSTR), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), - Token::CBORANY => Some(Type2::TaggedData { + ..Default::default() + })), + Token::CBORANY => Some(Type2::TaggedData(TaggedData { tag: Some(55799), t: type_from_token(Token::ANY), - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), + ..Default::default() + })), _ => None, } } @@ -1846,25 +1927,15 @@ pub fn type_from_token(token: Token) -> Type { Type { type_choices: vec![TypeChoice { type1: Type1 { - #[cfg(feature = "ast-comments")] - comments_after_type: None, - operator: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier::from(token), - generic_args: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }, + ..Default::default() + }), + ..Default::default() }, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - #[cfg(feature = "ast-comments")] - comments_before_type: None, + ..Default::default() }], - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() } } @@ -1874,7 +1945,7 @@ pub fn type_from_token(token: Token) -> Type { /// group = grpchoice * (S "//" S grpchoice) /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct Group<'a> { /// Group choices #[cfg_attr(target_arch = "wasm32", serde(borrow))] @@ -1968,7 +2039,7 @@ impl<'a> fmt::Display for Group<'a> { /// /// If tuple is true, then entry is marked by a trailing comma #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct GroupChoice<'a> { /// Group entries where the second item in the tuple indicates where or not a /// trailing comma is present @@ -2518,7 +2589,7 @@ impl<'a> fmt::Display for Occurrence<'a> { /// [occur S] [memberkey S] type /// ``` #[cfg_attr(target_arch = "wasm32", derive(Serialize))] -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Default)] pub struct ValueMemberKeyEntry<'a> { /// Optional occurrence indicator pub occur: Option>, @@ -2588,92 +2659,110 @@ impl<'a> fmt::Display for TypeGroupnameEntry<'a> { #[derive(Debug, Clone, PartialEq)] pub enum MemberKey<'a> { /// Type expression - Type1 { - /// Type1 - #[cfg_attr(target_arch = "wasm32", serde(borrow))] - t1: Box>, - /// Is cut indicator present - is_cut: bool, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_before_cut: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_cut: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_arrowmap: Option>, - }, + Type1(Type1MemberKey<'a>), /// Bareword string type - Bareword { - /// Identifier - #[cfg_attr(target_arch = "wasm32", serde(borrow))] - ident: Identifier<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_colon: Option>, - }, + Bareword(BarewordMemberKey<'a>), /// Value type - Value { - /// Value - #[cfg_attr(target_arch = "wasm32", serde(borrow))] - value: Value<'a>, - /// Span - #[cfg(feature = "ast-span")] - span: Span, - - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments: Option>, - #[cfg(feature = "ast-comments")] - #[cfg_attr(target_arch = "wasm32", serde(skip))] - #[doc(hidden)] - comments_after_colon: Option>, - }, + Value(ValueMemberKey<'a>), // Used while parsing a parenthesized type that is not followed by a cut nor // an arrow map #[cfg_attr(target_arch = "wasm32", serde(skip))] #[doc(hidden)] - ParenthesizedType { - non_member_key: ParenthesizedType<'a>, - #[cfg(feature = "ast-comments")] - comments_before_type_or_group: Option>, - #[cfg(feature = "ast-comments")] - comments_after_type_or_group: Option>, - }, + Parenthesized(ParenthesizedMemberKey<'a>), +} + +/// Type1 member key +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct Type1MemberKey<'a> { + /// Type1 + #[cfg_attr(target_arch = "wasm32", serde(borrow))] + pub t1: Box>, + /// Is cut indicator present + pub is_cut: bool, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_cut: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_cut: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_arrowmap: Option>, +} + +/// Bareword member key +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Clone, PartialEq, Default)] +pub struct BarewordMemberKey<'a> { + /// Identifier + #[cfg_attr(target_arch = "wasm32", serde(borrow))] + pub ident: Identifier<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_colon: Option>, +} + +/// Value member key +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] +#[derive(Debug, Clone, PartialEq)] +pub struct ValueMemberKey<'a> { + /// Value + #[cfg_attr(target_arch = "wasm32", serde(borrow))] + pub value: Value<'a>, + /// Span + #[cfg(feature = "ast-span")] + pub span: Span, + + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_colon: Option>, } +/// Parenthesized member key +#[cfg_attr(target_arch = "wasm32", derive(Serialize))] #[derive(Debug, Clone, PartialEq)] #[doc(hidden)] -pub enum ParenthesizedType<'a> { - Group(Group<'a>), - Type(Type<'a>), +pub struct ParenthesizedMemberKey<'a> { + pub non_member_key: ParenthesizedTypeOrGroup<'a>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_before_type_or_group: Option>, + #[cfg(feature = "ast-comments")] + #[cfg_attr(target_arch = "wasm32", serde(skip))] + #[doc(hidden)] + pub comments_after_type_or_group: Option>, } impl<'a> fmt::Display for MemberKey<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - MemberKey::Type1 { + MemberKey::Type1(Type1MemberKey { t1, #[cfg(feature = "ast-comments")] comments_before_cut, @@ -2683,7 +2772,7 @@ impl<'a> fmt::Display for MemberKey<'a> { #[cfg(feature = "ast-comments")] comments_after_arrowmap, .. - } => { + }) => { let mut mk_str = format!("{} ", t1); #[cfg(feature = "ast-comments")] @@ -2715,14 +2804,14 @@ impl<'a> fmt::Display for MemberKey<'a> { write!(f, "{}", mk_str) } - MemberKey::Bareword { + MemberKey::Bareword(BarewordMemberKey { ident, #[cfg(feature = "ast-comments")] comments, #[cfg(feature = "ast-comments")] comments_after_colon, .. - } => { + }) => { let mut mk_str = format!("{}", ident); #[cfg(feature = "ast-comments")] @@ -2743,14 +2832,14 @@ impl<'a> fmt::Display for MemberKey<'a> { write!(f, "{}", mk_str) } - MemberKey::Value { + MemberKey::Value(ValueMemberKey { value, #[cfg(feature = "ast-comments")] comments, #[cfg(feature = "ast-comments")] comments_after_colon, .. - } => { + }) => { let mut mk_str = format!("{}", value); #[cfg(feature = "ast-comments")] @@ -2771,13 +2860,13 @@ impl<'a> fmt::Display for MemberKey<'a> { write!(f, "{}", mk_str) } - MemberKey::ParenthesizedType { - non_member_key: ParenthesizedType::Group(g), + MemberKey::Parenthesized(ParenthesizedMemberKey { + non_member_key: ParenthesizedTypeOrGroup::Group(g), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] comments_after_type_or_group, - } => { + }) => { let mut nmk_str = String::new(); #[cfg(feature = "ast-comments")] @@ -2794,13 +2883,13 @@ impl<'a> fmt::Display for MemberKey<'a> { write!(f, "{}", nmk_str) } - MemberKey::ParenthesizedType { - non_member_key: ParenthesizedType::Type(t), + MemberKey::Parenthesized(ParenthesizedMemberKey { + non_member_key: ParenthesizedTypeOrGroup::Type(ParenthesizedType { pt, .. }), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] comments_after_type_or_group, - } => { + }) => { let mut nmk_str = String::new(); #[cfg(feature = "ast-comments")] @@ -2808,7 +2897,7 @@ impl<'a> fmt::Display for MemberKey<'a> { nmk_str.push_str(&comments.to_string()); } - nmk_str.push_str(&t.to_string()); + nmk_str.push_str(&pt.to_string()); #[cfg(feature = "ast-comments")] if let Some(comments) = comments_after_type_or_group { @@ -2937,31 +3026,22 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: "key1".into(), - comments: None, - comments_after_colon: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "value1".into(), - #[cfg(feature = "ast-span")] - span: Span::default(), - }, - operator: None, - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() + }), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() }, }), leading_comments: None, @@ -2971,39 +3051,29 @@ mod tests { }, OptionalComma { optional_comma: true, - trailing_comments: None, - _a: PhantomData::default(), + ..Default::default() } ), ( GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: "key2".into(), - comments: None, - comments_after_colon: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "value2".into(), - #[cfg(feature = "ast-span")] - span: Span::default(), - }, - operator: None, - comments_after_type: None, - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() + }), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() }, }), leading_comments: None, @@ -3013,17 +3083,13 @@ mod tests { }, OptionalComma { optional_comma: true, - trailing_comments: None, - _a: PhantomData::default(), + ..Default::default() } ), ], - comments_before_grpchoice: None, - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() }], - #[cfg(feature = "ast-span")] - span: Span::default(), + ..Default::default() } .to_string(), " key1: \"value1\", key2: \"value2\", ".to_string() diff --git a/src/faker.rs b/src/faker.rs index 3068a6cd..95b706d8 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -1,5 +1,5 @@ use crate::{ - ast::*, + ast::{self, *}, token::{lookup_ident, Token}, util::*, visitor::{self, *}, @@ -203,15 +203,15 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { ctrl: &Token<'a>, controller: &Type2<'a>, ) -> visitor::Result { - if let Type2::Typename { + if let Type2::Typename(Typename { ident: target_ident, .. - } = target + }) = target { - if let Type2::Typename { + if let Type2::Typename(Typename { ident: controller_ident, .. - } = controller + }) = controller { if let Some(name) = self.eval_generic_rule { if let Some(gr) = self @@ -258,7 +258,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { match ctrl { Token::SIZE => match target { - Type2::Typename { ident, .. } + Type2::Typename(Typename { ident, .. }) if is_ident_string_data_type(self.cddl, ident) || is_ident_uint_data_type(self.cddl, ident) => { @@ -281,26 +281,26 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { is_inclusive: bool, ) -> visitor::Result { match lower { - Type2::IntValue { value: lower_v, .. } => match upper { - Type2::IntValue { value: upper, .. } => { + Type2::IntValue(IntValue { value: lower_v, .. }) => match upper { + Type2::IntValue(IntValue { value: upper, .. }) => { if is_inclusive { self.faked_json = Some((*lower_v..=*upper).fake::().into()); } else { self.faked_json = Some((*lower_v..*upper).fake::().into()); } } - Type2::UintValue { value: upper, .. } => { + Type2::UintValue(UintValue { value: upper, .. }) => { if is_inclusive { self.faked_json = Some((*lower_v..=*upper as isize).fake::().into()); } else { self.faked_json = Some((*lower_v..*upper as isize).fake::().into()); } } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { return self.process_generic_args(ident, ga); } @@ -311,26 +311,26 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } _ => return Ok(()), }, - Type2::UintValue { value: lower_v, .. } => match upper { - Type2::IntValue { value: upper, .. } => { + Type2::UintValue(UintValue { value: lower_v, .. }) => match upper { + Type2::IntValue(IntValue { value: upper, .. }) => { if is_inclusive { self.faked_json = Some((*lower_v..=*upper as usize).fake::().into()); } else { self.faked_json = Some((*lower_v..*upper as usize).fake::().into()); } } - Type2::UintValue { value: upper, .. } => { + Type2::UintValue(UintValue { value: upper, .. }) => { if is_inclusive { self.faked_json = Some((*lower_v..=*upper).fake::().into()); } else { self.faked_json = Some((*lower_v..*upper).fake::().into()); } } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { return self.process_generic_args(ident, ga); } @@ -341,19 +341,19 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } _ => return Ok(()), }, - Type2::FloatValue { value: lower_v, .. } => match upper { - Type2::FloatValue { value: upper, .. } => { + Type2::FloatValue(FloatValue { value: lower_v, .. }) => match upper { + Type2::FloatValue(FloatValue { value: upper, .. }) => { if is_inclusive { self.faked_json = Some((*lower_v..=*upper).fake::().into()); } else { self.faked_json = Some((*lower_v..*upper).fake::().into()); } } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { return self.process_generic_args(ident, ga); } @@ -364,11 +364,11 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } _ => return Ok(()), }, - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { return self.process_generic_args(ident, ga); } @@ -392,10 +392,10 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { if let Some(mk) = &entry.member_key { match mk { - MemberKey::Bareword { ident, .. } => { + MemberKey::Bareword(BarewordMemberKey { ident, .. }) => { entries.insert(ident.ident.to_string(), (occur, entry.entry_type.clone())); } - MemberKey::Value { value, .. } => { + MemberKey::Value(ValueMemberKey { value, .. }) => { entries.insert(value.to_string(), (occur, entry.entry_type.clone())); } _ => return Ok(()), @@ -413,14 +413,14 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { fn visit_type2(&mut self, t2: &Type2<'a>) -> visitor::Result { match t2 { - Type2::TextValue { value, .. } => { + Type2::TextValue(TextValue { value, .. }) => { if let Some(Value::Array(array)) = self.faked_json.as_mut() { array.push(value.as_ref().into()); } else { self.faked_json = Some(value.as_ref().into()); } } - Type2::UTF8ByteString { value, .. } => { + Type2::UTF8ByteString(Utf8ByteString { value, .. }) => { let value = std::str::from_utf8(value.as_ref()).map_err(Error::Utf8Error)?; if let Some(Value::Array(array)) = self.faked_json.as_mut() { @@ -429,7 +429,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { self.faked_json = Some(value.into()); } } - Type2::UintValue { value, .. } => match &self.ctrl { + Type2::UintValue(UintValue { value, .. }) => match &self.ctrl { Some((target, Token::SIZE)) => { if is_ident_string_data_type(self.cddl, target) { self.faked_json = Some(value.fake::().into()) @@ -439,9 +439,9 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { } _ => self.faked_json = Some((*value).into()), }, - Type2::IntValue { value, .. } => self.faked_json = Some((*value).into()), - Type2::FloatValue { value, .. } => self.faked_json = Some((*value).into()), - Type2::Array { group, .. } => { + Type2::IntValue(IntValue { value, .. }) => self.faked_json = Some((*value).into()), + Type2::FloatValue(FloatValue { value, .. }) => self.faked_json = Some((*value).into()), + Type2::Array(Array { group, .. }) => { self.faked_json = Some(Value::Array(Vec::new())); self.entries = Entries::Array(Vec::new()); self.visit_group(group)?; @@ -620,7 +620,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { self.entries = Entries::None; } - Type2::Map { group, .. } => { + Type2::Map(ast::Map { group, .. }) => { self.faked_json = Some(Value::Object(Map::default())); self.entries = Entries::Map(HashMap::new()); self.visit_group(group)?; @@ -658,22 +658,22 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { self.entries = Entries::None; } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { return self.process_generic_args(ident, ga); } return self.visit_identifier(ident); } - Type2::ChoiceFromGroup { + Type2::ChoiceFromGroup(ChoiceFromGroup { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { self.is_group_to_choice_enum = true; @@ -712,20 +712,22 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { self.faked_json = Some(Name(EN).fake::().into()); } else if let Token::NUMBER = lookup_ident(ident.ident) { if FFaker.fake::() { - self.faked_json = Some(FFaker.fake::().into()) + self.faked_json = Some(FFaker.fake::().into()); } else { - self.faked_json = Some(FFaker.fake::().into()) + self.faked_json = Some(FFaker.fake::().into()); } } else if is_ident_float_data_type(self.cddl, ident) { - self.faked_json = Some(FFaker.fake::().into()) + self.faked_json = Some(FFaker.fake::().into()); } else if is_ident_uint_data_type(self.cddl, ident) { - self.faked_json = Some(FFaker.fake::().into()) + self.faked_json = Some(FFaker.fake::().into()); } else if is_ident_nint_data_type(self.cddl, ident) { - self.faked_json = Some((..0).fake::().into()) + self.faked_json = Some((..0).fake::().into()); } else if is_ident_integer_data_type(self.cddl, ident) { - self.faked_json = Some(FFaker.fake::().into()) + self.faked_json = Some(FFaker.fake::().into()); } else if is_ident_bool_data_type(self.cddl, ident) { - self.faked_json = Some(FFaker.fake::().into()) + self.faked_json = Some(FFaker.fake::().into()); + } else if is_ident_null_data_type(self.cddl, ident) { + self.faked_json = Some(Value::Null); } else if let Some(rule) = rule_from_ident(self.cddl, ident) { self.visit_rule(rule)?; } else { diff --git a/src/parser.rs b/src/parser.rs index 327210ad..0189bf8b 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -679,19 +679,20 @@ where // TODO: Replace with box pattern destructuring once supported in stable if let GroupEntry::ValueMemberKey { ge, .. } = &group_entry.0 { if ge.occur.is_none() && ge.member_key.is_none() { - let value = self.parse_type(Some(Type2::ParenthesizedType { - #[cfg(feature = "ast-comments")] - comments_before_type: comments_before_group.clone(), - pt: ge.entry_type.clone(), - #[cfg(feature = "ast-comments")] - comments_after_type: comments_after_group.clone(), - #[cfg(feature = "ast-span")] - span: Span( - begin_pt_range, - self.parser_position.range.1, - begin_rule_line, - ), - }))?; + let value = + self.parse_type(Some(Type2::ParenthesizedType(ParenthesizedType { + #[cfg(feature = "ast-comments")] + comments_before_type: comments_before_group.clone(), + pt: ge.entry_type.clone(), + #[cfg(feature = "ast-comments")] + comments_after_type: comments_after_group.clone(), + #[cfg(feature = "ast-span")] + span: Span( + begin_pt_range, + self.parser_position.range.1, + begin_rule_line, + ), + })))?; #[cfg(feature = "ast-span")] { @@ -992,13 +993,14 @@ where } #[cfg(feature = "ast-span")] - let begin_type_range = if let Some(Type2::ParenthesizedType { span, .. }) = parenthesized_type { - self.parser_position.line = span.2; + let begin_type_range = + if let Some(Type2::ParenthesizedType(ParenthesizedType { span, .. })) = parenthesized_type { + self.parser_position.line = span.2; - span.0 - } else { - self.parser_position.range.0 - }; + span.0 + } else { + self.parser_position.range.0 + }; let mut t = Type { type_choices: Vec::new(), @@ -1072,7 +1074,7 @@ where #[cfg(feature = "ast-span")] let mut begin_type1_range = self.lexer_position.range.0; - let t2_1 = if let Some(Type2::ParenthesizedType { + let t2_1 = if let Some(Type2::ParenthesizedType(ParenthesizedType { #[cfg(feature = "ast-comments")] comments_before_type, pt, @@ -1080,7 +1082,7 @@ where comments_after_type, #[cfg(feature = "ast-span")] span, - }) = parenthesized_type + })) = parenthesized_type { #[cfg(feature = "ast-span")] { @@ -1088,7 +1090,7 @@ where begin_type1_range = span.0; } - Type2::ParenthesizedType { + Type2::ParenthesizedType(ParenthesizedType { #[cfg(feature = "ast-comments")] comments_before_type, pt, @@ -1096,7 +1098,7 @@ where comments_after_type, #[cfg(feature = "ast-span")] span, - } + }) } else { self.parse_type2()? }; @@ -1211,64 +1213,68 @@ where ); match value { - token::Value::TEXT(t) => Ok(Type2::TextValue { + token::Value::TEXT(t) => Ok(Type2::TextValue(TextValue { value: t.clone(), #[cfg(feature = "ast-span")] span, - }), - token::Value::INT(i) => Ok(Type2::IntValue { + })), + token::Value::INT(i) => Ok(Type2::IntValue(IntValue { value: *i, #[cfg(feature = "ast-span")] span, - }), - token::Value::UINT(ui) => Ok(Type2::UintValue { + })), + token::Value::UINT(ui) => Ok(Type2::UintValue(UintValue { value: *ui, #[cfg(feature = "ast-span")] span, - }), - token::Value::FLOAT(f) => Ok(Type2::FloatValue { + })), + token::Value::FLOAT(f) => Ok(Type2::FloatValue(FloatValue { value: *f, #[cfg(feature = "ast-span")] span, - }), + })), token::Value::BYTE(token::ByteValue::UTF8(Cow::Borrowed(utf8))) => { - Ok(Type2::UTF8ByteString { + Ok(Type2::UTF8ByteString(Utf8ByteString { value: Cow::Borrowed(utf8), #[cfg(feature = "ast-span")] span, - }) + })) } token::Value::BYTE(token::ByteValue::UTF8(Cow::Owned(utf8))) => { - Ok(Type2::UTF8ByteString { + Ok(Type2::UTF8ByteString(Utf8ByteString { value: Cow::Owned(utf8.to_owned()), #[cfg(feature = "ast-span")] span, - }) + })) } token::Value::BYTE(token::ByteValue::B16(Cow::Borrowed(b16))) => { - Ok(Type2::B16ByteString { + Ok(Type2::B16ByteString(B16ByteString { value: Cow::Borrowed(b16), #[cfg(feature = "ast-span")] span, - }) + })) + } + token::Value::BYTE(token::ByteValue::B16(Cow::Owned(b16))) => { + Ok(Type2::B16ByteString(B16ByteString { + value: Cow::Owned(b16.to_owned()), + #[cfg(feature = "ast-span")] + span, + })) } - token::Value::BYTE(token::ByteValue::B16(Cow::Owned(b16))) => Ok(Type2::B16ByteString { - value: Cow::Owned(b16.to_owned()), - #[cfg(feature = "ast-span")] - span, - }), token::Value::BYTE(token::ByteValue::B64(Cow::Borrowed(b64))) => { - Ok(Type2::B64ByteString { + Ok(Type2::B64ByteString(B64ByteString { value: Cow::Borrowed(b64), #[cfg(feature = "ast-span")] span, - }) + })) + } + token::Value::BYTE(token::ByteValue::B64(Cow::Owned(b64))) => { + Ok(Type2::B64ByteString(B64ByteString { + value: Cow::Owned(b64.to_owned()), + #[cfg(feature = "ast-span")] + span, + })) } - token::Value::BYTE(token::ByteValue::B64(Cow::Owned(b64))) => Ok(Type2::B64ByteString { - value: Cow::Owned(b64.to_owned()), - #[cfg(feature = "ast-span")] - span, - }), } } @@ -1287,12 +1293,12 @@ where #[cfg(feature = "ast-span")] let end_type2_range = self.parser_position.range.1; - return Ok(Type2::Typename { + return Ok(Type2::Typename(Typename { ident, generic_args: Some(ga), #[cfg(feature = "ast-span")] span: Span(begin_type2_range, end_type2_range, begin_type2_line), - }); + })); } #[cfg(feature = "ast-span")] @@ -1301,7 +1307,7 @@ where self.parser_position.line = self.lexer_position.line; } - Ok(Type2::Typename { + Ok(Type2::Typename(Typename { ident: self.identifier_from_ident_token(*ident), generic_args: None, #[cfg(feature = "ast-span")] @@ -1310,7 +1316,7 @@ where self.parser_position.range.1, self.parser_position.line, ), - }) + })) } // ( type ) @@ -1341,7 +1347,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Ok(Type2::ParenthesizedType { + Ok(Type2::ParenthesizedType(ParenthesizedType { #[cfg(feature = "ast-comments")] comments_before_type, #[cfg(feature = "ast-comments")] @@ -1353,7 +1359,7 @@ where self.parser_position.range.1, self.parser_position.line, ), - }) + })) } // { group } @@ -1391,7 +1397,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Ok(Type2::Map { + Ok(Type2::Map(Map { #[cfg(feature = "ast-comments")] comments_before_group, group, @@ -1399,7 +1405,7 @@ where span, #[cfg(feature = "ast-comments")] comments_after_group, - }) + })) } // [ group ] @@ -1441,7 +1447,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Ok(Type2::Array { + Ok(Type2::Array(Array { #[cfg(feature = "ast-comments")] comments_before_group, group, @@ -1449,7 +1455,7 @@ where comments_after_group, #[cfg(feature = "ast-span")] span, - }) + })) } // ~ typename [genericarg] @@ -1473,24 +1479,24 @@ where if self.peek_token_is(&Token::LANGLEBRACKET) { self.next_token()?; - return Ok(Type2::Unwrap { + return Ok(Type2::Unwrap(Unwrap { #[cfg(feature = "ast-comments")] comments, ident, generic_args: Some(self.parse_genericargs()?), #[cfg(feature = "ast-span")] span: Span(0, 0, 0), - }); + })); } - return Ok(Type2::Unwrap { + return Ok(Type2::Unwrap(Unwrap { #[cfg(feature = "ast-comments")] comments, ident, generic_args: None, #[cfg(feature = "ast-span")] span: Span(0, 0, 0), - }); + })); } self.errors.push(Error::PARSER { @@ -1533,7 +1539,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Ok(Type2::ChoiceFromInlineGroup { + Ok(Type2::ChoiceFromInlineGroup(ChoiceFromInlineGroup { #[cfg(feature = "ast-comments")] comments, #[cfg(feature = "ast-comments")] @@ -1547,7 +1553,7 @@ where self.parser_position.range.1, begin_type2_line, ), - }) + })) } Token::IDENT(ident) => { let ident = self.identifier_from_ident_token(*ident); @@ -1556,7 +1562,7 @@ where let generic_args = Some(self.parse_genericargs()?); - return Ok(Type2::ChoiceFromGroup { + return Ok(Type2::ChoiceFromGroup(ChoiceFromGroup { #[cfg(feature = "ast-comments")] comments, ident, @@ -1567,7 +1573,7 @@ where self.parser_position.range.1, begin_type2_line, ), - }); + })); } #[cfg(feature = "ast-span")] @@ -1575,7 +1581,7 @@ where self.parser_position.range.1 = self.lexer_position.range.1; } - Ok(Type2::ChoiceFromGroup { + Ok(Type2::ChoiceFromGroup(ChoiceFromGroup { #[cfg(feature = "ast-comments")] comments, ident, @@ -1586,7 +1592,7 @@ where self.parser_position.range.1, begin_type2_line, ), - }) + })) } _ => { self.errors.push(Error::PARSER { @@ -1651,7 +1657,7 @@ where return Err(Error::INCREMENTAL); } - Ok(Type2::TaggedData { + Ok(Type2::TaggedData(TaggedData { tag, #[cfg(feature = "ast-comments")] comments_before_type, @@ -1664,10 +1670,10 @@ where self.parser_position.range.1, begin_type2_line, ), - }) + })) } // Tagged data of a major type - (Some(mt), constraint) => Ok(Type2::DataMajorType { + (Some(mt), constraint) => Ok(Type2::DataMajorType(DataMajorType { mt, constraint, #[cfg(feature = "ast-span")] @@ -1676,7 +1682,7 @@ where self.lexer_position.range.1, begin_type2_line, ), - }), + })), #[cfg(feature = "ast-span")] _ => Ok(Type2::Any(Span( begin_type2_range, @@ -1702,7 +1708,7 @@ where self.parser_position.line = self.lexer_position.line; } - Ok(Type2::Typename { + Ok(Type2::Typename(Typename { ident, generic_args: None, #[cfg(feature = "ast-span")] @@ -1711,7 +1717,7 @@ where self.parser_position.range.1, self.parser_position.line, ), - }) + })) } None => { #[cfg(feature = "ast-span")] @@ -2014,26 +2020,25 @@ where ); match member_key { - Some(MemberKey::ParenthesizedType { + Some(MemberKey::Parenthesized(ParenthesizedMemberKey { #[cfg(feature = "ast-comments")] - non_member_key: ParenthesizedType::Type(mut entry_type), + non_member_key: ParenthesizedTypeOrGroup::Type(entry_type), #[cfg(not(feature = "ast-comments"))] - non_member_key: ParenthesizedType::Type(entry_type), + non_member_key: ParenthesizedTypeOrGroup::Type(entry_type), #[cfg(feature = "ast-comments")] comments_before_type_or_group, - #[cfg(feature = "ast-comments")] - comments_after_type_or_group, - }) => { + .. + })) => { #[cfg(feature = "ast-span")] if let Token::COMMA = &self.cur_token { span.1 = self.lexer_position.range.1; } #[cfg(feature = "ast-comments")] - let trailing_comments = entry_type.comments_after_type(); + let trailing_comments = entry_type.comments_after_type; #[cfg(feature = "ast-span")] - if let Some((name, generic_args, _)) = entry_type.groupname_entry() { + if let Some((name, generic_args, _)) = entry_type.pt.groupname_entry() { if name.socket.is_none() && token::lookup_ident(name.ident) .in_standard_prelude() @@ -2063,7 +2068,7 @@ where } #[cfg(not(feature = "ast-span"))] - if let Some((name, generic_args)) = entry_type.groupname_entry() { + if let Some((name, generic_args)) = entry_type.pt.groupname_entry() { if name.socket.is_none() && token::lookup_ident(name.ident) .in_standard_prelude() @@ -2098,15 +2103,8 @@ where self.next_token()?; } - #[cfg(feature = "ast-comments")] - let trailing_comments = if let Some(comments) = entry_type.comments_after_type() { - Some(comments) - } else { - comments_after_type_or_group - }; - #[cfg(feature = "ast-span")] - if let Some((ident, _, _)) = entry_type.groupname_entry() { + if let Some((ident, _, _)) = entry_type.pt.groupname_entry() { if ident.socket.is_none() && token::lookup_ident(ident.ident) .in_standard_prelude() @@ -2123,7 +2121,7 @@ where } #[cfg(not(feature = "ast-span"))] - if let Some((ident, _)) = entry_type.groupname_entry() { + if let Some((ident, _)) = entry_type.pt.groupname_entry() { if ident.socket.is_none() && token::lookup_ident(ident.ident) .in_standard_prelude() @@ -2143,7 +2141,7 @@ where ge: Box::from(ValueMemberKeyEntry { occur, member_key: None, - entry_type, + entry_type: entry_type.pt, }), #[cfg(feature = "ast-comments")] leading_comments: comments_before_type_or_group, @@ -2153,13 +2151,13 @@ where span, }) } - Some(MemberKey::ParenthesizedType { - non_member_key: ParenthesizedType::Group(group), + Some(MemberKey::Parenthesized(ParenthesizedMemberKey { + non_member_key: ParenthesizedTypeOrGroup::Group(group), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] comments_after_type_or_group, - }) => { + })) => { #[cfg(feature = "ast-span")] if let Token::COMMA = &self.cur_token { span.1 = self.lexer_position.range.1; @@ -2468,14 +2466,14 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - let t1 = MemberKey::Type1 { + let t1 = MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident, generic_args: None, #[cfg(feature = "ast-span")] span: Span(begin_memberkey_range, end_t1_range, begin_memberkey_line), - }, + }), operator: None, #[cfg(feature = "ast-comments")] comments_after_type: None, @@ -2495,7 +2493,7 @@ where end_memberkey_range, begin_memberkey_line, ), - }; + }); self.next_token()?; @@ -2516,14 +2514,14 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - let t1 = MemberKey::Type1 { + let t1 = MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident, generic_args: None, #[cfg(feature = "ast-span")] span: Span(begin_memberkey_range, end_t1_range, begin_memberkey_line), - }, + }), operator: None, #[cfg(feature = "ast-comments")] comments_after_type: None, @@ -2543,7 +2541,7 @@ where end_memberkey_range, begin_memberkey_line, ), - }; + }); self.next_token()?; @@ -2558,7 +2556,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Some(MemberKey::Bareword { + Some(MemberKey::Bareword(BarewordMemberKey { ident, #[cfg(feature = "ast-comments")] comments: comments_before_cut, @@ -2570,7 +2568,7 @@ where self.parser_position.range.1, begin_memberkey_line, ), - }) + })) }; Ok(mk) @@ -2657,7 +2655,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Some(MemberKey::Type1 { + Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(t1), #[cfg(feature = "ast-comments")] comments_before_cut, @@ -2672,7 +2670,7 @@ where end_memberkey_range, begin_memberkey_line, ), - }) + })) } else { #[cfg(feature = "ast-comments")] let comments = self.collect_comments()?; @@ -2700,7 +2698,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Some(MemberKey::Value { + Some(MemberKey::Value(ValueMemberKey { value, #[cfg(feature = "ast-comments")] comments, @@ -2712,7 +2710,7 @@ where self.parser_position.range.1, begin_memberkey_line, ), - }) + })) }; if let Token::COLON = &self.cur_token { @@ -2817,13 +2815,13 @@ where Err(e) => return Err(e), }; - return Ok(Some(MemberKey::ParenthesizedType { - non_member_key: ParenthesizedType::Group(group), + return Ok(Some(MemberKey::Parenthesized(ParenthesizedMemberKey { + non_member_key: ParenthesizedTypeOrGroup::Group(group), #[cfg(feature = "ast-comments")] comments_before_type_or_group, #[cfg(feature = "ast-comments")] comments_after_type_or_group, - })); + }))); } // Parse tokens vec as type @@ -2865,9 +2863,9 @@ where #[cfg(feature = "ast-span")] let end_memberkey_range = self.lexer_position.range.1; - let t1 = Some(MemberKey::Type1 { + let t1 = Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::ParenthesizedType { + type2: Type2::ParenthesizedType(ParenthesizedType { pt: t, #[cfg(feature = "ast-comments")] comments_before_type: comments_before_type_or_group, @@ -2879,7 +2877,7 @@ where closing_parend_index, begin_memberkey_line, ), - }, + }), #[cfg(feature = "ast-comments")] comments_after_type: comments_before_cut.clone(), operator: None, @@ -2903,7 +2901,7 @@ where end_memberkey_range, begin_memberkey_line, ), - }); + })); return Ok(t1); } @@ -2921,9 +2919,9 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Some(MemberKey::Type1 { + Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::ParenthesizedType { + type2: Type2::ParenthesizedType(ParenthesizedType { pt: t, #[cfg(feature = "ast-comments")] comments_before_type: comments_before_type_or_group, @@ -2935,7 +2933,7 @@ where closing_parend_index, begin_memberkey_line, ), - }, + }), #[cfg(feature = "ast-comments")] comments_after_type: comments_before_cut.clone(), operator: None, @@ -2959,23 +2957,27 @@ where self.lexer_position.range.0, begin_memberkey_line, ), - }) + })) } else { - Some(MemberKey::ParenthesizedType { - non_member_key: ParenthesizedType::Type(Type { - type_choices: t.type_choices, + Some(MemberKey::Parenthesized(ParenthesizedMemberKey { + non_member_key: ParenthesizedTypeOrGroup::Type(ParenthesizedType { + pt: t, #[cfg(feature = "ast-span")] span: Span( begin_memberkey_range, self.parser_position.range.1, begin_memberkey_line, ), + #[cfg(feature = "ast-comments")] + comments_before_type: comments_before_type_or_group.clone(), + #[cfg(feature = "ast-comments")] + comments_after_type: comments_after_type_or_group.clone(), }), #[cfg(feature = "ast-comments")] - comments_before_type_or_group, - #[cfg(feature = "ast-comments")] comments_after_type_or_group, - }) + #[cfg(feature = "ast-comments")] + comments_before_type_or_group, + })) }; Ok(t1) @@ -3015,7 +3017,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - return Ok(Some(MemberKey::Type1 { + return Ok(Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(t1), #[cfg(feature = "ast-comments")] comments_before_cut, @@ -3030,7 +3032,7 @@ where end_memberkey_range, begin_memberkey_line, ), - })); + }))); } let t1 = if let Token::ARROWMAP = &self.cur_token { @@ -3046,7 +3048,7 @@ where #[cfg(not(feature = "ast-comments"))] self.advance_newline()?; - Some(MemberKey::Type1 { + Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(t1), #[cfg(feature = "ast-comments")] comments_before_cut, @@ -3061,17 +3063,29 @@ where self.parser_position.range.1, begin_memberkey_line, ), - }) + })) } else { - Some(MemberKey::ParenthesizedType { - non_member_key: ParenthesizedType::Type(Type { - type_choices: vec![TypeChoice { - #[cfg(feature = "ast-comments")] - comments_before_type: None, - #[cfg(feature = "ast-comments")] - comments_after_type: None, - type1: t1, - }], + Some(MemberKey::Parenthesized(ParenthesizedMemberKey { + non_member_key: ParenthesizedTypeOrGroup::Type(ParenthesizedType { + pt: Type { + type_choices: vec![TypeChoice { + #[cfg(feature = "ast-comments")] + comments_before_type: None, + #[cfg(feature = "ast-comments")] + comments_after_type: None, + type1: t1, + }], + #[cfg(feature = "ast-span")] + span: Span( + begin_memberkey_range, + self.parser_position.range.1, + begin_memberkey_line, + ), + }, + #[cfg(feature = "ast-comments")] + comments_before_type: None, + #[cfg(feature = "ast-comments")] + comments_after_type: None, #[cfg(feature = "ast-span")] span: Span( begin_memberkey_range, @@ -3083,7 +3097,7 @@ where comments_before_type_or_group: None, #[cfg(feature = "ast-comments")] comments_after_type_or_group: comments_before_cut, - }) + })) }; Ok(t1) diff --git a/src/parser_tests.rs b/src/parser_tests.rs index ef242d0d..35f06d7b 100644 --- a/src/parser_tests.rs +++ b/src/parser_tests.rs @@ -247,29 +247,25 @@ mod tests { args: vec![ GenericArg { arg: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "reboot".into(), span: Span(1, 9, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(1, 9, 1), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, GenericArg { arg: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "now".into(), span: Span(11, 16, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(11, 16, 1), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(0, 17, 1), @@ -292,12 +288,12 @@ mod tests { let expected_output = Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::ParenthesizedType { + type2: Type2::ParenthesizedType(ParenthesizedType { pt: Type { type_choices: vec![ TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "tchoice1".into(), socket: None, @@ -305,17 +301,15 @@ mod tests { }, generic_args: None, span: Span(2, 10, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(2, 10, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "tchoice2".into(), socket: None, @@ -323,27 +317,22 @@ mod tests { }, generic_args: None, span: Span(13, 21, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(13, 21, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(2, 21, 1), }, - comments_before_type: None, - comments_after_type: None, span: Span(0, 23, 1), - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(0, 23, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(0, 23, 1), }; @@ -367,19 +356,19 @@ mod tests { let expected_outputs = [ Type1 { - type2: Type2::UintValue { + type2: Type2::UintValue(UintValue { value: 5, span: Span(0, 1, 1), - }, + }), operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: true, span: Span(1, 3, 1), }, - type2: Type2::UintValue { + type2: Type2::UintValue(UintValue { value: 10, span: Span(3, 5, 1), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -387,19 +376,19 @@ mod tests { span: Span(0, 5, 1), }, Type1 { - type2: Type2::FloatValue { + type2: Type2::FloatValue(FloatValue { value: -10.5, span: Span(0, 5, 1), - }, + }), operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: false, span: Span(5, 8, 1), }, - type2: Type2::FloatValue { + type2: Type2::FloatValue(FloatValue { value: 10.1, span: Span(8, 12, 1), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -407,19 +396,19 @@ mod tests { span: Span(0, 12, 1), }, Type1 { - type2: Type2::FloatValue { + type2: Type2::FloatValue(FloatValue { value: 1.5, span: Span(0, 3, 1), - }, + }), operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: true, span: Span(3, 5, 1), }, - type2: Type2::FloatValue { + type2: Type2::FloatValue(FloatValue { value: 4.5, span: Span(5, 8, 1), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -427,7 +416,7 @@ mod tests { span: Span(0, 8, 1), }, Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "my..lower".into(), socket: None, @@ -435,13 +424,13 @@ mod tests { }, generic_args: None, span: Span(0, 9, 1), - }, + }), operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: false, span: Span(10, 13, 1), }, - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "upper".into(), socket: None, @@ -449,7 +438,7 @@ mod tests { }, generic_args: None, span: Span(14, 19, 1), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -457,7 +446,7 @@ mod tests { span: Span(0, 19, 1), }, Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "target".into(), socket: None, @@ -465,13 +454,13 @@ mod tests { }, generic_args: None, span: Span(0, 6, 1), - }, + }), operator: Some(Operator { operator: RangeCtlOp::CtlOp { ctrl: ".lt", span: Span(7, 10, 1), }, - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "controller".into(), socket: None, @@ -479,7 +468,7 @@ mod tests { }, generic_args: None, span: Span(11, 21, 1), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -487,12 +476,12 @@ mod tests { span: Span(0, 21, 1), }, Type1 { - type2: Type2::ParenthesizedType { + type2: Type2::ParenthesizedType(ParenthesizedType { pt: Type { type_choices: vec![ TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "text".into(), socket: None, @@ -500,17 +489,15 @@ mod tests { }, generic_args: None, span: Span(2, 6, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(2, 6, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "tstr".into(), socket: None, @@ -518,31 +505,28 @@ mod tests { }, generic_args: None, span: Span(9, 13, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(9, 13, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(2, 13, 1), }, - comments_before_type: None, - comments_after_type: None, span: Span(0, 15, 1), - }, + ..Default::default() + }), operator: Some(Operator { operator: RangeCtlOp::CtlOp { ctrl: ".eq", span: Span(16, 19, 1), }, - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "hello".into(), span: Span(20, 27, 1), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -581,11 +565,11 @@ mod tests { ]; let expected_outputs = [ - Type2::TextValue { + Type2::TextValue(TextValue { value: "myvalue".into(), span: Span(0, 9, 1), - }, - Type2::Typename { + }), + Type2::Typename(Typename { ident: Identifier { ident: "message".into(), socket: None, @@ -595,36 +579,32 @@ mod tests { args: vec![ GenericArg { arg: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "reboot".into(), span: Span(8, 16, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(8, 16, 1), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, GenericArg { arg: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "now".into(), span: Span(18, 23, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(18, 23, 1), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(7, 24, 1), }), span: Span(0, 24, 1), - }, - Type2::Typename { + }), + Type2::Typename(Typename { ident: Identifier { ident: "tcp-option".into(), socket: Some(SocketPlug::GROUP), @@ -632,23 +612,22 @@ mod tests { }, generic_args: None, span: Span(0, 12, 1), - }, - Type2::Unwrap { + }), + Type2::Unwrap(Unwrap { ident: Identifier { ident: "group1".into(), socket: None, span: Span(1, 7, 1), }, - generic_args: None, - comments: None, span: Span(0, 0, 0), - }, - Type2::TaggedData { + ..Default::default() + }), + Type2::TaggedData(TaggedData { tag: Some(997), t: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "tstr".into(), socket: None, @@ -656,26 +635,23 @@ mod tests { }, generic_args: None, span: Span(7, 11, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(7, 11, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(7, 11, 1), }, - comments_before_type: None, - comments_after_type: None, span: Span(0, 11, 1), - }, - Type2::FloatValue { + ..Default::default() + }), + Type2::FloatValue(FloatValue { value: 9.9, span: Span(0, 3, 1), - }, + }), Type2::Any(Span(0, 1, 1)), - Type2::Array { + Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -712,11 +688,10 @@ mod tests { }], span: Span(1, 11, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 12, 1), - }, - Type2::Array { + ..Default::default() + }), + Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -749,21 +724,19 @@ mod tests { }], span: Span(1, 10, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 11, 1), - }, - Type2::ChoiceFromGroup { + ..Default::default() + }), + Type2::ChoiceFromGroup(ChoiceFromGroup { ident: Identifier { ident: "groupname".into(), socket: None, span: Span(1, 10, 1), }, - generic_args: None, - comments: None, span: Span(0, 10, 1), - }, - Type2::ChoiceFromInlineGroup { + ..Default::default() + }), + Type2::ChoiceFromInlineGroup(ChoiceFromInlineGroup { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -792,12 +765,10 @@ mod tests { }], span: Span(3, 14, 1), }, - comments: None, - comments_before_group: None, - comments_after_group: None, span: Span(0, 14, 1), - }, - Type2::Map { + ..Default::default() + }), + Type2::Map(Map { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -808,26 +779,24 @@ mod tests { comments: None, _a: PhantomData::default(), }), - member_key: Some(MemberKey::Type1 { + member_key: Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "optional-key".into(), span: Span(4, 18, 1), - }, + }), operator: None, comments_after_type: None, span: Span(4, 18, 1), }), is_cut: true, - comments_before_cut: None, - comments_after_cut: None, - comments_after_arrowmap: None, span: Span(4, 23, 1), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "int".into(), socket: None, @@ -835,13 +804,11 @@ mod tests { }, generic_args: None, span: Span(24, 27, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(24, 27, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(24, 27, 1), }, @@ -861,11 +828,10 @@ mod tests { }], span: Span(2, 28, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 30, 1), - }, - Type2::Array { + ..Default::default() + }), + Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -877,7 +843,7 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "a".into(), socket: None, @@ -886,11 +852,11 @@ mod tests { comments: None, comments_after_colon: None, span: Span(4, 6, 1), - }), + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "int".into(), socket: None, @@ -898,13 +864,11 @@ mod tests { }, generic_args: None, span: Span(7, 10, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(7, 10, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(7, 10, 1), }, @@ -923,20 +887,19 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "b".into(), socket: None, span: Span(12, 13, 1), }, - comments: None, - comments_after_colon: None, span: Span(12, 14, 1), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "tstr".into(), socket: None, @@ -944,13 +907,11 @@ mod tests { }, generic_args: None, span: Span(15, 19, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(15, 19, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(15, 19, 1), }, @@ -987,10 +948,9 @@ mod tests { }], span: Span(2, 21, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 23, 1), - }, + ..Default::default() + }), ]; for (idx, expected_output) in expected_outputs.iter().enumerate() { @@ -1013,7 +973,7 @@ mod tests { ]; let expected_ouputs = [ - Type2::Array { + Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![ @@ -1025,7 +985,7 @@ mod tests { entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Array { + type2: Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -1058,16 +1018,13 @@ mod tests { }], span: Span(3, 15, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(2, 16, 1), - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(2, 16, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(2, 16, 1), }, @@ -1090,7 +1047,7 @@ mod tests { entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Array { + type2: Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -1123,16 +1080,14 @@ mod tests { }], span: Span(19, 36, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(18, 37, 1), - }, + ..Default::default() + }), operator: None, comments_after_type: None, span: Span(18, 37, 1), }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(18, 37, 1), }, @@ -1153,11 +1108,10 @@ mod tests { }], span: Span(2, 37, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 39, 1), - }, - Type2::Map { + ..Default::default() + }), + Type2::Map(Map { group: Group { group_choices: vec![ GroupChoice { @@ -1259,11 +1213,10 @@ mod tests { ], span: Span(2, 23, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 25, 1), - }, - Type2::Map { + ..Default::default() + }), + Type2::Map(Map { group: Group { group_choices: vec![GroupChoice { group_entries: vec![ @@ -1357,10 +1310,9 @@ mod tests { }], span: Span(2, 21, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(0, 23, 1), - }, + ..Default::default() + }), ]; for (idx, expected_output) in expected_ouputs.iter().enumerate() { @@ -1393,9 +1345,9 @@ mod tests { comments: None, _a: PhantomData::default(), }), - member_key: Some(MemberKey::Type1 { + member_key: Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "type1".into(), socket: None, @@ -1403,30 +1355,25 @@ mod tests { }, generic_args: None, span: Span(2, 7, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(2, 7, 1), + ..Default::default() }), is_cut: true, - comments_before_cut: None, - comments_after_cut: None, - comments_after_arrowmap: None, span: Span(2, 12, 1), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "value".into(), span: Span(13, 20, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(13, 20, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(13, 20, 1), }, @@ -1438,20 +1385,19 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "type1".into(), socket: None, span: Span(0, 5, 1), }, - comments: None, - comments_after_colon: None, span: Span(0, 6, 1), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "type2".into(), socket: None, @@ -1459,13 +1405,11 @@ mod tests { }, generic_args: None, span: Span(7, 12, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(7, 12, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(7, 12, 1), }, @@ -1495,16 +1439,16 @@ mod tests { comments: None, _a: PhantomData::default(), }), - member_key: Some(MemberKey::Value { + member_key: Some(MemberKey::Value(ValueMemberKey { value: token::Value::UINT(0), comments: None, comments_after_colon: None, span: Span(2, 4, 1), - }), + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "addrdistr".into(), socket: None, @@ -1512,13 +1456,11 @@ mod tests { }, generic_args: None, span: Span(5, 14, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(5, 14, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(5, 14, 1), }, @@ -1530,16 +1472,16 @@ mod tests { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Value { + member_key: Some(MemberKey::Value(ValueMemberKey { value: token::Value::UINT(0), comments: None, comments_after_colon: None, span: Span(0, 2, 1), - }), + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "finite_set".into(), socket: None, @@ -1548,7 +1490,7 @@ mod tests { generic_args: Some(GenericArgs { args: vec![GenericArg { arg: Box::from(Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "transaction_input".into(), socket: None, @@ -1556,25 +1498,21 @@ mod tests { }, generic_args: None, span: Span(14, 31, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(14, 31, 1), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(13, 32, 1), }), span: Span(3, 32, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(3, 32, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(3, 32, 1), }, @@ -1590,9 +1528,9 @@ mod tests { comments: None, _a: PhantomData::default(), }), - member_key: Some(MemberKey::Type1 { + member_key: Some(MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::Array { + type2: Type2::Array(Array { group: Group { group_choices: vec![GroupChoice { group_entries: vec![( @@ -1621,24 +1559,20 @@ mod tests { }], span: Span(3, 13, 1), }, - comments_before_group: None, - comments_after_group: None, span: Span(2, 14, 1), - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(2, 14, 1), + ..Default::default() }), is_cut: false, - comments_before_cut: None, - comments_after_cut: None, - comments_after_arrowmap: None, span: Span(2, 22, 1), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "coin".into(), socket: None, @@ -1646,13 +1580,11 @@ mod tests { }, generic_args: None, span: Span(18, 22, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(18, 22, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(18, 22, 1), }, @@ -1686,9 +1618,9 @@ mod tests { ]; let expected_outputs = [ - MemberKey::Type1 { + MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "type1".into(), socket: None, @@ -1696,38 +1628,32 @@ mod tests { }, generic_args: None, span: Span(0, 5, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(0, 5, 1), + ..Default::default() }), - is_cut: false, - comments_before_cut: None, - comments_after_cut: None, - comments_after_arrowmap: None, span: Span(0, 8, 1), - }, - MemberKey::Type1 { + ..Default::default() + }), + MemberKey::Type1(Type1MemberKey { t1: Box::from(Type1 { - type2: Type2::ParenthesizedType { + type2: Type2::ParenthesizedType(ParenthesizedType { pt: Type { type_choices: vec![ TypeChoice { type1: Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "mytype1".into(), span: Span(2, 11, 1), - }, - operator: None, + }), span: Span(2, 11, 1), - comments_after_type: None, + ..Default::default() }, - comments_after_type: None, - comments_before_type: None, + ..Default::default() }, TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "int", span: Span(14, 17, 1), @@ -1735,63 +1661,55 @@ mod tests { }, span: Span(14, 17, 1), generic_args: None, - }, + }), span: Span(14, 17, 1), - comments_after_type: None, - operator: None, + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(2, 17, 1), }, span: Span(0, 19, 1), - comments_before_type: None, - comments_after_type: None, - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(0, 19, 1), + ..Default::default() }), is_cut: true, - comments_before_cut: None, - comments_after_cut: None, - comments_after_arrowmap: None, span: Span(0, 24, 1), - }, - MemberKey::Bareword { + ..Default::default() + }), + MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "mybareword".into(), socket: None, span: Span(0, 10, 1), }, - comments: None, - comments_after_colon: None, span: Span(0, 11, 1), - }, - MemberKey::Bareword { + ..Default::default() + }), + MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "my..bareword".into(), socket: None, span: Span(0, 12, 1), }, - comments: None, - comments_after_colon: None, span: Span(0, 13, 1), - }, - MemberKey::Value { + ..Default::default() + }), + MemberKey::Value(ValueMemberKey { value: token::Value::TEXT("myvalue".into()), comments: None, comments_after_colon: None, span: Span(0, 10, 1), - }, - MemberKey::Value { + }), + MemberKey::Value(ValueMemberKey { value: token::Value::UINT(0), comments: None, comments_after_colon: None, span: Span(0, 2, 1), - }, + }), ]; for (idx, expected_output) in expected_outputs.iter().enumerate() { diff --git a/src/util.rs b/src/util.rs index 425dd736..c8f5ffd3 100644 --- a/src/util.rs +++ b/src/util.rs @@ -23,14 +23,16 @@ pub fn text_value_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<& if tc.type1.operator.is_none() { match &tc.type1.type2 { Type2::TextValue { .. } | Type2::UTF8ByteString { .. } => Some(&tc.type1.type2), - Type2::Typename { ident, .. } => text_value_from_ident(cddl, ident), - Type2::ParenthesizedType { pt, .. } => pt.type_choices.iter().find_map(|tc| { - if tc.type1.operator.is_none() { - text_value_from_type2(cddl, &tc.type1.type2) - } else { - None - } - }), + Type2::Typename(Typename { ident, .. }) => text_value_from_ident(cddl, ident), + Type2::ParenthesizedType(ParenthesizedType { pt, .. }) => { + pt.type_choices.iter().find_map(|tc| { + if tc.type1.operator.is_none() { + text_value_from_type2(cddl, &tc.type1.type2) + } else { + None + } + }) + } _ => None, } } else { @@ -45,9 +47,9 @@ pub fn text_value_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option<& /// Find text values from a given Type2 pub fn text_value_from_type2<'a>(cddl: &'a CDDL, t2: &'a Type2<'a>) -> Option<&'a Type2<'a>> { match t2 { - Type2::TextValue { .. } | Type2::UTF8ByteString { .. } => Some(t2), - Type2::Typename { ident, .. } => text_value_from_ident(cddl, ident), - Type2::Array { group, .. } => group.group_choices.iter().find_map(|gc| { + Type2::TextValue(_) | Type2::UTF8ByteString(_) => Some(t2), + Type2::Typename(Typename { ident, .. }) => text_value_from_ident(cddl, ident), + Type2::Array(Array { group, .. }) => group.group_choices.iter().find_map(|gc| { if gc.group_entries.len() == 2 { if let Some(ge) = gc.group_entries.first() { if let GroupEntry::ValueMemberKey { ge, .. } = &ge.0 { @@ -72,13 +74,15 @@ pub fn text_value_from_type2<'a>(cddl: &'a CDDL, t2: &'a Type2<'a>) -> Option<&' None } }), - Type2::ParenthesizedType { pt, .. } => pt.type_choices.iter().find_map(|tc| { - if tc.type1.operator.is_none() { - text_value_from_type2(cddl, &tc.type1.type2) - } else { - None - } - }), + Type2::ParenthesizedType(ParenthesizedType { pt, .. }) => { + pt.type_choices.iter().find_map(|tc| { + if tc.type1.operator.is_none() { + text_value_from_type2(cddl, &tc.type1.type2) + } else { + None + } + }) + } _ => None, } } @@ -106,11 +110,11 @@ pub fn unwrap_rule_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Option< if type_choices.iter().any(match_fn) { Some(r) } else if let Some(ident) = type_choices.iter().find_map(|tc| { - if let Type2::Typename { + if let Type2::Typename(Typename { ident, generic_args: None, .. - } = &tc.type1.type2 + }) = &tc.type1.type2 { Some(ident) } else { @@ -161,7 +165,7 @@ pub fn numeric_range_bound_from_ident<'a>( Type2::IntValue { .. } | Type2::UintValue { .. } | Type2::FloatValue { .. } => { Some(type2) } - Type2::Typename { ident, .. } => numeric_range_bound_from_ident(cddl, ident), + Type2::Typename(Typename { ident, .. }) => numeric_range_bound_from_ident(cddl, ident), _ => None, }, _ => None, @@ -257,7 +261,7 @@ pub fn is_ident_null_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_null_data_type(cddl, ident) } else { false @@ -275,7 +279,7 @@ pub fn is_ident_bool_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_bool_data_type(cddl, ident) } else { false @@ -301,7 +305,7 @@ pub fn ident_matches_bool_value(cddl: &CDDL, ident: &Identifier, value: bool) -> cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { ident_matches_bool_value(cddl, ident, value) } else { false @@ -319,7 +323,7 @@ pub fn is_ident_uri_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_uri_data_type(cddl, ident) } else { false @@ -337,7 +341,7 @@ pub fn is_ident_b64url_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_b64url_data_type(cddl, ident) } else { false @@ -355,7 +359,7 @@ pub fn is_ident_tdate_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_tdate_data_type(cddl, ident) } else { false @@ -373,7 +377,7 @@ pub fn is_ident_time_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if &rule.name == ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_time_data_type(cddl, ident) } else { false @@ -403,7 +407,7 @@ pub fn is_ident_numeric_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_numeric_data_type(cddl, ident) } else { false @@ -421,7 +425,7 @@ pub fn is_ident_uint_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_uint_data_type(cddl, ident) } else { false @@ -439,7 +443,7 @@ pub fn is_ident_nint_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_nint_data_type(cddl, ident) } else { false @@ -459,7 +463,7 @@ pub fn is_ident_integer_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_integer_data_type(cddl, ident) } else { false @@ -483,7 +487,7 @@ pub fn is_ident_float_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_float_data_type(cddl, ident) } else { false @@ -501,7 +505,7 @@ pub fn is_ident_string_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_string_data_type(cddl, ident) } else { false @@ -519,7 +523,7 @@ pub fn is_ident_any_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_any_type(cddl, ident) } else { false @@ -537,7 +541,7 @@ pub fn is_ident_byte_string_data_type(cddl: &CDDL, ident: &Identifier) -> bool { cddl.rules.iter().any(|r| match r { Rule::Type { rule, .. } if rule.name == *ident => rule.value.type_choices.iter().any(|tc| { - if let Type2::Typename { ident, .. } = &tc.type1.type2 { + if let Type2::Typename(Typename { ident, .. }) = &tc.type1.type2 { is_ident_byte_string_data_type(cddl, ident) } else { false diff --git a/src/validator/cbor.rs b/src/validator/cbor.rs index 102385b3..10a5a53b 100644 --- a/src/validator/cbor.rs +++ b/src/validator/cbor.rs @@ -743,8 +743,8 @@ where } match lower { - Type2::IntValue { value: l, .. } => match upper { - Type2::IntValue { value: u, .. } => { + Type2::IntValue(IntValue { value: l, .. }) => match upper { + Type2::IntValue(IntValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected integer to be in range {} <= value <= {}, got {:?}", @@ -778,7 +778,7 @@ where } } } - Type2::UintValue { value: u, .. } => { + Type2::UintValue(UintValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected integer to be in range {} <= value <= {}, got {:?}", @@ -820,8 +820,8 @@ where return Ok(()); } }, - Type2::UintValue { value: l, .. } => match upper { - Type2::UintValue { value: u, .. } => { + Type2::UintValue(UintValue { value: l, .. }) => match upper { + Type2::UintValue(UintValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected uint to be in range {} <= value <= {}, got {:?}", @@ -889,8 +889,8 @@ where return Ok(()); } }, - Type2::FloatValue { value: l, .. } => match upper { - Type2::FloatValue { value: u, .. } => { + Type2::FloatValue(FloatValue { value: l, .. }) => match upper { + Type2::FloatValue(FloatValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected float to be in range {} <= value <= {}, got {:?}", @@ -951,15 +951,15 @@ where ctrl: &Token<'a>, controller: &Type2<'a>, ) -> visitor::Result> { - if let Type2::Typename { + if let Type2::Typename(Typename { ident: target_ident, .. - } = target + }) = target { - if let Type2::Typename { + if let Type2::Typename(Typename { ident: controller_ident, .. - } = controller + }) = controller { if let Some(name) = self.eval_generic_rule { if let Some(gr) = self @@ -1007,14 +1007,14 @@ where match ctrl { Token::EQ => { match target { - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) { return self.visit_type2(controller); } } - Type2::Array { group, .. } => { + Type2::Array(Array { group, .. }) => { if let Value::Array(_) = &self.cbor { let mut entry_counts = Vec::new(); for gc in group.group_choices.iter() { @@ -1027,7 +1027,7 @@ where return Ok(()); } } - Type2::Map { .. } => { + Type2::Map(Map { .. }) => { if let Value::Map(_) = &self.cbor { self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; @@ -1046,7 +1046,7 @@ where } Token::NE => { match target { - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) { @@ -1056,7 +1056,7 @@ where return Ok(()); } } - Type2::Array { .. } => { + Type2::Array(Array { .. }) => { if let Value::Array(_) = &self.cbor { self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; @@ -1064,7 +1064,7 @@ where return Ok(()); } } - Type2::Map { .. } => { + Type2::Map(Map { .. }) => { if let Value::Map(_) = &self.cbor { self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; @@ -1082,7 +1082,7 @@ where Ok(()) } Token::LT | Token::GT | Token::GE | Token::LE => match target { - Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) if is_ident_numeric_data_type(self.cddl, ident) => { self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; @@ -1097,7 +1097,7 @@ where } }, Token::SIZE => match target { - Type2::Typename { ident, .. } + Type2::Typename(Typename { ident, .. }) if is_ident_string_data_type(self.cddl, ident) || is_ident_uint_data_type(self.cddl, ident) || is_ident_byte_string_data_type(self.cddl, ident) => @@ -1169,7 +1169,9 @@ where Token::REGEXP | Token::PCRE => { self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) + if is_ident_string_data_type(self.cddl, ident) => + { match self.cbor { Value::Text(_) | Value::Array(_) => self.visit_type2(controller)?, _ => self.add_error(format!( @@ -1190,7 +1192,9 @@ where Token::CBOR | Token::CBORSEQ => { self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) + if is_ident_byte_string_data_type(self.cddl, ident) => + { match &self.cbor { Value::Bytes(_) | Value::Array(_) => self.visit_type2(controller)?, _ => self.add_error(format!( @@ -1211,7 +1215,7 @@ where Token::BITS => { self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } + Type2::Typename(Typename { ident, .. }) if is_ident_byte_string_data_type(self.cddl, ident) || is_ident_uint_data_type(self.cddl, ident) => { @@ -1324,10 +1328,12 @@ where self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) + if is_ident_string_data_type(self.cddl, ident) => + { match self.cbor { Value::Text(_) | Value::Array(_) => { - if let Type2::ParenthesizedType { pt, .. } = controller { + if let Type2::ParenthesizedType(ParenthesizedType { pt, .. }) = controller { match abnf_from_complex_controller(self.cddl, pt) { Ok(values) => { let error_count = self.errors.len(); @@ -1372,10 +1378,12 @@ where self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } if is_ident_byte_string_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) + if is_ident_byte_string_data_type(self.cddl, ident) => + { match self.cbor { Value::Bytes(_) | Value::Array(_) => { - if let Type2::ParenthesizedType { pt, .. } = controller { + if let Type2::ParenthesizedType(ParenthesizedType { pt, .. }) = controller { match abnf_from_complex_controller(self.cddl, pt) { Ok(values) => { let error_count = self.errors.len(); @@ -1422,7 +1430,7 @@ where if let Some(ef) = self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); - if let Some(Type2::TextValue { value, .. }) = tv { + if let Some(Type2::TextValue(TextValue { value, .. })) = tv { if ef.contains(&&**value) { let err_count = self.errors.len(); self.visit_type2(target)?; @@ -1436,7 +1444,7 @@ where .get_or_insert(vec![value.to_string()]) .push(value.to_string()); } - } else if let Some(Type2::UTF8ByteString { value, .. }) = tv { + } else if let Some(Type2::UTF8ByteString(Utf8ByteString { value, .. })) = tv { let value = std::str::from_utf8(value).map_err(Error::UTF8Parsing)?; if ef.contains(&value) { let err_count = self.errors.len(); @@ -1465,7 +1473,7 @@ where if let Some(ef) = &self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); - if let Some(Type2::TextValue { value, .. }) = tv { + if let Some(Type2::TextValue(TextValue { value, .. })) = tv { if ef.contains(&JsValue::from(value.as_ref())) { let err_count = self.errors.len(); self.visit_type2(target)?; @@ -1479,7 +1487,7 @@ where .get_or_insert(vec![value.to_string()]) .push(value.to_string()); } - } else if let Some(Type2::UTF8ByteString { value, .. }) = tv { + } else if let Some(Type2::UTF8ByteString(Utf8ByteString { value, .. })) = tv { let value = std::str::from_utf8(value).map_err(Error::UTF8Parsing)?; if ef.contains(&JsValue::from(value)) { let err_count = self.errors.len(); @@ -1598,8 +1606,10 @@ where } match t2 { - Type2::TextValue { value, .. } => self.visit_value(&token::Value::TEXT(value.clone())), - Type2::Map { group, .. } => match &self.cbor { + Type2::TextValue(TextValue { value, .. }) => { + self.visit_value(&token::Value::TEXT(value.clone())) + } + Type2::Map(Map { group, .. }) => match &self.cbor { Value::Map(m) => { if self.is_member_key { let current_location = self.cbor_location.clone(); @@ -1759,7 +1769,7 @@ where Ok(()) } }, - Type2::Array { group, .. } => match &self.cbor { + Type2::Array(Array { group, .. }) => match &self.cbor { Value::Array(a) => { if group.group_choices.len() == 1 && group.group_choices[0].group_entries.is_empty() @@ -1847,11 +1857,11 @@ where Ok(()) } }, - Type2::ChoiceFromGroup { + Type2::ChoiceFromGroup(ChoiceFromGroup { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { if let Some(rule) = rule_from_ident(self.cddl, ident) { if let Some(gr) = self @@ -1904,17 +1914,17 @@ where Ok(()) } - Type2::ChoiceFromInlineGroup { group, .. } => { + Type2::ChoiceFromInlineGroup(ChoiceFromInlineGroup { group, .. }) => { self.is_group_to_choice_enum = true; self.visit_group(group)?; self.is_group_to_choice_enum = false; Ok(()) } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { if let Some(rule) = rule_from_ident(self.cddl, ident) { if let Some(gr) = self @@ -1954,19 +1964,21 @@ where self.visit_identifier(ident) } - Type2::IntValue { value, .. } => self.visit_value(&token::Value::INT(*value)), - Type2::UintValue { value, .. } => self.visit_value(&token::Value::UINT(*value)), - Type2::FloatValue { value, .. } => self.visit_value(&token::Value::FLOAT(*value)), - Type2::ParenthesizedType { pt, .. } => self.visit_type(pt), - Type2::Unwrap { + Type2::IntValue(IntValue { value, .. }) => self.visit_value(&token::Value::INT(*value)), + Type2::UintValue(UintValue { value, .. }) => self.visit_value(&token::Value::UINT(*value)), + Type2::FloatValue(FloatValue { value, .. }) => self.visit_value(&token::Value::FLOAT(*value)), + Type2::ParenthesizedType(ParenthesizedType { pt, .. }) => self.visit_type(pt), + Type2::Unwrap(Unwrap { ident, generic_args, .. - } => { + }) => { // Per // https://github.com/w3c/did-spec-registries/pull/138#issuecomment-719739215, // strip tag and validate underlying type - if let Some(Type2::TaggedData { t, .. }) = tag_from_token(&lookup_ident(ident.ident)) { + if let Some(Type2::TaggedData(TaggedData { t, .. })) = + tag_from_token(&lookup_ident(ident.ident)) + { return self.visit_type(&t); } @@ -2018,7 +2030,7 @@ where Ok(()) } - Type2::TaggedData { tag, t, .. } => match &self.cbor { + Type2::TaggedData(TaggedData { tag, t, .. }) => match &self.cbor { Value::Tag(actual_tag, value) => { if let Some(tag) = tag { if *tag as u64 != *actual_tag { @@ -2074,7 +2086,7 @@ where Ok(()) } }, - Type2::DataMajorType { mt, constraint, .. } => match &self.cbor { + Type2::DataMajorType(DataMajorType { mt, constraint, .. }) => match &self.cbor { Value::Integer(i) => { match mt { 0u8 => match constraint { @@ -3116,7 +3128,7 @@ where fn visit_memberkey(&mut self, mk: &MemberKey<'a>) -> visitor::Result> { match mk { - MemberKey::Type1 { is_cut, .. } => { + MemberKey::Type1(Type1MemberKey { is_cut, .. }) => { self.is_cut_present = *is_cut; walk_memberkey(self, mk)?; self.is_cut_present = false; diff --git a/src/validator/control.rs b/src/validator/control.rs index cffe9c91..be149706 100644 --- a/src/validator/control.rs +++ b/src/validator/control.rs @@ -1,7 +1,7 @@ #![cfg(any(feature = "json", feature = "cbor"))] #![cfg(not(feature = "lsp"))] -use crate::ast::{Identifier, Operator, RangeCtlOp, Rule, Type2, CDDL}; +use crate::ast::*; #[cfg(feature = "additional-controls")] use crate::{ast::Type, token::lookup_control_from_str, validator::ByteValue, Token}; @@ -23,7 +23,7 @@ pub fn string_literals_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Vec | t @ Type2::UTF8ByteString { .. } | t @ Type2::B16ByteString { .. } | t @ Type2::B64ByteString { .. } => literals.push(t), - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { literals.append(&mut string_literals_from_ident(cddl, ident)) } _ => continue, @@ -48,7 +48,7 @@ pub fn numeric_values_from_ident<'a>(cddl: &'a CDDL, ident: &Identifier) -> Vec< t @ Type2::IntValue { .. } | t @ Type2::UintValue { .. } | t @ Type2::FloatValue { .. } => literals.push(t), - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { literals.append(&mut numeric_values_from_ident(cddl, ident)) } _ => continue, @@ -74,11 +74,11 @@ pub fn cat_operation<'a>( let ctrl = if is_dedent { Token::DET } else { Token::CAT }; match target { - Type2::TextValue { value, .. } => match controller { + Type2::TextValue(TextValue { value, .. }) => match controller { // "testing" .cat "123" - Type2::TextValue { + Type2::TextValue(TextValue { value: controller, .. - } => { + }) => { if is_dedent { literals.push(format!("{}{}", dedent_str(value), dedent_str(controller)).into()) } else { @@ -86,7 +86,7 @@ pub fn cat_operation<'a>( } } // "testing" .cat a - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { let sl = string_literals_from_ident(cddl, ident); if sl.is_empty() { return Err(format!( @@ -99,9 +99,9 @@ pub fn cat_operation<'a>( } } // "testing" .cat '123' - Type2::UTF8ByteString { + Type2::UTF8ByteString(Utf8ByteString { value: controller, .. - } => match std::str::from_utf8(controller) { + }) => match std::str::from_utf8(controller) { Ok(controller) => { let controller = controller.trim_start_matches('\'').trim_end_matches('\''); @@ -114,9 +114,9 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("error parsing byte string: {}", e)), }, // "testing" .cat h'313233' - Type2::B16ByteString { + Type2::B16ByteString(B16ByteString { value: controller, .. - } => match base16::decode(controller) { + }) => match base16::decode(controller) { Ok(controller) => match String::from_utf8(controller) { Ok(controller) => { if is_dedent { @@ -130,9 +130,9 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("error decoding base16 byte string literal: {}", e)), }, // "testing" .cat b64'MTIz' - Type2::B64ByteString { + Type2::B64ByteString(B64ByteString { value: controller, .. - } => match base64::decode_config(controller, base64::URL_SAFE) { + }) => match base64::decode_config(controller, base64::URL_SAFE) { Ok(controller) => match String::from_utf8(controller) { Ok(controller) => { if is_dedent { @@ -151,7 +151,7 @@ pub fn cat_operation<'a>( } }, // "testing" .cat ( "123" / "1234" ) - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { if controller.type1.operator.is_none() { literals.append(&mut cat_operation( @@ -166,7 +166,7 @@ pub fn cat_operation<'a>( _ => return Err(format!("invalid controller used for {} operation", ctrl)), }, // a .cat "123" - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { // Only grab the first type choice literal from the target per // https://github.com/cbor-wg/cddl-control/issues/2#issuecomment-729253368 if let Some(value) = string_literals_from_ident(cddl, ident).first() { @@ -176,7 +176,7 @@ pub fn cat_operation<'a>( } } // ( "test" / "testing" ) .cat "123" - Type2::ParenthesizedType { pt: target, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: target, .. }) => { // Only grab the first type choice literal from the target per // https://github.com/cbor-wg/cddl-control/issues/2#issuecomment-729253368 if let Some(tc) = target.type_choices.first() { @@ -193,12 +193,12 @@ pub fn cat_operation<'a>( return Err(format!("invalid target type in {} control operator", ctrl)); } - Type2::UTF8ByteString { value, .. } => match std::str::from_utf8(value) { + Type2::UTF8ByteString(Utf8ByteString { value, .. }) => match std::str::from_utf8(value) { Ok(value) => match controller { // 'testing' .cat "123" - Type2::TextValue { + Type2::TextValue(TextValue { value: controller, .. - } => { + }) => { let value = value.trim_start_matches('\'').trim_end_matches('\''); if is_dedent { @@ -207,7 +207,7 @@ pub fn cat_operation<'a>( literals.push(format!("{}{}", value, controller).into()) } } - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { let sl = string_literals_from_ident(cddl, ident); if sl.is_empty() { return Err(format!( @@ -220,9 +220,9 @@ pub fn cat_operation<'a>( } } // 'testing' .cat '123 - Type2::UTF8ByteString { + Type2::UTF8ByteString(Utf8ByteString { value: controller, .. - } => match std::str::from_utf8(controller) { + }) => match std::str::from_utf8(controller) { Ok(controller) => { let value = value.trim_start_matches('\'').trim_end_matches('\''); let controller = controller.trim_start_matches('\'').trim_end_matches('\''); @@ -236,9 +236,9 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("error parsing byte string: {}", e)), }, // 'testing' .cat h'313233' - Type2::B16ByteString { + Type2::B16ByteString(B16ByteString { value: controller, .. - } => match base16::decode(controller) { + }) => match base16::decode(controller) { Ok(controller) => match String::from_utf8(controller) { Ok(controller) => { let value = value.trim_start_matches('\'').trim_end_matches('\''); @@ -254,9 +254,9 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("error decoding base16 byte string literal: {}", e)), }, // 'testing' .cat b64'MTIz' - Type2::B64ByteString { + Type2::B64ByteString(B64ByteString { value: controller, .. - } => match base64::decode_config(controller, base64::URL_SAFE) { + }) => match base64::decode_config(controller, base64::URL_SAFE) { Ok(controller) => match String::from_utf8(controller) { Ok(controller) => { let value = value.trim_start_matches('\'').trim_end_matches('\''); @@ -277,7 +277,7 @@ pub fn cat_operation<'a>( } }, // 'testing' .cat ( "123" / "1234" ) - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { if controller.type1.operator.is_none() { literals.append(&mut cat_operation( @@ -293,11 +293,11 @@ pub fn cat_operation<'a>( }, Err(e) => return Err(format!("error parsing byte string: {}", e)), }, - Type2::B16ByteString { value, .. } => match controller { + Type2::B16ByteString(B16ByteString { value, .. }) => match controller { // h'74657374696E67' .cat "123" - Type2::TextValue { + Type2::TextValue(TextValue { value: controller, .. - } => { + }) => { let controller = if is_dedent { base16::encode_lower(dedent_str(controller).as_bytes()) } else { @@ -316,7 +316,7 @@ pub fn cat_operation<'a>( } } // h'74657374696E67' .cat b - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { let sl = string_literals_from_ident(cddl, ident); if sl.is_empty() { return Err(format!( @@ -329,9 +329,9 @@ pub fn cat_operation<'a>( } } // h'74657374696E67' .cat '123' - Type2::UTF8ByteString { + Type2::UTF8ByteString(Utf8ByteString { value: controller, .. - } => { + }) => { let controller = if is_dedent { base16::encode_lower(&dedent_bytes(controller, true)?) } else { @@ -351,9 +351,9 @@ pub fn cat_operation<'a>( } } // h'74657374696E67' .cat h'313233' - Type2::B16ByteString { + Type2::B16ByteString(B16ByteString { value: controller, .. - } => { + }) => { let concat = if is_dedent { [ &dedent_bytes(value, false)?[..], @@ -370,9 +370,9 @@ pub fn cat_operation<'a>( } } // h'74657374696E67' .cat b64'MTIz' - Type2::B64ByteString { + Type2::B64ByteString(B64ByteString { value: controller, .. - } => match base64::decode_config(controller, base64::URL_SAFE) { + }) => match base64::decode_config(controller, base64::URL_SAFE) { Ok(controller) => { let controller = base16::encode_lower(&controller); let concat = if is_dedent { @@ -393,7 +393,7 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("controller is invalid base64: {}", e)), }, // h'74657374696E67' .cat ( "123" / "1234" ) - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { if controller.type1.operator.is_none() { literals.append(&mut cat_operation( @@ -407,11 +407,11 @@ pub fn cat_operation<'a>( } _ => return Err(format!("invalid controller used for {} operation", ctrl)), }, - Type2::B64ByteString { value, .. } => match controller { + Type2::B64ByteString(B64ByteString { value, .. }) => match controller { // b64'dGVzdGluZw==' .cat "123" - Type2::TextValue { + Type2::TextValue(TextValue { value: controller, .. - } => match base64::decode_config(value, base64::URL_SAFE) { + }) => match base64::decode_config(value, base64::URL_SAFE) { Ok(value) => { let concat = if is_dedent { [ @@ -435,7 +435,7 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("target is invalid base64: {}", e)), }, // b64'dGVzdGluZw==' .cat b - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { let sl = string_literals_from_ident(cddl, ident); if sl.is_empty() { return Err(format!( @@ -448,9 +448,9 @@ pub fn cat_operation<'a>( } } // b64'dGVzdGluZw==' .cat '123' - Type2::UTF8ByteString { + Type2::UTF8ByteString(Utf8ByteString { value: controller, .. - } => match base64::decode_config(value, base64::URL_SAFE) { + }) => match base64::decode_config(value, base64::URL_SAFE) { Ok(value) => { let concat = if is_dedent { [ @@ -474,9 +474,9 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("target is invalid base64: {}", e)), }, // b64'dGVzdGluZw==' .cat h'313233' - Type2::B16ByteString { + Type2::B16ByteString(B16ByteString { value: controller, .. - } => match base64::decode_config(value, base64::URL_SAFE) { + }) => match base64::decode_config(value, base64::URL_SAFE) { Ok(value) => match base16::decode(controller) { Ok(controller) => { let concat = if is_dedent { @@ -502,9 +502,9 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("target is invalid base64: {}", e)), }, // b64'dGVzdGluZw==' .cat b64'MTIz' - Type2::B64ByteString { + Type2::B64ByteString(B64ByteString { value: controller, .. - } => match base64::decode_config(value, base64::URL_SAFE) { + }) => match base64::decode_config(value, base64::URL_SAFE) { Ok(value) => match base64::decode_config(controller, base64::URL_SAFE) { Ok(controller) => { let concat = if is_dedent { @@ -530,7 +530,7 @@ pub fn cat_operation<'a>( Err(e) => return Err(format!("target is invalid base64: {}", e)), }, // b64'dGVzdGluZw==' .cat ( "123" / "1234" ) - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { if controller.type1.operator.is_none() { literals.append(&mut cat_operation( @@ -607,17 +607,17 @@ pub fn plus_operation<'a>( ) -> Result>, String> { let mut values = Vec::new(); match target { - Type2::UintValue { value, .. } => match controller { - Type2::UintValue { + Type2::UintValue(UintValue { value, .. }) => match controller { + Type2::UintValue(UintValue { value: controller, .. - } => values.push((value + controller).into()), - Type2::IntValue { + }) => values.push((value + controller).into()), + Type2::IntValue(IntValue { value: controller, .. - } => values.push(((*value as isize + controller) as usize).into()), - Type2::FloatValue { + }) => values.push(((*value as isize + controller) as usize).into()), + Type2::FloatValue(FloatValue { value: controller, .. - } => values.push(((*value as isize + *controller as isize) as usize).into()), - Type2::Typename { ident, .. } => { + }) => values.push(((*value as isize + *controller as isize) as usize).into()), + Type2::Typename(Typename { ident, .. }) => { let nv = numeric_values_from_ident(cddl, ident); if nv.is_empty() { return Err(format!( @@ -630,7 +630,7 @@ pub fn plus_operation<'a>( values.append(&mut plus_operation(cddl, target, controller)?) } } - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { match &controller.type1.operator { Some(Operator { @@ -649,17 +649,17 @@ pub fn plus_operation<'a>( } _ => return Err("invalid controller used for .plus operation".to_string()), }, - Type2::IntValue { value, .. } => match controller { - Type2::IntValue { + Type2::IntValue(IntValue { value, .. }) => match controller { + Type2::IntValue(IntValue { value: controller, .. - } => values.push((value + controller).into()), - Type2::UintValue { + }) => values.push((value + controller).into()), + Type2::UintValue(UintValue { value: controller, .. - } => values.push((value + *controller as isize).into()), - Type2::FloatValue { + }) => values.push((value + *controller as isize).into()), + Type2::FloatValue(FloatValue { value: controller, .. - } => values.push((value + *controller as isize).into()), - Type2::Typename { ident, .. } => { + }) => values.push((value + *controller as isize).into()), + Type2::Typename(Typename { ident, .. }) => { let nv = numeric_values_from_ident(cddl, ident); if nv.is_empty() { return Err(format!( @@ -672,7 +672,7 @@ pub fn plus_operation<'a>( values.append(&mut plus_operation(cddl, target, controller)?) } } - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { match &controller.type1.operator { Some(Operator { @@ -691,14 +691,14 @@ pub fn plus_operation<'a>( } _ => return Err("invalid controller used for .plus operation".to_string()), }, - Type2::FloatValue { value, .. } => match controller { - Type2::IntValue { + Type2::FloatValue(FloatValue { value, .. }) => match controller { + Type2::IntValue(IntValue { value: controller, .. - } => values.push((value + *controller as f64).into()), - Type2::FloatValue { + }) => values.push((value + *controller as f64).into()), + Type2::FloatValue(FloatValue { value: controller, .. - } => values.push((value + controller).into()), - Type2::Typename { ident, .. } => { + }) => values.push((value + controller).into()), + Type2::Typename(Typename { ident, .. }) => { let nv = numeric_values_from_ident(cddl, ident); if nv.is_empty() { return Err(format!( @@ -711,7 +711,7 @@ pub fn plus_operation<'a>( values.append(&mut plus_operation(cddl, target, controller)?) } } - Type2::ParenthesizedType { pt: controller, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: controller, .. }) => { for controller in controller.type_choices.iter() { match &controller.type1.operator { Some(Operator { @@ -730,7 +730,7 @@ pub fn plus_operation<'a>( } _ => return Err("invalid controller used for .plus operation".to_string()), }, - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { // Only grab the first type choice value from the target per // https://github.com/cbor-wg/cddl-control/issues/2#issuecomment-729253368 if let Some(value) = numeric_values_from_ident(cddl, ident).first() { @@ -739,7 +739,7 @@ pub fn plus_operation<'a>( return Err("invalid controller used for .plus operation".to_string()); } } - Type2::ParenthesizedType { pt: target, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt: target, .. }) => { // Only grab the first type choice value from the target per // https://github.com/cbor-wg/cddl-control/issues/2#issuecomment-729253368 if let Some(tc) = target.type_choices.first() { @@ -859,11 +859,10 @@ mod tests { )), false, )?, - vec![Type2::TextValue { + vec![Type2::TextValue(TextValue { value: "foo\n bar\n baz\n".into(), - #[cfg(feature = "ast-span")] - span: Span::default(), - }], + ..Default::default() + })], ); Ok(()) @@ -889,19 +888,16 @@ mod tests { cat_operation( &cddl, &Type2::from("foo".to_string()), - &Type2::Typename { + &Type2::Typename(Typename { ident: "b".into(), - generic_args: None, - #[cfg(feature = "ast-span")] - span: Span::default(), - }, + ..Default::default() + }), true, )?, - vec![Type2::TextValue { + vec![Type2::TextValue(TextValue { value: "foo\nbar\nbaz\n".into(), - #[cfg(feature = "ast-span")] - span: Span::default(), - }] + ..Default::default() + })] ); Ok(()) diff --git a/src/validator/json.rs b/src/validator/json.rs index c4c88700..16ee2afb 100644 --- a/src/validator/json.rs +++ b/src/validator/json.rs @@ -911,8 +911,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } match lower { - Type2::IntValue { value: l, .. } => match upper { - Type2::IntValue { value: u, .. } => { + Type2::IntValue(IntValue { value: l, .. }) => match upper { + Type2::IntValue(IntValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected integer to be in range {} <= value <= {}, got {}", @@ -951,7 +951,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } } } - Type2::UintValue { value: u, .. } => { + Type2::UintValue(UintValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected integer to be in range {} <= value <= {}, got {}", @@ -998,8 +998,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { return Ok(()); } }, - Type2::UintValue { value: l, .. } => match upper { - Type2::UintValue { value: u, .. } => { + Type2::UintValue(UintValue { value: l, .. }) => match upper { + Type2::UintValue(UintValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected uint to be in range {} <= value <= {}, got {}", @@ -1072,8 +1072,8 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { return Ok(()); } }, - Type2::FloatValue { value: l, .. } => match upper { - Type2::FloatValue { value: u, .. } => { + Type2::FloatValue(FloatValue { value: l, .. }) => match upper { + Type2::FloatValue(FloatValue { value: u, .. }) => { let error_str = if is_inclusive { format!( "expected float to be in range {} <= value <= {}, got {}", @@ -1139,15 +1139,15 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { ctrl: &Token<'a>, controller: &Type2<'a>, ) -> visitor::Result { - if let Type2::Typename { + if let Type2::Typename(Typename { ident: target_ident, .. - } = target + }) = target { - if let Type2::Typename { + if let Type2::Typename(Typename { ident: controller_ident, .. - } = controller + }) = controller { if let Some(name) = self.eval_generic_rule { if let Some(gr) = self @@ -1194,14 +1194,14 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { match ctrl { Token::EQ => match target { - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) { return self.visit_type2(controller); } } - Type2::Array { group, .. } => { + Type2::Array(Array { group, .. }) => { if let Value::Array(_) = &self.json { let mut entry_counts = Vec::new(); for gc in group.group_choices.iter() { @@ -1214,7 +1214,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { return Ok(()); } } - Type2::Map { .. } => { + Type2::Map(Map { .. }) => { if let Value::Object(_) = &self.json { self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; @@ -1230,7 +1230,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { )), }, Token::NE => match target { - Type2::Typename { ident, .. } => { + Type2::Typename(Typename { ident, .. }) => { if is_ident_string_data_type(self.cddl, ident) || is_ident_numeric_data_type(self.cddl, ident) { @@ -1240,7 +1240,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { return Ok(()); } } - Type2::Array { .. } => { + Type2::Array(Array { .. }) => { if let Value::Array(_) = &self.json { self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; @@ -1248,7 +1248,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { return Ok(()); } } - Type2::Map { .. } => { + Type2::Map(Map { .. }) => { if let Value::Object(_) = &self.json { self.ctrl = Some(ctrl.clone()); self.is_ctrl_map_equality = true; @@ -1264,7 +1264,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { )), }, Token::LT | Token::GT | Token::GE | Token::LE => match target { - Type2::Typename { ident, .. } if is_ident_numeric_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) if is_ident_numeric_data_type(self.cddl, ident) => { self.ctrl = Some(ctrl.clone()); self.visit_type2(controller)?; self.ctrl = None; @@ -1277,7 +1277,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { } }, Token::SIZE => match target { - Type2::Typename { ident, .. } + Type2::Typename(Typename { ident, .. }) if is_ident_string_data_type(self.cddl, ident) || is_ident_uint_data_type(self.cddl, ident) => { @@ -1342,7 +1342,9 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { Token::REGEXP | Token::PCRE => { self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) + if is_ident_string_data_type(self.cddl, ident) => + { match self.json { Value::String(_) | Value::Array(_) => self.visit_type2(controller)?, _ => self.add_error(format!( @@ -1443,10 +1445,12 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.ctrl = Some(ctrl.clone()); match target { - Type2::Typename { ident, .. } if is_ident_string_data_type(self.cddl, ident) => { + Type2::Typename(Typename { ident, .. }) + if is_ident_string_data_type(self.cddl, ident) => + { match self.json { Value::String(_) | Value::Array(_) => { - if let Type2::ParenthesizedType { pt, .. } = controller { + if let Type2::ParenthesizedType(ParenthesizedType { pt, .. }) = controller { match abnf_from_complex_controller(self.cddl, pt) { Ok(values) => { let error_count = self.errors.len(); @@ -1491,7 +1495,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { if let Some(ef) = self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); - if let Some(Type2::TextValue { value, .. }) = tv { + if let Some(Type2::TextValue(TextValue { value, .. })) = tv { if ef.contains(&&**value) { let err_count = self.errors.len(); self.visit_type2(target)?; @@ -1505,7 +1509,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { .get_or_insert(vec![value.to_string()]) .push(value.to_string()); } - } else if let Some(Type2::UTF8ByteString { value, .. }) = tv { + } else if let Some(Type2::UTF8ByteString(Utf8ByteString { value, .. })) = tv { let value = std::str::from_utf8(value).map_err(Error::UTF8Parsing)?; if ef.contains(&value) { let err_count = self.errors.len(); @@ -1532,7 +1536,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { if let Some(ef) = &self.enabled_features { let tv = text_value_from_type2(self.cddl, controller); - if let Some(Type2::TextValue { value, .. }) = tv { + if let Some(Type2::TextValue(TextValue { value, .. })) = tv { if ef.contains(&JsValue::from(value.as_ref())) { let err_count = self.errors.len(); self.visit_type2(target)?; @@ -1546,7 +1550,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { .get_or_insert(vec![value.to_string()]) .push(value.to_string()); } - } else if let Some(Type2::UTF8ByteString { value, .. }) = tv { + } else if let Some(Type2::UTF8ByteString(Utf8ByteString { value, .. })) = tv { let value = std::str::from_utf8(value).map_err(Error::UTF8Parsing)?; if ef.contains(&JsValue::from(value)) { let err_count = self.errors.len(); @@ -1576,8 +1580,10 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { fn visit_type2(&mut self, t2: &Type2<'a>) -> visitor::Result { match t2 { - Type2::TextValue { value, .. } => self.visit_value(&token::Value::TEXT(value.clone())), - Type2::Map { group, .. } => match &self.json { + Type2::TextValue(TextValue { value, .. }) => { + self.visit_value(&token::Value::TEXT(value.clone())) + } + Type2::Map(Map { group, .. }) => match &self.json { Value::Object(o) => { #[allow(clippy::needless_collect)] let o = o.keys().cloned().collect::>(); @@ -1697,7 +1703,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { Ok(()) } }, - Type2::Array { group, .. } => match &self.json { + Type2::Array(Array { group, .. }) => match &self.json { Value::Array(a) => { if group.group_choices.len() == 1 && group.group_choices[0].group_entries.is_empty() @@ -1740,11 +1746,11 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { Ok(()) } }, - Type2::ChoiceFromGroup { + Type2::ChoiceFromGroup(ChoiceFromGroup { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { if let Some(rule) = rule_from_ident(self.cddl, ident) { if let Some(gr) = self @@ -1797,17 +1803,17 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { Ok(()) } - Type2::ChoiceFromInlineGroup { group, .. } => { + Type2::ChoiceFromInlineGroup(ChoiceFromInlineGroup { group, .. }) => { self.is_group_to_choice_enum = true; self.visit_group(group)?; self.is_group_to_choice_enum = false; Ok(()) } - Type2::Typename { + Type2::Typename(Typename { ident, generic_args, .. - } => { + }) => { if let Some(ga) = generic_args { if let Some(rule) = rule_from_ident(self.cddl, ident) { if let Some(gr) = self @@ -1847,19 +1853,21 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { self.visit_identifier(ident) } - Type2::IntValue { value, .. } => self.visit_value(&token::Value::INT(*value)), - Type2::UintValue { value, .. } => self.visit_value(&token::Value::UINT(*value)), - Type2::FloatValue { value, .. } => self.visit_value(&token::Value::FLOAT(*value)), - Type2::ParenthesizedType { pt, .. } => self.visit_type(pt), - Type2::Unwrap { + Type2::IntValue(IntValue { value, .. }) => self.visit_value(&token::Value::INT(*value)), + Type2::UintValue(UintValue { value, .. }) => self.visit_value(&token::Value::UINT(*value)), + Type2::FloatValue(FloatValue { value, .. }) => self.visit_value(&token::Value::FLOAT(*value)), + Type2::ParenthesizedType(ParenthesizedType { pt, .. }) => self.visit_type(pt), + Type2::Unwrap(Unwrap { ident, generic_args, .. - } => { + }) => { // Per // https://github.com/w3c/did-spec-registries/pull/138#issuecomment-719739215, // strip tag and validate underlying type - if let Some(Type2::TaggedData { t, .. }) = tag_from_token(&lookup_ident(ident.ident)) { + if let Some(Type2::TaggedData(TaggedData { t, .. })) = + tag_from_token(&lookup_ident(ident.ident)) + { return self.visit_type(&t); } @@ -2343,7 +2351,7 @@ impl<'a> Visitor<'a, Error> for JSONValidator<'a> { fn visit_memberkey(&mut self, mk: &MemberKey<'a>) -> visitor::Result { match mk { - MemberKey::Type1 { is_cut, .. } => { + MemberKey::Type1(Type1MemberKey { is_cut, .. }) => { self.is_cut_present = *is_cut; walk_memberkey(self, mk)?; self.is_cut_present = false; diff --git a/src/visitor.rs b/src/visitor.rs index be075c3a..c4f344a2 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -138,7 +138,7 @@ pub trait Visitor<'a, E: Error> { } /// Visit nonmemberkey - fn visit_nonmemberkey(&mut self, nmk: &ParenthesizedType<'a>) -> Result { + fn visit_nonmemberkey(&mut self, nmk: &ParenthesizedTypeOrGroup<'a>) -> Result { walk_nonmemberkey(self, nmk) } } @@ -259,47 +259,47 @@ where V: Visitor<'a, E> + ?Sized, { match t2 { - Type2::Array { group, .. } => visitor.visit_group(group), - Type2::Map { group, .. } => visitor.visit_group(group), - Type2::ChoiceFromGroup { + Type2::Array(Array { group, .. }) => visitor.visit_group(group), + Type2::Map(Map { group, .. }) => visitor.visit_group(group), + Type2::ChoiceFromGroup(ChoiceFromGroup { generic_args, ident, .. - } => { + }) => { if let Some(ga) = generic_args { visitor.visit_genericargs(ga)?; } visitor.visit_identifier(ident) } - Type2::ChoiceFromInlineGroup { group, .. } => visitor.visit_group(group), - Type2::TaggedData { t, .. } => visitor.visit_type(t), - Type2::Typename { ident, .. } => visitor.visit_identifier(ident), - Type2::Unwrap { + Type2::ChoiceFromInlineGroup(ChoiceFromInlineGroup { group, .. }) => visitor.visit_group(group), + Type2::TaggedData(TaggedData { t, .. }) => visitor.visit_type(t), + Type2::Typename(Typename { ident, .. }) => visitor.visit_identifier(ident), + Type2::Unwrap(Unwrap { generic_args, ident, .. - } => { + }) => { if let Some(ga) = generic_args { visitor.visit_genericargs(ga)?; } visitor.visit_identifier(ident) } - Type2::ParenthesizedType { pt, .. } => visitor.visit_type(pt), - Type2::B16ByteString { value, .. } => { + Type2::ParenthesizedType(ParenthesizedType { pt, .. }) => visitor.visit_type(pt), + Type2::B16ByteString(B16ByteString { value, .. }) => { visitor.visit_value(&Value::BYTE(ByteValue::B16(value.clone()))) } - Type2::B64ByteString { value, .. } => { + Type2::B64ByteString(B64ByteString { value, .. }) => { visitor.visit_value(&Value::BYTE(ByteValue::B64(value.clone()))) } - Type2::UTF8ByteString { value, .. } => { + Type2::UTF8ByteString(Utf8ByteString { value, .. }) => { visitor.visit_value(&Value::BYTE(ByteValue::UTF8(value.clone()))) } - Type2::FloatValue { value, .. } => visitor.visit_value(&Value::FLOAT(*value)), - Type2::IntValue { value, .. } => visitor.visit_value(&Value::INT(*value)), - Type2::UintValue { value, .. } => visitor.visit_value(&Value::UINT(*value)), - Type2::TextValue { value, .. } => visitor.visit_value(&Value::TEXT(value.clone())), + Type2::FloatValue(FloatValue { value, .. }) => visitor.visit_value(&Value::FLOAT(*value)), + Type2::IntValue(IntValue { value, .. }) => visitor.visit_value(&Value::INT(*value)), + Type2::UintValue(UintValue { value, .. }) => visitor.visit_value(&Value::UINT(*value)), + Type2::TextValue(TextValue { value, .. }) => visitor.visit_value(&Value::TEXT(value.clone())), _ => Ok(()), } } @@ -409,10 +409,10 @@ where V: Visitor<'a, E> + ?Sized, { match mk { - MemberKey::Type1 { t1, .. } => visitor.visit_type1(t1), - MemberKey::Bareword { ident, .. } => visitor.visit_identifier(ident), - MemberKey::Value { value, .. } => visitor.visit_value(value), - MemberKey::ParenthesizedType { non_member_key, .. } => { + MemberKey::Type1(Type1MemberKey { t1, .. }) => visitor.visit_type1(t1), + MemberKey::Bareword(BarewordMemberKey { ident, .. }) => visitor.visit_identifier(ident), + MemberKey::Value(ValueMemberKey { value, .. }) => visitor.visit_value(value), + MemberKey::Parenthesized(ParenthesizedMemberKey { non_member_key, .. }) => { visitor.visit_nonmemberkey(non_member_key) } } @@ -441,13 +441,13 @@ where } /// Walk nonmemberkey -pub fn walk_nonmemberkey<'a, E, V>(visitor: &mut V, nmk: &ParenthesizedType<'a>) -> Result +pub fn walk_nonmemberkey<'a, E, V>(visitor: &mut V, nmk: &ParenthesizedTypeOrGroup<'a>) -> Result where E: Error, V: Visitor<'a, E> + ?Sized, { match nmk { - ParenthesizedType::Group(group) => visitor.visit_group(group), - ParenthesizedType::Type(t) => visitor.visit_type(t), + ParenthesizedTypeOrGroup::Group(group) => visitor.visit_group(group), + ParenthesizedTypeOrGroup::Type(t) => visitor.visit_type(&t.pt), } } diff --git a/tests/parser.rs b/tests/parser.rs index 4bb852a6..5da421f3 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -47,7 +47,7 @@ fn verify_cddl() -> Result<()> { value: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "secondrule".into(), socket: None, @@ -55,19 +55,16 @@ fn verify_cddl() -> Result<()> { }, generic_args: None, span: Span(9, 19, 1), - }, - operator: None, - comments_after_type: None, + }), span: Span(9, 19, 1), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(9, 19, 1), }, - comments_before_assignt: None, - comments_after_assignt: None, + ..Default::default() }, comments_after_rule: None, span: Span(0, 19, 1), @@ -79,21 +76,19 @@ fn verify_cddl() -> Result<()> { socket: None, span: Span(20, 27, 2), }, - generic_params: None, - is_type_choice_alternate: false, value: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::UintValue { + type2: Type2::UintValue(UintValue { value: 10, span: Span(30, 32, 2), - }, + }), operator: Some(Operator { operator: RangeCtlOp::RangeOp { is_inclusive: true, span: Span(32, 34, 2), }, - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "upper".into(), socket: None, @@ -101,7 +96,7 @@ fn verify_cddl() -> Result<()> { }, generic_args: None, span: Span(34, 39, 2), - }, + }), comments_before_operator: None, comments_after_operator: None, }), @@ -113,8 +108,7 @@ fn verify_cddl() -> Result<()> { }], span: Span(30, 39, 2), }, - comments_before_assignt: None, - comments_after_assignt: None, + ..Default::default() }, comments_after_rule: None, span: Span(20, 39, 2), @@ -132,35 +126,30 @@ fn verify_cddl() -> Result<()> { type_choices: vec![ TypeChoice { type1: Type1 { - type2: Type2::UintValue { + type2: Type2::UintValue(UintValue { value: 500, span: Span(48, 51, 3), - }, - operator: None, - comments_after_type: None, + }), span: Span(48, 51, 3), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, TypeChoice { type1: Type1 { - type2: Type2::UintValue { + type2: Type2::UintValue(UintValue { value: 600, span: Span(54, 57, 3), - }, - operator: None, - comments_after_type: None, + }), span: Span(54, 57, 3), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(48, 57, 3), }, - comments_before_assignt: None, - comments_after_assignt: None, + ..Default::default() }, comments_after_rule: None, span: Span(40, 57, 3), @@ -234,7 +223,7 @@ fn verify_cddl() -> Result<()> { value: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "message".into(), socket: None, @@ -244,50 +233,42 @@ fn verify_cddl() -> Result<()> { args: vec![ GenericArg { arg: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "reboot".into(), span: Span(94, 102, 5), - }, - operator: None, - comments_after_type: None, + }), span: Span(94, 102, 5), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, GenericArg { arg: Box::from(Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "now".into(), span: Span(104, 109, 5), - }, - operator: None, - comments_after_type: None, + }), span: Span(104, 109, 5), + ..Default::default() }), - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], - span: Span(93, 110, 5), }), span: Span(86, 110, 5), - }, - operator: None, - comments_after_type: None, + }), span: Span(86, 110, 5), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(86, 110, 5), }, - comments_before_assignt: None, - comments_after_assignt: None, + ..Default::default() }, - comments_after_rule: None, span: Span(75, 110, 5), + comments_after_rule: None, }, Rule::Type { rule: TypeRule { @@ -304,8 +285,7 @@ fn verify_cddl() -> Result<()> { socket: None, span: Span(119, 120, 6), }, - comments_before_ident: None, - comments_after_ident: None, + ..Default::default() }, GenericParam { param: Identifier { @@ -313,8 +293,7 @@ fn verify_cddl() -> Result<()> { socket: None, span: Span(122, 123, 6), }, - comments_before_ident: None, - comments_after_ident: None, + ..Default::default() }, ], span: Span(118, 124, 6), @@ -323,7 +302,7 @@ fn verify_cddl() -> Result<()> { value: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Map { + type2: Type2::Map(Map { group: Group { group_choices: vec![GroupChoice { group_entries: vec![ @@ -331,29 +310,26 @@ fn verify_cddl() -> Result<()> { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "type".into(), socket: None, span: Span(128, 132, 6), }, - comments: None, - comments_after_colon: None, span: Span(128, 133, 6), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::UintValue { + type2: Type2::UintValue(UintValue { value: 2, span: Span(134, 135, 6), - }, - operator: None, - comments_after_type: None, + }), span: Span(134, 135, 6), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(134, 135, 6), }, @@ -372,20 +348,19 @@ fn verify_cddl() -> Result<()> { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "value".into(), socket: None, span: Span(137, 142, 6), }, - comments: None, - comments_after_colon: None, span: Span(137, 143, 6), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "v".into(), socket: None, @@ -393,13 +368,11 @@ fn verify_cddl() -> Result<()> { }, generic_args: None, span: Span(144, 145, 6), - }, - operator: None, - comments_after_type: None, + }), span: Span(144, 145, 6), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(144, 145, 6), }, @@ -420,21 +393,17 @@ fn verify_cddl() -> Result<()> { }], span: Span(128, 145, 6), }, - comments_before_group: None, - comments_after_group: None, span: Span(127, 146, 6), - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(127, 146, 6), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(127, 146, 6), }, - comments_before_assignt: None, - comments_after_assignt: None, + ..Default::default() }, comments_after_rule: None, span: Span(111, 146, 6), @@ -451,27 +420,23 @@ fn verify_cddl() -> Result<()> { value: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::ChoiceFromGroup { + type2: Type2::ChoiceFromGroup(ChoiceFromGroup { ident: Identifier { ident: "colors".into(), socket: None, span: Span(156, 162, 7), }, - generic_args: None, - comments: None, span: Span(155, 162, 7), - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(155, 162, 7), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(155, 162, 7), }, - comments_before_assignt: None, - comments_after_assignt: None, + ..Default::default() }, comments_after_rule: None, span: Span(147, 162, 7), @@ -493,29 +458,26 @@ fn verify_cddl() -> Result<()> { GroupEntry::ValueMemberKey { ge: Box::from(ValueMemberKeyEntry { occur: None, - member_key: Some(MemberKey::Bareword { + member_key: Some(MemberKey::Bareword(BarewordMemberKey { ident: Identifier { ident: "red".into(), socket: None, span: Span(174, 177, 8), }, - comments: None, - comments_after_colon: None, span: Span(174, 178, 8), - }), + ..Default::default() + })), entry_type: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::TextValue { + type2: Type2::TextValue(TextValue { value: "red".into(), span: Span(179, 184, 8), - }, - operator: None, - comments_after_type: None, + }), span: Span(179, 184, 8), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(179, 184, 8), }, @@ -557,12 +519,12 @@ fn verify_cddl() -> Result<()> { value: Type { type_choices: vec![TypeChoice { type1: Type1 { - type2: Type2::ParenthesizedType { + type2: Type2::ParenthesizedType(ParenthesizedType { pt: Type { type_choices: vec![ TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "int".into(), socket: None, @@ -570,17 +532,15 @@ fn verify_cddl() -> Result<()> { }, generic_args: None, span: Span(196, 199, 9), - }, - operator: None, - comments_after_type: None, + }), span: Span(196, 199, 9), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, TypeChoice { type1: Type1 { - type2: Type2::Typename { + type2: Type2::Typename(Typename { ident: Identifier { ident: "float".into(), socket: None, @@ -588,27 +548,22 @@ fn verify_cddl() -> Result<()> { }, generic_args: None, span: Span(202, 207, 9), - }, - operator: None, - comments_after_type: None, + }), span: Span(202, 207, 9), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }, ], span: Span(196, 207, 9), }, - comments_before_type: None, - comments_after_type: None, span: Span(194, 209, 9), - }, - operator: None, - comments_after_type: None, + ..Default::default() + }), span: Span(194, 210, 9), + ..Default::default() }, - comments_before_type: None, - comments_after_type: None, + ..Default::default() }], span: Span(194, 210, 9), From adaf9056e5400238758c97f45df5d56f9d4101e9 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 11 Oct 2021 16:17:26 -0400 Subject: [PATCH 20/24] fix missing definition checks --- src/parser.rs | 111 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 0189bf8b..00d2df8a 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -390,7 +390,7 @@ where range: (span.0, span.1), }, msg: ErrorMsg { - short: format!("missing definition for rule {}", rule), + short: format!("missing definition for \"{}\"", rule), extended: None, }, }) @@ -402,7 +402,7 @@ where if !c.rules.iter().any(|r| r.name() == *rule) { self.errors.push(Error::PARSER { msg: ErrorMsg { - short: format!("missing definition for rule {}", rule), + short: format!("missing definition for \"{}\"", rule), extended: None, }, }) @@ -1293,6 +1293,13 @@ where #[cfg(feature = "ast-span")] let end_type2_range = self.parser_position.range.1; + if !self + .visited_rule_idents + .contains(&(ident.ident, ident.span)) + { + self.visited_rule_idents.push((ident.ident, ident.span)); + } + return Ok(Type2::Typename(Typename { ident, generic_args: Some(ga), @@ -1307,15 +1314,21 @@ where self.parser_position.line = self.lexer_position.line; } + let span = Span( + self.parser_position.range.0, + self.parser_position.range.1, + self.parser_position.line, + ); + + if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| r.0 == ident.0) { + self.visited_rule_idents.push((ident.0, span)); + } + Ok(Type2::Typename(Typename { ident: self.identifier_from_ident_token(*ident), generic_args: None, #[cfg(feature = "ast-span")] - span: Span( - self.parser_position.range.0, - self.parser_position.range.1, - self.parser_position.line, - ), + span, })) } @@ -2045,10 +2058,12 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == name.ident) { + if !params.iter().any(|&p| p == name.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) + { self.visited_rule_idents.push((name.ident, name.span)); } - } else { + } else if !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) { self.visited_rule_idents.push((name.ident, name.span)); } } @@ -2075,11 +2090,13 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == name.ident) { - self.visited_rule_idents.push(name.ident); + if !params.iter().any(|&p| p == name.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) + { + self.visited_rule_idents.push((name.ident, name.span)); } - } else { - self.visited_rule_idents.push(name.ident); + } else if !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) { + self.visited_rule_idents.push((name.ident, name.span)); } } @@ -2111,10 +2128,12 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == ident.ident) { + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + { self.visited_rule_idents.push((ident.ident, ident.span)); } - } else { + } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { self.visited_rule_idents.push((ident.ident, ident.span)); } } @@ -2128,11 +2147,13 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == ident.ident) { - self.visited_rule_idents.push(ident.ident); + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + { + self.visited_rule_idents.push((ident.ident, ident.span)); } - } else { - self.visited_rule_idents.push(ident.ident); + } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { + self.visited_rule_idents.push((ident.ident, ident.span)); } } } @@ -2201,10 +2222,12 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == ident.ident) { + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + { self.visited_rule_idents.push((ident.ident, ident.span)); } - } else { + } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { self.visited_rule_idents.push((ident.ident, ident.span)); } } @@ -2218,11 +2241,13 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == ident.ident) { - self.visited_rule_idents.push(ident.ident); + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + { + self.visited_rule_idents.push((ident.ident, ident.span)); } - } else { - self.visited_rule_idents.push(ident.ident); + } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { + self.visited_rule_idents.push((ident.ident, ident.span)); } } } @@ -2282,10 +2307,12 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == name.ident) { + if !params.iter().any(|&p| p == name.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) + { self.visited_rule_idents.push((name.ident, name.span)); } - } else { + } else if !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) { self.visited_rule_idents.push((name.ident, name.span)); } } @@ -2320,11 +2347,13 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == name.ident) { - self.visited_rule_idents.push(name.ident); + if !params.iter().any(|&p| p == name.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) + { + self.visited_rule_idents.push((name.ident, name.span)); } - } else { - self.visited_rule_idents.push(name.ident); + } else if !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) { + self.visited_rule_idents.push((name.ident, name.span)); } } @@ -2349,10 +2378,12 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == ident.ident) { + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + { self.visited_rule_idents.push((ident.ident, ident.span)); } - } else { + } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { self.visited_rule_idents.push((ident.ident, ident.span)); } } @@ -2366,11 +2397,13 @@ where .is_none() { if let Some(params) = &self.current_rule_generic_param_idents { - if !params.iter().any(|&p| p == ident.ident) { - self.visited_rule_idents.push(ident.ident); + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + { + self.visited_rule_idents.push((ident.ident, ident.span)); } - } else { - self.visited_rule_idents.push(ident.ident); + } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { + self.visited_rule_idents.push((ident.ident, ident.span)); } } } @@ -2815,6 +2848,8 @@ where Err(e) => return Err(e), }; + self.visited_rule_idents.append(&mut p.visited_rule_idents); + return Ok(Some(MemberKey::Parenthesized(ParenthesizedMemberKey { non_member_key: ParenthesizedTypeOrGroup::Group(group), #[cfg(feature = "ast-comments")] @@ -2838,6 +2873,8 @@ where Err(e) => return Err(e), }; + self.visited_rule_idents.append(&mut p.visited_rule_idents); + #[cfg(feature = "ast-comments")] let comments_before_cut = self.collect_comments()?; #[cfg(not(feature = "ast-comments"))] From ae73ba94ce47a44e658e27dc3d2429edfa0b80f4 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Mon, 11 Oct 2021 16:36:06 -0400 Subject: [PATCH 21/24] fix build errors --- src/parser.rs | 53 ++++++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 00d2df8a..c5a9e4c5 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1293,6 +1293,7 @@ where #[cfg(feature = "ast-span")] let end_type2_range = self.parser_position.range.1; + #[cfg(feature = "ast-span")] if !self .visited_rule_idents .contains(&(ident.ident, ident.span)) @@ -1300,6 +1301,11 @@ where self.visited_rule_idents.push((ident.ident, ident.span)); } + #[cfg(not(feature = "ast-span"))] + if !self.visited_rule_idents.contains(&ident.ident) { + self.visited_rule_idents.push(ident.ident); + } + return Ok(Type2::Typename(Typename { ident, generic_args: Some(ga), @@ -1314,16 +1320,23 @@ where self.parser_position.line = self.lexer_position.line; } + #[cfg(feature = "ast-span")] let span = Span( self.parser_position.range.0, self.parser_position.range.1, self.parser_position.line, ); + #[cfg(feature = "ast-span")] if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| r.0 == ident.0) { self.visited_rule_idents.push((ident.0, span)); } + #[cfg(not(feature = "ast-span"))] + if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| *r == ident.0) { + self.visited_rule_idents.push(ident.0); + } + Ok(Type2::Typename(Typename { ident: self.identifier_from_ident_token(*ident), generic_args: None, @@ -2091,12 +2104,12 @@ where { if let Some(params) = &self.current_rule_generic_param_idents { if !params.iter().any(|&p| p == name.ident) - && !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) + && !self.visited_rule_idents.iter().any(|r| *r == name.ident) { - self.visited_rule_idents.push((name.ident, name.span)); + self.visited_rule_idents.push(name.ident); } - } else if !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) { - self.visited_rule_idents.push((name.ident, name.span)); + } else if !self.visited_rule_idents.iter().any(|r| *r == name.ident) { + self.visited_rule_idents.push(name.ident); } } @@ -2148,12 +2161,12 @@ where { if let Some(params) = &self.current_rule_generic_param_idents { if !params.iter().any(|&p| p == ident.ident) - && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + && !self.visited_rule_idents.iter().any(|r| *r == ident.ident) { - self.visited_rule_idents.push((ident.ident, ident.span)); + self.visited_rule_idents.push(ident.ident); } - } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { - self.visited_rule_idents.push((ident.ident, ident.span)); + } else if !self.visited_rule_idents.iter().any(|r| *r == ident.ident) { + self.visited_rule_idents.push(ident.ident); } } } @@ -2242,12 +2255,12 @@ where { if let Some(params) = &self.current_rule_generic_param_idents { if !params.iter().any(|&p| p == ident.ident) - && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + && !self.visited_rule_idents.iter().any(|r| *r == ident.ident) { - self.visited_rule_idents.push((ident.ident, ident.span)); + self.visited_rule_idents.push(ident.ident); } - } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { - self.visited_rule_idents.push((ident.ident, ident.span)); + } else if !self.visited_rule_idents.iter().any(|r| *r == ident.ident) { + self.visited_rule_idents.push(ident.ident); } } } @@ -2348,12 +2361,12 @@ where { if let Some(params) = &self.current_rule_generic_param_idents { if !params.iter().any(|&p| p == name.ident) - && !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) + && !self.visited_rule_idents.iter().any(|r| *r == name.ident) { - self.visited_rule_idents.push((name.ident, name.span)); + self.visited_rule_idents.push(name.ident); } - } else if !self.visited_rule_idents.iter().any(|r| r.0 == name.ident) { - self.visited_rule_idents.push((name.ident, name.span)); + } else if !self.visited_rule_idents.iter().any(|r| *r == name.ident) { + self.visited_rule_idents.push(name.ident); } } @@ -2398,12 +2411,12 @@ where { if let Some(params) = &self.current_rule_generic_param_idents { if !params.iter().any(|&p| p == ident.ident) - && !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) + && !self.visited_rule_idents.iter().any(|r| *r == ident.ident) { - self.visited_rule_idents.push((ident.ident, ident.span)); + self.visited_rule_idents.push(ident.ident); } - } else if !self.visited_rule_idents.iter().any(|r| r.0 == ident.ident) { - self.visited_rule_idents.push((ident.ident, ident.span)); + } else if !self.visited_rule_idents.iter().any(|r| *r == ident.ident) { + self.visited_rule_idents.push(ident.ident); } } } From 1470e5b2b77e1925b3ab3bc226bdd4cabc071409 Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:25:16 -0400 Subject: [PATCH 22/24] allow missing rule definitions flag --- src/bin/cli.rs | 83 ++++++++++++++++++------ src/faker.rs | 2 +- src/lib.rs | 6 +- src/parser.rs | 135 ++++++++++++++++++++++++++------------- src/parser_tests.rs | 45 +++++++------ src/repl.rs | 2 +- src/validator/cbor.rs | 4 +- src/validator/control.rs | 4 +- src/validator/json.rs | 4 +- src/validator/mod.rs | 38 ++++++++--- tests/cddl.rs | 8 ++- tests/did.rs | 8 +-- tests/parser.rs | 4 +- 13 files changed, 236 insertions(+), 107 deletions(-) diff --git a/src/bin/cli.rs b/src/bin/cli.rs index 24fa02de..90fe595d 100644 --- a/src/bin/cli.rs +++ b/src/bin/cli.rs @@ -98,6 +98,14 @@ fn main() -> Result<(), Box> { .author(crate_authors!()) .about("Tool for verifying conformance of CDDL definitions against RFC 8610 and for validating JSON documents and CBOR binary files") .setting(AppSettings::SubcommandRequiredElseHelp) + .arg( + Arg::with_name("allow-missing-definitions") + .long("allow-missing-definitions") + .required(false) + .takes_value(false) + .global(true) + .help("Allow references to missing rule definitions") + ) .subcommand(SubCommand::with_name("compile-cddl") .about("Compile CDDL against RFC 8610") .arg_from_usage("-c --cddl= 'CDDL input file'")) @@ -108,8 +116,8 @@ fn main() -> Result<(), Box> { let matches = app.get_matches(); - if let Some(matches) = matches.subcommand_matches("compile-cddl") { - if let Some(c) = matches.value_of("cddl") { + if let Some(sub_matches) = matches.subcommand_matches("compile-cddl") { + if let Some(c) = sub_matches.value_of("cddl") { let p = Path::new(c); if !p.exists() { error!("CDDL document {:?} does not exist", p); @@ -126,14 +134,20 @@ fn main() -> Result<(), Box> { } let file_content = fs::read_to_string(c)?; - cddl_from_str(&mut lexer_from_str(&file_content), &file_content, true).map(|_| ())?; + cddl_from_str( + &mut lexer_from_str(&file_content), + &file_content, + true, + matches.is_present("allow-missing-definitions"), + ) + .map(|_| ())?; info!("{} is conformant", c); } } - if let Some(matches) = matches.subcommand_matches("compile-json") { - if let Some(j) = matches.value_of("json") { + if let Some(sub_matches) = matches.subcommand_matches("compile-json") { + if let Some(j) = sub_matches.value_of("json") { let p = Path::new(j); if !p.exists() { error!("CDDL document {:?} does not exist", p); @@ -157,10 +171,11 @@ fn main() -> Result<(), Box> { } } - if let Some(matches) = matches.subcommand_matches("validate") { - if let Some(cddl) = matches.value_of("cddl") { + if let Some(sub_matches) = matches.subcommand_matches("validate") { + if let Some(cddl) = sub_matches.value_of("cddl") { #[cfg(feature = "additional-controls")] - let enabled_features: Option> = matches.values_of("features").map(|f| f.collect()); + let enabled_features: Option> = + sub_matches.values_of("features").map(|f| f.collect()); #[cfg(feature = "additional-controls")] if let Some(enabled_features) = &enabled_features { let mut feature_str = String::from("enabled features: ["); @@ -193,7 +208,7 @@ fn main() -> Result<(), Box> { let cddl_str = fs::read_to_string(cddl)?; - if let Some(files) = matches.values_of("json") { + if let Some(files) = sub_matches.values_of("json") { for file in files { let p = Path::new(file); if !p.exists() { @@ -206,10 +221,15 @@ fn main() -> Result<(), Box> { let r = validate_json_from_str( &cddl_str, &fs::read_to_string(file)?, + matches.is_present("allow-missing-definitions"), enabled_features.as_deref(), ); #[cfg(not(feature = "additional-controls"))] - let r = validate_json_from_str(&cddl_str, &fs::read_to_string(file)?); + let r = validate_json_from_str( + &cddl_str, + &fs::read_to_string(file)?, + matches.is_present("allow-missing-definitions"), + ); match r { Ok(()) => { @@ -222,7 +242,7 @@ fn main() -> Result<(), Box> { } } - if let Some(files) = matches.values_of("cbor") { + if let Some(files) = sub_matches.values_of("cbor") { for file in files { let p = Path::new(file); if !p.exists() { @@ -235,9 +255,18 @@ fn main() -> Result<(), Box> { f.read_to_end(&mut data)?; #[cfg(feature = "additional-controls")] - let c = validate_cbor_from_slice(&cddl_str, &data, None); + let c = validate_cbor_from_slice( + &cddl_str, + &data, + matches.is_present("allow-missing-definitions"), + None, + ); #[cfg(not(feature = "additional-controls"))] - let c = validate_cbor_from_slice(&cddl_str, &data); + let c = validate_cbor_from_slice( + &cddl_str, + &data, + matches.is_present("allow-missing-definitions"), + ); match c { Ok(()) => { @@ -252,7 +281,7 @@ fn main() -> Result<(), Box> { return Ok(()); } - if matches.is_present("stdin") { + if sub_matches.is_present("stdin") { let stdin = io::stdin(); let mut reader = stdin.lock(); @@ -260,9 +289,18 @@ fn main() -> Result<(), Box> { reader.read_to_end(&mut data)?; if let Ok(json) = std::str::from_utf8(&data) { #[cfg(feature = "additional-controls")] - let r = validate_json_from_str(&cddl_str, json, None); + let r = validate_json_from_str( + &cddl_str, + json, + matches.is_present("allow-missing-definitions"), + None, + ); #[cfg(not(feature = "additional-controls"))] - let r = validate_json_from_str(&cddl_str, json); + let r = validate_json_from_str( + &cddl_str, + json, + matches.is_present("allow-missing-definitions"), + ); match r { Ok(()) => { @@ -274,9 +312,18 @@ fn main() -> Result<(), Box> { } } else { #[cfg(feature = "additional-controls")] - let c = validate_cbor_from_slice(&cddl_str, &data, enabled_features.as_deref()); + let c = validate_cbor_from_slice( + &cddl_str, + &data, + matches.is_present("allow-missing-definitions"), + enabled_features.as_deref(), + ); #[cfg(not(feature = "additional-controls"))] - let c = validate_cbor_from_slice(&cddl_str, &data); + let c = validate_cbor_from_slice( + &cddl_str, + &data, + matches.is_present("allow-missing-definitions"), + ); match c { Ok(()) => { diff --git a/src/faker.rs b/src/faker.rs index 95b706d8..a64702eb 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -742,7 +742,7 @@ impl<'a> Visitor<'a, Error> for Faker<'a> { /// Generate fake JSON from a given CDDL document string pub fn fake_json_from_cddl_str(cddl_str: &str) -> Result { let mut lexer = lexer_from_str(cddl_str); - let cddl = cddl_from_str(&mut lexer, cddl_str, true).map_err(Error::CDDLParsing)?; + let cddl = cddl_from_str(&mut lexer, cddl_str, true, false).map_err(Error::CDDLParsing)?; let mut faker = Faker::new(&cddl); for rule in faker.cddl.rules.iter() { diff --git a/src/lib.rs b/src/lib.rs index a53e0a5e..3a3c7065 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -227,7 +227,7 @@ //! use cddl::{lexer_from_str, parser::cddl_from_str}; //! //! let input = r#"myrule = int"#; -//! assert!(cddl_from_str(&mut lexer_from_str(input), input, true).is_ok()) +//! assert!(cddl_from_str(&mut lexer_from_str(input), input, true, false).is_ok()) //! ``` //! //! ### Validating JSON @@ -407,7 +407,7 @@ //! let json = r#""v""#; //! //! #[cfg(feature = "additional-controls")] -//! assert!(validate_json_from_str(cddl, json, Some(&["json"])).is_ok()) +//! assert!(validate_json_from_str(cddl, json, false, Some(&["json"])).is_ok()) //! ``` //! //! #### Comparing with JSON schema and JSON schema language @@ -493,7 +493,7 @@ //! let cbor = b"\x02"; //! //! #[cfg(feature = "additional-controls")] -//! assert!(validate_cbor_from_slice(cddl, cbor, Some(&["cbor"])).is_ok()) +//! assert!(validate_cbor_from_slice(cddl, cbor, false, Some(&["cbor"])).is_ok()) //! ``` //! //! ## `no_std` support diff --git a/src/parser.rs b/src/parser.rs index c5a9e4c5..6c51e61e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -44,6 +44,9 @@ pub struct Parser<'a, I> where I: Iterator>, { + /// Vec of collected parsing errors + pub errors: Vec, + tokens: I, str_input: &'a str, cur_token: Token<'a>, @@ -52,13 +55,12 @@ where peek_lexer_position: Position, #[cfg(feature = "ast-span")] parser_position: Position, - /// Vec of collected parsing errors - pub errors: Vec, #[cfg(feature = "ast-span")] visited_rule_idents: Vec<(&'a str, Span)>, #[cfg(not(feature = "ast-span"))] visited_rule_idents: Vec<&'a str>, current_rule_generic_param_idents: Option>, + allow_missing_definitions: bool, } /// Parsing error types @@ -108,9 +110,9 @@ where /// use cddl::lexer::Lexer; /// /// let input = r#"mycddl = ( int / float )"#; - /// let p = Parser::new(Lexer::new(input).iter(), input); + /// let p = Parser::new(Lexer::new(input).iter(), input, false); /// ``` - pub fn new(tokens: I, str_input: &'a str) -> Result> { + pub fn new(tokens: I, str_input: &'a str, allow_missing_definitions: bool) -> Result> { let mut p = Parser { tokens, str_input, @@ -123,6 +125,7 @@ where parser_position: Position::default(), visited_rule_idents: Vec::default(), current_rule_generic_param_idents: None, + allow_missing_definitions, }; p.next_token()?; @@ -145,7 +148,7 @@ where /// use cddl::lexer::Lexer; /// /// let input = r#"mycddl = ( int / float )"#; - /// if let Ok(mut p) = Parser::new(Lexer::new(input).iter(), input) { + /// if let Ok(mut p) = Parser::new(Lexer::new(input).iter(), input, false) { /// if let Err(Error::INCREMENTAL) = p.parse_cddl() { /// let _ = p.report_errors(true); /// } @@ -379,33 +382,35 @@ where } } - #[cfg(feature = "ast-span")] - for (rule, span) in self.visited_rule_idents.iter() { - if !c.rules.iter().any(|r| r.name() == *rule) { - self.errors.push(Error::PARSER { - position: Position { - column: 0, - index: span.0, - line: span.2, - range: (span.0, span.1), - }, - msg: ErrorMsg { - short: format!("missing definition for \"{}\"", rule), - extended: None, - }, - }) + if !self.allow_missing_definitions { + #[cfg(feature = "ast-span")] + for (rule, span) in self.visited_rule_idents.iter() { + if !c.rules.iter().any(|r| r.name() == *rule) { + self.errors.push(Error::PARSER { + position: Position { + column: 0, + index: span.0, + line: span.2, + range: (span.0, span.1), + }, + msg: ErrorMsg { + short: format!("missing definition for \"{}\"", rule), + extended: None, + }, + }) + } } - } - #[cfg(not(feature = "ast-span"))] - for rule in self.visited_rule_idents.iter() { - if !c.rules.iter().any(|r| r.name() == *rule) { - self.errors.push(Error::PARSER { - msg: ErrorMsg { - short: format!("missing definition for \"{}\"", rule), - extended: None, - }, - }) + #[cfg(not(feature = "ast-span"))] + for rule in self.visited_rule_idents.iter() { + if !c.rules.iter().any(|r| r.name() == *rule) { + self.errors.push(Error::PARSER { + msg: ErrorMsg { + short: format!("missing definition for \"{}\"", rule), + extended: None, + }, + }) + } } } @@ -1294,7 +1299,15 @@ where let end_type2_range = self.parser_position.range.1; #[cfg(feature = "ast-span")] - if !self + if let Some(params) = &self.current_rule_generic_param_idents { + if !params.iter().any(|&p| p == ident.ident) + && !self + .visited_rule_idents + .contains(&(ident.ident, ident.span)) + { + self.visited_rule_idents.push((ident.ident, ident.span)); + } + } else if !self .visited_rule_idents .contains(&(ident.ident, ident.span)) { @@ -1302,7 +1315,13 @@ where } #[cfg(not(feature = "ast-span"))] - if !self.visited_rule_idents.contains(&ident.ident) { + if let Some(params) = &self.current_rule_generic_param_idents { + if !params.iter().any(|&p| p == ident.ident) + && !self.visited_rule_idents.contains(&ident.ident) + { + self.visited_rule_idents.push(ident.ident); + } + } else if !self.visited_rule_idents.contains(&ident.ident) { self.visited_rule_idents.push(ident.ident); } @@ -1328,12 +1347,22 @@ where ); #[cfg(feature = "ast-span")] - if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| r.0 == ident.0) { + if let Some(params) = &self.current_rule_generic_param_idents { + if !params.iter().any(|&p| p == ident.0) + && !self.visited_rule_idents.contains(&(ident.0, span)) + { + self.visited_rule_idents.push((ident.0, span)); + } + } else if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| r.0 == ident.0) { self.visited_rule_idents.push((ident.0, span)); } #[cfg(not(feature = "ast-span"))] - if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| *r == ident.0) { + if let Some(params) = &self.current_rule_generic_param_idents { + if !params.iter().any(|&p| p == ident.0) && !self.visited_rule_idents.contains(&ident.0) { + self.visited_rule_idents.push(ident.0); + } + } else if ident.1.is_none() && !self.visited_rule_idents.iter().any(|r| *r == ident.0) { self.visited_rule_idents.push(ident.0); } @@ -2848,7 +2877,11 @@ where // Parse tokens vec as group if has_group_entries { - let mut p = Parser::new(tokens.into_iter(), self.str_input)?; + let mut p = Parser::new( + tokens.into_iter(), + self.str_input, + self.allow_missing_definitions, + )?; let group = match p.parse_group() { Ok(g) => g, Err(Error::INCREMENTAL) => { @@ -2873,7 +2906,11 @@ where } // Parse tokens vec as type - let mut p = Parser::new(tokens.into_iter(), self.str_input)?; + let mut p = Parser::new( + tokens.into_iter(), + self.str_input, + self.allow_missing_definitions, + )?; let t = match p.parse_type(None) { Ok(t) => t, Err(Error::INCREMENTAL) => { @@ -3384,6 +3421,7 @@ where /// `cddl::lexer_from_str()` /// * `input` - A string slice with the CDDL text input /// * `print_stderr` - When true, print any errors to stderr +/// * `allow_missing_definitions` - When true, allow references to missing rule definitions /// /// # Example /// @@ -3391,15 +3429,16 @@ where /// use cddl::{lexer_from_str, parser::cddl_from_str}; /// /// let input = r#"myrule = int"#; -/// let _ = cddl_from_str(&mut lexer_from_str(input), input, true); +/// let _ = cddl_from_str(&mut lexer_from_str(input), input, true, false); #[cfg(not(target_arch = "wasm32"))] #[cfg(feature = "std")] pub fn cddl_from_str<'a>( lexer: &'a mut Lexer<'a>, input: &'a str, print_stderr: bool, + allow_missing_definitions: bool, ) -> std::result::Result, String> { - match Parser::new(lexer.iter(), input).map_err(|e| e.to_string()) { + match Parser::new(lexer.iter(), input, allow_missing_definitions).map_err(|e| e.to_string()) { Ok(mut p) => match p.parse_cddl() { Ok(c) => Ok(c), Err(Error::INCREMENTAL) => { @@ -3428,6 +3467,8 @@ pub fn cddl_from_str<'a>( /// * `lexer` - A mutable reference to a `lexer::Lexer`. Can be created from /// `cddl::lexer_from_str()` /// * `input` - A string slice with the CDDL text input +/// * `allow_missing_definitions` - When true, allow references to missing rule +/// definitions /// /// # Example /// @@ -3443,8 +3484,9 @@ pub fn cddl_from_str<'a>( pub fn cddl_from_str<'a>( lexer: &'a mut Lexer<'a>, input: &'a str, + allow_missing_definitions: bool, ) -> std::result::Result, String> { - match Parser::new(lexer.iter(), input).map_err(|e| e.to_string()) { + match Parser::new(lexer.iter(), input, allow_missing_definitions).map_err(|e| e.to_string()) { Ok(mut p) => match p.parse_cddl() { Ok(c) => Ok(c), Err(Error::INCREMENTAL) => { @@ -3465,6 +3507,7 @@ pub fn cddl_from_str<'a>( /// # Arguments /// /// * `input` - A string slice with the CDDL text input +/// * `allow_missing_definitions` - When true, allow references to missing rule definitions /// /// # Example /// @@ -3480,14 +3523,17 @@ pub fn cddl_from_str<'a>( /// ``` #[cfg(target_arch = "wasm32")] #[wasm_bindgen] -pub fn cddl_from_str(input: &str) -> result::Result { +pub fn cddl_from_str( + input: &str, + allow_missing_definitions: bool, +) -> result::Result { #[derive(Serialize)] struct ParserError { position: Position, msg: ErrorMsg, } - match Parser::new(Lexer::new(input).iter(), input) { + match Parser::new(Lexer::new(input).iter(), input, allow_missing_definitions) { Ok(mut p) => match p.parse_cddl() { Ok(c) => JsValue::from_serde(&c).map_err(|e| JsValue::from(e.to_string())), Err(Error::INCREMENTAL) => { @@ -3524,14 +3570,17 @@ pub fn cddl_from_str(input: &str) -> result::Result { #[cfg(target_arch = "wasm32")] #[wasm_bindgen] /// Formats cddl from input string -pub fn format_cddl_from_str(input: &str) -> result::Result { +pub fn format_cddl_from_str( + input: &str, + allow_missing_definitions: bool, +) -> result::Result { #[derive(Serialize)] struct ParserError { position: Position, msg: ErrorMsg, } - match Parser::new(Lexer::new(input).iter(), input) { + match Parser::new(Lexer::new(input).iter(), input, allow_missing_definitions) { Ok(mut p) => match p.parse_cddl() { Ok(c) => Ok(c.to_string()), Err(Error::INCREMENTAL) => { diff --git a/src/parser_tests.rs b/src/parser_tests.rs index 35f06d7b..eaec6030 100644 --- a/src/parser_tests.rs +++ b/src/parser_tests.rs @@ -20,11 +20,11 @@ mod tests { let input = indoc!( r#" a = 1234 - a = b + a = 5678 "# ); - match Parser::new(Lexer::new(input).iter(), input) { + match Parser::new(Lexer::new(input).iter(), input, false) { Ok(mut p) => match p.parse_cddl() { Ok(_) => Ok(()), #[cfg(feature = "std")] @@ -41,8 +41,8 @@ mod tests { error: parser errors ┌─ input:2:1 │ - 2 │ a = b - │ ^^^^^ rule with the same identifier is already defined + 2 │ a = 5678 + │ ^^^^^^^^ rule with the same identifier is already defined "# ) @@ -59,8 +59,8 @@ mod tests { ┌── input:2:1 ─── │ - 2 │ a = b - │ ^^^^^ rule with the same identifier is already defined + 2 │ a = 5678 + │ ^^^^^^^^ rule with the same identifier is already defined "# ) @@ -78,7 +78,7 @@ mod tests { let input = r#""#; let mut l = Lexer::new(input); - let gps = Parser::new(&mut l.iter(), input)?.parse_genericparm()?; + let gps = Parser::new(&mut l.iter(), input, false)?.parse_genericparm()?; let expected_output = GenericParams { params: vec![ @@ -114,7 +114,7 @@ mod tests { fn verify_genericparm_diagnostic() -> Result<()> { let input = r#"<1, 2>"#; - match Parser::new(Lexer::new(input).iter(), input) { + match Parser::new(Lexer::new(input).iter(), input, false) { Ok(mut p) => match p.parse_genericparm() { Ok(_) => Ok(()), #[cfg(feature = "std")] @@ -175,7 +175,7 @@ mod tests { "# ); - match Parser::new(Lexer::new(input).iter(), input) { + match Parser::new(Lexer::new(input).iter(), input, false) { Ok(mut p) => match p.parse_cddl() { Ok(_) => Ok(()), #[cfg(feature = "std")] @@ -195,10 +195,17 @@ mod tests { │ ^^^^^^^^^^^^^ generic parameters should be between angle brackets '<' and '>' and separated by a comma ',' 2 │ ruleb = rulec 3 │ ruleb = ruled - │ ^^^^^^^^^^^^^ rule with the same identifier is already defined + │ ^^^^^^^^^^^^^ + │ │ │ + │ │ missing definition for "ruled" + │ rule with the same identifier is already defined 4 │ rulec = rulee + │ ^^^^^ missing definition for "rulee" 5 │ rulec = rulee2 - │ ^^^^^^^^^^^^^^ rule with the same identifier is already defined + │ ^^^^^^^^^^^^^^ + │ │ │ + │ │ missing definition for "rulee2" + │ rule with the same identifier is already defined "# ) @@ -241,7 +248,7 @@ mod tests { let mut l = Lexer::new(input); - let generic_args = Parser::new(l.iter(), input)?.parse_genericargs()?; + let generic_args = Parser::new(l.iter(), input, false)?.parse_genericargs()?; let expected_output = GenericArgs { args: vec![ @@ -283,7 +290,7 @@ mod tests { let mut l = Lexer::new(input); - let t = Parser::new(l.iter(), input)?.parse_type(None)?; + let t = Parser::new(l.iter(), input, false)?.parse_type(None)?; let expected_output = Type { type_choices: vec![TypeChoice { @@ -537,7 +544,7 @@ mod tests { for (idx, expected_output) in expected_outputs.iter().enumerate() { let mut l = Lexer::new(inputs[idx]); - let t1 = Parser::new(l.iter(), inputs[idx])?.parse_type1(None)?; + let t1 = Parser::new(l.iter(), inputs[idx], false)?.parse_type1(None)?; assert_eq!(&t1, expected_output); assert_eq!(t1.to_string(), expected_output.to_string()); @@ -955,7 +962,7 @@ mod tests { for (idx, expected_output) in expected_outputs.iter().enumerate() { let mut l = Lexer::new(inputs[idx]); - let t2 = Parser::new(l.iter(), inputs[idx])?.parse_type2()?; + let t2 = Parser::new(l.iter(), inputs[idx], false)?.parse_type2()?; assert_eq!(&t2, expected_output); assert_eq!(t2.to_string(), expected_output.to_string()); @@ -1317,7 +1324,7 @@ mod tests { for (idx, expected_output) in expected_ouputs.iter().enumerate() { let mut l = Lexer::new(inputs[idx]); - let t2 = Parser::new(l.iter(), inputs[idx])?.parse_type2()?; + let t2 = Parser::new(l.iter(), inputs[idx], false)?.parse_type2()?; assert_eq!(&t2, expected_output); assert_eq!(t2.to_string(), expected_output.to_string()); @@ -1597,7 +1604,7 @@ mod tests { for (idx, expected_output) in expected_outputs.iter().enumerate() { let mut l = Lexer::new(inputs[idx]); - let grpent = Parser::new(l.iter(), inputs[idx])?.parse_grpent(false)?; + let grpent = Parser::new(l.iter(), inputs[idx], false)?.parse_grpent(false)?; assert_eq!(&grpent, expected_output); assert_eq!(grpent.to_string(), expected_output.to_string()); @@ -1714,7 +1721,7 @@ mod tests { for (idx, expected_output) in expected_outputs.iter().enumerate() { let mut l = Lexer::new(inputs[idx]); - let mk = Parser::new(l.iter(), inputs[idx])?.parse_memberkey(false)?; + let mk = Parser::new(l.iter(), inputs[idx], false)?.parse_memberkey(false)?; if let Some(mk) = mk { assert_eq!(&mk, expected_output); @@ -1776,7 +1783,7 @@ mod tests { for (idx, expected_output) in expected_outputs.iter().enumerate() { let mut l = Lexer::new(inputs[idx]); - let o = Parser::new(l.iter(), inputs[idx])?.parse_occur(false)?; + let o = Parser::new(l.iter(), inputs[idx], false)?.parse_occur(false)?; if let Some(o) = o { assert_eq!(&o, expected_output); diff --git a/src/repl.rs b/src/repl.rs index adf2bbbf..46decc31 100644 --- a/src/repl.rs +++ b/src/repl.rs @@ -28,7 +28,7 @@ pub fn start(mut reader: R, mut writer: W) -> Result<()> { if let Ok(Some(_)) = control(&line) { writer.flush()?; } else { - if let Ok(c) = parser::cddl_from_str(&mut lexer::Lexer::new(&line), &line, true) { + if let Ok(c) = parser::cddl_from_str(&mut lexer::Lexer::new(&line), &line, true, false) { writer.write_all(format!("{:#?}\n", c).as_bytes())?; } diff --git a/src/validator/cbor.rs b/src/validator/cbor.rs index 10a5a53b..4ad3e649 100644 --- a/src/validator/cbor.rs +++ b/src/validator/cbor.rs @@ -3667,7 +3667,7 @@ mod tests { let cbor = ciborium::value::Value::Bytes(sha256_oid.as_bytes().to_vec()); let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true)?; + let cddl = cddl_from_str(&mut lexer, cddl, true, false)?; let mut cv = CBORValidator::new(&cddl, cbor, None); cv.validate()?; @@ -3686,7 +3686,7 @@ mod tests { ); let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true).map_err(json::Error::CDDLParsing); + let cddl = cddl_from_str(&mut lexer, cddl, true, false).map_err(json::Error::CDDLParsing); if let Err(e) = &cddl { println!("{}", e); } diff --git a/src/validator/control.rs b/src/validator/control.rs index be149706..c13b0703 100644 --- a/src/validator/control.rs +++ b/src/validator/control.rs @@ -845,7 +845,7 @@ mod tests { ); let mut l = lexer_from_str(cddl_str); - let cddl = cddl_from_str(&mut l, cddl_str, true)?; + let cddl = cddl_from_str(&mut l, cddl_str, true, false)?; assert_eq!( cat_operation( @@ -882,7 +882,7 @@ mod tests { ); let mut l = lexer_from_str(cddl_str); - let cddl = cddl_from_str(&mut l, cddl_str, true)?; + let cddl = cddl_from_str(&mut l, cddl_str, true, false)?; assert_eq!( cat_operation( diff --git a/src/validator/json.rs b/src/validator/json.rs index 16ee2afb..a0359e44 100644 --- a/src/validator/json.rs +++ b/src/validator/json.rs @@ -2638,7 +2638,7 @@ mod tests { let json = r#"{ "test": 10 }"#; let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true).map_err(json::Error::CDDLParsing); + let cddl = cddl_from_str(&mut lexer, cddl, true, false).map_err(json::Error::CDDLParsing); if let Err(e) = &cddl { println!("{}", e); } @@ -2665,7 +2665,7 @@ mod tests { let json = r#""v""#; let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true).map_err(json::Error::CDDLParsing); + let cddl = cddl_from_str(&mut lexer, cddl, true, false).map_err(json::Error::CDDLParsing); if let Err(e) = &cddl { println!("{}", e); } diff --git a/src/validator/mod.rs b/src/validator/mod.rs index d6c6b804..a9923fe8 100644 --- a/src/validator/mod.rs +++ b/src/validator/mod.rs @@ -44,10 +44,12 @@ trait Validator<'a, E: Error>: Visitor<'a, E> { pub fn validate_json_from_str( cddl: &str, json: &str, + allow_missing_definitions: bool, #[cfg(feature = "additional-controls")] enabled_features: Option<&[&str]>, ) -> json::Result { let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true).map_err(json::Error::CDDLParsing)?; + let cddl = cddl_from_str(&mut lexer, cddl, true, allow_missing_definitions) + .map_err(json::Error::CDDLParsing)?; let json = serde_json::from_str::(json).map_err(json::Error::JSONParsing)?; #[cfg(feature = "additional-controls")] @@ -66,10 +68,12 @@ pub fn validate_json_from_str( pub fn validate_json_from_str( cddl: &str, json: &str, + allow_missing_definitions: bool, enabled_features: Option>, ) -> std::result::Result { let mut l = Lexer::new(cddl); - let mut p = Parser::new((&mut l).iter(), cddl).map_err(|e| JsValue::from(e.to_string()))?; + let mut p = Parser::new((&mut l).iter(), cddl, allow_missing_definitions) + .map_err(|e| JsValue::from(e.to_string()))?; let c = p.parse_cddl().map_err(|e| JsValue::from(e.to_string()))?; if !p.errors.is_empty() { return Err( @@ -106,9 +110,14 @@ pub fn validate_json_from_str( #[cfg(not(feature = "additional-controls"))] #[wasm_bindgen] /// Validate JSON string from a given CDDL document string -pub fn validate_json_from_str(cddl: &str, json: &str) -> std::result::Result { +pub fn validate_json_from_str( + cddl: &str, + json: &str, + allow_missing_definitions: bool, +) -> std::result::Result { let mut l = Lexer::new(cddl); - let mut p = Parser::new((&mut l).iter(), cddl).map_err(|e| JsValue::from(e.to_string()))?; + let mut p = Parser::new((&mut l).iter(), cddl, allow_missing_definitions) + .map_err(|e| JsValue::from(e.to_string()))?; let c = p.parse_cddl().map_err(|e| JsValue::from(e.to_string()))?; if !p.errors.is_empty() { return Err( @@ -147,10 +156,12 @@ pub fn validate_json_from_str(cddl: &str, json: &str) -> std::result::Result, ) -> cbor::Result { let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true).map_err(cbor::Error::CDDLParsing)?; + let cddl = cddl_from_str(&mut lexer, cddl, true, allow_missing_definitions) + .map_err(cbor::Error::CDDLParsing)?; let cbor: ciborium::value::Value = ciborium::de::from_reader(cbor_slice).unwrap(); @@ -162,9 +173,14 @@ pub fn validate_cbor_from_slice( #[cfg(feature = "cbor")] #[cfg(not(feature = "additional-controls"))] /// Validate CBOR slice from a given CDDL document string -pub fn validate_cbor_from_slice(cddl: &str, cbor_slice: &[u8]) -> cbor::Result { +pub fn validate_cbor_from_slice( + cddl: &str, + cbor_slice: &[u8], + allow_missing_definitions: bool, +) -> cbor::Result { let mut lexer = lexer_from_str(cddl); - let cddl = cddl_from_str(&mut lexer, cddl, true).map_err(cbor::Error::CDDLParsing)?; + let cddl = + cddl_from_str(&mut lexer, cddl, allow_missing_definitions).map_err(cbor::Error::CDDLParsing)?; let cbor: ciborium::value::Value = ciborium::de::from_reader(cbor_slice).map_err(cbor::Error::CBORParsing)?; @@ -180,10 +196,12 @@ pub fn validate_cbor_from_slice(cddl: &str, cbor_slice: &[u8]) -> cbor::Result>, ) -> std::result::Result { let mut l = Lexer::new(cddl); - let mut p = Parser::new((&mut l).iter(), cddl).map_err(|e| JsValue::from(e.to_string()))?; + let mut p = Parser::new((&mut l).iter(), cddl, allow_missing_definitions) + .map_err(|e| JsValue::from(e.to_string()))?; let c = p.parse_cddl().map_err(|e| JsValue::from(e.to_string()))?; if !p.errors.is_empty() { return Err( @@ -223,9 +241,11 @@ pub fn validate_cbor_from_slice( pub fn validate_cbor_from_slice( cddl: &str, cbor_slice: &[u8], + allow_missing_definitions: bool, ) -> std::result::Result { let mut l = Lexer::new(cddl); - let mut p = Parser::new((&mut l).iter(), cddl).map_err(|e| JsValue::from(e.to_string()))?; + let mut p = Parser::new((&mut l).iter(), cddl, allow_missing_definitions) + .map_err(|e| JsValue::from(e.to_string()))?; let c = p.parse_cddl().map_err(|e| JsValue::from(e.to_string()))?; if !p.errors.is_empty() { return Err( diff --git a/tests/cddl.rs b/tests/cddl.rs index f74045a8..bd613cee 100644 --- a/tests/cddl.rs +++ b/tests/cddl.rs @@ -15,7 +15,12 @@ fn verify_cddl_compiles() -> Result<(), parser::Error> { } let file_content = fs::read_to_string(file.path()).unwrap(); - match parser::cddl_from_str(&mut lexer_from_str(&file_content), &file_content, true) { + match parser::cddl_from_str( + &mut lexer_from_str(&file_content), + &file_content, + true, + true, + ) { Ok(_) => println!("file: {:#?} ... success", file.path()), Err(_) => { return Err(parser::Error::INCREMENTAL); @@ -31,6 +36,7 @@ fn verify_json_validation() -> json::Result { validate_json_from_str( &fs::read_to_string("tests/fixtures/cddl/reputon.cddl").unwrap(), &fs::read_to_string("tests/fixtures/json/reputon.json").unwrap(), + true, None, ) } diff --git a/tests/did.rs b/tests/did.rs index b7e0a323..37f1ea6b 100644 --- a/tests/did.rs +++ b/tests/did.rs @@ -42,9 +42,9 @@ fn validate_did_json_examples() -> Result<(), Box> { let file = file?; if file.path().extension().and_then(OsStr::to_str).unwrap() == "json" { #[cfg(feature = "additional-controls")] - let r = validate_json_from_str(&cddl, &fs::read_to_string(file.path())?, None); + let r = validate_json_from_str(&cddl, &fs::read_to_string(file.path())?, true, None); #[cfg(not(feature = "additional-controls"))] - let r = validate_json_from_str(&cddl, &fs::read_to_string(file.path())?); + let r = validate_json_from_str(&cddl, &fs::read_to_string(file.path())?, true); println!("assert ok {:?}", file.path()); if let Err(e) = &r { println!("error validating {:?}\n", file.path()); @@ -92,9 +92,9 @@ fn validate_did_cbor_examples() -> Result<(), Box> { let mut data = Vec::new(); f.read_to_end(&mut data)?; #[cfg(feature = "additional-controls")] - let r = validate_cbor_from_slice(&cddl, &data, None); + let r = validate_cbor_from_slice(&cddl, &data, true, None); #[cfg(not(feature = "additional-controls"))] - let r = validate_cbor_from_slice(&cddl, &data); + let r = validate_cbor_from_slice(&cddl, &data, true); println!("assert ok {:?}", file.path()); if let Err(e) = &r { diff --git a/tests/parser.rs b/tests/parser.rs index 5da421f3..0a5e4423 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -30,7 +30,7 @@ fn verify_cddl() -> Result<()> { "# ); - match Parser::new(Lexer::new(input).iter(), input) { + match Parser::new(Lexer::new(input).iter(), input, true) { Ok(mut p) => match p.parse_cddl() { Ok(cddl) => { let expected_output = CDDL { @@ -625,7 +625,7 @@ fn cri_reference() -> std::result::Result<(), String> { ); let mut l = lexer_from_str(cddl); - let c_ast = cddl_from_str(&mut l, cddl, true)?; + let c_ast = cddl_from_str(&mut l, cddl, true, false)?; println!("{}", c_ast); From c37fb5ee19cdb04873a696434c58c41c4ecc01ff Mon Sep 17 00:00:00 2001 From: anweiss <2326106+anweiss@users.noreply.github.com> Date: Tue, 12 Oct 2021 13:32:52 -0400 Subject: [PATCH 23/24] wasm build fixes --- src/faker.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/faker.rs b/src/faker.rs index a64702eb..a3e05b7f 100644 --- a/src/faker.rs +++ b/src/faker.rs @@ -762,7 +762,10 @@ pub fn fake_json_from_cddl_str(cddl_str: &str) -> Result { #[cfg(target_arch = "wasm32")] #[wasm_bindgen] /// Generate fake JSON from a given CDDL document string -pub fn fake_json_from_cddl_str(cddl_str: &str) -> std::result::Result { +pub fn fake_json_from_cddl_str( + cddl_str: &str, + allow_missing_definitions: bool, +) -> std::result::Result { use crate::{ error::ParserError, lexer::Lexer, @@ -770,7 +773,8 @@ pub fn fake_json_from_cddl_str(cddl_str: &str) -> std::result::Result Date: Tue, 12 Oct 2021 13:36:23 -0400 Subject: [PATCH 24/24] update readme --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 55afdd15..cb284d2a 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ cddl help If using Docker: -> Replace `` with an appropriate [release](https://github.com/anweiss/cddl/releases) tag. Requires use of the `--volume` argument for mounting `.cddl` documents into the container when executing the command. `.json` or `.cbor` files can either be included in the volume mount or passed into the command via STDIN. +> Replace `` with an appropriate [release](https://github.com/anweiss/cddl/releases) tag. Requires use of the `--volume` argument for mounting `.cddl` documents into the container when executing the command. JSON or CBOR files can either be included in the volume mount or passed into the command via STDIN. ```sh docker run -it --rm -v $PWD:/cddl -w /cddl ghcr.io/anweiss/cddl-cli: help @@ -76,13 +76,13 @@ docker run -it --rm -v $PWD:/cddl -w /cddl ghcr.io/anweiss/cddl-cli: he You can validate JSON documents: ```sh -cddl validate --cddl --json [FILE.json]... +cddl validate --cddl --json [FILE]... ``` You can validate CBOR files: ```sh -cddl validate --cddl --cbor [FILE.cbor]... +cddl validate --cddl --cbor [FILE]... ``` It also supports validating files from STDIN (if it detects the input as valid UTF-8, it will attempt to validate the input as JSON, otherwise it will treat it as CBOR): @@ -175,7 +175,7 @@ Enable validation support for the additional control operators proposed in [http use cddl::{lexer_from_str, parser::cddl_from_str}; let input = r#"myrule = int"#; -assert!(cddl_from_str(&mut lexer_from_str(input), input, true).is_ok()) +assert!(cddl_from_str(&mut lexer_from_str(input), input, true, false).is_ok()) ``` ### Validating JSON @@ -195,7 +195,7 @@ let json = r#"{ "address": "1234 Lakeshore Dr" }"#; -assert!(validate_json_from_str(cddl, json).is_ok()) +assert!(validate_json_from_str(cddl, json, false).is_ok()) ``` This crate uses the [Serde](https://serde.rs/) framework, and more specifically, the [serde_json](https://crates.io/crates/serde_json) crate, for parsing and validating JSON. Serde was chosen due to its maturity in the ecosystem and its support for serializing and deserializing CBOR via the [ciborium](https://crates.io/crates/ciborium) crate. @@ -330,7 +330,7 @@ let cddl = r#"rule = false"#; let cbor = b"\xF4"; -assert!(validate_cbor_from_slice(cddl, cbor).is_ok()) +assert!(validate_cbor_from_slice(cddl, cbor, false).is_ok()) ``` This crate also uses [Serde](https://serde.rs/) and [ciborium](https://crates.io/crates/ciborium) for validating CBOR data structures. CBOR validation is done via the loosely typed [`ciborium::value::Value`](https://github.com/enarx/ciborium/blob/main/ciborium/src/value/mod.rs#L22) enum. In addition to all of the same features implemented by the JSON validator, this crate also supports validating CBOR tags (e.g. `#6.32(tstr)`), CBOR major types (e.g. `#1.2`), table types (e.g. `{ [ + tstr ] => int }`) and byte strings. The `.bits`, `.cbor` and `.cborseq` control operators are all supported as well. @@ -379,7 +379,7 @@ let cddl = r#" let cbor = b"\x02"; -assert!(validate_cbor_from_slice(cddl, cbor, Some(&["cbor"])).is_ok()) +assert!(validate_cbor_from_slice(cddl, cbor, false, Some(&["cbor"])).is_ok()) ``` ## `no_std` support