Skip to content

Commit

Permalink
setValue() should not be able to 'let' aka set new vars
Browse files Browse the repository at this point in the history
to ensure it's still possible to create new vars via the Runtime API, there's a new Let() method (which might shadow a var existing in a parent scope), as well as SetOrLet() which does the right thing for you, depending on if a var with the given name exists or not.
  • Loading branch information
sauerbraten committed Jun 30, 2020
1 parent 7dd582e commit 16fe512
Showing 1 changed file with 20 additions and 15 deletions.
35 changes: 20 additions & 15 deletions eval.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,24 +142,9 @@ func (state *Runtime) setValue(name string, val reflect.Value) {
sc = sc.parent
}

// find first non-nil variable scope and set as new variable
sc = state.scope
for sc != nil {
if sc.variables != nil {
sc.variables[name] = val
return
}
sc = sc.parent
}

panic(fmt.Errorf("could not find non-nil variable scope to set %q = %v", name, val))
}

// Set sets variable ${name} in the current template scope
func (state *Runtime) Set(name string, val interface{}) {
state.setValue(name, reflect.ValueOf(val))
}

// SetGlobal sets variable ${name} in the top-most template scope
func (state *Runtime) SetGlobal(name string, val interface{}) {
sc := state.scope
Expand All @@ -172,6 +157,26 @@ func (state *Runtime) SetGlobal(name string, val interface{}) {
sc.variables[name] = reflect.ValueOf(val)
}

// Set sets the existing variable ${name} in the template scope it lives in.
func (state *Runtime) Set(name string, val interface{}) {
state.setValue(name, reflect.ValueOf(val))
}

// Let creates a variable ${name} in the current template scope (possibly shadowing an existing variable of the same name in a parent scope).
func (state *Runtime) Let(name string, val interface{}) {
state.scope.variables[name] = reflect.ValueOf(val)
}

// SetOrLet calls Set() (if a variable with the given name is visible from the current scope) or Let() (if there is no variable with the given name in the current or any parent scope).
func (state *Runtime) SetOrLet(name string, val interface{}) {
_, err := state.resolve(name)
if err != nil {
state.Let(name, val)
} else {
state.Set(name, val)
}
}

// Resolve resolves a value from the execution context.
func (state *Runtime) resolve(name string) (reflect.Value, error) {
if name == "." {
Expand Down

0 comments on commit 16fe512

Please sign in to comment.