pubid 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/data/parg/adobe.json +1 -1
- data/data/parg/aiee.json +1 -1
- data/data/parg/amca.json +1 -1
- data/data/parg/ansi.json +1 -1
- data/data/parg/api.json +1 -1
- data/data/parg/ashrae.json +1 -1
- data/data/parg/asme.json +1 -1
- data/data/parg/astm.json +1 -1
- data/data/parg/bipm.json +1 -1
- data/data/parg/bsi.json +1 -1
- data/data/parg/calconnect.json +1 -1
- data/data/parg/ccsds.json +1 -1
- data/data/parg/cen_cenelec.json +1 -1
- data/data/parg/cie.json +1 -1
- data/data/parg/csa.json +1 -1
- data/data/parg/doi.json +1 -1
- data/data/parg/easc.json +1 -1
- data/data/parg/ecma.json +1 -1
- data/data/parg/etsi.json +1 -1
- data/data/parg/evs.json +1 -1
- data/data/parg/gb.json +1 -1
- data/data/parg/gost.json +1 -1
- data/data/parg/iala.json +1 -1
- data/data/parg/iana.json +1 -1
- data/data/parg/idf.json +1 -1
- data/data/parg/iec.json +1 -1
- data/data/parg/ieee.json +1 -29571
- data/data/parg/ietf.json +1 -1
- data/data/parg/iho.json +1 -0
- data/data/parg/ire.json +1 -1
- data/data/parg/isbn.json +1 -1
- data/data/parg/iso.json +1 -8510
- data/data/parg/itu.json +1 -1
- data/data/parg/jcgm.json +1 -1
- data/data/parg/jis.json +1 -1
- data/data/parg/nesc.json +1 -1
- data/data/parg/nist.json +1 -9588
- data/data/parg/oasis.json +1 -1
- data/data/parg/ogc.json +1 -1
- data/data/parg/oiml.json +1 -1
- data/data/parg/omg.json +1 -1
- data/data/parg/parg.json +1 -1
- data/data/parg/plateau.json +1 -1
- data/data/parg/sae.json +1 -1
- data/data/parg/tables/typed_stages.yaml +1 -0
- data/data/parg/tgpp.json +1 -1
- data/data/parg/un.json +1 -1
- data/data/parg/w3c.json +1 -1
- data/data/parg/xsf.json +1 -1
- data/lib/pubid/adobe/identifier.rb +1 -1
- data/lib/pubid/adobe/parser.rb +2 -113
- data/lib/pubid/amca/identifiers/base.rb +1 -1
- data/lib/pubid/amca/parser.rb +1 -145
- data/lib/pubid/ansi/identifier.rb +1 -1
- data/lib/pubid/ansi/parser.rb +1 -82
- data/lib/pubid/api/builder.rb +32 -1
- data/lib/pubid/api/identifier.rb +1 -1
- data/lib/pubid/api/parser.rb +1 -131
- data/lib/pubid/ashrae/identifiers/base.rb +1 -1
- data/lib/pubid/ashrae/parser.rb +3 -710
- data/lib/pubid/asme/builder.rb +6 -4
- data/lib/pubid/asme/identifier.rb +1 -2
- data/lib/pubid/asme/parser.rb +1 -328
- data/lib/pubid/astm/builder.rb +12 -3
- data/lib/pubid/astm/identifier.rb +1 -2
- data/lib/pubid/astm/parser.rb +1 -227
- data/lib/pubid/bipm/identifier.rb +8 -1
- data/lib/pubid/bipm/parser.rb +2 -224
- data/lib/pubid/bsi/builder.rb +2 -4
- data/lib/pubid/bsi/parser.rb +1 -666
- data/lib/pubid/bsi/single_identifier.rb +38 -1
- data/lib/pubid/calconnect/identifier.rb +1 -1
- data/lib/pubid/calconnect/parser.rb +2 -40
- data/lib/pubid/ccsds/identifier.rb +1 -1
- data/lib/pubid/ccsds/parser.rb +1 -66
- data/lib/pubid/cen_cenelec/identifier.rb +16 -1
- data/lib/pubid/cen_cenelec/parser.rb +3 -136
- data/lib/pubid/cie/identifier.rb +1 -1
- data/lib/pubid/cie/parser.rb +3 -378
- data/lib/pubid/conformance.rb +1 -1
- data/lib/pubid/csa/builder.rb +41 -18
- data/lib/pubid/csa/identifier.rb +12 -4
- data/lib/pubid/csa/identifiers/amendment.rb +28 -0
- data/lib/pubid/csa/identifiers.rb +1 -0
- data/lib/pubid/csa/parser.rb +16 -397
- data/lib/pubid/doi/identifier.rb +1 -1
- data/lib/pubid/doi/parser.rb +2 -37
- data/lib/pubid/easc/builder.rb +1 -1
- data/lib/pubid/easc/identifier.rb +1 -1
- data/lib/pubid/easc/parser.rb +2 -70
- data/lib/pubid/ecma/CLAUDE.md +8 -1
- data/lib/pubid/ecma/identifier.rb +13 -8
- data/lib/pubid/ecma/parser.rb +2 -54
- data/lib/pubid/ecma/renderer.rb +3 -7
- data/lib/pubid/errors.rb +18 -13
- data/lib/pubid/etsi/builder.rb +8 -5
- data/lib/pubid/etsi/identifiers/base.rb +1 -1
- data/lib/pubid/etsi/parser.rb +1 -132
- data/lib/pubid/evs/identifier.rb +7 -0
- data/lib/pubid/evs/parser.rb +1 -8
- data/lib/pubid/evs.rb +1 -1
- data/lib/pubid/gb/identifier.rb +7 -1
- data/lib/pubid/gb/parser.rb +2 -51
- data/lib/pubid/gost/identifier.rb +9 -1
- data/lib/pubid/gost/parser.rb +4 -81
- data/lib/pubid/iala/parser.rb +2 -121
- data/lib/pubid/iana/identifier.rb +1 -1
- data/lib/pubid/iana/parser.rb +2 -24
- data/lib/pubid/identifier.rb +78 -1
- data/lib/pubid/idf/builder.rb +42 -0
- data/lib/pubid/idf/identifier.rb +1 -1
- data/lib/pubid/idf/parser.rb +1 -137
- data/lib/pubid/idf.rb +1 -2
- data/lib/pubid/iec/builder.rb +158 -50
- data/lib/pubid/iec/identifier.rb +1 -1
- data/lib/pubid/iec/parser.rb +3 -430
- data/lib/pubid/ieee/aiee/identifier.rb +2 -1
- data/lib/pubid/ieee/aiee.rb +0 -1
- data/lib/pubid/ieee/builder.rb +2 -2
- data/lib/pubid/ieee/identifiers/base.rb +1 -1
- data/lib/pubid/ieee/ire/identifier.rb +2 -1
- data/lib/pubid/ieee/ire.rb +0 -1
- data/lib/pubid/ieee/nesc.rb +0 -1
- data/lib/pubid/ieee/parser.rb +1 -1257
- data/lib/pubid/ietf/identifiers/base.rb +17 -1
- data/lib/pubid/ietf/parser.rb +2 -47
- data/lib/pubid/ietf/renderer.rb +17 -2
- data/lib/pubid/iho/CLAUDE.md +89 -0
- data/lib/pubid/iho/builder.rb +4 -1
- data/lib/pubid/iho/identifiers/base.rb +28 -2
- data/lib/pubid/iho/renderer.rb +8 -0
- data/lib/pubid/iho/urn_generator.rb +11 -1
- data/lib/pubid/iho/urn_parser.rb +21 -11
- data/lib/pubid/iho.rb +0 -1
- data/lib/pubid/isbn/identifier.rb +1 -1
- data/lib/pubid/isbn/parser.rb +2 -31
- data/lib/pubid/iso/builder.rb +1 -1
- data/lib/pubid/iso/identifiers/directives.rb +6 -3
- data/lib/pubid/iso/identifiers/guide.rb +6 -3
- data/lib/pubid/iso/identifiers/international_standard.rb +3 -1
- data/lib/pubid/iso/identifiers/international_workshop_agreement.rb +6 -3
- data/lib/pubid/iso/normalizer.rb +1 -1
- data/lib/pubid/iso/parser.rb +1 -539
- data/lib/pubid/iso/supplement_identifier.rb +6 -3
- data/lib/pubid/iso/utilities.rb +4 -5
- data/lib/pubid/iso.rb +1 -19
- data/lib/pubid/itu/builder.rb +36 -20
- data/lib/pubid/itu/identifiers/base.rb +15 -2
- data/lib/pubid/itu/parser.rb +1 -775
- data/lib/pubid/jcgm/builder.rb +35 -0
- data/lib/pubid/jcgm/parser.rb +1 -151
- data/lib/pubid/jcgm.rb +1 -2
- data/lib/pubid/jis/builder.rb +18 -29
- data/lib/pubid/jis/identifier.rb +1 -1
- data/lib/pubid/jis/parser.rb +1 -128
- data/lib/pubid/nist/builder.rb +5 -1
- data/lib/pubid/nist/caster.rb +13 -3
- data/lib/pubid/nist/identifiers/base.rb +37 -2
- data/lib/pubid/nist/identifiers/circular.rb +2 -2
- data/lib/pubid/nist/identifiers/circular_supplement.rb +2 -2
- data/lib/pubid/nist/identifiers/commercial_standards_monthly.rb +2 -2
- data/lib/pubid/nist/identifiers/crpl_report.rb +2 -2
- data/lib/pubid/nist/identifiers/handbook.rb +2 -2
- data/lib/pubid/nist/identifiers/internal_report.rb +2 -2
- data/lib/pubid/nist/identifiers/miscellaneous_publication.rb +2 -2
- data/lib/pubid/nist/identifiers/monograph.rb +2 -2
- data/lib/pubid/nist/identifiers/report.rb +2 -2
- data/lib/pubid/nist/parser.rb +19 -775
- data/lib/pubid/nist/router.rb +4 -1
- data/lib/pubid/nist/supplement_identifier.rb +2 -2
- data/lib/pubid/oasis/identifier.rb +1 -1
- data/lib/pubid/oasis/parser.rb +2 -16
- data/lib/pubid/ogc/identifier.rb +1 -1
- data/lib/pubid/ogc/parser.rb +2 -26
- data/lib/pubid/oiml/identifiers/certification_system.rb +7 -0
- data/lib/pubid/oiml/identifiers/dual_published.rb +2 -2
- data/lib/pubid/oiml/parser.rb +1 -303
- data/lib/pubid/oiml.rb +1 -2
- data/lib/pubid/omg/identifier.rb +6 -1
- data/lib/pubid/omg/parser.rb +2 -76
- data/lib/pubid/parg/artifact.rb +22 -3
- data/lib/pubid/parg/model.rb +98 -0
- data/lib/pubid/parg.rb +1 -0
- data/lib/pubid/parser.rb +5 -4
- data/lib/pubid/parsers/mr_string.rb +1 -1
- data/lib/pubid/plateau/parser.rb +1 -66
- data/lib/pubid/plateau.rb +1 -2
- data/lib/pubid/renderers/directives_renderer.rb +1 -1
- data/lib/pubid/renderers/iwa_renderer.rb +1 -1
- data/lib/pubid/renderers/publisher_stripper.rb +82 -0
- data/lib/pubid/renderers/supplement_renderer.rb +1 -1
- data/lib/pubid/renderers.rb +1 -0
- data/lib/pubid/sae/identifiers/base.rb +1 -1
- data/lib/pubid/sae/parser.rb +1 -48
- data/lib/pubid/tgpp/identifier.rb +1 -1
- data/lib/pubid/tgpp/parser.rb +2 -59
- data/lib/pubid/un/identifier.rb +1 -1
- data/lib/pubid/un/parser.rb +1 -18
- data/lib/pubid/version.rb +1 -1
- data/lib/pubid/w3c/identifier.rb +1 -1
- data/lib/pubid/w3c/parser.rb +2 -27
- data/lib/pubid/xsf/identifier.rb +11 -7
- data/lib/pubid/xsf/parser.rb +3 -31
- data/lib/pubid/xsf/renderer.rb +2 -4
- data/lib/pubid.rb +8 -9
- metadata +15 -25
- data/lib/pubid/ieee/aiee/parser.rb +0 -130
- data/lib/pubid/ieee/ire/parser.rb +0 -109
- data/lib/pubid/ieee/nesc/parser.rb +0 -155
- data/lib/pubid/iho/parser.rb +0 -68
- data/lib/pubid/parser/common_parse_methods.rb +0 -13
- data/lib/pubid/parser/common_parse_rules.rb +0 -56
- data/lib/pubid/parser/grammar.rb +0 -96
data/lib/pubid/ieee/parser.rb
CHANGED
|
@@ -1,1261 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "parslet"
|
|
4
|
-
|
|
5
3
|
module Pubid
|
|
6
4
|
module Ieee
|
|
7
5
|
# Parser class for IEEE identifiers
|
|
8
6
|
# Single Responsibility: Parsing IEEE identifier syntax
|
|
9
7
|
# Note: IEEE is extremely complex with many edge cases
|
|
10
|
-
class Parser
|
|
11
|
-
# Basic building blocks
|
|
12
|
-
rule(:space) { str(" ") }
|
|
13
|
-
rule(:space?) { space.maybe }
|
|
14
|
-
rule(:dash) { str("-") }
|
|
15
|
-
rule(:dash?) { dash.maybe }
|
|
16
|
-
rule(:dot) { str(".") }
|
|
17
|
-
rule(:slash) { str("/") }
|
|
18
|
-
rule(:comma) { str(", ") }
|
|
19
|
-
rule(:digit) { match("[0-9]") }
|
|
20
|
-
rule(:digits) { digit.repeat(1) }
|
|
21
|
-
rule(:letter) { match("[A-Za-z]") }
|
|
22
|
-
rule(:upper) { match("[A-Z]") }
|
|
23
|
-
rule(:lower) { match("[a-z]") }
|
|
24
|
-
|
|
25
|
-
# Year pattern (4 digits starting with 19 or 20), optionally followed by letter(s)
|
|
26
|
-
# e.g. 2012, 201x, 2010a
|
|
27
|
-
rule(:year_digits) do
|
|
28
|
-
(str("19") | str("20")) >> digit.repeat(2,
|
|
29
|
-
2) >> lower.repeat(0,
|
|
30
|
-
2) >> digits.absent?
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Month patterns - numeric format (01-12)
|
|
34
|
-
rule(:month_numeric) do
|
|
35
|
-
(str("0") >> match("[1-9]")) | # 01-09
|
|
36
|
-
(str("1") >> match("[0-2]")) # 10-12
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Comprehensive date parsing
|
|
40
|
-
# Format 1: "September 2018" or "Sept 2018" (text month + year)
|
|
41
|
-
rule(:date_with_month_text) do
|
|
42
|
-
month_name.as(:month) >> space >> year_digits.as(:year)
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# Format 2: "2018-09" (year-numeric month)
|
|
46
|
-
rule(:date_with_month_numeric) do
|
|
47
|
-
year_digits.as(:year) >> dash >> month_numeric.as(:month)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Format 3: Just year "2018"
|
|
51
|
-
rule(:date_year_only) do
|
|
52
|
-
year_digits.as(:year)
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
# Combined date rule - longest match first
|
|
56
|
-
rule(:date_standalone) do
|
|
57
|
-
date_with_month_text | date_with_month_numeric | date_year_only
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
# Trailing print/reaffirm date "<sep>Month YYYY" — captured under the
|
|
61
|
-
# distinct :trailing_month/:trailing_year keys so it never collides with a
|
|
62
|
-
# base -YYYY identity year (the builder promotes it only when no base year
|
|
63
|
-
# exists). Accepts BOTH a month name ("May 2014") and a month-first numeric
|
|
64
|
-
# month ("05 2014"). The two variants are unambiguous: month_name never
|
|
65
|
-
# starts with a digit, and month_numeric (01-12) never matches a bare
|
|
66
|
-
# 19xx/20xx year — so a bare trailing year still falls through to callers'
|
|
67
|
-
# own bare-year clause.
|
|
68
|
-
rule(:trailing_month_year) do
|
|
69
|
-
# The numeric branch accepts `-` as well as space before the year:
|
|
70
|
-
# preprocessing (the `(\d)\s+(\d{4})` gsub) rewrites a trailing
|
|
71
|
-
# "05 2014" → "05-2014", so a numeric month reaches the grammar
|
|
72
|
-
# dash-joined; the month-name branch escapes that gsub (the char before
|
|
73
|
-
# the space is a letter) and stays space-joined.
|
|
74
|
-
((comma | space) >> month_name.as(:trailing_month) >> space >> year_digits.as(:trailing_year)) |
|
|
75
|
-
((comma | space) >> month_numeric.as(:trailing_month) >> (space | dash) >> year_digits.as(:trailing_year))
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
# Month patterns
|
|
79
|
-
rule(:month_name) do
|
|
80
|
-
# Period-suffixed abbreviations (longest first)
|
|
81
|
-
str("Sept.") | str("Oct.") | str("Nov.") | str("Dec.") |
|
|
82
|
-
str("Jan.") | str("Feb.") | str("Mar.") | str("Apr.") |
|
|
83
|
-
str("Jun.") | str("Jul.") | str("Aug.") |
|
|
84
|
-
# Full month names
|
|
85
|
-
str("January") | str("February") | str("March") | str("April") |
|
|
86
|
-
str("May") | str("June") | str("July") | str("August") |
|
|
87
|
-
str("September") | str("October") | str("November") | str("December") |
|
|
88
|
-
# Non-period abbreviations
|
|
89
|
-
str("Jan") | str("Feb") | str("Mar") | str("Apr") | str("Jun") |
|
|
90
|
-
str("Jul") | str("Aug") | str("Sep") | str("Sept") | str("Oct") | str("Nov") | str("Dec")
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
# Organizations
|
|
94
|
-
rule(:organization) do
|
|
95
|
-
str("IEEE") | str("AIEE") | str("ANSI") | str("ASA") |
|
|
96
|
-
# ANS (American Nuclear Society) — a third co-publisher on nuclear
|
|
97
|
-
# standards ("ANSI/IEEE/ANS 7.4-3-2-1982"). Listed AFTER ANSI so it
|
|
98
|
-
# never shadows the longer token.
|
|
99
|
-
str("ANS") |
|
|
100
|
-
str("IEC") | str("ISO") | str("ASTM") | str("CSA") | str("ASME") |
|
|
101
|
-
str("NACE") | str("NSF") | str("ASHRAE") | str("NCTA") | str("AESC") |
|
|
102
|
-
str("EIA") | # NEW Session 224: Add EIA support
|
|
103
|
-
# Historical / foreign co-publishers seen in relaton-data-ieee
|
|
104
|
-
# (bucket 4): AMPP, USAS (both standalone), and the IEEE sub-board /
|
|
105
|
-
# partner co-publishers USEMCSC, EAB, MPAI.
|
|
106
|
-
str("USEMCSC") | str("AMPP") | str("USAS") | str("EAB") | str("MPAI")
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# Complex organization prefixes (Category 5: ANSI Complex)
|
|
110
|
-
rule(:complex_org_prefix) do
|
|
111
|
-
str("ANSI/IEEE-ANS") | str("ANSI/IEEE") | str("ANSI")
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
# Characteristic IEEE number patterns (without prefix)
|
|
115
|
-
# These patterns are distinctly IEEE even without "IEEE Std" prefix
|
|
116
|
-
rule(:characteristic_ieee_number) do
|
|
117
|
-
# C37.xxx series (power systems) - C followed by 2 digits, dot, more digits
|
|
118
|
-
(str("C") >> digit.repeat(2,
|
|
119
|
-
2) >> dot >> digits >> match("[a-z]").repeat.maybe) |
|
|
120
|
-
# 802.xxx series (networking) - 802 followed by dot, digits, optional letter suffix
|
|
121
|
-
(str("802") >> dot >> digits >> match("[a-z]").repeat.maybe) |
|
|
122
|
-
# P followed by digits (draft projects)
|
|
123
|
-
(str("P") >> digits.repeat(1))
|
|
124
|
-
end
|
|
125
|
-
|
|
126
|
-
rule(:publisher) do
|
|
127
|
-
complex_org_prefix.as(:publisher) | organization.as(:publisher)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
rule(:copublisher) do
|
|
131
|
-
# Three-way copublisher strings (treat as single unit, longest first)
|
|
132
|
-
str("/ISO/IEC").as(:copublisher) |
|
|
133
|
-
str("/IEC/ISO").as(:copublisher) |
|
|
134
|
-
# Two-way copublishers (original pattern)
|
|
135
|
-
(slash >> space? >> organization.as(:copublisher))
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# Conformance document patterns (/Conformance01-2003, /Conformance02-2014)
|
|
139
|
-
# Allow optional space before slash for malformed inputs
|
|
140
|
-
rule(:conformance) do
|
|
141
|
-
(space? >> slash >> str("Conformance") >> match("[0-9]").repeat(1).as(:conf_number) >> dash >> year_digits.as(:conf_year)).as(:conformance)
|
|
142
|
-
end
|
|
143
|
-
|
|
144
|
-
# ASHRAE joint publication patterns (/ASHRAE Guideline 21-2012)
|
|
145
|
-
# Also handles /ASHRAE 21 without "Guideline"
|
|
146
|
-
rule(:ashrae_copub) do
|
|
147
|
-
(slash >> str("ASHRAE") >> space >>
|
|
148
|
-
(str("Guideline") >> space).maybe >>
|
|
149
|
-
digits.as(:ashrae_number) >>
|
|
150
|
-
(dash >> year_digits.as(:ashrae_year)).maybe).as(:ashrae_copub)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
# IEEE cross-reference patterns (/C62.22.1-1996)
|
|
154
|
-
# References another IEEE standard from a specific series (e.g., C62, C37, C57)
|
|
155
|
-
rule(:ieee_crossref) do
|
|
156
|
-
(slash >> str("C") >> digits >> dot >> digits >> dot >> digits >> dash >> year_digits).as(:ieee_crossref)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# IPCEA co-designation suffix (/IPCEA P-46-426-1962). Captured verbatim
|
|
160
|
-
# (leading slash included) so it round-trips through the `crossref`
|
|
161
|
-
# attribute. Used only by the S-designation rule below.
|
|
162
|
-
rule(:ipcea_copub) do
|
|
163
|
-
(slash >> str("IPCEA") >> space >>
|
|
164
|
-
match('[A-Za-z0-9.\-]').repeat(1)).as(:ipcea_copub)
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
# Historical IEEE/IPCEA co-published cable designation (e.g. S-135).
|
|
168
|
-
# The "S-<digits>" number has a dash between the letter series and the
|
|
169
|
-
# digits, which the shared `number` rule deliberately rejects (that
|
|
170
|
-
# tightening is what keeps a bare "IEEE S" from parsing). So this one-off
|
|
171
|
-
# family gets its own rule rather than loosening `number` and risking the
|
|
172
|
-
# 12k-row corpus. Requiring `str("S") >> dash >> digits` keeps "IEEE S"
|
|
173
|
-
# (no dash+digit) rejected. Handles: "IEEE Std S-135", "IEEE S-135",
|
|
174
|
-
# bare "S-135", the "/IPCEA …" slash co-designation, and the
|
|
175
|
-
# "(IPCEA …)" parenthetical variant.
|
|
176
|
-
rule(:s_designation) do
|
|
177
|
-
(publisher >> space).maybe >>
|
|
178
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
179
|
-
(str("S") >> dash >> digits).as(:s_number) >>
|
|
180
|
-
ipcea_copub.maybe >>
|
|
181
|
-
parenthetical.maybe
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
# Document number - support letters and digits, with optional prefix P
|
|
185
|
-
# Complex multi-part numbers like P11073-10404-10419 should be fully captured
|
|
186
|
-
# But simple cases like "623-1976" should not consume the dash before year
|
|
187
|
-
rule(:number) do
|
|
188
|
-
(str("P").maybe >>
|
|
189
|
-
# The numeric core must contain at least one digit: an optional letter
|
|
190
|
-
# prefix (C, S, …) then a required `digits` run, then any digit/letter
|
|
191
|
-
# tail. The old `(digits | upper).repeat(1)` wrongly accepted an
|
|
192
|
-
# all-letter token like a bare "S" (a prefix with no number — e.g.
|
|
193
|
-
# "IEEE S"), which is not a valid IEEE identifier.
|
|
194
|
-
upper.repeat(0) >> digits >> (digits | upper).repeat(0) >>
|
|
195
|
-
# Only consume dash+digits if followed by another dash+digits (multi-part pattern)
|
|
196
|
-
# OR if the digits don't look like a year (not 4 digits starting with 19/20)
|
|
197
|
-
# This prevents consuming "623-1976" as a number but allows "P11073-10404-10419"
|
|
198
|
-
(dash >> digits >> year_digits.absent? >> (dash >> digits).repeat).maybe >>
|
|
199
|
-
lower.maybe).as(:number)
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
# Type - handle "No." and "No" (case-insensitive), longest first
|
|
203
|
-
rule(:type_word) do
|
|
204
|
-
str("Draft Std") | str("STD") | str("Standard") |
|
|
205
|
-
str("Std No.") | str("Std") | # Add "Std No." before "Std"
|
|
206
|
-
str("PTC") | # ASME Performance Test Code
|
|
207
|
-
(match("[Nn]") >> str("o.")) | (match("[Nn]") >> str("o")) |
|
|
208
|
-
str("No")
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
# Part and subpart - handle both dot and dash separators
|
|
212
|
-
rule(:part) do
|
|
213
|
-
(dot | dash) >> match("[0-9A-Za-z]").repeat(1).as(:part)
|
|
214
|
-
end
|
|
215
|
-
|
|
216
|
-
rule(:subpart) do
|
|
217
|
-
(dot | dash | str("_")) >>
|
|
218
|
-
((str("REV") | str("Rev")).maybe >> match("[0-9a-z]").repeat(1) >>
|
|
219
|
-
(dot >> digits).maybe).as(:subpart)
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
# Year component - updated to use comprehensive date parsing
|
|
223
|
-
rule(:year) do
|
|
224
|
-
(dot | dash) >> date_standalone >> str("(E)").maybe
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
# Draft patterns
|
|
228
|
-
rule(:draft_status) do
|
|
229
|
-
# "Active" (bucket 3) joins the generic draft-status path so
|
|
230
|
-
# "IEEE Active Std P… /D…" parses like the "Unapproved" forms, without
|
|
231
|
-
# touching ieee_approved_draft_identifier (which would break the
|
|
232
|
-
# issue-#209 unapproved-drops-Std rendering). "Active Approved" completes
|
|
233
|
-
# the two-word matrix alongside "Active Unapproved" (draft-grammar
|
|
234
|
-
# coverage: the "<status> Draft P…/D…" prefix forms). Longest token first.
|
|
235
|
-
(str("Active Unapproved") | str("Active Approved") | str("Unapproved") |
|
|
236
|
-
str("Approved") | str("Active")) >> space
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
rule(:draft_prefix) do
|
|
240
|
-
space? >> (str("/") | str("_") | dash | space)
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
rule(:draft_version) do
|
|
244
|
-
# Enhanced to handle multiple draft notation patterns
|
|
245
|
-
# D is optional to handle /08 style drafts (e.g., IEEE P1052/08)
|
|
246
|
-
# A draft never begins with "R-" — that is the revision suffix
|
|
247
|
-
# (revision_suffix rule); guard so the D-less path doesn't swallow a
|
|
248
|
-
# bare "/R-<id>" (e.g. the no-draft "P1722/R-1") as a draft.
|
|
249
|
-
(str("R") >> dash).absent? >>
|
|
250
|
-
(str("D") >> str("IS").absent?).maybe >> # Avoid matching "DIS" (ISO stage)
|
|
251
|
-
(
|
|
252
|
-
# Pattern: D3.1 (decimal with 1-2 digits on each side) - MOST COMMON, put first
|
|
253
|
-
# Also handles trailing letter: D7.3A, D2.0E
|
|
254
|
-
(match("[0-9]").repeat(1,
|
|
255
|
-
2) >> dot >> match("[0-9]").repeat(1,
|
|
256
|
-
2) >> lower.maybe) |
|
|
257
|
-
# Pattern: D.XX (decimal starting with dot) - e.g., D.19
|
|
258
|
-
(dot >> digits) |
|
|
259
|
-
# Pattern: DX+X (plus sign) - e.g., D1+1
|
|
260
|
-
(digits >> str("+") >> digits) |
|
|
261
|
-
# Pattern: DXXXXeYY or DXXXX.eYY (complex) - e.g., D2012.e27
|
|
262
|
-
(digits >> dot.maybe >> str("e") >> digits) |
|
|
263
|
-
# Pattern: D-X or DX or DX-d or DX_letter (original patterns)
|
|
264
|
-
# Handles: D12, D3.0, D043Rev18, suffixes like D15Sept
|
|
265
|
-
(str("-").maybe >> match("[0-9A-Za-z]").repeat(1) >> (str("-d") | (str("_") >> match("[0-9A-Za-z]").repeat(0))).maybe)
|
|
266
|
-
).as(:draft_version)
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
rule(:draft_date) do
|
|
270
|
-
# Enhanced to handle: ", Sept 2008" or " Sept 2008" or ", Month Year"
|
|
271
|
-
((comma | space) >> month_name.as(:month) >> space >> year_digits.as(:year)) |
|
|
272
|
-
# Space-separated bare year after the draft designator
|
|
273
|
-
# ("IEEE Draft Std P14764/D1 2004, Nov 2004" - the "D1 2004" draft
|
|
274
|
-
# carries its own year, with the print date still trailing).
|
|
275
|
-
(space >> year_digits.as(:year)) |
|
|
276
|
-
# Numeric-month form ", 05 2007" / " 05 2007" — no text month name. The
|
|
277
|
-
# year separator may be a dash: preprocessing (parser.rb ~1278) rewrites
|
|
278
|
-
# a trailing " <digits> <year>" to "<digits>-<year>", so "05 2007"
|
|
279
|
-
# reaches the grammar as "05-2007".
|
|
280
|
-
((comma | space) >> month_numeric.as(:month) >> (space | dash) >> year_digits.as(:year)) |
|
|
281
|
-
(((space? >> comma >> space?) | space) >> month_name.as(:month) >>
|
|
282
|
-
(
|
|
283
|
-
# "Month DD, Year" (day then comma) and "Month DD Year" (day, no
|
|
284
|
-
# comma) — the day/year separator may be a dash for the same
|
|
285
|
-
# preprocessing reason ("July 15 2012" → "July 15-2012").
|
|
286
|
-
((space >> digits.as(:day)) >> ((comma | space | dash) >> year_digits.as(:year))) |
|
|
287
|
-
((space >> digits.as(:day)).maybe >> comma >> year_digits.as(:year)) |
|
|
288
|
-
(comma >> space? >> year_digits.as(:year)) |
|
|
289
|
-
(space >> year_digits.as(:year))
|
|
290
|
-
))
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
# FDIS and similar ISO stage codes without D prefix (Pattern 3)
|
|
294
|
-
# These appear after / in IEEE P identifiers but don't have the D prefix
|
|
295
|
-
# Examples: IEEE P15939/FDIS, IEEE P1234/CDV
|
|
296
|
-
rule(:fdraft) do
|
|
297
|
-
(slash >>
|
|
298
|
-
(str("FDIS") | str("CDV") | str("CD") | str("WD") | str("PWI") | str("NP")) >>
|
|
299
|
-
(
|
|
300
|
-
((comma | space) >> month_name.as(:month) >> space >> year_digits.as(:year)) | # Month Year
|
|
301
|
-
((comma | space) >> year_digits.as(:year)) # Year only (e.g., /FDIS, 2016)
|
|
302
|
-
).maybe >>
|
|
303
|
-
parenthetical.maybe).as(:fdraft)
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
rule(:draft) do
|
|
307
|
-
(draft_prefix >> draft_version.repeat(1, 2) >>
|
|
308
|
-
(dot >> digits.as(:revision)).maybe >>
|
|
309
|
-
# The compound both-systems form (docs/IEEE-DRAFT-STAGES.md
|
|
310
|
-
# §1.3): "=DDIS.3" - IEEE draft ordinal = draft of the ISO/IEC
|
|
311
|
-
# stage, with its iteration. The glued "=DDIS3" / "=DDIS-3"
|
|
312
|
-
# spellings are accepted aliases of "=DDIS.3".
|
|
313
|
-
(str("=") >> (str("D") >> (str("FDIS") | str("CDV") | str("PWI") |
|
|
314
|
-
str("DIS") | str("WD") | str("NP") | str("CD")) |
|
|
315
|
-
(str("FDIS") | str("CDV") | str("PWI") | str("DIS") | str("WD") |
|
|
316
|
-
str("NP") | str("CD"))).as(:draft_iso_stage) >>
|
|
317
|
-
(dot | dash).maybe >> digits.as(:draft_iso_iteration).maybe).maybe >>
|
|
318
|
-
draft_date.maybe).as(:draft)
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
# Trailing revision suffix "/R-<id>". Normalization funnels every revision
|
|
322
|
-
# spelling here — IEEE's native inline "Rev<n>" (repositioned) and
|
|
323
|
-
# relaton's synthetic "/R-<x>" (kept in place) — so a single trailing rule
|
|
324
|
-
# captures them all. The id is alphanumeric ("2", "18", "i").
|
|
325
|
-
rule(:revision_suffix) do
|
|
326
|
-
slash >> str("R") >> dash >> match('[0-9A-Za-z]').repeat(1).as(:revision)
|
|
327
|
-
end
|
|
328
|
-
|
|
329
|
-
# Edition - enhanced to support IEC formats like "Edition 1.0 2015-03"
|
|
330
|
-
#
|
|
331
|
-
# The edition's own year is captured as :edition_year (NOT :year). The
|
|
332
|
-
# generic Std branch carries a base "-YYYY" slot AND a separate trailing
|
|
333
|
-
# `edition.maybe`; a bare :year here would collide with the base :year
|
|
334
|
-
# when both fire, so Parslet warns "Duplicate subtrees … keys: [:year]"
|
|
335
|
-
# and drops the base identity year (the same failure #299 fixed for the
|
|
336
|
-
# trailing month/year clause). The builder promotes :edition_year to the
|
|
337
|
-
# identity year only when there is no base year.
|
|
338
|
-
rule(:edition) do
|
|
339
|
-
(comma >> year_digits.as(:edition_year) >> str(" Edition")) |
|
|
340
|
-
((space | dash) >> str("Edition ") >>
|
|
341
|
-
(digits >> dot >> digits).as(:edition) >>
|
|
342
|
-
# Year separator: a space, " - ", or a bare dash (preprocessing
|
|
343
|
-
# rewrites "Edition 3.0 2016" -> "Edition 3.0-2016", the shape the
|
|
344
|
-
# normalized "/E-<n>-YYYY" suffix produces — nil-residue item 1).
|
|
345
|
-
(str(" - ") | space | dash) >>
|
|
346
|
-
year_digits.as(:edition_year) >>
|
|
347
|
-
(dash >> digit.repeat(2, 2).as(:edition_month)).maybe) # Capture -MM as edition_month
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
# Part/subpart/year combinations
|
|
351
|
-
rule(:part_subpart_year) do
|
|
352
|
-
(part >> subpart.repeat(1, 2) >> year) |
|
|
353
|
-
(part >> subpart >> year) |
|
|
354
|
-
(part >> year) |
|
|
355
|
-
(part >> subpart) |
|
|
356
|
-
year |
|
|
357
|
-
part
|
|
358
|
-
end
|
|
359
|
-
|
|
360
|
-
# Corrigendum
|
|
361
|
-
rule(:corrigendum) do
|
|
362
|
-
# Enhanced: Accept space as separator, make separators more flexible
|
|
363
|
-
# Also accept "Corrigendum" as alternative to "Cor"
|
|
364
|
-
((str("_") | slash | dash | space) >>
|
|
365
|
-
(str("Corrigendum") | str("Cor")) >>
|
|
366
|
-
(dash | dot | space).maybe >> # More flexible separator after "Cor"
|
|
367
|
-
space? >> # Add space handling after separator
|
|
368
|
-
digits.as(:cor_number).maybe >>
|
|
369
|
-
((dash | str(":") | space) >> year_digits.as(:cor_year)).maybe).as(:corrigendum)
|
|
370
|
-
end
|
|
371
|
-
|
|
372
|
-
# Amendment — mirrors the corrigendum rule's separator flexibility so
|
|
373
|
-
# IEEE-format "/Amd 2-2004" and "/Amd2-2004" parse the same way as
|
|
374
|
-
# their Cor counterparts (issue #210).
|
|
375
|
-
rule(:amendment) do
|
|
376
|
-
((str("_") | slash | dash | space) >>
|
|
377
|
-
(str("Amendment") | str("Amd")) >>
|
|
378
|
-
(dash | dot | space).maybe >>
|
|
379
|
-
space? >>
|
|
380
|
-
digits.as(:amd_number).maybe >>
|
|
381
|
-
((dash | str(":") | space) >> year_digits.as(:amd_year)).maybe).as(:amendment)
|
|
382
|
-
end
|
|
383
|
-
|
|
384
|
-
# Interpretation notation (/INT)
|
|
385
|
-
# Enhanced to support optional year suffix: /INT-1991, /INT 1991
|
|
386
|
-
rule(:interpretation) do
|
|
387
|
-
(slash >> str("INT") >> ((dash | str(":") | space) >> year_digits.as(:int_year)).maybe).as(:interpretation)
|
|
388
|
-
end
|
|
389
|
-
|
|
390
|
-
# Reaffirmed - enhanced to support (R1992) format without space
|
|
391
|
-
rule(:reaffirmed) do
|
|
392
|
-
(
|
|
393
|
-
# Format: "Reaffirmed 1992"
|
|
394
|
-
(str("Reaffirmed ") >> year_digits.as(:year)) |
|
|
395
|
-
# Format: "(R1992)" - parentheses with R prefix (with or without space before)
|
|
396
|
-
(space.maybe >> str("(R") >> year_digits.as(:year) >> str(")"))
|
|
397
|
-
).as(:reaffirmed)
|
|
398
|
-
end
|
|
399
|
-
|
|
400
|
-
# Redline suffix at the very end. Accepts relaton's canonical " Redline"
|
|
401
|
-
# (space, no dash) and pubid's older " - Redline" (space-dash-space),
|
|
402
|
-
# case-insensitive. Captured (presence only) so the builder sets a
|
|
403
|
-
# `redline: true` flag the renderer restores — a redline is a distinct
|
|
404
|
-
# document and must not collapse to its base standard.
|
|
405
|
-
rule(:redline) do
|
|
406
|
-
(space >> (dash >> space).maybe >>
|
|
407
|
-
(str("Redline") | str("REDLINE") | str("redline"))).as(:redline)
|
|
408
|
-
end
|
|
409
|
-
|
|
410
|
-
# Book nickname (e.g., "[The Orange Book]", "[IEEE Gold Book]")
|
|
411
|
-
rule(:book_nickname) do
|
|
412
|
-
space >> str("[") >> match("[^\\]]").repeat(1).as(:nickname) >> str("]")
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
# Relationship type keywords for Pattern 4 identifiers
|
|
416
|
-
rule(:relationship_revision_of) do
|
|
417
|
-
str("Revision of ") | str("Revison of ")
|
|
418
|
-
end
|
|
419
|
-
rule(:relationship_amendment_to) { str("Amendment to ") }
|
|
420
|
-
rule(:relationship_corrigendum_to) do
|
|
421
|
-
str("Corrigendum to ") | str("Corrigenda to ")
|
|
422
|
-
end
|
|
423
|
-
rule(:relationship_incorporates) do
|
|
424
|
-
str("incorporates ") | str("Incorporating ") | str("Incorporates ")
|
|
425
|
-
end
|
|
426
|
-
rule(:relationship_adoption_of) { str("Adoption of ") }
|
|
427
|
-
rule(:relationship_supplement_to) { str("Supplement to ") }
|
|
428
|
-
rule(:relationship_draft_amendment) do
|
|
429
|
-
str("Draft Amendment to ") | str("DRAFT Amendment to ")
|
|
430
|
-
end
|
|
431
|
-
rule(:relationship_draft_revision) { str("Draft Revision of ") }
|
|
432
|
-
rule(:relationship_reaffirmation) { str("Reaffirmation of ") }
|
|
433
|
-
rule(:relationship_redesignation) do
|
|
434
|
-
str("Redesignation of ") | str("redesignated as ")
|
|
435
|
-
end
|
|
436
|
-
rule(:relationship_supersedes) { str("Supersedes ") | str("Supercedes ") }
|
|
437
|
-
rule(:relationship_previously_designated) do
|
|
438
|
-
str("Previously designated as ")
|
|
439
|
-
end
|
|
440
|
-
rule(:relationship_includes) { str("Includes ") } # NEW Session 171
|
|
441
|
-
|
|
442
|
-
# Combined relationship type (longest match first)
|
|
443
|
-
rule(:relationship_type) do
|
|
444
|
-
relationship_draft_amendment.as(:draft_amendment_to) |
|
|
445
|
-
relationship_draft_revision.as(:draft_revision_of) |
|
|
446
|
-
relationship_previously_designated.as(:previously_designated_as) |
|
|
447
|
-
relationship_reaffirmation.as(:reaffirmation_of) |
|
|
448
|
-
relationship_redesignation.as(:redesignation_of) |
|
|
449
|
-
relationship_supersedes.as(:supersedes) |
|
|
450
|
-
relationship_includes.as(:includes) | # NEW Session 171
|
|
451
|
-
relationship_revision_of.as(:revision_of) |
|
|
452
|
-
relationship_amendment_to.as(:amendment_to) |
|
|
453
|
-
relationship_corrigendum_to.as(:corrigendum_to) |
|
|
454
|
-
relationship_incorporates.as(:incorporates) |
|
|
455
|
-
relationship_adoption_of.as(:adoption_of) |
|
|
456
|
-
relationship_supplement_to.as(:supplement_to)
|
|
457
|
-
end
|
|
458
|
-
|
|
459
|
-
# Identifier string (for parsing list of related identifiers)
|
|
460
|
-
# Captures text until delimiter: comma, closing paren, "and", " / ", "; ", "as amended by"
|
|
461
|
-
# Uses absent? to ensure we stop at these delimiters
|
|
462
|
-
rule(:identifier_string) do
|
|
463
|
-
(
|
|
464
|
-
str(", and ").absent? >>
|
|
465
|
-
str(" and ").absent? >>
|
|
466
|
-
str(", ").absent? >>
|
|
467
|
-
str(" as amended by ").absent? >>
|
|
468
|
-
# Stop at any "/", ";", or "-" that introduces another relationship
|
|
469
|
-
# (look-ahead: separator + relationship_type keyword). This lets the
|
|
470
|
-
# slash inside "IEEE Std 525-2007/Cor 1-2015" stay part of the
|
|
471
|
-
# identifier, while the slash before "Incorporates ..." splits.
|
|
472
|
-
relationship_break.absent? >>
|
|
473
|
-
str(")").absent? >>
|
|
474
|
-
match(".")
|
|
475
|
-
).repeat(1)
|
|
476
|
-
end
|
|
477
|
-
|
|
478
|
-
# Identifier list (comma and "and" separated)
|
|
479
|
-
rule(:identifier_list) do
|
|
480
|
-
identifier_string.as(:id) >>
|
|
481
|
-
(
|
|
482
|
-
(str(", and ") | str(" and ") | str(", ")) >>
|
|
483
|
-
identifier_string.as(:id)
|
|
484
|
-
).repeat
|
|
485
|
-
end
|
|
486
|
-
|
|
487
|
-
# "as amended by" clause with identifier list
|
|
488
|
-
rule(:as_amended_by_clause) do
|
|
489
|
-
# Variant 1: "as amended by IEEE's X, Y, Z"
|
|
490
|
-
(str(" as amended by IEEE's ") >> identifier_list.as(:amendments)) |
|
|
491
|
-
# Variant 2: "as amended by X, Y, Z" (standard)
|
|
492
|
-
(str(" as amended by ") >> identifier_list.as(:amendments)) |
|
|
493
|
-
# Variant 3: "and its approved amendments" (no specific list)
|
|
494
|
-
str(" and its approved amendments").as(:approved_amendments)
|
|
495
|
-
end
|
|
496
|
-
|
|
497
|
-
# A character sequence that may separate two relationships inside the
|
|
498
|
-
# parenthetical: a "/", ";", or "-" with optional surrounding spaces.
|
|
499
|
-
# Standalone it is permissive — the actual decision to split is gated by
|
|
500
|
-
# `relationship_break`, which requires another relationship_type to
|
|
501
|
-
# follow. This way the slash in "IEEE Std 525-2007/Cor 1-2015" stays
|
|
502
|
-
# part of the related identifier.
|
|
503
|
-
rule(:relationship_separator) do
|
|
504
|
-
(space.maybe >> str("/") >> space.maybe) |
|
|
505
|
-
(space.maybe >> str(";") >> space.maybe) |
|
|
506
|
-
(space.maybe >> str("-") >> space.maybe)
|
|
507
|
-
end
|
|
508
|
-
|
|
509
|
-
# Look-ahead: a separator followed by another relationship_type keyword.
|
|
510
|
-
# Used as an absent? guard in identifier_string so the parser stops
|
|
511
|
-
# consuming characters right before a new relationship begins.
|
|
512
|
-
rule(:relationship_break) do
|
|
513
|
-
relationship_separator >> space.maybe >> relationship_type
|
|
514
|
-
end
|
|
515
|
-
|
|
516
|
-
# Relationship clause (handles all relationship types)
|
|
517
|
-
rule(:relationship_clause) do
|
|
518
|
-
space.maybe >> str("(") >>
|
|
519
|
-
relationship_type.as(:relationship_type) >>
|
|
520
|
-
identifier_list.as(:related_ids) >>
|
|
521
|
-
as_amended_by_clause.maybe >>
|
|
522
|
-
# Additional relationships separated by "/", ";", or "-" (optionally
|
|
523
|
-
# surrounded by spaces). The separator is only honored when followed
|
|
524
|
-
# by another relationship_type — identifier-internal slashes like
|
|
525
|
-
# "/Cor 1-2015" are not mistaken for relationship breaks because
|
|
526
|
-
# identifier_string stops at relationship_break ahead.
|
|
527
|
-
(
|
|
528
|
-
relationship_separator >>
|
|
529
|
-
relationship_type.as(:relationship_type) >>
|
|
530
|
-
identifier_list.as(:related_ids) >>
|
|
531
|
-
as_amended_by_clause.maybe
|
|
532
|
-
).repeat.as(:additional_rels) >>
|
|
533
|
-
str(")")
|
|
534
|
-
end
|
|
535
|
-
|
|
536
|
-
# Title portion separated by colon (Category 8)
|
|
537
|
-
rule(:title_portion) do
|
|
538
|
-
str(":") >> space >> match('[^\n]').repeat(1).as(:title)
|
|
539
|
-
end
|
|
540
|
-
|
|
541
|
-
# Approved Draft suffix (Category 7)
|
|
542
|
-
rule(:approved_draft_suffix) do
|
|
543
|
-
(space >> str("- (Approved Draft)")) | (space >> str("(Approved Draft)"))
|
|
544
|
-
end
|
|
545
|
-
|
|
546
|
-
# Additional parameters (inside parentheses)
|
|
547
|
-
rule(:additional_parameters) do
|
|
548
|
-
(space.maybe >> str("(") >> space.maybe >> # Space before/after '(' optional
|
|
549
|
-
# ("( Revision of …)" - a crawl space inside the paren must not push
|
|
550
|
-
# the narrative to the catch-all and into the render).
|
|
551
|
-
(reaffirmed |
|
|
552
|
-
# Handle "Revision of IEEE Std ..." with optional space after Std
|
|
553
|
-
(str("Revision of IEEE Std ") >> space.maybe >> match("[^)]").repeat(1).as(:revision_of)) |
|
|
554
|
-
# Handle typo "Revison of IEEE Std ..." with optional space after Std
|
|
555
|
-
(str("Revison of IEEE Std ") >> space.maybe >> match("[^)]").repeat(1).as(:revision_of)) |
|
|
556
|
-
# Handle "Revision to IEEE Std ..." with optional space after Std
|
|
557
|
-
(str("Revision to IEEE Std ") >> space.maybe >> match("[^)]").repeat(1).as(:revision_of)) |
|
|
558
|
-
# Handle "Revison to IEEE Std ..." with optional space after Std
|
|
559
|
-
(str("Revison to IEEE Std ") >> space.maybe >> match("[^)]").repeat(1).as(:revision_of)) |
|
|
560
|
-
# Amendment patterns (case-insensitive DRAFT)
|
|
561
|
-
((str("DRAFT") | str("Draft") | str("draft")) >> str(" Amendment to ") >> match("[^)]").repeat(1).as(:draft_amendment_to)) |
|
|
562
|
-
(str("Amendment to IEEE Std ") >> space.maybe >> match("[^)]").repeat(1).as(:amendment_to)) |
|
|
563
|
-
# Adoption patterns
|
|
564
|
-
(str("Adoption of ") >> match("[^)]").repeat(1).as(:adoption)) |
|
|
565
|
-
# Other specific patterns
|
|
566
|
-
(str("Notebooks") >> space? >> match("[^,\\)]").repeat(1).as(:notebooks)) |
|
|
567
|
-
(str("Standard Newspaper(s)") >> space? >> match("[^,\\)]").repeat(1).as(:standard_newspapers)) |
|
|
568
|
-
# Catch-all for any other parenthetical content (MUST BE LAST)
|
|
569
|
-
match("[^)]").repeat(1).as(:parenthetical_content)
|
|
570
|
-
) >>
|
|
571
|
-
str(")").maybe).as(:parameters)
|
|
572
|
-
end
|
|
573
|
-
|
|
574
|
-
# Parenthetical - try relationship_clause first, then fall back to additional_parameters
|
|
575
|
-
rule(:parenthetical) do
|
|
576
|
-
relationship_clause | additional_parameters
|
|
577
|
-
end
|
|
578
|
-
|
|
579
|
-
# IEC/IEEE copublished pattern - handle all variations comprehensively
|
|
580
|
-
# BUT exclude P prefix patterns (those are joint development)
|
|
581
|
-
rule(:iec_ieee_copublished) do
|
|
582
|
-
str("IEC/IEEE") >>
|
|
583
|
-
space >>
|
|
584
|
-
str("P").absent? >> # NOT a P prefix (would be joint development)
|
|
585
|
-
# The copublished number must contain at least one digit. This rejects
|
|
586
|
-
# an all-letter placeholder like "IEC/IEEE TR" (no real document
|
|
587
|
-
# number) — the same "require a digit" tightening the Standard number
|
|
588
|
-
# rule got, applied to the copublished number grammar.
|
|
589
|
-
(match("[^0-9\n]").repeat >> digit).present? >>
|
|
590
|
-
match("[^\n]").repeat(1).as(:content)
|
|
591
|
-
end
|
|
592
|
-
|
|
593
|
-
# Joint development patterns (ISO/IEC/IEEE in either IEEE or ISO format)
|
|
594
|
-
rule(:joint_development_ieee_format) do
|
|
595
|
-
# ISO/IEC/IEEE P26511/D8-2018 or ISO/IEEE P1003.1-2008 or IEC/IEEE P62582-1-2011
|
|
596
|
-
# ALSO handle: IEC/IEEE P60780-323, CDV1 2014 (comma before stage code)
|
|
597
|
-
# ALSO handle: IEEE/CSA P844.1/293.1/D2 (CSA dual numbering)
|
|
598
|
-
# ALSO handle: IEEE/ISO/IEC P42010/D=CD-2020 — the printed publisher
|
|
599
|
-
# order is the organization's perspective (pubid#469) and parses as
|
|
600
|
-
# printed; it is no longer rewritten to ISO-first.
|
|
601
|
-
(str("ISO/IEC/IEEE") | str("IEEE/ISO/IEC") | str("ISO/IEEE") | str("IEC/IEEE") | str("IEEE/CSA")).as(:joint_publishers) >>
|
|
602
|
-
space >>
|
|
603
|
-
# P = project (the document is a draft): identity-bearing, so it
|
|
604
|
-
# is captured and preserved, never silently consumed.
|
|
605
|
-
str("P").as(:project_marker) >>
|
|
606
|
-
digits.as(:number) >>
|
|
607
|
-
((dot | dash) >> digits.as(:part)).maybe >> # Optional part like .1 or -1
|
|
608
|
-
# CSA dual numbering: /293.1 (second number)
|
|
609
|
-
(slash >> digits >> (dot >> digits).maybe >> (dash >> digits.as(:draft_version)).maybe).maybe >>
|
|
610
|
-
(
|
|
611
|
-
# Variant 1b: the ordinal-less stage draft "D=CDV-2020" -
|
|
612
|
-
# D (draft) = CDV (the IEC stage it drafts). The year rides in
|
|
613
|
-
# the draft clause (a distinct key, so the builder keeps the
|
|
614
|
-
# date inside the designator). The year follows IEEE format:
|
|
615
|
-
# dash-joined ("D=CD-2020", the ruled canonical); the colon
|
|
616
|
-
# spelling ("D=CDV:2020") stays accepted as the alias it was
|
|
617
|
-
# frozen with. A dash-year is guarded to 19xx/20xx so a
|
|
618
|
-
# YYMM monthcode tail can never be read as a year.
|
|
619
|
-
(slash >> str("D") >> str("=") >>
|
|
620
|
-
(str("CDV") | str("FDIS") | str("PWI") | str("WD") |
|
|
621
|
-
str("NP") | str("DIS") | str("CD")).as(:draft_iso_stage) >>
|
|
622
|
-
((str(":") | str("-")) >>
|
|
623
|
-
((str("19") | str("20")) >> digit >> digit).as(:draft_stage_year)).maybe) |
|
|
624
|
-
# Variant 1: /D8 notation (original), with the compound
|
|
625
|
-
# both-systems suffix "=DDIS.3" (docs/IEEE-DRAFT-STAGES.md §1.3)
|
|
626
|
-
(slash >> str("D") >> digits.as(:draft_version) >>
|
|
627
|
-
(str("=") >> (str("D") >> (str("FDIS") | str("CDV") | str("PWI") |
|
|
628
|
-
str("DIS") | str("WD") | str("NP") | str("CD")) |
|
|
629
|
-
(str("FDIS") | str("CDV") | str("PWI") | str("DIS") | str("WD") |
|
|
630
|
-
str("NP") | str("CD"))).as(:draft_iso_stage) >>
|
|
631
|
-
(dot | dash).maybe >> digits.as(:draft_iso_iteration).maybe).maybe) |
|
|
632
|
-
# Variant 2: , CDV1 notation (comma before stage code) —
|
|
633
|
-
# the stage draft of the named ISO/IEC stage, its iteration
|
|
634
|
-
(comma >> (str("CDV") | str("FDIS") | str("CD") | str("DIS")).as(:iec_stage) >> digits.maybe.as(:stage_iteration))
|
|
635
|
-
).maybe >>
|
|
636
|
-
# Optional edition, from relaton's "/E-<n>" suffix normalized to
|
|
637
|
-
# "Edition <n>.0[ YYYY]" (nil-residue hand-off item 1). The edition
|
|
638
|
-
# rule carries its own year, so the year clause below simply doesn't
|
|
639
|
-
# fire when an edition is present.
|
|
640
|
-
edition.maybe >>
|
|
641
|
-
((dash >> year_digits.as(:year)) | # Either -YEAR
|
|
642
|
-
(comma.maybe >> space >> month_name.as(:month) >> space.maybe >> year_digits.as(:year))).maybe >> # Or Month YEAR (with optional comma)
|
|
643
|
-
revision_suffix.maybe
|
|
644
|
-
end
|
|
645
|
-
|
|
646
|
-
rule(:joint_development_iso_format) do
|
|
647
|
-
# ISO-led stage designations. Two spellings:
|
|
648
|
-
# colon form : "ISO/IEC/IEEE FDIS 26511:2018" (already used)
|
|
649
|
-
# corpus form : "ISO/IEC/IEEE FDIS P26515-2018-05" (historical)
|
|
650
|
-
# The corpus form adds a leading "P" on the number, a trailing
|
|
651
|
-
# "-YYYY[-MM]" date (instead of ":YYYY"), multi-digit committee-draft
|
|
652
|
-
# stage codes (CD1..CD4) plus CDV, and a wider set of joint publishers.
|
|
653
|
-
# (roadmap items 2/3, phase 1). longest publisher token first.
|
|
654
|
-
# The stage is OPTIONAL ONLY for ISO-led joint prefixes - the
|
|
655
|
-
# stage-less PUBLISHED form (pubid#317): "ISO/IEC/IEEE 26511:2018",
|
|
656
|
-
# "ISO/IEEE 11073-20101:2004(E)". Every other prefix keeps the
|
|
657
|
-
# stage REQUIREMENT so this rule cannot steal what belongs to
|
|
658
|
-
# iec_ieee_copublished ("IEC/IEEE 60076-2016"), the bare-IEEE
|
|
659
|
-
# project rules ("IEEE P802.16/D-3") or the ISO flavor
|
|
660
|
-
# ("ISO/IEC <n>:<year>").
|
|
661
|
-
iso_led = (str("ISO/IEC/IEEE") | str("IEEE/ISO/IEC") |
|
|
662
|
-
str("IEEE/IEC/ISO") | str("ISO/IEEE"))
|
|
663
|
-
staged_only = (str("IEC/IEEE") | str("IEEE/IEC") |
|
|
664
|
-
str("ISO/IEC") | str("IEEE"))
|
|
665
|
-
# ISO stage codes: FDIS, FCD, CDV; DIS/CD with an optional round
|
|
666
|
-
# digit (DIS2, CD1..CD4); WD/PWI/NP.
|
|
667
|
-
iso_stage = ((str("FDIS") >> digit.maybe) | (str("FCD") >> digit.maybe) |
|
|
668
|
-
(str("CDV") >> digit.maybe) |
|
|
669
|
-
(str("DIS") >> digit.maybe) |
|
|
670
|
-
(str("CD") >> digit.maybe) |
|
|
671
|
-
(str("WD") >> digit.maybe) | (str("PWI") >> digit.maybe) |
|
|
672
|
-
(str("NP") >> digit.maybe)).as(:iso_stage)
|
|
673
|
-
std_noise = (space >> str("Std")).maybe
|
|
674
|
-
# The empty-string marker distinguishes the stage-less PUBLISHED
|
|
675
|
-
# tree in the builder (absence of :iso_stage alone means IEEE format).
|
|
676
|
-
((iso_led.as(:joint_publishers) >> space >>
|
|
677
|
-
(iso_stage >> std_noise >> space |
|
|
678
|
-
str("").as(:iso_published) >> space.maybe)) |
|
|
679
|
-
(staged_only.as(:joint_publishers) >> space >>
|
|
680
|
-
iso_stage >> std_noise >> space)) >>
|
|
681
|
-
str("P").as(:project_marker).maybe >> # project marker (P =
|
|
682
|
-
# project/draft; its
|
|
683
|
-
# presence is identity)
|
|
684
|
-
digits.as(:number) >>
|
|
685
|
-
# part must not swallow the trailing year (year_digits.absent?). A
|
|
686
|
-
# DASH-joined part is tagged (:part_dash) - the catalogue-printed
|
|
687
|
-
# joint form spells the part with a dash ("21451-7") where the ISO
|
|
688
|
-
# form uses the dot.
|
|
689
|
-
((dot >> year_digits.absent? >> digits.as(:part)) |
|
|
690
|
-
(dash >> str("").as(:part_dash) >> year_digits.absent? >>
|
|
691
|
-
digits.as(:part))).maybe >>
|
|
692
|
-
(
|
|
693
|
-
(str(":") >> year_digits.as(:year)) |
|
|
694
|
-
# The dash-year (and ", Month YYYY" text date below) spellings are
|
|
695
|
-
# the catalogue-PRINTED joint form; tag them (:printed_form) so the
|
|
696
|
-
# builder routes to a Standard instead of the ISO joint reference.
|
|
697
|
-
(dash >> year_digits.as(:year) >>
|
|
698
|
-
(dash >> month_numeric.as(:month)).maybe >>
|
|
699
|
-
str("").as(:printed_dash_year)) |
|
|
700
|
-
# Trailing text date ", April 2015" / " April 2015" (build_joint_development
|
|
701
|
-
# already reads :month/:year). No :year collision — the iso rule has no
|
|
702
|
-
# other :year capture (edition uses :edition_year).
|
|
703
|
-
((comma | space) >> month_name.as(:month) >> space >>
|
|
704
|
-
year_digits.as(:year) >> str("").as(:printed_month_year))
|
|
705
|
-
).maybe >>
|
|
706
|
-
# Optional /D<draft> tail; the historical hyphenated form
|
|
707
|
-
# "…/D-3-2017" carries its date inside the draft clause (bucket 5);
|
|
708
|
-
# a date-less "/D-4" keeps its hyphen (bucket 7), hence dash.maybe.
|
|
709
|
-
# A text date may trail the DRAFT itself (pubid#216:
|
|
710
|
-
# "CD P26515/D1, March 2017", "FDIS P15289/D3, 2017") — distinct
|
|
711
|
-
# keys (:draft_month/:draft_year), because a plain :month/:year
|
|
712
|
-
# here collides with the date clause above and parslet drops the
|
|
713
|
-
# subtree with a "Duplicate subtrees" warning.
|
|
714
|
-
# The ISO/IEC edition marker may sit between the year and an
|
|
715
|
-
# amendment/draft tail: "8802.11:2012 (E)/Amd 1-2014". A distinct
|
|
716
|
-
# key - a second :parameters capture here collides with the
|
|
717
|
-
# trailing parenthetical slot (parslet drops duplicate subtrees).
|
|
718
|
-
(space.maybe >> str("(") >>
|
|
719
|
-
match("[^)]").repeat(1).as(:edition_marker) >> str(")")).maybe >>
|
|
720
|
-
# The stage-draft clause of the ISO-led print: "/D=WD.5" -
|
|
721
|
-
# D (draft) = the ISO/IEC stage it drafts, with its iteration
|
|
722
|
-
# (docs/IEEE-DRAFT-STAGES.md §1.2).
|
|
723
|
-
((slash >> str("D") >> str("=") >>
|
|
724
|
-
((str("FDIS") >> digit.maybe) | (str("FCD") >> digit.maybe) |
|
|
725
|
-
(str("CDV") >> digit.maybe) |
|
|
726
|
-
(str("DIS") >> digit.maybe) |
|
|
727
|
-
(str("CD") >> digit.maybe) |
|
|
728
|
-
(str("WD") >> digit.maybe) | (str("PWI") >> digit.maybe) |
|
|
729
|
-
(str("NP") >> digit.maybe)).as(:draft_iso_stage) >>
|
|
730
|
-
(dot >> (digits >> match("[A-Za-z]").repeat(0, 1)).as(:draft_iso_iteration)).maybe) |
|
|
731
|
-
(slash >> str("D") >> dash.maybe >>
|
|
732
|
-
match('[0-9.]').repeat(1).as(:draft_version) >>
|
|
733
|
-
(((comma | space) >> month_name.as(:draft_month) >> space >>
|
|
734
|
-
year_digits.as(:draft_year)) |
|
|
735
|
-
(comma >> year_digits.as(:draft_year))).maybe).maybe).maybe >>
|
|
736
|
-
# Optional amendment tail (pubid#317:
|
|
737
|
-
# "8802-11:2012/Amd.1:2014(E)") - the flat tree keys reuse
|
|
738
|
-
# build_flat_amendment.
|
|
739
|
-
(slash >> str("Amd") >> (dot | space).maybe >>
|
|
740
|
-
digits.as(:amd_number) >>
|
|
741
|
-
((str(":") | dash) >> year_digits.as(:amd_year)).maybe).maybe >>
|
|
742
|
-
# Optional corrigendum tail, the ISO print's dotted spelling
|
|
743
|
-
# (pubid#215): "8802-1AC:2018/Cor.1:2020(E)". The shared
|
|
744
|
-
# corrigendum rule accepts the slash/dot/colon separators; the
|
|
745
|
-
# flat tree routes through build_flat_corrigendum.
|
|
746
|
-
corrigendum.maybe >>
|
|
747
|
-
# Optional edition, from relaton's "/E-<n>" suffix normalized to
|
|
748
|
-
# "Edition <n>.0[ YYYY]" (nil-residue hand-off item 1).
|
|
749
|
-
edition.maybe >>
|
|
750
|
-
revision_suffix.maybe >>
|
|
751
|
-
# A redline is a distinct document of the joint ISO print
|
|
752
|
-
# (pubid#215): "15289:2015(E) - Redline". Same flag semantics as
|
|
753
|
-
# the generic rules - the builder sets redline: true.
|
|
754
|
-
redline.maybe >>
|
|
755
|
-
# Published joint docs print a language marker, after either the
|
|
756
|
-
# year or the amendment tail: "9945:2009(E)", "...Amd.1:2014(E)".
|
|
757
|
-
# The crawl sometimes spaces it ("…(E), January 2017" family,
|
|
758
|
-
# pubid#216), and a relationship parenthetical may follow
|
|
759
|
-
# ("…CD2 P15288-2013-09 (Revision of …)").
|
|
760
|
-
parenthetical.maybe
|
|
761
|
-
end
|
|
762
|
-
|
|
763
|
-
# Embedded (stage-LAST) ISO-led designations: the corpus writes the ISO
|
|
764
|
-
# stage AFTER the (dotted or dashed) part —
|
|
765
|
-
# "ISO/IEC/IEEE 29119.4.FDIS, April 2015" (dot part .4, stage .FDIS)
|
|
766
|
-
# "ISO/IEC/IEEE 24748-5.CD3, February 2015" (dash part -5, stage .CD3)
|
|
767
|
-
# "IEEE P24748.5.CD3, July 2015" (bare IEEE + P)
|
|
768
|
-
# — rather than before the number (joint_development_iso_format). Same
|
|
769
|
-
# meaning as the stage-first form: `29119.4`/`29119-4` = "29119 part 4" and
|
|
770
|
-
# the trailing `.FDIS` is the ISO stage, NOT a second part. Routes through
|
|
771
|
-
# the same build_joint_development (via :joint_publishers/:iso_stage), so the
|
|
772
|
-
# stage is modeled correctly and the numeric part stays separate.
|
|
773
|
-
# The stage-less ISO/IEC label with a colon year and the ISO/IEC
|
|
774
|
-
# edition marker: "ISO/IEC 13210:1994 (E)" - the ISO/IEC portion of a
|
|
775
|
-
# double-labeled standard. The (E) parenthetical is REQUIRED: without
|
|
776
|
-
# it this spelling is the ISO flavor's own form and must not be
|
|
777
|
-
# stolen. Routes through build_joint_development like every ISO-led
|
|
778
|
-
# joint reference.
|
|
779
|
-
rule(:joint_development_iso_iec_edition) do
|
|
780
|
-
str("ISO/IEC").as(:joint_publishers) >> space >>
|
|
781
|
-
str("").as(:iso_published) >>
|
|
782
|
-
str("P").as(:project_marker).maybe >>
|
|
783
|
-
digits.as(:number) >>
|
|
784
|
-
# The part may be dot- or dash-joined ("8802-9"); a dash-year
|
|
785
|
-
# ("1234-2012") is not a part.
|
|
786
|
-
# A distinct key: the iso-format route's :part_dash prints as a
|
|
787
|
-
# dot in the joint code (the "P24748.2:2018" convention); only
|
|
788
|
-
# the ISO/IEC LABEL keeps its printed dash.
|
|
789
|
-
((dot | (dash >> str("").as(:iec_label_dash) >> year_digits.absent?)) >>
|
|
790
|
-
digits.as(:part)).maybe >>
|
|
791
|
-
(str(":") >> space.maybe >> year_digits.as(:year)) >>
|
|
792
|
-
space.maybe >> parenthetical
|
|
793
|
-
end
|
|
794
|
-
|
|
795
|
-
rule(:joint_development_embedded_stage) do
|
|
796
|
-
# publisher set mirrors joint_development_iso_format (incl. bare IEEE);
|
|
797
|
-
# longest token first.
|
|
798
|
-
(str("ISO/IEC/IEEE") | str("IEEE/ISO/IEC") | str("IEEE/IEC/ISO") |
|
|
799
|
-
str("ISO/IEEE") | str("IEC/IEEE") | str("IEEE/IEC") | str("ISO/IEC") |
|
|
800
|
-
str("IEEE")).as(:joint_publishers) >>
|
|
801
|
-
space >>
|
|
802
|
-
str("P").as(:project_marker).maybe >> # project marker (P =
|
|
803
|
-
# project/draft; its
|
|
804
|
-
# presence is identity)
|
|
805
|
-
digits.as(:number) >>
|
|
806
|
-
# optional numeric part (dot or dash); must not swallow a year
|
|
807
|
-
((dot | dash) >> year_digits.absent? >> digits.as(:part)).maybe >>
|
|
808
|
-
# the embedded stage, dot-separated, closed vocab (same as iso_stage).
|
|
809
|
-
# The (digit|letter) look-ahead keeps it at a token boundary so "CD"
|
|
810
|
-
# can't match inside a longer token and a glued no-space date
|
|
811
|
-
# (".DISMay2013") is left to fall through.
|
|
812
|
-
dot >>
|
|
813
|
-
((str("FDIS") >> digit.maybe) | (str("FCD") >> digit.maybe) |
|
|
814
|
-
(str("CDV") >> digit.maybe) |
|
|
815
|
-
(str("DIS") >> digit.maybe) |
|
|
816
|
-
(str("CD") >> digit.maybe) |
|
|
817
|
-
(str("WD") >> digit.maybe) | (str("PWI") >> digit.maybe) |
|
|
818
|
-
(str("NP") >> digit.maybe)).as(:iso_stage) >>
|
|
819
|
-
(digit | match("[A-Za-z]")).absent? >>
|
|
820
|
-
# optional trailing date: :YYYY, -YYYY[-MM], or text "Month YYYY"
|
|
821
|
-
(
|
|
822
|
-
(str(":") >> year_digits.as(:year)) |
|
|
823
|
-
(dash >> year_digits.as(:year) >>
|
|
824
|
-
(dash >> month_numeric.as(:month)).maybe) |
|
|
825
|
-
((comma | space) >> month_name.as(:month) >> space >> year_digits.as(:year))
|
|
826
|
-
).maybe
|
|
827
|
-
end
|
|
828
|
-
|
|
829
|
-
# Number-first pattern: "1873-2015 IEEE Standard..."
|
|
830
|
-
rule(:number_first_identifier) do
|
|
831
|
-
number >>
|
|
832
|
-
(dash >> year_digits.as(:year)).maybe >>
|
|
833
|
-
space >>
|
|
834
|
-
(publisher >> copublisher.repeat.as(:copublishers)).as(:publishers) >>
|
|
835
|
-
space >>
|
|
836
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
837
|
-
match("[^\n]").repeat(0).as(:title)
|
|
838
|
-
end
|
|
839
|
-
|
|
840
|
-
# IEEE P pattern (without Std): "IEEE P1003.1..." OR just "P1003.1..." (prefix optional)
|
|
841
|
-
# `P` is not consumed here: the `number` rule carries its own optional
|
|
842
|
-
# leading P and captures it into :number ("P1003.1"), so Code.parse
|
|
843
|
-
# peels it as code.prefix and the project marker survives the parse —
|
|
844
|
-
# a bare `str("P")` swallowed it and "P1201/D0.3" came back without
|
|
845
|
-
# its P at all (pubid#18's data-loss complaint).
|
|
846
|
-
rule(:ieee_p_identifier) do
|
|
847
|
-
(str("IEEE").as(:publisher) >> space).maybe >> # Make IEEE prefix optional
|
|
848
|
-
number >>
|
|
849
|
-
(part_subpart_year | edition).maybe >>
|
|
850
|
-
# Pattern for /08 style drafts (digits without D prefix) - MUST come before corrigendum
|
|
851
|
-
(slash >> digits.as(:draft_version)).as(:digit_draft).maybe >>
|
|
852
|
-
# FDIS and other ISO stage codes without D prefix (Pattern 3)
|
|
853
|
-
fdraft.maybe >>
|
|
854
|
-
# Trailing "Month YYYY" print/reaffirm date. Captured under distinct
|
|
855
|
-
# keys so it never collides with the base -YYYY identity year (a
|
|
856
|
-
# collision made Parslet drop the base year and warn "Duplicate
|
|
857
|
-
# subtrees … keys: [:year]"). The builder promotes it to the identity
|
|
858
|
-
# only when there is no base year.
|
|
859
|
-
trailing_month_year.maybe >>
|
|
860
|
-
corrigendum.maybe >>
|
|
861
|
-
draft.maybe >>
|
|
862
|
-
# Revision trails the draft (before any date), matching normalization's
|
|
863
|
-
# ".../D<n>/R-<x>" repositioning of "P802.16Rev2/D3 Feb 2008".
|
|
864
|
-
revision_suffix.maybe >>
|
|
865
|
-
# ALSO accept month/year after draft (some patterns like /DX, Month YEAR)
|
|
866
|
-
trailing_month_year.maybe >>
|
|
867
|
-
# Trailing corrigendum AFTER the draft+date ("…/D1, Jan 2007/Cor. 1").
|
|
868
|
-
# The draft's own draft_date has already consumed the date, leaving
|
|
869
|
-
# "/Cor. 1" here; the resulting flat corrigendum+draft tree routes to
|
|
870
|
-
# build_flat_corrigendum (disjoint from the pre-draft corrigendum slot,
|
|
871
|
-
# which only fires when no draft precedes it).
|
|
872
|
-
corrigendum.maybe >>
|
|
873
|
-
parenthetical.maybe
|
|
874
|
-
end
|
|
875
|
-
|
|
876
|
-
# ANSI P pattern: "ANSI PN42.34-D9a, 2015" OR "ANSI P1234/D5"
|
|
877
|
-
rule(:ansi_p_identifier) do
|
|
878
|
-
str("ANSI").as(:publisher) >> space >>
|
|
879
|
-
str("P") >> space.maybe >> # Make space after P optional
|
|
880
|
-
number >>
|
|
881
|
-
(part_subpart_year | edition).maybe >>
|
|
882
|
-
# Trailing "Month YYYY"/bare-year date under distinct keys so they
|
|
883
|
-
# never collide with the base -YYYY identity year (see ieee_p_identifier).
|
|
884
|
-
trailing_month_year.maybe >>
|
|
885
|
-
corrigendum.maybe >>
|
|
886
|
-
draft.maybe >>
|
|
887
|
-
revision_suffix.maybe >>
|
|
888
|
-
# ALSO accept month/year after draft
|
|
889
|
-
trailing_month_year.maybe >>
|
|
890
|
-
# Accept bare year after draft: ", 2015"
|
|
891
|
-
((comma | space) >> year_digits.as(:trailing_year)).maybe >>
|
|
892
|
-
# Trailing corrigendum after the draft+date (parity with ieee_p_identifier).
|
|
893
|
-
corrigendum.maybe >>
|
|
894
|
-
parenthetical.maybe
|
|
895
|
-
end
|
|
896
|
-
|
|
897
|
-
# IEEE Draft P pattern: "IEEE Draft P802.11..." OR "Draft P802.11..." (IEEE prefix optional)
|
|
898
|
-
# An optional status phrase may precede "Draft" — "IEEE Unapproved Draft P…",
|
|
899
|
-
# "IEEE Active Approved Draft P…" — the largest index-v2 draft bucket. The
|
|
900
|
-
# status is captured (draft_status ends in a space, so "Approved Draft"
|
|
901
|
-
# splits cleanly) and round-trips as the draft_status attribute; the literal
|
|
902
|
-
# "Draft" stays a bare marker (dropped on render, like the plain form).
|
|
903
|
-
# `P` is not consumed here: the `number` rule carries its own optional
|
|
904
|
-
# leading P and captures it into :number ("P802.11"), so Code.parse peels
|
|
905
|
-
# it as code.prefix and the project marker round-trips (pubid#318) — a
|
|
906
|
-
# bare `str("P").maybe` here swallowed it and the render lost the P.
|
|
907
|
-
rule(:ieee_draft_p_identifier) do
|
|
908
|
-
(str("IEEE").as(:publisher) >> space).maybe >> # Make IEEE prefix optional
|
|
909
|
-
draft_status.as(:draft_status).maybe >>
|
|
910
|
-
str("Draft") >> space >>
|
|
911
|
-
# A status-word draft may carry a bare number
|
|
912
|
-
# ("IEEE Unapproved Draft 802.1ah/D4.2"). The `number` rule
|
|
913
|
-
# already accepts the bare forms (802.1ah, C57.15, 11073-10471).
|
|
914
|
-
number >>
|
|
915
|
-
(part_subpart_year | edition).maybe >>
|
|
916
|
-
# Trailing "Month YYYY" date under distinct keys so it never collides
|
|
917
|
-
# with the base -YYYY identity year (see ieee_p_identifier).
|
|
918
|
-
((space >> month_name.as(:trailing_month) >> space >> year_digits.as(:trailing_year)) |
|
|
919
|
-
(space >> month_numeric.as(:trailing_month) >> (space | dash) >> year_digits.as(:trailing_year))).maybe >>
|
|
920
|
-
draft.maybe >>
|
|
921
|
-
# A print date may trail a draft that carries its own date
|
|
922
|
-
# ("IEEE Unapproved Draft 24765/D1 2009, Oct 2009" - the draft's
|
|
923
|
-
# year is "2009", the print date is ", Oct 2009").
|
|
924
|
-
(comma >> space? >> month_name.as(:trailing_month) >> space >>
|
|
925
|
-
year_digits.as(:trailing_year)).maybe >>
|
|
926
|
-
revision_suffix.maybe >>
|
|
927
|
-
# …and the print date may also trail the repositioned revision
|
|
928
|
-
# ("IEEE Unapproved Draft P802.16Rev2/D9a, March 2009" reaches the
|
|
929
|
-
# grammar with its inline revision parsed natively).
|
|
930
|
-
(comma >> space? >> month_name.as(:trailing_month) >> space >>
|
|
931
|
-
year_digits.as(:trailing_year)).maybe >>
|
|
932
|
-
# Trailing corrigendum after the draft ("…/D2.0/Cor. 1", or
|
|
933
|
-
# "…/D1.0, Dec 2007/Cor. 1" where the draft's own draft_date consumes
|
|
934
|
-
# the date, leaving "/Cor. N"). The flat corrigendum+draft tree (no
|
|
935
|
-
# :base) routes to build_flat_corrigendum, which rebuilds the base
|
|
936
|
-
# standard (carrying the draft + draft_status) and wraps it.
|
|
937
|
-
corrigendum.maybe >>
|
|
938
|
-
parenthetical.maybe
|
|
939
|
-
end
|
|
940
|
-
|
|
941
|
-
# IEEE Approved Draft pattern: "IEEE Approved Draft Std P..."
|
|
942
|
-
rule(:ieee_approved_draft_identifier) do
|
|
943
|
-
str("IEEE").as(:publisher) >>
|
|
944
|
-
space >>
|
|
945
|
-
str("Approved") >> space >>
|
|
946
|
-
(str("Draft Std") | str("Std")).as(:type) >> space >>
|
|
947
|
-
str("P").maybe >>
|
|
948
|
-
number >>
|
|
949
|
-
(part_subpart_year | edition).maybe >>
|
|
950
|
-
draft.maybe >>
|
|
951
|
-
revision_suffix.maybe >>
|
|
952
|
-
parenthetical.maybe
|
|
953
|
-
end
|
|
954
|
-
|
|
955
|
-
# Combined AIEE identifier pattern: "AIEE No 72-1932 and AIEE No 73-1932"
|
|
956
|
-
# Handles "and"-separated AIEE identifiers (from "Nos X and Y" preprocessing)
|
|
957
|
-
rule(:combined_aiee_identifier) do
|
|
958
|
-
# First AIEE identifier
|
|
959
|
-
Aiee::Parser.new.aiee_identifier.as(:first_aiee) >>
|
|
960
|
-
# "and" separator
|
|
961
|
-
space >> str("and") >> space >>
|
|
962
|
-
# Second AIEE identifier
|
|
963
|
-
Aiee::Parser.new.aiee_identifier.as(:second_aiee)
|
|
964
|
-
end
|
|
965
|
-
|
|
966
|
-
# AIEE (American Institute of Electrical Engineers) patterns
|
|
967
|
-
# Detect AIEE patterns and delegate to AIEE parser
|
|
968
|
-
rule(:aiee_identifier) do
|
|
969
|
-
# Lookahead for AIEE patterns - do not consume input
|
|
970
|
-
(
|
|
971
|
-
# IEEE-AIEE transitional pattern
|
|
972
|
-
(str("IEEE-AIEE") >> space >> (str("No.") | str("Nos") | str("No") | str("Standard") | str("Trans."))) |
|
|
973
|
-
# A.I.E.E. pattern (with dots, no spaces)
|
|
974
|
-
(str("A.I.E.E.") >> space >> (str("No.") | str("Nos") | str("No"))) |
|
|
975
|
-
# A. I. E. E. pattern (with dots and spaces)
|
|
976
|
-
(str("A. I. E. E.") >> space >> (str("No.") | str("Nos") | str("No") | str("Standard"))) |
|
|
977
|
-
# AIEE pattern - extended to include more type words
|
|
978
|
-
(str("AIEE") >> space >> (str("No.") | str("Nos") | str("No") | str("Standard") | str("Trans.") | str("Std")))
|
|
979
|
-
).present? >>
|
|
980
|
-
# Delegate to AIEE parser if pattern detected
|
|
981
|
-
Aiee::Parser.new.aiee_identifier.as(:aiee)
|
|
982
|
-
end
|
|
983
|
-
|
|
984
|
-
# IRE (Institute of Radio Engineers) patterns
|
|
985
|
-
# Detect IRE patterns and delegate to IRE parser
|
|
986
|
-
rule(:ire_identifier) do
|
|
987
|
-
# Lookahead for IRE patterns - do not consume input
|
|
988
|
-
(
|
|
989
|
-
# Year-first pattern: "52 IRE 7.S2" or "60 IRE 28 PS7"
|
|
990
|
-
((match("[1-6]") >> digit >> space >> str("IRE")) | # 2-digit year format
|
|
991
|
-
(str("19") >> digit.repeat(2, 2) >> space >> str("IRE"))) |
|
|
992
|
-
# Prefix-first pattern: "IRE 7.S2-1952" (pubid#316 family 2) —
|
|
993
|
-
# IRE then a designation (digits or a type word). Loose on
|
|
994
|
-
# purpose: the sub-parser is strict, and a failed delegation just
|
|
995
|
-
# falls through to the remaining alternatives.
|
|
996
|
-
(str("IRE") >> space >> (digits | str("Standard") | str("Std") | str("Trans"))) |
|
|
997
|
-
# IEEE-IRE transitional pattern
|
|
998
|
-
(str("IEEE-IRE") >> space)
|
|
999
|
-
).present? >>
|
|
1000
|
-
# Delegate to IRE parser if pattern detected
|
|
1001
|
-
Ire::Parser.new.ire_identifier.as(:ire)
|
|
1002
|
-
end
|
|
1003
|
-
|
|
1004
|
-
# NESC (National Electrical Safety Code) patterns
|
|
1005
|
-
# Detect NESC patterns and delegate to NESC parser
|
|
1006
|
-
rule(:nesc_identifier) do
|
|
1007
|
-
# Lookahead for NESC patterns - do not consume input
|
|
1008
|
-
(
|
|
1009
|
-
# C2-YYYY pattern
|
|
1010
|
-
(str("C2-") >> year_digits) |
|
|
1011
|
-
# YYYY NESC pattern
|
|
1012
|
-
(year_digits >> space >> (str("NESC") | str("National Electrical Safety Code"))) |
|
|
1013
|
-
# Draft NESC pattern
|
|
1014
|
-
(str("Draft") >> space >> (str("NESC") | str("National Electrical Safety Code"))) |
|
|
1015
|
-
# Name-first pattern (NEW)
|
|
1016
|
-
(str("National Electrical Safety Code") >> str(",") >> space >> str("C2-")) |
|
|
1017
|
-
# Catalogue form: "IEEE Std YYYY NESC ..." / "IEEE Std YYYY National
|
|
1018
|
-
# Electrical Safety Code" - the prefix is consumed here (the NESC
|
|
1019
|
-
# renderer prepends "IEEE Std" itself) but must not fall through to
|
|
1020
|
-
# the generic standard grammar, which would read YYYY as a number.
|
|
1021
|
-
(str("IEEE") >> space >> str("Std") >> space >> year_digits >> space >>
|
|
1022
|
-
(str("NESC") | str("National Electrical Safety Code")))
|
|
1023
|
-
).present? >>
|
|
1024
|
-
# Delegate to NESC parser if pattern detected
|
|
1025
|
-
((str("IEEE") >> space >> str("Std") >> space).maybe >>
|
|
1026
|
-
Nesc::Parser.new.nesc_identifier).as(:nesc)
|
|
1027
|
-
end
|
|
1028
|
-
|
|
1029
|
-
# Draft notation for PSI (e.g., /D2, /D3, rawbib's /D-2)
|
|
1030
|
-
rule(:psi_draft) do
|
|
1031
|
-
slash >> str("D") >> dash.maybe >> digits.as(:draft_version)
|
|
1032
|
-
end
|
|
1033
|
-
|
|
1034
|
-
# Date on an SI/PSI identifier: ", Month Year" or "-YEAR[-MM]". The
|
|
1035
|
-
# comma branch also accepts a NUMERIC month and a DASH before the
|
|
1036
|
-
# year — the renderer emits ", 05 2010" for a numeric-month draft,
|
|
1037
|
-
# and the preprocessing gsub rewrites a trailing " <digits> <year>"
|
|
1038
|
-
# to "<digits>-<year>" (the same load-bearing coupling draft_date
|
|
1039
|
-
# documents), so the re-parse must read its own rendering back.
|
|
1040
|
-
rule(:psi_date) do
|
|
1041
|
-
(comma >> (month_name | month_numeric).as(:month) >> (space | dash) >>
|
|
1042
|
-
year_digits.as(:year)) |
|
|
1043
|
-
(dash >> year_digits.as(:year) >>
|
|
1044
|
-
(dash >> digit.repeat(2, 2).as(:month)).maybe)
|
|
1045
|
-
end
|
|
1046
|
-
|
|
1047
|
-
# IEEE/ASTM SI/PSI (Système International) patterns
|
|
1048
|
-
# SI = Published metric system standard
|
|
1049
|
-
# PSI = Proposed SI (draft)
|
|
1050
|
-
# Rawbib spellings (pubid#316 family 3): a bare "IEEE" publisher, a dot
|
|
1051
|
-
# separator after the type ("PSI.10", "SI 10.1997"), relaton's
|
|
1052
|
-
# hyphenated "/D-<n>" draft, and a dash year-month ("-2010-05").
|
|
1053
|
-
rule(:ieee_astm_si_psi) do
|
|
1054
|
-
(str("IEEE/ASTM") | str("IEEE")).as(:publishers) >>
|
|
1055
|
-
space >>
|
|
1056
|
-
(str("PSI") | str("SI")).as(:si_type) >>
|
|
1057
|
-
(space | str(".")) >>
|
|
1058
|
-
digits.as(:number) >>
|
|
1059
|
-
# Glued ".YEAR" edition date ("IEEE/ASTM SI 10.1997")
|
|
1060
|
-
(str(".") >> year_digits.as(:year)).maybe >>
|
|
1061
|
-
# The date and the draft appear in EITHER order: the legacy
|
|
1062
|
-
# spelling puts the draft first ("PSI 10/D2, October 2015"),
|
|
1063
|
-
# the rawbib hyphenated form ("PSI 10/D-3-2010") parses in place
|
|
1064
|
-
# with its date on the draft clause. Draft-first is tried first so the legacy
|
|
1065
|
-
# comma-date keeps its original match; each side is optional so
|
|
1066
|
-
# a date-only or draft-less form still parses.
|
|
1067
|
-
(
|
|
1068
|
-
(psi_draft >> psi_date.maybe) | (psi_date >> psi_draft.maybe)
|
|
1069
|
-
).maybe >>
|
|
1070
|
-
# Optional parenthetical (revision relationships)
|
|
1071
|
-
parenthetical.maybe
|
|
1072
|
-
end
|
|
1073
|
-
|
|
1074
|
-
# No-prefix IEEE identifier (characteristic patterns without "IEEE Std")
|
|
1075
|
-
# These are patterns that are distinctly IEEE even without explicit publisher
|
|
1076
|
-
rule(:no_prefix_ieee) do
|
|
1077
|
-
characteristic_ieee_number.as(:number) >>
|
|
1078
|
-
# Optional suffix (like -a, -b)
|
|
1079
|
-
(dash >> match("[A-Za-z]")).maybe.as(:suffix) >>
|
|
1080
|
-
# Optional year
|
|
1081
|
-
(dash >> year_digits).maybe.as(:year) >>
|
|
1082
|
-
# Optional draft notation
|
|
1083
|
-
draft.maybe >>
|
|
1084
|
-
# Optional language portion
|
|
1085
|
-
(str("(E)") | str("(F)")).maybe >>
|
|
1086
|
-
# Optional parenthetical content
|
|
1087
|
-
parenthetical.maybe
|
|
1088
|
-
end
|
|
1089
|
-
|
|
1090
|
-
# Corrigendum identifier with recursive base parsing
|
|
1091
|
-
# Captures base identifier for recursive parsing, then corrigendum supplement
|
|
1092
|
-
# Example: IEEE Std 535-2013/Cor. 1-2017
|
|
1093
|
-
rule(:corrigendum_identifier) do
|
|
1094
|
-
# Match a complete base identifier (reuse existing patterns)
|
|
1095
|
-
# Try standard patterns that would match "IEEE Std 535-2013"
|
|
1096
|
-
(
|
|
1097
|
-
((publisher >> copublisher.repeat.as(:copublishers)).as(:publishers) >> space).maybe >>
|
|
1098
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
1099
|
-
number >>
|
|
1100
|
-
part_subpart_year.maybe # This captures the full identifier before /Cor
|
|
1101
|
-
).as(:base) >>
|
|
1102
|
-
# Now match the corrigendum portion
|
|
1103
|
-
(slash | dash | space) >>
|
|
1104
|
-
str("Cor") >>
|
|
1105
|
-
(dash | dot | space).maybe >> # More flexible separator after "Cor"
|
|
1106
|
-
space? >>
|
|
1107
|
-
digits.as(:cor_number) >>
|
|
1108
|
-
((dash | str(":") | space) >> year_digits.as(:cor_year)).maybe >> # Optional cor year suffix
|
|
1109
|
-
parenthetical.maybe
|
|
1110
|
-
end
|
|
1111
|
-
|
|
1112
|
-
# Interpretation identifier with recursive base parsing
|
|
1113
|
-
# Captures base identifier for recursive parsing, then interpretation supplement
|
|
1114
|
-
# Example: IEEE Std 1076/INT-1991, IEEE Std 1003.1-1988/INT
|
|
1115
|
-
rule(:interpretation_identifier) do
|
|
1116
|
-
# Match a complete base identifier
|
|
1117
|
-
(
|
|
1118
|
-
((publisher >> copublisher.repeat.as(:copublishers)).as(:publishers) >> space).maybe >>
|
|
1119
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
1120
|
-
number >>
|
|
1121
|
-
part_subpart_year.maybe
|
|
1122
|
-
).as(:base) >>
|
|
1123
|
-
# Now match the interpretation portion
|
|
1124
|
-
(slash | dash | space) >>
|
|
1125
|
-
str("INT") >>
|
|
1126
|
-
((dash | str(":") | space) >> year_digits.as(:int_year)).maybe >> # Optional year suffix
|
|
1127
|
-
parenthetical.maybe
|
|
1128
|
-
end
|
|
1129
|
-
|
|
1130
|
-
# Conformance identifier with recursive base parsing
|
|
1131
|
-
# Captures base identifier for recursive parsing, then conformance supplement
|
|
1132
|
-
# Example: IEEE Std 802.16/Conformance01-2003
|
|
1133
|
-
rule(:conformance_identifier) do
|
|
1134
|
-
# Match a complete base identifier
|
|
1135
|
-
(
|
|
1136
|
-
((publisher >> copublisher.repeat.as(:copublishers)).as(:publishers) >> space).maybe >>
|
|
1137
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
1138
|
-
number >>
|
|
1139
|
-
part_subpart_year.maybe
|
|
1140
|
-
).as(:base) >>
|
|
1141
|
-
# Now match the conformance portion
|
|
1142
|
-
(slash | dash | space) >>
|
|
1143
|
-
str("Conformance") >>
|
|
1144
|
-
match("[0-9]").repeat(1).as(:conf_number) >>
|
|
1145
|
-
dash >>
|
|
1146
|
-
year_digits.as(:conf_year) >>
|
|
1147
|
-
parenthetical.maybe
|
|
1148
|
-
end
|
|
1149
|
-
|
|
1150
|
-
# Multi-numbered identifier: same document with multiple numbers
|
|
1151
|
-
# Examples: IEEE Std 1299/C62.22.1-1996, IEEE Std 960-1989, Std 1177-1989
|
|
1152
|
-
rule(:multi_numbered_identifier) do
|
|
1153
|
-
# Primary identifier (full IEEE identifier)
|
|
1154
|
-
((
|
|
1155
|
-
(publisher >> space).maybe >>
|
|
1156
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
1157
|
-
number >>
|
|
1158
|
-
(part_subpart_year | edition).maybe
|
|
1159
|
-
).as(:primary_identifier) >>
|
|
1160
|
-
# Separator: slash for cross-ref format, comma for joint standard
|
|
1161
|
-
(slash >> str("C") >> digits >> dot >> digits >> dot >> digits >> dash >> year_digits).as(:secondary_crossref)) |
|
|
1162
|
-
(comma >> space >> (type_word.as(:type) >> space?).maybe >> number >> dash >> year_digits).as(:secondary_joint)
|
|
1163
|
-
end
|
|
1164
|
-
|
|
1165
|
-
# CSA dual published pattern: IEEE Std 844.1-2017/CSA C22.2 No. 293.1-17
|
|
1166
|
-
rule(:csa_dual_published) do
|
|
1167
|
-
# IEEE portion (full identifier)
|
|
1168
|
-
(
|
|
1169
|
-
publisher >> space >>
|
|
1170
|
-
(type_word.as(:type) >> space?).maybe >>
|
|
1171
|
-
number >>
|
|
1172
|
-
(part_subpart_year | edition).maybe
|
|
1173
|
-
).as(:ieee_portion) >>
|
|
1174
|
-
# CSA portion with slash separator
|
|
1175
|
-
slash >>
|
|
1176
|
-
str("CSA") >> space >>
|
|
1177
|
-
# CSA number formats (various patterns observed)
|
|
1178
|
-
(
|
|
1179
|
-
# Format 1: C22.2 No. 293.1-17 (with NO., either case)
|
|
1180
|
-
(str("C") >> digit.repeat(2) >> dot >> digit >> space >> (str("No") | str("NO")) >> dot >> space >>
|
|
1181
|
-
match("[0-9.]").repeat(1) >> (dash | str(":")) >> digit.repeat(2)) |
|
|
1182
|
-
# Format 2: C293.2-17 (without NO., dash year)
|
|
1183
|
-
(str("C") >> match("[0-9.]").repeat(1) >> dash >> digit.repeat(2)) |
|
|
1184
|
-
# Format 3: C22.2 No. 293.3:19 (with NO., either case, colon year)
|
|
1185
|
-
(str("C") >> digit.repeat(2) >> dot >> digit >> space >> (str("No") | str("NO")) >> dot >> space >>
|
|
1186
|
-
match("[0-9.]").repeat(1) >> str(":") >> digit.repeat(2)) |
|
|
1187
|
-
# Format 4: C293.4:19 (without NO., colon year)
|
|
1188
|
-
(str("C") >> match("[0-9.]").repeat(1) >> str(":") >> digit.repeat(2))
|
|
1189
|
-
).as(:csa_portion)
|
|
1190
|
-
end
|
|
1191
|
-
|
|
1192
|
-
# Basic IEEE identifier (no dual PubIDs or complex revisions yet)
|
|
1193
|
-
rule(:identifier) do
|
|
1194
|
-
combined_aiee_identifier |
|
|
1195
|
-
aiee_identifier |
|
|
1196
|
-
combined_aiee_identifier |
|
|
1197
|
-
ire_identifier |
|
|
1198
|
-
nesc_identifier |
|
|
1199
|
-
ieee_astm_si_psi | # NEW Session 171: Add IEEE/ASTM SI/PSI support
|
|
1200
|
-
multi_numbered_identifier | # NEW: Try multi-numbered identifiers before generic patterns
|
|
1201
|
-
csa_dual_published | # NEW: Try CSA dual published before generic patterns
|
|
1202
|
-
s_designation | # Historical IEEE/IPCEA cable designation (S-135)
|
|
1203
|
-
corrigendum_identifier | # NEW: Try corrigendum before generic patterns
|
|
1204
|
-
interpretation_identifier | # NEW: Try interpretation identifier before generic patterns
|
|
1205
|
-
conformance_identifier | # NEW: Try conformance identifier before generic patterns
|
|
1206
|
-
joint_development_ieee_format |
|
|
1207
|
-
joint_development_iso_format |
|
|
1208
|
-
joint_development_iso_iec_edition | # stage-less ISO/IEC label with (E) - double-label portion
|
|
1209
|
-
|
|
1210
|
-
joint_development_embedded_stage | # stage-LAST embedded form (before generic)
|
|
1211
|
-
iec_ieee_copublished |
|
|
1212
|
-
number_first_identifier |
|
|
1213
|
-
ieee_approved_draft_identifier |
|
|
1214
|
-
ieee_draft_p_identifier |
|
|
1215
|
-
ieee_p_identifier |
|
|
1216
|
-
ansi_p_identifier | # NEW: ANSI P prefix support
|
|
1217
|
-
(((publisher >> copublisher.repeat.as(:copublishers)).as(:publishers) >> space).maybe >> # Make publisher optional
|
|
1218
|
-
draft_status.as(:draft_status).maybe >>
|
|
1219
|
-
(str("Draft Std").as(:type) >> space?).maybe >>
|
|
1220
|
-
(type_word.as(:type) >> (space >> str("No") >> space).maybe >> space?).maybe >>
|
|
1221
|
-
number >>
|
|
1222
|
-
(part_subpart_year | edition).maybe >>
|
|
1223
|
-
corrigendum.maybe >>
|
|
1224
|
-
amendment.maybe >>
|
|
1225
|
-
interpretation.maybe >> # NEW: Add /INT support
|
|
1226
|
-
conformance.maybe >> # NEW: Add /Conformance support
|
|
1227
|
-
ashrae_copub.maybe >> # NEW: Add /ASHRAE Guideline support
|
|
1228
|
-
ieee_crossref.maybe >> # NEW: Add /C62.22.1-1996 cross-reference support
|
|
1229
|
-
draft.maybe >>
|
|
1230
|
-
revision_suffix.maybe >>
|
|
1231
|
-
# Trailing "Month YYYY" print/reaffirm date under distinct keys so it
|
|
1232
|
-
# never collides with the base -YYYY identity year (see
|
|
1233
|
-
# ieee_p_identifier). The builder promotes it only when no base year.
|
|
1234
|
-
trailing_month_year.maybe >>
|
|
1235
|
-
# The ASHRAE joint suffix may also trail a draft+date
|
|
1236
|
-
# ("IEEE P1635/D13, December, 2017/ASHRAE Guideline 21"), so a
|
|
1237
|
-
# second slot catches it after the date.
|
|
1238
|
-
ashrae_copub.maybe >>
|
|
1239
|
-
# A bracketed narrative may sit between the base and a trailing
|
|
1240
|
-
# corrigendum: "IEEE Std 671-1985 [Corrigendum to IEEE Std 671-1985
|
|
1241
|
-
# (Reaff 2008)]/Cor. 1-2010" captures the bracket as the base's
|
|
1242
|
-
# nickname before the wrapper is parsed.
|
|
1243
|
-
book_nickname.maybe >>
|
|
1244
|
-
# Trailing corrigendum after the draft+date ("IEEE Approved P1015/D1,
|
|
1245
|
-
# Jan 2007/Cor. 1"): the generic bucket is the only path a status-word
|
|
1246
|
-
# form reaches. Routes via build_flat_corrigendum (disjoint from the
|
|
1247
|
-
# pre-draft corrigendum slot at line 954).
|
|
1248
|
-
corrigendum.maybe >>
|
|
1249
|
-
edition.maybe >>
|
|
1250
|
-
parenthetical.maybe >> # REVERT: Back to single parenthetical
|
|
1251
|
-
book_nickname.maybe >> # NEW: Add book nickname support
|
|
1252
|
-
redline.maybe >>
|
|
1253
|
-
title_portion.maybe >>
|
|
1254
|
-
approved_draft_suffix.maybe) |
|
|
1255
|
-
no_prefix_ieee # NEW: Try no-prefix patterns last (lowest priority)
|
|
1256
|
-
end
|
|
1257
|
-
|
|
1258
|
-
root(:identifier)
|
|
8
|
+
class Parser
|
|
1259
9
|
def self.normalize_input(string)
|
|
1260
10
|
# Strip .pdf extension if present (Pattern 3: File Extensions)
|
|
1261
11
|
cleaned = string.sub(/\.pdf$/i, "")
|
|
@@ -1269,7 +19,6 @@ module Pubid
|
|
|
1269
19
|
# No valid IEEE identifier pattern needs more than 1 space
|
|
1270
20
|
cleaned = cleaned.gsub(/\s+/, " ")
|
|
1271
21
|
|
|
1272
|
-
|
|
1273
22
|
# NEW Session 171: Remove wrong ! prefix
|
|
1274
23
|
cleaned = cleaned.gsub(/^!IEEE /, "IEEE ")
|
|
1275
24
|
|
|
@@ -1647,7 +396,6 @@ module Pubid
|
|
|
1647
396
|
# Remove period after "Std": "IEEE Std." -> "IEEE Std"
|
|
1648
397
|
cleaned = cleaned.gsub(/\bStd\.\s+/, "Std ")
|
|
1649
398
|
|
|
1650
|
-
|
|
1651
399
|
# Title portion removal after year: "YYYY - IEEE Standard for..."
|
|
1652
400
|
cleaned = cleaned.gsub(
|
|
1653
401
|
/(\d{4})(\s+\([^)]+\))?\s+-\s+IEEE\s+Standard\s+for.*$/, '\1\2'
|
|
@@ -1787,10 +535,6 @@ module Pubid
|
|
|
1787
535
|
|
|
1788
536
|
cleaned
|
|
1789
537
|
end
|
|
1790
|
-
|
|
1791
|
-
def self.parse(string)
|
|
1792
|
-
new.parse(normalize_input(string))
|
|
1793
|
-
end
|
|
1794
538
|
end
|
|
1795
539
|
end
|
|
1796
540
|
end
|