rpsl 0.1.1

A parser for the Routing Policy Specification Language (RPSL)
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
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
WHITESPACE      = _{ " " | "\t" | ( NEWLINE  ~ line_cont ) }
    line_cont   = _{ " " | "\t" | "+" }
COMMENT         = _{ "#" ~ ( !NEWLINE ~ ANY )* }

// ** RPSL character classes **
char            = { ASCII_ALPHANUMERIC }
extchar         = { char | "_" | "-" }
num             = @{ ASCII_DIGIT+ }

// ** RPSL keywords **
keyword         = { ( any_fltr | any_as | any_rs | peeras
                    | and | or | not
                    | atomic | from | to | at | action | accept | announce | except | refine
                    | networks | into | inbound | outbound )
                  ~ !( extchar | ".") }
    // Special names
    any_fltr    = @{ ^"ANY" }
    any_as      = @{ ^"AS-ANY" }
    any_rs      = @{ ^"RS-ANY" }
    peeras      = @{ ^"PeerAS" }
    // set operators
    and         = _{ ^"AND" }
    or          = _{ ^"OR" }
    not         = _{ ^"NOT" }
    // policy keywords
    atomic      = @{ ^"ATOMIC" }
    from        = _{ ^"FROM" }
    to          = _{ ^"TO" }
    at          = _{ ^"AT" }
    action      = _{ ^"ACTION" }
    accept      = _{ ^"ACCEPT" }
    announce    = _{ ^"ANNOUNCE" }
    except      = _{ ^"EXCEPT" }
    refine      = _{ ^"REFINE" }
    networks    = _{ ^"NETWORKS" }
    into        = _{ ^"INTO" }
    inbound     = _{ ^"INBOUND" }
    outbound    = _{ ^"OUTBOUND" }


// ** RPSL object names **
basic_name          = @{ !keyword ~ ( char ~ extchar* ) }
// special object names
special_name        = _{ as_set_name | route_set_name | rtr_set_name
                       | filter_set_name | peering_set_name }
    // aut-num name
    aut_num         = ${ ^"AS" ~ num }
    // set names
    set_comp        = _{ aut_num | peeras }
    as_set          = ${ ( set_comp ~ ":" )* ~ as_set_name ~ ( ":" ~ ( set_comp | as_set_name ) )* }
        as_set_name         = @{ !keyword ~ ^"AS-" ~ extchar+ }
    route_set       = ${ ( set_comp ~ ":" )* ~ route_set_name ~ ( ":" ~ ( set_comp | route_set_name ) )* }
        route_set_name      = @{ !keyword ~ ^"RS-" ~ extchar+ }
    rtr_set         = ${ ( set_comp ~ ":" )* ~ rtr_set_name ~ ( ":" ~ ( set_comp | rtr_set_name ) )* }
        rtr_set_name        = @{ !keyword ~ ^"RTRS-" ~ extchar+ }
    filter_set      = ${ ( set_comp ~ ":" )* ~ filter_set_name ~ ( ":" ~ ( set_comp | filter_set_name ) )* }
        filter_set_name     = @{ !keyword ~ ^"FLTR-" ~ extchar+ }
    peering_set     = ${ ( set_comp ~ ":" )* ~ peering_set_name ~ ( ":" ~ ( set_comp | peering_set_name ) )* }
        peering_set_name    = @{ !keyword ~ ^"PRNG-" ~ extchar+ }
// general object names
general_object_name = @{ !special_name ~ basic_name }
mntner_name         = @{ general_object_name }
person              = @{ free_form }
role                = @{ free_form }
dictionary          = @{ general_object_name }
inet_rtr            = @{ !keyword ~ dns_name }
key_cert            = _{ key_cert_pgp | key_cert_x509 }
    key_cert_pgp    = @{ ^"PGPKEY-" ~ ASCII_HEX_DIGIT+ }
    key_cert_x509   = @{ ^"X509-" ~ num }
as_block            =  { aut_num ~ "-" ~ aut_num }
inetnum             =  { ipv4_addr ~ "-" ~ ipv4_addr }
inet6num            =  { ipv6_addr ~ "-" ~ ipv6_addr }
route               =  { ipv4_prefix }
route6              =  { ipv6_prefix }
// object keys
rpsl_object_key     = _{ mntner_name | nic_hdl | as_set | route_set | rtr_set
                       | filter_set | peering_set | dictionary | inet_rtr
                       | key_cert | as_block | inetnum | inet6num
                       | route_key | route6_key }
    route_key       = ${ ipv4_prefix ~ ( " " | "-" )? ~ aut_num }
    route6_key      = ${ ipv6_prefix ~ ( " " | "-" )? ~ aut_num }

// ** RPSL IP address values **
ipv4_prefix     = @{ ipv4_addr ~ "/" ~ ipv4_prefix_len }
    ipv4_addr           = @{ ipv4_oct ~ ( "." ~ ipv4_oct ){3} }
    ipv4_oct            = @{ ASCII_DIGIT{1,3} }
    ipv4_prefix_len     = @{ ASCII_DIGIT{1,2} }
ipv6_prefix     = @{ ipv6_addr ~ "/" ~ ipv6_prefix_len }
    ipv6_addr           = @{ ipv6_mapped_ipv4_addr
                           |                                            ( ipv6_seg ~ ":" ){ 7} ~ ipv6_seg
                           |                                     "::" ~ ( ipv6_seg ~ ":" ){,6} ~ ipv6_seg
                           | ipv6_seg ~                          "::" ~ ( ipv6_seg ~ ":" ){,5} ~ ipv6_seg
                           | ipv6_seg ~ ( ":" ~ ipv6_seg ){,1} ~ "::" ~ ( ipv6_seg ~ ":" ){,4} ~ ipv6_seg
                           | ipv6_seg ~ ( ":" ~ ipv6_seg ){,2} ~ "::" ~ ( ipv6_seg ~ ":" ){,3} ~ ipv6_seg
                           | ipv6_seg ~ ( ":" ~ ipv6_seg ){,3} ~ "::" ~ ( ipv6_seg ~ ":" ){,2} ~ ipv6_seg
                           | ipv6_seg ~ ( ":" ~ ipv6_seg ){,4} ~ "::" ~ ( ipv6_seg ~ ":" ){,1} ~ ipv6_seg
                           | ipv6_seg ~ ( ":" ~ ipv6_seg ){,5} ~ "::" ~                          ipv6_seg
                           | ipv6_seg ~ ( ":" ~ ipv6_seg ){,6} ~ "::"
                           |                                     "::" }
    ipv6_mapped_ipv4_addr   = @{ ^"::ffff:" ~ ipv4_addr }
    ipv6_seg            = @{ ASCII_HEX_DIGIT{1,4} }
    ipv6_prefix_len     = @{ ASCII_DIGIT{1,3} }

// ** RPSL range operators **
range_op                = _{ range | exact | less_excl | less_incl }
    range               = ${ "^" ~ num ~ "-" ~ num }
    exact               = ${ "^" ~ num }
    less_excl           = @{ "^-" }
    less_incl           = @{ "^+" }

// ** RPSL IP address prefix range types
ipv4_prefix_range       = ${ ipv4_prefix ~ range_op? }
ipv6_prefix_range       = ${ ipv6_prefix ~ range_op? }

// ** RPSL miscellaneous syntax types **
free_form               = @{ ( !attr_sep ~ ANY )* }
    attr_sep            = @{ NEWLINE ~ ( !line_cont ~ ( ANY | EOI ) ) }
date                    = ${ year ~ month ~ day }
    year                = @{ ASCII_DIGIT{4} }
    month               = @{ ( "0" ~ '1'..'9' )
                           | ( "1" ~ '0'..'2' ) }
    day                 = @{ ( "0"      ~ '1'..'9' )
                           | ( '1'..'2' ~ '0'..'9' )
                           | ( "3"      ~ '0'..'1' ) }
dns_name                = @{ ASCII_ALPHA ~ ( ASCII_ALPHANUMERIC | "-" | "_")* ~ ( "." ~ dns_name )? }
email_addr              = @{ dns_name ~ "@" ~ dns_name }
nic_hdl                 = @{ general_object_name }
registry_name           = @{ general_object_name }
as_name                 = @{ general_object_name }
netname                 = @{ general_object_name }
tel_number              = @{ "+" ~ ASCII_DIGIT ~ ( ASCII_DIGIT | " " )* ~ ( ^"ext. " ~ ASCII_DIGIT+ )? }
object_descr            = @{ free_form }
remarks                 = @{ free_form }
address                 = @{ free_form }
trouble                 = @{ free_form }
owner                   = @{ free_form }
protocol_name           = _{ protocol_bgp4 | protocol_mpbgp
                           | protocol_ospf | protocol_isis
                           | protocol_ripng | protocol_rip
                           | protocol_igrp | protocol_static
                           | protocol_ripng | protocol_dvmrp
                           | protocol_pim_dm | protocol_pim_sm
                           | protocol_cbt | protocol_mospf
                           | protocol_unknown }
    protocol_bgp4       = @{ ^"BGP4" }
    protocol_mpbgp      = @{ ^"MPBGP" }
    protocol_ospf       = @{ ^"OSPF" }
    protocol_ripng      = @{ ^"RIPng" }
    protocol_rip        = @{ ^"RIP" }
    protocol_igrp       = @{ ^"IGRP" }
    protocol_isis       = @{ ^"IS-IS" }
    protocol_static     = @{ ^"STATIC" }
    protocol_dvmrp      = @{ ^"DVMRP" }
    protocol_pim_dm     = @{ ^"PIM-DM" }
    protocol_pim_sm     = @{ ^"PIM-SM" }
    protocol_cbt        = @{ ^"CBT" }
    protocol_mospf      = @{ ^"MOSPF" }
    protocol_unknown    = @{ general_object_name }
afi_safi                = ${ afi ~ ( "." ~ safi )? }
    afi                 = _{ afi_any | afi_ipv4 | afi_ipv6 }
        afi_any         = @{ ^"any" }
        afi_ipv4        = @{ ^"ipv4" }
        afi_ipv6        = @{ ^"ipv6" }
    safi                = _{ safi_unicast | safi_multicast }
        safi_unicast    = @{ ^"unicast" }
        safi_multicast  = @{ ^"multicast" }
named_route_set_member  = _{ route_set | as_set | any_as | any_rs | aut_num }
email_addr_regexp   = @{ free_form }
pgp_from_fingerpr   = @{ free_form }
crypt_hash          = @{ free_form }
key_fingerprint     = { ASCII_HEX_DIGIT+ }
key_certif          = @{ free_form }
signing_method      = _{ signing_method_pgp | signing_method_x509 }
    signing_method_pgp  = @{ ^"PGP" }
    signing_method_x509 = @{ ^"X509" }
encapsulation       = _{ encapsulation_gre | encapsulation_ipip }
    encapsulation_gre   = @{ ^"GRE" }
    encapsulation_ipip  = @{ ^"IPinIP" }
country_code        = @{ ASCII_ALPHA{2} }

// ** RPSL expressions **
// choices
ip_addr_choice              = @{ ipv4_addr | ipv6_addr }
ip_prefix_choice            = @{ ipv4_prefix | ipv6_prefix }
ip_prefix_range_choice      = _{ ipv4_prefix_range | ipv6_prefix_range }
as_set_member_choice        = _{ as_set | aut_num }
route_set_member_choice     = ${ ( ipv4_prefix | named_route_set_member ) ~ range_op? }
route_set_mp_member_choice  = ${ ( ip_prefix_choice | named_route_set_member ) ~ range_op? }
rtr_set_member_choice       = _{ rtr_set | ipv4_addr | inet_rtr }
rtr_set_mp_member_choice    = _{ rtr_set | ip_addr_choice | inet_rtr }

// lists
mntner_name_list            =  { mntner_name                 ~ ( "," ~ mntner_name )* }
route_set_list              = _{ route_set                   ~ ( "," ~ route_set )* }
ipv4_prefix_list            = _{ ipv4_prefix                 ~ ( "," ~ ipv4_prefix )* }
ipv4_prefix_range_list      =  { ipv4_prefix_range           ~ ( "," ~ ipv4_prefix_range )* }
ipv6_prefix_list            = _{ ipv6_prefix                 ~ ( "," ~ ipv6_prefix )* }
ipv6_prefix_range_list      =  { ipv6_prefix_range           ~ ( "," ~ ipv6_prefix_range )* }
ip_prefix_range_list        =  { ip_prefix_range_choice      ~ ( "," ~ ip_prefix_range_choice )* }
as_set_members_list         = _{ as_set_member_choice        ~ ( "," ~ as_set_member_choice )* }
route_set_members_list      = _{ route_set_member_choice     ~ ( "," ~ route_set_member_choice )* }
route_set_mp_members_list   = _{ route_set_mp_member_choice  ~ ( "," ~ route_set_mp_member_choice )* }
rtr_set_members_list        = _{ rtr_set_member_choice       ~ ( "," ~ rtr_set_member_choice )* }
rtr_set_mp_members_list     = _{ rtr_set_mp_member_choice    ~ ( "," ~ rtr_set_mp_member_choice )* }
as_set_list                 = _{ as_set                      ~ ( "," ~ as_set )* }
rtr_set_list                = _{ rtr_set                     ~ ( "," ~ rtr_set )* }
afi_safi_list               =  { afi_safi                    ~ ( "," ~ afi_safi )* }

// complex expressions
changed_expr            = { email_addr ~ date }

auth_expr               = _{ auth_expr_none | auth_expr_mail
                           | auth_expr_pgp_from | auth_expr_crypt
                           | auth_expr_person | auth_expr_role
                           | auth_expr_key_cert }
    auth_expr_none      = { ^"NONE" }
    auth_expr_mail      = { ^"MAIL-FROM" ~ email_addr_regexp }
    auth_expr_pgp_from  = { ^"PGP-FROM" ~ pgp_from_fingerpr }
    auth_expr_crypt     = { ^"CRYPT-PW" ~ crypt_hash }
    auth_expr_person    = { ^"PERSON" ~ person }
    auth_expr_role      = { ^"ROLE" ~ role }
    auth_expr_key_cert  = { key_cert }

action_expr             = { ( action_stmt ~ ";" )+ }
    action_stmt         = _{ action_stmt_oper | action_stmt_meth }
        action_stmt_oper    = { action_prop ~ action_op ~ action_val }
        action_stmt_meth    = ${ action_prop ~ ( "." ~ action_meth )? ~ "(" ~ action_val_list ~ ")" }
            action_prop     = _{ rp_pref | rp_med | rp_dpa | rp_aspath
                               | rp_community | rp_next_hop | rp_cost
                               | rp_unknown }
                rp_pref         = @{ ^"pref" ~ &action_prop_term }
                rp_med          = @{ ^"med" ~ &action_prop_term }
                rp_dpa          = @{ ^"dpa" ~ &action_prop_term }
                rp_aspath       = @{ ^"aspath" ~ &action_prop_term }
                rp_community    = @{ ^"community" ~ &action_prop_term }
                rp_next_hop     = @{ ^"next-hop" ~ &action_prop_term }
                rp_cost         = @{ ^"cost" ~ &action_prop_term }
                    // This is a hack to ensure that parsing doesn't fail
                    // when an unknown property name that begins with a
                    // known property name (e.g. "preference").
                    action_prop_term    = _{ WHITESPACE | "." | "(" | action_op }
                rp_unknown      = @{ basic_name }
            action_op       = _{ action_op_lsh_assign | action_op_rsh_assign
                               | action_op_add_assign | action_op_sub_assign
                               | action_op_mul_assign | action_op_div_assign
                               | action_op_eq | action_op_ne
                               | action_op_le | action_op_ge
                               | action_op_lt | action_op_gt
                               | action_op_assign | action_op_append }
                action_op_assign        = @{ "=" }
                action_op_append        = @{ ".=" }
                action_op_lsh_assign    = @{ "<<=" }
                action_op_rsh_assign    = @{ ">>=" }
                action_op_add_assign    = @{ "+=" }
                action_op_sub_assign    = @{ "-=" }
                action_op_mul_assign    = @{ "*=" }
                action_op_div_assign    = @{ "/=" }
                action_op_eq            = @{ "==" }
                action_op_ne            = @{ "!=" }
                action_op_le            = @{ "<=" }
                action_op_ge            = @{ ">=" }
                action_op_lt            = @{ "<" }
                action_op_gt            = @{ ">" }
            action_val_list = !{ action_val? ~ ( "," ~ action_val )* }
                action_val      = _{ action_val_nested | action_val_unit }
                    action_val_nested   =  { "{" ~ action_val_list ~ "}" }
                    action_val_unit     = @{ ( !( "}" | "," | ")" | ";" | WHITESPACE | NEWLINE ) ~ ANY )+ }
            action_meth     = @{ basic_name }

inject_expr             = { ( at ~ rtr_expr )? ~ ( action ~ action_expr )? ~ ( ^"upon" ~ inject_cond )? }
    inject_cond         = _{ inject_cond_and | inject_cond_or | inject_cond_unit }
        inject_cond_and         = { inject_cond_term ~ and ~ inject_cond_term }
        inject_cond_or          = { inject_cond_term ~ or ~ inject_cond_term }
        inject_cond_unit        = { inject_cond_term }
            inject_cond_term    = _{ inject_cond_term_have | inject_cond_term_excl | inject_cond_term_stat }
                inject_cond_term_have   = { ^"have-components" ~ "{" ~ ipv4_prefix_range_list ~ "}" }
                inject_cond_term_excl   = { ^"exclude" ~ "{" ~ ipv4_prefix_range_list ~ "}" }
                inject_cond_term_stat   = { ^"static" }

inject6_expr            = { ( at ~ mp_rtr_expr )? ~ ( action ~ action_expr )? ~ ( ^"upon" ~ inject6_cond )? }
    inject6_cond        = _{ inject6_cond_and | inject6_cond_or | inject6_cond_unit }
        inject6_cond_and        = { inject6_cond_term ~ and ~ inject6_cond_term }
        inject6_cond_or         = { inject6_cond_term ~ or ~ inject6_cond_term }
        inject6_cond_unit       = { inject6_cond_term }
            inject6_cond_term   = _{ inject6_cond_term_have | inject6_cond_term_excl | inject6_cond_term_stat }
                inject6_cond_term_have  = { ^"have-components" ~ "{" ~ ipv6_prefix_range_list ~ "}" }
                inject6_cond_term_excl  = { ^"exclude" ~ "{" ~ ipv6_prefix_range_list ~ "}" }
                inject6_cond_term_stat  = { ^"static" }

components_expr         = { atomic? ~ filter_expr? ~ components_proto_terms }
    components_proto_terms  = { components_proto_term* }
        components_proto_term   = { ^"protocol" ~ protocol_name ~ filter_expr }

components6_expr        = { atomic? ~ mp_filter_expr? ~ components6_proto_terms }
    components6_proto_terms = { components6_proto_term* }
        components6_proto_term  = { ^"protocol" ~ protocol_name ~ mp_filter_expr }

named_prefix_set        = { route_set | as_set | any_as | any_rs | aut_num | peeras }

as_path_regexpr         = { "<" ~ as_path_regexpr_soi? ~ as_path_regexpr_elem* ~ as_path_regexpr_eoi? ~ ">" }
    as_path_regexpr_soi     = @{ "^" }
    as_path_regexpr_eoi     = @{ "$" }
    as_path_regexpr_elem    = ${ as_path_regexpr_component ~ as_path_regexpr_op? }
        as_path_regexpr_component   = _{ as_path_set | as_path_set_compl
                                       | as_path_regexpr_alt
                                       | as_set | aut_num | as_path_any }
            as_path_any                 = @{ "." }
            as_path_set                 = !{ "[" ~ ( as_set | as_path_set_range | aut_num )+ ~ "]" }
            as_path_set_compl           = !{ "[" ~ "^" ~ ( as_set | as_path_set_range | aut_num )+ ~ "]" }
                as_path_set_range           = ${ aut_num ~ "-" ~ aut_num }
            as_path_regexpr_alt         = !{ "(" ~ as_path_regexpr_elem ~ "|" ~ as_path_regexpr_elem ~ ")" }
        as_path_regexpr_op          = _{ as_path_regexpr_opt
                                       | as_path_regexpr_any | as_path_regexpr_multi
                                       | as_path_regexpr_atleast | as_path_regexpr_atmost
                                       | as_path_regexpr_range
                                       | as_path_regexpr_any_same | as_path_regexpr_multi_same
                                       | as_path_regexpr_atleast_same | as_path_regexpr_atmost_same
                                       | as_path_regexpr_range_same }
            as_path_regexpr_opt             = @{ "?" }
            as_path_regexpr_any             = @{ "*" }
            as_path_regexpr_multi           = @{ "+" }
            as_path_regexpr_atleast         = ${ "{" ~ num ~ "," ~ "}" }
            as_path_regexpr_atmost          = ${ "{" ~ "," ~ num ~ "}" }
            as_path_regexpr_range           = ${ "{" ~ num ~ "," ~ num ~ "}" }
            as_path_regexpr_any_same        = @{ "~*" }
            as_path_regexpr_multi_same      = @{ "~+" }
            as_path_regexpr_atleast_same    = ${ "~{" ~ num ~ "," ~ "}" }
            as_path_regexpr_atmost_same     = ${ "~{" ~ "," ~ num ~ "}" }
            as_path_regexpr_range_same      = ${ "~{" ~ num ~ "," ~ num ~ "}" }

filter_expr             = _{ filter_expr_and | filter_expr_or | filter_expr_not | filter_expr_unit }
    filter_expr_and     = { filter_term ~ and ~ filter_expr }
    filter_expr_or      = { filter_term ~ or? ~ filter_expr }
    filter_expr_not     = { not ~ filter_expr }
    filter_expr_unit    = { filter_term }
        filter_term     = _{ any_fltr | named_filter | literal_filter | "(" ~ filter_expr ~ ")" }
            named_filter        = { filter_set }
            literal_filter      = { ranged_prefix_set | as_path_regexpr | action_stmt }
                ranged_prefix_set   = ${ prefix_set ~ range_op? }
                    prefix_set      = _{ literal_prefix_set | named_prefix_set }
                        literal_prefix_set  = !{ "{" ~ ranged_prefix? ~ ( "," ~ ranged_prefix )* ~ ","? ~ "}" }
                            ranged_prefix   = ${ ipv4_prefix ~ range_op? }

mp_filter_expr          = _{ mp_filter_expr_and | mp_filter_expr_or | mp_filter_expr_not | mp_filter_expr_unit }
    mp_filter_expr_and  = { mp_filter_term ~ and ~ mp_filter_expr }
    mp_filter_expr_or   = { mp_filter_term ~ or? ~ mp_filter_expr }
    mp_filter_expr_not  = { not ~ mp_filter_expr }
    mp_filter_expr_unit = { mp_filter_term }
        mp_filter_term  = _{ any_fltr | mp_named_filter | mp_literal_filter | "(" ~ mp_filter_expr ~ ")" }
            mp_named_filter     = { filter_set }
            mp_literal_filter   = { mp_ranged_prefix_set | as_path_regexpr | action_stmt }
                mp_ranged_prefix_set    = ${ mp_prefix_set ~ range_op? }
                    mp_prefix_set       = _{ mp_literal_prefix_set | named_prefix_set }
                        mp_literal_prefix_set   = !{ "{" ~ mp_ranged_prefix? ~ ( "," ~ mp_ranged_prefix )* ~ ","? ~ "}" }
                            mp_ranged_prefix    = ${ ( ipv4_prefix | ipv6_prefix ) ~ range_op? }

peering_expr            = _{ peering_expr_named | peering_expr_literal }
    peering_expr_named      = { peering_set }
    peering_expr_literal    = { as_expr ~ ( remote_rtr_expr )? ~ ( at ~ local_rtr_expr )? }
        remote_rtr_expr     = { rtr_expr }
        local_rtr_expr      = { rtr_expr }

mp_peering_expr         = _{ mp_peering_expr_named | mp_peering_expr_literal }
    mp_peering_expr_named   = { peering_set }
    mp_peering_expr_literal = { as_expr ~ ( remote_mp_rtr_expr )? ~ ( at ~ local_mp_rtr_expr )? }
        remote_mp_rtr_expr  = { mp_rtr_expr }
        local_mp_rtr_expr   = { mp_rtr_expr }

as_expr                 = _{ as_expr_and | as_expr_or | as_expr_except | as_expr_unit }
    as_expr_and         = { as_expr_term ~ and ~ as_expr }
    as_expr_or          = { as_expr_term ~ or ~ as_expr }
    as_expr_except      = { as_expr_term ~ except ~ as_expr }
    as_expr_unit        = { as_expr_term }
        as_expr_term    = _{ as_set | any_as | aut_num | "(" ~ as_expr ~ ")" }

rtr_expr                = _{ rtr_expr_and | rtr_expr_or | rtr_expr_except | rtr_expr_unit }
    rtr_expr_and        = { rtr_expr_term ~ and ~ rtr_expr }
    rtr_expr_or         = { rtr_expr_term ~ or ~ rtr_expr }
    rtr_expr_except     = { rtr_expr_term ~ except ~ rtr_expr }
    rtr_expr_unit       = { rtr_expr_term }
        rtr_expr_term       = _{ ipv4_addr | rtr_set | inet_rtr | "(" ~ rtr_expr ~ ")" }

mp_rtr_expr             = _{ mp_rtr_expr_and | mp_rtr_expr_or | mp_rtr_expr_except | mp_rtr_expr_unit }
    mp_rtr_expr_and     = { mp_rtr_expr_term ~ and ~ mp_rtr_expr }
    mp_rtr_expr_or      = { mp_rtr_expr_term ~ or ~ mp_rtr_expr }
    mp_rtr_expr_except  = { mp_rtr_expr_term ~ except ~ mp_rtr_expr }
    mp_rtr_expr_unit    = { mp_rtr_expr_term }
        mp_rtr_expr_term    = _{ ip_addr_choice | rtr_set | inet_rtr | "(" ~ mp_rtr_expr ~ ")" }

protocol_dist_expr      = _{ ( ^"protocol" ~ from_protocol )? ~ ( into ~ into_protocol )? }
    from_protocol       = { protocol_name }
    into_protocol       = { protocol_name }

import_stmt             = { protocol_dist_expr ~ import_afi_expr }
    import_afi_expr         = { import_expr }
        import_expr             = _{ import_expr_except | import_expr_refine | import_expr_unit }
            import_expr_except      = { import_term ~ except ~ import_afi_expr }
            import_expr_refine      = { import_term ~ refine ~ import_afi_expr }
            import_expr_unit        = { import_term }
                import_term             = { import_factor ~ ";"? | "{" ~ ( import_factor ~ ";" )+ ~ "}" }
                    import_factor           = { ( from ~ peering_expr ~ ( action ~ action_expr )? )+ ~ accept ~ filter_expr }

mp_import_stmt          = { protocol_dist_expr ~ mp_import_afi_expr }
    mp_import_afi_expr      = { ( ^"afi" ~ afi_safi_list )? ~ mp_import_expr }
        mp_import_expr          = _{ mp_import_expr_except | mp_import_expr_refine | mp_import_expr_unit }
            mp_import_expr_except   = { mp_import_term ~ except ~ mp_import_afi_expr }
            mp_import_expr_refine   = { mp_import_term ~ refine ~ mp_import_afi_expr }
            mp_import_expr_unit     = { mp_import_term }
                mp_import_term          = { mp_import_factor ~ ";"? | "{" ~ ( mp_import_factor ~ ";" )+ ~ "}" }
                    mp_import_factor        = { ( from ~ mp_peering_expr ~ ( action ~ action_expr )? )+ ~ accept ~ mp_filter_expr }

export_stmt             = { protocol_dist_expr ~ export_afi_expr }
    export_afi_expr         = { export_expr }
        export_expr             = _{ export_expr_except | export_expr_refine | export_expr_unit }
            export_expr_except      = { export_term ~ except ~ export_afi_expr }
            export_expr_refine      = { export_term ~ refine ~ export_afi_expr }
            export_expr_unit        = { export_term }
                export_term             = { export_factor ~ ";"? | "{" ~ ( export_factor ~ ";" )+ ~ "}" }
                    export_factor           = { ( to ~ peering_expr ~ ( action ~ action_expr )? )+ ~ announce ~ filter_expr }

mp_export_stmt          = { protocol_dist_expr ~ mp_export_afi_expr }
    mp_export_afi_expr      = { ( ^"afi" ~ afi_safi_list )? ~ mp_export_expr }
        mp_export_expr          = _{ mp_export_expr_except | mp_export_expr_refine | mp_export_expr_unit }
            mp_export_expr_except   = { mp_export_term ~ except ~ mp_export_afi_expr }
            mp_export_expr_refine   = { mp_export_term ~ refine ~ mp_export_afi_expr }
            mp_export_expr_unit     = { mp_export_term }
                mp_export_term          = { mp_export_factor ~ ";"? | "{" ~ ( mp_export_factor ~ ";" )+ ~ "}" }
                    mp_export_factor        = { ( to ~ mp_peering_expr ~ ( action ~ action_expr )? )+ ~ announce ~ mp_filter_expr }

default_expr            = { to ~ peering_expr ~ ( action ~ action_expr )? ~ ( networks ~ filter_expr )? }

mp_default_expr         = { ( ^"afi" ~ afi_safi_list )? ~ to ~ mp_peering_expr ~ ( action ~ action_expr )? ~ ( networks ~ mp_filter_expr )? }

aggr_mtd_expr           = _{ aggr_mtd_expr_inbound | aggr_mtd_expr_outbound }
    aggr_mtd_expr_inbound   = { inbound }
    aggr_mtd_expr_outbound  = { outbound ~ as_expr? }

// TODO
rp_attribute_expr       = @{ free_form }

// TODO
typedef_expr            = @{ free_form }

// TODO
protocol_expr           = @{ free_form }

ifaddr_expr             = { ipv4_addr ~ ^"masklen" ~ num ~ ( action ~ action_expr )? }

interface_expr          = { ip_addr_choice ~ ^"masklen" ~ num ~ ( action ~ action_expr )? ~ tunnel_spec? }
    tunnel_spec             = { ^"tunnel" ~ ip_addr_choice ~ "," ~ encapsulation }

peer_expr               = { protocol_name ~ peer_spec ~ ( peer_opts )? }
    peer_spec           = _{ ipv4_addr | rtr_set | peering_set | inet_rtr }
    peer_opts           = { peer_opt ~ ( "," ~ peer_opt )* }
        peer_opt        = ${ peer_opt_key ~ "(" ~ peer_opt_val? ~ ")" }
            peer_opt_key    = @{ basic_name }
            peer_opt_val    = @{ ( !( ")" | ";" ) ~ ANY )+ }
mp_peer_expr            = { protocol_name ~ mp_peer_spec ~ ( peer_opts )? }
    mp_peer_spec        = _{ ip_addr_choice | rtr_set | peering_set | inet_rtr }

mnt_routes_expr         = { mntner_name_list ~ mnt_routes_expr_qual? }
    mnt_routes_expr_qual    = _{ mnt_routes_expr_qual_list | mnt_routes_expr_qual_any }
        mnt_routes_expr_qual_list   = { "{" ~ ip_prefix_range_list ~ "}" }
        mnt_routes_expr_qual_any    = { ^"ANY" }

reclaim_expr            = _{ reclaim_expr_all | reclaim_expr_free_form }
    reclaim_expr_all        = { ^"ALL" }
    // TODO
    reclaim_expr_free_form  = @{ free_form }

// ** common RPSL attributes **
// common attributes
common_attrs                = _{ descr_attr | tech_c_attr | admin_c_attr | remarks_attr
                               | notify_attr | mnt_by_attr | changed_attr | source_attr }
    descr_attr              = !{ ^"descr:"           ~ object_descr }
    tech_c_attr             = !{ ^"tech-c:"          ~ nic_hdl }
    admin_c_attr            = !{ ^"admin-c:"         ~ nic_hdl }
    remarks_attr            = !{ ^"remarks:"         ~ remarks }
    notify_attr             = !{ ^"notify:"          ~ email_addr }
    mnt_by_attr             = !{ ^"mnt-by:"          ~ mntner_name_list }
    changed_attr            = !{ ^"changed:"         ~ changed_expr }
    source_attr             = !{ ^"source:"          ~ registry_name }
// contact attributes
contact_attrs               = _{ nic_hdl_attr | address_attr | phone_attr
                               | fax_no_attr | e_mail_attr | auth_attr }
    nic_hdl_attr            = !{ ^"nic-hdl:"         ~ nic_hdl }
    address_attr            = !{ ^"address:"         ~ address }
    phone_attr              = !{ ^"phone:"           ~ tel_number }
    fax_no_attr             = !{ ^"fax-no:"          ~ tel_number }
    e_mail_attr             = !{ ^"e-mail:"          ~ email_addr }
// set attributes
set_attrs                   = _{ mbrs_by_ref_attr | mnt_lower_attr }
    mbrs_by_ref_attr        = !{ ^"mbrs-by-ref:"     ~ mntner_name_list }
// route/route6 attributes
mp_route_attrs              = _{ origin_attr | route_member_of_attr
                               | aggr_bndry_attr | aggr_mtd_attr
                               | mnt_routes_attr | mnt_lower_attr
                               | reclaim_attr | no_reclaim_attr
                               | ping_hdl_attr }
    origin_attr             = !{ ^"origin:"             ~ aut_num }
    route_member_of_attr    = !{ ^"member-of:"          ~ route_set_list }
    aggr_bndry_attr         = !{ ^"aggr-bndry:"         ~ as_expr }
    aggr_mtd_attr           = !{ ^"aggr-mtd:"           ~ aggr_mtd_expr }
    ping_hdl_attr           = !{ ^"ping-hdl:"           ~ nic_hdl }
inetnum_attrs               = _{ netname_attr | country_attr
                               | mnt_routes_attr | mnt_lower_attr
                               | reclaim_attr | no_reclaim_attr }
    netname_attr            = !{ ^"netname:"            ~ netname }
    country_attr            = !{ ^"country:"            ~ country_code }
// special attributes
auth_attr                   = !{ ^"auth:"               ~ auth_expr }
mnt_routes_attr             = !{ ^"mnt-routes:"         ~ mnt_routes_expr }
mnt_lower_attr              = !{ ^"mnt-lower:"          ~ mntner_name_list }
reclaim_attr                = !{ ^"reclaim:"            ~ reclaim_expr }
no_reclaim_attr             = !{ ^"no-reclaim:"         ~ reclaim_expr }

// ** RPSL objects **
rpsl_object                     = _{ mntner_obj | person_obj | role_obj
                                   | as_block_obj | inetnum_obj | inet6num_obj
                                   | route_obj | route6_obj | as_set_obj
                                   | route_set_obj | filter_set_obj
                                   | rtr_set_obj | peering_set_obj
                                   | aut_num_obj | dictionary_obj
                                   | inet_rtr_obj | key_cert_obj }
// mntner
mntner_obj                      =  { mntner_class_attr      ~ ( mntner_attr )+ }
    mntner_class_attr           = _{ ^"mntner:"             ~ mntner_name }
    mntner_attr                 = ${ NEWLINE ~
                                   ( common_attrs | auth_attr
                                   | upd_to_attr | mnt_nfy_attr
                                   | referral_by_attr | auth_override_attr ) }
        upd_to_attr             = !{ ^"upd-to:"             ~ email_addr }
        mnt_nfy_attr            = !{ ^"mnt-nfy:"            ~ email_addr }
        referral_by_attr        = !{ ^"referral-by:"        ~ mntner_name }
        auth_override_attr      = !{ ^"auth-override:"      ~ date }
// person
person_obj                      =  { person_class_attr      ~ ( person_attr )+ }
    person_class_attr           = _{ ^"person:"             ~ person }
    person_attr                 = ${ NEWLINE ~
                                   ( common_attrs | contact_attrs ) }
// role object
role_obj                        =  { role_class_attr        ~ ( role_attr )+ }
    role_class_attr             = _{ ^"role:"               ~ role }
    role_attr                   = ${ NEWLINE ~
                                   ( common_attrs | contact_attrs
                                   | trouble_attr ) }
        trouble_attr            = !{ ^"trouble:"            ~ trouble }
// as-block object
as_block_obj                    =  { as_block_class_attr    ~ ( as_block_attr )+ }
    as_block_class_attr         = _{ ^"as-block:"           ~ as_block }
    as_block_attr               = ${ NEWLINE ~
                                   ( common_attrs | mnt_lower_attr
                                   | reclaim_attr | no_reclaim_attr )}
// inetnum object
inetnum_obj                     =  { inetnum_class_attr     ~ ( inetnum_attr )+ }
    inetnum_class_attr          = _{ ^"inetnum:"            ~ inetnum }
    inetnum_attr                = ${ NEWLINE ~
                                   ( common_attrs | inetnum_attrs )}
// inet6num object
inet6num_obj                    =  { inet6num_class_attr    ~ ( inet6num_attr )+ }
    inet6num_class_attr         = _{ ^"inet6num:"           ~ inet6num }
    inet6num_attr               = ${ NEWLINE ~
                                   ( common_attrs | inetnum_attrs )}
// route object
route_obj                       =  { route_class_attr       ~ ( route_attr )+ }
    route_class_attr            = _{ ^"route:"              ~ route }
    route_attr                  = ${ NEWLINE ~
                                   ( common_attrs | mp_route_attrs
                                   | inject_attr | components_attr
                                   | export_comps_attr | holes_attr
                                   | pingable4_attr ) }
        inject_attr             = !{ ^"inject:"             ~ inject_expr }
        components_attr         = !{ ^"components:"         ~ components_expr }
        export_comps_attr       = !{ ^"export-comps:"       ~ filter_expr }
        holes_attr              = !{ ^"holes:"              ~ ipv4_prefix_list }
        pingable4_attr          = !{ ^"pingable:"           ~ ipv4_addr }
// route6 object
route6_obj                      =  { route6_class_attr      ~ ( route6_attr )+ }
    route6_class_attr           = _{ ^"route6:"             ~ route6 }
    route6_attr                 = ${ NEWLINE ~
                                   ( common_attrs | mp_route_attrs
                                   | inject6_attr | components6_attr
                                   | export_comps6_attr | holes6_attr
                                   | pingable6_attr ) }
        inject6_attr            = !{ ^"inject:"             ~ inject6_expr }
        components6_attr        = !{ ^"components:"         ~ components6_expr }
        export_comps6_attr      = !{ ^"export-comps:"       ~ mp_filter_expr }
        holes6_attr             = !{ ^"holes:"              ~ ipv6_prefix_list }
        pingable6_attr          = !{ ^"pingable:"           ~ ipv6_addr }
// as-set object
as_set_obj                      =  { as_set_class_attr      ~ ( as_set_attr )+ }
    as_set_class_attr           = _{ ^"as-set:"             ~ as_set }
    as_set_attr                 = ${ NEWLINE ~
                                   ( common_attrs | set_attrs
                                   | as_set_members_attr ) }
        as_set_members_attr     = !{ ^"members:"            ~ as_set_members_list }
// route-set object
route_set_obj                   =  { route_set_class_attr   ~ ( route_set_attr )+ }
    route_set_class_attr        = _{ ^"route-set:"          ~ route_set }
    route_set_attr              = ${ NEWLINE ~
                                   ( common_attrs | set_attrs
                                   | route_set_members_attr | route_set_mp_members_attr ) }
        route_set_members_attr      = !{ ^"members:"        ~ route_set_members_list }
        route_set_mp_members_attr   = !{ ^"mp-members:"     ~ route_set_mp_members_list }
// filter-set object
filter_set_obj                  =  { filter_set_class_attr  ~ ( filter_set_attr )+ }
    filter_set_class_attr       = _{ ^"filter-set:"         ~ filter_set }
    filter_set_attr             = ${ NEWLINE ~
                                   ( common_attrs | filter_attr
                                   | mp_filter_attr | mnt_lower_attr ) }
        filter_attr             = !{ ^"filter:"             ~ filter_expr }
        mp_filter_attr          = !{ ^"mp-filter:"          ~ mp_filter_expr }
// rtr-set object
rtr_set_obj                     =  { rtr_set_class_attr     ~ ( rtr_set_attr )+ }
    rtr_set_class_attr          = _{ ^"rtr-set:"            ~ rtr_set }
    rtr_set_attr                = ${ NEWLINE ~
                                   ( common_attrs | set_attrs
                                   | rtr_set_members_attr
                                   | rtr_set_mp_members_attr ) }
        rtr_set_members_attr    = !{ ^"members:"            ~ rtr_set_members_list }
        rtr_set_mp_members_attr = !{ ^"mp-members:"         ~ rtr_set_mp_members_list }
// peering-set object
peering_set_obj                 =  { peering_set_class_attr ~ ( peering_set_attr )+ }
    peering_set_class_attr      = _{ ^"peering-set:"        ~ peering_set }
    peering_set_attr            = ${ NEWLINE ~
                                   ( common_attrs | peering_attr
                                   | mp_peering_attr | mnt_lower_attr ) }
        peering_attr            = !{ ^"peering:"            ~ peering_expr }
        mp_peering_attr         = !{ ^"mp-peering:"         ~ mp_peering_expr }
// aut-num class
aut_num_obj                     =  { aut_num_class_attr     ~ ( aut_num_attr )+ }
    aut_num_class_attr          = _{ ^"aut-num:"            ~ aut_num }
    aut_num_attr                = ${ NEWLINE ~
                                   ( common_attrs | as_name_attr | aut_num_member_of_attr
                                   | import_attr | mp_import_attr
                                   | export_attr | mp_export_attr
                                   | default_attr | mp_default_attr
                                   | mnt_routes_attr | mnt_lower_attr
                                   | reclaim_attr | no_reclaim_attr ) }
        as_name_attr            = !{ ^"as-name:"            ~ as_name }
        aut_num_member_of_attr  = !{ ^"member-of:"          ~ as_set_list }
        import_attr             = !{ ^"import:"             ~ import_stmt }
        mp_import_attr          = !{ ^"mp-import:"          ~ mp_import_stmt }
        export_attr             = !{ ^"export:"             ~ export_stmt }
        mp_export_attr          = !{ ^"mp-export:"          ~ mp_export_stmt }
        default_attr            = !{ ^"default:"            ~ default_expr }
        mp_default_attr         = !{ ^"mp-default:"         ~ mp_default_expr }
// dictionary object
dictionary_obj                  =  { dictionary_class_attr  ~ ( dictionary_attr )+ }
    dictionary_class_attr       = _{ ^"dictionary:"         ~ dictionary }
    dictionary_attr             = ${ NEWLINE ~
                                   ( common_attrs | rp_attribute_attr
                                   | typedef_attr | protocol_attr ) }
        rp_attribute_attr       = !{ ^"rp-attribute:"       ~ rp_attribute_expr }
        typedef_attr            = !{ ^"typedef:"            ~ typedef_expr }
        protocol_attr           = !{ ^"protocol:"           ~ protocol_expr }
// inet-rtr object
inet_rtr_obj                    =  { inet_rtr_class_attr    ~ ( inet_rtr_attr )+ }
    inet_rtr_class_attr         = _{ ^"inet-rtr:"           ~ inet_rtr }
    inet_rtr_attr               = ${ NEWLINE ~
                                   ( common_attrs | alias_attr
                                   | local_as_attr | ifaddr_attr
                                   | interface_attr | peer_attr | mp_peer_attr
                                   | inet_rtr_member_of_attr ) }
        alias_attr              = !{ ^"alias:"              ~ dns_name }
        local_as_attr           = !{ ^"local-as:"           ~ aut_num }
        ifaddr_attr             = !{ ^"ifaddr:"             ~ ifaddr_expr }
        interface_attr          = !{ ^"interface:"          ~ interface_expr }
        peer_attr               = !{ ^"peer:"               ~ peer_expr }
        mp_peer_attr            = !{ ^"mp-peer:"            ~ mp_peer_expr }
        inet_rtr_member_of_attr = !{ ^"member-of:"          ~ rtr_set_list }
// key-cert object
key_cert_obj                    =  { key_cert_class_attr    ~ ( key_cert_attr )+ }
    key_cert_class_attr         = _{ ^"key-cert:"           ~ key_cert }
    key_cert_attr               = ${ NEWLINE ~
                                   ( common_attrs | method_attr | owner_attr
                                   | fingerpr_attr | certif_attr ) }
        method_attr             = !{ ^"method:"             ~ signing_method }
        owner_attr              = !{ ^"owner:"              ~ owner }
        fingerpr_attr           = !{ ^"fingerpr:"           ~ key_fingerprint }
        certif_attr             = !{ ^"certif:"             ~ key_certif }

// ** standalone parsers **
just_rpsl_object                = _{ SOI ~ rpsl_object ~ NEWLINE? ~ EOI }
just_rpsl_object_key            = _{ SOI ~ rpsl_object_key ~ EOI }
// expressions
just_import_stmt                = _{ SOI ~ import_stmt ~ EOI }
just_mp_import_stmt             = _{ SOI ~ mp_import_stmt ~ EOI }
just_export_stmt                = _{ SOI ~ export_stmt ~ EOI }
just_mp_export_stmt             = _{ SOI ~ mp_export_stmt ~ EOI }
just_default_expr               = _{ SOI ~ default_expr ~ EOI }
just_mp_default_expr            = _{ SOI ~ mp_default_expr ~ EOI }
just_filter_expr                = _{ SOI ~ filter_expr ~ EOI }
just_mp_filter_expr             = _{ SOI ~ mp_filter_expr ~ EOI }
just_auth_expr                  = _{ SOI ~ auth_expr ~ EOI }
just_changed_expr               = _{ SOI ~ changed_expr ~ EOI }
just_peering_expr               = _{ SOI ~ peering_expr ~ EOI }
just_mp_peering_expr            = _{ SOI ~ mp_peering_expr ~ EOI }
just_action_expr                = _{ SOI ~ action_expr ~ EOI }
just_as_expr                    = _{ SOI ~ as_expr ~ EOI }
just_ifaddr_expr                = _{ SOI ~ ifaddr_expr ~ EOI }
just_interface_expr             = _{ SOI ~ interface_expr ~ EOI }
just_peer_expr                  = _{ SOI ~ peer_expr ~ EOI }
just_mp_peer_expr               = _{ SOI ~ mp_peer_expr ~ EOI }
just_rtr_expr                   = _{ SOI ~ rtr_expr ~ EOI }
just_mp_rtr_expr                = _{ SOI ~ mp_rtr_expr ~ EOI }
just_inject_expr                = _{ SOI ~ inject_expr ~ EOI }
just_inject6_expr               = _{ SOI ~ inject6_expr ~ EOI }
just_components_expr            = _{ SOI ~ components_expr ~ EOI }
just_components6_expr           = _{ SOI ~ components6_expr ~ EOI }
just_aggr_mtd_expr              = _{ SOI ~ aggr_mtd_expr ~ EOI }
just_mnt_routes_expr            = _{ SOI ~ mnt_routes_expr ~ EOI }
just_reclaim_expr               = _{ SOI ~ reclaim_expr ~ EOI }