From 04df8f4e84a04eeb8ab6172c63d23f43074abd8c Mon Sep 17 00:00:00 2001 From: 6d7a Date: Fri, 22 Mar 2024 17:40:16 +0100 Subject: [PATCH] refactor(header): unpack GlobalModuleReference in header --- rasn-compiler-tests/tests/structured_types.rs | 2 +- rasn-compiler/src/generator/rasn/builder.rs | 2 +- rasn-compiler/src/generator/rasn/utils.rs | 10 +- rasn-compiler/src/intermediate/mod.rs | 61 +++- rasn-compiler/src/parser/module_reference.rs | 309 +++++++++++++----- .../validator/linking/information_object.rs | 2 +- 6 files changed, 286 insertions(+), 100 deletions(-) diff --git a/rasn-compiler-tests/tests/structured_types.rs b/rasn-compiler-tests/tests/structured_types.rs index 4cf7601..3211c67 100644 --- a/rasn-compiler-tests/tests/structured_types.rs +++ b/rasn-compiler-tests/tests/structured_types.rs @@ -58,4 +58,4 @@ e2e_pdu!( fn personnel_record_children_default () -> SequenceOf { alloc::vec![] } "# -); \ No newline at end of file +); diff --git a/rasn-compiler/src/generator/rasn/builder.rs b/rasn-compiler/src/generator/rasn/builder.rs index 1d024d4..e6b0283 100644 --- a/rasn-compiler/src/generator/rasn/builder.rs +++ b/rasn-compiler/src/generator/rasn/builder.rs @@ -32,7 +32,7 @@ impl Backend for Rust { if let Some((module_ref, _)) = tlds.first().and_then(|tld| tld.get_index().cloned()) { let name = to_rust_snake_case(&module_ref.name); let imports = module_ref.imports.iter().map(|import| { - let module = to_rust_snake_case(&import.origin_name); + let module = to_rust_snake_case(&import.global_module_reference.module_reference); let mut usages = Some(vec![]); 'imports: for usage in &import.types { if usage.contains("{}") || usage.chars().all(|c| c.is_uppercase() || c == '-') { diff --git a/rasn-compiler/src/generator/rasn/utils.rs b/rasn-compiler/src/generator/rasn/utils.rs index aab3937..f305c6c 100644 --- a/rasn-compiler/src/generator/rasn/utils.rs +++ b/rasn-compiler/src/generator/rasn/utils.rs @@ -506,8 +506,14 @@ pub fn type_to_tokens(ty: &ASN1Type) -> Result { "Set values are currently unsupported!" )), ASN1Type::ElsewhereDeclaredType(e) => Ok(to_rust_title_case(&e.identifier)), - ASN1Type::InformationObjectFieldReference(_) => todo!(), - ASN1Type::Time(_) => todo!(), + ASN1Type::InformationObjectFieldReference(_) => Err(error!( + NotYetInplemented, + "Information Object field reference values are currently unsupported!" + )), + ASN1Type::Time(_) => Err(error!( + NotYetInplemented, + "Time values are currently unsupported!" + )), ASN1Type::GeneralizedTime(_) => Ok(quote!(GeneralizedTime)), ASN1Type::UTCTime(_) => Ok(quote!(UtcTime)), ASN1Type::EmbeddedPdv | ASN1Type::External => Ok(quote!(Any)), diff --git a/rasn-compiler/src/intermediate/mod.rs b/rasn-compiler/src/intermediate/mod.rs index 3f900b1..d4aa973 100644 --- a/rasn-compiler/src/intermediate/mod.rs +++ b/rasn-compiler/src/intermediate/mod.rs @@ -272,33 +272,60 @@ pub enum With { Descendants, } +/// Represents a global module reference as specified in +/// Rec. ITU-T X.680 (02/2021) +#[derive(Debug, Clone, PartialEq)] +pub struct ExternalValueReference { + pub module_reference: String, + pub value_reference: String, +} + +/// Represents a global module reference as specified in +/// Rec. ITU-T X.680 (02/2021) +#[derive(Debug, Clone, PartialEq)] +pub struct GlobalModuleReference { + pub module_reference: String, + pub assigned_identifier: AssignedIdentifier, +} + +impl From<(&str, AssignedIdentifier)> for GlobalModuleReference { + fn from(value: (&str, AssignedIdentifier)) -> Self { + Self { + module_reference: value.0.to_owned(), + assigned_identifier: value.1, + } + } +} + +/// Represents an assigned identifier as specified in +/// Rec. ITU-T X.680 (02/2021) +#[derive(Debug, Clone, PartialEq)] +pub enum AssignedIdentifier { + ObjectIdentifierValue(ObjectIdentifierValue), + ExternalValueReference(ExternalValueReference), + ValueReference(String), + ParameterizedValue { + value_reference: String, + actual_parameter_list: String, + }, + Empty, +} + /// Represents a module import as specified in /// Rec. ITU-T X.680 (02/2021) ยง 13.16 #[derive(Debug, Clone, PartialEq)] pub struct Import { pub types: Vec, - pub origin_name: String, - pub origin_identifier: Option, + pub global_module_reference: GlobalModuleReference, pub with: Option, } -impl - From<( - Vec<&str>, - (&str, Option, Option<&str>), - )> for Import -{ - fn from( - value: ( - Vec<&str>, - (&str, Option, Option<&str>), - ), - ) -> Self { +impl From<(Vec<&str>, (GlobalModuleReference, Option<&str>))> for Import { + fn from(value: (Vec<&str>, (GlobalModuleReference, Option<&str>))) -> Self { Self { types: value.0.into_iter().map(String::from).collect(), - origin_name: value.1 .0.into(), - origin_identifier: value.1 .1, - with: value.1 .2.map(|with| { + global_module_reference: value.1 .0, + with: value.1 .1.map(|with| { if with == WITH_SUCCESSORS { With::Successors } else { diff --git a/rasn-compiler/src/parser/module_reference.rs b/rasn-compiler/src/parser/module_reference.rs index b0c0ff5..5e8bc5e 100644 --- a/rasn-compiler/src/parser/module_reference.rs +++ b/rasn-compiler/src/parser/module_reference.rs @@ -1,16 +1,17 @@ use crate::intermediate::*; use nom::{ branch::alt, - bytes::complete::tag, + bytes::complete::{is_not, tag, take_until}, character::complete::char, - combinator::{into, map, opt, recognize, value}, + combinator::{into, map, not, opt, peek, recognize, value}, multi::{many0, separated_list1}, - sequence::{delimited, pair, preceded, terminated, tuple}, - IResult, + sequence::{delimited, pair, preceded, separated_pair, terminated, tuple}, + IResult, Parser, }; use super::{ common::{identifier, skip_ws, skip_ws_and_comments, value_identifier}, + in_braces, object_identifier::object_identifier_value, }; @@ -66,6 +67,54 @@ fn parameterized_identifier<'a>(input: &'a str) -> IResult<&'a str, &'a str> { terminated(identifier, tag("{}"))(input) } +fn global_module_reference(input: &str) -> IResult<&str, GlobalModuleReference> { + into(skip_ws_and_comments(pair( + identifier, + alt(( + map( + skip_ws_and_comments(object_identifier_value), + AssignedIdentifier::ObjectIdentifierValue, + ), + map( + skip_ws_and_comments(separated_pair(identifier, char(DOT), value_identifier)), + |(mod_ref, val_ref)| { + AssignedIdentifier::ExternalValueReference(ExternalValueReference { + module_reference: mod_ref.to_owned(), + value_reference: val_ref.to_owned(), + }) + }, + ), + map( + skip_ws_and_comments(pair( + value_identifier, + skip_ws(recognize(in_braces(take_until("}")))), + )), + |(v, p)| AssignedIdentifier::ParameterizedValue { + value_reference: v.to_owned(), + actual_parameter_list: p.to_owned(), + }, + ), + map( + skip_ws_and_comments(terminated( + value_identifier, + not(skip_ws_and_comments(alt(( + peek(value((), tag(FROM))), + peek(value((), char(COMMA))), + )))), + )), + |v| AssignedIdentifier::ValueReference(v.to_owned()), + ), + value( + AssignedIdentifier::Empty, + not(skip_ws_and_comments(alt(( + peek(value((), tag(FROM))), + peek(value((), char(COMMA))), + )))), + ), + )), + )))(input) +} + fn import<'a>(input: &'a str) -> IResult<&'a str, Import> { into(skip_ws_and_comments(pair( separated_list1( @@ -74,17 +123,13 @@ fn import<'a>(input: &'a str) -> IResult<&'a str, Import> { ), preceded( skip_ws_and_comments(tag(FROM)), - skip_ws_and_comments(tuple(( - identifier, - alt(( - value(None, skip_ws_and_comments(value_identifier)), - opt(skip_ws_and_comments(object_identifier_value)), - )), + skip_ws_and_comments(pair( + global_module_reference, opt(skip_ws_and_comments(alt(( tag(WITH_SUCCESSORS), tag(WITH_DESCENDANTS), )))), - ))), + )), ), )))(input) } @@ -163,7 +208,7 @@ mod tests { FROM CPM-OriginatingStationContainers {itu-t (0) identified-organization (4) etsi (0) itsDomain (5) wg1 (1) ts (103324) originatingStationContainers (2) major-version-1 (1) minor-version-1(1)} WITH SUCCESSORS; "#).unwrap().1, - ModuleReference { name: "CPM-PDU-Descriptions".into(), module_identifier: Some(DefinitiveIdentifier::DefinitiveOID(ObjectIdentifierValue(vec![ObjectIdentifierArc { name: Some("itu-t".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(4) }, ObjectIdentifierArc { name: Some("etsi".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("itsDomain".into()), number: Some(5) }, ObjectIdentifierArc { name: Some("wg1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("ts".into()), number: Some(103324) }, ObjectIdentifierArc { name: Some("cpm".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("major-version-1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("minor-version-1".into()), number: Some(1) }]))), encoding_reference_default: None, tagging_environment: TaggingEnvironment::Automatic, extensibility_environment: ExtensibilityEnvironment::Explicit, imports: vec![Import { types: vec!["ItsPduHeader".into(), "MessageRateHz".into(), "MessageSegmentationInfo".into(), "OrdinalNumber1B".into(), "ReferencePosition".into(), "StationType".into(), "TimestampIts".into()], origin_name: "ETSI-ITS-CDD".into(), origin_identifier: Some(ObjectIdentifierValue(vec![ObjectIdentifierArc { name: Some("itu-t".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(4) }, ObjectIdentifierArc { name: Some("etsi".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("itsDomain".into()), number: Some(5) }, ObjectIdentifierArc { name: Some("wg1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("ts".into()), number: Some(102894) }, ObjectIdentifierArc { name: Some("cdd".into()), number: Some(2) }, ObjectIdentifierArc { name: Some("major-version-3".into()), number: Some(3) }, ObjectIdentifierArc { name: Some("minor-version-1".into()), number: Some(1) }])), with: Some(With::Successors) }, Import { types: vec!["OriginatingRsuContainer".into(), "OriginatingVehicleContainer".into()], origin_name: "CPM-OriginatingStationContainers".into(), origin_identifier: Some(ObjectIdentifierValue(vec![ObjectIdentifierArc { name: Some("itu-t".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(4) }, ObjectIdentifierArc { name: Some("etsi".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("itsDomain".into()), number: Some(5) }, ObjectIdentifierArc { name: Some("wg1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("ts".into()), number: Some(103324) }, ObjectIdentifierArc { name: Some("originatingStationContainers".into()), number: Some(2) }, ObjectIdentifierArc { name: Some("major-version-1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("minor-version-1".into()), number: Some(1) }])), with: Some(With::Successors) }], exports: None } ) + ModuleReference { name: "CPM-PDU-Descriptions".into(), module_identifier: Some(DefinitiveIdentifier::DefinitiveOID(ObjectIdentifierValue(vec![ObjectIdentifierArc { name: Some("itu-t".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(4) }, ObjectIdentifierArc { name: Some("etsi".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("itsDomain".into()), number: Some(5) }, ObjectIdentifierArc { name: Some("wg1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("ts".into()), number: Some(103324) }, ObjectIdentifierArc { name: Some("cpm".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("major-version-1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("minor-version-1".into()), number: Some(1) }]))), encoding_reference_default: None, tagging_environment: TaggingEnvironment::Automatic, extensibility_environment: ExtensibilityEnvironment::Explicit, imports: vec![Import { types: vec!["ItsPduHeader".into(), "MessageRateHz".into(), "MessageSegmentationInfo".into(), "OrdinalNumber1B".into(), "ReferencePosition".into(), "StationType".into(), "TimestampIts".into()], global_module_reference: GlobalModuleReference { module_reference: "ETSI-ITS-CDD".into(), assigned_identifier: AssignedIdentifier::ObjectIdentifierValue(ObjectIdentifierValue(vec![ObjectIdentifierArc { name: Some("itu-t".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(4) }, ObjectIdentifierArc { name: Some("etsi".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("itsDomain".into()), number: Some(5) }, ObjectIdentifierArc { name: Some("wg1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("ts".into()), number: Some(102894) }, ObjectIdentifierArc { name: Some("cdd".into()), number: Some(2) }, ObjectIdentifierArc { name: Some("major-version-3".into()), number: Some(3) }, ObjectIdentifierArc { name: Some("minor-version-1".into()), number: Some(1) }]))}, with: Some(With::Successors) }, Import { types: vec!["OriginatingRsuContainer".into(), "OriginatingVehicleContainer".into()], global_module_reference: GlobalModuleReference { module_reference: "CPM-OriginatingStationContainers".into(), assigned_identifier: AssignedIdentifier::ObjectIdentifierValue(ObjectIdentifierValue(vec![ObjectIdentifierArc { name: Some("itu-t".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(4) }, ObjectIdentifierArc { name: Some("etsi".into()), number: Some(0) }, ObjectIdentifierArc { name: Some("itsDomain".into()), number: Some(5) }, ObjectIdentifierArc { name: Some("wg1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("ts".into()), number: Some(103324) }, ObjectIdentifierArc { name: Some("originatingStationContainers".into()), number: Some(2) }, ObjectIdentifierArc { name: Some("major-version-1".into()), number: Some(1) }, ObjectIdentifierArc { name: Some("minor-version-1".into()), number: Some(1) }]))}, with: Some(With::Successors) }], exports: None } ) } #[test] @@ -198,18 +243,20 @@ mod tests { imports: vec![ Import { types: vec!["ALGORITHM".into(), "AlgorithmIdentifier".into()], - origin_name: "AlgorithmInformation-2009".into(), - origin_identifier: Some(ObjectIdentifierValue(vec![ - ObjectIdentifierArc { name: Some("iso".into()), number: Some(1) }, - ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(3) }, - ObjectIdentifierArc { name: Some("dod".into()), number: Some(6) }, - ObjectIdentifierArc { name: Some("internet".into()), number: Some(1) }, - ObjectIdentifierArc { name: Some("security".into()), number: Some(5) }, - ObjectIdentifierArc { name: Some("mechanisms".into()), number: Some(5) }, - ObjectIdentifierArc { name: Some("pkix".into()), number: Some(7) }, - ObjectIdentifierArc { name: Some("id-mod".into()), number: Some(0) }, - ObjectIdentifierArc { name: Some("id-mod-algorithmInformation-02".into()), number: Some(58) }, - ])), + global_module_reference: GlobalModuleReference { + module_reference: "AlgorithmInformation-2009".into(), + assigned_identifier: AssignedIdentifier::ObjectIdentifierValue(ObjectIdentifierValue(vec![ + ObjectIdentifierArc { name: Some("iso".into()), number: Some(1) }, + ObjectIdentifierArc { name: Some("identified-organization".into()), number: Some(3) }, + ObjectIdentifierArc { name: Some("dod".into()), number: Some(6) }, + ObjectIdentifierArc { name: Some("internet".into()), number: Some(1) }, + ObjectIdentifierArc { name: Some("security".into()), number: Some(5) }, + ObjectIdentifierArc { name: Some("mechanisms".into()), number: Some(5) }, + ObjectIdentifierArc { name: Some("pkix".into()), number: Some(7) }, + ObjectIdentifierArc { name: Some("id-mod".into()), number: Some(0) }, + ObjectIdentifierArc { name: Some("id-mod-algorithmInformation-02".into()), number: Some(58) }, + ])) + }, with: Some(With::Descendants) } ], exports: Some(Exports::All) @@ -233,67 +280,173 @@ mod tests { vec![ Import { types: vec!["DomainParameters".into()], - origin_name: "ANSI-X9-42".into(), - origin_identifier: Some(ObjectIdentifierValue(vec![ - ObjectIdentifierArc { - name: Some("iso".into()), - number: Some(1) - }, - ObjectIdentifierArc { - name: Some("member-body".into()), - number: Some(2) - }, - ObjectIdentifierArc { - name: Some("us".into()), - number: Some(840) - }, - ObjectIdentifierArc { - name: Some("ansi-x942".into()), - number: Some(10046) - }, - ObjectIdentifierArc { - name: Some("module".into()), - number: Some(5) - }, - ObjectIdentifierArc { - name: None, - number: Some(1) - }, - ])), + global_module_reference: GlobalModuleReference { + module_reference: "ANSI-X9-42".into(), + assigned_identifier: AssignedIdentifier::ObjectIdentifierValue( + ObjectIdentifierValue(vec![ + ObjectIdentifierArc { + name: Some("iso".into()), + number: Some(1) + }, + ObjectIdentifierArc { + name: Some("member-body".into()), + number: Some(2) + }, + ObjectIdentifierArc { + name: Some("us".into()), + number: Some(840) + }, + ObjectIdentifierArc { + name: Some("ansi-x942".into()), + number: Some(10046) + }, + ObjectIdentifierArc { + name: Some("module".into()), + number: Some(5) + }, + ObjectIdentifierArc { + name: None, + number: Some(1) + }, + ]) + ) + }, with: None }, Import { types: vec!["ECDomainParameters".into()], - origin_name: "ANSI-X9-62".into(), - origin_identifier: Some(ObjectIdentifierValue(vec![ - ObjectIdentifierArc { - name: Some("iso".into()), - number: Some(1) - }, - ObjectIdentifierArc { - name: Some("member-body".into()), - number: Some(2) - }, - ObjectIdentifierArc { - name: Some("us".into()), - number: Some(840) - }, - ObjectIdentifierArc { - name: None, - number: Some(10045) - }, - ObjectIdentifierArc { - name: Some("modules".into()), - number: Some(0) - }, - ObjectIdentifierArc { - name: None, - number: Some(2) - }, - ])), + global_module_reference: GlobalModuleReference { + module_reference: "ANSI-X9-62".into(), + assigned_identifier: AssignedIdentifier::ObjectIdentifierValue( + ObjectIdentifierValue(vec![ + ObjectIdentifierArc { + name: Some("iso".into()), + number: Some(1) + }, + ObjectIdentifierArc { + name: Some("member-body".into()), + number: Some(2) + }, + ObjectIdentifierArc { + name: Some("us".into()), + number: Some(840) + }, + ObjectIdentifierArc { + name: None, + number: Some(10045) + }, + ObjectIdentifierArc { + name: Some("modules".into()), + number: Some(0) + }, + ObjectIdentifierArc { + name: None, + number: Some(2) + }, + ]) + ) + }, with: None } ] ) } + + #[test] + fn global_module_reference_empty_assigned_identifier() { + assert_eq!( + global_module_reference(r#" EMPTY-assigned-ID next-module-import, "#).unwrap(), + ( + " next-module-import, ", + GlobalModuleReference { + module_reference: "EMPTY-assigned-ID".to_owned(), + assigned_identifier: AssignedIdentifier::Empty + } + ) + ) + } + + #[test] + fn global_module_reference_val_ref_assigned_identifier() { + assert_eq!( + global_module_reference(r#" VALref-assigned-ID valref next-module-import,"#) + .unwrap() + .1, + GlobalModuleReference { + module_reference: "VALref-assigned-ID".to_owned(), + assigned_identifier: AssignedIdentifier::ValueReference("valref".to_owned()) + } + ) + } + + #[test] + fn global_module_reference_ext_val_ref_assigned_identifier() { + assert_eq!( + global_module_reference( + r#" ext-VALref-assigned-ID MODULE-ref.valref next-module-import,"# + ) + .unwrap() + .1, + GlobalModuleReference { + module_reference: "ext-VALref-assigned-ID".to_owned(), + assigned_identifier: AssignedIdentifier::ExternalValueReference( + ExternalValueReference { + module_reference: "MODULE-ref".to_owned(), + value_reference: "valref".to_owned() + } + ) + } + ) + } + + #[test] + fn issue_4_imports() { + assert_eq!( + imports( + r#"IMPORTS + + Criticality, + Presence, + PrivateIE-ID, + ProtocolExtensionID, + ProtocolIE-ID + FROM NGAP-CommonDataTypes + + maxPrivateIEs, + maxProtocolExtensions, + maxProtocolIEs + FROM NGAP-Constants;"# + ) + .unwrap() + .1, + vec![ + Import { + types: vec![ + "Criticality".to_owned(), + "Presence".to_owned(), + "PrivateIE-ID".to_owned(), + "ProtocolExtensionID".to_owned(), + "ProtocolIE-ID".to_owned(), + ], + global_module_reference: GlobalModuleReference { + module_reference: "NGAP-CommonDataTypes".to_owned(), + assigned_identifier: AssignedIdentifier::Empty + }, + with: None + }, + Import { + types: vec![ + "maxPrivateIEs".to_owned(), + "maxProtocolExtensions".to_owned(), + "maxProtocolIEs".to_owned() + ], + global_module_reference: GlobalModuleReference { + module_reference: "NGAP-Constants".to_owned(), + assigned_identifier: AssignedIdentifier::Empty + }, + with: None + } + ] + ); + } } diff --git a/rasn-compiler/src/validator/linking/information_object.rs b/rasn-compiler/src/validator/linking/information_object.rs index ec9efa7..23983e2 100644 --- a/rasn-compiler/src/validator/linking/information_object.rs +++ b/rasn-compiler/src/validator/linking/information_object.rs @@ -35,7 +35,7 @@ impl ToplevelInformationDefinition { } (ASN1Information::ObjectSet(ref mut o), Some(ClassLink::ByReference(class))) => { o.values.iter_mut().try_for_each(|value| match value { - ObjectSetValue::Reference(_) => todo!(), + ObjectSetValue::Reference(_) => Err(GrammarError { details: "Collecting supertypes of information object set values is currently unsupported!".into(), kind: GrammarErrorType::NotYetInplemented }), ObjectSetValue::Inline(ref mut fields) => { resolve_custom_syntax(fields, class)?; link_object_fields(fields, class, tlds)