@cavelang/parser 0.1.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 +105 -0
- package/dist/src/ast.d.ts +122 -0
- package/dist/src/ast.d.ts.map +1 -0
- package/dist/src/ast.js +13 -0
- package/dist/src/ast.js.map +1 -0
- package/dist/src/document.d.ts +36 -0
- package/dist/src/document.d.ts.map +1 -0
- package/dist/src/document.js +171 -0
- package/dist/src/document.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +19 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/line.d.ts +39 -0
- package/dist/src/line.d.ts.map +1 -0
- package/dist/src/line.js +293 -0
- package/dist/src/line.js.map +1 -0
- package/dist/src/token.d.ts +37 -0
- package/dist/src/token.d.ts.map +1 -0
- package/dist/src/token.js +51 -0
- package/dist/src/token.js.map +1 -0
- package/package.json +43 -0
- package/src/ast.ts +92 -0
- package/src/document.ts +190 -0
- package/src/index.ts +19 -0
- package/src/line.ts +335 -0
- package/src/token.ts +80 -0
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# @cavelang/parser
|
|
2
|
+
|
|
3
|
+
CAVE text → AST. Implements the syntax layer of the
|
|
4
|
+
[CAVE specification](../../README.md#the-specification): lexical rules (§4), line shapes
|
|
5
|
+
(§3), indentation kinds (§8) and the normative grammar (§16). Built on
|
|
6
|
+
[`@prelude/parser`](https://www.npmjs.com/package/@prelude/parser)
|
|
7
|
+
combinators.
|
|
8
|
+
|
|
9
|
+
The parser is deliberately *pre-semantic*: inverse verbs stay as written
|
|
10
|
+
(`packages/api PART-OF monorepo` keeps verb `PART-OF`), continuation lines
|
|
11
|
+
keep their missing endpoint, `UNLESS` stays `UNLESS`. The §13.4
|
|
12
|
+
canonicalization pipeline lives in `@cavelang/canonical`.
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import { parseDocument, parse } from '@cavelang/parser'
|
|
16
|
+
|
|
17
|
+
const doc = parseDocument(`
|
|
18
|
+
server CAUSE crash @ 80%
|
|
19
|
+
WHEN load > ~1000 req/s
|
|
20
|
+
WHEN NOT cache/enabled
|
|
21
|
+
`)
|
|
22
|
+
doc.lines // classified lines with depth + parent links
|
|
23
|
+
doc.diagnostics // never throws — problems are collected
|
|
24
|
+
|
|
25
|
+
parse('a USES b') // strict variant: throws on any diagnostic
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Pipeline
|
|
29
|
+
|
|
30
|
+
1. **Split physical lines**, measure indentation (`document.ts`).
|
|
31
|
+
2. **Split off the comment** at the first `;` outside quotes/backticks
|
|
32
|
+
(`Token.splitComment`).
|
|
33
|
+
3. **Tokenize** into words / `"text"` literals / `` `code` `` literals
|
|
34
|
+
(`token.ts`, `@prelude/parser` combinators).
|
|
35
|
+
4. **Classify** the line per §8's three-kind table: qualifier (starts with
|
|
36
|
+
`WHEN`/`UNLESS`/`VIA`/`BECAUSE`), continuation (starts with a bare
|
|
37
|
+
relational verb), or full claim.
|
|
38
|
+
5. **Parse the token stream** (`line.ts`): subject, verb, `NOT`, payload,
|
|
39
|
+
then metadata items.
|
|
40
|
+
6. **Resolve parents**: each structural line links to the nearest
|
|
41
|
+
less-indented structural line above.
|
|
42
|
+
|
|
43
|
+
## Payload classification
|
|
44
|
+
|
|
45
|
+
| Shape | Result |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `attr: value` | attribute payload (any verb — §21 uses `NEEDS test: …`) |
|
|
48
|
+
| `HAS attr value` (colonless, value numeric/date) | attribute payload + legacy diagnostic (§3.4) |
|
|
49
|
+
| numeric/date value (any verb) | metric payload — `latency IS 30ms`, `load EXCEEDS 1000 req/s` |
|
|
50
|
+
| nothing (verb `EXISTS`) | `none` payload (§5.2 bare existence) |
|
|
51
|
+
| single term | relational object |
|
|
52
|
+
| words only | relational object phrase (entity whitespace normalized later) |
|
|
53
|
+
|
|
54
|
+
The payload/metadata boundary is lexical: a metadata item is unambiguous at
|
|
55
|
+
its first token (`@ctx`, `@` + spaced percentage, `#tag`, `+/-`, `(Nσ)`,
|
|
56
|
+
`!`), so payload is everything before the first one (§4.3).
|
|
57
|
+
|
|
58
|
+
## Qualifier payloads
|
|
59
|
+
|
|
60
|
+
`qualifier_payload` is loose in the grammar; three shapes cover the spec's
|
|
61
|
+
examples and are tried in order:
|
|
62
|
+
|
|
63
|
+
1. full claim — `WHEN memory-leak EXISTS @ 60%` (§10.2)
|
|
64
|
+
2. comparison — `WHEN load > ~1000 req/s`; ops `>` `<` `>=` `<=` `=` `!=`
|
|
65
|
+
3. bare entity — `WHEN cache-miss`, `WHEN NOT cache/enabled`
|
|
66
|
+
|
|
67
|
+
## Design decisions
|
|
68
|
+
|
|
69
|
+
- **Never throw, always classify.** `parseDocument` returns an entry for
|
|
70
|
+
*every* physical line; broken ones become `invalid` with a diagnostic.
|
|
71
|
+
This honors the robust-extraction goal (§1.6) and makes the parser usable
|
|
72
|
+
as a linter.
|
|
73
|
+
- **Classification tiebreak.** A line starting with a verb-shaped token is
|
|
74
|
+
classified using the known standard vocabulary (standard verbs, `HAS`,
|
|
75
|
+
`REVERSE`, the §5.5 inverse names): second token `REVERSE` → claim
|
|
76
|
+
(declaration); second token a *known* verb → claim with an uppercase
|
|
77
|
+
subject (`API NEEDS auth`); first token known → continuation, even when
|
|
78
|
+
the object is ALL-CAPS (`USES JWT`, `PART-OF ORG`, `USES GPU cluster`);
|
|
79
|
+
neither known → claim (`API MIGRATES postgres`). The residual ambiguity —
|
|
80
|
+
an *extension*-verb continuation with an ALL-CAPS object — is inherently
|
|
81
|
+
registry-dependent and the parser stays registry-free; write the subject
|
|
82
|
+
explicitly there.
|
|
83
|
+
- **`@` disambiguation is exactly one character of lookahead** (§6.3):
|
|
84
|
+
the token `@` alone expects a following percentage (confidence);
|
|
85
|
+
`@anything` is a context.
|
|
86
|
+
- **No escape sequences in literals** — the spec defines none. A quoted
|
|
87
|
+
literal runs to the next matching delimiter; an unterminated one degrades
|
|
88
|
+
to a plain word.
|
|
89
|
+
- **Metadata problems don't kill lines.** `a USES b stray` parses with a
|
|
90
|
+
diagnostic; only structural failures (missing verb/object) invalidate a
|
|
91
|
+
line. Confidence must end in `%` and stay ≤ 100 (`@ 2026`, `@ 90`,
|
|
92
|
+
`@ 250%` are diagnosed rather than silently clamped); repeating a
|
|
93
|
+
non-repeatable metadata item (`@ N%`, `+/-`, `(Nσ)`, `!`) is diagnosed
|
|
94
|
+
with last-wins retention (§3.2 allows repetition only for contexts and
|
|
95
|
+
tags); a glued attribute colon (`expiry:3600s`) splits into the attribute
|
|
96
|
+
form with a diagnostic, since payload `:` is reserved (§4.3).
|
|
97
|
+
|
|
98
|
+
## Tests
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
pnpm --filter @cavelang/parser test
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Every syntax example from spec §3–§8, §16 and the §21 worked example is a
|
|
105
|
+
test case.
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAVE abstract syntax (spec §16).
|
|
3
|
+
*
|
|
4
|
+
* The parser turns text into `Line` values — pure syntax, before
|
|
5
|
+
* canonicalization. Inverse verbs are *not* resolved here (`packages/api
|
|
6
|
+
* PART-OF monorepo` parses with verb `PART-OF`); continuation lines keep
|
|
7
|
+
* their missing endpoint; qualifier payloads keep their surface shape.
|
|
8
|
+
* `@cavelang/canonical` applies the spec §13.4 pipeline on top of this AST.
|
|
9
|
+
*/
|
|
10
|
+
import type { Claim, Value, Tag, Context, Verb } from '@cavelang/core';
|
|
11
|
+
/** Line metadata suffixes (spec §6), all optional. */
|
|
12
|
+
export type Meta = {
|
|
13
|
+
readonly contexts: readonly Context.t[];
|
|
14
|
+
readonly tags: readonly Tag.t[];
|
|
15
|
+
/** `@ N%` as decimal; `undefined` means the default 100%. */
|
|
16
|
+
readonly conf?: number;
|
|
17
|
+
readonly importance: boolean;
|
|
18
|
+
/** `+/- delta` (spec §7.2). */
|
|
19
|
+
readonly delta?: Value.t;
|
|
20
|
+
/** `(Nσ)` override (spec §7.2). */
|
|
21
|
+
readonly sigmaLevel?: number;
|
|
22
|
+
/** `; comment` (spec §6.4). */
|
|
23
|
+
readonly comment?: string;
|
|
24
|
+
};
|
|
25
|
+
/** Empty metadata. */
|
|
26
|
+
export declare const emptyMeta: Meta;
|
|
27
|
+
/** Claim body without a subject — what a continuation line carries (spec §8.3). */
|
|
28
|
+
export type Body = {
|
|
29
|
+
readonly verb: string;
|
|
30
|
+
readonly negated: boolean;
|
|
31
|
+
readonly payload: Claim.Payload;
|
|
32
|
+
readonly meta: Meta;
|
|
33
|
+
};
|
|
34
|
+
/** Full claim: subject + body. */
|
|
35
|
+
export type Full = Body & {
|
|
36
|
+
readonly subject: Claim.Term;
|
|
37
|
+
};
|
|
38
|
+
/** Comparison operators accepted in qualifier payloads (`WHEN load > ~1000 req/s`). */
|
|
39
|
+
export type ComparisonOp = '>' | '<' | '>=' | '<=' | '=' | '!=';
|
|
40
|
+
export declare const comparisonOps: readonly ComparisonOp[];
|
|
41
|
+
/**
|
|
42
|
+
* Qualifier payload (spec §8.2). The grammar leaves `qualifier_payload`
|
|
43
|
+
* loose; three surface shapes cover the spec's examples:
|
|
44
|
+
*
|
|
45
|
+
* - full claim: `WHEN memory-leak EXISTS @ 60%`
|
|
46
|
+
* - bare entity: `WHEN cache-miss`, `WHEN NOT cache/enabled`
|
|
47
|
+
* - comparison: `WHEN load > ~1000 req/s`
|
|
48
|
+
*
|
|
49
|
+
* `negated` records a `NOT` immediately after the qualifier verb.
|
|
50
|
+
*/
|
|
51
|
+
export type QualifierPayload = {
|
|
52
|
+
readonly kind: 'claim';
|
|
53
|
+
readonly negated: boolean;
|
|
54
|
+
readonly claim: Full;
|
|
55
|
+
} | {
|
|
56
|
+
readonly kind: 'entity';
|
|
57
|
+
readonly negated: boolean;
|
|
58
|
+
readonly term: Claim.Term;
|
|
59
|
+
readonly meta: Meta;
|
|
60
|
+
} | {
|
|
61
|
+
readonly kind: 'comparison';
|
|
62
|
+
readonly negated: boolean;
|
|
63
|
+
readonly left: Claim.Term;
|
|
64
|
+
readonly op: ComparisonOp;
|
|
65
|
+
readonly value: Value.t;
|
|
66
|
+
readonly meta: Meta;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* A parsed line. `depth` is the indentation width in characters; `parent` is
|
|
70
|
+
* the index (into the document's `lines`) of the nearest less-indented
|
|
71
|
+
* structural line above (spec §8). `raw` is the line exactly as written.
|
|
72
|
+
*/
|
|
73
|
+
export type Line = {
|
|
74
|
+
readonly kind: 'blank';
|
|
75
|
+
readonly line: number;
|
|
76
|
+
readonly raw: string;
|
|
77
|
+
} | {
|
|
78
|
+
readonly kind: 'comment';
|
|
79
|
+
readonly line: number;
|
|
80
|
+
readonly raw: string;
|
|
81
|
+
readonly text: string;
|
|
82
|
+
} | {
|
|
83
|
+
readonly kind: 'claim';
|
|
84
|
+
readonly line: number;
|
|
85
|
+
readonly raw: string;
|
|
86
|
+
readonly depth: number;
|
|
87
|
+
readonly parent?: number;
|
|
88
|
+
readonly claim: Full;
|
|
89
|
+
} | {
|
|
90
|
+
readonly kind: 'continuation';
|
|
91
|
+
readonly line: number;
|
|
92
|
+
readonly raw: string;
|
|
93
|
+
readonly depth: number;
|
|
94
|
+
readonly parent?: number;
|
|
95
|
+
readonly body: Body;
|
|
96
|
+
} | {
|
|
97
|
+
readonly kind: 'qualifier';
|
|
98
|
+
readonly line: number;
|
|
99
|
+
readonly raw: string;
|
|
100
|
+
readonly depth: number;
|
|
101
|
+
readonly parent?: number;
|
|
102
|
+
readonly qualifier: Verb.Qualifier;
|
|
103
|
+
readonly payload: QualifierPayload;
|
|
104
|
+
} | {
|
|
105
|
+
readonly kind: 'invalid';
|
|
106
|
+
readonly line: number;
|
|
107
|
+
readonly raw: string;
|
|
108
|
+
readonly message: string;
|
|
109
|
+
};
|
|
110
|
+
export type t = Line;
|
|
111
|
+
/** Parser problem tied to a 1-based line number. */
|
|
112
|
+
export type Diagnostic = {
|
|
113
|
+
readonly line: number;
|
|
114
|
+
readonly message: string;
|
|
115
|
+
readonly raw: string;
|
|
116
|
+
};
|
|
117
|
+
/** Parsed document: every input line classified, plus collected problems. */
|
|
118
|
+
export type Document = {
|
|
119
|
+
readonly lines: readonly Line[];
|
|
120
|
+
readonly diagnostics: readonly Diagnostic[];
|
|
121
|
+
};
|
|
122
|
+
//# sourceMappingURL=ast.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.d.ts","sourceRoot":"","sources":["../../src/ast.ts"],"names":[],"mappings":"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"}
|
package/dist/src/ast.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CAVE abstract syntax (spec §16).
|
|
3
|
+
*
|
|
4
|
+
* The parser turns text into `Line` values — pure syntax, before
|
|
5
|
+
* canonicalization. Inverse verbs are *not* resolved here (`packages/api
|
|
6
|
+
* PART-OF monorepo` parses with verb `PART-OF`); continuation lines keep
|
|
7
|
+
* their missing endpoint; qualifier payloads keep their surface shape.
|
|
8
|
+
* `@cavelang/canonical` applies the spec §13.4 pipeline on top of this AST.
|
|
9
|
+
*/
|
|
10
|
+
/** Empty metadata. */
|
|
11
|
+
export const emptyMeta = { contexts: [], tags: [], importance: false };
|
|
12
|
+
export const comparisonOps = ['>', '<', '>=', '<=', '=', '!='];
|
|
13
|
+
//# sourceMappingURL=ast.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ast.js","sourceRoot":"","sources":["../../src/ast.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmBH,sBAAsB;AACtB,MAAM,CAAC,MAAM,SAAS,GACpB,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAA;AAkB/C,MAAM,CAAC,MAAM,aAAa,GACxB,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document parser (spec §8, §16).
|
|
3
|
+
*
|
|
4
|
+
* Splits input into physical lines, measures indentation, classifies each
|
|
5
|
+
* line (blank / comment / claim / continuation / qualifier), and resolves
|
|
6
|
+
* each indented line's parent — the nearest less-indented structural line
|
|
7
|
+
* above (spec §8).
|
|
8
|
+
*
|
|
9
|
+
* Classification of an indented line follows spec §8's table, decided by
|
|
10
|
+
* what the line starts with:
|
|
11
|
+
*
|
|
12
|
+
* - qualifier verb (`WHEN`/`UNLESS`/`VIA`/`BECAUSE`) → qualifier
|
|
13
|
+
* - bare relational verb → continuation
|
|
14
|
+
* - full triple → grouped claim
|
|
15
|
+
*
|
|
16
|
+
* One ambiguity needs a tiebreak: `API NEEDS auth` starts with a token that
|
|
17
|
+
* is lexically verb-shaped. If the *second* token is also verb-shaped (and
|
|
18
|
+
* not `NOT`), the line is a full triple with an uppercase subject —
|
|
19
|
+
* `CONTAINS REVERSE PART-OF` and `API NEEDS auth` both land here; otherwise
|
|
20
|
+
* it is a continuation.
|
|
21
|
+
*
|
|
22
|
+
* `parseDocument` never throws: broken lines become `invalid` entries and
|
|
23
|
+
* every problem is a diagnostic. `parse` is the strict variant.
|
|
24
|
+
*/
|
|
25
|
+
import type * as Ast from './ast.ts';
|
|
26
|
+
/**
|
|
27
|
+
* Parses a CAVE document. Never throws; problems surface as diagnostics and
|
|
28
|
+
* `invalid` lines.
|
|
29
|
+
*/
|
|
30
|
+
export declare const parseDocument: (input: string) => Ast.Document;
|
|
31
|
+
/**
|
|
32
|
+
* Strict parse: like {@link parseDocument} but throws an `Error` listing
|
|
33
|
+
* every diagnostic when the document has any.
|
|
34
|
+
*/
|
|
35
|
+
export declare const parse: (input: string) => readonly Ast.Line[];
|
|
36
|
+
//# sourceMappingURL=document.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../../src/document.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAA;AAgDpC;;;GAGG;AACH,eAAO,MAAM,aAAa,GAAI,OAAO,MAAM,KAAG,GAAG,CAAC,QAgGjD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG,SAAS,GAAG,CAAC,IAAI,EAStD,CAAA"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Document parser (spec §8, §16).
|
|
3
|
+
*
|
|
4
|
+
* Splits input into physical lines, measures indentation, classifies each
|
|
5
|
+
* line (blank / comment / claim / continuation / qualifier), and resolves
|
|
6
|
+
* each indented line's parent — the nearest less-indented structural line
|
|
7
|
+
* above (spec §8).
|
|
8
|
+
*
|
|
9
|
+
* Classification of an indented line follows spec §8's table, decided by
|
|
10
|
+
* what the line starts with:
|
|
11
|
+
*
|
|
12
|
+
* - qualifier verb (`WHEN`/`UNLESS`/`VIA`/`BECAUSE`) → qualifier
|
|
13
|
+
* - bare relational verb → continuation
|
|
14
|
+
* - full triple → grouped claim
|
|
15
|
+
*
|
|
16
|
+
* One ambiguity needs a tiebreak: `API NEEDS auth` starts with a token that
|
|
17
|
+
* is lexically verb-shaped. If the *second* token is also verb-shaped (and
|
|
18
|
+
* not `NOT`), the line is a full triple with an uppercase subject —
|
|
19
|
+
* `CONTAINS REVERSE PART-OF` and `API NEEDS auth` both land here; otherwise
|
|
20
|
+
* it is a continuation.
|
|
21
|
+
*
|
|
22
|
+
* `parseDocument` never throws: broken lines become `invalid` entries and
|
|
23
|
+
* every problem is a diagnostic. `parse` is the strict variant.
|
|
24
|
+
*/
|
|
25
|
+
import { Verb } from '@cavelang/core';
|
|
26
|
+
import * as Line from "./line.js";
|
|
27
|
+
import * as Token from "./token.js";
|
|
28
|
+
const indentOf = (raw) => {
|
|
29
|
+
let depth = 0;
|
|
30
|
+
let tabs = false;
|
|
31
|
+
while (depth < raw.length && (raw[depth] === ' ' || raw[depth] === '\t')) {
|
|
32
|
+
tabs ||= raw[depth] === '\t';
|
|
33
|
+
depth += 1;
|
|
34
|
+
}
|
|
35
|
+
return { depth, rest: raw.slice(depth), tabs };
|
|
36
|
+
};
|
|
37
|
+
const classify = (tokens, depth) => {
|
|
38
|
+
const head = tokens[0];
|
|
39
|
+
if (head.kind === 'word' && Verb.isQualifier(head.text)) {
|
|
40
|
+
return depth > 0 ?
|
|
41
|
+
'qualifier' :
|
|
42
|
+
{ error: `qualifier verb ${head.text} at top level — qualifiers attach to a parent claim (spec §8.2)` };
|
|
43
|
+
}
|
|
44
|
+
if (head.kind === 'word' && Verb.isVerbToken(head.text)) {
|
|
45
|
+
const second = tokens[1];
|
|
46
|
+
const secondWord = second?.kind === 'word' ? second.text : undefined;
|
|
47
|
+
// Tiebreak between "continuation" and "full triple with an uppercase
|
|
48
|
+
// subject", using the known standard vocabulary (see the README):
|
|
49
|
+
// CONTAINS REVERSE PART-OF → claim (declaration)
|
|
50
|
+
// NEEDS NOT downtime → continuation (NOT is a modifier)
|
|
51
|
+
// API NEEDS auth → claim (second token is a known verb)
|
|
52
|
+
// USES JWT / PART-OF ORG → continuation (first known, second not)
|
|
53
|
+
// API MIGRATES postgres → claim (neither known — subject wins)
|
|
54
|
+
const kind = secondWord === Verb.REVERSE ? 'claim' :
|
|
55
|
+
secondWord !== undefined && secondWord !== 'NOT' && Verb.isVerbToken(secondWord) ?
|
|
56
|
+
(Verb.isKnown(secondWord) ? 'claim' : Verb.isKnown(head.text) ? 'continuation' : 'claim') :
|
|
57
|
+
'continuation';
|
|
58
|
+
if (kind === 'continuation' && depth === 0) {
|
|
59
|
+
return { error: `continuation line at top level — nothing to inherit a subject from (spec §8.3)` };
|
|
60
|
+
}
|
|
61
|
+
return kind;
|
|
62
|
+
}
|
|
63
|
+
return 'claim';
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* Parses a CAVE document. Never throws; problems surface as diagnostics and
|
|
67
|
+
* `invalid` lines.
|
|
68
|
+
*/
|
|
69
|
+
export const parseDocument = (input) => {
|
|
70
|
+
const lines = [];
|
|
71
|
+
const diagnostics = [];
|
|
72
|
+
const stack = [];
|
|
73
|
+
const rawLines = input.split(/\r?\n/);
|
|
74
|
+
const problem = (line, raw, message) => {
|
|
75
|
+
diagnostics.push({ line, message, raw });
|
|
76
|
+
};
|
|
77
|
+
rawLines.forEach((raw, at) => {
|
|
78
|
+
const lineNo = at + 1;
|
|
79
|
+
const { depth, rest, tabs } = indentOf(raw);
|
|
80
|
+
if (tabs) {
|
|
81
|
+
problem(lineNo, raw, 'tab in indentation — use spaces');
|
|
82
|
+
}
|
|
83
|
+
if (rest === '') {
|
|
84
|
+
lines.push({ kind: 'blank', line: lineNo, raw });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (rest.startsWith(';')) {
|
|
88
|
+
lines.push({ kind: 'comment', line: lineNo, raw, text: rest.slice(1).trim() });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const { head, comment } = Token.splitComment(rest);
|
|
92
|
+
const tokens = Token.tokenize(head);
|
|
93
|
+
if (tokens.length === 0) {
|
|
94
|
+
lines.push({ kind: 'comment', line: lineNo, raw, text: comment ?? '' });
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const kind = classify(tokens, depth);
|
|
98
|
+
if (typeof kind === 'object') {
|
|
99
|
+
problem(lineNo, raw, kind.error);
|
|
100
|
+
lines.push({ kind: 'invalid', line: lineNo, raw, message: kind.error });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
while (stack.length > 0 && stack[stack.length - 1].depth >= depth) {
|
|
104
|
+
stack.pop();
|
|
105
|
+
}
|
|
106
|
+
const parent = stack[stack.length - 1]?.index;
|
|
107
|
+
if (parent === undefined && kind !== 'claim') {
|
|
108
|
+
const message = `${kind} line has no parent claim above (spec §8)`;
|
|
109
|
+
problem(lineNo, raw, message);
|
|
110
|
+
lines.push({ kind: 'invalid', line: lineNo, raw, message });
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const index = lines.length;
|
|
114
|
+
const push = (line, problems) => {
|
|
115
|
+
lines.push(line);
|
|
116
|
+
stack.push({ index, depth });
|
|
117
|
+
for (const message of problems) {
|
|
118
|
+
problem(lineNo, raw, message);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
switch (kind) {
|
|
122
|
+
case 'claim': {
|
|
123
|
+
const result = Line.parseClaim(tokens, comment);
|
|
124
|
+
if (!result.ok) {
|
|
125
|
+
problem(lineNo, raw, result.message);
|
|
126
|
+
lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
push({ kind: 'claim', line: lineNo, raw, depth, ...parent !== undefined ? { parent } : {}, claim: result.value }, result.problems);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
case 'continuation': {
|
|
133
|
+
const result = Line.parseBody(tokens, comment);
|
|
134
|
+
if (!result.ok) {
|
|
135
|
+
problem(lineNo, raw, result.message);
|
|
136
|
+
lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message });
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
push({ kind: 'continuation', line: lineNo, raw, depth, parent: parent, body: result.value }, result.problems);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
case 'qualifier': {
|
|
143
|
+
const qualifier = tokens[0].text;
|
|
144
|
+
const result = Line.parseQualifierPayload(tokens.slice(1), comment);
|
|
145
|
+
if (!result.ok) {
|
|
146
|
+
problem(lineNo, raw, result.message);
|
|
147
|
+
lines.push({ kind: 'invalid', line: lineNo, raw, message: result.message });
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
push({ kind: 'qualifier', line: lineNo, raw, depth, parent: parent, qualifier, payload: result.value }, result.problems);
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
return { lines, diagnostics };
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* Strict parse: like {@link parseDocument} but throws an `Error` listing
|
|
159
|
+
* every diagnostic when the document has any.
|
|
160
|
+
*/
|
|
161
|
+
export const parse = (input) => {
|
|
162
|
+
const { lines, diagnostics } = parseDocument(input);
|
|
163
|
+
if (diagnostics.length > 0) {
|
|
164
|
+
const detail = diagnostics
|
|
165
|
+
.map(diagnostic => ` line ${diagnostic.line}: ${diagnostic.message}`)
|
|
166
|
+
.join('\n');
|
|
167
|
+
throw new Error(`CAVE parse failed with ${diagnostics.length} problem(s):\n${detail}`);
|
|
168
|
+
}
|
|
169
|
+
return lines;
|
|
170
|
+
};
|
|
171
|
+
//# sourceMappingURL=document.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"document.js","sourceRoot":"","sources":["../../src/document.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@cavelang/parser` — CAVE text → AST (spec §3, §4, §8, §16).
|
|
3
|
+
*
|
|
4
|
+
* Line-oriented parser for the normative CAVE language, built on
|
|
5
|
+
* `@prelude/parser` combinators. Produces pure syntax: inverse verbs,
|
|
6
|
+
* continuations and `UNLESS` are resolved later by `@cavelang/canonical`
|
|
7
|
+
* (spec §13.4).
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { parseDocument } from '@cavelang/parser'
|
|
11
|
+
*
|
|
12
|
+
* const { lines, diagnostics } = parseDocument('auth/middleware USES jwt @ 90%')
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export * as Ast from './ast.ts';
|
|
16
|
+
export * as Line from './line.ts';
|
|
17
|
+
export * as Token from './token.ts';
|
|
18
|
+
export { parseDocument, parse } from './document.ts';
|
|
19
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@cavelang/parser` — CAVE text → AST (spec §3, §4, §8, §16).
|
|
3
|
+
*
|
|
4
|
+
* Line-oriented parser for the normative CAVE language, built on
|
|
5
|
+
* `@prelude/parser` combinators. Produces pure syntax: inverse verbs,
|
|
6
|
+
* continuations and `UNLESS` are resolved later by `@cavelang/canonical`
|
|
7
|
+
* (spec §13.4).
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { parseDocument } from '@cavelang/parser'
|
|
11
|
+
*
|
|
12
|
+
* const { lines, diagnostics } = parseDocument('auth/middleware USES jwt @ 90%')
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export * as Ast from "./ast.js";
|
|
16
|
+
export * as Line from "./line.js";
|
|
17
|
+
export * as Token from "./token.js";
|
|
18
|
+
export { parseDocument, parse } from "./document.js";
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,GAAG,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAA;AACjC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,eAAe,CAAA"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Token-stream line parser (spec §3.2, §16).
|
|
3
|
+
*
|
|
4
|
+
* Parses the token list of one line into claim/continuation/qualifier
|
|
5
|
+
* bodies. The payload/metadata boundary is decided lexically: metadata items
|
|
6
|
+
* are unambiguous at their first token (spec §4.3 reserved characters), so
|
|
7
|
+
* everything before the first metadata token is payload.
|
|
8
|
+
*/
|
|
9
|
+
import type * as Ast from './ast.ts';
|
|
10
|
+
import type { Token } from './token.ts';
|
|
11
|
+
export type Result<T> = {
|
|
12
|
+
readonly ok: true;
|
|
13
|
+
readonly value: T;
|
|
14
|
+
readonly problems: readonly string[];
|
|
15
|
+
} | {
|
|
16
|
+
readonly ok: false;
|
|
17
|
+
readonly message: string;
|
|
18
|
+
};
|
|
19
|
+
/** @returns `true` if `token` starts a metadata item (spec §4.3). */
|
|
20
|
+
export declare const isMetaStart: (token: Token) => boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Parses metadata tokens (spec §6). Never fails — unrecognized tokens are
|
|
23
|
+
* reported as problems and skipped, honoring the robust-extraction goal
|
|
24
|
+
* (spec §1.6).
|
|
25
|
+
*/
|
|
26
|
+
export declare const parseMeta: (tokens: readonly Token[], comment?: string) => {
|
|
27
|
+
meta: Ast.Meta;
|
|
28
|
+
problems: string[];
|
|
29
|
+
};
|
|
30
|
+
/** Parses `verb [NOT] payload metadata` — a continuation body (spec §8.3). */
|
|
31
|
+
export declare const parseBody: (tokens: readonly Token[], comment?: string) => Result<Ast.Body>;
|
|
32
|
+
/** Parses `subject verb [NOT] payload metadata` — a full claim line (spec §16). */
|
|
33
|
+
export declare const parseClaim: (tokens: readonly Token[], comment?: string) => Result<Ast.Full>;
|
|
34
|
+
/**
|
|
35
|
+
* Parses a qualifier payload (spec §8.2): a full claim, a comparison, or a
|
|
36
|
+
* bare entity — tried in that order.
|
|
37
|
+
*/
|
|
38
|
+
export declare const parseQualifierPayload: (tokens: readonly Token[], comment?: string) => Result<Ast.QualifierPayload>;
|
|
39
|
+
//# sourceMappingURL=line.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"line.d.ts","sourceRoot":"","sources":["../../src/line.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,KAAK,GAAG,MAAM,UAAU,CAAA;AACpC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAEvC,MAAM,MAAM,MAAM,CAAC,CAAC,IAChB;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,GAC9E;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAA;AAUpD,qEAAqE;AACrE,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,KAAG,OAOxC,CAAA;AAgCH;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,UAAU,MAAM,KAAG;IAAE,IAAI,EAAE,GAAG,CAAC,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;CAuG1G,CAAA;AA2ED,8EAA8E;AAC9E,eAAO,MAAM,SAAS,GAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,UAAU,MAAM,KAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAkBrF,CAAA;AAED,mFAAmF;AACnF,eAAO,MAAM,UAAU,GAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,UAAU,MAAM,KAAG,MAAM,CAAC,GAAG,CAAC,IAAI,CAatF,CAAA;AAKD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,UAAU,MAAM,KAAG,MAAM,CAAC,GAAG,CAAC,gBAAgB,CA0C7G,CAAA"}
|