@json-schema-engine/compiler 0.0.1

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 (93) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/emit.d.ts +52 -0
  4. package/dist/emit.d.ts.map +1 -0
  5. package/dist/emit.js +166 -0
  6. package/dist/emit.js.map +1 -0
  7. package/dist/explain.d.ts +28 -0
  8. package/dist/explain.d.ts.map +1 -0
  9. package/dist/explain.js +42 -0
  10. package/dist/explain.js.map +1 -0
  11. package/dist/index.d.ts +132 -0
  12. package/dist/index.d.ts.map +1 -0
  13. package/dist/index.js +169 -0
  14. package/dist/index.js.map +1 -0
  15. package/dist/plan.d.ts +83 -0
  16. package/dist/plan.d.ts.map +1 -0
  17. package/dist/plan.js +385 -0
  18. package/dist/plan.js.map +1 -0
  19. package/dist/runtime-compile.d.ts +30 -0
  20. package/dist/runtime-compile.d.ts.map +1 -0
  21. package/dist/runtime-compile.js +29 -0
  22. package/dist/runtime-compile.js.map +1 -0
  23. package/dist/runtime.d.ts +157 -0
  24. package/dist/runtime.d.ts.map +1 -0
  25. package/dist/runtime.js +336 -0
  26. package/dist/runtime.js.map +1 -0
  27. package/dist/serialize/apply.d.ts +28 -0
  28. package/dist/serialize/apply.d.ts.map +1 -0
  29. package/dist/serialize/apply.js +211 -0
  30. package/dist/serialize/apply.js.map +1 -0
  31. package/dist/serialize/context.d.ts +143 -0
  32. package/dist/serialize/context.d.ts.map +1 -0
  33. package/dist/serialize/context.js +93 -0
  34. package/dist/serialize/context.js.map +1 -0
  35. package/dist/serialize/expressions.d.ts +7 -0
  36. package/dist/serialize/expressions.d.ts.map +1 -0
  37. package/dist/serialize/expressions.js +177 -0
  38. package/dist/serialize/expressions.js.map +1 -0
  39. package/dist/serialize/guards.d.ts +7 -0
  40. package/dist/serialize/guards.d.ts.map +1 -0
  41. package/dist/serialize/guards.js +19 -0
  42. package/dist/serialize/guards.js.map +1 -0
  43. package/dist/serialize/index.d.ts +7 -0
  44. package/dist/serialize/index.d.ts.map +1 -0
  45. package/dist/serialize/index.js +266 -0
  46. package/dist/serialize/index.js.map +1 -0
  47. package/dist/serialize/keywords.d.ts +32 -0
  48. package/dist/serialize/keywords.d.ts.map +1 -0
  49. package/dist/serialize/keywords.js +131 -0
  50. package/dist/serialize/keywords.js.map +1 -0
  51. package/dist/serialize/messages.d.ts +36 -0
  52. package/dist/serialize/messages.d.ts.map +1 -0
  53. package/dist/serialize/messages.js +100 -0
  54. package/dist/serialize/messages.js.map +1 -0
  55. package/dist/serialize/names.d.ts +47 -0
  56. package/dist/serialize/names.d.ts.map +1 -0
  57. package/dist/serialize/names.js +115 -0
  58. package/dist/serialize/names.js.map +1 -0
  59. package/dist/serialize/spans.d.ts +34 -0
  60. package/dist/serialize/spans.d.ts.map +1 -0
  61. package/dist/serialize/spans.js +61 -0
  62. package/dist/serialize/spans.js.map +1 -0
  63. package/dist/serialize/statements.d.ts +16 -0
  64. package/dist/serialize/statements.d.ts.map +1 -0
  65. package/dist/serialize/statements.js +396 -0
  66. package/dist/serialize/statements.js.map +1 -0
  67. package/dist/serialize/unit.d.ts +8 -0
  68. package/dist/serialize/unit.d.ts.map +1 -0
  69. package/dist/serialize/unit.js +107 -0
  70. package/dist/serialize/unit.js.map +1 -0
  71. package/dist/standalone.d.ts +24 -0
  72. package/dist/standalone.d.ts.map +1 -0
  73. package/dist/standalone.js +166 -0
  74. package/dist/standalone.js.map +1 -0
  75. package/package.json +38 -0
  76. package/src/emit.ts +196 -0
  77. package/src/explain.ts +67 -0
  78. package/src/index.ts +366 -0
  79. package/src/plan.ts +496 -0
  80. package/src/runtime-compile.ts +90 -0
  81. package/src/runtime.ts +599 -0
  82. package/src/serialize/apply.ts +251 -0
  83. package/src/serialize/context.ts +161 -0
  84. package/src/serialize/expressions.ts +202 -0
  85. package/src/serialize/guards.ts +20 -0
  86. package/src/serialize/index.ts +432 -0
  87. package/src/serialize/keywords.ts +144 -0
  88. package/src/serialize/messages.ts +120 -0
  89. package/src/serialize/names.ts +136 -0
  90. package/src/serialize/spans.ts +88 -0
  91. package/src/serialize/statements.ts +531 -0
  92. package/src/serialize/unit.ts +118 -0
  93. package/src/standalone.ts +187 -0
@@ -0,0 +1,136 @@
1
+ // Emitted identifier names and IR scans shared by the serializer's modules.
2
+
3
+ import {
4
+ type LowerProduceValue,
5
+ type LowerStmt,
6
+ } from "@json-schema-engine/core";
7
+ import { type CodeChunk, id } from "../emit.js";
8
+ import type { EmitOutput, UnitContext } from "./context.js";
9
+
10
+ export const V = id("v"); // instance parameter
11
+ export const D = id("d"); // depth parameter
12
+ export const S = id("s"); // dynamic-scope parameter
13
+ export const R = id("R"); // runtime closure
14
+ export const T = id("T"); // interpreted-target table
15
+ export const EV = id("ev"); // runtime coverage channel (region emission, phase B)
16
+ export const EP = id("ep"); // evaluation-path prefix parameter (list emission)
17
+ export const IP = id("ip"); // instance-pointer prefix parameter (list emission)
18
+ export const ERRS = id("errs"); // error channel (list emission)
19
+ export const ANNS = id("anns"); // annotation channel (annotation mode)
20
+ export const ST = id("st"); // per-evaluation trace state (trace emission)
21
+ export const TP = id("tp"); // parent application node parameter (trace emission)
22
+ export const TN = id("tn"); // this application's node (trace emission)
23
+
24
+ /** Which channels an emission threads through every application. */
25
+ export interface ChannelShape {
26
+ output: EmitOutput;
27
+ annMode: boolean;
28
+ trace: boolean;
29
+ }
30
+
31
+ export const shapeOf = (ctx: UnitContext): ChannelShape => ({
32
+ output: ctx.output,
33
+ annMode: ctx.annMode,
34
+ trace: ctx.trace,
35
+ });
36
+
37
+ /**
38
+ * The arguments every application carries after the instance, depth, and
39
+ * scope: in list emission the two location prefixes and the record
40
+ * channels (the trace state and parent node under trace emission), and the
41
+ * coverage channel for an in-place region call. Unit signatures, unit
42
+ * calls, trampolines, and the root call all build from here, so the
43
+ * variants cannot drift apart. `locate` is called only in list emission —
44
+ * a flag-mode apply never computes its prefixes.
45
+ */
46
+ export function channelArgs(
47
+ shape: ChannelShape,
48
+ locate: () => [CodeChunk, CodeChunk],
49
+ parent: CodeChunk,
50
+ ev: boolean,
51
+ ): CodeChunk[] {
52
+ const args: CodeChunk[] = [];
53
+ if (shape.output === "list") {
54
+ args.push(...locate());
55
+ if (shape.trace) args.push(ST, parent);
56
+ else {
57
+ args.push(ERRS);
58
+ if (shape.annMode) args.push(ANNS);
59
+ }
60
+ }
61
+ if (ev) args.push(EV);
62
+ return args;
63
+ }
64
+
65
+ /** The interpreter trampoline an emission calls for an interpreted target. */
66
+ export function fragHelper(
67
+ shape: ChannelShape,
68
+ inPlaceRegion: boolean,
69
+ ): CodeChunk {
70
+ if (shape.output !== "list") return id(inPlaceRegion ? "h_fragc" : "h_frag");
71
+ if (shape.trace) return id("h_fragt");
72
+ return id(shape.annMode ? "h_fragla" : "h_fragl");
73
+ }
74
+
75
+ export const unitFn = (index: number): CodeChunk => id("u" + String(index));
76
+ // Region-variant of a unit function: same body with the trailing coverage
77
+ // channel threaded (COMPILED-CONSUMERS.md phase B). A distinct name so a unit
78
+ // can carry both a plain and a channel-threaded emission.
79
+ export const unitFnRegion = (index: number): CodeChunk =>
80
+ id("u" + String(index) + "c");
81
+ export const bindingVar = (n: number): CodeChunk => id("b" + String(n));
82
+ export const regexConst = (i: number): CodeChunk => id("r" + String(i));
83
+ export const formatConst = (i: number): CodeChunk => id("fmt" + String(i));
84
+ export const counterVar = (n: number): CodeChunk => id("c" + String(n));
85
+ export const foldVar = (n: number): CodeChunk => id("f" + String(n));
86
+
87
+ /** First `produce` node in a keyword's lowered statement list (searched into blocks). */
88
+ export function findProduce(
89
+ stmts: readonly LowerStmt[],
90
+ ): LowerProduceValue | null {
91
+ for (const stmt of stmts) {
92
+ switch (stmt.kind) {
93
+ case "produce":
94
+ return stmt.value;
95
+ case "if": {
96
+ const t = findProduce(stmt.then);
97
+ if (t) return t;
98
+ if (stmt.else) {
99
+ const e = findProduce(stmt.else);
100
+ if (e) return e;
101
+ }
102
+ break;
103
+ }
104
+ case "forEachKey":
105
+ case "forEachIndex": {
106
+ const b = findProduce(stmt.body);
107
+ if (b) return b;
108
+ break;
109
+ }
110
+ default:
111
+ break;
112
+ }
113
+ }
114
+ return null;
115
+ }
116
+
117
+ /** True when a keyword's lowered statement list contains an `annotate` node (searched into blocks). */
118
+ export function hasAnnotate(stmts: readonly LowerStmt[]): boolean {
119
+ for (const stmt of stmts) {
120
+ switch (stmt.kind) {
121
+ case "annotate":
122
+ return true;
123
+ case "if":
124
+ if (hasAnnotate(stmt.then) || (stmt.else && hasAnnotate(stmt.else)))
125
+ return true;
126
+ break;
127
+ case "forEachKey":
128
+ case "forEachIndex":
129
+ if (hasAnnotate(stmt.body)) return true;
130
+ break;
131
+ default:
132
+ break;
133
+ }
134
+ }
135
+ return false;
136
+ }
@@ -0,0 +1,88 @@
1
+ // Channel spans at application boundaries: the annotation and coverage
2
+ // channels mark before an application and truncate when it fails (rule 3).
3
+
4
+ import { type CodeChunk, id, join, js } from "../emit.js";
5
+ import { ANNS, EV, ST, TN } from "./names.js";
6
+ import { UnitContext } from "./context.js";
7
+
8
+ /** One marked channel: the annotation channel or the coverage channel. */
9
+ export interface Span {
10
+ kind: "anns" | "ev";
11
+ m: CodeChunk;
12
+ }
13
+
14
+ /** The annotation channel's current length: the value a span mark takes. */
15
+ export function annsLength(ctx: UnitContext): CodeChunk {
16
+ return ctx.trace ? js`${ST}.anns.length` : js`${ANNS}.length`;
17
+ }
18
+
19
+ /**
20
+ * Drop the annotations pushed since mark `m` (a failed application's).
21
+ * Trace emission routes the cut through the runtime, which discards or
22
+ * retains them by the artifact's level.
23
+ */
24
+ export function annsCut(ctx: UnitContext, m: CodeChunk): CodeChunk {
25
+ return ctx.trace
26
+ ? js`${id("h_cutA")}(${ST}, ${m});`
27
+ : js`${ANNS}.length = ${m};`;
28
+ }
29
+
30
+ /** Push one annotation unit; trace emission records the application with it. */
31
+ export function annsPush(ctx: UnitContext, unit: CodeChunk): CodeChunk {
32
+ return ctx.trace
33
+ ? js`${id("h_ann")}(${ST}, ${TN}, ${unit});`
34
+ : js`${ANNS}.push(${unit});`;
35
+ }
36
+
37
+ /**
38
+ * The channel spans active at an application boundary: `anns` in annotation
39
+ * mode, `ev` in region emission, both when composed, none otherwise. errs
40
+ * is not one of them: a failed application keeps its errors (they become
41
+ * irrelevant only when an enclosing KEYWORD accepts, draft-03 §12.2), so
42
+ * error truncation is keyword-scoped — see errMark() — not per branch.
43
+ */
44
+ export function channelSpans(ctx: UnitContext, includeEv = true): Span[] {
45
+ const spans: Span[] = [];
46
+ if (ctx.annMode) {
47
+ spans.push({ kind: "anns", m: id("m" + String(ctx.counters.temp++)) });
48
+ }
49
+ if (ctx.regionMode && includeEv) {
50
+ spans.push({ kind: "ev", m: id("m" + String(ctx.counters.temp++)) });
51
+ }
52
+ return spans;
53
+ }
54
+
55
+ export function spanDecls(ctx: UnitContext, spans: Span[]): CodeChunk {
56
+ return join(
57
+ " ",
58
+ spans.map(({ kind, m }) =>
59
+ kind === "anns"
60
+ ? js`const ${m} = ${annsLength(ctx)};`
61
+ : js`const ${m} = ${EV}.length;`,
62
+ ),
63
+ );
64
+ }
65
+
66
+ export function spanResets(ctx: UnitContext, spans: Span[]): CodeChunk {
67
+ return join(
68
+ " ",
69
+ spans.map(({ kind, m }) =>
70
+ kind === "anns" ? annsCut(ctx, m) : js`${EV}.length = ${m};`,
71
+ ),
72
+ );
73
+ }
74
+
75
+ /**
76
+ * One grouped-fold branch: run `call`, apply `hit` on success, truncate the
77
+ * active channel spans on failure (a failed branch's records and
78
+ * coverage discard; a passing branch's merge — channel rule 3 per branch).
79
+ */
80
+ export function branchSpan(
81
+ ctx: UnitContext,
82
+ call: CodeChunk,
83
+ hit: CodeChunk,
84
+ ): CodeChunk {
85
+ const spans = channelSpans(ctx);
86
+ if (spans.length === 0) return js`if (${call}) { ${hit} }`;
87
+ return js`{ ${spanDecls(ctx, spans)} if (${call}) { ${hit} } else { ${spanResets(ctx, spans)} } }`;
88
+ }