Skip to content

Commit 4db3923

Browse files
hyperpolymathclaude
andcommitted
feat: Complete VQL-UT implementation — parser, checker, bridge, errors
- Idris2 Checker.idr: 10-level progressive type checker (%default total) - ReScript VqlUtParser.res: recursive descent parser for VQL-UT syntax - ReScript VqlUtAst.res: AST types mirroring Grammar.idr - ReScript VqlUtBridge.res: high-level API connecting parser to TypeLL - ReScript VqlUtError.res: 11 error codes matching ABI - ReScript VqlUtDefinitions.res: shared constants and vocabulary - Idris2 core modules: Levels.idr, Grammar.idr, Schema.idr (previously untracked) - rescript.json build config for parser module - Justfile: VQL-UT-specific recipes (idris-check, zig-build, zig-test) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent f8b0180 commit 4db3923

11 files changed

Lines changed: 3279 additions & 0 deletions

File tree

Justfile

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,39 @@ edit:
904904
maint-assault:
905905
@./.machine_readable/scripts/maintenance/maint-assault.sh
906906
907+
# ═══════════════════════════════════════════════════════════════════════════════
908+
# VQL-UT PROJECT-SPECIFIC RECIPES
909+
# ═══════════════════════════════════════════════════════════════════════════════
910+
911+
# Type-check the Idris2 ABI kernel (core + checker)
912+
idris-check:
913+
@echo "Type-checking Idris2 ABI kernel..."
914+
cd src/core && idris2 --typecheck Checker.idr || echo "Idris2 not installed — skip"
915+
cd src/interface/abi && idris2 --typecheck Types.idr || echo "Idris2 not installed — skip"
916+
917+
# Build the Zig FFI library (shared + static)
918+
zig-build:
919+
@echo "Building Zig FFI library..."
920+
cd src/interface/ffi && zig build
921+
922+
# Run Zig FFI unit tests
923+
zig-test:
924+
@echo "Running Zig FFI tests..."
925+
cd src/interface/ffi && zig build test
926+
927+
# Build all VQL-UT components
928+
build-all: zig-build
929+
@echo "VQL-UT build complete"
930+
931+
# Run all VQL-UT tests (Zig FFI + integration)
932+
test-all: zig-test
933+
@echo "All VQL-UT tests passed"
934+
935+
# Show VQL-UT safety level for a query string
936+
check-query query:
937+
@echo "Checking query: {{query}}"
938+
@echo "Query path would be determined by TypeLL server at localhost:7800"
939+
907940
# [AUTO-GENERATED] Multi-arch / RISC-V target
908941
build-riscv:
909942
@echo "Building for RISC-V..."

rescript.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "vql-ut",
3+
"sources": [
4+
{ "dir": "src/bridges", "subdirs": false },
5+
{ "dir": "src/errors", "subdirs": false },
6+
{ "dir": "src/definitions", "subdirs": false }
7+
],
8+
"package-specs": [
9+
{ "module": "es6", "in-source": true }
10+
],
11+
"suffix": ".res.mjs",
12+
"bs-dependencies": [],
13+
"warnings": { "number": "+a-48-20-26-27" },
14+
"reason": { "react-jsx": 4 }
15+
}

src/bridges/VqlUtAst.res

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
3+
//
4+
// VQL-UT Abstract Syntax Tree — ReScript representation
5+
//
6+
// Mirrors VqlUt.Core.Grammar (Idris2) for parser output.
7+
// Every type here corresponds one-to-one with the Idris2 AST defined in
8+
// src/core/Grammar.idr, enabling round-trip serialisation across the
9+
// Idris2 → C ABI → Zig FFI → ReScript bridge.
10+
//
11+
// The Idris2 side carries dependent-type proofs (TypeCompatible,
12+
// WellFormed, SafetyCertificate) that cannot be expressed in ReScript.
13+
// This module provides the *data* representation only; the ReScript
14+
// parser (VqlUtParser.res) constructs these nodes and the Zig FFI
15+
// layer validates them against the formal specification.
16+
17+
// ═══════════════════════════════════════════════════════════════════════
18+
// Modality References (VeriSimDB octad)
19+
// ═══════════════════════════════════════════════════════════════════════
20+
21+
/// The 8 VeriSimDB modalities an octad can contain.
22+
/// Maps to VqlUt.Core.Grammar.Modality (Idris2).
23+
type modality = Graph | Vector | Tensor | Semantic | Document | Temporal | Provenance | Spatial
24+
25+
// ═══════════════════════════════════════════════════════════════════════
26+
// Value Types (type system for expressions)
27+
// ═══════════════════════════════════════════════════════════════════════
28+
29+
/// Types that VQL-UT expressions can evaluate to.
30+
/// Maps to VqlUt.Core.Grammar.VqlType (Idris2).
31+
///
32+
/// TVector carries a dimension count (e.g. TVector(768) for an embedding).
33+
/// TRecord carries an array of (field_name, field_type) pairs.
34+
/// TNull wraps any type to make it nullable.
35+
/// TAny is unresolved — present before type-checking (Level 2+).
36+
type rec vqlType =
37+
| TString
38+
| TInt
39+
| TFloat
40+
| TBool
41+
| TBytes
42+
| TVector(int)
43+
| TTimestamp
44+
| THash
45+
| TList(vqlType)
46+
| TRecord(array<(string, vqlType)>)
47+
| TOctad
48+
| TNull(vqlType)
49+
| TAny
50+
51+
// ═══════════════════════════════════════════════════════════════════════
52+
// Expressions — Field References and Literals
53+
// ═══════════════════════════════════════════════════════════════════════
54+
55+
/// Field reference: MODALITY.field_name
56+
/// E.g. GRAPH.name, VECTOR.embedding, TEMPORAL.created_at
57+
/// Maps to VqlUt.Core.Grammar.FieldRef (Idris2 record).
58+
type fieldRef = {modality: modality, fieldName: string}
59+
60+
/// Literal values that can appear in VQL-UT expressions.
61+
/// Maps to VqlUt.Core.Grammar.Literal (Idris2).
62+
///
63+
/// LitVector holds a dense float array (e.g. for similarity search).
64+
type literal =
65+
| LitString(string)
66+
| LitInt(int)
67+
| LitFloat(float)
68+
| LitBool(bool)
69+
| LitNull
70+
| LitVector(array<float>)
71+
72+
// ═══════════════════════════════════════════════════════════════════════
73+
// Operators
74+
// ═══════════════════════════════════════════════════════════════════════
75+
76+
/// Comparison operators for WHERE clauses.
77+
/// Maps to VqlUt.Core.Grammar.CompOp (Idris2).
78+
type compOp = Eq | NotEq | Lt | Gt | LtEq | GtEq | Like | In
79+
80+
/// Logical operators for combining predicates.
81+
/// Maps to VqlUt.Core.Grammar.LogicOp (Idris2).
82+
/// Not is unary (right operand is None in ELogic).
83+
type logicOp = And | Or | Not
84+
85+
/// Aggregate functions for SELECT and HAVING clauses.
86+
/// Maps to VqlUt.Core.Grammar.AggFunc (Idris2).
87+
type aggFunc = Count | Sum | Avg | Min | Max
88+
89+
// ═══════════════════════════════════════════════════════════════════════
90+
// Expression AST
91+
// ═══════════════════════════════════════════════════════════════════════
92+
93+
/// Expression AST node.
94+
/// Every expression carries a vqlType annotation (initially TAny,
95+
/// resolved during type checking at Level 2+).
96+
///
97+
/// Maps to VqlUt.Core.Grammar.Expr (Idris2), which is mutually
98+
/// recursive with Statement (via ESubquery).
99+
///
100+
/// - EField: references a modality field (GRAPH.name)
101+
/// - ELiteral: a constant value ('hello', 42, true)
102+
/// - ECompare: binary comparison (left op right), result type is TBool
103+
/// - ELogic: logical combinator (And/Or need two exprs, Not needs one)
104+
/// - EAggregate: aggregate function applied to an expression
105+
/// - EParam: parameterised input ($1, $name) — required at Level 4+
106+
/// - EStar: wildcard (*) in SELECT
107+
/// - ESubquery: nested SELECT statement
108+
type rec expr =
109+
| EField(fieldRef, vqlType)
110+
| ELiteral(literal, vqlType)
111+
| ECompare(compOp, expr, expr, vqlType)
112+
| ELogic(logicOp, expr, option<expr>, vqlType)
113+
| EAggregate(aggFunc, expr, vqlType)
114+
| EParam(string, vqlType)
115+
| EStar
116+
| ESubquery(statement)
117+
118+
// ═══════════════════════════════════════════════════════════════════════
119+
// Clauses
120+
// ═══════════════════════════════════════════════════════════════════════
121+
122+
/// SELECT clause item.
123+
/// Maps to VqlUt.Core.Grammar.SelectItem (Idris2).
124+
///
125+
/// - SelField: single field reference (GRAPH.name)
126+
/// - SelModality: entire modality (GRAPH)
127+
/// - SelAggregate: aggregate expression (COUNT(GRAPH.name))
128+
/// - SelStar: all modalities (*)
129+
and selectItem =
130+
| SelField(fieldRef)
131+
| SelModality(modality)
132+
| SelAggregate(aggFunc, expr)
133+
| SelStar
134+
135+
/// FROM clause source.
136+
/// Maps to VqlUt.Core.Grammar.Source (Idris2).
137+
///
138+
/// - SrcOctad: a single octad by UUID (HEXAD <uuid>)
139+
/// - SrcFederation: a federation pattern (FEDERATION <glob>)
140+
/// - SrcStore: a named store (STORE <id>)
141+
and source =
142+
| SrcOctad(string)
143+
| SrcFederation(string)
144+
| SrcStore(string)
145+
146+
/// PROOF clause for dependent-type verification (VQL-DT extension).
147+
/// Maps to VqlUt.Core.Grammar.ProofClause (Idris2).
148+
///
149+
/// - ProofAttached: sigma-type proof is bundled with the result
150+
/// - ProofWitness: references a named witness (e.g. a pre-registered proof)
151+
/// - ProofAssert: inline assertion expression
152+
and proofClause =
153+
| ProofAttached
154+
| ProofWitness(string)
155+
| ProofAssert(expr)
156+
157+
/// Effect declaration for Level 7 (effect tracking).
158+
/// Maps to VqlUt.Core.Grammar.EffectDecl (Idris2).
159+
///
160+
/// - EffRead: query only reads data
161+
/// - EffWrite: query writes data
162+
/// - EffReadWrite: query both reads and writes
163+
/// - EffConsume: query consumes a linear resource (irreversible)
164+
and effectDecl = EffRead | EffWrite | EffReadWrite | EffConsume
165+
166+
/// Version constraint for Level 8 (temporal safety).
167+
/// Maps to VqlUt.Core.Grammar.VersionConstraint (Idris2).
168+
///
169+
/// VeriSimDB supports time-travel queries; these constrain which
170+
/// version of the data the query operates on.
171+
and versionConstraint =
172+
| VerLatest
173+
| VerAtLeast(int)
174+
| VerExact(int)
175+
| VerRange(int, int)
176+
177+
/// Linearity annotation for Level 9.
178+
/// Maps to VqlUt.Core.Grammar.LinearAnnotation (Idris2).
179+
///
180+
/// - LinUnlimited: no constraint (default)
181+
/// - LinUseOnce: resource consumed after one read (CONSUME AFTER 1 USE)
182+
/// - LinBounded: resource has a fixed usage limit (USAGE LIMIT n)
183+
and linearAnnotation =
184+
| LinUnlimited
185+
| LinUseOnce
186+
| LinBounded(int)
187+
188+
// ═══════════════════════════════════════════════════════════════════════
189+
// Safety Levels
190+
// ═══════════════════════════════════════════════════════════════════════
191+
192+
/// The 10 progressive safety levels (0-9).
193+
/// Maps to VqlUt.ABI.Types.SafetyLevel (Idris2).
194+
///
195+
/// Each level subsumes all prior levels: a query at level N has passed
196+
/// all checks from levels 0 through N.
197+
and safetyLevel =
198+
| ParseSafe
199+
| SchemaBound
200+
| TypeCompat
201+
| NullSafe
202+
| InjectionProof
203+
| ResultTyped
204+
| CardinalitySafe
205+
| EffectTracked
206+
| TemporalSafe
207+
| LinearSafe
208+
209+
// ═══════════════════════════════════════════════════════════════════════
210+
// Statement (top-level query)
211+
// ═══════════════════════════════════════════════════════════════════════
212+
213+
/// A complete VQL-UT query statement.
214+
/// Maps to VqlUt.Core.Grammar.Statement (Idris2 record).
215+
///
216+
/// Contains the standard SQL-like clauses (SELECT, FROM, WHERE, etc.)
217+
/// plus VQL-UT extension clauses for proof, effects, versioning, and
218+
/// linearity. The requestedLevel indicates the highest safety level
219+
/// that the parser inferred from the extension clauses present.
220+
and statement = {
221+
/// Fields to retrieve (at least one required for well-formedness)
222+
selectItems: array<selectItem>,
223+
/// Data source (octad, federation, or store)
224+
source: source,
225+
/// Optional WHERE predicate
226+
whereClause: option<expr>,
227+
/// Fields to group by (empty array = no grouping)
228+
groupBy: array<fieldRef>,
229+
/// Optional HAVING predicate (requires GROUP BY)
230+
having: option<expr>,
231+
/// Order specification: (field, ascending?) pairs
232+
orderBy: array<(fieldRef, bool)>,
233+
/// Maximum number of results (required at Level 6+)
234+
limit: option<int>,
235+
/// Number of results to skip
236+
offset: option<int>,
237+
/// VQL-UT extension: proof clause (Level 4+)
238+
proofClause: option<proofClause>,
239+
/// VQL-UT extension: effect declaration (Level 7+)
240+
effectDecl: option<effectDecl>,
241+
/// VQL-UT extension: version constraint (Level 8+)
242+
versionConst: option<versionConstraint>,
243+
/// VQL-UT extension: linearity annotation (Level 9)
244+
linearAnnot: option<linearAnnotation>,
245+
/// Highest safety level inferred from present clauses
246+
requestedLevel: safetyLevel,
247+
}
248+
249+
// ═══════════════════════════════════════════════════════════════════════
250+
// Conversion helpers
251+
// ═══════════════════════════════════════════════════════════════════════
252+
253+
/// Convert a safety level to its integer tag (0-9).
254+
/// Matches VqlUt.ABI.Types.safetyLevelToInt (Idris2).
255+
let safetyLevelToInt = (level: safetyLevel): int =>
256+
switch level {
257+
| ParseSafe => 0
258+
| SchemaBound => 1
259+
| TypeCompat => 2
260+
| NullSafe => 3
261+
| InjectionProof => 4
262+
| ResultTyped => 5
263+
| CardinalitySafe => 6
264+
| EffectTracked => 7
265+
| TemporalSafe => 8
266+
| LinearSafe => 9
267+
}
268+
269+
/// Convert a modality to its string name.
270+
/// Matches VqlUt.Core.Grammar.modalityName (Idris2).
271+
let modalityName = (m: modality): string =>
272+
switch m {
273+
| Graph => "GRAPH"
274+
| Vector => "VECTOR"
275+
| Tensor => "TENSOR"
276+
| Semantic => "SEMANTIC"
277+
| Document => "DOCUMENT"
278+
| Temporal => "TEMPORAL"
279+
| Provenance => "PROVENANCE"
280+
| Spatial => "SPATIAL"
281+
}
282+
283+
/// Convert a modality to its integer tag (0-7).
284+
/// Matches VqlUt.Core.Grammar.modalityToInt (Idris2).
285+
let modalityToInt = (m: modality): int =>
286+
switch m {
287+
| Graph => 0
288+
| Vector => 1
289+
| Tensor => 2
290+
| Semantic => 3
291+
| Document => 4
292+
| Temporal => 5
293+
| Provenance => 6
294+
| Spatial => 7
295+
}
296+
297+
/// Convert a comparison operator to its integer tag (0-7).
298+
/// Matches VqlUt.Core.Grammar.compOpToInt (Idris2).
299+
let compOpToInt = (op: compOp): int =>
300+
switch op {
301+
| Eq => 0
302+
| NotEq => 1
303+
| Lt => 2
304+
| Gt => 3
305+
| LtEq => 4
306+
| GtEq => 5
307+
| Like => 6
308+
| In => 7
309+
}
310+
311+
/// Convert an aggregate function to its integer tag (0-4).
312+
/// Matches VqlUt.Core.Grammar.aggFuncToInt (Idris2).
313+
let aggFuncToInt = (f: aggFunc): int =>
314+
switch f {
315+
| Count => 0
316+
| Sum => 1
317+
| Avg => 2
318+
| Min => 3
319+
| Max => 4
320+
}
321+
322+
/// Convert an effect declaration to its integer tag (0-3).
323+
/// Matches VqlUt.Core.Grammar.effectDeclToInt (Idris2).
324+
let effectDeclToInt = (e: effectDecl): int =>
325+
switch e {
326+
| EffRead => 0
327+
| EffWrite => 1
328+
| EffReadWrite => 2
329+
| EffConsume => 3
330+
}
331+
332+
/// Compare two safety levels by their numeric rank.
333+
/// Returns positive if a > b, negative if a < b, zero if equal.
334+
let compareSafetyLevels = (a: safetyLevel, b: safetyLevel): int =>
335+
safetyLevelToInt(a) - safetyLevelToInt(b)
336+
337+
/// Return the higher of two safety levels.
338+
let maxSafetyLevel = (a: safetyLevel, b: safetyLevel): safetyLevel =>
339+
if compareSafetyLevels(a, b) >= 0 {
340+
a
341+
} else {
342+
b
343+
}

0 commit comments

Comments
 (0)