behavior-contracts 0.1.3 → 0.2.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.
- package/README.md +8 -2
- package/dist/authoring.d.ts +202 -0
- package/dist/authoring.d.ts.map +1 -0
- package/dist/authoring.js +787 -0
- package/dist/authoring.js.map +1 -0
- package/dist/behavior.d.ts +201 -0
- package/dist/behavior.d.ts.map +1 -0
- package/dist/behavior.js +373 -0
- package/dist/behavior.js.map +1 -0
- package/dist/builder.d.ts +154 -0
- package/dist/builder.d.ts.map +1 -0
- package/dist/builder.js +574 -0
- package/dist/builder.js.map +1 -0
- package/dist/generator/core.d.ts +89 -0
- package/dist/generator/core.d.ts.map +1 -0
- package/dist/generator/core.js +124 -0
- package/dist/generator/core.js.map +1 -0
- package/dist/generator/emit-go.d.ts +19 -0
- package/dist/generator/emit-go.d.ts.map +1 -0
- package/dist/generator/emit-go.js +79 -0
- package/dist/generator/emit-go.js.map +1 -0
- package/dist/generator/emit-php.d.ts +20 -0
- package/dist/generator/emit-php.d.ts.map +1 -0
- package/dist/generator/emit-php.js +76 -0
- package/dist/generator/emit-php.js.map +1 -0
- package/dist/generator/emit-python.d.ts +10 -0
- package/dist/generator/emit-python.d.ts.map +1 -0
- package/dist/generator/emit-python.js +75 -0
- package/dist/generator/emit-python.js.map +1 -0
- package/dist/generator/emit-rust.d.ts +25 -0
- package/dist/generator/emit-rust.d.ts.map +1 -0
- package/dist/generator/emit-rust.js +125 -0
- package/dist/generator/emit-rust.js.map +1 -0
- package/dist/generator/emit-typescript.d.ts +11 -0
- package/dist/generator/emit-typescript.d.ts.map +1 -0
- package/dist/generator/emit-typescript.js +68 -0
- package/dist/generator/emit-typescript.js.map +1 -0
- package/dist/generator/fingerprint.d.ts +14 -0
- package/dist/generator/fingerprint.d.ts.map +1 -0
- package/dist/generator/fingerprint.js +74 -0
- package/dist/generator/fingerprint.js.map +1 -0
- package/dist/generator/index.d.ts +9 -0
- package/dist/generator/index.d.ts.map +1 -0
- package/dist/generator/index.js +25 -0
- package/dist/generator/index.js.map +1 -0
- package/dist/generator/literal.d.ts +8 -0
- package/dist/generator/literal.d.ts.map +1 -0
- package/dist/generator/literal.js +191 -0
- package/dist/generator/literal.js.map +1 -0
- package/dist/guard.d.ts +18 -0
- package/dist/guard.d.ts.map +1 -1
- package/dist/guard.js +130 -0
- package/dist/guard.js.map +1 -1
- package/dist/index.d.ts +14 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +15 -2
- package/dist/index.js.map +1 -1
- package/dist/plan.d.ts +36 -0
- package/dist/plan.d.ts.map +1 -1
- package/dist/plan.js +152 -14
- package/dist/plan.js.map +1 -1
- package/package.json +4 -1
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import type { ComponentGraphIR } from "../behavior.js";
|
|
2
|
+
export type GeneratorFailureCode = "INPUT_NOT_PORTABLE_IR" | "UNSUPPORTED_IR_VERSION" | "UNSUPPORTED_EXPR_VERSION" | "EMPTY_IR" | "DUPLICATE_COMPONENT" | "UNKNOWN_LANGUAGE";
|
|
3
|
+
export declare class GeneratorFailure extends Error {
|
|
4
|
+
code: GeneratorFailureCode;
|
|
5
|
+
constructor(code: GeneratorFailureCode, message: string);
|
|
6
|
+
}
|
|
7
|
+
/** 生成時に emitter へ渡される言語中立コンテキスト(検証済み)。 */
|
|
8
|
+
export interface EmitContext {
|
|
9
|
+
/** 検証済み可搬 IR(構造は入力のまま — キー順保存)。 */
|
|
10
|
+
ir: ComponentGraphIR;
|
|
11
|
+
/** source IR の fingerprint(`"fnv1a64:<16hex>"`)。 */
|
|
12
|
+
fingerprint: string;
|
|
13
|
+
/** 生成時 SPEC_VERSIONS のうち実行経路が依存する版(焼き込み対象)。 */
|
|
14
|
+
specVersions: {
|
|
15
|
+
behavior: number;
|
|
16
|
+
expression: number;
|
|
17
|
+
plan: number;
|
|
18
|
+
};
|
|
19
|
+
/** IR 内の component 名(宣言順)。 */
|
|
20
|
+
componentNames: string[];
|
|
21
|
+
/** runtime-core を import するモジュール指定子(emitter の既定を上書き可)。 */
|
|
22
|
+
runtimeImport: string;
|
|
23
|
+
}
|
|
24
|
+
/** 言語 emitter プラグイン。DSL 非依存の EmitContext からモジュール全文を emit する。 */
|
|
25
|
+
export interface EmitterPlugin {
|
|
26
|
+
/** 言語識別子(`generateModule` の `language`)。 */
|
|
27
|
+
language: string;
|
|
28
|
+
/** 生成ファイルの拡張子(`.ts` / `.py` …)。 */
|
|
29
|
+
fileExtension: string;
|
|
30
|
+
/** runtime-core の既定 import 指定子(`"behavior-contracts"` / `"behavior_contracts"`)。 */
|
|
31
|
+
defaultRuntimeImport: string;
|
|
32
|
+
/**
|
|
33
|
+
* 推奨ファイル名の上書き(省略時は `behaviors.generated` + fileExtension)。
|
|
34
|
+
* Rust のように `.` 区切りがモジュール名として使えない言語が指定する。
|
|
35
|
+
*/
|
|
36
|
+
filenameHint?: string;
|
|
37
|
+
/** モジュール全文を emit(決定的であること)。 */
|
|
38
|
+
emit(ctx: EmitContext): string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* registerEmitter — 言語 emitter を登録する(consumer / 後続 SP の言語追加 seam)。
|
|
42
|
+
* 同名言語の再登録は上書き(テスト・差し替え用)。
|
|
43
|
+
*/
|
|
44
|
+
export declare function registerEmitter(plugin: EmitterPlugin): void;
|
|
45
|
+
/** 登録済み言語の一覧(宣言順不定 — 表示用途はソートして使う)。 */
|
|
46
|
+
export declare function registeredLanguages(): string[];
|
|
47
|
+
export interface GenerateOptions {
|
|
48
|
+
/** 生成先言語(登録済み emitter の識別子。SP1: "typescript" | "python")。 */
|
|
49
|
+
language: string;
|
|
50
|
+
/**
|
|
51
|
+
* runtime-core を import するモジュール指定子。省略時は emitter の既定
|
|
52
|
+
* (npm/PyPI パッケージ名)。テスト・vendored 配置ではソースへの相対パス等を渡す。
|
|
53
|
+
* 生成コードの決定性は指定子込み(同一 IR + 同一オプション → byte-identical)。
|
|
54
|
+
*/
|
|
55
|
+
runtimeImport?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface GeneratedModule {
|
|
58
|
+
/** 生成言語。 */
|
|
59
|
+
language: string;
|
|
60
|
+
/** モジュール全文(実行可能なソースコード)。 */
|
|
61
|
+
code: string;
|
|
62
|
+
/** source IR の fingerprint(生成コードにも定数として焼き込み済み)。 */
|
|
63
|
+
fingerprint: string;
|
|
64
|
+
/** 焼き込んだ spec versions。 */
|
|
65
|
+
specVersions: {
|
|
66
|
+
behavior: number;
|
|
67
|
+
expression: number;
|
|
68
|
+
plan: number;
|
|
69
|
+
};
|
|
70
|
+
/** bind で公開される component 名(IR 宣言順)。 */
|
|
71
|
+
componentNames: string[];
|
|
72
|
+
/** 推奨ファイル名(`behaviors.generated` + 言語拡張子)。 */
|
|
73
|
+
filenameHint: string;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* generateModule — 可搬 component-graph IR から言語ネイティブの実行モジュールを生成する。
|
|
77
|
+
*
|
|
78
|
+
* 生成物の形(全言語共通の契約):
|
|
79
|
+
* - IR がネイティブリテラル定数として埋め込まれる(実行時 JSON パースなし)。
|
|
80
|
+
* - `EXPECTED_SPEC_VERSIONS` / `IR_FINGERPRINT` 定数 + ロード時 fail-closed 検査。
|
|
81
|
+
* - `bind(handlers)`(TS はさらに `bindAsync`): handler 注入を受けて
|
|
82
|
+
* `{component名: (input) => runBehavior(IR, handlers, input, name)}` を返す薄い束ね。
|
|
83
|
+
* **handler は常に境界注入**であり、生成対象にならない(C4)。
|
|
84
|
+
*
|
|
85
|
+
* @throws {GeneratorFailure} 入力が可搬 IR でない / 版超過 / 未知言語(fail-closed)。
|
|
86
|
+
* @throws {PortabilityError} IR が Portability Guard に違反するとき。
|
|
87
|
+
*/
|
|
88
|
+
export declare function generateModule(ir: unknown, options: GenerateOptions): GeneratedModule;
|
|
89
|
+
//# sourceMappingURL=core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.d.ts","sourceRoot":"","sources":["../../src/generator/core.ts"],"names":[],"mappings":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAGvD,MAAM,MAAM,oBAAoB,GAC5B,uBAAuB,GACvB,wBAAwB,GACxB,0BAA0B,GAC1B,UAAU,GACV,qBAAqB,GACrB,kBAAkB,CAAC;AAEvB,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,IAAI,EAAE,oBAAoB,CAAC;gBACf,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,MAAM;CAKxD;AAOD,0CAA0C;AAC1C,MAAM,WAAW,WAAW;IAC1B,mCAAmC;IACnC,EAAE,EAAE,gBAAgB,CAAC;IACrB,oDAAoD;IACpD,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,8BAA8B;IAC9B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,gEAAgE;AAChE,MAAM,WAAW,aAAa;IAC5B,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC;IACjB,mCAAmC;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,oBAAoB,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+BAA+B;IAC/B,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAAC;CAChC;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAE3D;AAED,uCAAuC;AACvC,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAE9C;AA8CD,MAAM,WAAW,eAAe;IAC9B,6DAA6D;IAC7D,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,YAAY;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,WAAW,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,YAAY,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,uCAAuC;IACvC,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,8CAA8C;IAC9C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CA+BrF"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core.ts — SCP Runtime Code Generation Layer: 共通 Generator 本体(bc#13 SP1)。
|
|
3
|
+
*
|
|
4
|
+
* docs/scp-ir-architecture.md §7.2–§7.4 の規範実装:
|
|
5
|
+
* - **入力は可搬 IR のみ**(§5 の component-graph ドキュメント。ソース/内部 IR は拒否 —
|
|
6
|
+
* concept.md §5.6 Generator Interface)。生成時に envelope(irVersion / exprVersion)と
|
|
7
|
+
* assertPortableComponentGraph を fail-closed で検査する。
|
|
8
|
+
* - **DSL 非依存**: components[] / Expression IR / plan という DSL 不変部(§7.4)だけを
|
|
9
|
+
* 消費する。DSL 固有部(catalog 実装・handler)は生成コードに載らず、実行時に
|
|
10
|
+
* `IR + {effects,config,hooks}` 境界で注入される(concept.md §4.4)。
|
|
11
|
+
* - **実行ロジックを再実装しない**: 生成コードは事前構築済みネイティブリテラルを既存の
|
|
12
|
+
* runtime-core API(runBehavior / runBehaviorAsync / run_behavior)へ渡す薄い束ね
|
|
13
|
+
* (runtime≈0 追加。graphddb #208 の AOT パターンの一般化)。
|
|
14
|
+
* - **決定的**: 同一 IR ドキュメント → byte-identical な生成コード(タイムスタンプ・
|
|
15
|
+
* 絶対パス等の非決定要素を埋め込まない)。
|
|
16
|
+
* - **spec-version / fingerprint 焼き込み**: 生成時の SPEC_VERSIONS(behavior /
|
|
17
|
+
* expression / plan)と source IR の fingerprint を定数として焼き込み、生成モジュールは
|
|
18
|
+
* ロード時に runtime の定数と照合して skew を LOUD reject する(#208 の
|
|
19
|
+
* prepared-artifact 規律)。
|
|
20
|
+
*
|
|
21
|
+
* 経路の恒久併存(§7.2): この codegen 経路(エンドポイント 3)は動的 JSON 経路
|
|
22
|
+
* (エンドポイント 2)を置き換えない。両経路は同一 IR に対して観測等価であることが
|
|
23
|
+
* conformance ゲート(§7.3 — ts/test/codegen-conformance.test.ts)で強制される。
|
|
24
|
+
*/
|
|
25
|
+
import { SPEC_VERSIONS } from "../index.js";
|
|
26
|
+
import { assertPortableComponentGraph } from "../guard.js";
|
|
27
|
+
import { fingerprintComponentGraph } from "./fingerprint.js";
|
|
28
|
+
export class GeneratorFailure extends Error {
|
|
29
|
+
code;
|
|
30
|
+
constructor(code, message) {
|
|
31
|
+
super(message);
|
|
32
|
+
this.code = code;
|
|
33
|
+
this.name = "GeneratorFailure";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function gfail(code, message) {
|
|
37
|
+
throw new GeneratorFailure(code, message);
|
|
38
|
+
}
|
|
39
|
+
const registry = new Map();
|
|
40
|
+
/**
|
|
41
|
+
* registerEmitter — 言語 emitter を登録する(consumer / 後続 SP の言語追加 seam)。
|
|
42
|
+
* 同名言語の再登録は上書き(テスト・差し替え用)。
|
|
43
|
+
*/
|
|
44
|
+
export function registerEmitter(plugin) {
|
|
45
|
+
registry.set(plugin.language, plugin);
|
|
46
|
+
}
|
|
47
|
+
/** 登録済み言語の一覧(宣言順不定 — 表示用途はソートして使う)。 */
|
|
48
|
+
export function registeredLanguages() {
|
|
49
|
+
return [...registry.keys()].sort();
|
|
50
|
+
}
|
|
51
|
+
// ── 入力検証(生成時 fail-closed)────────────────────────────────────────────
|
|
52
|
+
/**
|
|
53
|
+
* 可搬 IR envelope 検査 + Portability Guard。**可搬 component-graph IR 以外は LOUD reject**
|
|
54
|
+
* (graphddb operations.json のような consumer bundle・内部 IR・任意 JSON を黙って
|
|
55
|
+
* 受け付けない)。
|
|
56
|
+
*/
|
|
57
|
+
function validateGeneratorInput(ir) {
|
|
58
|
+
if (ir === null || typeof ir !== "object" || Array.isArray(ir))
|
|
59
|
+
gfail("INPUT_NOT_PORTABLE_IR", "generator input must be a portable component-graph IR document ({irVersion, exprVersion, components[]} — scp-ir-architecture.md §5); got a non-object (fail-closed)");
|
|
60
|
+
const doc = ir;
|
|
61
|
+
if (doc.irVersion === undefined || doc.components === undefined)
|
|
62
|
+
gfail("INPUT_NOT_PORTABLE_IR", "generator input must be a portable component-graph IR document ({irVersion, exprVersion, components[]}); the codegen path consumes portable IR ONLY — never source/internal IR or consumer bundles (fail-closed)");
|
|
63
|
+
if (doc.irVersion !== 1)
|
|
64
|
+
gfail("UNSUPPORTED_IR_VERSION", `irVersion ${String(doc.irVersion)} is not supported (supported: 1) (fail-closed)`);
|
|
65
|
+
const exprVersion = doc.exprVersion;
|
|
66
|
+
if (typeof exprVersion !== "number" || !Number.isInteger(exprVersion) || exprVersion < 1)
|
|
67
|
+
gfail("INPUT_NOT_PORTABLE_IR", `exprVersion must be a positive integer, got ${String(exprVersion)} (fail-closed)`);
|
|
68
|
+
if (exprVersion > SPEC_VERSIONS.expression)
|
|
69
|
+
gfail("UNSUPPORTED_EXPR_VERSION", `exprVersion ${exprVersion} exceeds supported expression version ${SPEC_VERSIONS.expression} (fail-closed)`);
|
|
70
|
+
// Portability Guard(P0-2): 関数残存・非文字列 component 参照・未知 operator を静的拒否。
|
|
71
|
+
assertPortableComponentGraph(ir);
|
|
72
|
+
const components = doc.components;
|
|
73
|
+
if (components.length === 0)
|
|
74
|
+
gfail("EMPTY_IR", "IR has no components — nothing to generate (fail-closed)");
|
|
75
|
+
const seen = new Set();
|
|
76
|
+
for (const c of components) {
|
|
77
|
+
if (seen.has(c.name))
|
|
78
|
+
gfail("DUPLICATE_COMPONENT", `component name '${c.name}' appears more than once — bind() keys must be unique (fail-closed)`);
|
|
79
|
+
seen.add(c.name);
|
|
80
|
+
}
|
|
81
|
+
return ir;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* generateModule — 可搬 component-graph IR から言語ネイティブの実行モジュールを生成する。
|
|
85
|
+
*
|
|
86
|
+
* 生成物の形(全言語共通の契約):
|
|
87
|
+
* - IR がネイティブリテラル定数として埋め込まれる(実行時 JSON パースなし)。
|
|
88
|
+
* - `EXPECTED_SPEC_VERSIONS` / `IR_FINGERPRINT` 定数 + ロード時 fail-closed 検査。
|
|
89
|
+
* - `bind(handlers)`(TS はさらに `bindAsync`): handler 注入を受けて
|
|
90
|
+
* `{component名: (input) => runBehavior(IR, handlers, input, name)}` を返す薄い束ね。
|
|
91
|
+
* **handler は常に境界注入**であり、生成対象にならない(C4)。
|
|
92
|
+
*
|
|
93
|
+
* @throws {GeneratorFailure} 入力が可搬 IR でない / 版超過 / 未知言語(fail-closed)。
|
|
94
|
+
* @throws {PortabilityError} IR が Portability Guard に違反するとき。
|
|
95
|
+
*/
|
|
96
|
+
export function generateModule(ir, options) {
|
|
97
|
+
const plugin = registry.get(options.language);
|
|
98
|
+
if (!plugin)
|
|
99
|
+
gfail("UNKNOWN_LANGUAGE", `no emitter registered for language '${options.language}' (registered: ${registeredLanguages().join(", ")}) (fail-closed)`);
|
|
100
|
+
const validated = validateGeneratorInput(ir);
|
|
101
|
+
const fingerprint = fingerprintComponentGraph(validated);
|
|
102
|
+
const specVersions = {
|
|
103
|
+
behavior: SPEC_VERSIONS.behavior,
|
|
104
|
+
expression: SPEC_VERSIONS.expression,
|
|
105
|
+
plan: SPEC_VERSIONS.plan,
|
|
106
|
+
};
|
|
107
|
+
const componentNames = validated.components.map((c) => c.name);
|
|
108
|
+
const ctx = {
|
|
109
|
+
ir: validated,
|
|
110
|
+
fingerprint,
|
|
111
|
+
specVersions,
|
|
112
|
+
componentNames,
|
|
113
|
+
runtimeImport: options.runtimeImport ?? plugin.defaultRuntimeImport,
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
language: plugin.language,
|
|
117
|
+
code: plugin.emit(ctx),
|
|
118
|
+
fingerprint,
|
|
119
|
+
specVersions,
|
|
120
|
+
componentNames,
|
|
121
|
+
filenameHint: plugin.filenameHint ?? `behaviors.generated${plugin.fileExtension}`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"core.js","sourceRoot":"","sources":["../../src/generator/core.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emit-go.ts — Go emitter(共通 Generator, bc#13 SP2)。
|
|
3
|
+
*
|
|
4
|
+
* 生成物: 可搬 IR を **JNode ネイティブ複合リテラル**(`dslcontracts.JObjOf` /
|
|
5
|
+
* `[]dslcontracts.JNode` / `json.Number` — RunBehavior が消費する JNode ドメイン。
|
|
6
|
+
* dynamic 経路の ParseJSONOrdered 出力と同型)として埋め込み、runtime-core の
|
|
7
|
+
* `RunBehavior` に handler 注入で渡す薄い accessor(`Bind`)を公開する .go ファイル。
|
|
8
|
+
*
|
|
9
|
+
* ロード時検査は **init 時**(package import 時): spec-version skew / fingerprint
|
|
10
|
+
* mismatch は `init()` の panic で LOUD reject — 生成 package を import しただけで
|
|
11
|
+
* プロセスが起動不能になる(#208 prepared-artifact 規律。first-Bind 遅延ではなく
|
|
12
|
+
* init を選ぶ: Go では import 副作用が慣用で、検査漏れの窓が生じない)。
|
|
13
|
+
*
|
|
14
|
+
* 出力は gofmt-clean(tab インデント・trailing comma)— CI の gofmt -l ゲートと
|
|
15
|
+
* fixture byte-drift ゲートの両立のため、emitter 出力自体が gofmt 不動点である。
|
|
16
|
+
*/
|
|
17
|
+
import type { EmitterPlugin } from "./core.js";
|
|
18
|
+
export declare const goEmitter: EmitterPlugin;
|
|
19
|
+
//# sourceMappingURL=emit-go.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-go.d.ts","sourceRoot":"","sources":["../../src/generator/emit-go.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,WAAW,CAAC;AA2E5D,eAAO,MAAM,SAAS,EAAE,aAKvB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { emitDocLiteral } from "./literal.js";
|
|
2
|
+
function emit(ctx) {
|
|
3
|
+
const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
|
|
4
|
+
const names = componentNames.map((n) => JSON.stringify(n)).join(", ");
|
|
5
|
+
const irLiteral = emitDocLiteral(ctx.ir, "go");
|
|
6
|
+
return `// GENERATED by behavior-contracts common generator (bc#13) — DO NOT EDIT.
|
|
7
|
+
// Input: portable component-graph IR only (scp-ir-architecture.md §5/§7.4).
|
|
8
|
+
// This module is the codegen endpoint (§7.3 endpoint 3): the IR is embedded as a
|
|
9
|
+
// native JNode composite literal and handed to the EXISTING runtime core
|
|
10
|
+
// (RunBehavior) — no execution logic is generated. Handlers are ALWAYS injected
|
|
11
|
+
// at the boundary (IR + {effects,config,hooks} — concept.md §4.4); they are
|
|
12
|
+
// never generated.
|
|
13
|
+
// irFingerprint: ${fingerprint}
|
|
14
|
+
|
|
15
|
+
package behaviors
|
|
16
|
+
|
|
17
|
+
import (
|
|
18
|
+
"encoding/json"
|
|
19
|
+
"fmt"
|
|
20
|
+
|
|
21
|
+
dslcontracts ${JSON.stringify(runtimeImport)}
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
// ExpectedSpecVersions are the spec versions baked at generation time
|
|
25
|
+
// (fail-closed constant comparison at init).
|
|
26
|
+
var ExpectedSpecVersions = map[string]int64{"behavior": ${specVersions.behavior}, "expression": ${specVersions.expression}, "plan": ${specVersions.plan}}
|
|
27
|
+
|
|
28
|
+
// IRFingerprint is the FNV-1a 64 fingerprint of the source portable IR
|
|
29
|
+
// (CanonicalJSON discipline, #208).
|
|
30
|
+
const IRFingerprint = ${JSON.stringify(fingerprint)}
|
|
31
|
+
|
|
32
|
+
// ComponentNames are the components exposed by Bind(), in IR declaration order.
|
|
33
|
+
var ComponentNames = []string{${names}}
|
|
34
|
+
|
|
35
|
+
// IR is the portable component-graph IR, embedded as a native JNode composite
|
|
36
|
+
// literal (no JSON parse at runtime).
|
|
37
|
+
var IR dslcontracts.JNode = ${irLiteral}
|
|
38
|
+
|
|
39
|
+
// init — load-time fail-closed checks (#208 prepared-artifact discipline).
|
|
40
|
+
// A spec-version skew or fingerprint mismatch panics at package initialization,
|
|
41
|
+
// so importing a stale/tampered generated module fails LOUDLY before any
|
|
42
|
+
// behavior can run.
|
|
43
|
+
func init() {
|
|
44
|
+
for k, want := range ExpectedSpecVersions {
|
|
45
|
+
if got := dslcontracts.SpecVersions[k]; got != want {
|
|
46
|
+
panic(fmt.Sprintf("behavior-contracts generated module: spec-version skew for '%s' (generated=%d, runtime=%d) — regenerate against this runtime (fail-closed)", k, want, got))
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
got, err := dslcontracts.FingerprintComponentGraph(IR)
|
|
50
|
+
if err != nil {
|
|
51
|
+
panic(fmt.Sprintf("behavior-contracts generated module: fingerprint recompute failed: %v (fail-closed)", err))
|
|
52
|
+
}
|
|
53
|
+
if got != IRFingerprint {
|
|
54
|
+
panic(fmt.Sprintf("behavior-contracts generated module: IR fingerprint mismatch (baked=%s, embedded literal=%s) — the generated code was modified or corrupted (fail-closed)", IRFingerprint, got))
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Bind — inject handlers (boundary injection; catalog name → implementation) and
|
|
59
|
+
// get one executor func per component. Each call delegates to the runtime core's
|
|
60
|
+
// RunBehavior over the embedded IR (dynamic-path equivalent — §7.3).
|
|
61
|
+
func Bind(handlers dslcontracts.ComponentExec) map[string]func(input *dslcontracts.Obj) (dslcontracts.Value, error) {
|
|
62
|
+
bound := make(map[string]func(input *dslcontracts.Obj) (dslcontracts.Value, error), len(ComponentNames))
|
|
63
|
+
for _, name := range ComponentNames {
|
|
64
|
+
n := name
|
|
65
|
+
bound[n] = func(input *dslcontracts.Obj) (dslcontracts.Value, error) {
|
|
66
|
+
return dslcontracts.RunBehavior(IR, handlers, input, n)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return bound
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
export const goEmitter = {
|
|
74
|
+
language: "go",
|
|
75
|
+
fileExtension: ".go",
|
|
76
|
+
defaultRuntimeImport: "github.com/foo-ogawa/behavior-contracts/go",
|
|
77
|
+
emit,
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=emit-go.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-go.js","sourceRoot":"","sources":["../../src/generator/emit-go.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,SAAS,IAAI,CAAC,GAAgB;IAC5B,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACzE,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC/C,OAAO;;;;;;;oBAOW,WAAW;;;;;;;;gBAQf,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC;;;;;0DAKa,YAAY,CAAC,QAAQ,mBAAmB,YAAY,CAAC,UAAU,aAAa,YAAY,CAAC,IAAI;;;;wBAI/H,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;;;gCAGnB,KAAK;;;;8BAIP,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCtC,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,SAAS,GAAkB;IACtC,QAAQ,EAAE,IAAI;IACd,aAAa,EAAE,KAAK;IACpB,oBAAoB,EAAE,4CAA4C;IAClE,IAAI;CACL,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emit-php.ts — PHP emitter(共通 Generator, bc#13 SP2)。
|
|
3
|
+
*
|
|
4
|
+
* 生成物: 可搬 IR を **ネイティブ配列/stdClass リテラル**(`(object) [...]` /
|
|
5
|
+
* `[...]` — Behavior::runBehavior が消費する json_decode(.., false) 同型ドメイン)
|
|
6
|
+
* として埋め込み、`Behavior::runBehavior` に handler 注入で渡す accessor
|
|
7
|
+
* (`bind` クロージャ)を公開する .php ファイル。
|
|
8
|
+
*
|
|
9
|
+
* ロード形: PHP に「モジュール」概念は無いため、生成ファイルは **require の戻り値**
|
|
10
|
+
* としてモジュールオブジェクト(stdClass: EXPECTED_SPEC_VERSIONS / IR_FINGERPRINT /
|
|
11
|
+
* COMPONENT_NAMES / IR / bind)を返す。トップレベルシンボルを定義しないので、
|
|
12
|
+
* 同一プロセスで複数の生成モジュールを衝突なく require できる
|
|
13
|
+
* (変数スコープ漏れを避けるにはクロージャ内で require すること)。
|
|
14
|
+
*
|
|
15
|
+
* ロード時検査は **require 時**: spec-version skew / fingerprint mismatch は
|
|
16
|
+
* RuntimeException で LOUD reject(#208 prepared-artifact 規律)。
|
|
17
|
+
*/
|
|
18
|
+
import type { EmitterPlugin } from "./core.js";
|
|
19
|
+
export declare const phpEmitter: EmitterPlugin;
|
|
20
|
+
//# sourceMappingURL=emit-php.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-php.d.ts","sourceRoot":"","sources":["../../src/generator/emit-php.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,WAAW,CAAC;AAyE5D,eAAO,MAAM,UAAU,EAAE,aAKxB,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { emitDocLiteral } from "./literal.js";
|
|
2
|
+
/** PHP 単一引用符リテラル(識別子・fingerprint 用 — ASCII 前提)。 */
|
|
3
|
+
function phpSq(s) {
|
|
4
|
+
return `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
5
|
+
}
|
|
6
|
+
function emit(ctx) {
|
|
7
|
+
const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
|
|
8
|
+
const names = componentNames.map(phpSq).join(", ");
|
|
9
|
+
const irLiteral = emitDocLiteral(ctx.ir, "php");
|
|
10
|
+
return `<?php
|
|
11
|
+
|
|
12
|
+
// GENERATED by behavior-contracts common generator (bc#13) — DO NOT EDIT.
|
|
13
|
+
// Input: portable component-graph IR only (scp-ir-architecture.md §5/§7.4).
|
|
14
|
+
// This module is the codegen endpoint (§7.3 endpoint 3): the IR is embedded as a
|
|
15
|
+
// native stdClass/array literal and handed to the EXISTING runtime core
|
|
16
|
+
// (Behavior::runBehavior) — no execution logic is generated. Handlers are ALWAYS
|
|
17
|
+
// injected at the boundary (IR + {effects,config,hooks} — concept.md §4.4); they
|
|
18
|
+
// are never generated.
|
|
19
|
+
// irFingerprint: ${fingerprint}
|
|
20
|
+
|
|
21
|
+
declare(strict_types=1);
|
|
22
|
+
|
|
23
|
+
// Spec versions baked at generation time (fail-closed constant comparison at require).
|
|
24
|
+
$expectedSpecVersions = ['behavior' => ${specVersions.behavior}, 'expression' => ${specVersions.expression}, 'plan' => ${specVersions.plan}];
|
|
25
|
+
|
|
26
|
+
// FNV-1a 64 fingerprint of the source portable IR (canonical-json discipline, #208).
|
|
27
|
+
$irFingerprint = ${phpSq(fingerprint)};
|
|
28
|
+
|
|
29
|
+
// Component names exposed by bind(), in IR declaration order.
|
|
30
|
+
$componentNames = [${names}];
|
|
31
|
+
|
|
32
|
+
// The portable component-graph IR, embedded as a native literal (no JSON parse at require).
|
|
33
|
+
$ir = ${irLiteral};
|
|
34
|
+
|
|
35
|
+
// Require-time fail-closed checks (#208 prepared-artifact discipline).
|
|
36
|
+
$runtimeSpecVersions = [
|
|
37
|
+
'behavior' => \\${runtimeImport}\\SpecVersions::BEHAVIOR,
|
|
38
|
+
'expression' => \\${runtimeImport}\\SpecVersions::EXPRESSION,
|
|
39
|
+
'plan' => \\${runtimeImport}\\SpecVersions::PLAN,
|
|
40
|
+
];
|
|
41
|
+
foreach ($expectedSpecVersions as $specKey => $specWant) {
|
|
42
|
+
$specGot = $runtimeSpecVersions[$specKey] ?? null;
|
|
43
|
+
if ($specGot !== $specWant) {
|
|
44
|
+
throw new \\RuntimeException("behavior-contracts generated module: spec-version skew for '{$specKey}' (generated={$specWant}, runtime={$specGot}) — regenerate against this runtime (fail-closed)");
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
$gotFingerprint = \\${runtimeImport}\\Fingerprint::componentGraph($ir);
|
|
48
|
+
if ($gotFingerprint !== $irFingerprint) {
|
|
49
|
+
throw new \\RuntimeException("behavior-contracts generated module: IR fingerprint mismatch (baked={$irFingerprint}, embedded literal={$gotFingerprint}) — the generated code was modified or corrupted (fail-closed)");
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// bind — inject handlers (boundary injection; catalog name → implementation) and
|
|
53
|
+
// get one executor closure per component. Each call delegates to the runtime
|
|
54
|
+
// core's Behavior::runBehavior over the embedded IR (dynamic-path equivalent — §7.3).
|
|
55
|
+
return (object) [
|
|
56
|
+
'EXPECTED_SPEC_VERSIONS' => $expectedSpecVersions,
|
|
57
|
+
'IR_FINGERPRINT' => $irFingerprint,
|
|
58
|
+
'COMPONENT_NAMES' => $componentNames,
|
|
59
|
+
'IR' => $ir,
|
|
60
|
+
'bind' => static function (array $handlers) use ($ir, $componentNames): array {
|
|
61
|
+
$bound = [];
|
|
62
|
+
foreach ($componentNames as $name) {
|
|
63
|
+
$bound[$name] = static fn (array $input = []): mixed => \\${runtimeImport}\\Behavior::runBehavior($ir, $handlers, $input, $name);
|
|
64
|
+
}
|
|
65
|
+
return $bound;
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
`;
|
|
69
|
+
}
|
|
70
|
+
export const phpEmitter = {
|
|
71
|
+
language: "php",
|
|
72
|
+
fileExtension: ".php",
|
|
73
|
+
defaultRuntimeImport: "BehaviorContracts",
|
|
74
|
+
emit,
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=emit-php.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-php.js","sourceRoot":"","sources":["../../src/generator/emit-php.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,mDAAmD;AACnD,SAAS,KAAK,CAAC,CAAS;IACtB,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC;AAC9D,CAAC;AAED,SAAS,IAAI,CAAC,GAAgB;IAC5B,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACzE,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAChD,OAAO;;;;;;;;;oBASW,WAAW;;;;;yCAKU,YAAY,CAAC,QAAQ,qBAAqB,YAAY,CAAC,UAAU,eAAe,YAAY,CAAC,IAAI;;;mBAGvH,KAAK,CAAC,WAAW,CAAC;;;qBAGhB,KAAK;;;QAGlB,SAAS;;;;sBAIK,aAAa;wBACX,aAAa;kBACnB,aAAa;;;;;;;;sBAQT,aAAa;;;;;;;;;;;;;;;;wEAgBqC,aAAa;;;;;CAKpF,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAkB;IACvC,QAAQ,EAAE,KAAK;IACf,aAAa,EAAE,MAAM;IACrB,oBAAoB,EAAE,mBAAmB;IACzC,IAAI;CACL,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emit-python.ts — Python emitter(共通 Generator, bc#13 SP1)。
|
|
3
|
+
*
|
|
4
|
+
* 生成物: 可搬 IR を **dict リテラル**として埋め込み、`behavior_contracts.run_behavior` に
|
|
5
|
+
* handler 注入で渡す薄い accessor(`bind`)を公開する .py モジュール。TS emitter と同形:
|
|
6
|
+
* spec-version / fingerprint 定数の焼き込み + ロード時 fail-closed 検査。
|
|
7
|
+
*/
|
|
8
|
+
import type { EmitterPlugin } from "./core.js";
|
|
9
|
+
export declare const pythonEmitter: EmitterPlugin;
|
|
10
|
+
//# sourceMappingURL=emit-python.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-python.d.ts","sourceRoot":"","sources":["../../src/generator/emit-python.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,WAAW,CAAC;AAwE5D,eAAO,MAAM,aAAa,EAAE,aAK3B,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { emitDocLiteral } from "./literal.js";
|
|
2
|
+
/** Python 文字列リテラル(JSON エスケープは Python でも合法)。 */
|
|
3
|
+
function pyStr(s) {
|
|
4
|
+
return JSON.stringify(s);
|
|
5
|
+
}
|
|
6
|
+
function emit(ctx) {
|
|
7
|
+
const { fingerprint, specVersions, componentNames, runtimeImport } = ctx;
|
|
8
|
+
const names = componentNames.map(pyStr).join(", ");
|
|
9
|
+
const namesTuple = componentNames.length === 1 ? `(${names},)` : `(${names})`;
|
|
10
|
+
const irLiteral = emitDocLiteral(ctx.ir, "py");
|
|
11
|
+
return `# GENERATED by behavior-contracts common generator (bc#13) — DO NOT EDIT.
|
|
12
|
+
# Input: portable component-graph IR only (scp-ir-architecture.md §5/§7.4).
|
|
13
|
+
# This module is the codegen endpoint (§7.3 endpoint 3): the IR is embedded as a
|
|
14
|
+
# native dict literal and handed to the EXISTING runtime core (run_behavior) —
|
|
15
|
+
# no execution logic is generated. Handlers are ALWAYS injected at the boundary
|
|
16
|
+
# (IR + {effects,config,hooks}); they are never generated.
|
|
17
|
+
# irFingerprint: ${fingerprint}
|
|
18
|
+
from ${runtimeImport} import SPEC_VERSIONS, fingerprint_component_graph, run_behavior
|
|
19
|
+
|
|
20
|
+
# Spec versions baked at generation time (fail-closed constant comparison at load).
|
|
21
|
+
EXPECTED_SPEC_VERSIONS = {"behavior": ${specVersions.behavior}, "expression": ${specVersions.expression}, "plan": ${specVersions.plan}}
|
|
22
|
+
|
|
23
|
+
# FNV-1a 64 fingerprint of the source portable IR (canonical_json discipline, #208).
|
|
24
|
+
IR_FINGERPRINT = ${pyStr(fingerprint)}
|
|
25
|
+
|
|
26
|
+
# Component names exposed by bind(), in IR declaration order.
|
|
27
|
+
COMPONENT_NAMES = ${namesTuple}
|
|
28
|
+
|
|
29
|
+
# The portable component-graph IR, embedded as a native dict literal (no JSON parse at runtime).
|
|
30
|
+
IR = ${irLiteral}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _check_generated_module() -> None:
|
|
34
|
+
# load-time fail-closed checks (#208 prepared-artifact discipline).
|
|
35
|
+
for _k, _want in EXPECTED_SPEC_VERSIONS.items():
|
|
36
|
+
_got = SPEC_VERSIONS.get(_k)
|
|
37
|
+
if _got != _want:
|
|
38
|
+
raise RuntimeError(
|
|
39
|
+
"behavior-contracts generated module: spec-version skew for '%s' "
|
|
40
|
+
"(generated=%s, runtime=%s) — regenerate against this runtime (fail-closed)"
|
|
41
|
+
% (_k, _want, _got)
|
|
42
|
+
)
|
|
43
|
+
_got_fp = fingerprint_component_graph(IR)
|
|
44
|
+
if _got_fp != IR_FINGERPRINT:
|
|
45
|
+
raise RuntimeError(
|
|
46
|
+
"behavior-contracts generated module: IR fingerprint mismatch "
|
|
47
|
+
"(baked=%s, embedded literal=%s) — the generated code was modified or corrupted (fail-closed)"
|
|
48
|
+
% (IR_FINGERPRINT, _got_fp)
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
_check_generated_module()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def bind(handlers):
|
|
56
|
+
"""Inject handlers (boundary injection; catalog name -> implementation) and get
|
|
57
|
+
one callable per component. Each call delegates to the runtime core's
|
|
58
|
+
run_behavior over the embedded IR (dynamic-path equivalent — §7.3)."""
|
|
59
|
+
|
|
60
|
+
def _make(name):
|
|
61
|
+
def _call(input=None):
|
|
62
|
+
return run_behavior(IR, handlers, dict(input or {}), name)
|
|
63
|
+
|
|
64
|
+
return _call
|
|
65
|
+
|
|
66
|
+
return {name: _make(name) for name in COMPONENT_NAMES}
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
export const pythonEmitter = {
|
|
70
|
+
language: "python",
|
|
71
|
+
fileExtension: ".py",
|
|
72
|
+
defaultRuntimeImport: "behavior_contracts",
|
|
73
|
+
emit,
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=emit-python.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-python.js","sourceRoot":"","sources":["../../src/generator/emit-python.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAE9C,+CAA+C;AAC/C,SAAS,KAAK,CAAC,CAAS;IACtB,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,IAAI,CAAC,GAAgB;IAC5B,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,GAAG,CAAC;IACzE,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,cAAc,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC;IAC9E,MAAM,SAAS,GAAG,cAAc,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC/C,OAAO;;;;;;mBAMU,WAAW;OACvB,aAAa;;;wCAGoB,YAAY,CAAC,QAAQ,mBAAmB,YAAY,CAAC,UAAU,aAAa,YAAY,CAAC,IAAI;;;mBAGlH,KAAK,CAAC,WAAW,CAAC;;;oBAGjB,UAAU;;;OAGvB,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqCf,CAAC;AACF,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,QAAQ,EAAE,QAAQ;IAClB,aAAa,EAAE,KAAK;IACpB,oBAAoB,EAAE,oBAAoB;IAC1C,IAAI;CACL,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* emit-rust.ts — Rust emitter(共通 Generator, bc#13 SP2)。
|
|
3
|
+
*
|
|
4
|
+
* 生成物: 可搬 IR を **`serde_json::json!` マクロのネイティブ構築コード**として埋め込み
|
|
5
|
+
* (JSON テキストの実行時パースなし・構文はコンパイル時検査)、runtime-core の
|
|
6
|
+
* `run_behavior` に handler 注入で渡す accessor(`bind` → `Bound::call`)を公開する
|
|
7
|
+
* .rs モジュール。
|
|
8
|
+
*
|
|
9
|
+
* **「true const」からの正直な逸脱(SP1 audit の SP2 指針 (c))**:
|
|
10
|
+
* Rust runtime は IR を `serde_json::Value` で消費するが、`Value` は const 構築
|
|
11
|
+
* できない。そのため IR は `std::sync::LazyLock`(std, Rust >= 1.80)で**初回使用時に
|
|
12
|
+
* 一度だけ**ネイティブ構築される(以後は共有参照)。実行時 JSON パースは行わず、
|
|
13
|
+
* 構築コストは初回 1 回のみ。const-friendly な型付き IR 受け皿を runtime に足す案は
|
|
14
|
+
* runtime 再設計を伴うため将来 issue(本 SP のスコープ外)。
|
|
15
|
+
*
|
|
16
|
+
* ロード時検査は **first-use 時**: `IR` の LazyLock 初期化子の中で spec-version /
|
|
17
|
+
* fingerprint を検査し、skew は panic で LOUD reject(`bind()` が最初に force する)。
|
|
18
|
+
*
|
|
19
|
+
* 出力は rustfmt-clean(rustfmt は json! マクロ本体を触らないため、emitter の
|
|
20
|
+
* レイアウトが不動点になる)— fixture byte-drift ゲートと `cargo fmt --check` 系
|
|
21
|
+
* ゲートの両立のため。
|
|
22
|
+
*/
|
|
23
|
+
import type { EmitterPlugin } from "./core.js";
|
|
24
|
+
export declare const rustEmitter: EmitterPlugin;
|
|
25
|
+
//# sourceMappingURL=emit-rust.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"emit-rust.d.ts","sourceRoot":"","sources":["../../src/generator/emit-rust.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAe,aAAa,EAAE,MAAM,WAAW,CAAC;AAyH5D,eAAO,MAAM,WAAW,EAAE,aAMzB,CAAC"}
|