// Package exec runs a compiled Plan against the graph seam. This file is// the RowEval seam: every filter/projection evaluates through it, so the// executor never cares whether the interpreted or the columnar compiled// form is behind a given expression.
package execimport ()// RowEval is a bound expression in per-row-evaluable form.typeRowEvalinterface {Eval(ctx *eval.Ctx, row []value.Value, slots map[string]int) value.Value}// interpExpr is the portable per-row evaluable: the AST run through the// interpreter.type interpExpr struct{ e ast.Expr }func ( interpExpr) ( *eval.Ctx, []value.Value, map[string]int) value.Value {returneval.Eval(, .e, , )}// interpPinned counts expressions the differential test hook routed to// the interpreter, so the dual-path harness can assert its forced leg// really took the interpreted path -- a silently dead hook would compare// compiled against compiled and prove nothing (the colAggFired pattern).var interpPinned int// InterpPinned exposes the counter to the harness's liveness assertion.func () int { returninterpPinned }// compileEval binds an expression for per-row evaluation: the columnar// compiled form when the graph asserts the native capability (and the// differential test hook doesn't pin the interpreter), else interpreted.func compileEval( *eval.Ctx, ast.Expr, map[string]int) RowEval {if .ForceInterp {interpPinned++returninterpExpr{} }if , := .G.(graph.Native); {returncompile.New(, , , .Snapshot()) }returninterpExpr{}}// hoistEval applies the backend's IN-list hoisting to a bound expression:// batch-constant lists bake a membership index, carried loop-invariant// lists cache per match-call. The interpreted form re-evaluates lists per// row (correct, just not pre-hashed), mirroring the Rust portable default.func hoistEval( *eval.Ctx, RowEval, , func(int) bool, []value.Value, map[string]int) RowEval { , := .(*compile.Compiled)if ! {return }returncompile.HoistCarriedIn(compile.HoistConstIn(, , , , ), )}// evalPushdown reports the row slots a bound expression reads (through// slots), whether it contains a node that pins it to the last op level,// and whether it walks the graph despite being slot-resolved (a memoized// subquery: reads only its memo slots, but every distinct correlation// tuple still pays a graph walk). The compiled form introspects its// resolved nodes; the interpreted form walks the AST conservatively.func evalPushdown( RowEval, ast.Expr, map[string]int, *[]int, , *bool) {if , := .(*compile.Compiled); { , , := compile.Slots() * = append(*, ...) * = * || * = * || return }astPushdown(, , , )}// astPushdown is the interpreted path's conservative slot analysis.func astPushdown( ast.Expr, map[string]int, *[]int, *bool) {switch n := .(type) {case *ast.Lit:case *ast.Var:if , := [.Name]; { * = append(*, ) }case *ast.Prop:if , := [.Var]; { * = append(*, ) }case *ast.HasLabelExpr:if , := [.Var]; { * = append(*, ) }case *ast.Unary: (.Expr, , , )case *ast.Binary: (.LHS, , , ) (.RHS, , , )case *ast.ListExpr:for , := range .Elems { (, , , ) }case *ast.IsTruth: (.Expr, , , )case *ast.IsTyped: (.Expr, , , )case *ast.In: (.Expr, , , ) (.List, , , )case *ast.IsNull: (.Expr, , , )case *ast.Case:if .Operand != nil { (.Operand, , , ) }for , := range .Whens { (.Cond, , , ) (.Result, , , ) }if .Else != nil { (.Else, , , ) }default:// Subqueries, function calls, comprehensions, cost, map forms: // conservative last-level placement. * = true }}
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.