@ldclabs/kip-lang 2.0.2 → 2.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/CHANGELOG.md +69 -0
- package/README.md +4 -4
- package/dist/ast.d.ts +75 -58
- package/dist/ast.d.ts.map +1 -1
- package/dist/exec-ast.d.ts +51 -50
- package/dist/exec-ast.d.ts.map +1 -1
- package/dist/formatter.d.ts.map +1 -1
- package/dist/formatter.js +62 -121
- package/dist/formatter.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +112 -97
- package/dist/lower.js.map +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +146 -224
- package/dist/parser.js.map +1 -1
- package/dist/semantics.js +66 -35
- package/dist/semantics.js.map +1 -1
- package/dist/token.d.ts +4 -11
- package/dist/token.d.ts.map +1 -1
- package/dist/token.js +8 -22
- package/dist/token.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/src/ast.ts +73 -70
- package/src/exec-ast.ts +53 -42
- package/src/formatter.ts +61 -139
- package/src/index.ts +7 -13
- package/src/lower.ts +134 -106
- package/src/parser.ts +161 -250
- package/src/semantics.ts +63 -37
- package/src/token.ts +8 -22
- package/src/version.ts +1 -1
package/src/parser.ts
CHANGED
|
@@ -63,17 +63,13 @@ import type {
|
|
|
63
63
|
UnsetStructuralClause,
|
|
64
64
|
StructuralRemoval,
|
|
65
65
|
ExpectVersionClause,
|
|
66
|
-
|
|
66
|
+
VersionPlane,
|
|
67
67
|
UpdateStatement,
|
|
68
68
|
UpdateAction,
|
|
69
|
-
|
|
70
|
-
SupersedeAssertionStatement,
|
|
71
|
-
CorrectEvidenceStatement,
|
|
72
|
-
TransitionActivityStatement,
|
|
69
|
+
TransitionStatement,
|
|
73
70
|
SetRetentionStatement,
|
|
74
|
-
ArchiveStatement,
|
|
75
|
-
TombstoneStatement,
|
|
76
71
|
PurgeStatement,
|
|
72
|
+
PurgePayloadStatement,
|
|
77
73
|
MergeConceptStatement,
|
|
78
74
|
DescribeStatement,
|
|
79
75
|
DescribeTargetKind,
|
|
@@ -88,7 +84,6 @@ import type {
|
|
|
88
84
|
PreviewStatement,
|
|
89
85
|
HistoryStatement,
|
|
90
86
|
ChangesStatement,
|
|
91
|
-
SnapshotStatement,
|
|
92
87
|
ExportCapsuleStatement,
|
|
93
88
|
Expression,
|
|
94
89
|
FunctionCallExpr,
|
|
@@ -199,13 +194,8 @@ class Parser {
|
|
|
199
194
|
case TokenType.Ensure:
|
|
200
195
|
case TokenType.Assert:
|
|
201
196
|
case TokenType.Update:
|
|
202
|
-
case TokenType.Retract:
|
|
203
|
-
case TokenType.Supersede:
|
|
204
|
-
case TokenType.Correct:
|
|
205
197
|
case TokenType.Transition:
|
|
206
198
|
case TokenType.Set:
|
|
207
|
-
case TokenType.Archive:
|
|
208
|
-
case TokenType.Tombstone:
|
|
209
199
|
case TokenType.Purge:
|
|
210
200
|
case TokenType.Merge:
|
|
211
201
|
return this.parseMutationClause()
|
|
@@ -227,8 +217,6 @@ class Parser {
|
|
|
227
217
|
return this.parseHistoryStatement()
|
|
228
218
|
case TokenType.Changes:
|
|
229
219
|
return this.parseChangesStatement()
|
|
230
|
-
case TokenType.Snapshot:
|
|
231
|
-
return this.parseSnapshotStatement()
|
|
232
220
|
case TokenType.Export:
|
|
233
221
|
return this.parseExportCapsuleStatement()
|
|
234
222
|
|
|
@@ -255,20 +243,10 @@ class Parser {
|
|
|
255
243
|
return this.parseAssertStatement()
|
|
256
244
|
case TokenType.Update:
|
|
257
245
|
return this.parseUpdateStatement()
|
|
258
|
-
case TokenType.Retract:
|
|
259
|
-
return this.parseRetractAssertion()
|
|
260
|
-
case TokenType.Supersede:
|
|
261
|
-
return this.parseSupersedeAssertion()
|
|
262
|
-
case TokenType.Correct:
|
|
263
|
-
return this.parseCorrectEvidence()
|
|
264
246
|
case TokenType.Transition:
|
|
265
|
-
return this.
|
|
247
|
+
return this.parseTransitionStatement()
|
|
266
248
|
case TokenType.Set:
|
|
267
249
|
return this.parseSetRetention()
|
|
268
|
-
case TokenType.Archive:
|
|
269
|
-
return this.parseArchiveStatement()
|
|
270
|
-
case TokenType.Tombstone:
|
|
271
|
-
return this.parseTombstoneStatement()
|
|
272
250
|
case TokenType.Purge:
|
|
273
251
|
return this.parsePurgeStatement()
|
|
274
252
|
case TokenType.Merge:
|
|
@@ -385,25 +363,18 @@ class Parser {
|
|
|
385
363
|
const start = this.currentPos()
|
|
386
364
|
const first = this.expect(TokenType.As)
|
|
387
365
|
this.expectSecondWord(TokenType.Of, first)
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
} else if (this.match(TokenType.Tx)) {
|
|
393
|
-
basis = 'TX'
|
|
394
|
-
} else if (this.match(TokenType.Time)) {
|
|
395
|
-
basis = 'TIME'
|
|
396
|
-
} else {
|
|
366
|
+
// Cognitive time is a sequence coordinate. A transaction id or an instant
|
|
367
|
+
// is resolved to one first (DESCRIBE TRANSACTION / DESCRIBE SNAPSHOT AT
|
|
368
|
+
// TIME), so the read names the sequence it actually ran against.
|
|
369
|
+
if (!this.match(TokenType.Seq)) {
|
|
397
370
|
this.error(
|
|
398
|
-
`Expected SEQ
|
|
371
|
+
`Expected SEQ after AS OF but got '${this.current().value}'`,
|
|
399
372
|
this.current()
|
|
400
373
|
)
|
|
401
|
-
basis = 'SEQ'
|
|
402
374
|
}
|
|
403
375
|
const value = this.parseScalarValue()
|
|
404
376
|
return {
|
|
405
377
|
kind: 'AsOfClause',
|
|
406
|
-
basis,
|
|
407
378
|
value,
|
|
408
379
|
range: { start, end: this.endPos() }
|
|
409
380
|
}
|
|
@@ -1263,6 +1234,7 @@ class Parser {
|
|
|
1263
1234
|
handle,
|
|
1264
1235
|
setFacets: [],
|
|
1265
1236
|
unsetFacets: [],
|
|
1237
|
+
expectVersions: [],
|
|
1266
1238
|
range: { start, end: start },
|
|
1267
1239
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1268
1240
|
}
|
|
@@ -1277,10 +1249,6 @@ class Parser {
|
|
|
1277
1249
|
this.rejectRepeat(stmt.match, 'MATCH', tok)
|
|
1278
1250
|
stmt.match = this.parseMatchClause()
|
|
1279
1251
|
break
|
|
1280
|
-
case TokenType.Expect:
|
|
1281
|
-
this.rejectRepeat(stmt.expectVersion, 'EXPECT VERSION', tok)
|
|
1282
|
-
stmt.expectVersion = this.parseExpectVersionClause()
|
|
1283
|
-
break
|
|
1284
1252
|
case TokenType.Set: {
|
|
1285
1253
|
const clause = this.parseSetClause()
|
|
1286
1254
|
if (clause.kind === 'SetFieldsClause') {
|
|
@@ -1319,6 +1287,9 @@ class Parser {
|
|
|
1319
1287
|
if (this.pos === before) break
|
|
1320
1288
|
}
|
|
1321
1289
|
this.expect(TokenType.RBrace)
|
|
1290
|
+
// Preconditions trail the body, in the one tail order every mutation
|
|
1291
|
+
// shares: [WHERE] [LIMIT] {EXPECT VERSION} (Spec §52.8).
|
|
1292
|
+
stmt.expectVersions = this.parseExpectVersions()
|
|
1322
1293
|
stmt.range = { start, end: this.endPos() }
|
|
1323
1294
|
return stmt
|
|
1324
1295
|
}
|
|
@@ -1334,15 +1305,13 @@ class Parser {
|
|
|
1334
1305
|
: undefined
|
|
1335
1306
|
this.dialect = 'raw'
|
|
1336
1307
|
const tuple = this.parsePropositionTuple()
|
|
1337
|
-
const
|
|
1338
|
-
? this.parseExpectVersionClause()
|
|
1339
|
-
: undefined
|
|
1308
|
+
const expectVersions = this.parseExpectVersions()
|
|
1340
1309
|
|
|
1341
1310
|
return {
|
|
1342
1311
|
kind: 'EnsurePropositionStatement',
|
|
1343
1312
|
handle,
|
|
1344
1313
|
tuple,
|
|
1345
|
-
|
|
1314
|
+
expectVersions,
|
|
1346
1315
|
range: { start, end: this.endPos() },
|
|
1347
1316
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1348
1317
|
}
|
|
@@ -1613,23 +1582,52 @@ class Parser {
|
|
|
1613
1582
|
const expect = this.expect(TokenType.Expect)
|
|
1614
1583
|
this.expectSecondWord(TokenType.Version, expect)
|
|
1615
1584
|
const value = this.parseScalarValue()
|
|
1585
|
+
|
|
1586
|
+
// `OF <plane>` guards one plane's own version instead of the element's
|
|
1587
|
+
// (Spec §35.1): a verdict guarded on ATTRIBUTES is not spoiled by a
|
|
1588
|
+
// metabolism sweep that touched a Facet.
|
|
1589
|
+
let plane: VersionPlane | undefined
|
|
1590
|
+
if (this.match(TokenType.Of)) {
|
|
1591
|
+
const tok = this.current()
|
|
1592
|
+
switch (tok.type) {
|
|
1593
|
+
case TokenType.Attributes:
|
|
1594
|
+
this.advance()
|
|
1595
|
+
plane = { kind: 'ATTRIBUTES' }
|
|
1596
|
+
break
|
|
1597
|
+
case TokenType.Structural:
|
|
1598
|
+
this.advance()
|
|
1599
|
+
plane = { kind: 'STRUCTURAL' }
|
|
1600
|
+
break
|
|
1601
|
+
case TokenType.Retention:
|
|
1602
|
+
this.advance()
|
|
1603
|
+
plane = { kind: 'RETENTION' }
|
|
1604
|
+
break
|
|
1605
|
+
case TokenType.Facet:
|
|
1606
|
+
this.advance()
|
|
1607
|
+
plane = { kind: 'FACET', facet: this.parseSchemaSymbol() }
|
|
1608
|
+
break
|
|
1609
|
+
default:
|
|
1610
|
+
this.error(
|
|
1611
|
+
`Expected ATTRIBUTES, STRUCTURAL, RETENTION or FACET after OF but got '${tok.value}'`,
|
|
1612
|
+
tok
|
|
1613
|
+
)
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
1616
|
return {
|
|
1617
1617
|
kind: 'ExpectVersionClause',
|
|
1618
1618
|
value,
|
|
1619
|
+
plane,
|
|
1619
1620
|
range: { start, end: this.endPos() }
|
|
1620
1621
|
}
|
|
1621
1622
|
}
|
|
1622
1623
|
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
const
|
|
1626
|
-
this.
|
|
1627
|
-
|
|
1628
|
-
return {
|
|
1629
|
-
kind: 'ExpectStateClause',
|
|
1630
|
-
value,
|
|
1631
|
-
range: { start, end: this.endPos() }
|
|
1624
|
+
/** `{ expect_version_clause }` — the trailing precondition list. */
|
|
1625
|
+
private parseExpectVersions(): ExpectVersionClause[] {
|
|
1626
|
+
const clauses: ExpectVersionClause[] = []
|
|
1627
|
+
while (this.check(TokenType.Expect)) {
|
|
1628
|
+
clauses.push(this.parseExpectVersionClause())
|
|
1632
1629
|
}
|
|
1630
|
+
return clauses
|
|
1633
1631
|
}
|
|
1634
1632
|
|
|
1635
1633
|
// ────────────────────────────────────────────────────────────────────
|
|
@@ -1642,10 +1640,6 @@ class Parser {
|
|
|
1642
1640
|
this.expectKeywordWithSpace(TokenType.Update)
|
|
1643
1641
|
const target = this.parseTargetRef()
|
|
1644
1642
|
|
|
1645
|
-
const expectVersion = this.check(TokenType.Expect)
|
|
1646
|
-
? this.parseExpectVersionClause()
|
|
1647
|
-
: undefined
|
|
1648
|
-
|
|
1649
1643
|
const actions: UpdateAction[] = []
|
|
1650
1644
|
for (;;) {
|
|
1651
1645
|
if (this.check(TokenType.Set)) {
|
|
@@ -1669,9 +1663,9 @@ class Parser {
|
|
|
1669
1663
|
}
|
|
1670
1664
|
|
|
1671
1665
|
// WHERE binds a ?variable target; a direct :id / "id" target already names
|
|
1672
|
-
// the element and may omit it, exactly as
|
|
1673
|
-
// SET RETENTION
|
|
1674
|
-
//
|
|
1666
|
+
// the element and may omit it, exactly as TRANSITION / PURGE /
|
|
1667
|
+
// SET RETENTION do (Spec §58). Whether a bare ?variable is bound is
|
|
1668
|
+
// semantic — inside MUTATE it may be a local handle.
|
|
1675
1669
|
let where: WhereClause | undefined
|
|
1676
1670
|
if (this.check(TokenType.Where)) {
|
|
1677
1671
|
this.expectKeywordWithSpace(TokenType.Where)
|
|
@@ -1679,107 +1673,40 @@ class Parser {
|
|
|
1679
1673
|
where = this.parseWhereClause()
|
|
1680
1674
|
}
|
|
1681
1675
|
const limit = this.check(TokenType.Limit) ? this.parseLimitClause() : undefined
|
|
1676
|
+
const expectVersions = this.parseExpectVersions()
|
|
1682
1677
|
|
|
1683
1678
|
return {
|
|
1684
1679
|
kind: 'UpdateStatement',
|
|
1685
1680
|
target,
|
|
1686
|
-
expectVersion,
|
|
1687
1681
|
actions,
|
|
1688
1682
|
where,
|
|
1689
1683
|
limit,
|
|
1684
|
+
expectVersions,
|
|
1690
1685
|
range: { start, end: this.endPos() },
|
|
1691
1686
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1692
1687
|
}
|
|
1693
1688
|
}
|
|
1694
1689
|
|
|
1695
1690
|
// ────────────────────────────────────────────────────────────────────
|
|
1696
|
-
// KML — lifecycle
|
|
1691
|
+
// KML — TRANSITION (the one lifecycle statement, Spec §52.5)
|
|
1697
1692
|
// ────────────────────────────────────────────────────────────────────
|
|
1698
1693
|
|
|
1699
|
-
private
|
|
1700
|
-
const leadingComments = this.collectLeadingComments()
|
|
1701
|
-
const start = this.currentPos()
|
|
1702
|
-
const retract = this.expectKeywordWithSpace(TokenType.Retract)
|
|
1703
|
-
this.expectSecondWord(TokenType.Assertion, retract)
|
|
1704
|
-
const target = this.parseTargetRef()
|
|
1705
|
-
|
|
1706
|
-
let where: WhereClause | undefined
|
|
1707
|
-
if (this.check(TokenType.Where)) {
|
|
1708
|
-
this.expectKeywordWithSpace(TokenType.Where)
|
|
1709
|
-
this.dialect = 'raw'
|
|
1710
|
-
where = this.parseWhereClause()
|
|
1711
|
-
}
|
|
1712
|
-
const limit = this.check(TokenType.Limit) ? this.parseLimitClause() : undefined
|
|
1713
|
-
const expectState = this.check(TokenType.Expect)
|
|
1714
|
-
? this.parseExpectStateClause()
|
|
1715
|
-
: undefined
|
|
1716
|
-
|
|
1717
|
-
return {
|
|
1718
|
-
kind: 'RetractAssertionStatement',
|
|
1719
|
-
target,
|
|
1720
|
-
where,
|
|
1721
|
-
limit,
|
|
1722
|
-
expectState,
|
|
1723
|
-
range: { start, end: this.endPos() },
|
|
1724
|
-
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1728
|
-
private parseSupersedeAssertion(): SupersedeAssertionStatement {
|
|
1729
|
-
const leadingComments = this.collectLeadingComments()
|
|
1730
|
-
const start = this.currentPos()
|
|
1731
|
-
const supersede = this.expectKeywordWithSpace(TokenType.Supersede)
|
|
1732
|
-
this.expectSecondWord(TokenType.Assertion, supersede)
|
|
1733
|
-
const target = this.parseTargetRef()
|
|
1734
|
-
this.expect(TokenType.By)
|
|
1735
|
-
const by = this.parseTargetRef()
|
|
1736
|
-
const expectState = this.check(TokenType.Expect)
|
|
1737
|
-
? this.parseExpectStateClause()
|
|
1738
|
-
: undefined
|
|
1739
|
-
|
|
1740
|
-
return {
|
|
1741
|
-
kind: 'SupersedeAssertionStatement',
|
|
1742
|
-
target,
|
|
1743
|
-
by,
|
|
1744
|
-
expectState,
|
|
1745
|
-
range: { start, end: this.endPos() },
|
|
1746
|
-
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1747
|
-
}
|
|
1748
|
-
}
|
|
1749
|
-
|
|
1750
|
-
private parseCorrectEvidence(): CorrectEvidenceStatement {
|
|
1694
|
+
private parseTransitionStatement(): TransitionStatement {
|
|
1751
1695
|
const leadingComments = this.collectLeadingComments()
|
|
1752
1696
|
const start = this.currentPos()
|
|
1753
|
-
|
|
1754
|
-
this.expectSecondWord(TokenType.Evidence, correct)
|
|
1755
|
-
const target = this.parseTargetRef()
|
|
1756
|
-
this.expect(TokenType.By)
|
|
1757
|
-
const by = this.parseTargetRef()
|
|
1758
|
-
const expectState = this.check(TokenType.Expect)
|
|
1759
|
-
? this.parseExpectStateClause()
|
|
1760
|
-
: undefined
|
|
1761
|
-
|
|
1762
|
-
return {
|
|
1763
|
-
kind: 'CorrectEvidenceStatement',
|
|
1764
|
-
target,
|
|
1765
|
-
by,
|
|
1766
|
-
expectState,
|
|
1767
|
-
range: { start, end: this.endPos() },
|
|
1768
|
-
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
|
|
1772
|
-
private parseTransitionActivity(): TransitionActivityStatement {
|
|
1773
|
-
const leadingComments = this.collectLeadingComments()
|
|
1774
|
-
const start = this.currentPos()
|
|
1775
|
-
const transition = this.expectKeywordWithSpace(TokenType.Transition)
|
|
1776
|
-
this.expectSecondWord(TokenType.Activity, transition)
|
|
1697
|
+
this.expectKeywordWithSpace(TokenType.Transition)
|
|
1777
1698
|
const target = this.parseTargetRef()
|
|
1778
1699
|
this.expect(TokenType.To)
|
|
1779
1700
|
const to = this.parseScalarValue()
|
|
1780
1701
|
|
|
1781
|
-
//
|
|
1782
|
-
|
|
1702
|
+
// `BY` names the replacing element for "superseded" / "corrected".
|
|
1703
|
+
let by: TargetRef | undefined
|
|
1704
|
+
if (this.match(TokenType.By)) {
|
|
1705
|
+
by = this.parseTargetRef()
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// A pending Activity finalizes terminal fields and topology in the same
|
|
1709
|
+
// statement that moves it (Spec §17.5, §52.5).
|
|
1783
1710
|
const finalize: (SetFieldsClause | SetStructuralClause)[] = []
|
|
1784
1711
|
while (this.check(TokenType.Set)) {
|
|
1785
1712
|
const clause = this.parseSetClause()
|
|
@@ -1787,23 +1714,31 @@ class Parser {
|
|
|
1787
1714
|
finalize.push(clause)
|
|
1788
1715
|
} else {
|
|
1789
1716
|
this.error(
|
|
1790
|
-
'TRANSITION
|
|
1717
|
+
'TRANSITION accepts only SET FIELDS and SET STRUCTURAL',
|
|
1791
1718
|
this.current()
|
|
1792
1719
|
)
|
|
1793
1720
|
break
|
|
1794
1721
|
}
|
|
1795
1722
|
}
|
|
1796
1723
|
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1724
|
+
let where: WhereClause | undefined
|
|
1725
|
+
if (this.check(TokenType.Where)) {
|
|
1726
|
+
this.expectKeywordWithSpace(TokenType.Where)
|
|
1727
|
+
this.dialect = 'raw'
|
|
1728
|
+
where = this.parseWhereClause()
|
|
1729
|
+
}
|
|
1730
|
+
const limit = this.check(TokenType.Limit) ? this.parseLimitClause() : undefined
|
|
1731
|
+
const expectVersions = this.parseExpectVersions()
|
|
1800
1732
|
|
|
1801
1733
|
return {
|
|
1802
|
-
kind: '
|
|
1734
|
+
kind: 'TransitionStatement',
|
|
1803
1735
|
target,
|
|
1804
1736
|
to,
|
|
1737
|
+
by,
|
|
1805
1738
|
finalize,
|
|
1806
|
-
|
|
1739
|
+
where,
|
|
1740
|
+
limit,
|
|
1741
|
+
expectVersions,
|
|
1807
1742
|
range: { start, end: this.endPos() },
|
|
1808
1743
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1809
1744
|
}
|
|
@@ -1828,9 +1763,7 @@ class Parser {
|
|
|
1828
1763
|
where = this.parseWhereClause()
|
|
1829
1764
|
}
|
|
1830
1765
|
const limit = this.check(TokenType.Limit) ? this.parseLimitClause() : undefined
|
|
1831
|
-
const
|
|
1832
|
-
? this.parseExpectVersionClause()
|
|
1833
|
-
: undefined
|
|
1766
|
+
const expectVersions = this.parseExpectVersions()
|
|
1834
1767
|
|
|
1835
1768
|
return {
|
|
1836
1769
|
kind: 'SetRetentionStatement',
|
|
@@ -1838,52 +1771,19 @@ class Parser {
|
|
|
1838
1771
|
assignments,
|
|
1839
1772
|
where,
|
|
1840
1773
|
limit,
|
|
1841
|
-
|
|
1774
|
+
expectVersions,
|
|
1842
1775
|
range: { start, end: this.endPos() },
|
|
1843
1776
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1844
1777
|
}
|
|
1845
1778
|
}
|
|
1846
1779
|
|
|
1847
|
-
private
|
|
1848
|
-
const
|
|
1849
|
-
this.parseRemovalBody(TokenType.Archive)
|
|
1850
|
-
return {
|
|
1851
|
-
kind: 'ArchiveStatement',
|
|
1852
|
-
target,
|
|
1853
|
-
where,
|
|
1854
|
-
limit,
|
|
1855
|
-
expectState,
|
|
1856
|
-
range: { start, end: this.endPos() },
|
|
1857
|
-
leadingComments
|
|
1858
|
-
}
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
private parseTombstoneStatement(): TombstoneStatement {
|
|
1862
|
-
const { start, target, where, limit, expectState, leadingComments } =
|
|
1863
|
-
this.parseRemovalBody(TokenType.Tombstone)
|
|
1864
|
-
return {
|
|
1865
|
-
kind: 'TombstoneStatement',
|
|
1866
|
-
target,
|
|
1867
|
-
where,
|
|
1868
|
-
limit,
|
|
1869
|
-
expectState,
|
|
1870
|
-
range: { start, end: this.endPos() },
|
|
1871
|
-
leadingComments
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
/** ARCHIVE and TOMBSTONE share one shape; PURGE adds its confirmation. */
|
|
1876
|
-
private parseRemovalBody(keyword: TokenType): {
|
|
1877
|
-
start: Position
|
|
1878
|
-
target: TargetRef
|
|
1879
|
-
where?: WhereClause
|
|
1880
|
-
limit?: LimitClause
|
|
1881
|
-
expectState?: ExpectStateClause
|
|
1882
|
-
leadingComments?: string[]
|
|
1883
|
-
} {
|
|
1884
|
-
const comments = this.collectLeadingComments()
|
|
1780
|
+
private parsePurgeStatement(): PurgeStatement | PurgePayloadStatement {
|
|
1781
|
+
const leadingComments = this.collectLeadingComments()
|
|
1885
1782
|
const start = this.currentPos()
|
|
1886
|
-
this.expectKeywordWithSpace(
|
|
1783
|
+
const purge = this.expectKeywordWithSpace(TokenType.Purge)
|
|
1784
|
+
if (this.check(TokenType.Payload)) {
|
|
1785
|
+
return this.parsePurgePayloadTail(start, purge, leadingComments)
|
|
1786
|
+
}
|
|
1887
1787
|
const target = this.parseTargetRef()
|
|
1888
1788
|
|
|
1889
1789
|
let where: WhereClause | undefined
|
|
@@ -1892,25 +1792,54 @@ class Parser {
|
|
|
1892
1792
|
this.dialect = 'raw'
|
|
1893
1793
|
where = this.parseWhereClause()
|
|
1894
1794
|
}
|
|
1795
|
+
|
|
1895
1796
|
const limit = this.check(TokenType.Limit) ? this.parseLimitClause() : undefined
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1797
|
+
const expectVersions = this.parseExpectVersions()
|
|
1798
|
+
|
|
1799
|
+
let referencePolicy: ScalarValue | undefined
|
|
1800
|
+
if (this.check(TokenType.Reference)) {
|
|
1801
|
+
const reference = this.expect(TokenType.Reference)
|
|
1802
|
+
this.expectSecondWord(TokenType.Policy, reference)
|
|
1803
|
+
referencePolicy = this.parseScalarValue()
|
|
1804
|
+
}
|
|
1805
|
+
|
|
1806
|
+
// The grammar freezes the confirmation spelling. Physical erasure is
|
|
1807
|
+
// exceptional, so the literal is required and checked here rather than
|
|
1808
|
+
// left for the engine to discover.
|
|
1809
|
+
this.expect(TokenType.Confirm)
|
|
1810
|
+
const confirmTok = this.current()
|
|
1811
|
+
const confirm = this.parseStringLiteral()
|
|
1812
|
+
if (confirm.parsed !== 'PURGE') {
|
|
1813
|
+
this.error(
|
|
1814
|
+
`PURGE must be confirmed with the exact literal "PURGE", got ${confirmTok.value}`,
|
|
1815
|
+
confirmTok
|
|
1816
|
+
)
|
|
1817
|
+
}
|
|
1899
1818
|
|
|
1900
1819
|
return {
|
|
1901
|
-
|
|
1820
|
+
kind: 'PurgeStatement',
|
|
1902
1821
|
target,
|
|
1903
1822
|
where,
|
|
1904
1823
|
limit,
|
|
1905
|
-
|
|
1906
|
-
|
|
1824
|
+
expectVersions,
|
|
1825
|
+
referencePolicy,
|
|
1826
|
+
confirm,
|
|
1827
|
+
range: { start, end: this.endPos() },
|
|
1828
|
+
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1907
1829
|
}
|
|
1908
1830
|
}
|
|
1909
1831
|
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1832
|
+
/**
|
|
1833
|
+
* `PURGE PAYLOAD` erases Evidence bytes while the element survives
|
|
1834
|
+
* (Spec §60.6), so there is no REFERENCE POLICY clause; the confirmation
|
|
1835
|
+
* literal is the same as element purge.
|
|
1836
|
+
*/
|
|
1837
|
+
private parsePurgePayloadTail(
|
|
1838
|
+
start: Position,
|
|
1839
|
+
purge: Token,
|
|
1840
|
+
leadingComments: string[]
|
|
1841
|
+
): PurgePayloadStatement {
|
|
1842
|
+
this.expectSecondWord(TokenType.Payload, purge)
|
|
1914
1843
|
const target = this.parseTargetRef()
|
|
1915
1844
|
|
|
1916
1845
|
let where: WhereClause | undefined
|
|
@@ -1921,33 +1850,24 @@ class Parser {
|
|
|
1921
1850
|
}
|
|
1922
1851
|
|
|
1923
1852
|
const limit = this.check(TokenType.Limit) ? this.parseLimitClause() : undefined
|
|
1853
|
+
const expectVersions = this.parseExpectVersions()
|
|
1924
1854
|
|
|
1925
|
-
let referencePolicy: ScalarValue | undefined
|
|
1926
|
-
if (this.check(TokenType.Reference)) {
|
|
1927
|
-
const reference = this.expect(TokenType.Reference)
|
|
1928
|
-
this.expectSecondWord(TokenType.Policy, reference)
|
|
1929
|
-
referencePolicy = this.parseScalarValue()
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
// The grammar freezes the confirmation spelling. Physical erasure is
|
|
1933
|
-
// exceptional, so the literal is required and checked here rather than
|
|
1934
|
-
// left for the engine to discover.
|
|
1935
1855
|
this.expect(TokenType.Confirm)
|
|
1936
1856
|
const confirmTok = this.current()
|
|
1937
1857
|
const confirm = this.parseStringLiteral()
|
|
1938
1858
|
if (confirm.parsed !== 'PURGE') {
|
|
1939
1859
|
this.error(
|
|
1940
|
-
`PURGE must be confirmed with the exact literal "PURGE", got ${confirmTok.value}`,
|
|
1860
|
+
`PURGE PAYLOAD must be confirmed with the exact literal "PURGE", got ${confirmTok.value}`,
|
|
1941
1861
|
confirmTok
|
|
1942
1862
|
)
|
|
1943
1863
|
}
|
|
1944
1864
|
|
|
1945
1865
|
return {
|
|
1946
|
-
kind: '
|
|
1866
|
+
kind: 'PurgePayloadStatement',
|
|
1947
1867
|
target,
|
|
1948
1868
|
where,
|
|
1949
1869
|
limit,
|
|
1950
|
-
|
|
1870
|
+
expectVersions,
|
|
1951
1871
|
confirm,
|
|
1952
1872
|
range: { start, end: this.endPos() },
|
|
1953
1873
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
@@ -1969,16 +1889,14 @@ class Parser {
|
|
|
1969
1889
|
this.dialect = 'raw'
|
|
1970
1890
|
where = this.parseWhereClause()
|
|
1971
1891
|
}
|
|
1972
|
-
const
|
|
1973
|
-
? this.parseExpectVersionClause()
|
|
1974
|
-
: undefined
|
|
1892
|
+
const expectVersions = this.parseExpectVersions()
|
|
1975
1893
|
|
|
1976
1894
|
return {
|
|
1977
1895
|
kind: 'MergeConceptStatement',
|
|
1978
1896
|
source,
|
|
1979
1897
|
into,
|
|
1980
1898
|
where,
|
|
1981
|
-
|
|
1899
|
+
expectVersions,
|
|
1982
1900
|
range: { start, end: this.endPos() },
|
|
1983
1901
|
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
1984
1902
|
}
|
|
@@ -2015,11 +1933,6 @@ class Parser {
|
|
|
2015
1933
|
case TokenType.Protocol:
|
|
2016
1934
|
this.expectSecondWord(TokenType.Protocol, describe)
|
|
2017
1935
|
return stmt('PROTOCOL')
|
|
2018
|
-
case TokenType.Execution: {
|
|
2019
|
-
const exec = this.expectSecondWord(TokenType.Execution, describe)
|
|
2020
|
-
this.expectSecondWord(TokenType.Context, exec)
|
|
2021
|
-
return stmt('EXECUTION_CONTEXT')
|
|
2022
|
-
}
|
|
2023
1936
|
case TokenType.Capabilities:
|
|
2024
1937
|
this.expectSecondWord(TokenType.Capabilities, describe)
|
|
2025
1938
|
return stmt('CAPABILITIES')
|
|
@@ -2076,8 +1989,18 @@ class Parser {
|
|
|
2076
1989
|
}
|
|
2077
1990
|
case TokenType.Snapshot: {
|
|
2078
1991
|
this.expectSecondWord(TokenType.Snapshot, describe)
|
|
2079
|
-
|
|
2080
|
-
|
|
1992
|
+
// A snapshot is addressed by sequence, or resolved from an instant:
|
|
1993
|
+
// the one place wall-clock time enters cognitive-time addressing.
|
|
1994
|
+
let asOf: AsOfClause | undefined
|
|
1995
|
+
let atTime: ScalarValue | undefined
|
|
1996
|
+
if (this.check(TokenType.As)) {
|
|
1997
|
+
asOf = this.parseAsOfClause()
|
|
1998
|
+
} else if (this.check(TokenType.At)) {
|
|
1999
|
+
const at = this.expect(TokenType.At)
|
|
2000
|
+
this.expectSecondWord(TokenType.Time, at)
|
|
2001
|
+
atTime = this.parseScalarValue()
|
|
2002
|
+
}
|
|
2003
|
+
return stmt('SNAPSHOT', { asOf, atTime })
|
|
2081
2004
|
}
|
|
2082
2005
|
case TokenType.Capsule:
|
|
2083
2006
|
this.expectSecondWord(TokenType.Capsule, describe)
|
|
@@ -2088,11 +2011,6 @@ class Parser {
|
|
|
2088
2011
|
const value = this.isMetaValueStart() ? this.parseScalarValue() : undefined
|
|
2089
2012
|
return stmt('EPISTEMIC_POLICY', { value })
|
|
2090
2013
|
}
|
|
2091
|
-
case TokenType.Projection: {
|
|
2092
|
-
const projection = this.expectSecondWord(TokenType.Projection, describe)
|
|
2093
|
-
this.expectSecondWord(TokenType.Capability, projection)
|
|
2094
|
-
return stmt('PROJECTION_CAPABILITY')
|
|
2095
|
-
}
|
|
2096
2014
|
case TokenType.Trust: {
|
|
2097
2015
|
this.expectSecondWord(TokenType.Trust, describe)
|
|
2098
2016
|
const value = this.isMetaValueStart() ? this.parseScalarValue() : undefined
|
|
@@ -2123,6 +2041,8 @@ class Parser {
|
|
|
2123
2041
|
|
|
2124
2042
|
let target: ListTargetKind
|
|
2125
2043
|
let status: ScalarValue | undefined
|
|
2044
|
+
let element: ScalarValue | undefined
|
|
2045
|
+
let depth: ScalarValue | undefined
|
|
2126
2046
|
|
|
2127
2047
|
switch (tok.type) {
|
|
2128
2048
|
case TokenType.Spaces:
|
|
@@ -2160,6 +2080,14 @@ class Parser {
|
|
|
2160
2080
|
target = 'EPISTEMIC_POLICIES'
|
|
2161
2081
|
break
|
|
2162
2082
|
}
|
|
2083
|
+
case TokenType.Dependents:
|
|
2084
|
+
// Bounded reverse provenance closure (Spec §63.5): the operand is
|
|
2085
|
+
// required, the DEPTH bound is optional and defaults engine-side to 1.
|
|
2086
|
+
this.expectSecondWord(TokenType.Dependents, list)
|
|
2087
|
+
target = 'DEPENDENTS'
|
|
2088
|
+
element = this.parseScalarValue()
|
|
2089
|
+
if (this.match(TokenType.Depth)) depth = this.parseScalarValue()
|
|
2090
|
+
break
|
|
2163
2091
|
default:
|
|
2164
2092
|
this.error(`Unknown LIST target '${tok.value}'`, tok)
|
|
2165
2093
|
throw new ParseAbort()
|
|
@@ -2174,6 +2102,8 @@ class Parser {
|
|
|
2174
2102
|
kind: 'ListStatement',
|
|
2175
2103
|
target,
|
|
2176
2104
|
status,
|
|
2105
|
+
element,
|
|
2106
|
+
depth,
|
|
2177
2107
|
limit,
|
|
2178
2108
|
cursor,
|
|
2179
2109
|
range: { start, end: this.endPos() },
|
|
@@ -2419,7 +2349,7 @@ class Parser {
|
|
|
2419
2349
|
}
|
|
2420
2350
|
|
|
2421
2351
|
// ────────────────────────────────────────────────────────────────────
|
|
2422
|
-
// META — HISTORY / CHANGES
|
|
2352
|
+
// META — HISTORY / CHANGES
|
|
2423
2353
|
// ────────────────────────────────────────────────────────────────────
|
|
2424
2354
|
|
|
2425
2355
|
private parseHistoryStatement(): HistoryStatement {
|
|
@@ -2510,19 +2440,6 @@ class Parser {
|
|
|
2510
2440
|
}
|
|
2511
2441
|
}
|
|
2512
2442
|
|
|
2513
|
-
private parseSnapshotStatement(): SnapshotStatement {
|
|
2514
|
-
const leadingComments = this.collectLeadingComments()
|
|
2515
|
-
const start = this.currentPos()
|
|
2516
|
-
this.expect(TokenType.Snapshot)
|
|
2517
|
-
const asOf = this.check(TokenType.As) ? this.parseAsOfClause() : undefined
|
|
2518
|
-
return {
|
|
2519
|
-
kind: 'SnapshotStatement',
|
|
2520
|
-
asOf,
|
|
2521
|
-
range: { start, end: this.endPos() },
|
|
2522
|
-
leadingComments: leadingComments.length ? leadingComments : undefined
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
|
|
2526
2443
|
// ────────────────────────────────────────────────────────────────────
|
|
2527
2444
|
// META — EXPORT CAPSULE
|
|
2528
2445
|
// ────────────────────────────────────────────────────────────────────
|
|
@@ -3449,13 +3366,8 @@ class Parser {
|
|
|
3449
3366
|
TokenType.Ensure,
|
|
3450
3367
|
TokenType.Assert,
|
|
3451
3368
|
TokenType.Update,
|
|
3452
|
-
TokenType.Retract,
|
|
3453
|
-
TokenType.Supersede,
|
|
3454
|
-
TokenType.Correct,
|
|
3455
3369
|
TokenType.Transition,
|
|
3456
3370
|
TokenType.Set,
|
|
3457
|
-
TokenType.Archive,
|
|
3458
|
-
TokenType.Tombstone,
|
|
3459
3371
|
TokenType.Purge,
|
|
3460
3372
|
TokenType.Merge,
|
|
3461
3373
|
TokenType.Describe,
|
|
@@ -3466,7 +3378,6 @@ class Parser {
|
|
|
3466
3378
|
TokenType.Preview,
|
|
3467
3379
|
TokenType.History,
|
|
3468
3380
|
TokenType.Changes,
|
|
3469
|
-
TokenType.Snapshot,
|
|
3470
3381
|
TokenType.Export,
|
|
3471
3382
|
TokenType.EOF
|
|
3472
3383
|
])
|