|
| 1 | +# Janus-QL Grammar Audit |
| 2 | + |
| 3 | +Date: 2026-07-09 |
| 4 | + |
| 5 | +This note compares the Janus-QL Core EBNF in `/Users/kushbisen/Code/janusql-spec/spec-src/sections/03a-core-grammar.bs` with the current implementation in `/Users/kushbisen/Code/janus/src/parsing/janusql_parser/`. |
| 6 | + |
| 7 | +## Verdict |
| 8 | + |
| 9 | +The EBNF is broadly faithful for the public Janus-QL Core window model: |
| 10 | + |
| 11 | +- `PREFIX` declarations are parsed by `parse_prefix_declaration()`. |
| 12 | +- `REGISTER RStream ... AS` is optional and enforced by `parse_register_clause()`. |
| 13 | +- `FROM NAMED WINDOW` declarations are split into `ON STREAM [RANGE ... STEP ...]`, `ON LOG [START ... END]`, and `ON LOG [OFFSET ... RANGE ... STEP ...]` by `parse_window_clause()`. |
| 14 | +- `WINDOW <name> { ... }` references are extracted from `WHERE` and checked against declared windows by `validate_where_window_references()`. |
| 15 | +- Historical-only nested subqueries are identified in `extract_nested_subqueries()` and restricted during subquery planning in `plan_nested_subqueries()` and `validate_subquery_plan()`. |
| 16 | +- Top-level `GROUP BY` and `HAVING` are preserved in the AST and in generated historical SPARQL. |
| 17 | + |
| 18 | +The main mismatch is that the implementation is looser than the EBNF around `SELECT` items and `WINDOW` bodies: |
| 19 | + |
| 20 | +- `SELECT` clauses are stored as text. The parser does not fully parse projection items against a strict `Var | (Expression AS Var)` grammar. |
| 21 | +- `WINDOW` bodies are also stored as text. The parser does not fully parse triple patterns or `FILTER` expressions. It performs only shallow Janus-specific checks such as undeclared windows, `SERVICE` rejection, and property-path rejection. |
| 22 | +- As a result, the EBNF is a conservative public contract, but the implementation may accept some extra SPARQL-like shapes as opaque body text. |
| 23 | + |
| 24 | +## Syntax vs Semantic Validation |
| 25 | + |
| 26 | +The current implementation splits enforcement across phases. |
| 27 | + |
| 28 | +Rejected during parsing: |
| 29 | + |
| 30 | +- `ON STREAM [START ... END]` |
| 31 | +- `ON STREAM [OFFSET ... RANGE ... STEP ...]` |
| 32 | +- `ON LOG [RANGE ... STEP ...]` |
| 33 | +- unsupported `REGISTER` operators such as `IStream` and `DStream` |
| 34 | + |
| 35 | +Rejected during later validation or planning: |
| 36 | + |
| 37 | +- duplicate window names |
| 38 | +- `RANGE == 0` or `STEP == 0` |
| 39 | +- `START >= END` |
| 40 | +- historical sliding `RANGE > OFFSET` |
| 41 | +- undeclared `WINDOW` references |
| 42 | +- nested subqueries with no known `WINDOW` |
| 43 | +- nested subqueries that reference live windows only |
| 44 | +- nested subqueries that mix live and historical windows |
| 45 | + |
| 46 | +This distinction matters for the specification text: some invalid combinations are not merely semantic constraints over a permissive grammar; they are already rejected by the parser based on the `ON STREAM` versus `ON LOG` token sequence. |
| 47 | + |
| 48 | +## Construct Coverage |
| 49 | + |
| 50 | +The implementation and tests currently cover the requested constructs as follows: |
| 51 | + |
| 52 | +- `PREFIX` declarations: implemented and tested. |
| 53 | +- optional `REGISTER RStream`: implemented and tested, including historical-only queries without `REGISTER`. |
| 54 | +- `SELECT` with variables and aliased expressions: implemented as text-preserving parsing with output-variable extraction; tested with variables and aggregate aliases. |
| 55 | +- `FROM NAMED WINDOW`: implemented and tested. |
| 56 | +- `ON STREAM` with `RANGE/STEP`: implemented and tested. |
| 57 | +- `ON LOG` with fixed `START/END`: implemented and tested. |
| 58 | +- `ON LOG` with sliding `OFFSET/RANGE/STEP`: implemented and tested. |
| 59 | +- `WHERE` clauses with `WINDOW` blocks: implemented and tested. |
| 60 | +- triple patterns: passed through inside `WINDOW` bodies; not structurally parsed by Janus. |
| 61 | +- `FILTER` expressions: passed through inside `WINDOW` bodies; not structurally parsed beyond Janus-specific exclusions. |
| 62 | +- historical nested `SELECT` subqueries: implemented and tested. |
| 63 | +- `GROUP BY` and `HAVING`: implemented and tested for top-level historical queries and nested historical subqueries. |
| 64 | + |
| 65 | +## SPARQL-Inherited Terminals |
| 66 | + |
| 67 | +The specification says Janus-QL Core inherits SPARQL-style lexical forms for `IRIREF`, `PrefixedName`, `Literal`, `Name`, `PrefixName`, and `Var`. |
| 68 | + |
| 69 | +That is directionally true, but the current implementation does not contain a full SPARQL lexer for those terminals. In practice: |
| 70 | + |
| 71 | +- Janus parses the Janus-specific top-level clauses itself. |
| 72 | +- prefixed names and `<iri>` forms are handled by lightweight token splitting and prefix expansion. |
| 73 | +- triple-pattern terms and most expression text are forwarded as SPARQL-like text rather than fully validated by the Janus parser. |
| 74 | + |
| 75 | +## Recommended Specification Changes |
| 76 | + |
| 77 | +- Keep the current EBNF split between `ON STREAM` and `ON LOG`; it matches implementation behavior. |
| 78 | +- Add an explicit note near the EBNF that `SELECT` items, triple patterns, and `FILTER` expressions are specified conservatively, while the current implementation uses shallow parsing and may accept extension syntax as opaque SPARQL-like text. |
| 79 | +- In the invalid examples section, add explicit examples for: |
| 80 | + - `ON STREAM [START ... END]` |
| 81 | + - `ON STREAM [OFFSET ... RANGE ... STEP ...]` |
| 82 | + - `ON LOG [RANGE ... STEP ...]` |
| 83 | +- Keep the nested-subquery rule outside the pure EBNF as a validation/planning rule: the syntax shape is parseable, but live-only and mixed nested subqueries are rejected semantically after window-dependency analysis. |
| 84 | + |
| 85 | +## Local Test Updates |
| 86 | + |
| 87 | +This repo now has explicit public-spec regression tests for: |
| 88 | + |
| 89 | +- invalid `ON STREAM [START ... END]` |
| 90 | +- invalid `ON STREAM [OFFSET ... RANGE ... STEP ...]` |
| 91 | +- invalid `ON LOG [RANGE ... STEP ...]` |
| 92 | + |
| 93 | +Those were added to `/Users/kushbisen/Code/janus/tests/public_spec_behavior_test.rs`. |
0 commit comments