Skip to content

Commit

Permalink
make it an expr instead
Browse files Browse the repository at this point in the history
  • Loading branch information
mattnibs committed Oct 11, 2023
1 parent bed68b9 commit d2e3ddc
Show file tree
Hide file tree
Showing 13 changed files with 79 additions and 166 deletions.
38 changes: 1 addition & 37 deletions compiler/ast/dag/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ type (
Expr interface {
ExprDAG()
}
PathElem interface {
pathElem()
}
RecordElem interface {
recordAST()
}
Expand All @@ -30,7 +27,7 @@ type (
}
Assignment struct {
Kind string `json:"kind" unpack:""`
LHS Path `json:"lhs"`
LHS Expr `json:"lhs"`
RHS Expr `json:"rhs"`
}
BinaryExpr struct {
Expand Down Expand Up @@ -75,10 +72,6 @@ type (
Exprs []Expr `json:"exprs"`
Body Seq `json:"body"`
}
Path struct {
Kind string `json:"kind" unpack:""`
Path []PathElem `json:"path"`
}
RecordExpr struct {
Kind string `json:"kind" unpack:""`
Elems []RecordElem `json:"elems"`
Expand Down Expand Up @@ -130,7 +123,6 @@ func (*Func) ExprDAG() {}
func (*Literal) ExprDAG() {}
func (*MapExpr) ExprDAG() {}
func (*OverExpr) ExprDAG() {}
func (*Path) ExprDAG() {}
func (*RecordExpr) ExprDAG() {}
func (*RegexpMatch) ExprDAG() {}
func (*RegexpSearch) ExprDAG() {}
Expand Down Expand Up @@ -167,34 +159,6 @@ func (*Spread) recordAST() {}
func (*Spread) vectorElem() {}
func (*VectorValue) vectorElem() {}

func (p *Path) StaticPath() *This {
this := &This{Kind: "This"}
for _, elem := range p.Path {
p, ok := elem.(*StaticPathElem)
if !ok {
return nil
}
this.Path = append(this.Path, p.Name)
}
return this
}

func NewStaticPath(path ...string) *Path {
p := Path{Kind: "Path"}
for _, name := range path {
p.Path = append(p.Path, &StaticPathElem{Kind: "StaticPathElem", Name: name})
}
return &p
}

type StaticPathElem struct {
Kind string `json:"kind" unpack:""`
Name string `json:"name"`
}

func (*This) pathElem() {}
func (*StaticPathElem) pathElem() {}

func NewBinaryExpr(op string, lhs, rhs Expr) *BinaryExpr {
return &BinaryExpr{
Kind: "BinaryExpr",
Expand Down
2 changes: 0 additions & 2 deletions compiler/ast/dag/unpack.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ var unpacker = unpack.New(
Over{},
OverExpr{},
Pass{},
Path{},
PoolScan{},
Put{},
RecordExpr{},
Expand All @@ -52,7 +51,6 @@ var unpacker = unpack.New(
Slicer{},
Sort{},
Spread{},
StaticPathElem{},
Summarize{},
Switch{},
Tail{},
Expand Down
51 changes: 30 additions & 21 deletions compiler/kernel/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@ func (b *Builder) compileExpr(e dag.Expr) (expr.Evaluator, error) {
return expr.NewDottedExpr(b.zctx(), field.Path(e.Path)), nil
case *dag.Dot:
return b.compileDotExpr(e)
case *dag.Path:
// Path only works as a general expression if it is a static path.
if this := e.StaticPath(); this != nil {
return expr.NewDottedExpr(b.zctx(), field.Path(this.Path)), nil
}
return nil, fmt.Errorf("internal error: invalid path expression %s", e)
case *dag.UnaryExpr:
return b.compileUnary(*e)
case *dag.BinaryExpr:
Expand Down Expand Up @@ -269,23 +263,38 @@ func (b *Builder) compileDotExpr(dot *dag.Dot) (expr.Evaluator, error) {
return expr.NewDotExpr(b.zctx(), record, dot.RHS), nil
}

func (b *Builder) compilePath(e dag.Path) (*expr.Path, error) {
elems := make([]expr.PathElem, 0, len(e.Path))
for _, elem := range e.Path {
switch e := elem.(type) {
case *dag.This:
eval, err := b.compileExpr(e)
if err != nil {
return nil, err
}
elems = append(elems, expr.NewPathElemExpr(b.octx.Zctx, eval))
case *dag.StaticPathElem:
elems = append(elems, &expr.StaticPathElem{Name: e.Name})
default:
return nil, fmt.Errorf("internal error: invalid lval type %T", e)
func (b *Builder) compilePath(e dag.Expr) (*expr.Path, error) {
switch e := e.(type) {
case *dag.This:
var elems []expr.PathElem
for _, elem := range e.Path {
elems = append(elems, &expr.StaticPathElem{Name: elem})
}
return expr.NewPath(elems), nil
case *dag.BinaryExpr:
if e.Op != "[" {
return nil, fmt.Errorf("internal error: invalid path expression %T", e)
}
lhs, err := b.compilePath(e.LHS)
if err != nil {
return nil, err
}
rhs, err := b.compileExpr(e.RHS)
if err != nil {
return nil, err
}
lhs.Elems = append(lhs.Elems, expr.NewPathElemExpr(b.zctx(), rhs))
return lhs, nil
case *dag.Dot:
lhs, err := b.compilePath(e.LHS)
if err != nil {
return nil, err
}
lhs.Elems = append(lhs.Elems, &expr.StaticPathElem{Name: e.RHS})
return lhs, nil
default:
return nil, fmt.Errorf("internal error: invalid path expression %T", e)
}
return expr.NewPath(elems), nil
}

func (b *Builder) compileAssignment(node *dag.Assignment) (expr.Assignment, error) {
Expand Down
4 changes: 2 additions & 2 deletions compiler/kernel/groupby.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ func (b *Builder) compileAggAssignment(assignment dag.Assignment) (field.Path, *
if !ok {
return nil, nil, errors.New("aggregator is not an aggregation expression")
}
this := assignment.LHS.StaticPath()
if this == nil {
this, ok := assignment.LHS.(*dag.This)
if !ok {
return nil, nil, errors.New("internal error: aggregator assignment must be a static path")
}
m, err := b.compileAgg(aggAST)
Expand Down
4 changes: 2 additions & 2 deletions compiler/kernel/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,8 +357,8 @@ func (b *Builder) compileStaticAssignments(assignments []dag.Assignment) ([]fiel
lhs := make([]field.Path, 0, len(assignments))
rhs := make([]expr.Evaluator, 0, len(assignments))
for _, a := range assignments {
this := a.LHS.StaticPath()
if this == nil {
this, ok := a.LHS.(*dag.This)
if !ok {
return nil, nil, errors.New("internal error: dynamic path in assignment when expecting a static path")
}
lhs = append(lhs, slices.Clone(this.Path))
Expand Down
11 changes: 3 additions & 8 deletions compiler/optimizer/op.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (o *Optimizer) analyzeSortKey(op dag.Op, in order.SortKey) (order.SortKey,
return order.Nil, nil
case *dag.Put:
for _, assignment := range op.Args {
if fieldOf(&assignment.LHS).Equal(key) {
if fieldOf(assignment.LHS).Equal(key) {
return order.Nil, nil
}
}
Expand Down Expand Up @@ -101,7 +101,7 @@ func isKeyOfSummarize(summarize *dag.Summarize, in order.SortKey) bool {
}
key := in.Keys[0]
for _, outputKeyExpr := range summarize.Keys {
groupByKey := fieldOf(&outputKeyExpr.LHS)
groupByKey := fieldOf(outputKeyExpr.LHS)
if groupByKey.Equal(key) {
rhsExpr := outputKeyExpr.RHS
rhs := fieldOf(rhsExpr)
Expand Down Expand Up @@ -147,7 +147,7 @@ func analyzeCuts(assignments []dag.Assignment, sortKey order.SortKey) order.Sort
scoreboard := make(map[string]field.Path)
scoreboard[fieldKey(key)] = key
for _, a := range assignments {
lhs := fieldOf(&a.LHS)
lhs := fieldOf(a.LHS)
rhs := fieldOf(a.RHS)
if lhs == nil {
// If we cannot statically determine the data flow,
Expand Down Expand Up @@ -211,11 +211,6 @@ func fieldOf(e dag.Expr) field.Path {
if this, ok := e.(*dag.This); ok {
return this.Path
}
if path, ok := e.(*dag.Path); ok {
if this := path.StaticPath(); this != nil {
return this.Path
}
}
return nil
}

Expand Down
2 changes: 1 addition & 1 deletion compiler/optimizer/optimizer.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func (o *Optimizer) propagateSortKeyOp(op dag.Op, parents []order.SortKey) ([]or
//XXX handle only primary key for now
key := parent.Primary()
for _, k := range op.Keys {
if groupByKey := fieldOf(&k.LHS); groupByKey.Equal(key) {
if groupByKey := fieldOf(k.LHS); groupByKey.Equal(key) {
rhsExpr := k.RHS
rhs := fieldOf(rhsExpr)
if rhs.Equal(key) || orderPreservingCall(rhsExpr, groupByKey) {
Expand Down
2 changes: 1 addition & 1 deletion compiler/optimizer/parallelize.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ func (o *Optimizer) liftIntoParPaths(ops []dag.Op) {
// so the ingress aggregator should simply reference the key
// by its name. This loop updates the ingress to do so.
for k := range op.Keys {
op.Keys[k].RHS = &op.Keys[k].LHS
op.Keys[k].RHS = op.Keys[k].LHS
}
case *dag.Sort:
if len(op.Args) != 1 {
Expand Down
83 changes: 24 additions & 59 deletions compiler/semantic/expr.go
Original file line number Diff line number Diff line change
Expand Up @@ -420,55 +420,6 @@ func (a *analyzer) semBinary(e *ast.BinaryExpr) (dag.Expr, error) {
}, nil
}

func (a *analyzer) semPath(e ast.Expr) (*dag.Path, error) {
switch e := e.(type) {
case *ast.BinaryExpr:
if e.Op == "." {
lhs, err := a.semPath(e.LHS)
if err != nil || lhs == nil {
return nil, err
}
id, ok := e.RHS.(*ast.ID)
if !ok {
return nil, nil
}
lhs.Path = append(lhs.Path, &dag.StaticPathElem{Kind: "StaticPathElem", Name: id.Name})
return lhs, nil
}
if e.Op == "[" {
lhs, err := a.semPath(e.LHS)
if lhs == nil || err != nil {
return nil, nil
}
rhs, err := a.semExpr(e.RHS)
if err != nil {
return nil, err
}
if this, ok := rhs.(*dag.This); ok {
lhs.Path = append(lhs.Path, this)
return lhs, nil
}
if p, ok := isStringConst(a.zctx, rhs); ok {
lhs.Path = append(lhs.Path, &dag.StaticPathElem{Kind: "StaticPathElem", Name: p})
return lhs, nil
}
}
return nil, nil
case *ast.ID:
id, err := a.semID(e)
if err != nil {
return nil, err
}
if this, ok := id.(*dag.This); ok {
return dag.NewStaticPath(this.Path...), nil
}
return nil, nil
}
// This includes a null Expr, which can happen if the AST is missing
// a field or sets it to null.
return nil, nil
}

func (a *analyzer) isIndexOfThis(lhs, rhs dag.Expr) *dag.This {
if this, ok := lhs.(*dag.This); ok {
if s, ok := isStringConst(a.zctx, rhs); ok {
Expand Down Expand Up @@ -573,30 +524,44 @@ func (a *analyzer) semAssignment(e ast.Assignment) (dag.Assignment, error) {
if err != nil {
return dag.Assignment{}, err
}
var lhs *dag.Path
var lhs dag.Expr
if e.LHS == nil {
path, err := derriveLHSPath(rhs)
if err != nil {
return dag.Assignment{}, err
}
lhs = dag.NewStaticPath(path...)
lhs = &dag.This{Kind: "This", Path: path}
} else {
if lhs, err = a.semPath(e.LHS); lhs == nil {
if err == nil {
err = errors.New("illegal left-hand side of assignment")
}
if lhs, err = a.semExpr(e.LHS); err != nil {
return dag.Assignment{}, err
}
}
if len(lhs.Path) == 0 {
return dag.Assignment{}, errors.New("cannot assign to 'this'")
if !a.isValidPath(lhs) {
return dag.Assignment{}, errors.New("illegal left-hand side of assignment")
}
if this, ok := lhs.(*dag.This); ok {
if len(this.Path) == 0 {
return dag.Assignment{}, errors.New("cannot assign to 'this'")
}
}
return dag.Assignment{Kind: "Assignment", LHS: lhs, RHS: rhs}, nil
}

func (a *analyzer) isValidPath(e dag.Expr) bool {
switch e := e.(type) {
case *dag.This:
return true
case *dag.Dot:
return a.isValidPath(e.LHS)
case *dag.BinaryExpr:
return e.Op == "[" && a.isValidPath(e.LHS)
}
return dag.Assignment{Kind: "Assignment", LHS: *lhs, RHS: rhs}, nil
return false
}

func assignHasDynamicPath(assignments []dag.Assignment) bool {
for _, a := range assignments {
if a.LHS.StaticPath() == nil {
if _, ok := a.LHS.(*dag.This); !ok {
return true
}
}
Expand Down
Loading

0 comments on commit d2e3ddc

Please sign in to comment.