pubid 2.0.4 → 2.0.5

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.
data/data/parg/jis.json CHANGED
@@ -1 +1 @@
1
- {"bindings":null,"version":"0.1.0","grammar":"PubidJis","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Entity":{"atom":155}},{"Str":{"pattern":"WES"}},{"Named":{"name":"wes","atom":1}},{"Entity":{"atom":6}},{"Str":{"pattern":" "}},{"Str":{"pattern":" "}},{"Alternative":{"atoms":[4,5]}},{"Named":{"name":"space","atom":3}},{"Entity":{"atom":12}},{"Entity":{"atom":10}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":9,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"number","atom":11}},{"Entity":{"atom":25}},{"Entity":{"atom":23}},{"Entity":{"atom":19}},{"Str":{"pattern":"-"}},{"Str":{"pattern":"ー"}},{"Alternative":{"atoms":[16,17]}},{"Named":{"name":"dash","atom":18}},{"Entity":{"atom":10}},{"Repetition":{"atom":20,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"part","atom":21}},{"Sequence":{"atoms":[15,22]}},{"Repetition":{"atom":14,"min":0,"max":null,"tag":"Repetition"}},{"Named":{"name":"parts","atom":24}},{"Entity":{"atom":41}},{"Entity":{"atom":30}},{"Str":{"pattern":":"}},{"Str":{"pattern":":"}},{"Alternative":{"atoms":[28,29]}},{"Named":{"name":"colon","atom":27}},{"Entity":{"atom":10}},{"Repetition":{"atom":32,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"year","atom":33}},{"Str":{"pattern":"R"}},{"Str":{"pattern":"R"}},{"Repetition":{"atom":36,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[35,37]}},{"Repetition":{"atom":38,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"reaffirmed","atom":39}},{"Sequence":{"atoms":[31,34,40]}},{"Repetition":{"atom":26,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":54}},{"Str":{"pattern":"("}},{"Str":{"pattern":"("}},{"Alternative":{"atoms":[44,45]}},{"Str":{"pattern":"E"}},{"Str":{"pattern":"J"}},{"Alternative":{"atoms":[47,48]}},{"Named":{"name":"language","atom":49}},{"Str":{"pattern":")"}},{"Str":{"pattern":")"}},{"Alternative":{"atoms":[51,52]}},{"Sequence":{"atoms":[46,50,53]}},{"Repetition":{"atom":43,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":66}},{"Str":{"pattern":"("}},{"Str":{"pattern":"規格群"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[57,58,59]}},{"Str":{"pattern":"("}},{"Str":{"pattern":"規格群"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[61,62,63]}},{"Alternative":{"atoms":[60,64]}},{"Named":{"name":"all_parts","atom":65}},{"Repetition":{"atom":56,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":136}},{"Entity":{"atom":93}},{"Entity":{"atom":71}},{"Str":{"pattern":"/"}},{"Named":{"name":"slash","atom":70}},{"Str":{"pattern":"AMENDMENT"}},{"Str":{"pattern":"AMD"}},{"Alternative":{"atoms":[73,74]}},{"Named":{"name":"amd_type","atom":75}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":77}},{"Entity":{"atom":10}},{"Repetition":{"atom":79,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"amd_number","atom":80}},{"Entity":{"atom":30}},{"Named":{"name":"colon","atom":82}},{"Entity":{"atom":10}},{"Repetition":{"atom":84,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"amd_year","atom":85}},{"Str":{"pattern":"R"}},{"Str":{"pattern":"R"}},{"Repetition":{"atom":88,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[87,89]}},{"Repetition":{"atom":90,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"amd_reaffirmed","atom":91}},{"Sequence":{"atoms":[72,76,78,81,83,86,92]}},{"Named":{"name":"amendment","atom":69}},{"Entity":{"atom":109}},{"Entity":{"atom":71}},{"Named":{"name":"slash","atom":96}},{"Str":{"pattern":"EXPLANATION"}},{"Str":{"pattern":"EXPL"}},{"Alternative":{"atoms":[98,99]}},{"Named":{"name":"expl_type","atom":100}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":102}},{"Entity":{"atom":10}},{"Repetition":{"atom":104,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"expl_number","atom":105}},{"Sequence":{"atoms":[103,106]}},{"Repetition":{"atom":107,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[97,101,108]}},{"Named":{"name":"explanation","atom":95}},{"Entity":{"atom":134}},{"Entity":{"atom":71}},{"Named":{"name":"slash","atom":112}},{"Str":{"pattern":"CORRIGENDUM"}},{"Str":{"pattern":"CORR"}},{"Alternative":{"atoms":[114,115]}},{"Named":{"name":"corr_type","atom":116}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":118}},{"Entity":{"atom":10}},{"Repetition":{"atom":120,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"corr_number","atom":121}},{"Entity":{"atom":30}},{"Named":{"name":"colon","atom":123}},{"Entity":{"atom":10}},{"Repetition":{"atom":125,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"corr_year","atom":126}},{"Str":{"pattern":"R"}},{"Str":{"pattern":"R"}},{"Repetition":{"atom":129,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[128,130]}},{"Repetition":{"atom":131,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"corr_reaffirmed","atom":132}},{"Sequence":{"atoms":[113,117,119,122,124,127,133]}},{"Named":{"name":"corrigendum","atom":111}},{"Alternative":{"atoms":[94,110,135]}},{"Repetition":{"atom":68,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":153}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":139}},{"Str":{"pattern":"SYMBOL"}},{"Named":{"name":"symbol_present","atom":141}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":143}},{"Entity":{"atom":148}},{"Re":{"pattern":"[\\x01-\\x09]"}},{"Re":{"pattern":"[\\x0b-\\u{10ffff}]"}},{"Alternative":{"atoms":[146,147]}},{"Repetition":{"atom":145,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"symbol_value","atom":149}},{"Sequence":{"atoms":[144,150]}},{"Repetition":{"atom":151,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[140,142,152]}},{"Repetition":{"atom":138,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[2,7,8,13,42,55,67,137,154]}},{"Entity":{"atom":199}},{"Str":{"pattern":"JIS"}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":158}},{"Entity":{"atom":71}},{"Named":{"name":"slash","atom":160}},{"Alternative":{"atoms":[159,161]}},{"Repetition":{"atom":162,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[157,163]}},{"Repetition":{"atom":164,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":176}},{"Str":{"pattern":"TR"}},{"Str":{"pattern":"TS"}},{"Alternative":{"atoms":[167,168]}},{"Named":{"name":"type","atom":169}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":171}},{"Entity":{"atom":71}},{"Named":{"name":"slash","atom":173}},{"Alternative":{"atoms":[172,174]}},{"Sequence":{"atoms":[170,175]}},{"Repetition":{"atom":166,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":178}},{"Repetition":{"atom":179,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":183}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Named":{"name":"series","atom":182}},{"Entity":{"atom":6}},{"Named":{"name":"space","atom":184}},{"Repetition":{"atom":185,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":12}},{"Entity":{"atom":25}},{"Entity":{"atom":41}},{"Repetition":{"atom":189,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":54}},{"Repetition":{"atom":191,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":66}},{"Repetition":{"atom":193,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":136}},{"Repetition":{"atom":195,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":153}},{"Repetition":{"atom":197,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[165,177,180,181,186,187,188,190,192,194,196,198]}},{"Alternative":{"atoms":[0,156]}}],"root":200},"bindings":[{"capture":"wes","path":"wes","type":"string","card":null,"preprocess":null},{"capture":"type","path":"type","type":"string","card":null,"preprocess":null},{"capture":"series","path":"series","type":"string","card":null,"preprocess":null},{"capture":"number","path":"number","type":"string","card":null,"preprocess":null},{"capture":"part","path":"parts[].part","type":"string","card":null,"preprocess":null},{"capture":"year","path":"year","type":"string","card":null,"preprocess":null},{"capture":"reaffirmed","path":"reaffirmed","type":"string","card":null,"preprocess":null},{"capture":"language","path":"language","type":"string","card":null,"preprocess":null},{"capture":"all_parts","path":"all_parts","type":"string","card":null,"preprocess":null},{"capture":"amd_type","path":"amd_type","type":"string","card":null,"preprocess":null},{"capture":"amd_number","path":"amd_number","type":"string","card":null,"preprocess":null},{"capture":"amd_year","path":"amd_year","type":"string","card":null,"preprocess":null},{"capture":"amd_reaffirmed","path":"amd_reaffirmed","type":"string","card":null,"preprocess":null},{"capture":"expl_type","path":"expl_type","type":"string","card":null,"preprocess":null},{"capture":"expl_number","path":"expl_number","type":"string","card":null,"preprocess":null},{"capture":"corr_type","path":"corr_type","type":"string","card":null,"preprocess":null},{"capture":"corr_number","path":"corr_number","type":"string","card":null,"preprocess":null},{"capture":"corr_year","path":"corr_year","type":"string","card":null,"preprocess":null},{"capture":"corr_reaffirmed","path":"corr_reaffirmed","type":"string","card":null,"preprocess":null},{"capture":"symbol_present","path":"symbol_present","type":"string","card":null,"preprocess":null},{"capture":"symbol_value","path":"symbol_value","type":"string","card":null,"preprocess":null}]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule supplement: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule supplement: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule supplement: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule symbol_value_char: branches 1 and 2 are order-dependent (first set not statically known)","rule identifier: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"JIS B 0001","expect":{}},{"entry":"identifier","kind":"accept","input":"JIS X 0208:1997","expect":{}},{"entry":"identifier","kind":"accept","input":"WES 7700-1:2019","expect":{}},{"entry":"identifier","kind":"accept","input":"WES 7301:2020R","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}},{"entry":"identifier","kind":"reject","input":"JIS WES 7700","expect":{}},{"entry":"identifier","kind":"reject","input":"WES X 7700","expect":{}}],"docs":{},"source":"# Port of lib/pubid/jis/parser.rb — JIS identifiers with the Japanese\n# full-width separator tolerance (ー   : ()), TR/TS prefixes, parts,\n# reaffirmed years, (E)/(J) language codes, 規格群 all-parts, AMD/EXPL/\n# CORR supplements, and the SYMBOL clause. WES (Japan Welding Engineering\n# Society) ids share the JIS tail but carry no series letter or JIS prefix.\n\ngrammar PubidJis version \"0.1.0\" edition 2 {\n dash = (\"-\" / \"ー\") as dash\n space = (\" \" / \" \")\n colon = (\":\" / \":\")\n type_prefix = (\"TR\" / \"TS\") as type (space / slash)\n series = %x41-5A as series\n number = (1*digit) as number\n part = dash (1*digit) as part\n parts = (*part) as parts\n reaffirmed = \"R\" (*\"R\")\n year = colon (1*digit) as year ([\"R\" (*\"R\")]) as reaffirmed\n language = (\"(\" / \"(\") (\"E\" / \"J\") as language (\")\" / \")\")\n all_parts = ((\"(\" \"規格群\" \")\") / (\"(\" \"規格群\" \")\")) as all_parts\n amendment = slash (\"AMENDMENT\" / \"AMD\") as amd_type space (1*digit) as amd_number colon (1*digit) as amd_year ([\"R\" (*\"R\")]) as amd_reaffirmed\n explanation = slash (\"EXPLANATION\" / \"EXPL\") as expl_type ([space (1*digit) as expl_number])\n corrigendum = slash (\"CORRIGENDUM\" / \"CORR\") as corr_type space (1*digit) as corr_number colon (1*digit) as corr_year ([\"R\" (*\"R\")]) as corr_reaffirmed\n supplement = (amendment as amendment) / (explanation as explanation) / (corrigendum as corrigendum)\n symbol_value_char = %x01-09 / %x0B-10FFFF\n symbol_clause = space \"SYMBOL\" as symbol_present ([space (1*symbol_value_char) as symbol_value])\n wes_identifier = \"WES\" as wes space number parts [year] [language] [all_parts] [supplement] [symbol_clause]\n jis_identifier = [\"JIS\" [(space / slash)]] [type_prefix] [space] series [space] number parts [year] [language] [all_parts] [supplement] [symbol_clause]\n identifier = wes_identifier / jis_identifier\n upper = %x41-5A\n digit = %x30-39\n slash = \"/\"\n entry identifier: identifier\n\n # Typed model bindings: bound captures land on the consumer\n # builder's fields of the same name; repeated parts collect under\n # parts[].part.\n bindings identifier {\n wes -> wes (string)\n type -> type (string)\n series -> series (string)\n number -> number (string)\n part -> parts[].part (string)\n year -> year (string)\n reaffirmed -> reaffirmed (string)\n language -> language (string)\n all_parts -> all_parts (string)\n amd_type -> amd_type (string)\n amd_number -> amd_number (string)\n amd_year -> amd_year (string)\n amd_reaffirmed -> amd_reaffirmed (string)\n expl_type -> expl_type (string)\n expl_number -> expl_number (string)\n corr_type -> corr_type (string)\n corr_number -> corr_number (string)\n corr_year -> corr_year (string)\n corr_reaffirmed -> corr_reaffirmed (string)\n symbol_present -> symbol_present (string)\n symbol_value -> symbol_value (string)\n }\n\n \n test {\n accept \"JIS B 0001\"\n accept \"JIS X 0208:1997\"\n accept \"WES 7700-1:2019\"\n accept \"WES 7301:2020R\"\n reject \"nonsense\"\n reject \"JIS WES 7700\"\n reject \"WES X 7700\"\n }\n}\n","source_hash":"cee4b9e9e0254a2e48e9c1bbc9b4c13684765434ddcd309b58be70a85611f798","unicode_tables":"onigmo (Ruby 3.4.10)","compiler_version":"1.3.114","edition":2,"checksum":"sha256:67d1e26097f00ecaac49d17b5955421c1ee3969b4d25269c6b76ee58c8f102dc"}
1
+ {"bindings":null,"version":"0.1.0","grammar":"PubidJis","shape":"parsanol-tree/v2","binding_version":1,"entries":{"identifier":{"root":"identifier","grammar":{"atoms":[{"Entity":{"atom":144}},{"Str":{"pattern":"WES"}},{"Named":{"name":"wes","atom":1}},{"Entity":{"atom":6}},{"Str":{"pattern":" "}},{"Str":{"pattern":" "}},{"Alternative":{"atoms":[4,5]}},{"Entity":{"atom":11}},{"Entity":{"atom":9}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Repetition":{"atom":8,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"number","atom":10}},{"Entity":{"atom":24}},{"Entity":{"atom":22}},{"Entity":{"atom":18}},{"Str":{"pattern":"-"}},{"Str":{"pattern":"ー"}},{"Alternative":{"atoms":[15,16]}},{"Named":{"name":"dash","atom":17}},{"Entity":{"atom":9}},{"Repetition":{"atom":19,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"part","atom":20}},{"Sequence":{"atoms":[14,21]}},{"Repetition":{"atom":13,"min":0,"max":null,"tag":"Repetition"}},{"Named":{"name":"parts","atom":23}},{"Entity":{"atom":40}},{"Entity":{"atom":29}},{"Str":{"pattern":":"}},{"Str":{"pattern":":"}},{"Alternative":{"atoms":[27,28]}},{"Entity":{"atom":9}},{"Repetition":{"atom":30,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"year","atom":31}},{"Entity":{"atom":38}},{"Str":{"pattern":"R"}},{"Str":{"pattern":"R"}},{"Repetition":{"atom":35,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[34,36]}},{"Named":{"name":"reaffirmed","atom":37}},{"Repetition":{"atom":33,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[26,32,39]}},{"Repetition":{"atom":25,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":53}},{"Str":{"pattern":"("}},{"Str":{"pattern":"("}},{"Alternative":{"atoms":[43,44]}},{"Str":{"pattern":"E"}},{"Str":{"pattern":"J"}},{"Alternative":{"atoms":[46,47]}},{"Named":{"name":"language","atom":48}},{"Str":{"pattern":")"}},{"Str":{"pattern":")"}},{"Alternative":{"atoms":[50,51]}},{"Sequence":{"atoms":[45,49,52]}},{"Repetition":{"atom":42,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":65}},{"Str":{"pattern":"("}},{"Str":{"pattern":"規格群"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[56,57,58]}},{"Str":{"pattern":"("}},{"Str":{"pattern":"規格群"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[60,61,62]}},{"Alternative":{"atoms":[59,63]}},{"Named":{"name":"all_parts","atom":64}},{"Repetition":{"atom":55,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":127}},{"Entity":{"atom":89}},{"Entity":{"atom":70}},{"Str":{"pattern":"/"}},{"Str":{"pattern":"AMENDMENT"}},{"Str":{"pattern":"AMD"}},{"Alternative":{"atoms":[71,72]}},{"Named":{"name":"amd_type","atom":73}},{"Entity":{"atom":6}},{"Entity":{"atom":9}},{"Repetition":{"atom":76,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"amd_number","atom":77}},{"Entity":{"atom":29}},{"Entity":{"atom":9}},{"Repetition":{"atom":80,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"amd_year","atom":81}},{"Str":{"pattern":"R"}},{"Str":{"pattern":"R"}},{"Repetition":{"atom":84,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[83,85]}},{"Repetition":{"atom":86,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"amd_reaffirmed","atom":87}},{"Sequence":{"atoms":[69,74,75,78,79,82,88]}},{"Named":{"name":"amendment","atom":68}},{"Entity":{"atom":103}},{"Entity":{"atom":70}},{"Str":{"pattern":"EXPLANATION"}},{"Str":{"pattern":"EXPL"}},{"Alternative":{"atoms":[93,94]}},{"Named":{"name":"expl_type","atom":95}},{"Entity":{"atom":6}},{"Entity":{"atom":9}},{"Repetition":{"atom":98,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"expl_number","atom":99}},{"Sequence":{"atoms":[97,100]}},{"Repetition":{"atom":101,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[92,96,102]}},{"Named":{"name":"explanation","atom":91}},{"Entity":{"atom":125}},{"Entity":{"atom":70}},{"Str":{"pattern":"CORRIGENDUM"}},{"Str":{"pattern":"CORR"}},{"Alternative":{"atoms":[107,108]}},{"Named":{"name":"corr_type","atom":109}},{"Entity":{"atom":6}},{"Entity":{"atom":9}},{"Repetition":{"atom":112,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"corr_number","atom":113}},{"Entity":{"atom":29}},{"Entity":{"atom":9}},{"Repetition":{"atom":116,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"corr_year","atom":117}},{"Str":{"pattern":"R"}},{"Str":{"pattern":"R"}},{"Repetition":{"atom":120,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[119,121]}},{"Repetition":{"atom":122,"min":0,"max":1,"tag":"Maybe"}},{"Named":{"name":"corr_reaffirmed","atom":123}},{"Sequence":{"atoms":[106,110,111,114,115,118,124]}},{"Named":{"name":"corrigendum","atom":105}},{"Alternative":{"atoms":[90,104,126]}},{"Repetition":{"atom":67,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":142}},{"Entity":{"atom":6}},{"Str":{"pattern":"SYMBOL"}},{"Named":{"name":"symbol_present","atom":131}},{"Entity":{"atom":6}},{"Entity":{"atom":137}},{"Re":{"pattern":"[\\x01-\\x09]"}},{"Re":{"pattern":"[\\x0b-\\u{10ffff}]"}},{"Alternative":{"atoms":[135,136]}},{"Repetition":{"atom":134,"min":1,"max":null,"tag":"Repetition"}},{"Named":{"name":"symbol_value","atom":138}},{"Sequence":{"atoms":[133,139]}},{"Repetition":{"atom":140,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[130,132,141]}},{"Repetition":{"atom":129,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[2,3,7,12,41,54,66,128,143]}},{"Entity":{"atom":182}},{"Str":{"pattern":"JIS"}},{"Entity":{"atom":6}},{"Entity":{"atom":70}},{"Alternative":{"atoms":[147,148]}},{"Repetition":{"atom":149,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[146,150]}},{"Repetition":{"atom":151,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":161}},{"Str":{"pattern":"TR"}},{"Str":{"pattern":"TS"}},{"Alternative":{"atoms":[154,155]}},{"Named":{"name":"type","atom":156}},{"Entity":{"atom":6}},{"Entity":{"atom":70}},{"Alternative":{"atoms":[158,159]}},{"Sequence":{"atoms":[157,160]}},{"Repetition":{"atom":153,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":6}},{"Repetition":{"atom":163,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":167}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Named":{"name":"series","atom":166}},{"Entity":{"atom":6}},{"Repetition":{"atom":168,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":11}},{"Entity":{"atom":24}},{"Entity":{"atom":40}},{"Repetition":{"atom":172,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":53}},{"Repetition":{"atom":174,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":65}},{"Repetition":{"atom":176,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":127}},{"Repetition":{"atom":178,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":142}},{"Repetition":{"atom":180,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[152,162,164,165,169,170,171,173,175,177,179,181]}},{"Alternative":{"atoms":[0,145]}}],"root":183},"bindings":[{"capture":"wes","path":"wes","type":"string","card":null,"preprocess":null},{"capture":"type","path":"type","type":"string","card":null,"preprocess":null},{"capture":"series","path":"series","type":"string","card":null,"preprocess":null},{"capture":"number","path":"number","type":"string","card":null,"preprocess":null},{"capture":"part","path":"parts[].part","type":"string","card":null,"preprocess":null},{"capture":"year","path":"year","type":"string","card":null,"preprocess":null},{"capture":"reaffirmed","path":"reaffirmed","type":"string","card":null,"preprocess":null},{"capture":"language","path":"language","type":"string","card":null,"preprocess":null},{"capture":"all_parts","path":"all_parts","type":"string","card":null,"preprocess":null},{"capture":"amd_type","path":"amd_type","type":"string","card":null,"preprocess":null},{"capture":"amd_number","path":"amd_number","type":"string","card":null,"preprocess":null},{"capture":"amd_year","path":"amd_year","type":"string","card":null,"preprocess":null},{"capture":"amd_reaffirmed","path":"amd_reaffirmed","type":"string","card":null,"preprocess":null},{"capture":"expl_type","path":"expl_type","type":"string","card":null,"preprocess":null},{"capture":"expl_number","path":"expl_number","type":"string","card":null,"preprocess":null},{"capture":"corr_type","path":"corr_type","type":"string","card":null,"preprocess":null},{"capture":"corr_number","path":"corr_number","type":"string","card":null,"preprocess":null},{"capture":"corr_year","path":"corr_year","type":"string","card":null,"preprocess":null},{"capture":"corr_reaffirmed","path":"corr_reaffirmed","type":"string","card":null,"preprocess":null},{"capture":"symbol_present","path":"symbol_present","type":"string","card":null,"preprocess":null},{"capture":"symbol_value","path":"symbol_value","type":"string","card":null,"preprocess":null}]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule supplement: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule supplement: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule supplement: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule symbol_value_char: branches 1 and 2 are order-dependent (first set not statically known)","rule identifier: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"identifier","render":{},"derive":{},"tests":[{"entry":"identifier","kind":"accept","input":"JIS B 0001","expect":{}},{"entry":"identifier","kind":"accept","input":"JIS X 0208:1997","expect":{}},{"entry":"identifier","kind":"accept","input":"WES 7700-1:2019","expect":{}},{"entry":"identifier","kind":"accept","input":"WES 7301:2020R","expect":{}},{"entry":"identifier","kind":"reject","input":"JIS WES 7700","expect":{}},{"entry":"identifier","kind":"reject","input":"WES X 7700","expect":{}},{"entry":"identifier","kind":"reject","input":"nonsense","expect":{}},{"entry":"identifier","kind":"example","input":"WES 7700-1:2019","expect":{"wes":"WES","number":"7700","year":"2019"}},{"entry":"identifier","kind":"example","input":"WES 7301:2020R","expect":{"wes":"WES","number":"7301","year":"2020","reaffirmed":"R"}},{"entry":"identifier","kind":"example","input":"JIS X 0208:1997","expect":{"series":"X","number":"0208","year":"1997"}},{"entry":"identifier","kind":"example","input":"WES 7700:2019/AMD 1:2020R","expect":{"wes":"WES","number":"7700","amd_type":"AMD","amd_number":"1","amd_year":"2020","amd_reaffirmed":"R"}},{"entry":"identifier","kind":"example","input":"JIS X 0208:1997R","expect":{"series":"X","year":"1997","reaffirmed":"R"}},{"entry":"identifier","kind":"example","input":"JIS X 0208:1997RR","expect":{"series":"X","year":"1997","reaffirmed":"RR"}}],"docs":{},"source":"# Port of lib/pubid/jis/parser.rb — JIS identifiers with the Japanese\n# full-width separator tolerance (ー   : ()), TR/TS prefixes, parts,\n# reaffirmed years, (E)/(J) language codes, 規格群 all-parts, AMD/EXPL/\n# CORR supplements, and the SYMBOL clause. WES (Japan Welding Engineering\n# Society) ids share the JIS tail but carry no series letter or JIS prefix.\n\ngrammar PubidJis version \"0.1.0\" edition 2 {\n dash = (\"-\" / \"ー\") as dash\n space = (\" \" / \" \")\n colon = (\":\" / \":\")\n type_prefix = (\"TR\" / \"TS\") as type (space / slash)\n series = %x41-5A as series\n number = (1*digit) as number\n part = dash (1*digit) as part\n parts = (*part) as parts\n reaffirmed = \"R\" (*\"R\")\n year = colon (1*digit) as year [reaffirmed_rule]\n language = (\"(\" / \"(\") (\"E\" / \"J\") as language (\")\" / \")\")\n all_parts = ((\"(\" \"規格群\" \")\") / (\"(\" \"規格群\" \")\")) as all_parts\n amendment = {\n slash (\"AMENDMENT\" / \"AMD\") as amd_type\n space\n (1*digit) as amd_number\n colon (1*digit) as amd_year\n ([\"R\" (*\"R\")]) as amd_reaffirmed\n }\n explanation = {\n slash (\"EXPLANATION\" / \"EXPL\") as expl_type\n ([space (1*digit) as expl_number])\n }\n corrigendum = {\n slash (\"CORRIGENDUM\" / \"CORR\") as corr_type\n space\n (1*digit) as corr_number\n colon (1*digit) as corr_year\n ([\"R\" (*\"R\")]) as corr_reaffirmed\n }\n supplement = {\n (amendment as amendment)\n / (explanation as explanation)\n / (corrigendum as corrigendum)\n }\n symbol_value_char = %x01-09 / %x0B-10FFFF\n symbol_clause = {\n space \"SYMBOL\" as symbol_present\n ([space (1*symbol_value_char) as symbol_value])\n }\n wes_identifier = {\n \"WES\" as wes\n space\n number\n parts\n [year]\n [language]\n [all_parts]\n [supplement]\n [symbol_clause]\n }\n jis_identifier = {\n [\"JIS\" [(space / slash)]]\n [type_prefix]\n [space]\n series\n [space]\n number\n parts\n [year]\n [language]\n [all_parts]\n [supplement]\n [symbol_clause]\n }\n identifier = wes_identifier / jis_identifier\n upper = %x41-5A\n digit = %x30-39\n slash = \"/\"\n reaffirmed_rule = (\"R\" (*\"R\")) as reaffirmed\n entry identifier: identifier\n\n # Typed model bindings: bound captures land on the consumer\n # builder's fields of the same name; repeated parts collect under\n # parts[].part.\n bindings identifier {\n wes -> wes (string)\n type -> type (string)\n series -> series (string)\n number -> number (string)\n part -> parts[].part (string)\n year -> year (string)\n reaffirmed -> reaffirmed (string)\n language -> language (string)\n all_parts -> all_parts (string)\n amd_type -> amd_type (string)\n amd_number -> amd_number (string)\n amd_year -> amd_year (string)\n amd_reaffirmed -> amd_reaffirmed (string)\n expl_type -> expl_type (string)\n expl_number -> expl_number (string)\n corr_type -> corr_type (string)\n corr_number -> corr_number (string)\n corr_year -> corr_year (string)\n corr_reaffirmed -> corr_reaffirmed (string)\n symbol_present -> symbol_present (string)\n symbol_value -> symbol_value (string)\n }\n\n test {\n accept \"JIS B 0001\"\n accept \"JIS X 0208:1997\"\n accept \"WES 7700-1:2019\"\n accept \"WES 7301:2020R\"\n reject \"JIS WES 7700\"\n reject \"WES X 7700\"\n reject \"nonsense\"\n example \"WES 7700-1:2019\" { wes: \"WES\", number: \"7700\", year: \"2019\" }\n example \"WES 7301:2020R\" { wes: \"WES\", number: \"7301\", year: \"2020\", reaffirmed: \"R\" }\n example \"JIS X 0208:1997\" { series: \"X\", number: \"0208\", year: \"1997\" }\n example \"WES 7700:2019/AMD 1:2020R\" { wes: \"WES\", number: \"7700\", amd_type: \"AMD\", amd_number: \"1\", amd_year: \"2020\", amd_reaffirmed: \"R\" }\n example \"JIS X 0208:1997R\" { series: \"X\", year: \"1997\", reaffirmed: \"R\" }\n example \"JIS X 0208:1997RR\" { series: \"X\", year: \"1997\", reaffirmed: \"RR\" }\n }\n}\n","source_hash":"bb68f75e3e1d9b7e79613bd6cff60ccd77f6e2e68ace2569a2fbc968543b1f3d","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.121","edition":2,"semantics_hash":"sha256:b16cf5d2687fef91bb0c21ce6b417cf9d9dfcf9aec0280169acb246f48d6b22b","checksum":"sha256:156eb10c6a7638055e3ca2556c6bf62ecca6521b432c828269cdcbab080c44be"}
data/data/parg/parg.json CHANGED
@@ -1 +1 @@
1
- {"bindings":null,"version":"1.0.0","grammar":"PgMeta","shape":"parsanol-tree/v2","binding_version":1,"entries":{"file":{"root":"pg_file","grammar":{"atoms":[{"Entity":{"atom":5}},{"Entity":{"atom":4}},{"Re":{"pattern":"[ ]"}},{"Re":{"pattern":"[\\x09]"}},{"Alternative":{"atoms":[2,3]}},{"Repetition":{"atom":1,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":572}},{"Entity":{"atom":21}},{"Str":{"pattern":"use"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":19}},{"Entity":{"atom":15}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Alternative":{"atoms":[13,14]}},{"Entity":{"atom":17}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Re":{"pattern":"[_]"}},{"Alternative":{"atoms":[12,16,18]}},{"Repetition":{"atom":11,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[8,9,10]}},{"Entity":{"atom":29}},{"Str":{"pattern":"##"}},{"Entity":{"atom":27}},{"Re":{"pattern":"[\\x01-\\x09]"}},{"Re":{"pattern":"[\\x0b-\\u{10ffff}]"}},{"Alternative":{"atoms":[25,26]}},{"Repetition":{"atom":24,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[23,28]}},{"Entity":{"atom":34}},{"Str":{"pattern":"#"}},{"Entity":{"atom":27}},{"Repetition":{"atom":32,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[31,33]}},{"Entity":{"atom":571}},{"Entity":{"atom":521}},{"Str":{"pattern":"grammar"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"version"}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Str":{"pattern":"\""}},{"Str":{"pattern":"\\"}},{"Entity":{"atom":27}},{"Sequence":{"atoms":[45,46]}},{"Entity":{"atom":52}},{"Re":{"pattern":"[\\x01-\\x09]"}},{"Re":{"pattern":"[\\x0b-\\x21]"}},{"Re":{"pattern":"[\\x23-\\u{10ffff}]"}},{"Alternative":{"atoms":[49,50,51]}},{"Alternative":{"atoms":[47,48]}},{"Repetition":{"atom":53,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"\""}},{"Sequence":{"atoms":[44,54,55]}},{"Entity":{"atom":5}},{"Entity":{"atom":71}},{"Str":{"pattern":"mode"}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[59,60,61]}},{"Str":{"pattern":"edition"}},{"Entity":{"atom":5}},{"Entity":{"atom":67}},{"Entity":{"atom":17}},{"Repetition":{"atom":66,"min":1,"max":null,"tag":"Repetition"}},{"Entity":{"atom":56}},{"Alternative":{"atoms":[65,68]}},{"Sequence":{"atoms":[63,64,69]}},{"Alternative":{"atoms":[62,70]}},{"Sequence":{"atoms":[57,58]}},{"Repetition":{"atom":72,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":5}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Entity":{"atom":4}},{"Entity":{"atom":79}},{"Re":{"pattern":"[\\x0a]"}},{"Alternative":{"atoms":[77,78]}},{"Repetition":{"atom":80,"min":1,"max":null,"tag":"Repetition"}},{"Entity":{"atom":515}},{"Entity":{"atom":259}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":5}},{"Entity":{"atom":258}},{"Entity":{"atom":257}},{"Entity":{"atom":256}},{"Entity":{"atom":5}},{"Entity":{"atom":104}},{"Entity":{"atom":67}},{"Str":{"pattern":"*"}},{"Entity":{"atom":67}},{"Repetition":{"atom":95,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[94,96]}},{"Repetition":{"atom":97,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[93,98]}},{"Str":{"pattern":"*"}},{"Entity":{"atom":67}},{"Repetition":{"atom":101,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[100,102]}},{"Alternative":{"atoms":[99,103]}},{"Entity":{"atom":5}},{"Entity":{"atom":251}},{"Str":{"pattern":"!"}},{"Str":{"pattern":"&"}},{"Alternative":{"atoms":[107,108]}},{"Entity":{"atom":250}},{"Entity":{"atom":249}},{"Entity":{"atom":141}},{"Entity":{"atom":131}},{"Str":{"pattern":"%x"}},{"Entity":{"atom":121}},{"Entity":{"atom":120}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Re":{"pattern":"[\\x41-\\x46]"}},{"Re":{"pattern":"[\\x61-\\x66]"}},{"Alternative":{"atoms":[117,118,119]}},{"Repetition":{"atom":116,"min":2,"max":6,"tag":"Repetition"}},{"Str":{"pattern":"-"}},{"Entity":{"atom":121}},{"Sequence":{"atoms":[122,123]}},{"Str":{"pattern":"."}},{"Entity":{"atom":121}},{"Sequence":{"atoms":[125,126]}},{"Repetition":{"atom":127,"min":1,"max":null,"tag":"Repetition"}},{"Alternative":{"atoms":[124,128]}},{"Repetition":{"atom":129,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[114,115,130]}},{"Entity":{"atom":135}},{"Str":{"pattern":"%i"}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[133,134]}},{"Entity":{"atom":139}},{"Str":{"pattern":"%s"}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[137,138]}},{"Entity":{"atom":56}},{"Alternative":{"atoms":[113,132,136,140]}},{"Str":{"pattern":"("}},{"Entity":{"atom":5}},{"Repetition":{"atom":143,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":173}},{"Entity":{"atom":5}},{"Str":{"pattern":"/"}},{"Entity":{"atom":5}},{"Entity":{"atom":170}},{"Entity":{"atom":5}},{"Entity":{"atom":167}},{"Entity":{"atom":159}},{"Entity":{"atom":5}},{"Str":{"pattern":"as"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[153,154,155,156]}},{"Repetition":{"atom":157,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[111,158]}},{"Alternative":{"atoms":[106,152]}},{"Repetition":{"atom":160,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[92,105,161]}},{"Entity":{"atom":164}},{"Sequence":{"atoms":[109,110]}},{"Entity":{"atom":159}},{"Alternative":{"atoms":[162,163,165]}},{"Sequence":{"atoms":[91,166]}},{"Sequence":{"atoms":[150,151]}},{"Repetition":{"atom":168,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[90,169]}},{"Sequence":{"atoms":[146,147,148,149]}},{"Repetition":{"atom":171,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[89,172]}},{"Entity":{"atom":5}},{"Repetition":{"atom":174,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[142,144,145,175,176]}},{"Str":{"pattern":"["}},{"Entity":{"atom":5}},{"Repetition":{"atom":179,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":173}},{"Entity":{"atom":5}},{"Repetition":{"atom":182,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"]"}},{"Sequence":{"atoms":[178,180,181,183,184]}},{"Entity":{"atom":196}},{"Str":{"pattern":"alt"}},{"Entity":{"atom":5}},{"Str":{"pattern":"from_table"}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Entity":{"atom":5}},{"Str":{"pattern":"column"}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[187,188,189,190,191,192,193,194,195]}},{"Entity":{"atom":214}},{"Str":{"pattern":"set"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Str":{"pattern":"("}},{"Entity":{"atom":5}},{"Repetition":{"atom":206,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":173}},{"Entity":{"atom":5}},{"Repetition":{"atom":209,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[205,207,208,210,211]}},{"Alternative":{"atoms":[204,212]}},{"Sequence":{"atoms":[198,199,200,201,202,203,213]}},{"Entity":{"atom":247}},{"Str":{"pattern":"switch"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Repetition":{"atom":221,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":237}},{"Entity":{"atom":56}},{"Str":{"pattern":"_"}},{"Alternative":{"atoms":[224,225]}},{"Entity":{"atom":5}},{"Str":{"pattern":"->"}},{"Entity":{"atom":5}},{"Entity":{"atom":236}},{"Entity":{"atom":20}},{"Str":{"pattern":"."}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[232,233]}},{"Repetition":{"atom":234,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[231,235]}},{"Sequence":{"atoms":[226,227,228,229,230]}},{"Entity":{"atom":81}},{"Entity":{"atom":237}},{"Sequence":{"atoms":[238,239]}},{"Repetition":{"atom":240,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[223,241]}},{"Repetition":{"atom":242,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":81}},{"Repetition":{"atom":244,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[216,217,218,219,220,222,243,245,246]}},{"Entity":{"atom":236}},{"Alternative":{"atoms":[112,177,185,186,197,215,248]}},{"Sequence":{"atoms":[111,158]}},{"Sequence":{"atoms":[109,110]}},{"Alternative":{"atoms":[106,152]}},{"Repetition":{"atom":252,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[92,105,253]}},{"Alternative":{"atoms":[254,163,165]}},{"Sequence":{"atoms":[91,255]}},{"Sequence":{"atoms":[90,169]}},{"Sequence":{"atoms":[89,172]}},{"Sequence":{"atoms":[84,85,86,87,88]}},{"Entity":{"atom":347}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":4}},{"Entity":{"atom":79}},{"Alternative":{"atoms":[264,265]}},{"Repetition":{"atom":266,"min":0,"max":null,"tag":"Repetition"}},{"Re":{"pattern":"[{]"}},{"Entity":{"atom":344}},{"Entity":{"atom":343}},{"Entity":{"atom":342}},{"Entity":{"atom":277}},{"Entity":{"atom":4}},{"Entity":{"atom":79}},{"Entity":{"atom":34}},{"Alternative":{"atoms":[273,274,275]}},{"Repetition":{"atom":276,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":104}},{"Entity":{"atom":277}},{"Entity":{"atom":337}},{"Str":{"pattern":"!"}},{"Str":{"pattern":"&"}},{"Alternative":{"atoms":[281,282]}},{"Entity":{"atom":336}},{"Entity":{"atom":335}},{"Entity":{"atom":141}},{"Str":{"pattern":"("}},{"Entity":{"atom":277}},{"Repetition":{"atom":288,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":318}},{"Entity":{"atom":277}},{"Str":{"pattern":"/"}},{"Entity":{"atom":277}},{"Entity":{"atom":315}},{"Entity":{"atom":277}},{"Entity":{"atom":312}},{"Entity":{"atom":304}},{"Entity":{"atom":277}},{"Str":{"pattern":"as"}},{"Entity":{"atom":277}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[298,299,300,301]}},{"Repetition":{"atom":302,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[285,303]}},{"Alternative":{"atoms":[280,297]}},{"Repetition":{"atom":305,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[278,279,306]}},{"Entity":{"atom":309}},{"Sequence":{"atoms":[283,284]}},{"Entity":{"atom":304}},{"Alternative":{"atoms":[307,308,310]}},{"Sequence":{"atoms":[272,311]}},{"Sequence":{"atoms":[295,296]}},{"Repetition":{"atom":313,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[271,314]}},{"Sequence":{"atoms":[291,292,293,294]}},{"Repetition":{"atom":316,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[270,317]}},{"Entity":{"atom":277}},{"Repetition":{"atom":319,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[287,289,290,320,321]}},{"Str":{"pattern":"["}},{"Entity":{"atom":277}},{"Repetition":{"atom":324,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":318}},{"Entity":{"atom":277}},{"Repetition":{"atom":327,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"]"}},{"Sequence":{"atoms":[323,325,326,328,329]}},{"Entity":{"atom":196}},{"Entity":{"atom":214}},{"Entity":{"atom":247}},{"Entity":{"atom":236}},{"Alternative":{"atoms":[286,322,330,331,332,333,334]}},{"Sequence":{"atoms":[285,303]}},{"Sequence":{"atoms":[283,284]}},{"Alternative":{"atoms":[280,297]}},{"Repetition":{"atom":338,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[278,279,339]}},{"Alternative":{"atoms":[340,308,310]}},{"Sequence":{"atoms":[272,341]}},{"Sequence":{"atoms":[271,314]}},{"Sequence":{"atoms":[270,317]}},{"Entity":{"atom":277}},{"Re":{"pattern":"[}]"}},{"Sequence":{"atoms":[261,262,263,267,268,269,345,346]}},{"Entity":{"atom":355}},{"Str":{"pattern":"entry"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[349,350,351,352,353,354]}},{"Entity":{"atom":413}},{"Str":{"pattern":"bindings"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":81}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Repetition":{"atom":362,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":403}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"->"}},{"Entity":{"atom":5}},{"Entity":{"atom":379}},{"Entity":{"atom":20}},{"Str":{"pattern":"["}},{"Str":{"pattern":"]"}},{"Sequence":{"atoms":[371,372]}},{"Str":{"pattern":"."}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[374,375]}},{"Alternative":{"atoms":[373,376]}},{"Repetition":{"atom":377,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[370,378]}},{"Entity":{"atom":5}},{"Str":{"pattern":"("}},{"Entity":{"atom":20}},{"Str":{"pattern":","}},{"Entity":{"atom":5}},{"Entity":{"atom":390}},{"Entity":{"atom":17}},{"Str":{"pattern":"."}},{"Str":{"pattern":"*"}},{"Alternative":{"atoms":[386,387,388]}},{"Repetition":{"atom":389,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[383,384,385]}},{"Repetition":{"atom":391,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[380,381,382,392,393]}},{"Repetition":{"atom":394,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":5}},{"Str":{"pattern":"preprocess"}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[396,397,398,399,400]}},{"Repetition":{"atom":401,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[365,366,367,368,369,395,402]}},{"Entity":{"atom":81}},{"Entity":{"atom":403}},{"Sequence":{"atoms":[404,405]}},{"Repetition":{"atom":406,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[364,407]}},{"Repetition":{"atom":408,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":81}},{"Repetition":{"atom":410,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[357,358,359,360,361,363,409,411,412]}},{"Entity":{"atom":435}},{"Str":{"pattern":"preprocess"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":81}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Repetition":{"atom":420,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":432}},{"Str":{"pattern":"table_lookup"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"->"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[423,424,425,426,427,428,429,430,431]}},{"Entity":{"atom":81}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[415,416,417,418,419,421,422,433,434]}},{"Entity":{"atom":485}},{"Str":{"pattern":"test"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[438,439]}},{"Repetition":{"atom":440,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":81}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Repetition":{"atom":444,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":476}},{"Str":{"pattern":"accept"}},{"Str":{"pattern":"reject"}},{"Str":{"pattern":"example"}},{"Alternative":{"atoms":[447,448,449]}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Entity":{"atom":5}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Repetition":{"atom":455,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":467}},{"Entity":{"atom":20}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Entity":{"atom":67}},{"Str":{"pattern":"true"}},{"Str":{"pattern":"false"}},{"Alternative":{"atoms":[463,464]}},{"Alternative":{"atoms":[461,462,465]}},{"Sequence":{"atoms":[458,459,460,466]}},{"Entity":{"atom":81}},{"Repetition":{"atom":468,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[453,454,456,457,469,470]}},{"Repetition":{"atom":471,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[450,451,452,472]}},{"Entity":{"atom":34}},{"Entity":{"atom":29}},{"Alternative":{"atoms":[473,474,475]}},{"Entity":{"atom":81}},{"Entity":{"atom":476}},{"Sequence":{"atoms":[477,478]}},{"Repetition":{"atom":479,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[446,480]}},{"Repetition":{"atom":481,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":81}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[437,441,442,443,445,482,483,484]}},{"Entity":{"atom":494}},{"Str":{"pattern":"custom"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[487,488,489,490,491,492,493]}},{"Entity":{"atom":503}},{"Str":{"pattern":"state"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[496,497,498,499,500,501,502]}},{"Entity":{"atom":512}},{"Str":{"pattern":"glue"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[508,509]}},{"Repetition":{"atom":510,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[505,506,507,511]}},{"Entity":{"atom":29}},{"Entity":{"atom":34}},{"Alternative":{"atoms":[83,260,348,356,414,436,486,495,504,513,514]}},{"Sequence":{"atoms":[76,82]}},{"Repetition":{"atom":516,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":81}},{"Repetition":{"atom":518,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[37,38,39,40,41,42,43,73,74,75,517,519,520]}},{"Entity":{"atom":355}},{"Entity":{"atom":413}},{"Entity":{"atom":435}},{"Entity":{"atom":485}},{"Entity":{"atom":563}},{"Str":{"pattern":"render"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":81}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Entity":{"atom":558}},{"Str":{"pattern":"field"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Sequence":{"atoms":[534,535,536]}},{"Str":{"pattern":"literal"}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[538,539,540]}},{"Str":{"pattern":"cond"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":81}},{"Str":{"pattern":"{"}},{"Entity":{"atom":81}},{"Entity":{"atom":554}},{"Sequence":{"atoms":[547,548]}},{"Repetition":{"atom":549,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":81}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[542,543,544,545,546,550,551,552]}},{"Alternative":{"atoms":[537,541,553]}},{"Sequence":{"atoms":[547,548]}},{"Repetition":{"atom":555,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[542,543,544,545,546,556,551,552]}},{"Alternative":{"atoms":[537,541,557]}},{"Sequence":{"atoms":[532,533]}},{"Repetition":{"atom":559,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":81}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[527,528,529,530,531,560,561,562]}},{"Entity":{"atom":570}},{"Str":{"pattern":"derive"}},{"Entity":{"atom":5}},{"Entity":{"atom":20}},{"Entity":{"atom":5}},{"Entity":{"atom":56}},{"Sequence":{"atoms":[565,566,567,568,569]}},{"Alternative":{"atoms":[36,522,523,524,525,526,564]}},{"Alternative":{"atoms":[7,22,30,35]}},{"Entity":{"atom":81}},{"Repetition":{"atom":573,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[6,574]}},{"Repetition":{"atom":575,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":5}},{"Sequence":{"atoms":[0,576,577]}}],"root":578},"bindings":[]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule nonl: branches 1 and 2 are order-dependent (first set not statically known)","rule str_body_char: branches 1 and 3 are order-dependent (first set not statically known)","rule str_body_char: branches 2 and 3 are order-dependent (first set not statically known)","rule hex: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule hex: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule hex: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 4 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 5 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 5 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 6 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 4 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 5 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 5 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 6 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule test_line: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 4 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 5 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 8 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 9 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 4 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 5 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 8 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 9 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 10 and 11 are order-dependent (shared first bytes; ordered choice is decisive)","rule top_item: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"file","render":{},"derive":{},"tests":[{"entry":"file","kind":"accept","input":"grammar T version \"1\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = b / c as d }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { g = [x] 3*y !z &w (p / q) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { k = 1*3(e / f) !(g h) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { custom lookback = \"ParsanolAtoms::Lookbehind\" a = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { state block_kind: symbol a = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (set block_kind = \"quote\") %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (switch block_kind { \"quote\" -> q _ -> never }) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (set d = (3*4(%x2D)) %x0A) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (!(state d) %x61-7A) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" {\n p = {\n %i\"iso\" / %i\"ieee\"\n }\n}","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { q = { a b } }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" {\n r =\n {\n x as y\n }\n}","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" {\n s = {\n # a comment is body whitespace\n !(t / u) 2*v\n }\n}","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" mode \"v1\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" mode \"v2\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition 1 { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition 2 { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition \"v2\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition 2 {\n glue ws comment\n ws = 1*( %x20 )\n comment = \"#\" *nonl\n main = \"a\" ws \"b\"\n}","expect":{}},{"entry":"file","kind":"reject","input":"grammar T version \"1\" { q = { a }","expect":{}},{"entry":"file","kind":"reject","input":"grammar T version \"1\" { q = { } }","expect":{}},{"entry":"file","kind":"reject","input":"nonsense","expect":{}},{"entry":"file","kind":"reject","input":"grammar T version \"1\" { = }","expect":{}}],"docs":{},"source":"# PG described in PG — the self-description grammar (F10, phase 1).\n# It recognizes the language this file is written in, over raw text:\n# whitespace is threaded explicitly (pq = potential whitespace within a\n# line, nlws = line-breaking whitespace, bw = brace-body whitespace: the\n# b* rules thread it so brace-form rule bodies span lines). The\n# reference compiler remains parsanol-ruby (SSOT, TODO 11); this\n# artifact is the validator — and brace_rule below is itself written in\n# the brace form it recognizes.\n\ngrammar PgMeta version \"1.0.0\" edition 1 {\n\n # ---- lexical ----\n digit = %x30-39\n hexdig = %x30-39 / %x41-46 / %x61-66\n letter = %x41-5A / %x61-7A\n ident_char = letter / digit / %x5F\n ident = 1*ident_char\n newline = %x0A\n nonl = %x01-09 / %x0B-10FFFF\n comment = \"#\" *nonl\n doc_marker = \"##\" *nonl\n ws = %x20 / %x09\n nlws = 1*(ws / newline)\n pq = *ws\n\n # ---- terminals ----\n str_body_char = %x01-09 / %x0B-21 / %x23-10FFFF\n dstring = \"\\\"\" *(\"\\\\\" nonl / str_body_char) \"\\\"\"\n istring = \"%i\" dstring\n sstring = \"%s\" dstring\n hexdigits = 2*6hexdig\n hexlit = \"%x\" hexdigits [(\"-\" hexdigits) / 1*(\".\" hexdigits)]\n hex = hexlit / istring / sstring / dstring\n\n # ---- expressions (pq-threaded) ----\n choice = seq *(pq \"/\" pq seq)\n seq = element *(pq element)\n element = pq (rep_prefix pq [pred / postfixed] / pred / postfixed)\n rep_prefix = num [\"*\" [num]] / \"*\" [num]\n num = 1*digit\n pred = (\"!\" / \"&\") postfixed\n postfixed = primary [pq \"as\" pq ident]\n table_alt = \"alt\" pq \"from_table\" pq dstring pq \"column\" pq dstring\n set_expr = \"set\" pq ident pq \"=\" pq (dstring / \"(\" [pq] choice [pq] \")\")\n switch_arm = (dstring / \"_\") pq \"->\" pq dotted_ident\n switch_expr = \"switch\" pq ident pq \"{\" *nlws [switch_arm *(nlws switch_arm)] *nlws \"}\"\n custom_line = \"custom\" pq ident pq \"=\" pq dstring\n state_line = \"state\" pq ident pq \":\" pq ident\n dotted_ident = ident *(\".\" ident)\n primary = hex / \"(\" [pq] choice [pq] \")\" / \"[\" [pq] choice [pq] \"]\" / table_alt / set_expr / switch_expr / dotted_ident\n\n # ---- brace-body expressions (bw-threaded: newlines are whitespace) ----\n bw = *(ws / newline / comment)\n bchoice = bseq *(bw \"/\" bw bseq)\n bseq = belement *(bw belement)\n belement = bw (rep_prefix bw [bpred / bpostfixed] / bpred / bpostfixed)\n bpred = (\"!\" / \"&\") bpostfixed\n bprimary = hex / \"(\" [bw] bchoice [bw] \")\" / \"[\" [bw] bchoice [bw] \"]\" / table_alt / set_expr / switch_expr / dotted_ident\n bpostfixed = bprimary [bw \"as\" bw ident]\n\n # ---- rules and sections ----\n rule = ident pq \"=\" pq choice\n brace_rule = {\n ident pq \"=\" *(ws / newline) %x7B\n bchoice bw %x7D\n }\n entry_section = \"entry\" pq ident \":\" pq ident\n path = ident *((\"[\" \"]\") / (\".\" ident))\n cardinality = 1*(digit / \".\" / \"*\")\n binding = ident pq \"->\" pq path [pq \"(\" ident [\",\" pq cardinality] \")\"] [pq \"preprocess\" \":\" pq ident]\n bindings_section = \"bindings\" pq ident nlws \"{\" [nlws] [binding *(nlws binding)] [nlws] \"}\"\n step = \"table_lookup\" pq ident pq ident pq \"->\" pq ident\n preprocess_section = \"preprocess\" pq ident nlws \"{\" *nlws step nlws \"}\"\n test_line = (\"accept\" / \"reject\" / \"example\") pq dstring [pq \"{\" *nlws test_pair *nlws \"}\"] / comment / doc_marker\n test_pair = ident \":\" pq (dstring / num / (\"true\" / \"false\"))\n test_section = \"test\" [pq ident] nlws \"{\" *nlws [test_line *(nlws test_line)] nlws \"}\"\n rule_line = rule / brace_rule / entry_section / bindings_section / preprocess_section / test_section / custom_line / state_line / glue_line / doc_marker / comment\n edition_decl = \"mode\" pq dstring / \"edition\" pq (num / dstring)\n glue_line = \"glue\" pq ident *(pq ident)\n grammar_block = \"grammar\" pq ident pq \"version\" pq dstring [pq edition_decl] pq \"{\" *(nlws rule_line) *nlws \"}\"\n render_section = \"render\" pq ident nlws \"{\" *(nlws render_seg) nlws \"}\"\n render_seg = (\"field\" pq ident) / (\"literal\" pq dstring) / (\"cond\" pq ident nlws \"{\" *(nlws render_seg) nlws \"}\")\n derive_section = \"derive\" pq ident pq dstring\n top = grammar_block / entry_section / bindings_section / preprocess_section / test_section / render_section / derive_section\n use_line = \"use\" pq ident\n top_item = use_line / doc_marker / comment / top\n\n pg_file = pq *(top_item [nlws]) pq\n\n entry file: pg_file\n\n test {\n accept \"grammar T version \\\"1\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { a = b / c as d }\"\n accept \"grammar T version \\\"1\\\" { g = [x] 3*y !z &w (p / q) }\"\n accept \"grammar T version \\\"1\\\" { k = 1*3(e / f) !(g h) }\"\n accept \"grammar T version \\\"1\\\" { custom lookback = \\\"ParsanolAtoms::Lookbehind\\\" a = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { state block_kind: symbol a = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { a = (set block_kind = \\\"quote\\\") %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { a = (switch block_kind { \\\"quote\\\" -> q _ -> never }) }\"\n accept \"grammar T version \\\"1\\\" { a = (set d = (3*4(%x2D)) %x0A) }\"\n accept \"grammar T version \\\"1\\\" { a = (!(state d) %x61-7A) }\"\n accept \"grammar T version \\\"1\\\" {\\n p = {\\n %i\\\"iso\\\" / %i\\\"ieee\\\"\\n }\\n}\"\n accept \"grammar T version \\\"1\\\" { q = { a b } }\"\n accept \"grammar T version \\\"1\\\" {\\n r =\\n {\\n x as y\\n }\\n}\"\n accept \"grammar T version \\\"1\\\" {\\n s = {\\n # a comment is body whitespace\\n !(t / u) 2*v\\n }\\n}\"\n accept \"grammar T version \\\"1\\\" mode \\\"v1\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" mode \\\"v2\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition 1 { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition 2 { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition \\\"v2\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition 2 {\\n glue ws comment\\n ws = 1*( %x20 )\\n comment = \\\"#\\\" *nonl\\n main = \\\"a\\\" ws \\\"b\\\"\\n}\"\n reject \"grammar T version \\\"1\\\" { q = { a }\"\n reject \"grammar T version \\\"1\\\" { q = { } }\"\n reject \"nonsense\"\n reject \"grammar T version \\\"1\\\" { = }\"\n }\n}\n","source_hash":"a738f893d9e8521a366965a38a3230f9e09b8e120fc79b1b0bbfd21fb2163317","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.121","edition":1,"semantics_hash":"sha256:12c9a95efba271975b4967186623ace463b9b9c635a72c16195b6b2c5c5c50c5","checksum":"sha256:5ddc6e4322906cfaff4023e467769eeb4d12120a5150faaf50b2ae5f7775a003"}
1
+ {"bindings":null,"version":"1.0.0","grammar":"PgMeta","shape":"parsanol-tree/v2","binding_version":1,"entries":{"file":{"root":"pg_file","grammar":{"atoms":[{"Entity":{"atom":5}},{"Entity":{"atom":4}},{"Re":{"pattern":"[ ]"}},{"Re":{"pattern":"[\\x09]"}},{"Alternative":{"atoms":[2,3]}},{"Repetition":{"atom":1,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":591}},{"Entity":{"atom":23}},{"Str":{"pattern":"use"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":21}},{"Entity":{"atom":15}},{"Re":{"pattern":"[\\x41-\\x5a]"}},{"Re":{"pattern":"[\\x61-\\x7a]"}},{"Alternative":{"atoms":[13,14]}},{"Named":{"name":"letter","atom":12}},{"Entity":{"atom":18}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Named":{"name":"digit","atom":17}},{"Re":{"pattern":"[_]"}},{"Alternative":{"atoms":[16,19,20]}},{"Repetition":{"atom":11,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[8,9,10]}},{"Entity":{"atom":32}},{"Str":{"pattern":"##"}},{"Entity":{"atom":29}},{"Re":{"pattern":"[\\x01-\\x09]"}},{"Re":{"pattern":"[\\x0b-\\u{10ffff}]"}},{"Alternative":{"atoms":[27,28]}},{"Named":{"name":"nonl","atom":26}},{"Repetition":{"atom":30,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[25,31]}},{"Entity":{"atom":38}},{"Str":{"pattern":"#"}},{"Entity":{"atom":29}},{"Named":{"name":"nonl","atom":35}},{"Repetition":{"atom":36,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[34,37]}},{"Entity":{"atom":590}},{"Entity":{"atom":538}},{"Str":{"pattern":"grammar"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"version"}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Str":{"pattern":"\""}},{"Str":{"pattern":"\\"}},{"Entity":{"atom":29}},{"Named":{"name":"nonl","atom":50}},{"Sequence":{"atoms":[49,51]}},{"Entity":{"atom":57}},{"Re":{"pattern":"[\\x01-\\x09]"}},{"Re":{"pattern":"[\\x0b-\\x21]"}},{"Re":{"pattern":"[\\x23-\\u{10ffff}]"}},{"Alternative":{"atoms":[54,55,56]}},{"Named":{"name":"str_body_char","atom":53}},{"Alternative":{"atoms":[52,58]}},{"Repetition":{"atom":59,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"\""}},{"Sequence":{"atoms":[48,60,61]}},{"Entity":{"atom":5}},{"Entity":{"atom":78}},{"Str":{"pattern":"mode"}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[65,66,67]}},{"Str":{"pattern":"edition"}},{"Entity":{"atom":5}},{"Entity":{"atom":74}},{"Entity":{"atom":18}},{"Named":{"name":"digit","atom":72}},{"Repetition":{"atom":73,"min":1,"max":null,"tag":"Repetition"}},{"Entity":{"atom":62}},{"Alternative":{"atoms":[71,75]}},{"Sequence":{"atoms":[69,70,76]}},{"Alternative":{"atoms":[68,77]}},{"Sequence":{"atoms":[63,64]}},{"Repetition":{"atom":79,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":5}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Entity":{"atom":4}},{"Entity":{"atom":86}},{"Re":{"pattern":"[\\x0a]"}},{"Alternative":{"atoms":[84,85]}},{"Repetition":{"atom":87,"min":1,"max":null,"tag":"Repetition"}},{"Entity":{"atom":532}},{"Entity":{"atom":271}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":5}},{"Entity":{"atom":270}},{"Entity":{"atom":267}},{"Entity":{"atom":264}},{"Entity":{"atom":5}},{"Entity":{"atom":111}},{"Entity":{"atom":74}},{"Str":{"pattern":"*"}},{"Entity":{"atom":74}},{"Repetition":{"atom":102,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[101,103]}},{"Repetition":{"atom":104,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[100,105]}},{"Str":{"pattern":"*"}},{"Entity":{"atom":74}},{"Repetition":{"atom":108,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[107,109]}},{"Alternative":{"atoms":[106,110]}},{"Entity":{"atom":5}},{"Entity":{"atom":259}},{"Str":{"pattern":"!"}},{"Str":{"pattern":"&"}},{"Alternative":{"atoms":[114,115]}},{"Entity":{"atom":258}},{"Entity":{"atom":257}},{"Entity":{"atom":149}},{"Entity":{"atom":139}},{"Str":{"pattern":"%x"}},{"Entity":{"atom":129}},{"Entity":{"atom":127}},{"Re":{"pattern":"[\\x30-\\x39]"}},{"Re":{"pattern":"[\\x41-\\x46]"}},{"Re":{"pattern":"[\\x61-\\x66]"}},{"Alternative":{"atoms":[124,125,126]}},{"Named":{"name":"hexdig","atom":123}},{"Repetition":{"atom":128,"min":2,"max":6,"tag":"Repetition"}},{"Str":{"pattern":"-"}},{"Entity":{"atom":129}},{"Sequence":{"atoms":[130,131]}},{"Str":{"pattern":"."}},{"Entity":{"atom":129}},{"Sequence":{"atoms":[133,134]}},{"Repetition":{"atom":135,"min":1,"max":null,"tag":"Repetition"}},{"Alternative":{"atoms":[132,136]}},{"Repetition":{"atom":137,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[121,122,138]}},{"Entity":{"atom":143}},{"Str":{"pattern":"%i"}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[141,142]}},{"Entity":{"atom":147}},{"Str":{"pattern":"%s"}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[145,146]}},{"Entity":{"atom":62}},{"Alternative":{"atoms":[120,140,144,148]}},{"Str":{"pattern":"("}},{"Entity":{"atom":5}},{"Repetition":{"atom":151,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":181}},{"Entity":{"atom":5}},{"Str":{"pattern":"/"}},{"Entity":{"atom":5}},{"Entity":{"atom":178}},{"Entity":{"atom":5}},{"Entity":{"atom":175}},{"Entity":{"atom":167}},{"Entity":{"atom":5}},{"Str":{"pattern":"as"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[161,162,163,164]}},{"Repetition":{"atom":165,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[118,166]}},{"Alternative":{"atoms":[113,160]}},{"Repetition":{"atom":168,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[99,112,169]}},{"Entity":{"atom":172}},{"Sequence":{"atoms":[116,117]}},{"Entity":{"atom":167}},{"Alternative":{"atoms":[170,171,173]}},{"Sequence":{"atoms":[98,174]}},{"Sequence":{"atoms":[158,159]}},{"Repetition":{"atom":176,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[97,177]}},{"Sequence":{"atoms":[154,155,156,157]}},{"Repetition":{"atom":179,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[96,180]}},{"Entity":{"atom":5}},{"Repetition":{"atom":182,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[150,152,153,183,184]}},{"Str":{"pattern":"["}},{"Entity":{"atom":5}},{"Repetition":{"atom":187,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":181}},{"Entity":{"atom":5}},{"Repetition":{"atom":190,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"]"}},{"Sequence":{"atoms":[186,188,189,191,192]}},{"Entity":{"atom":204}},{"Str":{"pattern":"alt"}},{"Entity":{"atom":5}},{"Str":{"pattern":"from_table"}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Entity":{"atom":5}},{"Str":{"pattern":"column"}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[195,196,197,198,199,200,201,202,203]}},{"Entity":{"atom":222}},{"Str":{"pattern":"set"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Str":{"pattern":"("}},{"Entity":{"atom":5}},{"Repetition":{"atom":214,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":181}},{"Entity":{"atom":5}},{"Repetition":{"atom":217,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[213,215,216,218,219]}},{"Alternative":{"atoms":[212,220]}},{"Sequence":{"atoms":[206,207,208,209,210,211,221]}},{"Entity":{"atom":255}},{"Str":{"pattern":"switch"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Repetition":{"atom":229,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":245}},{"Entity":{"atom":62}},{"Str":{"pattern":"_"}},{"Alternative":{"atoms":[232,233]}},{"Entity":{"atom":5}},{"Str":{"pattern":"->"}},{"Entity":{"atom":5}},{"Entity":{"atom":244}},{"Entity":{"atom":22}},{"Str":{"pattern":"."}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[240,241]}},{"Repetition":{"atom":242,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[239,243]}},{"Sequence":{"atoms":[234,235,236,237,238]}},{"Entity":{"atom":88}},{"Entity":{"atom":245}},{"Sequence":{"atoms":[246,247]}},{"Repetition":{"atom":248,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[231,249]}},{"Repetition":{"atom":250,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":88}},{"Repetition":{"atom":252,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[224,225,226,227,228,230,251,253,254]}},{"Entity":{"atom":244}},{"Alternative":{"atoms":[119,185,193,194,205,223,256]}},{"Sequence":{"atoms":[118,166]}},{"Sequence":{"atoms":[116,117]}},{"Alternative":{"atoms":[113,160]}},{"Repetition":{"atom":260,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[99,112,261]}},{"Alternative":{"atoms":[262,171,173]}},{"Sequence":{"atoms":[98,263]}},{"Sequence":{"atoms":[158,159]}},{"Repetition":{"atom":265,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[97,266]}},{"Sequence":{"atoms":[154,155,156,157]}},{"Repetition":{"atom":268,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[96,269]}},{"Sequence":{"atoms":[91,92,93,94,95]}},{"Entity":{"atom":363}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":4}},{"Entity":{"atom":86}},{"Alternative":{"atoms":[276,277]}},{"Repetition":{"atom":278,"min":0,"max":null,"tag":"Repetition"}},{"Re":{"pattern":"[{]"}},{"Entity":{"atom":360}},{"Entity":{"atom":357}},{"Entity":{"atom":354}},{"Entity":{"atom":289}},{"Entity":{"atom":4}},{"Entity":{"atom":86}},{"Entity":{"atom":38}},{"Alternative":{"atoms":[285,286,287]}},{"Repetition":{"atom":288,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":111}},{"Entity":{"atom":289}},{"Entity":{"atom":349}},{"Str":{"pattern":"!"}},{"Str":{"pattern":"&"}},{"Alternative":{"atoms":[293,294]}},{"Entity":{"atom":348}},{"Entity":{"atom":347}},{"Entity":{"atom":149}},{"Str":{"pattern":"("}},{"Entity":{"atom":289}},{"Repetition":{"atom":300,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":330}},{"Entity":{"atom":289}},{"Str":{"pattern":"/"}},{"Entity":{"atom":289}},{"Entity":{"atom":327}},{"Entity":{"atom":289}},{"Entity":{"atom":324}},{"Entity":{"atom":316}},{"Entity":{"atom":289}},{"Str":{"pattern":"as"}},{"Entity":{"atom":289}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[310,311,312,313]}},{"Repetition":{"atom":314,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[297,315]}},{"Alternative":{"atoms":[292,309]}},{"Repetition":{"atom":317,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[290,291,318]}},{"Entity":{"atom":321}},{"Sequence":{"atoms":[295,296]}},{"Entity":{"atom":316}},{"Alternative":{"atoms":[319,320,322]}},{"Sequence":{"atoms":[284,323]}},{"Sequence":{"atoms":[307,308]}},{"Repetition":{"atom":325,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[283,326]}},{"Sequence":{"atoms":[303,304,305,306]}},{"Repetition":{"atom":328,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[282,329]}},{"Entity":{"atom":289}},{"Repetition":{"atom":331,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[299,301,302,332,333]}},{"Str":{"pattern":"["}},{"Entity":{"atom":289}},{"Repetition":{"atom":336,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":330}},{"Entity":{"atom":289}},{"Repetition":{"atom":339,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"]"}},{"Sequence":{"atoms":[335,337,338,340,341]}},{"Entity":{"atom":204}},{"Entity":{"atom":222}},{"Entity":{"atom":255}},{"Entity":{"atom":244}},{"Alternative":{"atoms":[298,334,342,343,344,345,346]}},{"Sequence":{"atoms":[297,315]}},{"Sequence":{"atoms":[295,296]}},{"Alternative":{"atoms":[292,309]}},{"Repetition":{"atom":350,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[290,291,351]}},{"Alternative":{"atoms":[352,320,322]}},{"Sequence":{"atoms":[284,353]}},{"Sequence":{"atoms":[307,308]}},{"Repetition":{"atom":355,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[283,356]}},{"Sequence":{"atoms":[303,304,305,306]}},{"Repetition":{"atom":358,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[282,359]}},{"Entity":{"atom":289}},{"Re":{"pattern":"[}]"}},{"Sequence":{"atoms":[273,274,275,279,280,281,361,362]}},{"Entity":{"atom":371}},{"Str":{"pattern":"entry"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[365,366,367,368,369,370]}},{"Entity":{"atom":430}},{"Str":{"pattern":"bindings"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":88}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Repetition":{"atom":378,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":420}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"->"}},{"Entity":{"atom":5}},{"Entity":{"atom":395}},{"Entity":{"atom":22}},{"Str":{"pattern":"["}},{"Str":{"pattern":"]"}},{"Sequence":{"atoms":[387,388]}},{"Str":{"pattern":"."}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[390,391]}},{"Alternative":{"atoms":[389,392]}},{"Repetition":{"atom":393,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[386,394]}},{"Entity":{"atom":5}},{"Str":{"pattern":"("}},{"Entity":{"atom":22}},{"Str":{"pattern":","}},{"Entity":{"atom":5}},{"Entity":{"atom":407}},{"Entity":{"atom":18}},{"Named":{"name":"digit","atom":402}},{"Str":{"pattern":"."}},{"Str":{"pattern":"*"}},{"Alternative":{"atoms":[403,404,405]}},{"Repetition":{"atom":406,"min":1,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[399,400,401]}},{"Repetition":{"atom":408,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":")"}},{"Sequence":{"atoms":[396,397,398,409,410]}},{"Repetition":{"atom":411,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":5}},{"Str":{"pattern":"preprocess"}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[413,414,415,416,417]}},{"Repetition":{"atom":418,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[381,382,383,384,385,412,419]}},{"Entity":{"atom":88}},{"Entity":{"atom":420}},{"Sequence":{"atoms":[421,422]}},{"Repetition":{"atom":423,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[380,424]}},{"Repetition":{"atom":425,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":88}},{"Repetition":{"atom":427,"min":0,"max":1,"tag":"Maybe"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[373,374,375,376,377,379,426,428,429]}},{"Entity":{"atom":452}},{"Str":{"pattern":"preprocess"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":88}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Repetition":{"atom":437,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":449}},{"Str":{"pattern":"table_lookup"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"->"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[440,441,442,443,444,445,446,447,448]}},{"Entity":{"atom":88}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[432,433,434,435,436,438,439,450,451]}},{"Entity":{"atom":502}},{"Str":{"pattern":"test"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[455,456]}},{"Repetition":{"atom":457,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":88}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Repetition":{"atom":461,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":493}},{"Str":{"pattern":"accept"}},{"Str":{"pattern":"reject"}},{"Str":{"pattern":"example"}},{"Alternative":{"atoms":[464,465,466]}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Entity":{"atom":5}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Repetition":{"atom":472,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":484}},{"Entity":{"atom":22}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Entity":{"atom":74}},{"Str":{"pattern":"true"}},{"Str":{"pattern":"false"}},{"Alternative":{"atoms":[480,481]}},{"Alternative":{"atoms":[478,479,482]}},{"Sequence":{"atoms":[475,476,477,483]}},{"Entity":{"atom":88}},{"Repetition":{"atom":485,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[470,471,473,474,486,487]}},{"Repetition":{"atom":488,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[467,468,469,489]}},{"Entity":{"atom":38}},{"Entity":{"atom":32}},{"Alternative":{"atoms":[490,491,492]}},{"Entity":{"atom":88}},{"Entity":{"atom":493}},{"Sequence":{"atoms":[494,495]}},{"Repetition":{"atom":496,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[463,497]}},{"Repetition":{"atom":498,"min":0,"max":1,"tag":"Maybe"}},{"Entity":{"atom":88}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[454,458,459,460,462,499,500,501]}},{"Entity":{"atom":511}},{"Str":{"pattern":"custom"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":"="}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[504,505,506,507,508,509,510]}},{"Entity":{"atom":520}},{"Str":{"pattern":"state"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Str":{"pattern":":"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[513,514,515,516,517,518,519]}},{"Entity":{"atom":529}},{"Str":{"pattern":"glue"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[525,526]}},{"Repetition":{"atom":527,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[522,523,524,528]}},{"Entity":{"atom":32}},{"Entity":{"atom":38}},{"Alternative":{"atoms":[90,272,364,372,431,453,503,512,521,530,531]}},{"Sequence":{"atoms":[83,89]}},{"Repetition":{"atom":533,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":88}},{"Repetition":{"atom":535,"min":0,"max":null,"tag":"Repetition"}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[41,42,43,44,45,46,47,80,81,82,534,536,537]}},{"Entity":{"atom":371}},{"Entity":{"atom":430}},{"Entity":{"atom":452}},{"Entity":{"atom":502}},{"Entity":{"atom":582}},{"Str":{"pattern":"render"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":88}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Entity":{"atom":577}},{"Str":{"pattern":"field"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Sequence":{"atoms":[551,552,553]}},{"Str":{"pattern":"literal"}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[555,556,557]}},{"Str":{"pattern":"cond"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":88}},{"Str":{"pattern":"{"}},{"Entity":{"atom":88}},{"Entity":{"atom":573}},{"Sequence":{"atoms":[551,552,553]}},{"Sequence":{"atoms":[555,556,557]}},{"Sequence":{"atoms":[564,565]}},{"Repetition":{"atom":568,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":88}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[559,560,561,562,563,569,570,571]}},{"Alternative":{"atoms":[566,567,572]}},{"Sequence":{"atoms":[564,565]}},{"Repetition":{"atom":574,"min":0,"max":null,"tag":"Repetition"}},{"Sequence":{"atoms":[559,560,561,562,563,575,570,571]}},{"Alternative":{"atoms":[554,558,576]}},{"Sequence":{"atoms":[549,550]}},{"Repetition":{"atom":578,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":88}},{"Str":{"pattern":"}"}},{"Sequence":{"atoms":[544,545,546,547,548,579,580,581]}},{"Entity":{"atom":589}},{"Str":{"pattern":"derive"}},{"Entity":{"atom":5}},{"Entity":{"atom":22}},{"Entity":{"atom":5}},{"Entity":{"atom":62}},{"Sequence":{"atoms":[584,585,586,587,588]}},{"Alternative":{"atoms":[40,539,540,541,542,543,583]}},{"Alternative":{"atoms":[7,24,33,39]}},{"Entity":{"atom":88}},{"Repetition":{"atom":592,"min":0,"max":1,"tag":"Maybe"}},{"Sequence":{"atoms":[6,593]}},{"Repetition":{"atom":594,"min":0,"max":null,"tag":"Repetition"}},{"Entity":{"atom":5}},{"Sequence":{"atoms":[0,595,596]}}],"root":597},"bindings":[]}},"preprocess":{},"tables":{},"lint":{"order_warnings":["rule nonl: branches 1 and 2 are order-dependent (first set not statically known)","rule str_body_char: branches 1 and 3 are order-dependent (first set not statically known)","rule str_body_char: branches 2 and 3 are order-dependent (first set not statically known)","rule hex: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule hex: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule hex: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 4 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 5 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 5 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule primary: branches 6 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 4 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 5 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 5 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule bprimary: branches 6 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule test_line: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 2 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 4 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 5 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 8 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 1 and 9 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 4 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 5 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 6 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 7 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 8 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 2 and 9 are order-dependent (shared first bytes; ordered choice is decisive)","rule rule_line: branches 10 and 11 are order-dependent (shared first bytes; ordered choice is decisive)","rule top_item: branches 2 and 3 are order-dependent (shared first bytes; ordered choice is decisive)"]},"default_entry":"file","render":{},"derive":{},"tests":[{"entry":"file","kind":"accept","input":"grammar T version \"1\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = b / c as d }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { g = [x] 3*y !z &w (p / q) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { k = 1*3(e / f) !(g h) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { custom lookback = \"ParsanolAtoms::Lookbehind\" a = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { state block_kind: symbol a = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (set block_kind = \"quote\") %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (switch block_kind { \"quote\" -> q _ -> never }) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (set d = (3*4(%x2D)) %x0A) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { a = (!(state d) %x61-7A) }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" {\n p = {\n %i\"iso\" / %i\"ieee\"\n }\n}","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" { q = { a b } }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" {\n r =\n {\n x as y\n }\n}","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" {\n s = {\n # a comment is body whitespace\n !(t / u) 2*v\n }\n}","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" mode \"v1\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" mode \"v2\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition 1 { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition 2 { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition \"v2\" { x = %x30-39 }","expect":{}},{"entry":"file","kind":"accept","input":"grammar T version \"1\" edition 2 {\n glue ws comment\n ws = 1*( %x20 )\n comment = \"#\" *nonl\n main = \"a\" ws \"b\"\n}","expect":{}},{"entry":"file","kind":"reject","input":"grammar T version \"1\" { q = { a }","expect":{}},{"entry":"file","kind":"reject","input":"grammar T version \"1\" { q = { } }","expect":{}},{"entry":"file","kind":"reject","input":"nonsense","expect":{}},{"entry":"file","kind":"reject","input":"grammar T version \"1\" { = }","expect":{}}],"docs":{},"source":"# PG described in PG — the self-description grammar (F10, phase 1).\n# It recognizes the language this file is written in, over raw text:\n# whitespace is threaded explicitly (pq = potential whitespace within a\n# line, nlws = line-breaking whitespace, bw = brace-body whitespace: the\n# b* rules thread it so brace-form rule bodies span lines). The\n# reference compiler remains parsanol-ruby (SSOT, TODO 11); this\n# artifact is the validator — and brace_rule below is itself written in\n# the brace form it recognizes.\n\ngrammar PgMeta version \"1.0.0\" edition 2 {\n\n # ---- lexical ----\n digit = %x30-39\n hexdig = %x30-39 / %x41-46 / %x61-66\n letter = %x41-5A / %x61-7A\n ident_char = letter / digit / %x5F\n ident = 1*ident_char\n newline = %x0A\n nonl = %x01-09 / %x0B-10FFFF\n comment = \"#\" *nonl\n doc_marker = \"##\" *nonl\n ws = %x20 / %x09\n nlws = 1*(ws / newline)\n pq = *ws\n\n # ---- terminals ----\n str_body_char = %x01-09 / %x0B-21 / %x23-10FFFF\n dstring = \"\\\"\" *(\"\\\\\" nonl / str_body_char) \"\\\"\"\n istring = \"%i\" dstring\n sstring = \"%s\" dstring\n hexdigits = 2*6hexdig\n hexlit = \"%x\" hexdigits [(\"-\" hexdigits) / 1*(\".\" hexdigits)]\n hex = hexlit / istring / sstring / dstring\n\n # ---- expressions (pq-threaded) ----\n choice = seq *(pq \"/\" pq seq)\n seq = element *(pq element)\n element = pq (rep_prefix pq [pred / postfixed] / pred / postfixed)\n rep_prefix = num [\"*\" [num]] / \"*\" [num]\n num = 1*digit\n pred = (\"!\" / \"&\") postfixed\n postfixed = primary [pq \"as\" pq ident]\n table_alt = \"alt\" pq \"from_table\" pq dstring pq \"column\" pq dstring\n set_expr = \"set\" pq ident pq \"=\" pq (dstring / \"(\" [pq] choice [pq] \")\")\n switch_arm = (dstring / \"_\") pq \"->\" pq dotted_ident\n switch_expr = \"switch\" pq ident pq \"{\" *nlws [switch_arm *(nlws switch_arm)] *nlws \"}\"\n custom_line = \"custom\" pq ident pq \"=\" pq dstring\n state_line = \"state\" pq ident pq \":\" pq ident\n dotted_ident = ident *(\".\" ident)\n primary = hex / \"(\" [pq] choice [pq] \")\" / \"[\" [pq] choice [pq] \"]\" / table_alt / set_expr / switch_expr / dotted_ident\n\n # ---- brace-body expressions (bw-threaded: newlines are whitespace) ----\n bw = *(ws / newline / comment)\n bchoice = bseq *(bw \"/\" bw bseq)\n bseq = belement *(bw belement)\n belement = bw (rep_prefix bw [bpred / bpostfixed] / bpred / bpostfixed)\n bpred = (\"!\" / \"&\") bpostfixed\n bprimary = hex / \"(\" [bw] bchoice [bw] \")\" / \"[\" [bw] bchoice [bw] \"]\" / table_alt / set_expr / switch_expr / dotted_ident\n bpostfixed = bprimary [bw \"as\" bw ident]\n\n # ---- rules and sections ----\n rule = ident pq \"=\" pq choice\n brace_rule = {\n ident pq \"=\" *(ws / newline) %x7B\n bchoice bw %x7D\n }\n entry_section = \"entry\" pq ident \":\" pq ident\n path = ident *((\"[\" \"]\") / (\".\" ident))\n cardinality = 1*(digit / \".\" / \"*\")\n binding = ident pq \"->\" pq path [pq \"(\" ident [\",\" pq cardinality] \")\"] [pq \"preprocess\" \":\" pq ident]\n bindings_section = \"bindings\" pq ident nlws \"{\" [nlws] [binding *(nlws binding)] [nlws] \"}\"\n step = \"table_lookup\" pq ident pq ident pq \"->\" pq ident\n preprocess_section = \"preprocess\" pq ident nlws \"{\" *nlws step nlws \"}\"\n test_line = (\"accept\" / \"reject\" / \"example\") pq dstring [pq \"{\" *nlws test_pair *nlws \"}\"] / comment / doc_marker\n test_pair = ident \":\" pq (dstring / num / (\"true\" / \"false\"))\n test_section = \"test\" [pq ident] nlws \"{\" *nlws [test_line *(nlws test_line)] nlws \"}\"\n rule_line = rule / brace_rule / entry_section / bindings_section / preprocess_section / test_section / custom_line / state_line / glue_line / doc_marker / comment\n edition_decl = \"mode\" pq dstring / \"edition\" pq (num / dstring)\n glue_line = \"glue\" pq ident *(pq ident)\n grammar_block = \"grammar\" pq ident pq \"version\" pq dstring [pq edition_decl] pq \"{\" *(nlws rule_line) *nlws \"}\"\n render_section = \"render\" pq ident nlws \"{\" *(nlws render_seg) nlws \"}\"\n render_seg = (\"field\" pq ident) / (\"literal\" pq dstring) / (\"cond\" pq ident nlws \"{\" *(nlws render_seg) nlws \"}\")\n derive_section = \"derive\" pq ident pq dstring\n top = grammar_block / entry_section / bindings_section / preprocess_section / test_section / render_section / derive_section\n use_line = \"use\" pq ident\n top_item = use_line / doc_marker / comment / top\n\n pg_file = pq *(top_item [nlws]) pq\n\n entry file: pg_file\n\n test {\n accept \"grammar T version \\\"1\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { a = b / c as d }\"\n accept \"grammar T version \\\"1\\\" { g = [x] 3*y !z &w (p / q) }\"\n accept \"grammar T version \\\"1\\\" { k = 1*3(e / f) !(g h) }\"\n accept \"grammar T version \\\"1\\\" { custom lookback = \\\"ParsanolAtoms::Lookbehind\\\" a = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { state block_kind: symbol a = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { a = (set block_kind = \\\"quote\\\") %x30-39 }\"\n accept \"grammar T version \\\"1\\\" { a = (switch block_kind { \\\"quote\\\" -> q _ -> never }) }\"\n accept \"grammar T version \\\"1\\\" { a = (set d = (3*4(%x2D)) %x0A) }\"\n accept \"grammar T version \\\"1\\\" { a = (!(state d) %x61-7A) }\"\n accept \"grammar T version \\\"1\\\" {\\n p = {\\n %i\\\"iso\\\" / %i\\\"ieee\\\"\\n }\\n}\"\n accept \"grammar T version \\\"1\\\" { q = { a b } }\"\n accept \"grammar T version \\\"1\\\" {\\n r =\\n {\\n x as y\\n }\\n}\"\n accept \"grammar T version \\\"1\\\" {\\n s = {\\n # a comment is body whitespace\\n !(t / u) 2*v\\n }\\n}\"\n accept \"grammar T version \\\"1\\\" mode \\\"v1\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" mode \\\"v2\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition 1 { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition 2 { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition \\\"v2\\\" { x = %x30-39 }\"\n accept \"grammar T version \\\"1\\\" edition 2 {\\n glue ws comment\\n ws = 1*( %x20 )\\n comment = \\\"#\\\" *nonl\\n main = \\\"a\\\" ws \\\"b\\\"\\n}\"\n reject \"grammar T version \\\"1\\\" { q = { a }\"\n reject \"grammar T version \\\"1\\\" { q = { } }\"\n reject \"nonsense\"\n reject \"grammar T version \\\"1\\\" { = }\"\n }\n}\n","source_hash":"4ff02e95155a1784f722f413ff98913800d571622ddeff37b56fc53c51188644","unicode_tables":"onigmo (Ruby 3.4.8)","compiler_version":"1.3.126","edition":2,"semantics_hash":"sha256:0d41b8456d396150de6c860f2b0fd53ed8dc7299ca30a62910c8e8565905709f","checksum":"sha256:acd4d7e293d3879091d30bc8a0d987b4b0e99baac82d68af3f95ee68e8420848"}
@@ -0,0 +1,118 @@
1
+ # PG described in PG — the self-description grammar (F10, phase 1).
2
+ # It recognizes the language this file is written in, over raw text:
3
+ # whitespace is threaded explicitly (pq = potential whitespace within a
4
+ # line, nlws = line-breaking whitespace, bw = brace-body whitespace: the
5
+ # b* rules thread it so brace-form rule bodies span lines). The
6
+ # reference compiler remains parsanol-ruby (SSOT, TODO 11); this
7
+ # artifact is the validator — and brace_rule below is itself written in
8
+ # the brace form it recognizes.
9
+
10
+ grammar PgMeta version "1.0.0" edition 2 {
11
+
12
+ # ---- lexical ----
13
+ digit = %x30-39
14
+ hexdig = %x30-39 / %x41-46 / %x61-66
15
+ letter = %x41-5A / %x61-7A
16
+ ident_char = letter / digit / %x5F
17
+ ident = 1*ident_char
18
+ newline = %x0A
19
+ nonl = %x01-09 / %x0B-10FFFF
20
+ comment = "#" *nonl
21
+ doc_marker = "##" *nonl
22
+ ws = %x20 / %x09
23
+ nlws = 1*(ws / newline)
24
+ pq = *ws
25
+
26
+ # ---- terminals ----
27
+ str_body_char = %x01-09 / %x0B-21 / %x23-10FFFF
28
+ dstring = "\"" *("\\" nonl / str_body_char) "\""
29
+ istring = "%i" dstring
30
+ sstring = "%s" dstring
31
+ hexdigits = 2*6hexdig
32
+ hexlit = "%x" hexdigits [("-" hexdigits) / 1*("." hexdigits)]
33
+ hex = hexlit / istring / sstring / dstring
34
+
35
+ # ---- expressions (pq-threaded) ----
36
+ choice = seq *(pq "/" pq seq)
37
+ seq = element *(pq element)
38
+ element = pq (rep_prefix pq [pred / postfixed] / pred / postfixed)
39
+ rep_prefix = num ["*" [num]] / "*" [num]
40
+ num = 1*digit
41
+ pred = ("!" / "&") postfixed
42
+ postfixed = primary [pq "as" pq ident]
43
+ table_alt = "alt" pq "from_table" pq dstring pq "column" pq dstring
44
+ set_expr = "set" pq ident pq "=" pq (dstring / "(" [pq] choice [pq] ")")
45
+ switch_arm = (dstring / "_") pq "->" pq dotted_ident
46
+ switch_expr = "switch" pq ident pq "{" *nlws [switch_arm *(nlws switch_arm)] *nlws "}"
47
+ custom_line = "custom" pq ident pq "=" pq dstring
48
+ state_line = "state" pq ident pq ":" pq ident
49
+ dotted_ident = ident *("." ident)
50
+ primary = hex / "(" [pq] choice [pq] ")" / "[" [pq] choice [pq] "]" / table_alt / set_expr / switch_expr / dotted_ident
51
+
52
+ # ---- brace-body expressions (bw-threaded: newlines are whitespace) ----
53
+ bw = *(ws / newline / comment)
54
+ bchoice = bseq *(bw "/" bw bseq)
55
+ bseq = belement *(bw belement)
56
+ belement = bw (rep_prefix bw [bpred / bpostfixed] / bpred / bpostfixed)
57
+ bpred = ("!" / "&") bpostfixed
58
+ bprimary = hex / "(" [bw] bchoice [bw] ")" / "[" [bw] bchoice [bw] "]" / table_alt / set_expr / switch_expr / dotted_ident
59
+ bpostfixed = bprimary [bw "as" bw ident]
60
+
61
+ # ---- rules and sections ----
62
+ rule = ident pq "=" pq choice
63
+ brace_rule = {
64
+ ident pq "=" *(ws / newline) %x7B
65
+ bchoice bw %x7D
66
+ }
67
+ entry_section = "entry" pq ident ":" pq ident
68
+ path = ident *(("[" "]") / ("." ident))
69
+ cardinality = 1*(digit / "." / "*")
70
+ binding = ident pq "->" pq path [pq "(" ident ["," pq cardinality] ")"] [pq "preprocess" ":" pq ident]
71
+ bindings_section = "bindings" pq ident nlws "{" [nlws] [binding *(nlws binding)] [nlws] "}"
72
+ step = "table_lookup" pq ident pq ident pq "->" pq ident
73
+ preprocess_section = "preprocess" pq ident nlws "{" *nlws step nlws "}"
74
+ test_line = ("accept" / "reject" / "example") pq dstring [pq "{" *nlws test_pair *nlws "}"] / comment / doc_marker
75
+ test_pair = ident ":" pq (dstring / num / ("true" / "false"))
76
+ test_section = "test" [pq ident] nlws "{" *nlws [test_line *(nlws test_line)] nlws "}"
77
+ rule_line = rule / brace_rule / entry_section / bindings_section / preprocess_section / test_section / custom_line / state_line / glue_line / doc_marker / comment
78
+ edition_decl = "mode" pq dstring / "edition" pq (num / dstring)
79
+ glue_line = "glue" pq ident *(pq ident)
80
+ grammar_block = "grammar" pq ident pq "version" pq dstring [pq edition_decl] pq "{" *(nlws rule_line) *nlws "}"
81
+ render_section = "render" pq ident nlws "{" *(nlws render_seg) nlws "}"
82
+ render_seg = ("field" pq ident) / ("literal" pq dstring) / ("cond" pq ident nlws "{" *(nlws render_seg) nlws "}")
83
+ derive_section = "derive" pq ident pq dstring
84
+ top = grammar_block / entry_section / bindings_section / preprocess_section / test_section / render_section / derive_section
85
+ use_line = "use" pq ident
86
+ top_item = use_line / doc_marker / comment / top
87
+
88
+ pg_file = pq *(top_item [nlws]) pq
89
+
90
+ entry file: pg_file
91
+
92
+ test {
93
+ accept "grammar T version \"1\" { x = %x30-39 }"
94
+ accept "grammar T version \"1\" { a = b / c as d }"
95
+ accept "grammar T version \"1\" { g = [x] 3*y !z &w (p / q) }"
96
+ accept "grammar T version \"1\" { k = 1*3(e / f) !(g h) }"
97
+ accept "grammar T version \"1\" { custom lookback = \"ParsanolAtoms::Lookbehind\" a = %x30-39 }"
98
+ accept "grammar T version \"1\" { state block_kind: symbol a = %x30-39 }"
99
+ accept "grammar T version \"1\" { a = (set block_kind = \"quote\") %x30-39 }"
100
+ accept "grammar T version \"1\" { a = (switch block_kind { \"quote\" -> q _ -> never }) }"
101
+ accept "grammar T version \"1\" { a = (set d = (3*4(%x2D)) %x0A) }"
102
+ accept "grammar T version \"1\" { a = (!(state d) %x61-7A) }"
103
+ accept "grammar T version \"1\" {\n p = {\n %i\"iso\" / %i\"ieee\"\n }\n}"
104
+ accept "grammar T version \"1\" { q = { a b } }"
105
+ accept "grammar T version \"1\" {\n r =\n {\n x as y\n }\n}"
106
+ accept "grammar T version \"1\" {\n s = {\n # a comment is body whitespace\n !(t / u) 2*v\n }\n}"
107
+ accept "grammar T version \"1\" mode \"v1\" { x = %x30-39 }"
108
+ accept "grammar T version \"1\" mode \"v2\" { x = %x30-39 }"
109
+ accept "grammar T version \"1\" edition 1 { x = %x30-39 }"
110
+ accept "grammar T version \"1\" edition 2 { x = %x30-39 }"
111
+ accept "grammar T version \"1\" edition \"v2\" { x = %x30-39 }"
112
+ accept "grammar T version \"1\" edition 2 {\n glue ws comment\n ws = 1*( %x20 )\n comment = \"#\" *nonl\n main = \"a\" ws \"b\"\n}"
113
+ reject "grammar T version \"1\" { q = { a }"
114
+ reject "grammar T version \"1\" { q = { } }"
115
+ reject "nonsense"
116
+ reject "grammar T version \"1\" { = }"
117
+ }
118
+ }
@@ -9,3 +9,5 @@ These notes were part of the root `CLAUDE.md`. Read them before you change `lib/
9
9
  - **BIPM index key (`root.number`) + MR slug**: relaton-index narrows on `id.root.number.to_s` (`Relaton::Index::Type#get_id_number` → `bsearch_left`/`bsearch_right`), and the same `number` feeds `to_mr_string`/`to_slug`, which consumers use as an output **filename**. `Pubid::Bipm::Builder` used to set `number` only in `build_committee`/`build_meeting`/`build_guide`, so **6,213 of the 7,922 published `relaton-data-bipm` index-v2 rows (78%) shared the empty key `""`** and the binary search silently degenerated to a linear scan. The four number-less builders now derive one: **Metrologia → the volume** (`Metrologia 55 1A 06007` → `"55"`), **SI Brochure → `edition`** for the brochure and **`variant`** for the derived products (`"9e"`, `"Appendix 3"`, `"Concise"`, `"FAQ"`), **MEP → `mep_code || report_code`** (`"S1"`, `"KUPRTM"`, `"BIPM-2019/05"`). The Metrologia key is deliberately the **coarse, clustering** one (all articles of a volume share a bucket — 61 buckets, median 81), matching the IETF draft-slug and IANA registry-slug convention; **per-article distinctness comes from the MR string, not from `number`**. Two groups stay `number`-less **on purpose** (7 rows of 7,922, so 99.91% coverage): the ordinal-less committee declarations (`CGPM DECL (1889)`, upstream `1889-00.yaml`) and the journal-level `Metrologia` record — filling them would move `urn:bipm:cgpm:decl::1889`'s documented **empty number segment**; both are pinned by `spec/pubid/bipm/root_number_spec.rb` so the gap stays visible. **`number` is not stored twice where it would merely duplicate another key.** A Metrologia article's `volume` is a **derived reader** (`def volume; number&.to_i; end` on the `MetrologiaArticle` leaf), not an attribute — the IANA `registry` / IETF `series` pattern. That one case is essentially the whole duplication: 6,204 of the 6,206 published rows carrying a derived `number` are articles, so the change shrinks the serialized ids by **9.6%** and was verified to reproduce the published Integer `volume` for all 6,205 article rows. It is safe as a plain method only because `volume` is no longer a lutaml attribute **anywhere** in the hierarchy (a method shadowing a generated accessor corrupts attribute resolution). `:volume` stays listed in `NUMBER_SOURCE_ATTRIBUTES` — the base `#exclude` loop skips a non-attribute name, but `exclude(:volume)` must still clear the key it derives from. **`edition`/`variant` and `mep_code`/`report_code` DO stay**, and that is not an oversight: each pair shares one class, so the renderer needs to know *which* of the two a value is (`9e v3.01 (2019/2024, E)` vs `Concise`; `SI MEP S1` vs `Rapport BIPM-2019/05`). Deriving those would trade a duplicated key for a subtler discriminator rule across 5 corpus rows. The redundancy is **one-way, unlike the IEEE `CodeNumber` mixin** it superficially resembles: `Builder` is the **constructor of record**, and nothing rebuilds `number` afterwards — so `MetrologiaArticle.new(volume: 51, …)` has an empty key, and a legacy pre-`number` row deserializes with `number` nil (lutaml assigns attributes *after* `initialize`, so an `initialize` hook would not heal it either — and worse, `#exclude` rebuilds through `self.class.new`, so such a hook would silently re-fill a `number` the caller just excluded). What **is** handled is the exclusion direction: `NUMBER_SOURCE_ATTRIBUTES` (`volume edition variant mep_code report_code`) drives `#exclude` to clear `number` whenever the attribute it derives from is excluded — the "reset the WHOLE cluster" lesson recorded for CSA's year and IEEE's year/month/day. **Nothing about rendering changed**: no renderer or URN branch reads `number` for these families, verified by a corpus diff — `to_s` and `to_urn` are byte-identical before/after for all 7,920 parseable ids. **MR**: BIPM had **no** `mr_*` override at all and inherits none of the base hooks usefully — it keeps its publisher in the `PUBLISHER` constant (so `mr_publisher` was nil), its year in an `:integer` (not a `Components::Date`, so `mr_year` was nil), its edition in a `:string` (not a `Components::Edition`, so the base `mr_edition`'s `edition.number` **raised `NoMethodError`** on every SI Brochure) and its own `type_code` (not a `typed_stage`, so `mr_type` was nil). Result: 90 fixture ids collapsed onto **21** slugs, `""` for 41 of them. The base now overrides those four plus `mr_type`, and adds an `mr_slug(*parts)` helper; each **leaf** supplies `mr_type` + `mr_number_with_part`. `mr_slug` sanitizes **by charset** (`gsub(/[^a-z0-9]+/, "-")`), not by an enumerated escape list, so a field added later cannot leak an unsafe character — BIPM needs three today: a `/` (the MEP report code `BIPM-2019/05`), a space (the SI Brochure variant `Appendix 3`) and a **`.`** (the brochure version `v3.01`). The dot matters beyond filename safety: `Renderers::MrString` joins **segments** with `.`, so a dot inside one would break the documented segment structure (hence `bipm.si-brochure.9e-v3-01.e`, not `…9e-v3.01.e`). Caveat pinned in the code: `-` is both the intra-segment join and the substitute, which is unambiguous only because no field feeding `mr_slug` admits a `-` today (`number`'s own internal `-` in `10-1` is safe because the `group` before it cannot contain one). The **group is load-bearing in the number segment** for CommitteeDocument/Meeting/Guide (`CCTF REC 2` vs `CCEM REC 2`; the 17th CGPM vs the 17th CIPM meeting; `CCL-GD-MeP-1` vs `CCEM-GD-RSI-1` — the guide sequence restarts per committee, so both carry number `"1"`). Verified over the corpus: **7,920 distinct slugs for 7,920 ids, zero collisions, zero non-filename-safe slugs.** Three **deliberate collapses**, pinned by `spec/pubid/bipm/mr_string_spec.rb`: `form` (short vs long committee spelling) and the MEP/Guide `appendix`/`annex`/`part` full-content tail are omitted, because MR is a canonical *document* slug and the URN already collapses them; `language` **is** kept, because the E and F records are distinct files upstream. **Watch out**: the long French spelling is *not* merely another rendering — `Builder#build_committee`/`build_meeting` record it as `language: "F"`, so `Résolution 1 de la CGPM (1927)` names the **French record** and correctly differs from the language-neutral `CGPM RES 1 (1927)`; only a same-language pair collapses. **Note on the determinism landmine**: BIPM declares `attribute :number, :string` on the **shared** `Pubid::Bipm::Identifier` (the IHO/JIS/GOST pattern), not on the leaves as IEEE/IETF/IANA/CIE do — it predates that lesson and is unchanged here, so `spec/pubid/bipm/root_number_spec.rb` carries the structural tripwire (the base *and* all six leaves must resolve `number` to `Lutaml::Model::Type::String`) and **is only meaningful under the full `bundle exec rake`**. **relaton note**: `relaton-data-bipm` must regenerate `index-v2.yaml` to gain the key (and to drop the now-unstored `volume`; `Relaton::Bipm::Bibliography#id_hash` reads `pubid.volume`, which the derived reader keeps working unchanged). A pre-`number` row degrades **silently, not loudly** — lutaml ignores unknown keys and `Relaton::Index::FileIO#id_supported?` skips its round-trip check for concrete subclasses (every BIPM id is a leaf) — so no `require_number!`-style raise is added (rendering does not depend on `number`, and `CGPM DECL` is legitimately number-less). `Relaton::Bipm::Bibliography#get_bipm` also still calls the **block** form `index.search { |r| … }`, which passes `id = nil` and skips `candidates_by_number` entirely, so nothing narrows until it adopts the id form.
10
10
 
11
11
  - **BIPM loose consumer forms (retiring `Relaton::Bipm::Id`)**: `Relaton::Bipm::Bibliography` could not use pubid as its **query** parser — it kept a bespoke regex grammar (`Relaton::Bipm::Id`) because `Pubid::Bipm.parse` rejected the spellings real references use. The grammar now accepts them, so relaton can match pubid-to-pubid like every other flavor. **All of these are NORMALIZING parses — the identifier renders back in BIPM's canonical spelling, never the input** — which is the whole point (a loose query must produce an identifier equal to the index row's), and which is exactly why they must **never** go into the byte-exact `spec/fixtures/bipm/identifiers/pass/` (the `CIPM/2005-06(REV)` precedent); their expectations live in `spec/pubid/bipm/loose_consumer_forms_spec.rb`. Six constructs: **(1) Meeting word order** — `meeting_en` gained a `<group> Meeting <n>` branch and `meeting_fr` gained a plain-`e` ordinal branch (`CIPM 111e Réunion (2022)`) and a `<group> Réunion <n>` branch, all normalizing to `CCTF 14th Meeting (1999)` / `CIPM 111<sup>e</sup> réunion (2022)`. **(2) `committee_group_fr`** — a French type name in the English (group-leading) word order (`CIPM Décision 101-1 (2012)` → `Décision 101-1 du CIPM (2012)`). Its slot in `group_leading` is **after `committee_long_en`**, which is load-bearing: `Action` and `Statement` are in *both* `TYPE_NAME_EN` and `TYPE_NAME_FR`, so the English rule must claim them first or `CIPM Action 5 (2010)` would flip to French. Like the existing French rules it sets `language: "F"` — information the user typed, which a consumer can always widen away but could never recover. **(3) `GROUP_ALIASES`** (`CCDS`→`CCTF`) and **(4) `LANGUAGE_ALIASES`** (`EN`→`E`, `FR`→`F`, longest-first in the `lang` rule so `EN` is never read as a bare `E`): both are resolved in the **builder**, so an alias never reaches an attribute and the index stores only the current name and the one-letter code. `PARSEABLE_GROUPS` (= `GROUPS + GROUP_ALIASES.keys`) is what the `group` rule alternates over; `GROUPS` itself is unchanged, so nothing else sees the alias. **(5) `si_brochure_section`** — the bare `SI Brochure` and `SI Brochure Part 1`. Neither names an edition, so **both are partial references with a nil `number`** that wildcard every edition (the date-less `CCTF REC 2` reading). `Part N` points at a section *inside* the brochure — there is no `si-brochure-part-1.yaml` upstream and relaton's `Id` deletes `:part` before comparing — so it rides in the shared `part` attribute and stays **out** of the index key, exactly as the MEP/guide `Part N.M` tail does. **A Parslet fact worth recording, because it contradicts what several comments in this repo imply**: Parslet threads `consume_all` down through an alternation, so an alternative matching only a **prefix** counts as a failure and the next one is tried — verified by reordering. `si_brochure_section` therefore cannot truncate `SI Brochure Concise` whatever its slot, and `committee_bare` could not shadow a typed form even if it came first. Alternation order decides **only** between two alternatives that both consume the *whole* input — which is exactly the `committee_long_en`-before-`committee_group_fr` case above, and the only ordering here that is genuinely load-bearing (verified: flipping it renders `CIPM Action 5 (2010)` as the French `Action 5 du CIPM (2010)`, a different record). The `BIPM ` prefix was also made **optional on the main `si_brochure` rule** (it already was on the variant rule): `si-brochure.yaml` stores its docnumber *without* it, and `Relaton::Bipm::Bibliography.search` strips a leading `BIPM ` before pubid ever sees the string — so `SI Brochure 9e v3.01 (2019/2024, E)` used to be a hard parse failure. **(6) `TYPE_WORD_ALIASES`** — a **data-corruption fix**: `Declaration`/`Déclaration` were in the `type_name_en`/`type_name_fr` alternations but **not** in `TYPE_WORD_TO_CODE` (which is built from `TYPE_NAME_EN`/`TYPE_NAME_FR`, where DECL's name is `Statement` in both languages), so `CGPM Declaration 1 (1971)` parsed with `type_code` **nil** and rendered as the corrupt `"CGPM 1 (1971)"` (double space), `Déclaration 1 du CGPM (1971)` as `" 1 de la CGPM (1971)"`. Both now map to DECL and render `Statement`. **The matching contract relaton needs** (pinned by the spec against real `index-v2` rows): committee-document and meeting rows are stored **language- and form-neutral** — verified, all 1348 + 367 — so the BIPM stem is **`pubid.exclude(:language, :form)`**, and every loose form reduces under it to the identifier rebuilt from its row. The SI Brochure is the exception: a nil-`edition` query must match *any* `SiBrochure` row, which is what `Id#id_hash`'s `{group: "SI", type: "Brochure"}` collapse already meant. **Also fixed here**: `UrnParser#build_metrologia`/`#build_si_brochure` never set the derived `number`, so a URN round-trip silently emptied the relaton index key (the shared `"flavor URN round-trip"` example only compares `to_urn`, so it was invisible) — now set from the same source the builder uses, guarded by a `presence` helper because an unfilled URN segment is `""`, not nil. **Verified**: all 7,922 published `relaton-data-bipm` rows re-parse from their own `to_s` with an identical hash, class and MR slug (0 mismatches, 0 MR collisions), and all 90 pass fixtures stay byte-exact. **Deliberately NOT changed:** `CCTF Recommendation 2009-02` still reads as the literal number `2009-02` while the index keys that document under `2` — genuinely ambiguous, since `NNNN-NN` is a real BIPM number form (`CIPM 2005-06`), so the consumer keeps a fallback. **Known pre-existing gap, deliberately untouched:** the SI Brochure URN carries only language/edition/version/years, so `Concise`, `FAQ` and `Appendix 3` — three distinct documents — already share `urn:bipm:si-brochure::::`, and the new bare/section forms join that bucket (defensibly, being partial references rather than distinct documents). Fixing it needs a URN-shape decision plus a matching `UrnParser` branch. `Pubid.parse` auto-routing does not resolve **any** BIPM form today (also pre-existing), so `PREFIXES` was left alone — adding `CCDS` there would change nothing observable. (hand-off: bipm-loose-consumer-forms; consumer follow-up: relaton__relaton__bipm-drop-id-parser-for-pubid.)
12
+
13
+ - **Routing reaches BIPM (`Pubid.parse`, pubid#644)**: the note above says "`Pubid.parse` auto-routing does not resolve **any** BIPM form today … so `PREFIXES` was left alone" — that is no longer true, in two halves. **(1) `PREFIXES` gained the two SI-family series tokens** `SI Brochure` and `SI MEP`: both lead real printed references on their own (`SI Brochure 9e v3.01 (2019/2024, E)` — the spelling relaton's `Bibliography#search` strips the `BIPM ` off, per the note above — and `SI MEP 10`), and before this both parsed **directly** but the router could not route them (no prefix owner ⇒ no non-exact fallback). "Rapport" stays excluded per the ambiguous-token policy (generic French word). **(2) The quoted-title form** `BIPM "The International System of Units"` — the brochure IS titled that — is mapped onto the parseable `BIPM SI Brochure` section form by **`data/bipm/update_codes.yaml`** (the CIPM-MRA precedent), so it parses as a **partial reference** that wildcards every edition, exactly like `SI Brochure Part 1`; the bare `"The International System of Units"` maps to `SI Brochure`. Both are normalizing parses and live with the loose-forms expectations, never in the byte-exact fixtures. The **French title is deliberately not mapped**: it names the F-language record specifically, and mapping it would silently drop typed language information (the loose-forms rule above). Also note the router's prefix-owner mechanism is what makes the normalizing parses routable: `Pubid::Bipm.parse("BIPM SI Brochure")` happens to round-trip exactly, but `SI Brochure 9e …` renders with the leading `BIPM ` the input lacked — without prefix-owner status the router would reject it. (hand-off: router-printed-forms-644.)
data/lib/pubid/bipm.rb CHANGED
@@ -6,13 +6,19 @@ module Pubid
6
6
  extend Pubid::PrefixesSupport
7
7
 
8
8
  # Leading tokens a printed BIPM identifier can start with: the 13 committee
9
- # acronyms, "Metrologia" (journal), and "BIPM" (the SI Brochure). JCGM is
10
- # deliberately excluded — it is owned by the separate Pubid::Jcgm flavor,
11
- # so BIPM never emits pubid:jcgm:* rows. French full-name forms that lead
12
- # with a type word ("Recommandation 1 du CCL …") are omitted per the
9
+ # acronyms, "Metrologia" (journal), "BIPM" (the publisher prefix the SI
10
+ # Brochure / MEP / guide families print), and the two SI-family series
11
+ # tokens that can lead a reference on their own — "SI Brochure 9e …" and
12
+ # "SI MEP 10" are printed without the leading BIPM by consumers that strip
13
+ # it (relaton's Bibliography#search among them), so both spellings must
14
+ # route. JCGM is deliberately excluded — it is owned by the separate
15
+ # Pubid::Jcgm flavor, so BIPM never emits pubid:jcgm:* rows. French
16
+ # full-name forms that lead with a type word ("Recommandation 1 du CCL …")
17
+ # and the generic French word "Rapport" are omitted per the
13
18
  # "exclude ambiguous tokens" policy.
14
19
  PREFIXES = %w[
15
20
  BIPM Metrologia
21
+ SI\ Brochure SI\ MEP
16
22
  CIPM CGPM JCRB CCTF CCQM CCT CCL CCAUV CCU CCM CCEM CCPR CCRI
17
23
  ].freeze
18
24
 
@@ -91,3 +91,7 @@ The general fix (`metanorma__pubid__exclude-recursion-depth` hand-off) promotes
91
91
  Verified: `spec/pubid/supplement_date_attributes_spec.rb` exercises the mechanism directly; `spec/pubid/bsi/parse_gaps_spec.rb`, `match_primitives_spec.rb` and `adoption_base_spec.rb`, and `spec/pubid/cen_cenelec/relaton_blockers_spec.rb`'s 10 pinned `:supplement_year` cases, all pass unchanged. Because the new logic only fires when `supplement_date_attributes` is non-empty, every other flavor (including ISO/IEC, which deliberately keep a supplement's year in `date` with no protection — see `lib/pubid/cen_cenelec/CLAUDE.md`) is untouched.
92
92
 
93
93
  **Open question, not resolved here: `#dated_version_of?`/`#draft_of?` on a bare BSI supplement.** Both compare `exclude(:date, :year[, …])`, which — like every other bare `:date`/`:year` exclusion — now protects a supplement's own date unless `:supplement_year` is also passed. Two standalone `BS 7273-4:2015+A1:2021`/`...+A1:2022` objects were `dated_version_of?` each other before this branch (BSI's old `year`-attribute dodge never protected against `exclude(:year)`) and are not after. **Whether that's the right answer is genuinely unclear and deliberately left open pending feedback** — one reading is that this just makes BSI consistent with CEN/CENELEC, which already behaved this way before this branch (its pre-existing per-flavor `#exclude` override had the same protection); the other is that these two generic relational predicates should be widened to accept a `:supplement_year`-aware exclusion set so they can still recognize two differently-dated editions of the *same supplement* as related. (The predicates switched from `matches?(other, ignore: …)` to the equivalent `exclude(…)` comparison so NIST's asymmetric `#matches?` override no longer breaks them; BSI behavior is unchanged.) Locked (as current behavior, not as a verdict) by `spec/pubid/supplement_date_attributes_spec.rb`.
94
+
95
+ ## The `BSI `-prefixed spelling of the BS series parses (pubid#644)
96
+
97
+ `BSI BS 5950` used to be a hard parse failure: the strip in `Pubid::Bsi::Identifier.parse` (`strip_bsi_prefix`) only dropped the `BSI ` prefix before PAS/PD/DD/BIP (`BSI_PREFIXED_SERIES`), and `BS` was deliberately absent because **BSI never prints `BSI` in front of its own BS series**. That remains true of the **render** — `to_s(with_publisher: true)` still answers `BS 5950` for a British Standard, and the `BSI` prefix is re-added only for `BSI_PREFIXED_SERIES` — but **external references do cite the series as `BSI BS 5950`**, so the prefixed spelling is now accepted on **parse**: `STRIPPABLE_SERIES = BSI_PREFIXED_SERIES + ["BS"]` drives the strip, and the input normalizes to the canonical `BS 5950` (a normalizing parse — never a byte-exact fixture). Two lists, one line apart, because the parse and render halves of the same question legitimately differ: `BSI_PREFIXED_SERIES` answers "which series does BSI *print* its publisher in front of", `STRIPPABLE_SERIES` answers "which series does an *external* citation print it in front of". Locked by `spec/pubid/router_printed_forms_spec.rb` (routing + canonical render + stable reparse).
@@ -37,7 +37,16 @@ module Pubid
37
37
  # itself and is never preceded by it.
38
38
  BSI_PREFIXED_SERIES = %w[PAS PD DD BIP].freeze
39
39
 
40
- BSI_PREFIX = /\ABSI\s+(?=(?:#{BSI_PREFIXED_SERIES.join('|')})\b)/
40
+ # Series tokens whose `BSI `-prefixed spelling parses (the strip below
41
+ # drops the prefix before the baked grammar runs). That is the
42
+ # BSI_PREFIXED_SERIES plus `BS`: `BS` is never PRINTED with the prefix
43
+ # by BSI itself, but external references do cite the British Standard
44
+ # series as `BSI BS 5950` (pubid#644), so the prefixed spelling is
45
+ # accepted on parse and normalizes to the canonical `BS 5950`. Render
46
+ # never re-adds the prefix for `BS` — only BSI_PREFIXED_SERIES does.
47
+ STRIPPABLE_SERIES = (BSI_PREFIXED_SERIES + %w[BS]).freeze
48
+
49
+ BSI_PREFIX = /\ABSI\s+(?=(?:#{STRIPPABLE_SERIES.join('|')})\b)/
41
50
 
42
51
  # `BSI PAS 2031:2019` is the external spelling of `PAS 2031:2019`. The
43
52
  # prefix is not part of the identity, so it is dropped before the baked
@@ -1812,7 +1812,12 @@ module Pubid
1812
1812
  # Optional attributes (excluding part/subpart since they're in code)
1813
1813
  extract_optional(parsed, attributes, :edition)
1814
1814
  extract_optional(parsed, attributes, :revision)
1815
- extract_optional(parsed, attributes, :rev_sep)
1815
+ # A printed separator before the revision is notation residue: once the
1816
+ # revision is repositioned to the canonical face (and every corpus
1817
+ # expectation for these variants renders it absent), carrying rev_sep
1818
+ # would make the variant hash differ from its canonical equivalent.
1819
+ # Keep it only for a bare "Rev" with no number.
1820
+ extract_optional(parsed, attributes, :rev_sep) unless attributes[:revision] =~ /\A\d/
1816
1821
  attributes[:rev_bare] = true if parsed[:rev_bare]
1817
1822
 
1818
1823
  # Month/day - always extract if present (but not if already extracted from year)