package semantics
import (
"github.com/freeeve/gochickpeas/gql/internal/ast"
"github.com/freeeve/gochickpeas/gql/value"
)
func AutoParameterize (q *ast .Query ) []value .Value {
var vals []value .Value
liftParts (q .Parts , &vals )
return vals
}
func LitValue (l ast .Literal ) value .Value {
switch l .Kind {
case ast .LitInt :
return value .Int (l .I )
case ast .LitFloat :
return value .Float (l .F )
case ast .LitStr :
return value .Str (l .S )
case ast .LitBool :
return value .Bool (l .B )
default :
return value .Null ()
}
}
func liftParts(parts []ast .QueryPart , vals *[]value .Value ) {
for i := range parts {
part := &parts [i ]
for _ , clause := range part .Clauses {
liftClause (clause , vals )
}
liftProjection (&part .Ret , vals )
}
}
func liftLit(lit *ast .Literal , vals *[]value .Value ) {
switch lit .Kind {
case ast .LitNull , ast .LitParam , ast .LitNamedParam :
return
}
slot := uint32 (len (*vals ))
*vals = append (*vals , LitValue (*lit ))
*lit = ast .ParamLit (slot )
}
func liftProps(props []ast .PropEntry , vals *[]value .Value ) {
for i := range props {
liftLit (&props [i ].Val , vals )
}
}
func isComparison(op ast .BinOp ) bool {
switch op {
case ast .OpLt , ast .OpLte , ast .OpGt , ast .OpGte , ast .OpEq , ast .OpNeq ,
ast .OpStartsWith , ast .OpEndsWith , ast .OpContains :
return true
}
return false
}
func liftPattern(p *ast .Pattern , vals *[]value .Value ) {
liftProps (p .Start .Props , vals )
for i := range p .Hops {
liftProps (p .Hops [i ].Rel .Props , vals )
liftProps (p .Hops [i ].Node .Props , vals )
}
}
func liftClause(c ast .Clause , vals *[]value .Value ) {
switch n := c .(type ) {
case *ast .Match :
for i := range n .Patterns {
liftPattern (&n .Patterns [i ], vals )
}
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
case *ast .With :
liftProjection (&n .Proj , vals )
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
case *ast .ShortestPath :
liftPattern (&n .Pattern , vals )
case *ast .PathBind :
liftPattern (&n .Pattern , vals )
case *ast .CallProc :
case *ast .Unwind :
liftExpr (n .Expr , vals )
case *ast .CallSubquery :
liftParts (n .Query .Parts , vals )
}
}
func liftProjection(p *ast .Projection , vals *[]value .Value ) {
for i := range p .Items {
liftExpr (p .Items [i ].Expr , vals )
}
for i := range p .OrderBy {
liftExpr (p .OrderBy [i ].Expr , vals )
}
}
func liftWhereExpr(e ast .Expr , vals *[]value .Value ) {
switch n := e .(type ) {
case *ast .Binary :
switch {
case n .Op == ast .OpAnd || n .Op == ast .OpOr :
liftWhereExpr (n .LHS , vals )
liftWhereExpr (n .RHS , vals )
case isComparison (n .Op ):
if lit := propCmpLit (n .LHS , n .RHS ); lit != nil {
liftLit (lit , vals )
} else {
liftWhereExpr (n .LHS , vals )
liftWhereExpr (n .RHS , vals )
}
default :
liftExpr (n , vals )
}
case *ast .Unary :
if n .Op == ast .Not {
liftWhereExpr (n .Expr , vals )
} else {
liftExpr (n , vals )
}
case *ast .Exists :
liftPattern (n .Pattern , vals )
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
case *ast .CountSub :
liftPattern (n .Pattern , vals )
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
default :
liftExpr (e , vals )
}
}
func propCmpLit(lhs , rhs ast .Expr ) *ast .Literal {
if _ , ok := lhs .(*ast .Prop ); ok {
if lit , ok := rhs .(*ast .Lit ); ok {
return &lit .Value
}
}
if _ , ok := rhs .(*ast .Prop ); ok {
if lit , ok := lhs .(*ast .Lit ); ok {
return &lit .Value
}
}
return nil
}
func liftExpr(e ast .Expr , vals *[]value .Value ) {
switch n := e .(type ) {
case *ast .Unary :
liftExpr (n .Expr , vals )
case *ast .Binary :
liftExpr (n .LHS , vals )
liftExpr (n .RHS , vals )
case *ast .Func :
for _ , a := range n .Args {
liftExpr (a , vals )
}
case *ast .ListExpr :
for _ , el := range n .Elems {
liftExpr (el , vals )
}
case *ast .In :
liftExpr (n .Expr , vals )
liftExpr (n .List , vals )
case *ast .IsNull :
liftExpr (n .Expr , vals )
case *ast .IsTruth :
liftExpr (n .Expr , vals )
case *ast .IsTyped :
liftExpr (n .Expr , vals )
case *ast .Case :
if n .Operand != nil {
liftExpr (n .Operand , vals )
}
for _ , w := range n .Whens {
liftExpr (w .Cond , vals )
liftExpr (w .Result , vals )
}
if n .Else != nil {
liftExpr (n .Else , vals )
}
case *ast .Exists :
liftPattern (n .Pattern , vals )
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
case *ast .CountSub :
liftPattern (n .Pattern , vals )
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
case *ast .PatternComp :
liftPattern (n .Pattern , vals )
if n .Where != nil {
liftWhereExpr (n .Where , vals )
}
liftExpr (n .Proj , vals )
case *ast .ListPred :
liftExpr (n .List , vals )
liftExpr (n .Pred , vals )
case *ast .Reduce :
liftExpr (n .Init , vals )
liftExpr (n .List , vals )
liftExpr (n .Body , vals )
case *ast .ListComp :
liftExpr (n .List , vals )
if n .Filter != nil {
liftExpr (n .Filter , vals )
}
if n .Map != nil {
liftExpr (n .Map , vals )
}
case *ast .Index :
liftExpr (n .Base , vals )
liftExpr (n .Idx , vals )
case *ast .Slice :
liftExpr (n .Base , vals )
if n .From != nil {
liftExpr (n .From , vals )
}
if n .To != nil {
liftExpr (n .To , vals )
}
case *ast .PropOf :
liftExpr (n .Base , vals )
case *ast .MapProj :
for _ , en := range n .Entries {
if en .Kind == ast .MapProjField {
liftExpr (en .Expr , vals )
}
}
case *ast .MapLit :
for _ , f := range n .Fields {
liftExpr (f .Val , vals )
}
}
}
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 .