Skip to content

Commit

Permalink
vector: Rudimentary support functions
Browse files Browse the repository at this point in the history
This commit adds rudimentary support for functions. There are a lot of
shortcomings compared to sequence notably: only supports function lower(),
does not variants/unions and wrapped errors are not handled, and it is
not currently tested. Future work will brings things in feature parity.
  • Loading branch information
mattnibs committed Aug 15, 2024
1 parent 71e35c5 commit 722b0a5
Showing 5 changed files with 133 additions and 3 deletions.
22 changes: 20 additions & 2 deletions compiler/kernel/vexpr.go
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import (
"github.com/brimdata/zed/compiler/ast/dag"
"github.com/brimdata/zed/pkg/field"
vamexpr "github.com/brimdata/zed/runtime/vam/expr"
vamfunc "github.com/brimdata/zed/runtime/vam/expr/function"
"github.com/brimdata/zed/zson"
)

@@ -35,8 +36,8 @@ func (b *Builder) compileVamExpr(e dag.Expr) (vamexpr.Evaluator, error) {
return b.compileVamBinary(e)
//case *dag.Conditional:
// return b.compileVamConditional(*e)
//case *dag.Call:
// return b.compileVamCall(*e)
case *dag.Call:
return b.compileVamCall(e)
//case *dag.RegexpMatch:
// return b.compileVamRegexpMatch(e)
//case *dag.RegexpSearch:
@@ -142,3 +143,20 @@ func (b *Builder) compileVamExprs(in []dag.Expr) ([]vamexpr.Evaluator, error) {
}
return exprs, nil
}

func (b *Builder) compileVamCall(call *dag.Call) (vamexpr.Evaluator, error) {
fn, path, err := vamfunc.New(b.zctx(), call.Name, len(call.Args))
if err != nil {
return nil, err
}
args := call.Args
if path != nil {
dagPath := &dag.This{Kind: "This", Path: path}
args = append([]dag.Expr{dagPath}, args...)
}
exprs, err := b.compileVamExprs(args)
if err != nil {
return nil, err
}
return vamexpr.NewCall(fn, exprs), nil
}
29 changes: 28 additions & 1 deletion runtime/vam/expr/eval.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,34 @@
package expr

import "github.com/brimdata/zed/vector"
import (
"github.com/brimdata/zed/vector"
)

type Evaluator interface {
Eval(vector.Any) vector.Any
}

type Function interface {
Call([]vector.Any) vector.Any
}

type Call struct {
fn Function
exprs []Evaluator
args []vector.Any
}

func NewCall(fn Function, exprs []Evaluator) *Call {
return &Call{
fn: fn,
exprs: exprs,
args: make([]vector.Any, len(exprs)),
}
}

func (c *Call) Eval(this vector.Any) vector.Any {
for k, e := range c.exprs {
c.args[k] = e.Eval(this)
}
return c.fn.Call(c.args)
}
25 changes: 25 additions & 0 deletions runtime/vam/expr/function/function.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package function

import (
"github.com/brimdata/zed"
"github.com/brimdata/zed/pkg/field"
"github.com/brimdata/zed/runtime/sam/expr/function"
"github.com/brimdata/zed/runtime/vam/expr"
)

func New(zctx *zed.Context, name string, narg int) (expr.Function, field.Path, error) {
argmin := 1
argmax := 1
var path field.Path
var f expr.Function
switch name {
case "lower":
f = &ToLower{zctx}
default:
return nil, nil, function.ErrNoSuchFunction
}
if err := function.CheckArgCount(narg, argmin, argmax); err != nil {
return nil, nil, err
}
return f, path, nil
}
31 changes: 31 additions & 0 deletions runtime/vam/expr/function/string.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package function

import (
"strings"

"github.com/brimdata/zed"
"github.com/brimdata/zed/vector"
)

// https://github.com/brimdata/zed/blob/main/docs/language/functions.md#lower
type ToLower struct {
zctx *zed.Context
}

func (t *ToLower) Call(args []vector.Any) vector.Any {
v := vector.Under(args[0])
if v.Type() != zed.TypeString {
// XXX This should be a wrapped error as seen in sequential world.
// XXX If this is a View we probably need to transfer.
return vector.NewStringError(t.zctx, "lower: string arg required", v.Len())
}
out := vector.NewStringEmpty(v.Len(), vector.NewBoolEmpty(v.Len(), nil))
for i := uint32(0); i < v.Len(); i++ {
s, null := vector.StringValue(v, i)
if null {
out.Nulls.Set(i)
}
out.Append(strings.ToLower(s))
}
return out
}
29 changes: 29 additions & 0 deletions vector/string.go
Original file line number Diff line number Diff line change
@@ -45,3 +45,32 @@ func (s *String) Serialize(b *zcode.Builder, slot uint32) {
b.Append(zed.EncodeString(s.Value(slot)))
}
}

func StringValue(val Any, slot uint32) (string, bool) {
switch val := val.(type) {
case *String:
if val.Nulls.Value(slot) {
return "", true
}
return val.Value(slot), false
case *Const:
if val.Nulls.Value(slot) {
return "", true
}
s, _ := val.AsString()
return s, false
case *Dict:
if val.Nulls.Value(slot) {
return "", true
}
slot = uint32(val.Index[slot])
return val.Any.(*String).Value(slot), false
case *View:
slot = val.Index[slot]
if val.Any.(*String).Nulls.Value(slot) {
return "", true
}
return val.Any.(*String).Value(slot), false
}
panic(val)
}

0 comments on commit 722b0a5

Please sign in to comment.