You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extend the temporal-range key-bracket binding (foo[t1...t2], foo[...t2], foo[t1...]) introduced for flat leaf keys in #74 to the remaining key shapes that route through the lexer-captured bracket path:
Navigation stops — a[t1...t2].b, a.foo[t1...]
Scope prefixes — a[t1...].(foo = "X")
Transitive leaves — foo[t1...t2]*
This is the grammar/AST/parse side only (same as #74); server-side evaluation remains a separate Concourse concern.
#74 implemented range bindings on flat leaf keys only. Those flow through the parser path (Key() → OPEN_BRACKET KeyBracketParameter() CLOSE_BRACKET in grammar/grammar.jjt), where bracket content is tokenized in the default lexer state and interpreted by Parsing.applyKeyBracket(base, content).
The shapes above instead flow through the lexer-captured path: the whole key (e.g. a[t1...t2].b, foo[t1...t2]*) is captured as a single PERIOD_SEPARATED_STRING / NAVIGATION_SCOPE_OPEN / ASTERISK_SUFFIXED_STRING token via the #KEY_BRACKET fragment (grammar.jjt:310), and the bracket content is split out and parsed by hand in NavigationKeyStop.parseBracketContent (NavigationKeyStop.java:208-230). That method currently produces a single TimestampSymbol and is unaware of the ... range form.
Deferring kept #74 to one parse path, one new AST node (TemporalRangeKeySymbol), and left all existing single-timestamp navigation behavior untouched as a regression net.
Scope of work
NavigationKeyStop must carry a range, not just an instant. Today it holds a single @Nullable TimestampSymbol timestamp (NavigationKeyStop.java:266). It needs to additionally carry an optional end endpoint (or a small range descriptor) and thread it through withTimestamp() (:323), segment()/baseSegment() (:364,386), and equals/hashCode (:285-302).
NavigationKeySymbol rendering/strip must reflect the range.joinStops/components/baseKey/stripParameters (:120-129,207-248) delegate to the stop's segment(), so they should follow once the stop renders the range; withTimestampOnLastStop (:92-112) and parseScopePrefix (:47-75) need to construct the range form when the content is a range.
Lift the leaf-only guard.TemporalRangeKeySymbol's constructor currently rejects wrapping a NavigationKeySymbol ("temporal-range bindings on navigation keys are not yet supported"); navigation ranges live on the stop, not on this wrapper, so the navigation path will not construct TemporalRangeKeySymbol directly — confirm the guard stays correct.
Canonical round-trip. Each new shape must survive tokenize → toString → re-parse to an equal AST (the assertRoundTrip helper in BracketTimestampMatrixTest), with the canonical all-micros bracket form.
Tests
Extend BracketTimestampMatrixTest (range rows on first stop, leaf stop, mid-chain, scope prefix, transitive), BracketTimestampCommandTest (accept on reads, reject on writes/range-history), and add navigation cases mirroring the existing N* and S* sections. Update CCL_REFERENCE.md §8.4 to remove the "not yet supported on navigation/scope/transitive" caveat once landed.
Notes
Endpoint parsing reuses NaturalLanguage.parseMicros per endpoint (parity with the single-instant form); quoted/natural-language endpoint robustness is whatever the single form already supports.
Summary
Extend the temporal-range key-bracket binding (
foo[t1...t2],foo[...t2],foo[t1...]) introduced for flat leaf keys in #74 to the remaining key shapes that route through the lexer-captured bracket path:a[t1...t2].b,a.foo[t1...]a[t1...].(foo = "X")foo[t1...t2]*This is the grammar/AST/parse side only (same as #74); server-side evaluation remains a separate Concourse concern.
Background — why these were deferred from #74
#74 implemented range bindings on flat leaf keys only. Those flow through the parser path (
Key()→OPEN_BRACKET KeyBracketParameter() CLOSE_BRACKETingrammar/grammar.jjt), where bracket content is tokenized in the default lexer state and interpreted byParsing.applyKeyBracket(base, content).The shapes above instead flow through the lexer-captured path: the whole key (e.g.
a[t1...t2].b,foo[t1...t2]*) is captured as a singlePERIOD_SEPARATED_STRING/NAVIGATION_SCOPE_OPEN/ASTERISK_SUFFIXED_STRINGtoken via the#KEY_BRACKETfragment (grammar.jjt:310), and the bracket content is split out and parsed by hand inNavigationKeyStop.parseBracketContent(NavigationKeyStop.java:208-230). That method currently produces a singleTimestampSymboland is unaware of the...range form.Deferring kept #74 to one parse path, one new AST node (
TemporalRangeKeySymbol), and left all existing single-timestamp navigation behavior untouched as a regression net.Scope of work
NavigationKeyStopmust carry a range, not just an instant. Today it holds a single@Nullable TimestampSymbol timestamp(NavigationKeyStop.java:266). It needs to additionally carry an optional end endpoint (or a small range descriptor) and thread it throughwithTimestamp()(:323),segment()/baseSegment()(:364,386), andequals/hashCode(:285-302).parseBracketContentmust detect.... Reuse the same...split logic centralized inParsing.applyKeyBracket(added in Temporal range key-bracket binding: foo[t1...t2], foo[...t2], foo[t1...] (grammar/AST/parse only) #74) rather than duplicating it, so the parser path and lexer path stay in lockstep.NavigationKeySymbolrendering/strip must reflect the range.joinStops/components/baseKey/stripParameters(:120-129,207-248) delegate to the stop'ssegment(), so they should follow once the stop renders the range;withTimestampOnLastStop(:92-112) andparseScopePrefix(:47-75) need to construct the range form when the content is a range.TemporalRangeKeySymbol's constructor currently rejects wrapping aNavigationKeySymbol("temporal-range bindings on navigation keys are not yet supported"); navigation ranges live on the stop, not on this wrapper, so the navigation path will not constructTemporalRangeKeySymboldirectly — confirm the guard stays correct.tokenize→toString→ re-parse to an equal AST (theassertRoundTriphelper inBracketTimestampMatrixTest), with the canonical all-micros bracket form.Tests
Extend
BracketTimestampMatrixTest(range rows on first stop, leaf stop, mid-chain, scope prefix, transitive),BracketTimestampCommandTest(accept on reads, reject on writes/range-history), and add navigation cases mirroring the existingN*andS*sections. UpdateCCL_REFERENCE.md§8.4 to remove the "not yet supported on navigation/scope/transitive" caveat once landed.Notes
NaturalLanguage.parseMicrosper endpoint (parity with the single-instant form); quoted/natural-language endpoint robustness is whatever the single form already supports.