diff --git a/rasn-compiler-tests/tests/structured_types.rs b/rasn-compiler-tests/tests/structured_types.rs index da18b23..614dd47 100644 --- a/rasn-compiler-tests/tests/structured_types.rs +++ b/rasn-compiler-tests/tests/structured_types.rs @@ -278,7 +278,6 @@ e2e_pdu!( "# ); - e2e_pdu!( multiple_named_bits_default, r#" diff --git a/rasn-compiler/src/intermediate/constraints.rs b/rasn-compiler/src/intermediate/constraints.rs index 3c778b2..ff533c1 100644 --- a/rasn-compiler/src/intermediate/constraints.rs +++ b/rasn-compiler/src/intermediate/constraints.rs @@ -727,7 +727,7 @@ pub enum SubtypeElement { PermittedAlphabet(Box), SizeConstraint(Box), TypeConstraint(ASN1Type), - SingleTypeConstraint(InnerTypeConstraint), + SingleTypeConstraint(Vec), MultipleTypeConstraints(InnerTypeConstraint), PatternConstraint(PatternConstraint), UserDefinedConstraint(UserDefinedConstraint), @@ -766,7 +766,7 @@ impl Vec<(&str, Option>, Option)>, ), ) -> Self { - SubtypeElement::SingleTypeConstraint(InnerTypeConstraint { + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { is_partial: value.0.is_some(), constraints: value .1 diff --git a/rasn-compiler/src/lexer/constraint.rs b/rasn-compiler/src/lexer/constraint.rs index decac9e..d3e5e59 100644 --- a/rasn-compiler/src/lexer/constraint.rs +++ b/rasn-compiler/src/lexer/constraint.rs @@ -265,6 +265,17 @@ fn permitted_alphabet_constraint(input: Input<'_>) -> ParserResult<'_, SubtypeEl } fn single_type_constraint(input: Input<'_>) -> ParserResult<'_, SubtypeElement> { + opt_delimited::( + skip_ws_and_comments(char(LEFT_PARENTHESIS)), + skip_ws_and_comments(into(preceded( + tag(WITH_COMPONENT), + skip_ws_and_comments(map(constraint, SubtypeElement::SingleTypeConstraint)), + ))), + skip_ws_and_comments(char(RIGHT_PARENTHESIS)), + )(input) +} + +fn multiple_type_constraints(input: Input<'_>) -> ParserResult<'_, SubtypeElement> { opt_delimited::( skip_ws_and_comments(char(LEFT_PARENTHESIS)), skip_ws_and_comments(into(preceded( @@ -284,26 +295,6 @@ fn single_type_constraint(input: Input<'_>) -> ParserResult<'_, SubtypeElement> )(input) } -fn multiple_type_constraints(input: Input<'_>) -> ParserResult<'_, SubtypeElement> { - opt_delimited::( - skip_ws_and_comments(char(LEFT_PARENTHESIS)), - skip_ws_and_comments(preceded( - tag(WITH_COMPONENT), - skip_ws_and_comments(alt(( - map(single_type_constraint, |s| { - if let SubtypeElement::SingleTypeConstraint(c) = s { - SubtypeElement::MultipleTypeConstraints(c) - } else { - s - } - }), - multiple_type_constraints, - ))), - )), - skip_ws_and_comments(char(RIGHT_PARENTHESIS)), - )(input) -} - fn subset_member( input: Input<'_>, ) -> ParserResult<'_, (&str, Option>, Option)> { @@ -568,54 +559,82 @@ mod tests { .1, vec![Constraint::SubtypeConstraint(ElementSet { set: ElementOrSetOperation::SetOperation(SetOperation { - base: SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { - is_partial: true, - constraints: vec![ConstrainedComponent { - identifier: "containerId".into(), - constraints: vec![Constraint::SubtypeConstraint(ElementSet { - set: ElementOrSetOperation::SetOperation(SetOperation { - base: SubtypeElement::SingleValue { - value: ASN1Value::All, - extensible: false - }, - operator: SetOperator::Except, - operant: Box::new(ElementOrSetOperation::Element( - SubtypeElement::SingleValue { - value: ASN1Value::Integer(1), - extensible: false - } - )) - }), - extensible: false - })], - presence: ComponentPresence::Unspecified - }] - }), - operator: SetOperator::Union, - operant: Box::new(ElementOrSetOperation::Element( - SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { - is_partial: true, - constraints: vec![ConstrainedComponent { - identifier: "containerId".into(), - constraints: vec![Constraint::SubtypeConstraint(ElementSet { - set: ElementOrSetOperation::SetOperation(SetOperation { - base: SubtypeElement::SingleValue { - value: ASN1Value::All, - extensible: false - }, - operator: SetOperator::Except, - operant: Box::new(ElementOrSetOperation::Element( - SubtypeElement::SingleValue { - value: ASN1Value::Integer(2), + base: SubtypeElement::SingleTypeConstraint(vec![ + Constraint::SubtypeConstraint(ElementSet { + extensible: false, + set: ElementOrSetOperation::Element( + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { + is_partial: true, + constraints: vec![ConstrainedComponent { + identifier: "containerId".into(), + constraints: vec![Constraint::SubtypeConstraint( + ElementSet { + set: ElementOrSetOperation::SetOperation( + SetOperation { + base: SubtypeElement::SingleValue { + value: ASN1Value::All, + extensible: false + }, + operator: SetOperator::Except, + operant: Box::new( + ElementOrSetOperation::Element( + SubtypeElement::SingleValue { + value: ASN1Value::Integer(1), + extensible: false + } + ) + ) + } + ), extensible: false } - )) - }), - extensible: false - })], - presence: ComponentPresence::Unspecified - }] + )], + presence: ComponentPresence::Unspecified + }] + }) + ) }) + ]), + operator: SetOperator::Union, + operant: Box::new(ElementOrSetOperation::Element( + SubtypeElement::SingleTypeConstraint(vec![Constraint::SubtypeConstraint( + ElementSet { + extensible: false, + set: ElementOrSetOperation::Element( + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { + is_partial: true, + constraints: vec![ConstrainedComponent { + identifier: "containerId".into(), + constraints: vec![Constraint::SubtypeConstraint( + ElementSet { + set: ElementOrSetOperation::SetOperation( + SetOperation { + base: SubtypeElement::SingleValue { + value: ASN1Value::All, + extensible: false + }, + operator: SetOperator::Except, + operant: Box::new( + ElementOrSetOperation::Element( + SubtypeElement::SingleValue { + value: ASN1Value::Integer( + 2 + ), + extensible: false + } + ) + ) + } + ), + extensible: false + } + )], + presence: ComponentPresence::Unspecified + }] + }) + ) + } + )]) )) }), extensible: false @@ -636,7 +655,7 @@ mod tests { .unwrap() .1, vec![Constraint::SubtypeConstraint(ElementSet { - set: ElementOrSetOperation::Element(SubtypeElement::SingleTypeConstraint( + set: ElementOrSetOperation::Element(SubtypeElement::MultipleTypeConstraints( InnerTypeConstraint { is_partial: false, constraints: vec![ @@ -685,7 +704,7 @@ mod tests { .unwrap() .1, vec![Constraint::SubtypeConstraint(ElementSet { - set: ElementOrSetOperation::Element(SubtypeElement::SingleTypeConstraint( + set: ElementOrSetOperation::Element(SubtypeElement::MultipleTypeConstraints( InnerTypeConstraint { is_partial: true, constraints: vec![ @@ -729,24 +748,38 @@ mod tests { .1, vec![Constraint::SubtypeConstraint(ElementSet { set: ElementOrSetOperation::SetOperation(SetOperation { - base: SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { - is_partial: true, - constraints: vec![ConstrainedComponent { - identifier: "eventDeltaTime".into(), - constraints: vec![], - presence: ComponentPresence::Present - }] - }), + base: SubtypeElement::SingleTypeConstraint(vec![ + Constraint::SubtypeConstraint(ElementSet { + set: ElementOrSetOperation::Element( + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { + is_partial: true, + constraints: vec![ConstrainedComponent { + identifier: "eventDeltaTime".into(), + constraints: vec![], + presence: ComponentPresence::Present + }] + }), + ), + extensible: false + }) + ]), operator: SetOperator::Union, operant: Box::new(ElementOrSetOperation::Element( - SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { - is_partial: true, - constraints: vec![ConstrainedComponent { - identifier: "eventDeltaTime".into(), - constraints: vec![], - presence: ComponentPresence::Absent - }] - }) + SubtypeElement::SingleTypeConstraint(vec![Constraint::SubtypeConstraint( + ElementSet { + set: ElementOrSetOperation::Element( + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { + is_partial: true, + constraints: vec![ConstrainedComponent { + identifier: "eventDeltaTime".into(), + constraints: vec![], + presence: ComponentPresence::Absent + }] + }) + ), + extensible: false + } + )]) )) }), extensible: false @@ -767,7 +800,7 @@ mod tests { .1, vec![Constraint::SubtypeConstraint(ElementSet { set: ElementOrSetOperation::SetOperation(SetOperation { - base: SubtypeElement::SingleTypeConstraint(InnerTypeConstraint { + base: SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { is_partial: true, constraints: vec![ ConstrainedComponent { @@ -784,7 +817,7 @@ mod tests { }), operator: SetOperator::Union, operant: Box::new(ElementOrSetOperation::Element( - SubtypeElement::SingleTypeConstraint(InnerTypeConstraint { + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { is_partial: true, constraints: vec![ ConstrainedComponent { @@ -1091,7 +1124,7 @@ mod tests { .unwrap() .1, vec![Constraint::SubtypeConstraint(ElementSet { - set: ElementOrSetOperation::Element(SubtypeElement::SingleTypeConstraint( + set: ElementOrSetOperation::Element(SubtypeElement::MultipleTypeConstraints( InnerTypeConstraint { is_partial: false, constraints: vec![ @@ -1249,4 +1282,40 @@ mod tests { })] ) } + + #[test] + fn with_component_intersection() { + assert_eq!( + vec![Constraint::SubtypeConstraint(ElementSet { + set: ElementOrSetOperation::SetOperation(SetOperation { + base: SubtypeElement::SingleTypeConstraint(vec![ + Constraint::SubtypeConstraint(ElementSet { + set: ElementOrSetOperation::Element(SubtypeElement::ContainedSubtype { + subtype: ASN1Type::ElsewhereDeclaredType(DeclarationElsewhere { + parent: None, + identifier: "EtsiTs103097Certificate".into(), + constraints: vec![], + }), + extensible: false, + }), + extensible: false, + }), + ]), + operator: SetOperator::Intersection, + operant: Box::new(ElementOrSetOperation::Element( + SubtypeElement::SizeConstraint(Box::new(ElementOrSetOperation::Element( + SubtypeElement::SingleValue { + value: ASN1Value::Integer(1,), + extensible: false, + }, + ))), + )) + }), + extensible: false, + })], + constraint(r#"((WITH COMPONENT (EtsiTs103097Certificate))^(SIZE(1)))"#.into()) + .unwrap() + .1 + ) + } } diff --git a/rasn-compiler/src/lexer/real.rs b/rasn-compiler/src/lexer/real.rs index 104e872..5d705b8 100644 --- a/rasn-compiler/src/lexer/real.rs +++ b/rasn-compiler/src/lexer/real.rs @@ -122,7 +122,7 @@ mod tests { .1, ASN1Type::Real(Real { constraints: vec![Constraint::SubtypeConstraint(ElementSet { - set: ElementOrSetOperation::Element(SubtypeElement::SingleTypeConstraint( + set: ElementOrSetOperation::Element(SubtypeElement::MultipleTypeConstraints( InnerTypeConstraint { is_partial: false, constraints: vec![ diff --git a/rasn-compiler/src/lexer/sequence.rs b/rasn-compiler/src/lexer/sequence.rs index d5fa0f4..7affef4 100644 --- a/rasn-compiler/src/lexer/sequence.rs +++ b/rasn-compiler/src/lexer/sequence.rs @@ -217,7 +217,7 @@ is_recursive: false, name: "clusterBoundingBoxShape".into(), tag: None, ty: ASN1Type::ElsewhereDeclaredType(DeclarationElsewhere { parent: None, - identifier: "Shape".into(), constraints: vec![Constraint::SubtypeConstraint(ElementSet { set: ElementOrSetOperation::Element(SubtypeElement::SingleTypeConstraint(InnerTypeConstraint { is_partial: true, constraints: vec![ConstrainedComponent { identifier: "elliptical".into(), constraints: vec![], presence: ComponentPresence::Absent },ConstrainedComponent { identifier: "radial".into(), constraints: vec![], presence: ComponentPresence::Absent },ConstrainedComponent { identifier: "radialShapes".into(), constraints: vec![], presence: ComponentPresence::Absent }] })), extensible: false }) + identifier: "Shape".into(), constraints: vec![Constraint::SubtypeConstraint(ElementSet { set: ElementOrSetOperation::Element(SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { is_partial: true, constraints: vec![ConstrainedComponent { identifier: "elliptical".into(), constraints: vec![], presence: ComponentPresence::Absent },ConstrainedComponent { identifier: "radial".into(), constraints: vec![], presence: ComponentPresence::Absent },ConstrainedComponent { identifier: "radialShapes".into(), constraints: vec![], presence: ComponentPresence::Absent }] })), extensible: false }) ]}), default_value: None, is_optional: true, diff --git a/rasn-compiler/src/lexer/tests/mod.rs b/rasn-compiler/src/lexer/tests/mod.rs index e09a5a4..5686fa4 100644 --- a/rasn-compiler/src/lexer/tests/mod.rs +++ b/rasn-compiler/src/lexer/tests/mod.rs @@ -175,24 +175,40 @@ fn parses_toplevel_crossrefering_declaration() { identifier: "EventHistory".into(), constraints: vec![Constraint::SubtypeConstraint(ElementSet { set: ElementOrSetOperation::SetOperation(SetOperation { - base: SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { - is_partial: true, - constraints: vec![ConstrainedComponent { - identifier: "eventDeltaTime".into(), - constraints: vec![], - presence: ComponentPresence::Present - }] - }), + base: SubtypeElement::SingleTypeConstraint(vec![ + Constraint::SubtypeConstraint(ElementSet { + extensible: false, + set: ElementOrSetOperation::Element( + SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { + is_partial: true, + constraints: vec![ConstrainedComponent { + identifier: "eventDeltaTime".into(), + constraints: vec![], + presence: ComponentPresence::Present + }] + }) + ) + }) + ]), operator: SetOperator::Union, operant: Box::new(ElementOrSetOperation::Element( - SubtypeElement::MultipleTypeConstraints(InnerTypeConstraint { - is_partial: true, - constraints: vec![ConstrainedComponent { - identifier: "eventDeltaTime".into(), - constraints: vec![], - presence: ComponentPresence::Absent - }] - }) + SubtypeElement::SingleTypeConstraint(vec![ + Constraint::SubtypeConstraint(ElementSet { + extensible: false, + set: ElementOrSetOperation::Element( + SubtypeElement::MultipleTypeConstraints( + InnerTypeConstraint { + is_partial: true, + constraints: vec![ConstrainedComponent { + identifier: "eventDeltaTime".into(), + constraints: vec![], + presence: ComponentPresence::Absent + }] + } + ) + ) + }) + ]) )) }), extensible: false diff --git a/rasn-compiler/src/validator/linking/constraints.rs b/rasn-compiler/src/validator/linking/constraints.rs index 728a225..4652562 100644 --- a/rasn-compiler/src/validator/linking/constraints.rs +++ b/rasn-compiler/src/validator/linking/constraints.rs @@ -63,8 +63,12 @@ impl SubtypeElement { SubtypeElement::TypeConstraint(t) => { t.link_constraint_reference(identifier, tlds)?; } - SubtypeElement::SingleTypeConstraint(s) - | SubtypeElement::MultipleTypeConstraints(s) => { + SubtypeElement::SingleTypeConstraint(constraints) => { + for c in constraints { + c.link_cross_reference(identifier, tlds)?; + } + } + SubtypeElement::MultipleTypeConstraints(s) => { for b in s.constraints.iter_mut().flat_map(|cc| &mut cc.constraints) { b.link_cross_reference(identifier, tlds)?; } @@ -98,8 +102,10 @@ impl SubtypeElement { } SubtypeElement::SizeConstraint(s) => s.has_cross_reference(), SubtypeElement::TypeConstraint(t) => t.references_class_by_name(), - SubtypeElement::MultipleTypeConstraints(s) - | SubtypeElement::SingleTypeConstraint(s) => s + SubtypeElement::SingleTypeConstraint(c) => { + c.iter().any(|constraint| constraint.has_cross_reference()) + } + SubtypeElement::MultipleTypeConstraints(s) => s .constraints .iter() .any(|cc| cc.constraints.iter().any(|c| c.has_cross_reference())), diff --git a/rasn-compiler/src/validator/linking/mod.rs b/rasn-compiler/src/validator/linking/mod.rs index 9c8980d..8fb1b80 100644 --- a/rasn-compiler/src/validator/linking/mod.rs +++ b/rasn-compiler/src/validator/linking/mod.rs @@ -1045,11 +1045,17 @@ impl ASN1Value { ASN1Value::SequenceOrSet(o), ) => { *self = ASN1Value::BitStringNamedBits( - o.iter().filter_map(|(_, v)| match &**v { - ASN1Value::ElsewhereDeclaredValue { identifier, .. } => Some(identifier.clone()), - ASN1Value::EnumeratedValue { enumerable, .. } => Some(enumerable.clone()), - _ => None - }).collect() + o.iter() + .filter_map(|(_, v)| match &**v { + ASN1Value::ElsewhereDeclaredValue { identifier, .. } => { + Some(identifier.clone()) + } + ASN1Value::EnumeratedValue { enumerable, .. } => { + Some(enumerable.clone()) + } + _ => None, + }) + .collect(), ); self.link_with_type(tlds, ty, type_name) } @@ -1062,11 +1068,17 @@ impl ASN1Value { ) if matches![**value, ASN1Value::SequenceOrSet(_)] => { if let ASN1Value::SequenceOrSet(o) = &**value { *value = Box::new(ASN1Value::BitStringNamedBits( - o.iter().filter_map(|(_, v)| match &**v { - ASN1Value::ElsewhereDeclaredValue { identifier, .. } => Some(identifier.clone()), - ASN1Value::EnumeratedValue { enumerable, .. } => Some(enumerable.clone()), - _ => None - }).collect() + o.iter() + .filter_map(|(_, v)| match &**v { + ASN1Value::ElsewhereDeclaredValue { identifier, .. } => { + Some(identifier.clone()) + } + ASN1Value::EnumeratedValue { enumerable, .. } => { + Some(enumerable.clone()) + } + _ => None, + }) + .collect(), )); self.link_with_type(tlds, ty, type_name)?; }