rasn-compiler 0.16.0

An ASN.1 compiler producing bindings for the rasn framework
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
use crate::{
    input::{context_boundary, Input},
    intermediate::*,
};
use nom::{
    branch::alt,
    bytes::complete::{tag, take_until},
    character::complete::{char, one_of},
    combinator::{into, map, not, opt, peek, recognize, value},
    multi::{many0, many1, separated_list1},
    sequence::{delimited, pair, preceded, separated_pair, terminated},
    Parser,
};

use super::{
    common::{identifier, skip_ws, skip_ws_and_comments, value_reference},
    error::ParserResult,
    in_braces, into_inner,
    object_identifier::object_identifier_value,
};

pub fn module_header(input: Input<'_>) -> ParserResult<'_, ModuleHeader> {
    skip_ws_and_comments(into((
        identifier,
        opt(skip_ws(definitive_identification)),
        skip_ws_and_comments(delimited(
            tag(DEFINITIONS),
            opt(environments),
            skip_ws_and_comments(pair(tag(ASSIGN), skip_ws_and_comments(tag(BEGIN)))),
        )),
        context_boundary(opt(exports)),
        context_boundary(opt(imports)),
    )))
    .parse(input)
}

fn definitive_identification(input: Input<'_>) -> ParserResult<'_, DefinitiveIdentifier> {
    into(pair(object_identifier_value, opt(iri_value))).parse(input)
}

fn iri_value(input: Input<'_>) -> ParserResult<'_, &str> {
    into_inner(skip_ws_and_comments(delimited(
        tag("\"/"),
        recognize(separated_list1(char('/'), unicode_label)),
        char('"'),
    )))
    .parse(input)
}

fn unicode_label(input: Input<'_>) -> ParserResult<'_, &str> {
    skip_ws_and_comments(into_inner(recognize(many1(one_of(
        "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890-_~.",
    )))))
    .parse(input)
}

fn exports(input: Input<'_>) -> ParserResult<'_, Exports> {
    skip_ws_and_comments(delimited(
        tag(EXPORTS),
        skip_ws(alt((
            value(Exports::All, tag(ALL)),
            into(separated_list1(
                skip_ws(char(COMMA)),
                skip_ws(alt((parameterized_identifier, identifier))),
            )),
        ))),
        char(SEMICOLON),
    ))
    .parse(input)
}

fn imports(input: Input<'_>) -> ParserResult<'_, Vec<Import>> {
    skip_ws_and_comments(delimited(
        tag(IMPORTS),
        skip_ws_and_comments(many0(import)),
        skip_ws_and_comments(char(SEMICOLON)),
    ))
    .parse(input)
}

fn parameterized_identifier(input: Input<'_>) -> ParserResult<'_, &str> {
    terminated(identifier, tag("{}")).parse(input)
}

fn global_module_reference(input: Input<'_>) -> ParserResult<'_, 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_reference)),
                |(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_reference,
                    skip_ws(recognize(in_braces(take_until("}")))),
                )),
                |(v, p)| AssignedIdentifier::ParameterizedValue {
                    value_reference: v.to_owned(),
                    actual_parameter_list: p.inner().to_owned(),
                },
            ),
            map(
                skip_ws_and_comments(terminated(
                    value_reference,
                    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))),
                )))),
            ),
        )),
    )))
    .parse(input)
}

fn import(input: Input<'_>) -> ParserResult<'_, Import> {
    into(skip_ws_and_comments(pair(
        separated_list1(
            skip_ws(char(COMMA)),
            skip_ws(alt((parameterized_identifier, identifier))),
        ),
        preceded(
            skip_ws_and_comments(tag(FROM)),
            skip_ws_and_comments(pair(
                global_module_reference,
                opt(into_inner(skip_ws_and_comments(alt((
                    tag(WITH_SUCCESSORS),
                    tag(WITH_DESCENDANTS),
                ))))),
            )),
        ),
    )))
    .parse(input)
}

fn environments(
    input: Input<'_>,
) -> ParserResult<
    '_,
    (
        Option<EncodingReferenceDefault>,
        TaggingEnvironment,
        ExtensibilityEnvironment,
    ),
> {
    (
        opt(skip_ws_and_comments(into(terminated(
            identifier,
            into_inner(skip_ws(tag(INSTRUCTIONS))),
        )))),
        skip_ws_and_comments(map(
            opt(terminated(
                into_inner(alt((tag(AUTOMATIC), tag(IMPLICIT), tag(EXPLICIT)))),
                skip_ws(tag(TAGS)),
            )),
            |m| match m {
                Some(AUTOMATIC) => TaggingEnvironment::Automatic,
                Some(EXPLICIT) => TaggingEnvironment::Explicit,
                _ => TaggingEnvironment::Implicit,
            },
        )),
        skip_ws_and_comments(map(opt(tag(EXTENSIBILITY_IMPLIED)), |m| {
            if m.is_some() {
                ExtensibilityEnvironment::Implied
            } else {
                ExtensibilityEnvironment::Explicit
            }
        })),
    )
        .parse(input)
}

#[cfg(test)]
mod tests {
    use std::vec;

    use crate::lexer::module_header::*;

    #[test]
    fn parses_a_module_header() {
        assert_eq!(module_header(r#"--! @options: no-fields-header

    ETSI-ITS-CDD {itu-t (0) identified-organization (4) etsi (0) itsDomain (5) wg1 (1) 102894 cdd (2) major-version-3 (3) minor-version-1 (1)}

    DEFINITIONS AUTOMATIC TAGS ::=

    BEGIN
    "#.into()).unwrap().1,
    ModuleHeader {name:"ETSI-ITS-CDD".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:None,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)}]))),encoding_reference_default:None,tagging_environment:crate::intermediate::TaggingEnvironment::Automatic,extensibility_environment:crate::intermediate::ExtensibilityEnvironment::Explicit, imports: vec![], exports: None }
  )
    }

    #[test]
    fn parses_a_module_header_with_imports() {
        assert_eq!(module_header(r#"CPM-PDU-Descriptions { itu-t (0) identified-organization (4) etsi (0) itsDomain (5) wg1 (1) ts (103324) cpm (1) major-version-1 (1) minor-version-1(1)}

        DEFINITIONS AUTOMATIC TAGS ::=

        BEGIN

        IMPORTS

        ItsPduHeader, MessageRateHz, MessageSegmentationInfo, OrdinalNumber1B,  ReferencePosition, StationType, TimestampIts
        FROM ETSI-ITS-CDD {itu-t (0) identified-organization (4) etsi (0) itsDomain (5) wg1 (1) ts (102894) cdd (2) major-version-3 (3) minor-version-1 (1)}
        WITH SUCCESSORS

        OriginatingRsuContainer, OriginatingVehicleContainer
        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;
    "#.into()).unwrap().1,
    ModuleHeader { 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]
    fn parses_iri_value() {
        assert_eq!(module_header(r#"CMSCKMKeyManagement {itu-t recommendation(0) x(24) cms-profile(894) module(0) cKMKeyManagement(1) version1(1)}
        "/ITU-T/Recommendation/X/CMS-Profile/Module/CKMKeyManagement/Version1"
        DEFINITIONS ::=
        BEGIN
        EXPORTS ALL;
        IMPORTS
        ALGORITHM,AlgorithmIdentifier{}
        FROM AlgorithmInformation-2009
        {iso(1) identified-organization(3) dod(6) internet(1) security(5)
        mechanisms(5) pkix(7) id-mod(0) id-mod-algorithmInformation-02(58)} WITH DESCENDANTS;"#.into()).unwrap().1,
        ModuleHeader {
            name: "CMSCKMKeyManagement".into(),
            module_identifier: Some(DefinitiveIdentifier::DefinitiveOIDandIRI {
                oid: ObjectIdentifierValue(vec![
                    ObjectIdentifierArc { name: Some("itu-t".into()), number: None },
                    ObjectIdentifierArc { name: Some("recommendation".into()), number: Some(0) },
                    ObjectIdentifierArc { name: Some("x".into()), number: Some(24) },
                    ObjectIdentifierArc { name: Some("cms-profile".into()), number: Some(894) },
                    ObjectIdentifierArc { name: Some("module".into()), number: Some(0) },
                    ObjectIdentifierArc { name: Some("cKMKeyManagement".into()), number: Some(1) },
                    ObjectIdentifierArc { name: Some("version1".into()), number: Some(1) },
                ]),
                iri: "ITU-T/Recommendation/X/CMS-Profile/Module/CKMKeyManagement/Version1".into()
            }),
            encoding_reference_default: None,
            tagging_environment: TaggingEnvironment::Implicit,
            extensibility_environment: ExtensibilityEnvironment::Explicit,
            imports: vec![
                Import {
                    types: vec!["ALGORITHM".into(), "AlgorithmIdentifier".into()],
                    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)
        })
    }

    #[test]
    fn parses_imports() {
        assert_eq!(
            imports(
                r#"IMPORTS
            DomainParameters
            FROM ANSI-X9-42
            {iso(1) member-body(2) us(840) ansi-x942(10046) module(5) 1}
            ECDomainParameters
            FROM ANSI-X9-62
            {iso(1) member-body(2) us(840) 10045 modules(0) 2};"#
                    .into()
            )
            .unwrap()
            .1,
            vec![
                Import {
                    types: vec!["DomainParameters".into()],
                    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()],
                    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, "#.into()).unwrap(),
            (
                Input::from(" next-module-import, ").with_line_column_and_offset(1, 19, 18),
                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,"#.into())
                .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,"#.into()
            )
            .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;"#
                    .into()
            )
            .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
                }
            ]
        );
    }
}