Source File
ctx.go
Belonging Package
github.com/freeeve/gochickpeas/gql/internal/eval
// 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.package evalimport ()// 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.type Ctx struct {G graph.Graph// Params are the auto-lifted parameter values, indexed by slot.Params []value.Value// Named are the explicit $name parameter values.Named map[string]value.Value// ForceInterp pins every expression to the interpreted path even on a// native-capable graph -- the differential test hook behind the// dual-path harness.ForceInterp bool// 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).MatchEpoch uint64// 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.CompileWhere func(e ast.Expr, slots map[string]int) func(*Ctx, []value.Value) value.Value// subqShapes caches each subquery pattern's DFS shape and scratch for// this execution (params are fixed per Ctx, so the memoized level-0// scan stays valid; a fresh Ctx per run keeps prepared-plan reuse// safe).subqShapes map[*ast.Pattern]*subqueryShape// scopes caches each list-scope node's reusable inner scope (the slot// map and idx are lexically invariant across the node's per-row// evaluations; the row buffer is refilled each call). A tree AST never// evaluates one node re-entrantly, so a single buffer per node is safe.scopes map[ast.Expr]*scopeScratch// 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.DecorTables map[DecorTableKey]map[graph.NodeID]intDecorBuilds int// constCalls memoizes all-literal scalar calls for this execution: a// call whose every argument is a literal (params included -- fixed per// Ctx) evaluates once instead of per row, so a temporal constructor in// a subquery WHERE parses its ISO string once per execution rather// than once per visited row. A nil entry marks a known non-constant// call so the argument scan runs once per node. Sound on the same// invariant as the compile-layer fold: every scalar function is// deterministic (locked by the zero-arg fold tests); a future volatile// function must be excluded here as well as at foldFunc/constExpr.constCalls map[*ast.Func]*value.Value// argvStack backs the interpreter's function-call argument rows as// stack frames (see evalScalarFuncUncached): one growable slice per// execution instead of one slice per call.argvStack []value.Value}// DecorTableKey identifies one shared decorrelated side table.type DecorTableKey struct {Canon stringAnchor uint32}// scopeScratch is one list-scope node's reused inner environment: the slot// map and iteration-variable indices built once, and a row buffer refilled// from the outer row on each evaluation.type scopeScratch struct {slots map[string]intidx []introw []value.ValuebaseLen int}// ParamValue resolves an auto-lifted slot; out of range is Null.func ( *Ctx) ( uint32) value.Value {if int() < len(.Params) {return .Params[]}return value.Null()}// NamedValue resolves an explicit $name parameter; an unsupplied name is// Null (a missing parameter reads as null rather than an error).func ( *Ctx) ( string) value.Value {if , := .Named[]; {return}return value.Null()}// LitValue converts a parsed literal into a runtime value, resolving// parameters from the context.func ( *Ctx, ast.Literal) value.Value {switch .Kind {case ast.LitInt:return value.Int(.I)case ast.LitFloat:return value.Float(.F)case ast.LitStr:return value.Str(.S)case ast.LitBool:return value.Bool(.B)case ast.LitParam:return .ParamValue(.P)case ast.LitNamedParam:return .NamedValue(.S)default:return value.Null()}}
![]() |
The pages are generated with Golds v0.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. |