@stackables/bridge-compiler 0.0.1 → 1.0.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 +49 -0
- package/build/bridge-format.d.ts +3 -3
- package/build/bridge-format.d.ts.map +1 -1
- package/build/bridge-format.js +9 -5
- package/build/index.d.ts +3 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -3
- package/build/language-service.d.ts.map +1 -1
- package/build/language-service.js +47 -6
- package/build/parser/index.d.ts +1 -1
- package/build/parser/index.d.ts.map +1 -1
- package/build/parser/index.js +1 -1
- package/build/parser/lexer.d.ts +1 -0
- package/build/parser/lexer.d.ts.map +1 -1
- package/build/parser/lexer.js +155 -31
- package/build/parser/parser.d.ts +12 -3
- package/build/parser/parser.d.ts.map +1 -1
- package/build/parser/parser.js +63 -13
- package/package.json +3 -3
package/README.md
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
[](https://github.com/stackables/bridge)
|
|
2
|
+
|
|
3
|
+
# The Bridge Compiler
|
|
4
|
+
|
|
5
|
+
The parser for [The Bridge](https://github.com/stackables/bridge) — turns `.bridge` source files into executable instructions.
|
|
6
|
+
|
|
7
|
+
## Installing
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @stackables/bridge-compiler
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Parsing a Bridge File
|
|
14
|
+
|
|
15
|
+
The most common thing you'll do — read a `.bridge` file and get instructions the engine can run:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { parseBridge } from "@stackables/bridge-compiler";
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
|
|
21
|
+
const source = readFileSync("logic.bridge", "utf8");
|
|
22
|
+
const instructions = parseBridge(source);
|
|
23
|
+
|
|
24
|
+
// → Instruction[] — feed this to executeBridge() or bridgeTransform()
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Serializing Back to `.bridge`
|
|
28
|
+
|
|
29
|
+
Round-trip support — parse a bridge file, then serialize the AST back into clean `.bridge` text:
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import {
|
|
33
|
+
parseBridgeFormat,
|
|
34
|
+
serializeBridge,
|
|
35
|
+
} from "@stackables/bridge-compiler";
|
|
36
|
+
|
|
37
|
+
const ast = parseBridgeFormat(source);
|
|
38
|
+
const formatted = serializeBridge(ast);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Part of the Bridge Ecosystem
|
|
42
|
+
|
|
43
|
+
| Package | What it does |
|
|
44
|
+
| ---------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
|
|
45
|
+
| [`@stackables/bridge`](https://www.npmjs.com/package/@stackables/bridge) | **The All-in-One** — everything in a single install |
|
|
46
|
+
| [`@stackables/bridge-core`](https://www.npmjs.com/package/@stackables/bridge-core) | **The Engine** — runs the instructions this package produces |
|
|
47
|
+
| [`@stackables/bridge-graphql`](https://www.npmjs.com/package/@stackables/bridge-graphql) | **The Adapter** — wires bridges into a GraphQL schema |
|
|
48
|
+
| [`@stackables/bridge-stdlib`](https://www.npmjs.com/package/@stackables/bridge-stdlib) | **The Standard Library** — httpCall, strings, arrays, and more |
|
|
49
|
+
| [`@stackables/bridge-types`](https://www.npmjs.com/package/@stackables/bridge-types) | **Shared Types** — `ToolCallFn`, `ToolMap`, `CacheStore` |
|
package/build/bridge-format.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { BridgeDocument } from "@stackables/bridge-core";
|
|
2
2
|
export { parsePath } from "@stackables/bridge-core";
|
|
3
3
|
/**
|
|
4
4
|
* Parse .bridge text — delegates to the Chevrotain parser.
|
|
5
5
|
*/
|
|
6
|
-
export declare function parseBridge(text: string):
|
|
7
|
-
export declare function serializeBridge(
|
|
6
|
+
export declare function parseBridge(text: string): BridgeDocument;
|
|
7
|
+
export declare function serializeBridge(doc: BridgeDocument): string;
|
|
8
8
|
//# sourceMappingURL=bridge-format.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge-format.d.ts","sourceRoot":"","sources":["../src/bridge-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"bridge-format.d.ts","sourceRoot":"","sources":["../src/bridge-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EAOf,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAExD;AAcD,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAkC3D"}
|
package/build/bridge-format.js
CHANGED
|
@@ -19,7 +19,9 @@ function serializeControl(ctrl) {
|
|
|
19
19
|
return "break";
|
|
20
20
|
}
|
|
21
21
|
// ── Serializer ───────────────────────────────────────────────────────────────
|
|
22
|
-
export function serializeBridge(
|
|
22
|
+
export function serializeBridge(doc) {
|
|
23
|
+
const version = doc.version ?? BRIDGE_VERSION;
|
|
24
|
+
const { instructions } = doc;
|
|
23
25
|
const bridges = instructions.filter((i) => i.kind === "bridge");
|
|
24
26
|
const tools = instructions.filter((i) => i.kind === "tool");
|
|
25
27
|
const consts = instructions.filter((i) => i.kind === "const");
|
|
@@ -43,7 +45,7 @@ export function serializeBridge(instructions) {
|
|
|
43
45
|
for (const bridge of bridges) {
|
|
44
46
|
blocks.push(serializeBridgeBlock(bridge));
|
|
45
47
|
}
|
|
46
|
-
return `version ${
|
|
48
|
+
return `version ${version}\n\n` + blocks.join("\n\n") + "\n";
|
|
47
49
|
}
|
|
48
50
|
/**
|
|
49
51
|
* Whether a value string needs quoting to be re-parseable as a bare value.
|
|
@@ -100,7 +102,8 @@ function serializeToolBlock(tool) {
|
|
|
100
102
|
}
|
|
101
103
|
}
|
|
102
104
|
else {
|
|
103
|
-
|
|
105
|
+
const depVTag = dep.version ? `@${dep.version}` : "";
|
|
106
|
+
lines.push(` with ${dep.tool}${depVTag} as ${dep.handle}`);
|
|
104
107
|
}
|
|
105
108
|
}
|
|
106
109
|
// Wires
|
|
@@ -210,11 +213,12 @@ function serializeBridgeBlock(bridge) {
|
|
|
210
213
|
// Short form `with <name>` when handle == last segment of name
|
|
211
214
|
const lastDot = h.name.lastIndexOf(".");
|
|
212
215
|
const defaultHandle = lastDot !== -1 ? h.name.substring(lastDot + 1) : h.name;
|
|
213
|
-
|
|
216
|
+
const vTag = h.version ? `@${h.version}` : "";
|
|
217
|
+
if (h.handle === defaultHandle && !vTag) {
|
|
214
218
|
lines.push(` with ${h.name}`);
|
|
215
219
|
}
|
|
216
220
|
else {
|
|
217
|
-
lines.push(` with ${h.name} as ${h.handle}`);
|
|
221
|
+
lines.push(` with ${h.name}${vTag} as ${h.handle}`);
|
|
218
222
|
}
|
|
219
223
|
break;
|
|
220
224
|
}
|
package/build/index.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @stackables/bridge-compiler — Bridge DSL parser, serializer, and language service.
|
|
3
3
|
*
|
|
4
|
-
* Turns `.bridge` source text into `
|
|
4
|
+
* Turns `.bridge` source text into `BridgeDocument` (JSON AST) and provides
|
|
5
5
|
* IDE intelligence (diagnostics, completions, hover).
|
|
6
6
|
*/
|
|
7
|
-
export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, } from "./parser/index.ts";
|
|
7
|
+
export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser/index.ts";
|
|
8
8
|
export type { BridgeDiagnostic, BridgeParseResult } from "./parser/index.ts";
|
|
9
9
|
export { BridgeLexer, allTokens } from "./parser/index.ts";
|
|
10
|
-
export { parseBridge as parseBridgeFormat, serializeBridge } from "./bridge-format.ts";
|
|
10
|
+
export { parseBridge as parseBridgeFormat, serializeBridge, } from "./bridge-format.ts";
|
|
11
11
|
export { BridgeLanguageService } from "./language-service.ts";
|
|
12
12
|
export type { BridgeCompletion, BridgeHover, CompletionKind, Position, Range, } from "./language-service.ts";
|
|
13
13
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,qBAAqB,IAAI,WAAW,EACpC,qBAAqB,EACrB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,qBAAqB,IAAI,WAAW,EACpC,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAI3D,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,KAAK,GACN,MAAM,uBAAuB,CAAC"}
|
package/build/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @stackables/bridge-compiler — Bridge DSL parser, serializer, and language service.
|
|
3
3
|
*
|
|
4
|
-
* Turns `.bridge` source text into `
|
|
4
|
+
* Turns `.bridge` source text into `BridgeDocument` (JSON AST) and provides
|
|
5
5
|
* IDE intelligence (diagnostics, completions, hover).
|
|
6
6
|
*/
|
|
7
7
|
// ── Parser ──────────────────────────────────────────────────────────────────
|
|
8
|
-
export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, } from "./parser/index.js";
|
|
8
|
+
export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser/index.js";
|
|
9
9
|
export { BridgeLexer, allTokens } from "./parser/index.js";
|
|
10
10
|
// ── Serializer ──────────────────────────────────────────────────────────────
|
|
11
|
-
export { parseBridge as parseBridgeFormat, serializeBridge } from "./bridge-format.js";
|
|
11
|
+
export { parseBridge as parseBridgeFormat, serializeBridge, } from "./bridge-format.js";
|
|
12
12
|
// ── Language service ────────────────────────────────────────────────────────
|
|
13
13
|
export { BridgeLanguageService } from "./language-service.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"language-service.d.ts","sourceRoot":"","sources":["../src/language-service.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"language-service.d.ts","sourceRoot":"","sources":["../src/language-service.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAW1D,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3D,MAAM,MAAM,KAAK,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAoCF,qBAAa,qBAAqB;IAChC,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,iBAAiB,CAA0B;IAEnD;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmB1B;;;;OAIG;IACH,cAAc,IAAI,gBAAgB,EAAE;IAmEpC;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,EAAE;IA4CjD;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI;CAqE5C"}
|
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
* svc.getHover({ line, character });
|
|
14
14
|
*/
|
|
15
15
|
import { parseBridgeDiagnostics } from "./parser/index.js";
|
|
16
|
-
import {
|
|
16
|
+
import { collectVersionedHandles } from "@stackables/bridge-core";
|
|
17
|
+
import { std, STD_VERSION } from "@stackables/bridge-stdlib";
|
|
17
18
|
// ── Internal lookup tables (built once at module load) ─────────────────────
|
|
18
19
|
const builtinToolNames = [
|
|
19
20
|
...Object.keys(std).map((k) => `std.${k}`),
|
|
@@ -63,7 +64,7 @@ export class BridgeLanguageService {
|
|
|
63
64
|
return;
|
|
64
65
|
}
|
|
65
66
|
const result = parseBridgeDiagnostics(text);
|
|
66
|
-
this.instructions = result.instructions;
|
|
67
|
+
this.instructions = result.document.instructions;
|
|
67
68
|
this.startLines = result.startLines;
|
|
68
69
|
this.parserDiagnostics = result.diagnostics;
|
|
69
70
|
}
|
|
@@ -98,6 +99,42 @@ export class BridgeLanguageService {
|
|
|
98
99
|
}
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
// Check @version tags on tool handles against the bundled std version.
|
|
103
|
+
// Versions exceeding the bundled std emit a warning: the tool must be
|
|
104
|
+
// provided at runtime via the tools map.
|
|
105
|
+
const versioned = collectVersionedHandles(this.instructions);
|
|
106
|
+
if (versioned.length > 0) {
|
|
107
|
+
const stdParts = STD_VERSION.split(".").map(Number);
|
|
108
|
+
const [stdMajor = 0, stdMinor = 0] = stdParts;
|
|
109
|
+
for (const { name, version } of versioned) {
|
|
110
|
+
if (!name.startsWith("std."))
|
|
111
|
+
continue;
|
|
112
|
+
const vParts = version.split(".").map(Number);
|
|
113
|
+
const [vMajor = 0, vMinor = 0] = vParts;
|
|
114
|
+
if (vMajor === stdMajor && stdMinor >= vMinor)
|
|
115
|
+
continue;
|
|
116
|
+
// Find the line that contains this version tag so we can report it
|
|
117
|
+
const versionTag = `@${version}`;
|
|
118
|
+
for (let i = 0; i < this.lines.length; i++) {
|
|
119
|
+
const col = this.lines[i].indexOf(versionTag);
|
|
120
|
+
if (col === -1)
|
|
121
|
+
continue;
|
|
122
|
+
// Make sure it's adjacent to the tool name
|
|
123
|
+
if (!this.lines[i].includes(name + versionTag))
|
|
124
|
+
continue;
|
|
125
|
+
diags.push({
|
|
126
|
+
message: `"${name}@${version}" exceeds bundled std ${STD_VERSION}. ` +
|
|
127
|
+
`Provide this tool version at runtime via the tools map.`,
|
|
128
|
+
severity: "warning",
|
|
129
|
+
range: {
|
|
130
|
+
start: { line: i, character: col },
|
|
131
|
+
end: { line: i, character: col + versionTag.length },
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
break;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
101
138
|
return diags;
|
|
102
139
|
}
|
|
103
140
|
// ── Completions ────────────────────────────────────────────────────────
|
|
@@ -217,8 +254,10 @@ function getWordAt(line, character) {
|
|
|
217
254
|
}
|
|
218
255
|
function handleBindingMarkdown(h) {
|
|
219
256
|
switch (h.kind) {
|
|
220
|
-
case "tool":
|
|
221
|
-
|
|
257
|
+
case "tool": {
|
|
258
|
+
const ver = h.version ? ` @${h.version}` : "";
|
|
259
|
+
return `**Tool handle** \`${h.handle}\`\n\nSource: \`${h.name}${ver}\``;
|
|
260
|
+
}
|
|
222
261
|
case "input":
|
|
223
262
|
return `**Input handle** \`${h.handle}\`\n\nGraphQL field arguments`;
|
|
224
263
|
case "output":
|
|
@@ -237,7 +276,9 @@ function toolDepMarkdown(d) {
|
|
|
237
276
|
return `**Context dep** \`${d.handle}\`\n\nGraphQL execution context`;
|
|
238
277
|
case "const":
|
|
239
278
|
return `**Const dep** \`${d.handle}\`\n\nNamed constants declared in this file`;
|
|
240
|
-
case "tool":
|
|
241
|
-
|
|
279
|
+
case "tool": {
|
|
280
|
+
const ver = d.version ? ` @${d.version}` : "";
|
|
281
|
+
return `**Tool dep** \`${d.handle}\`\n\nTool: \`${d.tool}${ver}\``;
|
|
282
|
+
}
|
|
242
283
|
}
|
|
243
284
|
}
|
package/build/parser/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Re-exports the public parse function as well as the lexer for direct access.
|
|
5
5
|
*/
|
|
6
|
-
export { parseBridgeChevrotain, parseBridgeDiagnostics } from "./parser.ts";
|
|
6
|
+
export { parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser.ts";
|
|
7
7
|
export type { BridgeDiagnostic, BridgeParseResult } from "./parser.ts";
|
|
8
8
|
export { BridgeLexer, allTokens } from "./lexer.ts";
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
|
package/build/parser/index.js
CHANGED
|
@@ -3,5 +3,5 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Re-exports the public parse function as well as the lexer for direct access.
|
|
5
5
|
*/
|
|
6
|
-
export { parseBridgeChevrotain, parseBridgeDiagnostics } from "./parser.js";
|
|
6
|
+
export { parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser.js";
|
|
7
7
|
export { BridgeLexer, allTokens } from "./lexer.js";
|
package/build/parser/lexer.d.ts
CHANGED
|
@@ -55,6 +55,7 @@ export declare const Equals: import("chevrotain").TokenType;
|
|
|
55
55
|
export declare const Dot: import("chevrotain").TokenType;
|
|
56
56
|
export declare const Colon: import("chevrotain").TokenType;
|
|
57
57
|
export declare const Comma: import("chevrotain").TokenType;
|
|
58
|
+
export declare const VersionTag: import("chevrotain").TokenType;
|
|
58
59
|
export declare const StringLiteral: import("chevrotain").TokenType;
|
|
59
60
|
export declare const NumberLiteral: import("chevrotain").TokenType;
|
|
60
61
|
export declare const TrueLiteral: import("chevrotain").TokenType;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/parser/lexer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAe,KAAK,EAAE,MAAM,YAAY,CAAC;AAIhD,eAAO,MAAM,OAAO,gCAIlB,CAAC;AAEH,eAAO,MAAM,EAAE,gCAIb,CAAC;AAEH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AAIH,eAAO,MAAM,UAAU,gCAGrB,CAAC;AAIH,eAAO,MAAM,SAAS,
|
|
1
|
+
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/parser/lexer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAe,KAAK,EAAE,MAAM,YAAY,CAAC;AAIhD,eAAO,MAAM,OAAO,gCAIlB,CAAC;AAEH,eAAO,MAAM,EAAE,gCAIb,CAAC;AAEH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AAIH,eAAO,MAAM,UAAU,gCAGrB,CAAC;AAIH,eAAO,MAAM,SAAS,gCAIpB,CAAC;AACH,eAAO,MAAM,MAAM,gCAIjB,CAAC;AACH,eAAO,MAAM,QAAQ,gCAInB,CAAC;AACH,eAAO,MAAM,QAAQ,gCAInB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,MAAM,gCAIjB,CAAC;AACH,eAAO,MAAM,IAAI,gCAIf,CAAC;AACH,eAAO,MAAM,MAAM,gCAIjB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,QAAQ,gCAInB,CAAC;AACH,eAAO,MAAM,SAAS,gCAIpB,CAAC;AACH,eAAO,MAAM,IAAI,gCAIf,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,KAAK,gCAIhB,CAAC;AACH,eAAO,MAAM,IAAI,gCAIf,CAAC;AACH,eAAO,MAAM,KAAK,gCAIhB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AACH,eAAO,MAAM,UAAU,gCAIrB,CAAC;AACH,eAAO,MAAM,OAAO,gCAIlB,CAAC;AAIH,eAAO,MAAM,KAAK,gCAAgD,CAAC;AACnE,eAAO,MAAM,YAAY,gCAGvB,CAAC;AACH,eAAO,MAAM,aAAa,gCAGxB,CAAC;AACH,eAAO,MAAM,OAAO,gCAAoD,CAAC;AACzE,eAAO,MAAM,YAAY,gCAGvB,CAAC;AACH,eAAO,MAAM,YAAY,gCAGvB,CAAC;AACH,eAAO,MAAM,SAAS,gCAAoD,CAAC;AAC3E,eAAO,MAAM,YAAY,gCAGvB,CAAC;AACH,eAAO,MAAM,SAAS,gCAAoD,CAAC;AAC3E,eAAO,MAAM,WAAW,gCAAqD,CAAC;AAC9E,eAAO,MAAM,QAAQ,gCAAkD,CAAC;AACxE,eAAO,MAAM,IAAI,gCAA+C,CAAC;AACjE,eAAO,MAAM,IAAI,gCAA+C,CAAC;AACjE,eAAO,MAAM,MAAM,gCAAiD,CAAC;AACrE,eAAO,MAAM,MAAM,gCAAiD,CAAC;AACrE,eAAO,MAAM,MAAM,gCAAiD,CAAC;AACrE,eAAO,MAAM,MAAM,gCAAiD,CAAC;AACrE,eAAO,MAAM,OAAO,gCAAkD,CAAC;AACvE,eAAO,MAAM,OAAO,gCAAkD,CAAC;AACvE,eAAO,MAAM,MAAM,gCAAgD,CAAC;AACpE,eAAO,MAAM,GAAG,gCAA8C,CAAC;AAC/D,eAAO,MAAM,KAAK,gCAA+C,CAAC;AAClE,eAAO,MAAM,KAAK,gCAA+C,CAAC;AAClE,eAAO,MAAM,UAAU,gCAGrB,CAAC;AAIH,eAAO,MAAM,aAAa,gCAGxB,CAAC;AAEH,eAAO,MAAM,aAAa,gCAGxB,CAAC;AAEH,eAAO,MAAM,WAAW,gCAItB,CAAC;AACH,eAAO,MAAM,YAAY,gCAIvB,CAAC;AACH,eAAO,MAAM,WAAW,gCAItB,CAAC;AAEH,eAAO,MAAM,SAAS,gCAGpB,CAAC;AAEH,eAAO,MAAM,KAAK,gCAAgD,CAAC;AACnE,eAAO,MAAM,KAAK,gCAA+C,CAAC;AAIlE,eAAO,MAAM,SAAS,kCA6DrB,CAAC;AAEF,eAAO,MAAM,WAAW,OAGtB,CAAC"}
|
package/build/parser/lexer.js
CHANGED
|
@@ -27,38 +27,145 @@ export const Identifier = createToken({
|
|
|
27
27
|
pattern: /[a-zA-Z_][\w-]*/,
|
|
28
28
|
});
|
|
29
29
|
// ── Keywords ───────────────────────────────────────────────────────────────
|
|
30
|
-
export const VersionKw = createToken({
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
export const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
export const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
export const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
export const
|
|
51
|
-
|
|
52
|
-
|
|
30
|
+
export const VersionKw = createToken({
|
|
31
|
+
name: "VersionKw",
|
|
32
|
+
pattern: /version/i,
|
|
33
|
+
longer_alt: Identifier,
|
|
34
|
+
});
|
|
35
|
+
export const ToolKw = createToken({
|
|
36
|
+
name: "ToolKw",
|
|
37
|
+
pattern: /tool/i,
|
|
38
|
+
longer_alt: Identifier,
|
|
39
|
+
});
|
|
40
|
+
export const BridgeKw = createToken({
|
|
41
|
+
name: "BridgeKw",
|
|
42
|
+
pattern: /bridge/i,
|
|
43
|
+
longer_alt: Identifier,
|
|
44
|
+
});
|
|
45
|
+
export const DefineKw = createToken({
|
|
46
|
+
name: "DefineKw",
|
|
47
|
+
pattern: /define/i,
|
|
48
|
+
longer_alt: Identifier,
|
|
49
|
+
});
|
|
50
|
+
export const ConstKw = createToken({
|
|
51
|
+
name: "ConstKw",
|
|
52
|
+
pattern: /const/i,
|
|
53
|
+
longer_alt: Identifier,
|
|
54
|
+
});
|
|
55
|
+
export const WithKw = createToken({
|
|
56
|
+
name: "WithKw",
|
|
57
|
+
pattern: /with/i,
|
|
58
|
+
longer_alt: Identifier,
|
|
59
|
+
});
|
|
60
|
+
export const AsKw = createToken({
|
|
61
|
+
name: "AsKw",
|
|
62
|
+
pattern: /as/i,
|
|
63
|
+
longer_alt: Identifier,
|
|
64
|
+
});
|
|
65
|
+
export const FromKw = createToken({
|
|
66
|
+
name: "FromKw",
|
|
67
|
+
pattern: /from/i,
|
|
68
|
+
longer_alt: Identifier,
|
|
69
|
+
});
|
|
70
|
+
export const InputKw = createToken({
|
|
71
|
+
name: "InputKw",
|
|
72
|
+
pattern: /input/i,
|
|
73
|
+
longer_alt: Identifier,
|
|
74
|
+
});
|
|
75
|
+
export const OutputKw = createToken({
|
|
76
|
+
name: "OutputKw",
|
|
77
|
+
pattern: /output/i,
|
|
78
|
+
longer_alt: Identifier,
|
|
79
|
+
});
|
|
80
|
+
export const ContextKw = createToken({
|
|
81
|
+
name: "ContextKw",
|
|
82
|
+
pattern: /context/i,
|
|
83
|
+
longer_alt: Identifier,
|
|
84
|
+
});
|
|
85
|
+
export const OnKw = createToken({
|
|
86
|
+
name: "OnKw",
|
|
87
|
+
pattern: /on/i,
|
|
88
|
+
longer_alt: Identifier,
|
|
89
|
+
});
|
|
90
|
+
export const ErrorKw = createToken({
|
|
91
|
+
name: "ErrorKw",
|
|
92
|
+
pattern: /error/i,
|
|
93
|
+
longer_alt: Identifier,
|
|
94
|
+
});
|
|
95
|
+
export const ForceKw = createToken({
|
|
96
|
+
name: "ForceKw",
|
|
97
|
+
pattern: /force/i,
|
|
98
|
+
longer_alt: Identifier,
|
|
99
|
+
});
|
|
100
|
+
export const AliasKw = createToken({
|
|
101
|
+
name: "AliasKw",
|
|
102
|
+
pattern: /alias/i,
|
|
103
|
+
longer_alt: Identifier,
|
|
104
|
+
});
|
|
105
|
+
export const CatchKw = createToken({
|
|
106
|
+
name: "CatchKw",
|
|
107
|
+
pattern: /catch/i,
|
|
108
|
+
longer_alt: Identifier,
|
|
109
|
+
});
|
|
110
|
+
export const AndKw = createToken({
|
|
111
|
+
name: "AndKw",
|
|
112
|
+
pattern: /and/,
|
|
113
|
+
longer_alt: Identifier,
|
|
114
|
+
});
|
|
115
|
+
export const OrKw = createToken({
|
|
116
|
+
name: "OrKw",
|
|
117
|
+
pattern: /or/,
|
|
118
|
+
longer_alt: Identifier,
|
|
119
|
+
});
|
|
120
|
+
export const NotKw = createToken({
|
|
121
|
+
name: "NotKw",
|
|
122
|
+
pattern: /not/,
|
|
123
|
+
longer_alt: Identifier,
|
|
124
|
+
});
|
|
125
|
+
export const ThrowKw = createToken({
|
|
126
|
+
name: "ThrowKw",
|
|
127
|
+
pattern: /throw/,
|
|
128
|
+
longer_alt: Identifier,
|
|
129
|
+
});
|
|
130
|
+
export const PanicKw = createToken({
|
|
131
|
+
name: "PanicKw",
|
|
132
|
+
pattern: /panic/,
|
|
133
|
+
longer_alt: Identifier,
|
|
134
|
+
});
|
|
135
|
+
export const ContinueKw = createToken({
|
|
136
|
+
name: "ContinueKw",
|
|
137
|
+
pattern: /continue/,
|
|
138
|
+
longer_alt: Identifier,
|
|
139
|
+
});
|
|
140
|
+
export const BreakKw = createToken({
|
|
141
|
+
name: "BreakKw",
|
|
142
|
+
pattern: /break/,
|
|
143
|
+
longer_alt: Identifier,
|
|
144
|
+
});
|
|
53
145
|
// ── Operators & punctuation ────────────────────────────────────────────────
|
|
54
146
|
export const Arrow = createToken({ name: "Arrow", pattern: /<-/ });
|
|
55
|
-
export const NullCoalesce = createToken({
|
|
56
|
-
|
|
147
|
+
export const NullCoalesce = createToken({
|
|
148
|
+
name: "NullCoalesce",
|
|
149
|
+
pattern: /\|\|/,
|
|
150
|
+
});
|
|
151
|
+
export const ErrorCoalesce = createToken({
|
|
152
|
+
name: "ErrorCoalesce",
|
|
153
|
+
pattern: /\?\?/,
|
|
154
|
+
});
|
|
57
155
|
export const SafeNav = createToken({ name: "SafeNav", pattern: /\?\./ });
|
|
58
|
-
export const QuestionMark = createToken({
|
|
59
|
-
|
|
156
|
+
export const QuestionMark = createToken({
|
|
157
|
+
name: "QuestionMark",
|
|
158
|
+
pattern: /\?/,
|
|
159
|
+
});
|
|
160
|
+
export const GreaterEqual = createToken({
|
|
161
|
+
name: "GreaterEqual",
|
|
162
|
+
pattern: />=/,
|
|
163
|
+
});
|
|
60
164
|
export const LessEqual = createToken({ name: "LessEqual", pattern: /<=/ });
|
|
61
|
-
export const DoubleEquals = createToken({
|
|
165
|
+
export const DoubleEquals = createToken({
|
|
166
|
+
name: "DoubleEquals",
|
|
167
|
+
pattern: /==/,
|
|
168
|
+
});
|
|
62
169
|
export const NotEquals = createToken({ name: "NotEquals", pattern: /!=/ });
|
|
63
170
|
export const GreaterThan = createToken({ name: "GreaterThan", pattern: />/ });
|
|
64
171
|
export const LessThan = createToken({ name: "LessThan", pattern: /</ });
|
|
@@ -74,6 +181,10 @@ export const Equals = createToken({ name: "Equals", pattern: /=/ });
|
|
|
74
181
|
export const Dot = createToken({ name: "Dot", pattern: /\./ });
|
|
75
182
|
export const Colon = createToken({ name: "Colon", pattern: /:/ });
|
|
76
183
|
export const Comma = createToken({ name: "Comma", pattern: /,/ });
|
|
184
|
+
export const VersionTag = createToken({
|
|
185
|
+
name: "VersionTag",
|
|
186
|
+
pattern: /@\d[\d.]*[\dx]*/,
|
|
187
|
+
});
|
|
77
188
|
// ── Literals ───────────────────────────────────────────────────────────────
|
|
78
189
|
export const StringLiteral = createToken({
|
|
79
190
|
name: "StringLiteral",
|
|
@@ -83,9 +194,21 @@ export const NumberLiteral = createToken({
|
|
|
83
194
|
name: "NumberLiteral",
|
|
84
195
|
pattern: /-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/,
|
|
85
196
|
});
|
|
86
|
-
export const TrueLiteral = createToken({
|
|
87
|
-
|
|
88
|
-
|
|
197
|
+
export const TrueLiteral = createToken({
|
|
198
|
+
name: "TrueLiteral",
|
|
199
|
+
pattern: /true/,
|
|
200
|
+
longer_alt: Identifier,
|
|
201
|
+
});
|
|
202
|
+
export const FalseLiteral = createToken({
|
|
203
|
+
name: "FalseLiteral",
|
|
204
|
+
pattern: /false/,
|
|
205
|
+
longer_alt: Identifier,
|
|
206
|
+
});
|
|
207
|
+
export const NullLiteral = createToken({
|
|
208
|
+
name: "NullLiteral",
|
|
209
|
+
pattern: /null/,
|
|
210
|
+
longer_alt: Identifier,
|
|
211
|
+
});
|
|
89
212
|
export const PathToken = createToken({
|
|
90
213
|
name: "PathToken",
|
|
91
214
|
pattern: /\/[\w./-]+/,
|
|
@@ -120,6 +243,7 @@ export const allTokens = [
|
|
|
120
243
|
Dot,
|
|
121
244
|
Colon,
|
|
122
245
|
Comma,
|
|
246
|
+
VersionTag,
|
|
123
247
|
StringLiteral,
|
|
124
248
|
// Keywords before Identifier (longer_alt prevents prefix stealing)
|
|
125
249
|
VersionKw,
|
package/build/parser/parser.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
-
import type { Instruction } from "@stackables/bridge-core";
|
|
2
|
-
|
|
1
|
+
import type { BridgeDocument, Instruction } from "@stackables/bridge-core";
|
|
2
|
+
/** Exported parser version metadata for runtime use. */
|
|
3
|
+
export declare const PARSER_VERSION: {
|
|
4
|
+
/** Current bridge language version */
|
|
5
|
+
readonly current: "1.5";
|
|
6
|
+
/** Minimum supported major version (inclusive) */
|
|
7
|
+
readonly minMajor: 1;
|
|
8
|
+
/** Maximum supported major version (inclusive) */
|
|
9
|
+
readonly maxMajor: 1;
|
|
10
|
+
};
|
|
11
|
+
export declare function parseBridgeChevrotain(text: string): BridgeDocument;
|
|
3
12
|
export type BridgeDiagnostic = {
|
|
4
13
|
message: string;
|
|
5
14
|
severity: "error" | "warning";
|
|
@@ -15,7 +24,7 @@ export type BridgeDiagnostic = {
|
|
|
15
24
|
};
|
|
16
25
|
};
|
|
17
26
|
export type BridgeParseResult = {
|
|
18
|
-
|
|
27
|
+
document: BridgeDocument;
|
|
19
28
|
diagnostics: BridgeDiagnostic[];
|
|
20
29
|
/** 1-based start line for each top-level instruction */
|
|
21
30
|
startLines: Map<Instruction, number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAoEA,OAAO,KAAK,EAEV,cAAc,EAKd,WAAW,EAMZ,MAAM,yBAAyB,CAAC;AAumCjC,wDAAwD;AACxD,eAAO,MAAM,cAAc;IACzB,sCAAsC;;IAEtC,kDAAkD;;IAElD,kDAAkD;;CAE1C,CAAC;AAMX,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAElE;AAID,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE;QACL,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3C,GAAG,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KAC1C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,wDAAwD;IACxD,UAAU,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA8DtE"}
|
package/build/parser/parser.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Produces the *exact same* AST types (`Instruction[]`).
|
|
6
6
|
*/
|
|
7
7
|
import { CstParser } from "chevrotain";
|
|
8
|
-
import { allTokens, Identifier, VersionKw, ToolKw, BridgeKw, DefineKw, ConstKw, WithKw, AsKw, FromKw, InputKw, OutputKw, ContextKw, OnKw, ErrorKw, Arrow, ForceKw, AliasKw, AndKw, OrKw, NotKw, ThrowKw, PanicKw, ContinueKw, BreakKw, NullCoalesce, ErrorCoalesce, SafeNav, CatchKw, LParen, RParen, LCurly, RCurly, LSquare, RSquare, Equals, Dot, Colon, Comma, StringLiteral, NumberLiteral, PathToken, TrueLiteral, FalseLiteral, NullLiteral, Star, Slash, Plus, Minus, GreaterEqual, LessEqual, DoubleEquals, NotEquals, GreaterThan, LessThan, QuestionMark, BridgeLexer, } from "./lexer.js";
|
|
8
|
+
import { allTokens, Identifier, VersionKw, ToolKw, BridgeKw, DefineKw, ConstKw, WithKw, AsKw, FromKw, InputKw, OutputKw, ContextKw, OnKw, ErrorKw, Arrow, ForceKw, AliasKw, AndKw, OrKw, NotKw, ThrowKw, PanicKw, ContinueKw, BreakKw, NullCoalesce, ErrorCoalesce, SafeNav, CatchKw, LParen, RParen, LCurly, RCurly, LSquare, RSquare, Equals, Dot, Colon, Comma, StringLiteral, NumberLiteral, PathToken, TrueLiteral, FalseLiteral, NullLiteral, Star, Slash, Plus, Minus, GreaterEqual, LessEqual, DoubleEquals, NotEquals, GreaterThan, LessThan, QuestionMark, VersionTag, BridgeLexer, } from "./lexer.js";
|
|
9
9
|
import { SELF_MODULE } from "@stackables/bridge-core";
|
|
10
10
|
// ── Reserved-word guards (mirroring the regex parser) ──────────────────────
|
|
11
11
|
const RESERVED_KEYWORDS = new Set([
|
|
@@ -160,6 +160,9 @@ class BridgeParser extends CstParser {
|
|
|
160
160
|
},
|
|
161
161
|
ALT: () => {
|
|
162
162
|
this.SUBRULE(this.dottedName, { LABEL: "toolName" });
|
|
163
|
+
this.OPTION3(() => {
|
|
164
|
+
this.CONSUME(VersionTag, { LABEL: "toolVersion" });
|
|
165
|
+
});
|
|
163
166
|
this.CONSUME3(AsKw);
|
|
164
167
|
this.SUBRULE3(this.nameToken, { LABEL: "toolAlias" });
|
|
165
168
|
},
|
|
@@ -350,6 +353,9 @@ class BridgeParser extends CstParser {
|
|
|
350
353
|
},
|
|
351
354
|
ALT: () => {
|
|
352
355
|
this.SUBRULE(this.dottedName, { LABEL: "refName" });
|
|
356
|
+
this.OPTION6(() => {
|
|
357
|
+
this.CONSUME(VersionTag, { LABEL: "refVersion" });
|
|
358
|
+
});
|
|
353
359
|
this.OPTION5(() => {
|
|
354
360
|
this.CONSUME5(AsKw);
|
|
355
361
|
this.SUBRULE5(this.nameToken, { LABEL: "refAlias" });
|
|
@@ -1051,6 +1057,19 @@ const parserInstance = new BridgeParser();
|
|
|
1051
1057
|
// Lenient instance: error recovery enabled (used by parseBridgeDiagnostics)
|
|
1052
1058
|
const diagParserInstance = new BridgeParser({ recovery: true });
|
|
1053
1059
|
const BRIDGE_VERSION = "1.5";
|
|
1060
|
+
/** Minimum major version the parser can handle (inclusive). */
|
|
1061
|
+
const BRIDGE_MIN_MAJOR = 1;
|
|
1062
|
+
/** Maximum major version the parser can handle (inclusive). */
|
|
1063
|
+
const BRIDGE_MAX_MAJOR = 1;
|
|
1064
|
+
/** Exported parser version metadata for runtime use. */
|
|
1065
|
+
export const PARSER_VERSION = {
|
|
1066
|
+
/** Current bridge language version */
|
|
1067
|
+
current: BRIDGE_VERSION,
|
|
1068
|
+
/** Minimum supported major version (inclusive) */
|
|
1069
|
+
minMajor: BRIDGE_MIN_MAJOR,
|
|
1070
|
+
/** Maximum supported major version (inclusive) */
|
|
1071
|
+
maxMajor: BRIDGE_MAX_MAJOR,
|
|
1072
|
+
};
|
|
1054
1073
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1055
1074
|
// Public API
|
|
1056
1075
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -1100,11 +1119,11 @@ export function parseBridgeDiagnostics(text) {
|
|
|
1100
1119
|
});
|
|
1101
1120
|
}
|
|
1102
1121
|
// 3. Visit → AST (semantic errors thrown as "Line N: ..." messages)
|
|
1103
|
-
let
|
|
1122
|
+
let document = { instructions: [] };
|
|
1104
1123
|
let startLines = new Map();
|
|
1105
1124
|
try {
|
|
1106
1125
|
const result = toBridgeAst(cst, []);
|
|
1107
|
-
|
|
1126
|
+
document = { version: result.version, instructions: result.instructions };
|
|
1108
1127
|
startLines = result.startLines;
|
|
1109
1128
|
}
|
|
1110
1129
|
catch (err) {
|
|
@@ -1120,7 +1139,7 @@ export function parseBridgeDiagnostics(text) {
|
|
|
1120
1139
|
},
|
|
1121
1140
|
});
|
|
1122
1141
|
}
|
|
1123
|
-
return {
|
|
1142
|
+
return { document, diagnostics, startLines };
|
|
1124
1143
|
}
|
|
1125
1144
|
function internalParse(text, previousInstructions) {
|
|
1126
1145
|
// 1. Lex
|
|
@@ -1137,7 +1156,8 @@ function internalParse(text, previousInstructions) {
|
|
|
1137
1156
|
throw new Error(e.message);
|
|
1138
1157
|
}
|
|
1139
1158
|
// 3. Visit → AST
|
|
1140
|
-
|
|
1159
|
+
const result = toBridgeAst(cst, previousInstructions);
|
|
1160
|
+
return { version: result.version, instructions: result.instructions };
|
|
1141
1161
|
}
|
|
1142
1162
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
1143
1163
|
// CST → AST transformation (imperative visitor)
|
|
@@ -2204,9 +2224,22 @@ function toBridgeAst(cst, previousInstructions) {
|
|
|
2204
2224
|
}
|
|
2205
2225
|
const versionTok = tok(versionDecl, "ver");
|
|
2206
2226
|
const versionNum = versionTok?.image;
|
|
2207
|
-
if (versionNum
|
|
2208
|
-
throw new Error(`
|
|
2227
|
+
if (!versionNum) {
|
|
2228
|
+
throw new Error(`Missing version number. Bridge files must begin with: version ${BRIDGE_VERSION}`);
|
|
2229
|
+
}
|
|
2230
|
+
// Accept any version whose major falls within the supported range.
|
|
2231
|
+
// When the parser supports multiple majors (e.g. 1.x through 2.x),
|
|
2232
|
+
// bridge files from any of them are valid syntax.
|
|
2233
|
+
const vParts = versionNum.split(".");
|
|
2234
|
+
const vMajor = parseInt(vParts[0], 10);
|
|
2235
|
+
const supportedRange = BRIDGE_MIN_MAJOR === BRIDGE_MAX_MAJOR
|
|
2236
|
+
? `${BRIDGE_MIN_MAJOR}.x`
|
|
2237
|
+
: `${BRIDGE_MIN_MAJOR}.x – ${BRIDGE_MAX_MAJOR}.x`;
|
|
2238
|
+
if (isNaN(vMajor) || vMajor < BRIDGE_MIN_MAJOR || vMajor > BRIDGE_MAX_MAJOR) {
|
|
2239
|
+
throw new Error(`Unsupported bridge major version "${versionNum}". This parser supports version ${supportedRange}`);
|
|
2209
2240
|
}
|
|
2241
|
+
// Store the declared version (lives on BridgeDocument, not in instructions).
|
|
2242
|
+
const version = versionNum;
|
|
2210
2243
|
const tagged = [];
|
|
2211
2244
|
for (const n of subs(cst, "constDecl"))
|
|
2212
2245
|
tagged.push({
|
|
@@ -2270,7 +2303,7 @@ function toBridgeAst(cst, previousInstructions) {
|
|
|
2270
2303
|
}
|
|
2271
2304
|
}
|
|
2272
2305
|
}
|
|
2273
|
-
return { instructions, startLines };
|
|
2306
|
+
return { version, instructions, startLines };
|
|
2274
2307
|
}
|
|
2275
2308
|
// ── Const ───────────────────────────────────────────────────────────────
|
|
2276
2309
|
function buildConstDef(node) {
|
|
@@ -2319,7 +2352,13 @@ function buildToolDef(node, previousInstructions) {
|
|
|
2319
2352
|
else if (wc.toolName) {
|
|
2320
2353
|
const tName = extractDottedName(wc.toolName[0]);
|
|
2321
2354
|
const tAlias = extractNameToken(wc.toolAlias[0]);
|
|
2322
|
-
|
|
2355
|
+
const tVersion = wc.toolVersion?.[0]?.image.slice(1);
|
|
2356
|
+
deps.push({
|
|
2357
|
+
kind: "tool",
|
|
2358
|
+
handle: tAlias,
|
|
2359
|
+
tool: tName,
|
|
2360
|
+
...(tVersion ? { version: tVersion } : {}),
|
|
2361
|
+
});
|
|
2323
2362
|
}
|
|
2324
2363
|
continue;
|
|
2325
2364
|
}
|
|
@@ -2400,10 +2439,10 @@ function buildBridge(node, previousInstructions) {
|
|
|
2400
2439
|
`}`,
|
|
2401
2440
|
].join("\n");
|
|
2402
2441
|
const result = internalParse(expandedText, previousInstructions);
|
|
2403
|
-
const bridgeInst = result.find((i) => i.kind === "bridge");
|
|
2442
|
+
const bridgeInst = result.instructions.find((i) => i.kind === "bridge");
|
|
2404
2443
|
if (bridgeInst)
|
|
2405
2444
|
bridgeInst.passthrough = passthroughName;
|
|
2406
|
-
return result;
|
|
2445
|
+
return result.instructions;
|
|
2407
2446
|
}
|
|
2408
2447
|
// Full bridge block
|
|
2409
2448
|
const bodyLines = subs(node, "bridgeBodyLine");
|
|
@@ -2530,6 +2569,7 @@ function buildBridgeBody(bodyLines, bridgeType, bridgeField, previousInstruction
|
|
|
2530
2569
|
}
|
|
2531
2570
|
else if (wc.refName) {
|
|
2532
2571
|
const name = extractDottedName(wc.refName[0]);
|
|
2572
|
+
const versionTag = wc.refVersion?.[0]?.image.slice(1);
|
|
2533
2573
|
const lastDot = name.lastIndexOf(".");
|
|
2534
2574
|
const defaultHandle = lastDot !== -1 ? name.substring(lastDot + 1) : name;
|
|
2535
2575
|
const handle = wc.refAlias
|
|
@@ -2554,7 +2594,12 @@ function buildBridgeBody(bodyLines, bridgeType, bridgeField, previousInstruction
|
|
|
2554
2594
|
const key = `${modulePart}:${fieldPart}`;
|
|
2555
2595
|
const instance = (instanceCounters.get(key) ?? 0) + 1;
|
|
2556
2596
|
instanceCounters.set(key, instance);
|
|
2557
|
-
handleBindings.push({
|
|
2597
|
+
handleBindings.push({
|
|
2598
|
+
handle,
|
|
2599
|
+
kind: "tool",
|
|
2600
|
+
name,
|
|
2601
|
+
...(versionTag ? { version: versionTag } : {}),
|
|
2602
|
+
});
|
|
2558
2603
|
handleRes.set(handle, {
|
|
2559
2604
|
module: modulePart,
|
|
2560
2605
|
type: bridgeType,
|
|
@@ -2566,7 +2611,12 @@ function buildBridgeBody(bodyLines, bridgeType, bridgeField, previousInstruction
|
|
|
2566
2611
|
const key = `Tools:${name}`;
|
|
2567
2612
|
const instance = (instanceCounters.get(key) ?? 0) + 1;
|
|
2568
2613
|
instanceCounters.set(key, instance);
|
|
2569
|
-
handleBindings.push({
|
|
2614
|
+
handleBindings.push({
|
|
2615
|
+
handle,
|
|
2616
|
+
kind: "tool",
|
|
2617
|
+
name,
|
|
2618
|
+
...(versionTag ? { version: versionTag } : {}),
|
|
2619
|
+
});
|
|
2570
2620
|
handleRes.set(handle, {
|
|
2571
2621
|
module: SELF_MODULE,
|
|
2572
2622
|
type: "Tools",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stackables/bridge-compiler",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "Bridge DSL parser, serializer, and language service",
|
|
5
5
|
"main": "./build/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"chevrotain": "^11.1.2",
|
|
26
|
-
"@stackables/bridge-core": "0.0
|
|
27
|
-
"@stackables/bridge-stdlib": "
|
|
26
|
+
"@stackables/bridge-core": "1.0.0",
|
|
27
|
+
"@stackables/bridge-stdlib": "1.5.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@types/node": "^25.3.2",
|