tijani
4f3ef7d314
git-svn-id: https://svn.tlawal.org/svn/monkey@62 f6afcba9-9ef1-4bdd-9b72-7484f5705bac
66 lines
2.0 KiB
Go
66 lines
2.0 KiB
Go
/*
|
|
Environment
|
|
|
|
An environment in this interpreter is what is used to keep track of values by associating them with a name.
|
|
Under the hood, the environment is basically an hash map that associates strings with objects.
|
|
*/
|
|
|
|
package object
|
|
|
|
type Environment struct {
|
|
store map[string]Object
|
|
outer *Environment
|
|
}
|
|
|
|
func NewEnvironment() *Environment {
|
|
s := make(map[string]Object)
|
|
return &Environment{store: s, outer: nil}
|
|
}
|
|
|
|
/*
|
|
Enclosing Environments
|
|
|
|
Here is a problem case, lets say in monkey I would want to type this:
|
|
|
|
```
|
|
let i = 5;
|
|
let print_num = fn(i) {
|
|
puts(i);
|
|
}
|
|
|
|
print_num(10);
|
|
puts(i);
|
|
```
|
|
|
|
The ideal result of the above code in the monkey programming language is for 10 and 5 to be the outputs respectively.
|
|
In a situation where enclosed environment does not exists, both outputs will be 10 because the current value of i
|
|
would be overwritten. The ideal situation would be to preserve the previous binding to 'i' while also making a a new
|
|
one.
|
|
|
|
This works be creating a new instance of object.Environment with a pointer to the environment it should extend, doing this
|
|
encloses a fresh and empty environment with an existing one. When the Get method is called and it itself doesn't have the value
|
|
associated with the given name, it calls the Get of the enclosing environment. That's the environment it's extending. If that
|
|
enclosing environment can't find the value, it calls its own enclosing environment and so on until there is no enclosing environment
|
|
anymore and it will error out to an unknown identifier.
|
|
*/
|
|
func NewEnclosedEnvironment(outer *Environment) *Environment {
|
|
env := NewEnvironment()
|
|
env.outer = outer
|
|
return env
|
|
}
|
|
|
|
func (l_environment *Environment) Get(name string) (Object, bool) {
|
|
obj, ok := l_environment.store[name]
|
|
|
|
if !ok && l_environment.outer != nil {
|
|
obj, ok = l_environment.outer.Get(name)
|
|
}
|
|
|
|
return obj, ok
|
|
}
|
|
|
|
func (l_environment *Environment) Set(name string, value Object) Object {
|
|
l_environment.store[name] = value
|
|
return value
|
|
}
|