@tabnas/abnf 0.4.21 → 0.4.22

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.
package/dist/abnf.d.ts CHANGED
@@ -6,4 +6,4 @@ export { VERSION, abnf, abnfConvert, parseAbnf, emitGrammarSpec, eliminateLeftRe
6
6
  export type { AbnfConvertOptions, AbnfCompileOptions, ActionsMap };
7
7
  export { translate } from './translate';
8
8
  export type { TranslationPart, TranslationParts } from './translate';
9
- declare const VERSION = "0.4.21";
9
+ declare const VERSION = "0.4.22";
package/dist/abnf.js CHANGED
@@ -38,6 +38,6 @@ Object.defineProperty(exports, "translate", { enumerable: true, get: function ()
38
38
  // VERSION is this package's version. It MUST equal package.json "version":
39
39
  // the release orchestrator rewrites both, and the version test fails the
40
40
  // build if they drift. Mirrors `const VERSION` in go/abnf.go.
41
- const VERSION = '0.4.21';
41
+ const VERSION = '0.4.22';
42
42
  exports.VERSION = VERSION;
43
43
  //# sourceMappingURL=abnf.js.map
package/dist/translate.js CHANGED
@@ -43,12 +43,13 @@ const TRANSLATION = Object.freeze({
43
43
  "Where the compiler reordered a rule's alternatives to tell them apart (a longer lookahead ahead of a shorter one that begins with the same character, a keyword ahead of a character class that can take it), the alternatives that push a helper of the compiler's are put back in the order its numbers record, and the others are written in the compiled order: the rule compiles back the same, and the spec compiled back can differ in the order of the alternates other rules build through it, in the numbers of the compiler's helpers and in the order of its tokens, which is the order the lexer tries two tokens a place expects, so where a keyword and a class that can take it trade places the grammar compiled back accepts what the spec refused (start = ident / \\"if\\" ident with ident = %x61-7A: the spec refuses ifx, and the text compiles back to one that accepts it).",
44
44
  "A left recursion that ran through another rule (P = Q, Q = P \\"+\\" / NR) is written as the compiler rewrote it, with the leading reference that closed the cycle left in place, and compiles back to another spec, since the compiler now substitutes that reference.",
45
45
  "The start rule is written first, as ABNF's start rule is its first; a spec whose start rule was not its first rule compiles back with that rule moved first.",
46
- "Terminals are written in RFC 5234's forms: a literal as a quoted string (with %s where it matches exactly and holds a letter) or, where a quoted string cannot hold it, as a numeric value of its code points, a range as %x and its ends, and a rule the compiler made a token of (CR = %x0D, referenced as CR) as that rule, after the others.",
46
+ "Terminals are written in RFC 5234's forms: a literal as a quoted string (with %s where it matches exactly and holds a letter) or, where a quoted string cannot hold it, as a numeric value of its code points, a range as %x and its ends, the class of every code point (GBNF's dot) as %x0-10FFFF, and a rule the compiler made a token of (CR = %x0D, referenced as CR) as that rule, after the others.",
47
47
  "A rule the compiler made a token of, whose name is one the compiler could give its literal by itself (B = \\"b\\", or any name of capitals, digits and underscores where the literal holds a character past ASCII), cannot be told from that literal and is written as the literal: it compiles back with the token later in the token table, or under the name the literal gives it.",
48
48
  "Repetitions are written in RFC 5234's forms, *A, 1*A, m*nA, [ A ] for an option over a group and 0*1A for an option over anything else; a repetition of a repetition, which another notation can write and RFC 5234 cannot, is put in a group of its own and compiles back with one more group.",
49
49
  "An empty alternative, which RFC 5234 has no syntax for, is written as nothing between its slashes, which the compiler reads as one; in a rule whose alternatives the compiler emits as its open alternates, where it puts the empty one last wherever it stood, it is written first.",
50
50
  "A spec compiled from another notation compiles back under ABNF's own settings: the group tag on every alternate, and lexer options the other notation adds (GBNF's exact lexing), are ABNF's, and a class of several members, which RFC 5234 cannot write, is written as the alternation of its members, each range a range and each character a string or a range of one, and compiles back as that alternation.",
51
- "A spec the render cannot write as ABNF is refused with TARGET_VALUE_UNREPRESENTABLE, naming what it met: an action (a value annotation's builders, a user action, the probe dispatcher of an optional prefix), a condition or a counter other than a repetition's, an error generator or an alternate modifier, a function reference where a rule or a count is due, a set of tokens at one place, a removal, a clear or the form that edits a rule already installed, a token no ABNF terminal matches (a negated class, a class holding a character past ASCII alone, a class whose flags change what it matches, a pattern that is neither one class nor an escaped literal, a case-sensitive literal holding a letter and a character no quoted string holds, a character past U+FFFF), a rule name ABNF cannot spell, the empty name among them, a repetition bounded past what the compiler numbers, a repetition of no copies, whose item the spec does not keep, or a spec that gives its match tokens' order as a list of its own (Go's tokenOrder), whose rules' order, which ranks the tokens, is lost."
51
+ "The tree builders every compiled grammar carries (@node$, @capture$, @bubble$ and @fold$, with their k settings) and its marks are not written, since the compiler makes them again from the rules: a spec whose builders or marks are others compiles back with the compiler's own, and recognises what it recognised.",
52
+ "A spec the render cannot write as ABNF is refused with TARGET_VALUE_UNREPRESENTABLE, naming what it met: an action (a value annotation's builders, a user action, the probe dispatcher of an optional prefix), a condition or a counter other than a repetition's, an error generator or an alternate modifier, a function reference where a rule or a count is due, a set of tokens at one place, a removal, a clear or the form that edits a rule already installed, a token no ABNF terminal matches (a negated class, a class holding a character past ASCII alone, a class whose flags change what it matches (no u on a class that is negated, reaches past U+FFFF or holds every code point, or u on one that holds a surrogate), a pattern that is neither one class nor an escaped literal, a case-sensitive literal holding a letter and a character no quoted string holds, a case-insensitive literal holding a character past ASCII and no ASCII letter, whose numeric value would match one case alone, a character past U+FFFF), a token set whose tokens are not the class its name gives, a rule with no alternate to open with, a sequence's step with more alternates than a step, a rule the compiler lifted to a token whose name another rule holds, a start that is not the start wrapper every grammar text compiles to (one open alternate that matches nothing and pushes a rule, closed by the end of the source alone), a rule name ABNF cannot spell, the empty name among them, a repetition bounded past what the compiler numbers, a repetition of no copies, whose item the spec does not keep, or a spec that gives its match tokens' order as a list of its own (Go's tokenOrder), whose rules' order, which ranks the tokens, is lost."
52
53
  ]
53
54
  }
54
55
  }
@@ -72,17 +73,20 @@ const TRANSLATION = Object.freeze({
72
73
  ; reads the compiler's shapes back into the notation:
73
74
  ;
74
75
  ; - A rule the author wrote is a rule of the spec that the spec's
75
- ; \`meta.provenance\` does not name; every rule it names is the
76
- ; compiler's: a repetition's, an option's or a group's helper
77
- ; (\`_gen<n>_star_...\`, \`_plus_\`, \`_opt_\`, \`_rep_\`, \`_group\`), a
78
- ; sequence's chain steps (\`$alt<i>\`, \`$step<j>\`), a left-factored tail
79
- ; (\`$fact<k>\`) and the start wrapper. A helper is written where it is
80
- ; referenced, as the construct it compiles: a repeat loop (the replace
81
- ; loop every \`*A\` compiles to, its entry \`{c: {n.rep: 0}, r: <self>}\`)
82
- ; as \`*A\`, a plus as \`1*A\`, an option over a group as \`[ ... ]\` and over
83
- ; anything else as \`0*1A\`, a counted repetition as \`m*nA\` (its nested
84
- ; optionals counted), a group as \`( ... )\`. A factored tail is expanded
85
- ; back into the alternatives it was factored from, which the compiler
76
+ ; \`meta.provenance\` does not name (a spec without it is read by the
77
+ ; names the compiler gives its rules, a helper's only where it has
78
+ ; the shape of its kind too, and the start wrapper by its shape);
79
+ ; every rule it names is the compiler's: a repetition's, an
80
+ ; option's or a group's helper (\`_gen<n>_star_...\`, \`_plus_\`, \`_opt_\`,
81
+ ; \`_rep_\`, \`_group\`), a sequence's chain steps (\`$alt<i>\`,
82
+ ; \`$step<j>\`), a left-factored tail (\`$fact<k>\`) and the start
83
+ ; wrapper. A helper is written where it is referenced, as the
84
+ ; construct it compiles: a repeat loop (the replace loop every \`*A\`
85
+ ; compiles to, its entry \`{c: {n.rep: 0}, r: <self>}\`) as \`*A\`, a plus
86
+ ; as \`1*A\`, an option over a group as \`[ ... ]\` and over anything else
87
+ ; as \`0*1A\`, a counted repetition as \`m*nA\` (its nested optionals
88
+ ; counted), a group as \`( ... )\`. A factored tail is expanded back
89
+ ; into the alternatives it was factored from, which the compiler
86
90
  ; factors again, and alternatives that were each a group, which the
87
91
  ; compiler factored into the first, are read back as the groups they
88
92
  ; were.
@@ -102,32 +106,48 @@ const TRANSLATION = Object.freeze({
102
106
  ; by one same tail, still stand together.
103
107
  ; - A token is written as the terminal it matches: a fixed token as a
104
108
  ; quoted string, \`%s"..."\` where it holds a letter, a case-folding
105
- ; match token as a quoted string, a range as \`%x<lo>-<hi>\` (a token set
106
- ; the compiler laid over a contested range read back from its name),
107
- ; and the engine's \`#TX\`, \`#NR\`, \`#ST\` and \`#VL\` by their names. A
108
- ; string a quoted string cannot hold is written as a numeric value,
109
- ; \`%x<hex>.<hex>\`. A token named for a rule the compiler lifted to it
110
- ; (\`CR = %x0D\` becomes the token \`#CR\`) is written as that rule, after
111
- ; the others, and referenced by name.
109
+ ; match token as a quoted string, a range as \`%x<lo>-<hi>\` (a token
110
+ ; set the compiler laid over a contested range read back from its
111
+ ; name, once its tokens are found to be that range), \`[\\s\\S]\` (GBNF's
112
+ ; \`.\`) as \`%x0-10FFFF\`, and the engine's \`#TX\`, \`#NR\`, \`#ST\` and \`#VL\`
113
+ ; by their names. A string a quoted string cannot hold is written as a
114
+ ; numeric value, \`%x<hex>.<hex>\`, which the compiler reads as
115
+ ; case-insensitive where it holds a letter of ASCII and as exact where
116
+ ; it holds none: a case-folding string past ASCII with no such letter,
117
+ ; whose numeric value would match one case alone, is refused. A token
118
+ ; named for a rule the
119
+ ; compiler lifted to it (\`CR = %x0D\` becomes the token \`#CR\`) is
120
+ ; written as that rule, after the others, and referenced by name.
112
121
  ; - An RFC 5234 core rule (ALPHA, DIGIT, ...) in the spec is not written,
113
122
  ; since the compiler adds it again wherever it is referenced, and a
114
123
  ; leading reference to one is written back as any other is.
115
124
  ;
116
125
  ; What a rule cannot be read back to is refused with
117
- ; TARGET_VALUE_UNREPRESENTABLE, naming the rule: an action other than the
118
- ; tree builders every compiled grammar carries (a value annotation's
126
+ ; TARGET_VALUE_UNREPRESENTABLE, naming the rule: an action other than
127
+ ; the tree builders every compiled grammar carries (a value annotation's
119
128
  ; builders, a user action, the probe dispatcher's), a condition or a
120
129
  ; counter other than a repeat loop's, an error generator or an alternate
121
130
  ; modifier (\`e\`, \`h\`), a function reference where a rule or a count is
122
131
  ; due, a set of tokens at one place, the form that edits a rule already
123
132
  ; installed (\`{alts, inject}\`), a removal, and a token no ABNF terminal
124
- ; matches (a negated class, a class holding a character past ASCII alone,
125
- ; a class whose flags change what it matches, a pattern that is neither
126
- ; one class nor an escaped literal). A spec serialized by Go, which writes
127
- ; its rules in name order and its match tokens' order as a list of its
128
- ; own (\`options.match.tokenOrder\`), is refused when that list holds two
129
- ; tokens or more: the rules' order, which ranks the tokens (the order the
130
- ; lexer tries two tokens a place expects), is lost.
133
+ ; matches (a negated class, a class holding a character past ASCII
134
+ ; alone, a class whose flags change what it matches, a pattern that is
135
+ ; neither one class nor an escaped literal). A token set whose tokens
136
+ ; are not the class its name gives, a rule with no alternate to open
137
+ ; with, a sequence's step with more alternates than a step, and a rule
138
+ ; the compiler lifted to a token whose name another rule holds are
139
+ ; refused too. A spec serialized by Go, which writes its rules in name
140
+ ; order and its match tokens' order as a list of its own
141
+ ; (\`options.match.tokenOrder\`), is refused when that list holds two
142
+ ; tokens or more: the rules' order, which ranks the tokens (the order
143
+ ; the lexer tries two tokens a place expects), is lost. The tree
144
+ ; builders and the marks are not written: the compiler makes them again
145
+ ; from the rules.
146
+ ; A spec whose start is not the start wrapper every grammar text
147
+ ; compiles to (one open alternate that matches nothing and pushes a
148
+ ; rule, closed by the end of the source alone) is refused as well: its
149
+ ; text would compile back inside such a wrapper, whose close lets the
150
+ ; end of the source come after what the lexer skips.
131
151
  ;
132
152
  ; A spec compiled from another notation is written as far as ABNF can say
133
153
  ; it: a class of several members (GBNF's and EBNF's \`[a-zA-Z_]\`) as the
@@ -344,9 +364,154 @@ def abnf-made [cx name]
344
364
  case :string true
345
365
  case _ false
346
366
  case _
347
- match (abnf-starts "_gen" name)
348
- case true true
349
- case false (abnf-some (abnf-rest (split "$" name)))
367
+ match (abnf-some (abnf-rest (split "$" name)))
368
+ case true (abnf-split-name name)
369
+ case false
370
+ match (abnf-gen-kind name)
371
+ case ""
372
+ match (abnf-same name (get :start cx))
373
+ case true (abnf-wrapper (abnf-rule cx name))
374
+ case false false
375
+ case k (abnf-helper-shape cx name k)
376
+
377
+ ; The kind of helper a name gives, as the compiler names the helpers it
378
+ ; makes, \`_gen<n>_<kind>...\` with the kind a repetition's, an option's or
379
+ ; a group's (\`_gen3_star_x\`, \`_gen4_group\`), or "" for any other name: a
380
+ ; rule the author wrote may begin with \`_gen\` too (\`_general\`).
381
+ def abnf-gen-kind [name]
382
+ match (abnf-starts "_gen" name)
383
+ case false ""
384
+ case true
385
+ let [parts (split "_" (abnf-after "_gen" name))]
386
+ match (count parts)
387
+ case 1 ""
388
+ case _
389
+ match (match (abnf-digits (abnf-at parts 0)) (case true (abnf-among (abnf-at parts 1) ["star" "plus" "opt" "rep" "group"])) (case false false))
390
+ case true (abnf-at parts 1)
391
+ case false ""
392
+
393
+ ; Whether a name is one the compiler gives a rule it splits off another,
394
+ ; every part after a \`$\` one of its own: a dispatcher's alternative
395
+ ; (\`$alt<i>\`), a chain's step (\`$step<j>\`), a left-factored tail
396
+ ; (\`$fact<k>\`), a probe dispatcher (\`$pd<i>\`) and its parts (\`$probe\`,
397
+ ; \`$with\`, \`$no\`, numbered where the name was taken).
398
+ def abnf-split-name [name]
399
+ abnf-none (filter (fn [p] (abnf-not (abnf-split-part p))) (abnf-rest (split "$" name)))
400
+
401
+ def abnf-split-part [p]
402
+ abnf-some (filter (fn [k] (abnf-split-fits k p)) ["alt" "step" "fact" "pd" "probe" "with" "no"])
403
+
404
+ def abnf-split-fits [k p]
405
+ match (abnf-starts k p)
406
+ case false false
407
+ case true
408
+ match (abnf-after k p)
409
+ case "" (abnf-among k ["probe" "with" "no"])
410
+ case rest (abnf-digits rest)
411
+
412
+ ; A rule named as the compiler names a helper, in a spec that names no
413
+ ; provenance, is the compiler's where it has the shape the compiler gives
414
+ ; that kind, and the author's otherwise: a repetition's loop has its
415
+ ; guarded entry (\`{c: {n.rep: 0}, r: <self>}\`); a plus is its item and the
416
+ ; loop after it; an option one element and the empty alternative; a
417
+ ; counted repetition copies of one element, and the option or the loop
418
+ ; after them; a group any alternatives.
419
+ def abnf-helper-shape [cx name k]
420
+ match k
421
+ case "group" true
422
+ case "star" (abnf-some (filter (fn [alt] (abnf-loop-entry name alt)) (abnf-open (abnf-rule cx name))))
423
+ case _
424
+ let [alts (abnf-raw-alts cx name)]
425
+ match k
426
+ case "plus" (abnf-plus-shape alts)
427
+ case "opt" (abnf-opt-shape alts)
428
+ case _ (abnf-rep-shape alts)
429
+
430
+ def abnf-loop-entry [name alt]
431
+ match (abnf-same (abnf-r alt) name)
432
+ case false false
433
+ case true
434
+ let [c (get "c" alt)]
435
+ match (kind c)
436
+ case :record (abnf-loop-value c "n.rep" [0])
437
+ case _ false
438
+
439
+ def abnf-plus-shape [alts]
440
+ match (count alts)
441
+ case 1
442
+ let [seq (abnf-vec (abnf-at alts 0))]
443
+ match (count seq)
444
+ case 2 (abnf-same (abnf-helper-ref (abnf-at seq 1)) "star")
445
+ case _ false
446
+ case _ false
447
+
448
+ def abnf-opt-shape [alts]
449
+ match (count alts)
450
+ case 2
451
+ let [counts (map count alts)]
452
+ match (abnf-among "0" (map abnf-num counts))
453
+ case true (abnf-among "1" (map abnf-num counts))
454
+ case false false
455
+ case _ false
456
+
457
+ def abnf-rep-shape [alts]
458
+ match (count alts)
459
+ case 1
460
+ let [seq (abnf-vec (abnf-at alts 0))]
461
+ match (count seq)
462
+ case 0 true
463
+ case _
464
+ let [lead (match (abnf-among (abnf-helper-ref (top seq)) ["star" "opt"]) (case true (pop seq)) (case false seq))]
465
+ let [keys (map abnf-el-name lead)]
466
+ abnf-none (filter (fn [key] (match key (case "" true) (case _ (abnf-not (abnf-same key (abnf-at keys 0)))))) keys)
467
+ case _ false
468
+
469
+ ; The kind of helper an element references by name, or "".
470
+ def abnf-helper-ref [el]
471
+ match (get :k el)
472
+ case :ref (abnf-gen-kind (get :name el))
473
+ case _ ""
474
+
475
+ ; A token or a reference by its name, any other element "".
476
+ def abnf-el-name [el]
477
+ match (get :k el)
478
+ case :tok (string-join "" ["#" (get :name el)])
479
+ case :ref (string-join "" ["@" (get :name el)])
480
+ case _ ""
481
+
482
+ ; The start wrapper the compiler adds, which \`options.rule.start\` names:
483
+ ; one open alternate that consumes nothing and pushes the grammar's start
484
+ ; rule, and the end of the source, and nothing else, to close it.
485
+ def abnf-wrapper [r]
486
+ let [o (abnf-open r)]
487
+ match (count o)
488
+ case 1
489
+ let [a (abnf-at o 0)]
490
+ match (match (abnf-some (abnf-s a)) (case true false) (case false (abnf-full (abnf-p a))))
491
+ case false false
492
+ case true
493
+ let [c (abnf-close r)]
494
+ match (count c)
495
+ case 0 false
496
+ case _ (abnf-none (filter (fn [x] (abnf-not (abnf-wrapper-end x))) c))
497
+ case _ false
498
+
499
+ ; A close alternate that matches the end of the source and goes nowhere.
500
+ def abnf-wrapper-end [alt]
501
+ match (abnf-same (string-join " " (abnf-s alt)) "#ZZ")
502
+ case false false
503
+ case true (abnf-empty (abnf-target alt))
504
+
505
+ ; Every grammar text compiles to a start wrapper around its start rule,
506
+ ; and the wrapper's close lets the end of the source come after what the
507
+ ; lexer skips (\`ab \` where the grammar is \`ab\`). So the rule
508
+ ; \`options.rule.start\` names must be that wrapper: a spec that starts at
509
+ ; another rule, or at a wrapper without its close, would come back
510
+ ; accepting what it refuses.
511
+ def abnf-check-start [cx]
512
+ match (abnf-wrapper (abnf-rule cx (get :start cx)))
513
+ case true true
514
+ case false (abnf-fail (string-join "" ["the start rule " (get :start cx) " is not the start wrapper every grammar text compiles to (one open alternate that matches nothing and pushes a rule, closed by the end of the source alone)"]))
350
515
 
351
516
  ; The kind the tree builders give a rule the author wrote: "user", or
352
517
  ; "core" for an RFC 5234 core rule the compiler added.
@@ -493,7 +658,9 @@ def abnf-check-rule [cx name]
493
658
  match (kind r)
494
659
  case :record
495
660
  let [phases (count (map (fn [phase] (abnf-check-phase name phase (get phase r))) ["open" "close"]))]
496
- count (map (fn [alt] (abnf-check-alt cx name alt)) (abnf-cat (abnf-open r) (abnf-close r)))
661
+ match (count (abnf-open r))
662
+ case 0 (abnf-fail (string-join "" ["rule " name " has no alternate to open with, which no grammar text writes"]))
663
+ case _ (count (map (fn [alt] (abnf-check-alt cx name alt)) (abnf-cat (abnf-open r) (abnf-close r))))
497
664
  case :null (abnf-fail (string-join "" ["rule " name " is removed, which is not written"]))
498
665
  case _ (abnf-fail (string-join "" ["rule " name " is not a rule's alternates, which is not written"]))
499
666
 
@@ -515,7 +682,9 @@ def abnf-check [spec cx]
515
682
  case true (abnf-fail "it clears the grammar it is installed on, which is not written")
516
683
  case _
517
684
  let [order (abnf-check-order spec)]
518
- count (map (fn [name] (abnf-check-rule cx name)) (keys (get :rules cx)))
685
+ let [start (abnf-check-start cx)]
686
+ let [rules (count (map (fn [name] (abnf-check-rule cx name)) (keys (get :rules cx))))]
687
+ abnf-check-sets cx (abnf-used cx)
519
688
 
520
689
  ; ---- tokens
521
690
 
@@ -554,9 +723,9 @@ def abnf-match-token [t m]
554
723
  match (abnf-class-pattern body)
555
724
  case false (abnf-fail (string-join "" ["the token " t " is the pattern " m ", which is not one class the render reads, and no ABNF terminal matches it"]))
556
725
  case true
557
- match (abnf-among flags ["" "u"])
726
+ match (abnf-flags-fit body flags)
558
727
  case true (abnf-class body flags)
559
- case false (abnf-fail (string-join "" ["the token " t " is the class " m ", whose flags (" flags ") change what it matches, and no ABNF terminal matches it"]))
728
+ case false (abnf-fail (string-join "" ["the token " t " is the class " m ", whose flags (" (match flags (case "" "none") (case _ flags)) ") change what it matches, and no ABNF terminal matches it"]))
560
729
  case false
561
730
  match flags
562
731
  case "i"
@@ -689,6 +858,193 @@ def abnf-trim-end-once [s]
689
858
  case true (abnf-before "_" s)
690
859
  case false s
691
860
 
861
+ ; ---- code points and the ranges a class holds
862
+
863
+ ; A code point, from its one to six hexadecimal digits in either case, as
864
+ ; three numbers, its bytes from the highest, each the place of its two
865
+ ; digits among \`abnf-hex-pairs\`: code points are ordered as these are.
866
+ def abnf-cp [h]
867
+ let [x (abnf-six (abnf-hex-upper h))]
868
+ let [high (abnf-pair-start x)]
869
+ let [rest (abnf-after high x)]
870
+ vector (abnf-pair-index high) (abnf-pair-index (abnf-pair-start rest)) (abnf-pair-index (abnf-pair-end rest))
871
+
872
+ def abnf-six [h]
873
+ string-join "" [(match (length h) (case 1 "00000") (case 2 "0000") (case 3 "000") (case 4 "00") (case 5 "0") (case _ "")) h]
874
+
875
+ def abnf-pair-start [x]
876
+ abnf-at (filter (fn [p] (abnf-starts p x)) abnf-hex-pairs) 0
877
+
878
+ def abnf-pair-end [x]
879
+ abnf-at (filter (fn [p] (abnf-ends p x)) abnf-hex-pairs) 0
880
+
881
+ def abnf-pair-index [p]
882
+ abnf-at (filter (fn [i] (abnf-same (abnf-at abnf-hex-pairs i) p)) (indices abnf-hex-pairs)) 0
883
+
884
+ def abnf-cp-order [a b]
885
+ match (compare (abnf-at a 0) (abnf-at b 0))
886
+ case :equal
887
+ match (compare (abnf-at a 1) (abnf-at b 1))
888
+ case :equal (compare (abnf-at a 2) (abnf-at b 2))
889
+ case other other
890
+ case other other
891
+
892
+ def abnf-cp-before [a b]
893
+ match (abnf-cp-order a b)
894
+ case :less true
895
+ case _ false
896
+
897
+ def abnf-cp-is [a b]
898
+ match (abnf-cp-order a b)
899
+ case :equal true
900
+ case _ false
901
+
902
+ ; The code point after one: its low byte one more, carried into the bytes
903
+ ; above it.
904
+ def abnf-cp-next [c]
905
+ match (abnf-at c 2)
906
+ case 255
907
+ match (abnf-at c 1)
908
+ case 255 (vector (abnf-plus (abnf-at c 0) 1) 0 0)
909
+ case _ (vector (abnf-at c 0) (abnf-plus (abnf-at c 1) 1) 0)
910
+ case _ (vector (abnf-at c 0) (abnf-at c 1) (abnf-plus (abnf-at c 2) 1))
911
+
912
+ def abnf-cp-max [cps]
913
+ abnf-at (filter (fn [c] (abnf-none (filter (fn [d] (abnf-cp-before c d)) cps))) cps) 0
914
+
915
+ def abnf-span [lo hi]
916
+ record
917
+ entry :lo lo
918
+ entry :hi hi
919
+
920
+ ; The members of a class's pattern, read as \`abnf-class-pattern\` admits
921
+ ; them: each a range, from its low end's digits to its high end's (a
922
+ ; character alone is a range of one); \`[\\s\\S]\` every code point. A
923
+ ; negated class's are the ones it excludes.
924
+ def abnf-class-hex-spans [body]
925
+ match body
926
+ case "[\\\\s\\\\S]" [(abnf-span "0" "10FFFF")]
927
+ case _
928
+ let [inner (abnf-before "]" (abnf-after "[" body))]
929
+ let [pieces (abnf-rest (split "\\\\u" (match (abnf-starts "^" inner) (case true (abnf-after "^" inner)) (case false inner))))]
930
+ let [lows (map (fn [p] (abnf-ends "-" p)) pieces)]
931
+ let [ends (abnf-cat [false] lows)]
932
+ map
933
+ fn [i]
934
+ let [lo (abnf-piece-hex (abnf-at pieces i))]
935
+ match (abnf-at lows i)
936
+ case true (abnf-span lo (abnf-piece-hex (abnf-at pieces (abnf-plus i 1))))
937
+ case false (abnf-span lo lo)
938
+ filter (fn [i] (abnf-not (abnf-at ends i))) (indices pieces)
939
+
940
+ def abnf-piece-hex [p]
941
+ let [core (match (abnf-ends "-" p) (case true (abnf-before "-" p)) (case false p))]
942
+ match (abnf-starts "{" core)
943
+ case true (abnf-before "}" (abnf-after "{" core))
944
+ case false core
945
+
946
+ def abnf-class-spans [body]
947
+ map (fn [s] (abnf-span (abnf-cp (get :lo s)) (abnf-cp (get :hi s)))) (abnf-class-hex-spans body)
948
+
949
+ ; Ranges sorted by their low ends and merged where they overlap or meet:
950
+ ; two lists of ranges hold the same code points when these are the same.
951
+ def abnf-spans-merged [spans]
952
+ let [sorted (abnf-spans-sorted spans)]
953
+ let [starts (filter (fn [i] (abnf-none (filter (fn [j] (match (abnf-less j i) (case true (abnf-not (abnf-cp-before (abnf-cp-next (get :hi (abnf-at sorted j))) (get :lo (abnf-at sorted i))))) (case false false))) (indices sorted)))) (indices sorted))]
954
+ map (fn [k] (abnf-block-span sorted starts k)) (indices starts)
955
+
956
+ def abnf-block-span [sorted starts k]
957
+ let [from (abnf-at starts k)]
958
+ let [members (filter (fn [i] (match (abnf-less i from) (case true false) (case false (abnf-before-start starts k i)))) (indices sorted))]
959
+ abnf-span (get :lo (abnf-at sorted from)) (abnf-cp-max (map (fn [i] (get :hi (abnf-at sorted i))) members))
960
+
961
+ def abnf-before-start [starts k i]
962
+ match (abnf-less (abnf-plus k 1) (count starts))
963
+ case true (abnf-less i (abnf-at starts (abnf-plus k 1)))
964
+ case false true
965
+
966
+ def abnf-spans-sorted [spans]
967
+ let [ranks (map (fn [i] (count (filter (fn [j] (match (abnf-cp-order (get :lo (abnf-at spans j)) (get :lo (abnf-at spans i))) (case :less true) (case :equal (abnf-less j i)) (case _ false))) (indices spans)))) (indices spans))]
968
+ map (fn [k] (abnf-at spans (abnf-at (filter (fn [i] (match (compare (abnf-at ranks i) k) (case :equal true) (case _ false))) (indices spans)) 0))) (indices spans)
969
+
970
+ def abnf-spans-same [a b]
971
+ match (compare (count a) (count b))
972
+ case :equal (abnf-none (filter (fn [i] (match (abnf-cp-is (get :lo (abnf-at a i)) (get :lo (abnf-at b i))) (case true (abnf-not (abnf-cp-is (get :hi (abnf-at a i)) (get :hi (abnf-at b i))))) (case false true))) (indices a)))
973
+ case _ false
974
+
975
+ ; Whether two lists of ranges hold every code point between them, each
976
+ ; once: a negated class's ranges and the ranges it matches.
977
+ def abnf-spans-tile [a b]
978
+ let [all (abnf-spans-sorted (abnf-cat (abnf-spans-merged a) (abnf-spans-merged b)))]
979
+ match (count all)
980
+ case 0 false
981
+ case _
982
+ match (match (abnf-cp-is (get :lo (abnf-at all 0)) (abnf-cp "0")) (case true (abnf-cp-is (get :hi (top all)) (abnf-cp "10FFFF"))) (case false false))
983
+ case false false
984
+ case true
985
+ let [nexts (abnf-rest all)]
986
+ abnf-none (filter (fn [i] (abnf-not (abnf-cp-is (get :lo (abnf-at nexts i)) (abnf-cp-next (get :hi (abnf-at all i)))))) (indices nexts))
987
+
988
+ ; Whether a class's flags are the ones it is matched with once its text is
989
+ ; written and compiled back. Every compiler here gives \`u\` to a class that
990
+ ; is negated, holds a character past U+FFFF or is \`[\\s\\S]\`, and to no
991
+ ; other. Without \`u\` such a class matches one UTF-16 code unit, half of a
992
+ ; character past U+FFFF, and with it one code point. A class of other
993
+ ; characters matches the same either way, unless it holds a surrogate,
994
+ ; which \`u\` matches only where it stands alone.
995
+ def abnf-flags-fit [body flags]
996
+ match (abnf-wants-u body)
997
+ case true (abnf-same flags "u")
998
+ case false
999
+ match (abnf-holds-surrogate body)
1000
+ case true (abnf-empty flags)
1001
+ case false (abnf-among flags ["" "u"])
1002
+
1003
+ def abnf-wants-u [body]
1004
+ match body
1005
+ case "[\\\\s\\\\S]" true
1006
+ case _
1007
+ match (abnf-starts "[^" body)
1008
+ case true true
1009
+ case false (abnf-some (abnf-rest (split "\\\\u{" body)))
1010
+
1011
+ ; A class none of whose members is past U+FFFF holds a surrogate where a
1012
+ ; range's low end is not above U+DFFF and its high end not below U+D800.
1013
+ def abnf-holds-surrogate [body]
1014
+ abnf-some (filter (fn [s] (match (abnf-hex-from (get :lo s) ["E" "F"]) (case true false) (case false (abnf-hex-from (get :hi s) ["D8" "D9" "DA" "DB" "DC" "DD" "DE" "DF" "E" "F"])))) (abnf-class-hex-spans body))
1015
+
1016
+ def abnf-hex-from [h prefixes]
1017
+ let [x (abnf-hex-upper h)]
1018
+ match (length x)
1019
+ case 4 (abnf-some (filter (fn [p] (abnf-starts p x)) prefixes))
1020
+ case _ false
1021
+
1022
+ ; A token set is the class its name gives when the tokens it lays over
1023
+ ; that class are the class: their ranges, merged, are the class's ranges,
1024
+ ; or, for a negated class, every code point the class does not exclude.
1025
+ ; The compiler lays a contested class over the atoms of a partition, each
1026
+ ; a token of its own, and names the set for the class; the render writes
1027
+ ; the class the name gives, so a set whose tokens match anything else is
1028
+ ; refused.
1029
+ def abnf-check-sets [cx used]
1030
+ count (map (fn [k] (abnf-check-set cx (string-join "" ["#" k]))) (filter (fn [k] (match (abnf-starts "RX_" k) (case true (abnf-some (abnf-rest (split (string-join "" [" #" k " "]) used)))) (case false false))) (keys (get :sets cx))))
1031
+
1032
+ def abnf-check-set [cx t]
1033
+ let [cls (abnf-set-token t)]
1034
+ let [pat (get :pat cls)]
1035
+ let [spans (abnf-flat (map (fn [m] (abnf-member-spans cx t m)) (abnf-vec (get-path (as-path [(abnf-bare t)]) (get :sets cx)))))]
1036
+ let [own (abnf-class-spans pat)]
1037
+ match (match (abnf-starts "[^" pat) (case true (abnf-spans-tile own spans)) (case false (abnf-spans-same (abnf-spans-merged own) (abnf-spans-merged spans))))
1038
+ case true true
1039
+ case false (abnf-fail (string-join "" ["the token set " t " lays tokens over its class " pat " that match other characters than the class does, and the render writes the class the set's name gives"]))
1040
+
1041
+ def abnf-member-spans [cx t m]
1042
+ let [src (match (kind m) (case :string (abnf-str (get-path (as-path [m]) (get :match cx)))) (case _ ""))]
1043
+ let [body (abnf-after "^" (string-join "/" (pop (abnf-rest (split "/" src)))))]
1044
+ match (match (abnf-starts "@" src) (case true (match (abnf-class-pattern body) (case true (match (abnf-starts "[^" body) (case true false) (case false (abnf-flags-fit body (top (split "/" src)))))) (case false false))) (case false false))
1045
+ case true (abnf-class-spans body)
1046
+ case false (abnf-fail (string-join "" ["the token set " t " holds " (abnf-str m) ", which is not one class the render reads"]))
1047
+
692
1048
  def abnf-engine-token [t]
693
1049
  match t
694
1050
  case "#TX" (record (entry :k :engine) (entry :name "TX"))
@@ -752,11 +1108,23 @@ def abnf-entry-key [alt]
752
1108
  ; the empty alternative, or a guard that ends it on what may follow; two
753
1109
  ; or more bare ones (\`a ::= | \`) are as many empty alternatives.
754
1110
  def abnf-simple-alts [r]
755
- let [alts (map abnf-entry-els (abnf-unique abnf-entry-key (abnf-open r)))]
1111
+ let [alts (abnf-flat (map (fn [alt] (map (fn [i] (abnf-entry-els alt)) (indices (abnf-ones (abnf-copies (abnf-open r) alt))))) (abnf-unique abnf-entry-key (abnf-open r))))]
756
1112
  let [bare (count (filter abnf-bare-empty (abnf-open r)))]
757
1113
  let [empties (match (abnf-some (filter abnf-none alts)) (case false []) (case true (map (fn [i] []) (indices (abnf-ones (match (abnf-less bare 2) (case true 1) (case false bare)))))))]
758
1114
  abnf-cat empties (abnf-number-order (filter abnf-some alts))
759
1115
 
1116
+ ; How many times an alternative stands among the open alternates: the
1117
+ ; lookahead copies a dispatch makes of one alternative consume and push the
1118
+ ; same and look ahead at different tokens, and are one; alternates alike
1119
+ ; in everything are as many alternatives as there are of them.
1120
+ def abnf-copies [open alt]
1121
+ let [group (filter (fn [a] (abnf-same (abnf-entry-key a) (abnf-entry-key alt))) open)]
1122
+ let [counts (map (fn [a] (count (filter (fn [b] (abnf-same (abnf-whole-key b) (abnf-whole-key a))) group))) group)]
1123
+ abnf-at (filter (fn [c] (abnf-none (filter (fn [d] (abnf-less c d)) counts))) counts) 0
1124
+
1125
+ def abnf-whole-key [alt]
1126
+ string-join "" [(string-join " " (abnf-s alt)) "|" (abnf-num (abnf-b alt)) "|" (abnf-target alt)]
1127
+
760
1128
  def abnf-bare-empty [alt]
761
1129
  match (abnf-some (abnf-s alt))
762
1130
  case true false
@@ -805,7 +1173,7 @@ def abnf-filled [alts]
805
1173
  ; The steps of a chain, each a segment: the tokens its open alternate
806
1174
  ; consumes and the rule it pushes, the next step named in its close.
807
1175
  def abnf-chain-walk [self cx name depth acc]
808
- let [r (abnf-rule cx name)]
1176
+ let [r (abnf-chain-step name (abnf-rule cx name))]
809
1177
  let [els (abnf-cat acc (abnf-entry-els (abnf-at (abnf-open r) 0)))]
810
1178
  match (count (abnf-close r))
811
1179
  case 0 els
@@ -902,6 +1270,15 @@ def abnf-raw-alts [cx name]
902
1270
  case "" (abnf-simple-alts r)
903
1271
  case _ (vector (abnf-chain cx name))
904
1272
 
1273
+ ; A step of a sequence's chain, as the compiler makes one: one open
1274
+ ; alternate, a segment of the sequence, and at most one close alternate,
1275
+ ; which names the next step. A rule that replaces itself in its close and
1276
+ ; has more alternates than that is no chain the render reads back.
1277
+ def abnf-chain-step [name r]
1278
+ match (match (count (abnf-open r)) (case 1 (abnf-less (count (abnf-close r)) 2)) (case _ false))
1279
+ case true r
1280
+ case false (abnf-fail (string-join "" ["rule " name " replaces itself in its close as a sequence's step does, and has more alternates than a step, which is not read back"]))
1281
+
905
1282
  ; ---- the compiler's helpers, read back
906
1283
 
907
1284
  ; The kind of a helper the compiler named: \`_gen<n>_<kind>...\`.
@@ -1338,8 +1715,12 @@ def abnf-unsub-at [cx alts best accepted covers i]
1338
1715
 
1339
1716
  ; A literal: a quoted string where it can hold the text (\`%s\` before it
1340
1717
  ; when the match is exact and the text holds a letter), and otherwise a
1341
- ; numeric value, \`%x\` and each character's code point, which ABNF reads
1342
- ; as a case-insensitive string.
1718
+ ; numeric value, \`%x\` and each character's code point, which tabnas-abnf
1719
+ ; reads as a case-insensitive string where it holds a letter of ASCII,
1720
+ ; with the folding a case-insensitive pattern has, and as an exact one
1721
+ ; where it holds none. So a case-insensitive literal holding a character
1722
+ ; past ASCII, which may have cases, and no letter of ASCII is refused: its
1723
+ ; numeric value would match the one case it spells.
1343
1724
  def abnf-lit-text [text cs]
1344
1725
  match text
1345
1726
  case "" "\\"\\""
@@ -1358,7 +1739,10 @@ def abnf-lit-text [text cs]
1358
1739
  match (abnf-has-letter text)
1359
1740
  case true (abnf-fail (string-join "" ["the case-sensitive literal " (quoted text) " holds a character a quoted string cannot hold, and a numeric value matches case-insensitively"]))
1360
1741
  case false (string-join "" ["%x" (string-join "." (abnf-codes text))])
1361
- case false (string-join "" ["%x" (string-join "." (abnf-codes text))])
1742
+ case false
1743
+ match (match (abnf-has-letter text) (case true true) (case false (chars-within [[0 127] [65536 1114111]] text)))
1744
+ case true (string-join "" ["%x" (string-join "." (abnf-codes text))])
1745
+ case false (abnf-fail (string-join "" ["the case-insensitive literal " (quoted text) " holds a character past ASCII that may have cases and no ASCII letter, and a numeric value without a letter matches exactly"]))
1362
1746
 
1363
1747
  ; A code point of a class's pattern, \`\\uXXXX\` or \`\\u{X...}\`, as ABNF's
1364
1748
  ; hexadecimal digits.
@@ -1378,8 +1762,14 @@ def abnf-escape-hex [e]
1378
1762
  ; class of several members, which another notation writes, as the
1379
1763
  ; alternation of its members, each range a range and each character a
1380
1764
  ; string that matches it exactly, or a range of one where a string cannot
1381
- ; hold it. A negated class has no ABNF form.
1765
+ ; hold it; \`[\\s\\S]\` (GBNF's \`.\`) as the range of every code point. A
1766
+ ; negated class has no ABNF form.
1382
1767
  def abnf-class-text [pat flags]
1768
+ match pat
1769
+ case "[\\\\s\\\\S]" "%x0-10FFFF"
1770
+ case _ (abnf-range-text pat)
1771
+
1772
+ def abnf-range-text [pat]
1383
1773
  let [body (abnf-before "]" (abnf-after "[" pat))]
1384
1774
  match (abnf-starts "^" body)
1385
1775
  case true (abnf-fail (string-join "" ["the class " pat " is negated, which ABNF has no form for"]))
@@ -1582,8 +1972,24 @@ def abnf-lifted-production [cx t]
1582
1972
  let [info (abnf-token cx t)]
1583
1973
  string-join "" [(abnf-ref-text (abnf-bare t)) " = " (abnf-lit-text (get :text info) (get :cs info))]
1584
1974
 
1975
+ ; A rule the compiler lifted to a token is written under the token's name,
1976
+ ; which no rule of the spec may hold already: two productions of one name
1977
+ ; are one rule.
1978
+ def abnf-check-lifted [cx lifted]
1979
+ map
1980
+ fn [t]
1981
+ match (abnf-has cx (abnf-bare t))
1982
+ case true (abnf-fail (string-join "" ["the token " t " is written as a rule named " (abnf-bare t) ", the name of another rule the spec holds"]))
1983
+ case false t
1984
+ lifted
1985
+
1986
+ ; The grammar's start rule: the one the start wrapper pushes, or the rule
1987
+ ; \`options.rule.start\` names where it is no wrapper.
1585
1988
  def abnf-start-rule [cx]
1586
- abnf-p (abnf-at (abnf-open (abnf-rule cx (get :start cx))) 0)
1989
+ let [r (abnf-rule cx (get :start cx))]
1990
+ match (abnf-wrapper r)
1991
+ case true (abnf-p (abnf-at (abnf-open r) 0))
1992
+ case false (get :start cx)
1587
1993
 
1588
1994
  def abnf-file [spec]
1589
1995
  let [cx (abnf-context spec)]
@@ -1593,7 +1999,7 @@ def abnf-file [spec]
1593
1999
  let [ordered (abnf-cat [start] (filter (fn [n] (abnf-not (abnf-same n start))) names))]
1594
2000
  let [used (abnf-used cx)]
1595
2001
  let [tokens (abnf-cat (keys (get :fixed cx)) (keys (get :match cx)))]
1596
- let [lifted (filter (fn [t] (abnf-lifted cx used t)) tokens)]
2002
+ let [lifted (abnf-check-lifted cx (filter (fn [t] (abnf-lifted cx used t)) tokens))]
1597
2003
  let [cands (abnf-candidates cx (abnf-cat ordered (abnf-direct-core cx)))]
1598
2004
  string-join ""
1599
2005
  vector