Skip to content

Commit

Permalink
add the view method
Browse files Browse the repository at this point in the history
  • Loading branch information
SimFG committed Aug 30, 2024
1 parent b56e7b9 commit d3e451c
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 8 deletions.
10 changes: 10 additions & 0 deletions builtin/builtin.go
Original file line number Diff line number Diff line change
Expand Up @@ -1010,4 +1010,14 @@ var Builtins = []*Function{
},
Types: types(new(func(int) int)),
},
{
Name: "view",
Fast: View,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
return anyType, nil
},
},
}
6 changes: 5 additions & 1 deletion builtin/lib.go
Original file line number Diff line number Diff line change
Expand Up @@ -368,7 +368,11 @@ func flatten(arg reflect.Value) []any {
x := flatten(v)
ret = append(ret, x...)
} else {
ret = append(ret, v.Interface())
if v.CanInterface() {
ret = append(ret, v.Interface())
} else {
ret = append(ret, v)
}
}
}
return ret
Expand Down
103 changes: 103 additions & 0 deletions builtin/view.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package builtin

import (
"encoding/json"
"fmt"
"reflect"

"github.com/expr-lang/expr/internal/deref"
)

type DataView struct {
Type string `json:"type,omitempty"`
Value string `json:"value,omitempty"`
Fields map[string]DataView `json:"fields,omitempty"`
}

var ZeroValue = DataView{
Type: "nil",
Value: "nil",
}

func View(arg any) (result any) {
defer func() {
resultBytes, _ := json.Marshal(result)
result = string(resultBytes)
}()
if arg == nil {
return ZeroValue
}

argValue := deref.Value(reflect.ValueOf(arg))

if !isComplicateKind(argValue.Kind()) {
return getSimpleView(argValue)
}

if argValue.Kind() != reflect.Struct {
return DataView{
Type: argValue.Type().String(),
Value: fmt.Sprintf("%v", innerInterface(argValue)),
}
}

argType := deref.Type(reflect.TypeOf(arg))
fields := make(map[string]DataView)
for i := 0; i < argValue.NumField(); i++ {
fieldType := argType.Field(i)
fieldValue := deref.Value(argValue.Field(i))
if !isComplicateKind(fieldValue.Kind()) {
fields[fieldType.Name] = getSimpleView(fieldValue)
} else {
fields[fieldType.Name] = DataView{
Type: fieldType.Type.String(),
}
}
}

return DataView{
Type: argValue.Type().String(),
Fields: fields,
}
}

func isComplicateKind(kind reflect.Kind) bool {
switch kind {
case reflect.Struct, reflect.Chan, reflect.Func, reflect.Interface:
return true
}
return false
}

func getSimpleView(arg reflect.Value) DataView {
switch arg.Kind() {
case reflect.Array, reflect.Slice:
return DataView{
Type: arg.Type().String(),
Value: fmt.Sprintf("%v", flatten(arg)),
}
case reflect.Map:
keys := arg.MapKeys()
out := make([][2]any, len(keys))
// TODO how to show the detail when the value is a struct
for i, key := range keys {
out[i] = [2]any{innerInterface(key), innerInterface(arg.MapIndex(key))}
}
return DataView{
Type: arg.Type().String(),
Value: fmt.Sprintf("%v", out),
}
}

return DataView{
Type: arg.Type().String(),
Value: fmt.Sprintf("%v", innerInterface(arg)),
}
}

func innerInterface(v reflect.Value) any {
if v.CanInterface() {
return v.Interface()
}
return v
}
9 changes: 5 additions & 4 deletions checker/checker.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ func ParseCheck(input string, config *conf.Config) (*parser.Tree, error) {
}

if len(config.Visitors) > 0 {
// We need to perform types check, because some visitors may rely on
// types information available in the tree.
_, _ = Check(tree, config)

// TODO fubang 1000 count?
for i := 0; i < 1000; i++ {
more := false
for _, v := range config.Visitors {
// We need to perform types check, because some visitors may rely on
// types information available in the tree.
_, _ = Check(tree, config)

ast.Walk(&tree.Node, v)

if v, ok := v.(interface {
Expand Down
8 changes: 5 additions & 3 deletions vm/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ func Fetch(from, i any) any {
return name == fieldName
})
if value.IsValid() {
return value.Interface()
return GetFieldValue(value)
}
}
panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
Expand All @@ -86,7 +86,7 @@ type Field struct {
func FetchField(from any, field *Field) any {
v := reflect.ValueOf(from)
if v.Kind() != reflect.Invalid {
v = reflect.Indirect(v)
v = deref.Value(v)

// We can use v.FieldByIndex here, but it will panic if the field
// is not exists. And we need to recover() to generate a more
Expand Down Expand Up @@ -117,9 +117,11 @@ func fieldByIndex(v reflect.Value, field *Field) reflect.Value {
if len(field.Index) == 1 {
return v.Field(field.Index[0])
}
fmt.Println("inner print", field.Index)
for i, x := range field.Index {
println("inner print for:", i, x)
if i > 0 {
if v.Kind() == reflect.Ptr {
if v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
if v.IsNil() {
panic(fmt.Sprintf("cannot get %v from %v", field.Path[i], field.Path[i-1]))
}
Expand Down

0 comments on commit d3e451c

Please sign in to comment.