-
Notifications
You must be signed in to change notification settings - Fork 67
/
dot.go
122 lines (110 loc) · 2.69 KB
/
dot.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
package expr
import (
"errors"
"slices"
"github.com/brimdata/zed"
"github.com/brimdata/zed/pkg/field"
"github.com/brimdata/zed/zcode"
)
type This struct{}
func (*This) Eval(_ Context, this *zed.Value) *zed.Value {
return this
}
type DotExpr struct {
zctx *zed.Context
record Evaluator
field string
fieldIndices []int
}
func NewDotExpr(zctx *zed.Context, record Evaluator, field string) *DotExpr {
return &DotExpr{
zctx: zctx,
record: record,
field: field,
}
}
func NewDottedExpr(zctx *zed.Context, f field.Path) Evaluator {
ret := Evaluator(&This{})
for _, name := range f {
ret = NewDotExpr(zctx, ret, name)
}
return ret
}
func (d *DotExpr) Eval(ectx Context, this *zed.Value) *zed.Value {
var tmpVal zed.Value
val := d.record.Eval(ectx, this).Under(&tmpVal)
// Cases are ordered by decreasing expected frequency.
switch typ := val.Type.(type) {
case *zed.TypeRecord:
i, ok := d.fieldIndex(typ)
if !ok {
return d.zctx.Missing()
}
return ectx.NewValue(typ.Fields[i].Type, getNthFromContainer(val.Bytes(), i))
case *zed.TypeMap:
return indexMap(d.zctx, ectx, typ, val.Bytes(), zed.NewString(d.field))
case *zed.TypeOfType:
return d.evalTypeOfType(ectx, val.Bytes())
}
return d.zctx.Missing()
}
func (d *DotExpr) fieldIndex(typ *zed.TypeRecord) (int, bool) {
id := typ.ID()
if id >= len(d.fieldIndices) {
d.fieldIndices = slices.Grow(d.fieldIndices[:0], id+1)[:id+1]
}
if i := d.fieldIndices[id]; i > 0 {
return i - 1, true
} else if i < 0 {
return 0, false
}
i, ok := typ.IndexOfField(d.field)
if ok {
d.fieldIndices[id] = i + 1
} else {
d.fieldIndices[id] = -1
}
return i, ok
}
func (d *DotExpr) evalTypeOfType(ectx Context, b zcode.Bytes) *zed.Value {
typ, _ := d.zctx.DecodeTypeValue(b)
if typ, ok := zed.TypeUnder(typ).(*zed.TypeRecord); ok {
if typ, ok := typ.TypeOfField(d.field); ok {
return d.zctx.LookupTypeValue(typ)
}
}
return d.zctx.Missing()
}
// DotExprToString returns Zed for the Evaluator assuming it's a field expr.
func DotExprToString(e Evaluator) (string, error) {
f, err := DotExprToField(e)
if err != nil {
return "", err
}
return f.String(), nil
}
func DotExprToField(e Evaluator) (field.Path, error) {
switch e := e.(type) {
case *This:
return field.Path{}, nil
case *DotExpr:
lhs, err := DotExprToField(e.record)
if err != nil {
return nil, err
}
return append(lhs, e.field), nil
case *Literal:
return field.Path{e.val.String()}, nil
case *Index:
lhs, err := DotExprToField(e.container)
if err != nil {
return nil, err
}
rhs, err := DotExprToField(e.index)
if err != nil {
return nil, err
}
return append(lhs, rhs...), nil
}
return nil, errors.New("not a field")
}