@tabnas/proto 0.6.3 → 0.6.4

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/src/proto.ts CHANGED
@@ -6,9 +6,11 @@
6
6
  // declaration and/or supplied via the `version` option.
7
7
 
8
8
  import { Tabnas } from '@tabnas/parser'
9
- import { abnf } from '@tabnas/abnf'
9
+ import type { GrammarSpec } from '@tabnas/parser'
10
10
 
11
- import { grammarText } from './grammar'
11
+ // The grammar, compiled at build time from proto-grammar/*.abnf by `npm
12
+ // run gen-grammar` (gen-grammar.js). Generated: never edit it.
13
+ import compiledGrammar from './proto-grammar.json'
12
14
  import { buildFile } from './build-descriptor'
13
15
  import { recordAggregate } from './aggregate'
14
16
  import {
@@ -25,42 +27,34 @@ export interface ProtoOptions {
25
27
  reconcile: boolean
26
28
  }
27
29
 
28
- type AnyTabnas = Tabnas & { abnf?: Function }
30
+ // The engine's GrammarSpec type describes a match token as a RegExp; the
31
+ // serialized form carries it as an `@~/…/` string, which `tn.grammar()`
32
+ // resolves on install. Hence the cast.
33
+ const COMPILED = compiledGrammar as unknown as GrammarSpec
29
34
 
30
35
  // The Tabnas plugin: installs the union proto grammar so the engine can
31
36
  // parse `.proto` source into a `{rule, src, kids}` CST. Use the exported
32
37
  // `parse()` / `toDescriptor()` to turn that CST into a FileDescriptorProto.
33
- const Proto = ((tn: AnyTabnas, _options?: Partial<ProtoOptions>) => {
34
- // Proto drives parsing through @tabnas/abnf; ensure it is installed.
35
- if ('function' !== typeof tn.abnf) tn.use(abnf)
36
- // The grammar admits every keyword as an identifier, which a compiler
37
- // without `tokenClasses` expands into millions of alternates
38
- // (tabnas/bnf#71) and never finishes installing. Probe the installed
39
- // compiler with a three-token grammar first, so an old @tabnas/bnf
40
- // fails here, at once and by name, rather than hanging.
41
- const probe = (tn.abnf as any).toSpec('s = a a\na = "x" / "y"\n',
42
- { tag: 'proto', start: 's', tokenClasses: true })
43
- if (!probe?.options?.tokenSet?.a) {
44
- throw new Error('@tabnas/proto: the installed @tabnas/bnf does not ' +
45
- 'support tokenClasses; upgrade @tabnas/bnf (tabnas/bnf#74)')
46
- }
47
- // `wordKeywords` makes a keyword match as a whole word; `tokenClasses`
48
- // compiles `ident` (an identifier or any keyword) to one engine token
49
- // set, so a lookahead position peeks it as one token rather than one
50
- // alternate per keyword. Both are required: see AGENTS.md.
51
- ;(tn.abnf as Function)(grammarText, {
52
- tag: 'proto',
53
- start: 'proto',
54
- wordKeywords: true,
55
- tokenClasses: true,
56
- })
38
+ const Proto = ((tn: Tabnas, _options?: Partial<ProtoOptions>) => {
39
+ // The union grammar, compiled. gen-grammar.js ran @tabnas/abnf over the
40
+ // union text (src/grammar.ts) at build time, with the options this
41
+ // plugin used to pass at every install: `wordKeywords` makes a keyword
42
+ // match as a whole word, and `tokenClasses` compiles `ident` (an
43
+ // identifier or any keyword) to one engine token set, so a lookahead
44
+ // position peeks it as one token rather than one alternate per keyword;
45
+ // both are required (see AGENTS.md). The compiler wrote the CST
46
+ // builders as the engine's own `@node$` / `@capture$` / `@bubble$`
47
+ // builtins, so the file is pure data and installing it loads no
48
+ // compiler. The engine installs a copy: the imported object is shared,
49
+ // and nothing writes to it.
50
+ tn.grammar(COMPILED)
57
51
  // An aggregate value (`option (f) = { a: 1 };`) is recorded as the text
58
52
  // between its braces, which the CST's `src` does not keep: the lexer
59
53
  // drops whitespace and comments. This action reads it from the source
60
54
  // while the brace tokens are to hand; see ./aggregate.ts.
61
55
  tn.rule('constant', (rs: any) => rs.ac(recordAggregate))
62
56
  }) as {
63
- (tn: AnyTabnas, options?: Partial<ProtoOptions>): void
57
+ (tn: Tabnas, options?: Partial<ProtoOptions>): void
64
58
  defaults: ProtoOptions
65
59
  }
66
60
 
@@ -82,7 +76,7 @@ function toDescriptor(cst: any, options?: Partial<ProtoOptions>): FileDescriptor
82
76
  // engine via `const j = new Tabnas().use(Proto)` and call
83
77
  // `toDescriptor(j.parse(src), opts)`.
84
78
  function parse(src: string, options?: Partial<ProtoOptions>): FileDescriptorProto {
85
- const tn = new Tabnas({ rewind: { history: 8192 } }) as AnyTabnas
79
+ const tn = new Tabnas({ rewind: { history: 8192 } })
86
80
  Proto(tn, options)
87
81
  return toDescriptor(tn.parse(src), options)
88
82
  }
@@ -90,7 +84,7 @@ function parse(src: string, options?: Partial<ProtoOptions>): FileDescriptorProt
90
84
  // VERSION is this package's version. It MUST equal package.json "version":
91
85
  // the release orchestrator rewrites both, and test/version.test.ts fails the
92
86
  // build if they drift. Mirrors `const VERSION` in go/proto.go.
93
- const VERSION = '0.6.3'
87
+ const VERSION = '0.6.4'
94
88
 
95
89
  export { Proto, parse, toDescriptor, VERSION }
96
90
  export type { ProtoVersion }