parseman 0.48.1 → 0.50.0

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.
Files changed (83) hide show
  1. package/dist/analysis/commitment.d.ts +2 -1
  2. package/dist/analysis/commitment.d.ts.map +1 -1
  3. package/dist/analysis/diagnostics.js +1931 -861
  4. package/dist/analysis/diagnostics.js.map +3 -3
  5. package/dist/analysis/rebuild.d.ts.map +1 -1
  6. package/dist/cli/index.js +1236 -164
  7. package/dist/cli/index.js.map +3 -3
  8. package/dist/combinators/trivia-skip.d.ts +1 -1
  9. package/dist/combinators/trivia-skip.d.ts.map +1 -1
  10. package/dist/compiler/build-arity.d.ts +16 -0
  11. package/dist/compiler/build-arity.d.ts.map +1 -1
  12. package/dist/compiler/degradation.d.ts +0 -2
  13. package/dist/compiler/degradation.d.ts.map +1 -1
  14. package/dist/compiler/ir-serialize.d.ts.map +1 -1
  15. package/dist/compiler/linker.d.ts.map +1 -1
  16. package/dist/compiler/token-alphabet.d.ts +11 -0
  17. package/dist/compiler/token-alphabet.d.ts.map +1 -1
  18. package/dist/compiler/token-capability.js +185 -20
  19. package/dist/compiler/token-capability.js.map +1 -1
  20. package/dist/cst/capture-buffer.d.ts +5 -1
  21. package/dist/cst/capture-buffer.d.ts.map +1 -1
  22. package/dist/index.js +1354 -278
  23. package/dist/index.js.map +3 -3
  24. package/dist/language-service/index.js +2 -1
  25. package/dist/language-service/index.js.map +1 -1
  26. package/dist/plugin/direct-builder-static.d.ts +20 -0
  27. package/dist/plugin/direct-builder-static.d.ts.map +1 -1
  28. package/dist/plugin/entry-supercompiler.d.ts +48 -0
  29. package/dist/plugin/entry-supercompiler.d.ts.map +1 -0
  30. package/dist/plugin/evaluator.d.ts +13 -0
  31. package/dist/plugin/evaluator.d.ts.map +1 -1
  32. package/dist/plugin/index.d.ts.map +1 -1
  33. package/dist/plugin/index.js +2118 -376
  34. package/dist/plugin/index.js.map +3 -3
  35. package/dist/run/index.js +2 -1
  36. package/dist/run/index.js.map +1 -1
  37. package/dist/spec/index.js +29 -7
  38. package/dist/spec/index.js.map +1 -1
  39. package/dist/table/assemble.d.ts.map +1 -1
  40. package/dist/table/compile-rule-map.d.ts +6 -5
  41. package/dist/table/compile-rule-map.d.ts.map +1 -1
  42. package/dist/table/emit-assembly.d.ts +6 -1
  43. package/dist/table/emit-assembly.d.ts.map +1 -1
  44. package/dist/table/encode.d.ts.map +1 -1
  45. package/dist/table/index.js +1298 -231
  46. package/dist/table/index.js.map +3 -3
  47. package/dist/table/ops.d.ts +3 -2
  48. package/dist/table/ops.d.ts.map +1 -1
  49. package/dist/table/program.d.ts +15 -1
  50. package/dist/table/program.d.ts.map +1 -1
  51. package/dist/table/scalar-terminal.d.ts +30 -0
  52. package/dist/table/scalar-terminal.d.ts.map +1 -1
  53. package/dist/table/site-labels.d.ts +8 -0
  54. package/dist/table/site-labels.d.ts.map +1 -1
  55. package/dist/types.d.ts +8 -2
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/version.d.ts +1 -1
  58. package/package.json +1 -1
  59. package/src/analysis/commitment.ts +19 -8
  60. package/src/analysis/rebuild.ts +1 -0
  61. package/src/combinators/trivia-skip.ts +2 -2
  62. package/src/compiler/build-arity.ts +50 -0
  63. package/src/compiler/degradation.ts +0 -6
  64. package/src/compiler/ir-serialize.ts +17 -3
  65. package/src/compiler/linker.ts +14 -1
  66. package/src/compiler/token-alphabet.ts +322 -28
  67. package/src/cst/capture-buffer.ts +34 -11
  68. package/src/plugin/direct-builder-static.ts +116 -12
  69. package/src/plugin/entry-supercompiler.ts +567 -0
  70. package/src/plugin/evaluator.ts +60 -2
  71. package/src/plugin/index.ts +147 -4
  72. package/src/table/assemble.ts +125 -42
  73. package/src/table/compile-rule-map.ts +8 -7
  74. package/src/table/compile.ts +7 -8
  75. package/src/table/emit-assembly.ts +646 -126
  76. package/src/table/emit.ts +1 -1
  77. package/src/table/encode.ts +132 -7
  78. package/src/table/ops.ts +3 -2
  79. package/src/table/program.ts +44 -3
  80. package/src/table/scalar-terminal.ts +213 -1
  81. package/src/table/site-labels.ts +22 -9
  82. package/src/types.ts +1 -1
  83. package/src/version.ts +1 -1
@@ -8,6 +8,13 @@ import { parseSync } from 'oxc-parser'
8
8
  const STATIC_BUILDER_GLOBALS = new Set([
9
9
  'Array', 'Boolean', 'Date', 'JSON', 'Math', 'NaN', 'Number', 'Object', 'String',
10
10
  'Infinity', 'parseFloat', 'parseInt', 'undefined',
11
+ // Frozen intrinsic error constructors. Reducers pervasively `throw new TypeError(…)`;
12
+ // once the statement walker walks a `throw` argument these surface as free names, and
13
+ // refusing them would re-refuse the very productions the block-body lift clears. They
14
+ // carry no closure state, so admitting them cannot make an unanalyzable builder
15
+ // analyzable by accident. A MODULE-SCOPE custom error stays a free name (rescued by
16
+ // provenance or refused) — unchanged.
17
+ 'Error', 'TypeError', 'RangeError', 'SyntaxError',
11
18
  ])
12
19
 
13
20
  type Ast = { type: string; [key: string]: unknown }
@@ -33,30 +40,70 @@ function unwrapCallbackExpression(node: Ast | undefined): Ast | undefined {
33
40
  * AST binding check, never a source-text heuristic: property names and plain
34
41
  * object keys are not lexical reads. The result becomes inert metadata on the
35
42
  * macro-produced node and is enforced later by the runtime IR re-lowerer.
43
+ *
44
+ * Kept as the combined `structural ++ free` list so every existing caller and the
45
+ * standalone unit gate see one flat array. `directBuilderBindings` exposes the
46
+ * split the provenance path needs.
36
47
  */
37
48
  export function directBuilderUnsupportedBindings(src: string): string[] {
49
+ const r = directBuilderBindings(src)
50
+ return [...r.structural, ...r.free]
51
+ }
52
+
53
+ /**
54
+ * The analysis, SPLIT into two kinds of unsupported binding:
55
+ *
56
+ * - `structural` — a refusal no provenance can rescue: an un-analyzable node
57
+ * kind, a non-Identifier parameter, `this` / `arguments`, an async or generator
58
+ * reducer. These fail closed and fall back to the interpreter.
59
+ * - `free` — a plain lexical read of a name declared OUTSIDE the builder. Such a
60
+ * name is a refusal on its own, but it CAN be re-bound in a downstream module if
61
+ * that module re-emits the import it came from. The evaluator resolves each free
62
+ * name against the authoring module's imports: one that resolves is carried as
63
+ * import provenance; one that does not stays a refusal.
64
+ */
65
+ export function directBuilderBindings(src: string): { structural: string[]; free: string[] } {
38
66
  let init: Ast | undefined
39
67
  try {
40
68
  const parsed = parseSync('parseman-direct-builder.ts', `const _direct = (${src})`)
41
- if (parsed.errors.length > 0) return ['invalid callback source']
69
+ if (parsed.errors.length > 0) return { structural: ['invalid callback source'], free: [] }
42
70
  const program = parsed.program as unknown as Ast
43
- const statement = (program.body as Ast[] | undefined)?.[0]
44
- const declaration = (statement?.declarations as Ast[] | undefined)?.[0]
71
+ const statementNode = (program.body as Ast[] | undefined)?.[0]
72
+ const declaration = (statementNode?.declarations as Ast[] | undefined)?.[0]
45
73
  init = unwrapCallbackExpression(declaration?.init as Ast | undefined)
46
74
  } catch {
47
- return ['invalid callback source']
75
+ return { structural: ['invalid callback source'], free: [] }
48
76
  }
49
- if (init?.type !== 'ArrowFunctionExpression' || !Array.isArray(init.params)) return ['unsupported callback shape']
77
+ // A direct builder is an arrow OR a resolved `function` reducer (a bare reference
78
+ // to a top-level `function foldOperation(…) {…}` resolves to a FunctionExpression
79
+ // here). Both inline verbatim into the fused table. An async or generator reducer
80
+ // is NOT a pure synchronous builder and stays refused.
81
+ if (init === undefined) return { structural: ['unsupported callback shape'], free: [] }
82
+ const isCallable = init.type === 'ArrowFunctionExpression'
83
+ || init.type === 'FunctionExpression'
84
+ || init.type === 'FunctionDeclaration'
85
+ if (!isCallable || !Array.isArray(init.params)) return { structural: ['unsupported callback shape'], free: [] }
86
+ if (init.async === true || init.generator === true) return { structural: ['unsupported callback shape'], free: [] }
50
87
  const allowed = new Set(STATIC_BUILDER_GLOBALS)
51
88
  for (const param of init.params as Ast[]) {
52
- if (param.type !== 'Identifier' || typeof param.name !== 'string') return ['unsupported parameter pattern']
89
+ if (param.type !== 'Identifier' || typeof param.name !== 'string') return { structural: ['unsupported parameter pattern'], free: [] }
53
90
  allowed.add(param.name)
54
91
  }
55
- const unsupported = new Set<string>()
56
- const reportUnsupportedNode = (ast: Ast): void => { unsupported.add(`unsupported ${ast.type}`) }
92
+ // A named function expression binds its own name inside its body (recursion), so
93
+ // an inlined `function foldOperation(…) { … foldOperation(…) … }` is self-contained.
94
+ const selfName = astChild(init.id)
95
+ if (selfName?.type === 'Identifier' && typeof selfName.name === 'string') allowed.add(selfName.name)
96
+
97
+ const structural = new Set<string>()
98
+ const free = new Set<string>()
99
+ const reportUnsupportedNode = (ast: Ast): void => { structural.add(`unsupported ${ast.type}`) }
57
100
  const read = (ast: Ast, allowedNames: ReadonlySet<string>): void => {
58
101
  if (typeof ast.name === 'string' && allowedNames.has(ast.name)) return
59
- unsupported.add(typeof ast.name === 'string' ? ast.name : 'identifier')
102
+ // `arguments` is a function-only binding that no import can supply; refuse it
103
+ // structurally rather than letting it masquerade as a rescuable free name.
104
+ if (ast.name === 'arguments') { structural.add('unsupported arguments'); return }
105
+ if (typeof ast.name === 'string') free.add(ast.name)
106
+ else structural.add('unsupported identifier')
60
107
  }
61
108
  const expression = (node: unknown, allowedNames: ReadonlySet<string>): void => {
62
109
  const ast = astChild(node)
@@ -89,14 +136,71 @@ export function directBuilderUnsupportedBindings(src: string): string[] {
89
136
  if (param.type !== 'Identifier' || typeof param.name !== 'string') { reportUnsupportedNode(param); continue }
90
137
  nested.add(param.name)
91
138
  }
92
- if (astChild(ast.body)?.type === 'BlockStatement') { reportUnsupportedNode(astChild(ast.body)!); return }
139
+ // A nested arrow with a block body is carried as source and inlined verbatim,
140
+ // exactly like the top-level builder — walk it, do not refuse it.
141
+ const nestedBody = astChild(ast.body)
142
+ if (nestedBody?.type === 'BlockStatement') { statement(nestedBody, nested); return }
93
143
  expression(ast.body, nested)
94
144
  return
95
145
  }
96
146
  default: reportUnsupportedNode(ast); return
97
147
  }
98
148
  }
99
- if (astChild(init.body)?.type === 'BlockStatement') unsupported.add('unsupported BlockStatement')
149
+ // A block body is not a SERIALIZATION limit — `buildSrc` is carried as text and
150
+ // inlined verbatim downstream, so a statement inlines exactly as an expression
151
+ // does. The refusal was an ANALYZER gap: the walker only knew expressions. Walk
152
+ // statements too and the refusal disappears for the shapes grammar reducers use.
153
+ const statement = (node: unknown, names: Set<string>): void => {
154
+ const ast = astChild(node)
155
+ if (!ast) return
156
+ switch (ast.type) {
157
+ case 'VariableDeclaration':
158
+ for (const d of astArray(ast.declarations)) {
159
+ expression(d.init, names)
160
+ const idAst = astChild(d.id)
161
+ if (idAst?.type === 'Identifier' && typeof idAst.name === 'string') names.add(idAst.name)
162
+ else reportUnsupportedNode(idAst ?? ast)
163
+ }
164
+ return
165
+ case 'ReturnStatement': expression(ast.argument, names); return
166
+ case 'ExpressionStatement': expression(ast.expression, names); return
167
+ case 'ThrowStatement': expression(ast.argument, names); return
168
+ case 'IfStatement':
169
+ expression(ast.test, names)
170
+ statement(ast.consequent, new Set(names))
171
+ if (ast.alternate) statement(ast.alternate, new Set(names))
172
+ return
173
+ case 'ForStatement': {
174
+ // The init's bindings (`index`) are visible to test / update / body but must
175
+ // not leak to the enclosing scope — hence the child set.
176
+ const inner = new Set(names)
177
+ if (ast.init) {
178
+ const initAst = astChild(ast.init)
179
+ if (initAst?.type === 'VariableDeclaration') statement(initAst, inner)
180
+ else expression(initAst, inner)
181
+ }
182
+ if (ast.test) expression(ast.test, inner)
183
+ if (ast.update) expression(ast.update, inner)
184
+ statement(ast.body, inner)
185
+ return
186
+ }
187
+ case 'ForOfStatement': case 'ForInStatement': {
188
+ // The iterable (`ast.right`) is read in the OUTER scope; the loop variable is
189
+ // in scope only for the body. A non-declaration target (`for (x of …)`, a
190
+ // destructuring or member target) is refused by the statement walker.
191
+ const inner = new Set(names)
192
+ statement(ast.left, inner)
193
+ expression(ast.right, names)
194
+ statement(ast.body, inner)
195
+ return
196
+ }
197
+ case 'BlockStatement': { const inner = new Set(names); for (const s of astArray(ast.body)) statement(s, inner); return }
198
+ case 'BreakStatement': case 'ContinueStatement': case 'EmptyStatement': return
199
+ default: reportUnsupportedNode(ast); return
200
+ }
201
+ }
202
+ const bodyAst = astChild(init.body)
203
+ if (bodyAst?.type === 'BlockStatement') statement(bodyAst, allowed)
100
204
  else expression(init.body, allowed)
101
- return [...unsupported]
205
+ return { structural: [...structural], free: [...free] }
102
206
  }