aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPřemysl Janouch <p@janouch.name>2018-10-10 19:49:17 +0200
committerPřemysl Janouch <p@janouch.name>2018-10-10 19:56:05 +0200
commit563e8ba06913f0c6a7df42e1c379162f902f9570 (patch)
treecbc43125e54ef8eeaa84313b19924d71c52c7928
parentb210216c711de9043964313662677dff513fde1d (diff)
downloadell-563e8ba06913f0c6a7df42e1c379162f902f9570.tar.gz
ell-563e8ba06913f0c6a7df42e1c379162f902f9570.tar.xz
ell-563e8ba06913f0c6a7df42e1c379162f902f9570.zip
Go: store scopes and globals as maps
-rw-r--r--cmd/repl/main.go3
-rw-r--r--ell/ell.go48
2 files changed, 18 insertions, 33 deletions
diff --git a/cmd/repl/main.go b/cmd/repl/main.go
index 098452d..b1bb413 100644
--- a/cmd/repl/main.go
+++ b/cmd/repl/main.go
@@ -48,8 +48,7 @@ func complete(L *ell.Ell, line string, pos int) (
head, line = line[:lastSpace+1], line[lastSpace+1:]
}
- for _, v := range L.Globals {
- name := v.List[0].String
+ for name := range L.Globals {
if strings.HasPrefix(strings.ToLower(name), line) {
completions = append(completions, name)
}
diff --git a/ell/ell.go b/ell/ell.go
index 154f731..b517865 100644
--- a/ell/ell.go
+++ b/ell/ell.go
@@ -538,8 +538,8 @@ type Handler func(*Ell, []V, *[]V) bool
// Ell is an interpreter context.
type Ell struct {
- Globals []*V // list of global variables
- scopes [][]*V // dynamic scopes from the newest
+ Globals map[string]V // list of global variables
+ scopes []map[string]V // dynamic scopes from the newest
Native map[string]Handler // maps strings to Go functions
Error string // error information
@@ -548,7 +548,8 @@ type Ell struct {
// New returns a new interpreter context ready for program execution.
func New() *Ell {
return &Ell{
- Native: make(map[string]Handler),
+ Globals: make(map[string]V),
+ Native: make(map[string]Handler),
}
}
@@ -561,26 +562,15 @@ func scopeFind(scope []*V, name string) int {
return -1
}
-// TODO: This is O(n), let's just make them a map[string]*V.
-func scopePrepend(scope []*V, name string, v *V) []*V {
- key := NewString(name)
- pair := NewList([]V{*key, *v})
-
- result := make([]*V, len(scope)+1)
- copy(result[1:], scope)
- result[0] = pair
- return result
-}
-
// Get retrieves a value by name from the scope or from global variables.
func (ell *Ell) Get(name string) *V {
for _, scope := range ell.scopes {
- if place := scopeFind(scope, name); place >= 0 {
- return &scope[place].List[1]
+ if v, ok := scope[name]; ok {
+ return &v
}
}
- if place := scopeFind(ell.Globals, name); place >= 0 {
- return &ell.Globals[place].List[1]
+ if v, ok := ell.Globals[name]; ok {
+ return &v
}
return nil
}
@@ -588,18 +578,14 @@ func (ell *Ell) Get(name string) *V {
// Set sets a value by name in the scope or in global variables.
func (ell *Ell) Set(name string, v *V) {
for _, scope := range ell.scopes {
- if place := scopeFind(scope, name); place >= 0 {
- scope[place].List[1] = *v
+ if _, ok := scope[name]; ok {
+ scope[name] = *v
return
}
}
// Variables only get deleted by "arg" or from the global scope.
- if place := scopeFind(ell.Globals, name); place >= 0 {
- ell.Globals[place].List[1] = *v
- } else {
- ell.Globals = scopePrepend(ell.Globals, name, v)
- }
+ ell.Globals[name] = *v
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -714,10 +700,10 @@ func (ell *Ell) evalStatement(statement *V, result *[]V) bool {
return false
}
-func argsToScope(args []V) []*V {
- scope := scopePrepend(nil, "args", NewList(args))
+func argsToScope(args []V) map[string]V {
+ scope := map[string]V{"args": *NewList(args)}
for i, arg := range args {
- scope = scopePrepend(scope, fmt.Sprintf("%d", i+1), arg.Clone())
+ scope[fmt.Sprintf("%d", i+1)] = *arg.Clone()
}
return scope
}
@@ -726,7 +712,7 @@ func argsToScope(args []V) []*V {
// eats args.
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.
- newScopes := make([][]*V, len(ell.scopes)+1)
+ newScopes := make([]map[string]V, len(ell.scopes)+1)
newScopes[0] = argsToScope(args)
copy(newScopes[1:], ell.scopes)
ell.scopes = newScopes
@@ -796,12 +782,12 @@ func fnLocal(ell *Ell, args []V, result *[]V) bool {
}
// Duplicates or non-strings don't really matter to us, user's problem.
- scope := &ell.scopes[0]
+ scope := ell.scopes[0]
values := args[1:]
for _, name := range args[0].List {
- *scope = scopePrepend(*scope, name.String, values[0].Clone())
if len(values) > 0 {
+ scope[name.String] = *values[0].Clone()
values = values[1:]
}
}