github.com/MontFerret/ferret@v0.18.0/pkg/runtime/expressions/member.go (about) 1 package expressions 2 3 import ( 4 "context" 5 6 "github.com/pkg/errors" 7 8 "github.com/MontFerret/ferret/pkg/runtime/core" 9 "github.com/MontFerret/ferret/pkg/runtime/values" 10 ) 11 12 type MemberExpression struct { 13 src core.SourceMap 14 source core.Expression 15 path []*MemberPathSegment 16 preCompiledPath []core.Value 17 } 18 19 func NewMemberExpression(src core.SourceMap, source core.Expression, path []*MemberPathSegment, preCompiledPath []core.Value) (*MemberExpression, error) { 20 if source == nil { 21 return nil, core.Error(core.ErrMissedArgument, "source") 22 } 23 24 if len(path) == 0 { 25 return nil, core.Error(core.ErrMissedArgument, "path expressions") 26 } 27 28 return &MemberExpression{src, source, path, preCompiledPath}, nil 29 } 30 31 func (e *MemberExpression) Exec(ctx context.Context, scope *core.Scope) (core.Value, error) { 32 member, err := e.source.Exec(ctx, scope) 33 34 if err != nil { 35 if e.path[0].optional { 36 return values.None, nil 37 } 38 39 return values.None, core.SourceError( 40 e.src, 41 err, 42 ) 43 } 44 45 var segments = e.preCompiledPath 46 47 if e.preCompiledPath == nil { 48 segments = make([]core.Value, len(e.path)) 49 50 // unfold the path 51 for i, seg := range e.path { 52 segment, err := seg.exp.Exec(ctx, scope) 53 54 if err != nil { 55 return values.None, err 56 } 57 58 segments[i] = segment 59 } 60 } 61 62 var pathErr core.PathError 63 var out core.Value = values.None 64 65 getter, ok := member.(core.Getter) 66 67 if ok { 68 out, pathErr = getter.GetIn(ctx, segments) 69 } else { 70 out, pathErr = values.GetIn(ctx, member, segments) 71 } 72 73 if pathErr != nil { 74 segmentIdx := pathErr.Segment() 75 // if invalid index is returned, we ignore the optionality check 76 // and return the pathErr 77 if segmentIdx >= len(e.path) { 78 return values.None, errors.New(pathErr.Format(segments)) 79 } 80 81 segment := e.path[segmentIdx] 82 83 if !segment.optional { 84 return values.None, errors.New(pathErr.Format(segments)) 85 } 86 87 return values.None, nil 88 } 89 90 return out, nil 91 }