Go: store scopes in reverse order for efficiency

This commit is contained in:
Přemysl Eric Janouch 2018-10-10 19:53:22 +02:00
parent 563e8ba069
commit 2717cd569b
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 9 additions and 13 deletions

View File

@ -539,7 +539,7 @@ type Handler func(*Ell, []V, *[]V) bool
// Ell is an interpreter context. // Ell is an interpreter context.
type Ell struct { type Ell struct {
Globals map[string]V // list of global variables Globals map[string]V // list of global variables
scopes []map[string]V // dynamic scopes from the newest scopes []map[string]V // dynamic scopes from the oldest
Native map[string]Handler // maps strings to Go functions Native map[string]Handler // maps strings to Go functions
Error string // error information Error string // error information
@ -564,8 +564,8 @@ func scopeFind(scope []*V, name string) int {
// Get retrieves a value by name from the scope or from global variables. // Get retrieves a value by name from the scope or from global variables.
func (ell *Ell) Get(name string) *V { func (ell *Ell) Get(name string) *V {
for _, scope := range ell.scopes { for i := len(ell.scopes) - 1; i >= 0; i-- {
if v, ok := scope[name]; ok { if v, ok := ell.scopes[i][name]; ok {
return &v return &v
} }
} }
@ -577,9 +577,9 @@ func (ell *Ell) Get(name string) *V {
// Set sets a value by name in the scope or in global variables. // Set sets a value by name in the scope or in global variables.
func (ell *Ell) Set(name string, v *V) { func (ell *Ell) Set(name string, v *V) {
for _, scope := range ell.scopes { for i := len(ell.scopes) - 1; i >= 0; i-- {
if _, ok := scope[name]; ok { if _, ok := ell.scopes[i][name]; ok {
scope[name] = *v ell.scopes[i][name] = *v
return return
} }
} }
@ -711,11 +711,7 @@ func argsToScope(args []V) map[string]V {
// EvalBlock executes a block and returns whatever the last statement returned, // EvalBlock executes a block and returns whatever the last statement returned,
// eats args. // eats args.
func (ell *Ell) EvalBlock(body []V, args []V, result *[]V) bool { func (ell *Ell) EvalBlock(body []V, args []V, result *[]V) bool {
// TODO: This is O(n), let's just rather append and traverse in reverse. ell.scopes = append(ell.scopes, argsToScope(args))
newScopes := make([]map[string]V, len(ell.scopes)+1)
newScopes[0] = argsToScope(args)
copy(newScopes[1:], ell.scopes)
ell.scopes = newScopes
ok := true ok := true
for _, stmt := range body { for _, stmt := range body {
@ -724,7 +720,7 @@ func (ell *Ell) EvalBlock(body []V, args []V, result *[]V) bool {
break break
} }
} }
ell.scopes = ell.scopes[1:] ell.scopes = ell.scopes[:len(ell.scopes)-1]
return ok return ok
} }
@ -782,7 +778,7 @@ func fnLocal(ell *Ell, args []V, result *[]V) bool {
} }
// Duplicates or non-strings don't really matter to us, user's problem. // Duplicates or non-strings don't really matter to us, user's problem.
scope := ell.scopes[0] scope := ell.scopes[len(ell.scopes)-1]
values := args[1:] values := args[1:]
for _, name := range args[0].List { for _, name := range args[0].List {