Skip to content

Commit

Permalink
fix static scope handling
Browse files Browse the repository at this point in the history
  • Loading branch information
mandelsoft committed Feb 14, 2019
1 parent 73be7b0 commit ebdc644
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 43 deletions.
12 changes: 9 additions & 3 deletions dynaml/defined.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@ func (e CallExpr) valid(binding Binding) (interface{}, EvaluationInfo, bool) {
}

func (e CallExpr) defined(binding Binding) (interface{}, EvaluationInfo, bool) {
info := DefaultInfo()
pushed := make([]Expression, len(e.Arguments))
ok := true
resolved := true

copy(pushed, e.Arguments)
for i, _ := range pushed {
_, _, ok = ResolveExpressionOrPushEvaluation(&pushed[i], &resolved, nil, binding, true)
if resolved && !ok {
return false, DefaultInfo(), true
_, info, ok = ResolveExpressionOrPushEvaluation(&pushed[i], &resolved, nil, binding, true)
if resolved {
if !ok {
return false, DefaultInfo(), true
}
if info.Undefined {
return false, DefaultInfo(), true
}
}
}
if !resolved {
Expand Down
2 changes: 1 addition & 1 deletion dynaml/expression.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ type SourceProvider interface {

type Binding interface {
SourceProvider
GetLocalBinding() map[string]yaml.Node
GetStaticBinding() map[string]yaml.Node
GetRootBinding() map[string]yaml.Node

FindFromRoot([]string) (yaml.Node, bool)
Expand Down
2 changes: 1 addition & 1 deletion dynaml/fake_binding_helper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (c FakeBinding) WithSource(source string) Binding {
return c
}

func (c FakeBinding) GetLocalBinding() map[string]yaml.Node {
func (c FakeBinding) GetStaticBinding() map[string]yaml.Node {
return map[string]yaml.Node{}
}

Expand Down
50 changes: 37 additions & 13 deletions dynaml/lambda.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,18 @@ type LambdaExpr struct {
E Expression
}

func keys(m map[string]yaml.Node) []string {
s := []string{}
for k := range m {
s = append(s, k)
}
return s
}

func (e LambdaExpr) Evaluate(binding Binding, locally bool) (interface{}, EvaluationInfo, bool) {
info := DefaultInfo()
debug.Debug("LAMBDA VALUE with resolver %+v\n", binding)

return LambdaValue{e, binding.GetLocalBinding(), staticScope(binding)}, info, true
return LambdaValue{e, binding.GetStaticBinding(), staticScope(binding)}, info, true
}

func (e LambdaExpr) String() string {
Expand Down Expand Up @@ -69,7 +76,7 @@ func (e LambdaRefExpr) Evaluate(binding Binding, locally bool) (interface{}, Eva
debug.Debug("no lambda expression: %T\n", expr)
return info.Error("'%s' is no lambda expression", v)
}
lambda = LambdaValue{lexpr, binding.GetLocalBinding(), staticScope(binding)}
lambda = LambdaValue{lexpr, binding.GetStaticBinding(), staticScope(binding)}

default:
return info.Error("lambda reference must resolve to lambda value or string")
Expand All @@ -84,7 +91,7 @@ func (e LambdaRefExpr) String() string {

type LambdaValue struct {
lambda LambdaExpr
local map[string]yaml.Node
static map[string]yaml.Node
resolver Binding
}

Expand All @@ -105,18 +112,35 @@ func (e LambdaValue) EquivalentTo(val interface{}) bool {
return ok && reflect.DeepEqual(e.lambda, o.lambda)
}

func (e LambdaValue) String() string {
binding := ""
if len(e.local) > 0 {
binding = "{"
func short(val interface{}, all bool) string {
switch v := val.(type) {
case []yaml.Node:
s := "["
sep := ""
for _, e := range v {
s = fmt.Sprintf("%s%s%s", s, sep, short(e.Value(), all))
sep = ", "
}
return s + "]"
case map[string]yaml.Node:
s := "{"
sep := ""
for n, v := range e.local {
if n != "_" {
binding += fmt.Sprintf("%s%s: %v", sep, n, v.Value())
for k, e := range v {
if all || k != "_" {
s = fmt.Sprintf("%s%s%s: %s", s, sep, k, short(e.Value(), all))
sep = ", "
}
}
binding += "}"
return s + "}"
default:
return fmt.Sprintf("%v", v)
}
}

func (e LambdaValue) String() string {
binding := ""
if len(e.static) > 0 {
binding = short(e.static, false)
}
return fmt.Sprintf("%s%s", binding, e.lambda)
}
Expand All @@ -133,7 +157,7 @@ func (e LambdaValue) Evaluate(args []interface{}, binding Binding, locally bool)
return false, nil, info, false
}
inp := map[string]yaml.Node{}
for n, v := range e.local {
for n, v := range e.static {
inp[n] = v
}
debug.Debug("LAMBDA CALL: inherit local %+v\n", inp)
Expand Down
45 changes: 45 additions & 0 deletions flow/cascade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,51 @@ values: 3
Expect(template).To(CascadeAs(resolved, source, stub))
})
})

Context("lambda scopes", func() {
Context("in lambdas", func() {
It("are passed to nested lambdas", func() {
source := parseYAML(`
---
func: (( |x|->($a=100) |y|->($b=101) |z|->[x,y,z,a,b] ))
values: (( .func(1)(2)(3) ))
`)
resolved := parseYAML(`
---
values:
- 1
- 2
- 3
- 100
- 101
`)
Expect(template).To(CascadeAs(resolved, source))
})
})
Context("in templates", func() {
It("are passed to nested lambdas", func() {
source := parseYAML(`
---
template:
<<: (( &template ))
func: (( |y|->{$x=x, $y=y} ))
func: (( |x|->*template ))
inst: (( .func("instx") ))
values: (( .inst.func("insty") ))
`)
resolved := parseYAML(`
---
values:
x: instx
"y": insty
`)
Expect(template).To(CascadeAs(resolved, source))
})
})
})
})

Describe("using local nodes", func() {
Expand Down
44 changes: 27 additions & 17 deletions flow/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@ import (
)

type Scope struct {
local map[string]yaml.Node
path []string
next *Scope
root *Scope
local map[string]yaml.Node
static map[string]yaml.Node
path []string
next *Scope
root *Scope
}

func newFakeScope(outer *Scope, path []string, local map[string]yaml.Node) *Scope {
return newScope(outer, path, local, nil)
}

func newScope(outer *Scope, path []string, local map[string]yaml.Node) *Scope {
scope := &Scope{local, path, outer, nil}
func newScope(outer *Scope, path []string, local, static map[string]yaml.Node) *Scope {
scope := &Scope{local, static, path, outer, nil}
if outer == nil {
scope.root = scope
} else {
Expand All @@ -38,8 +43,8 @@ type DefaultEnvironment struct {

currentSourceName string

local map[string]yaml.Node
outer dynaml.Binding
static map[string]yaml.Node
outer dynaml.Binding

active bool
}
Expand All @@ -55,10 +60,10 @@ func keys(s map[string]yaml.Node) string {
}

func (e DefaultEnvironment) String() string {
result := fmt.Sprintf("ENV: %s local: %s", strings.Join(e.path, ", "), keys(e.local))
result := fmt.Sprintf("SCOPES: <%s> static: %s", strings.Join(e.path, ", "), keys(e.static))
s := e.scope
for s != nil {
result = result + "\n " + keys(s.local)
result = result + "\n <" + strings.Join(s.path, ", ") + ">" + keys(s.local) + keys(s.static)
s = s.next
}
return result
Expand Down Expand Up @@ -101,8 +106,8 @@ func (e DefaultEnvironment) GetScope() *Scope {
return e.scope
}

func (e DefaultEnvironment) GetLocalBinding() map[string]yaml.Node {
return e.local
func (e DefaultEnvironment) GetStaticBinding() map[string]yaml.Node {
return e.static
}

func (e DefaultEnvironment) FindFromRoot(path []string) (yaml.Node, bool) {
Expand Down Expand Up @@ -146,14 +151,20 @@ func (e DefaultEnvironment) WithSource(source string) dynaml.Binding {
}

func (e DefaultEnvironment) WithScope(step map[string]yaml.Node) dynaml.Binding {
e.scope = newScope(e.scope, e.path, step)
e.local = map[string]yaml.Node{}
e.scope = newScope(e.scope, e.path, step, e.static)
return e
}

func (e DefaultEnvironment) WithLocalScope(step map[string]yaml.Node) dynaml.Binding {
e.scope = newScope(e.scope, nil, step)
e.local = step
static := map[string]yaml.Node{}
for k, v := range e.static {
static[k] = v
}
for k, v := range step {
static[k] = v
}
e.static = static
e.scope = newScope(e.scope, nil, step, static)
return e
}

Expand All @@ -166,7 +177,6 @@ func (e DefaultEnvironment) WithPath(step string) dynaml.Binding {
copy(newPath, e.stubPath)
e.stubPath = append(newPath, step)

e.local = map[string]yaml.Node{}
return e
}

Expand Down
12 changes: 6 additions & 6 deletions flow/environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ foo:
`)

environment := DefaultEnvironment{
scope: newScope(nil, nil, tree.Value().(map[string]yaml.Node)),
scope: newFakeScope(nil, nil, tree.Value().(map[string]yaml.Node)),
}

Context("when the first step is found", func() {
Expand All @@ -37,7 +37,7 @@ foos:
`)

environment := DefaultEnvironment{
scope: newScope(nil, nil, tree.Value().(map[string]yaml.Node)),
scope: newFakeScope(nil, nil, tree.Value().(map[string]yaml.Node)),
}

It("treats the name as the key", func() {
Expand Down Expand Up @@ -66,7 +66,7 @@ foo:
`)

environment := DefaultEnvironment{
scope: newScope(newScope(newScope(nil, nil,
scope: newFakeScope(newFakeScope(newFakeScope(nil, nil,
tree.Value().(map[string]yaml.Node)), nil,
tree.Value().(map[string]yaml.Node)["foo"].Value().(map[string]yaml.Node)), nil,
tree.Value().(map[string]yaml.Node)["foo"].Value().(map[string]yaml.Node)["bar"].Value().(map[string]yaml.Node)),
Expand All @@ -92,7 +92,7 @@ foo:
`)

environment := DefaultEnvironment{
scope: newScope(newScope(newScope(nil, nil,
scope: newFakeScope(newFakeScope(newFakeScope(nil, nil,
tree.Value().(map[string]yaml.Node)), nil,
tree.Value().(map[string]yaml.Node)["foo"].Value().(map[string]yaml.Node)), nil,
tree.Value().(map[string]yaml.Node)["foo"].Value().(map[string]yaml.Node)["bar"].Value().(map[string]yaml.Node)),
Expand Down Expand Up @@ -122,7 +122,7 @@ foo:
`)

environment := DefaultEnvironment{
scope: newScope(nil, nil, tree.Value().(map[string]yaml.Node)),
scope: newFakeScope(nil, nil, tree.Value().(map[string]yaml.Node)),
}

It("returns the node found by the path from the root", func() {
Expand All @@ -141,7 +141,7 @@ foo:
`)

environment := DefaultEnvironment{
scope: newScope(nil, nil, tree.Value().(map[string]yaml.Node)),
scope: newFakeScope(nil, nil, tree.Value().(map[string]yaml.Node)),
}

It("accepts [x] for following through lists", func() {
Expand Down
2 changes: 1 addition & 1 deletion flow/flow.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func flowMap(root yaml.Node, env dynaml.Binding) yaml.Node {
debug.Debug("found temporary declaration\n")
}
if flags.Local() {
debug.Debug("found local declaration\n")
debug.Debug("found static declaration\n")
}
}
if ok && m.Has(dynaml.TEMPLATE) {
Expand Down
1 change: 1 addition & 0 deletions flow/flow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6374,6 +6374,7 @@ result:
})
})
})

Describe("scoped expressions", func() {
Context("in normal expressions", func() {
It("accepts empty scopes", func() {
Expand Down
2 changes: 1 addition & 1 deletion yaml/node.go
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ func EmbeddedDynaml(root Node) *string {
if !ok {
return nil
}
rootString=strings.Replace(rootString,"\n"," ", -1)
rootString = strings.Replace(rootString, "\n", " ", -1)
sub := embeddedDynaml.FindStringSubmatch(rootString)
if sub == nil {
return nil
Expand Down

0 comments on commit ebdc644

Please sign in to comment.