Skip to content

Commit

Permalink
Move store to internal/store
Browse files Browse the repository at this point in the history
  • Loading branch information
k1LoW committed Dec 30, 2024
1 parent 85c668e commit 482eb94
Show file tree
Hide file tree
Showing 28 changed files with 1,760 additions and 1,599 deletions.
32 changes: 32 additions & 0 deletions alias.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package runn

import (
"github.com/k1LoW/runn/internal/eval"
"github.com/k1LoW/runn/internal/exprtrace"
)

func EvalWithTrace(e string, store exprtrace.EvalEnv) (*exprtrace.EvalResult, error) {
return eval.EvalWithTrace(e, store)
}

func Eval(e string, store exprtrace.EvalEnv) (any, error) {
return eval.Eval(e, store)
}

// EvalAny evaluate any type. but, EvalAny do not evaluate map key.
func EvalAny(e any, store exprtrace.EvalEnv) (any, error) {
return eval.EvalAny(e, store)
}

func EvalCond(cond string, store exprtrace.EvalEnv) (bool, error) {
return eval.EvalCond(cond, store)
}

func EvalCount(count string, store exprtrace.EvalEnv) (int, error) {
return eval.EvalCount(count, store)
}

// EvalExpand evaluates `in` and expand `{{ }}` in `in` using `store`.
func EvalExpand(in any, store exprtrace.EvalEnv) (any, error) {
return eval.EvalExpand(in, store)
}
244 changes: 8 additions & 236 deletions bind.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@ import (
"context"
"fmt"
"sort"
"strings"

"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/parser"
"github.com/k1LoW/runn/internal/store"
"github.com/samber/lo"
)

Expand All @@ -22,256 +20,30 @@ func newBindRunner() *bindRunner {
func (rnr *bindRunner) Run(ctx context.Context, s *step, first bool) error {
o := s.parent
cond := s.bindCond
store := o.store.toMap()
store[storeRootKeyIncluded] = o.included
sm := o.store.ToMap()
sm[store.RootKeyIncluded] = o.included
if first {
if !s.deferred {
store[storeRootKeyPrevious] = o.store.latest()
sm[store.RootKeyPrevious] = o.store.Latest()
}
} else {
if !s.deferred {
store[storeRootKeyPrevious] = o.store.previous()
sm[store.RootKeyPrevious] = o.store.Previous()
}
store[storeRootKeyCurrent] = o.store.latest()
sm[store.RootKeyCurrent] = o.store.Latest()
}
keys := lo.Keys(cond)
sort.Slice(keys, func(i, j int) bool {
return keys[i] < keys[j]
})
for _, k := range keys {
if lo.Contains(reservedStoreRootKeys, k) {
return fmt.Errorf("%q is reserved", k)
}
v := cond[k]
kv, err := evalBindKeyValue(o.store.bindVars, k, v, store)
if err != nil {
return err
if err := o.store.RecordBindVar(k, v, sm); err != nil {
return fmt.Errorf("failed to record bind vars: %w", err)
}
o.store.bindVars = kv
}
if first {
o.record(s.idx, nil)
}
return nil
}

func evalBindKeyValue(bindVars map[string]any, k string, v any, store map[string]any) (map[string]any, error) {
vv, err := EvalAny(v, store)
if err != nil {
return nil, err
}
if strings.HasSuffix(k, "[]") {
// Append to slice
// - foo[]
// - foo[bar][]
kk := strings.TrimSuffix(k, "[]")
return evalBindKeyValue(bindVars, kk, []any{v}, store)
}
// Merge to map
// - foo
// - foo[bar]
// - foo['bar']
// - foo[5]
// - foo[bar][baz]
tr, err := parser.Parse(k)
if err != nil {
return nil, err
}
kv, err := nodeToMap(tr.Node, vv, store)
if err != nil {
return nil, err
}
return mergeVars(bindVars, kv), nil
}

func nodeToMap(n ast.Node, v any, store map[string]any) (map[string]any, error) {
m := map[string]any{}
switch nn := n.(type) {
case *ast.IdentifierNode:
k := nn.Value
if lo.Contains(reservedStoreRootKeys, k) {
return nil, fmt.Errorf("%q is reserved", k)
}
m[k] = v
case *ast.MemberNode:
switch nnn := nn.Node.(type) {
case *ast.IdentifierNode:
k := nnn.Value
if lo.Contains(reservedStoreRootKeys, k) {
return nil, fmt.Errorf("%q is reserved", k)
}
switch p := nn.Property.(type) {
case *ast.IdentifierNode:
kk, err := EvalAny(p.Value, store)
if err != nil {
return nil, err
}
if kk == nil {
return nil, fmt.Errorf("invalid value: %v", p.Value)
}
m[k] = map[any]any{
kk: v,
}
case *ast.StringNode:
m[k] = map[any]any{
p.Value: v,
}
case *ast.IntegerNode:
m[k] = map[any]any{
p.Value: v,
}
case *ast.MemberNode:
kk, err := EvalAny(p.String(), store)
if err != nil {
return nil, err
}
if kk == nil {
return nil, fmt.Errorf("invalid value: %v", p.String())
}
m[k] = map[any]any{
kk: v,
}
default:
return nil, fmt.Errorf("invalid node type of %v: %T", nn.Property, nn.Property)
}
case *ast.MemberNode:
var vv map[any]any
switch p := nn.Property.(type) {
case *ast.IdentifierNode:
kk, err := EvalAny(p.Value, store)
if err != nil {
return nil, err
}
if kk == nil {
return nil, fmt.Errorf("invalid value: %v", p.Value)
}
vv = map[any]any{
kk: v,
}
case *ast.StringNode:
vv = map[any]any{
p.Value: v,
}
case *ast.IntegerNode:
vv = map[any]any{
p.Value: v,
}
case *ast.MemberNode:
kk, err := EvalAny(p.String(), store)
if err != nil {
return nil, err
}
if kk == nil {
return nil, fmt.Errorf("invalid value: %v", p.String())
}
vv = map[any]any{
kk: v,
}
default:
return nil, fmt.Errorf("invalid node type of %v: %T", nn.Property, nn.Property)
}
vvv, err := nodeToMap(nnn, vv, store)
if err != nil {
return nil, err
}
m = vvv
}
default:
return nil, fmt.Errorf("invalid node type of %v: %T", n, n)
}
return m, nil
}

func mergeVars(org map[string]any, vars map[string]any) map[string]any {
store := make(map[string]any, len(org)+len(vars))
for k, v := range org {
store[k] = v
}
for k, v := range vars {
sv, ok := store[k]
if !ok {
store[k] = v
continue
}
switch svv := sv.(type) {
case map[string]any:
switch vv := v.(type) {
case map[string]any:
store[k] = mergeVars(svv, vv)
case map[any]any:
// convert svv map[string]any to map[any]any
svv2 := make(map[any]any, len(svv))
for k, v := range svv {
svv2[k] = v
}
store[k] = mergeMapAny(svv2, vv)
default:
store[k] = vv
}
case map[any]any:
switch vv := v.(type) {
case map[string]any:
// convert vv map[string]any to map[any]any
vv2 := make(map[any]any, len(vv))
for k, v := range vv {
vv2[k] = v
}
store[k] = mergeMapAny(svv, vv2)
case map[any]any:
store[k] = mergeMapAny(svv, vv)
default:
store[k] = vv
}
case []any:
switch vv := v.(type) {
case []any:
store[k] = append(svv, vv...)
default:
store[k] = vv
}
default:
store[k] = v
}
}
return store
}

func mergeMapAny(org map[any]any, vars map[any]any) map[any]any {
store := map[any]any{}
for k, v := range org {
store[k] = v
}
for k, v := range vars {
sv, ok := store[k]
if !ok {
store[k] = v
continue
}
switch svv := sv.(type) {
case map[string]any:
switch vv := v.(type) {
case map[string]any:
store[k] = mergeVars(svv, vv)
default:
store[k] = vv
}
case map[any]any:
switch vv := v.(type) {
case map[any]any:
store[k] = mergeMapAny(svv, vv)
default:
store[k] = vv
}
case []any:
switch vv := v.(type) {
case []any:
store[k] = append(svv, vv...)
default:
store[k] = vv
}
default:
store[k] = v
}
}
return store
}
Loading

0 comments on commit 482eb94

Please sign in to comment.