Involved Source Files Binary operator evaluation shared by the interpreter and the compiled
path: string predicates (STARTS WITH / ENDS WITH / CONTAINS) and the
arithmetic operators (+, -, *, /) over numbers, strings, lists, and
temporals/durations, with checked integer arithmetic (overflow and
division by zero yield Null -- eval has no per-row error channel). Split
from funcs.go, which holds the scalar built-in functions. Package eval is the interpreted expression evaluator: the portable path
that evaluates bound AST expressions per row against the graph seam.
Port of the Rust engine's eval.rs; the columnar compiled path (M16)
mirrors it and both must produce identical results. The core interpreter: evaluate a bound expression against a slot-indexed
row. Aggregate functions are handled by the executor, never here (they
evaluate to Null if reached). The scalar-function registry: the FuncOp enumeration and the
name-resolution helpers that map a (case-insensitive) function name to a
resolved op. The per-row evaluation kernels live in funcs.go; carrying a
resolved FuncOp lets the compiled path skip name dispatch. The arithmetic/string-predicate scalar-function kernels, shared verbatim
by the interpreter and the compiled path so both produce identical
results. No scalar function touches the graph except startNode/endNode,
which resolve in evalScalarFunc. The FuncOp enumeration and name
resolution live in funcop.go. Scalar built-in application helpers: positional argument access, the
range/substring/toString value builders, and the datetime/duration
constructors with their checked integer arithmetic. Split from funcs.go,
which holds the function registry (ResolveFuncOp) and the ApplyFunc
dispatch. List-scoped expression forms: the all/any/none/single quantifiers,
reduce folds, and list comprehensions. Each binds its iteration
variable in a slot appended past the current row. Correlated subquery matching: EXISTS { MATCH ... }, COUNT { MATCH ... },
and pattern comprehensions, all sharing one anchored DFS over the
pattern. The DFS's evaluation-invariant setup (anchor-reversal, level
slots, the extended scope, compiled node and rel matchers) is shaped
once per pattern and cached on the Ctx with its evaluation scratch, so
the per-row cost is a row refresh instead of map/slice/matcher rebuilds. The correlated-subquery DFS walk: level-by-level candidate generation
over a shaped pattern (anchored endpoints, lazily compiled matchers,
the quantified-hop reach) -- the evaluation half of subquery.go's
shape/count entry points. Temporal arithmetic for the runtime value type: epoch-millis-backed
date/datetime values and durations, with civil-calendar decomposition.
Query-side only -- stored i64-millis columns coerce against these on
compare. Pure integer math (port of the Rust temporal.rs). Temporal component access and duration arithmetic: reading a named
component off an epoch-millis instant or a (months, days, millis)
duration, applying a duration to an instant (checked calendar add), and
the Euclidean integer-math helpers they share. Split from temporal.go,
which holds the ISO parsing and formatting.
Package-Level Type Names (total 3)
/* sort by: | */
Ctx carries the evaluation environment: the graph and the query's
parameter values. It replaces the Rust engine's thread-local
ParamScope/NamedParamScope -- explicit and threaded through every
evaluation, so nested subquery evaluation and reuse across goroutines
need no scope choreography. CompileWhere, when set, compiles a subquery WHERE against the
walk's inner slot map and returns a per-row evaluator; nil (or
ForceInterp) keeps the interpreted path. The executor layer
installs it -- it can reach the compiler without an import cycle
-- so a subquery's filter runs the same compiled machinery as a
stage filter instead of re-interpreting the AST (and re-evaluating
its constant subexpressions) once per candidate.DecorBuildsint DecorTables shares decorrelated COUNT{} side tables across sibling
compiled subqueries within one execution, keyed by the subquery's
canonical identity (endpoint variable names substituted, so the same
subquery written against two outer variables collides) and the
resolved anchor node. Params are fixed per Ctx, so identities that
embed parameter slots stay valid for the Ctx's lifetime. DecorBuilds
counts table builds across the execution -- tests assert a shared
identity builds once, not once per sibling. ForceInterp pins every expression to the interpreted path even on a
native-capable graph -- the differential test hook behind the
dual-path harness.Ggraph.Graph MatchEpoch is bumped once per match-call by the executor, so a
loop-invariant carried IN list's membership cache rebuilds per call
and is reused across that call's candidates (replaces the Rust
thread-local epoch). Named are the explicit $name parameter values. Params are the auto-lifted parameter values, indexed by slot. NamedValue resolves an explicit $name parameter; an unsupplied name is
Null (a missing parameter reads as null rather than an error). ParamValue resolves an auto-lifted slot; out of range is Null.
func Eval(ctx *Ctx, expr ast.Expr, row []value.Value, slots map[string]int) value.Value
func LitValue(ctx *Ctx, l ast.Literal) value.Value
func SubqueryCount(ctx *Ctx, pattern *ast.Pattern, where ast.Expr, outerRow []value.Value, outerSlots map[string]int, stopAtFirst bool) int
func SubqueryGroupCount(ctx *Ctx, pattern *ast.Pattern, where ast.Expr, outerRow []value.Value, outerSlots map[string]int, anchorVar, groupVar string) map[graph.NodeID]int
func github.com/freeeve/gochickpeas/gql/internal/compile.ConstValue(ctx *Ctx, e ast.Expr, slots map[string]int, g *chickpeas.Snapshot) (value.Value, bool)
func github.com/freeeve/gochickpeas/gql/internal/compile.HoistConstIn(ctx *Ctx, c *compile.Compiled, isConst func(int) bool, sample []value.Value, slots map[string]int) *compile.Compiled
func github.com/freeeve/gochickpeas/gql/internal/compile.New(ctx *Ctx, e ast.Expr, slots map[string]int, g *chickpeas.Snapshot) *compile.Compiled
func github.com/freeeve/gochickpeas/gql/internal/compile.(*Compiled).Eval(ctx *Ctx, row []value.Value, slots map[string]int) value.Value
func github.com/freeeve/gochickpeas/gql/internal/exec.Execute(ctx *Ctx, p *plan.Plan) ([][]value.Value, error)
func github.com/freeeve/gochickpeas/gql/internal/exec.ExecuteProfiled(ctx *Ctx, p *plan.Plan) *explain.Profile
func github.com/freeeve/gochickpeas/gql/internal/exec.RowEval.Eval(ctx *Ctx, row []value.Value, slots map[string]int) value.Value
ApplyDuration applies a duration (months, days, millis) to an
epoch-millis temporal, sign = +1 (add) or -1 (subtract). Months are a
calendar add (day clamped to the target month length, e.g. Jan 31 + 1
month = Feb 28); days and millis are absolute. Every step is checked:
ok=false on overflow, so the caller yields Null rather than a wrapped
nonsense instant. Note the boundary -- shifting a recent instant by
i64-scale milliseconds to a very negative-but-representable value is exact
and stays ok; only a genuine overflow declines.
ApplyFunc applies a resolved scalar function to its evaluated arguments.
Arith is +, -, *, /: string + concatenates; temporal +/- duration is a
calendar add; Int op Int is checked (overflow and division by zero
yield Null -- eval has no per-row error channel, so Null is the honest
result); mixed numerics coerce through float64, where division by zero
is also Null. Shared with the compiled path.
CivilFromDays is the inverse: civil (year, month, day) from days since
1970-01-01.
CmpBool maps a three-valued comparison through a predicate on the
ordering; incomparable is Null. Shared with the compiled path.
Component is a temporal component accessor (.year/.month/.day/.hour/...
/.epochMillis) on an epoch-millis temporal; ok is false for an unknown
component (the caller yields Null).
Concat is the || operator: string or list concatenation only -- unlike
+, it never adds numbers; any other operand pair is Null.
DaysFromCivil is days since 1970-01-01 for a civil (year, month, day) --
Howard Hinnant's algorithm.
DaysInMonth is the day count of (year, month), accounting for leap years
(used to clamp a calendar + duration).
DurationComponent is a duration component accessor on a (months, days,
millis) duration, with the groups independent (Neo4j's convention): the
months group answers years/quarters/months (months is the group TOTAL,
so duration({years: 1}).months = 12), the days group weeks/days, and
the millis group hours/minutes/seconds/milliseconds (each the group
total at that unit, so PT2H reads .minutes = 120). ok=false for an
unknown component.
Eval evaluates expr against row (slot-indexed bindings).
IsKnownScalarFunc reports whether name is a scalar function the engine
evaluates (case-insensitive): a ResolveFuncOp op or the graph-resolved
startNode/endNode. The binder consults this to reject unknown function
names at plan time rather than silently evaluating them to null.
ISOString renders an epoch-millis temporal as ISO-8601, the inverse of
ParseISO: 'YYYY-MM-DD' for a Date; 'YYYY-MM-DDTHH:MM:SS' for the datetime
kinds, with '.mmm' appended only when the sub-second remainder is
non-zero. This is the single temporal string formatter -- any other
surface that stringifies a temporal should delegate here so the forms
cannot drift.
LitValue converts a parsed literal into a runtime value, resolving
parameters from the context.
ParseISO parses an ISO-ish temporal string into epoch milliseconds
(UTC): YYYY-MM-DD, optionally THH:MM[:SS[.mmm]] and a trailing Z/offset
(the offset is accepted but treated as UTC -- no real zone handling).
ok is false on a malformed string.
ParseISODuration parses an ISO-8601 duration string (PnYnMnWnD[TnHnMnS],
e.g. 'P100D', 'PT12H', 'P1Y2M3DT4H5M6S') into calendar components:
months, days, and sub-day milliseconds. A leading '-'/'+' sign negates the
whole duration, and the seconds field accepts a millisecond fraction
('PT1.5S'); ok is false on a malformed string or a component that overflows.
ResolveFuncOp resolves a scalar-function name (case-insensitive); ok is
false for an unknown function (which yields null at evaluation).
StrPred is a string predicate (STARTS WITH / ENDS WITH / CONTAINS):
Bool when both operands are strings, Null otherwise. Shared with the
compiled path.
SubqueryCount counts matches of a correlated subquery against the
current outer row, anchoring pattern nodes that name an outer variable
to their bound value. stopAtFirst short-circuits for EXISTS. A single
fixed-length pattern (quantifiers are treated as one hop).
SubqueryGroupCount evaluates a correlated subquery ONCE with the group
variable left free, returning the match count bucketed by the node the
group variable binds to. It is the decorrelated form of SubqueryCount:
where SubqueryCount re-walks the pattern once per outer entity bound to
the group variable, a single SubqueryGroupCount call -- anchored on the
SHARED endpoint (anchorVar, still bound from the outer row) -- yields every
entity's count in one pass over the anchored set, so the per-entity cost
collapses from a walk to an O(1) map read.
anchorVar must name an outer variable bound in outerRow; groupVar names the
pattern endpoint to bucket by, left UNBOUND here even when it is itself an
outer variable (its outer binding is ignored -- enumeration rebinds it per
match). The returned map is keyed only by node id, so it is independent of
what the outer query calls the group variable: two subqueries with the same
pattern, WHERE, and anchor share one table (see task 084 / rustychickpeas
091). The result for a given entity equals SubqueryCount with that entity
bound -- the invariant the decor parity test asserts.
Package-Level Constants (total 52)
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
Resolved scalar functions.
MSPerDay is the milliseconds in a civil day.
The pages are generated with Goldsv0.8.7. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.