Fix a closure-block scope bug (#99)
* fix issue #98 * remove objects.CompiledModule * remove objects.CompiledModule
This commit is contained in:
parent
9ccc6dd901
commit
fc4e3586c4
6 changed files with 74 additions and 53 deletions
|
@ -63,11 +63,6 @@ func (b *Bytecode) FormatConstants() (output []string) {
|
|||
for _, l := range FormatInstructions(cn.Instructions, 0) {
|
||||
output = append(output, fmt.Sprintf(" %s", l))
|
||||
}
|
||||
case *objects.CompiledModule:
|
||||
output = append(output, fmt.Sprintf("[% 3d] (Compiled Module|%p)", cidx, &cn))
|
||||
for _, l := range FormatInstructions(cn.Instructions, 0) {
|
||||
output = append(output, fmt.Sprintf(" %s", l))
|
||||
}
|
||||
default:
|
||||
output = append(output, fmt.Sprintf("[% 3d] %s (%s|%p)", cidx, cn, reflect.TypeOf(cn).Elem().Name(), &cn))
|
||||
}
|
||||
|
@ -116,5 +111,4 @@ func init() {
|
|||
gob.Register(&objects.MapIterator{})
|
||||
gob.Register(&objects.ArrayIterator{})
|
||||
gob.Register(&objects.Time{})
|
||||
gob.Register(&objects.CompiledModule{})
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ func (t *SymbolTable) Resolve(name string) (symbol *Symbol, depth int, ok bool)
|
|||
|
||||
// if symbol is defined in parent table and if it's not global/builtin
|
||||
// then it's free variable.
|
||||
if depth > 0 && symbol.Scope != ScopeGlobal && symbol.Scope != ScopeBuiltin {
|
||||
if !t.block && depth > 0 && symbol.Scope != ScopeGlobal && symbol.Scope != ScopeBuiltin {
|
||||
return t.defineFree(symbol), depth, true
|
||||
}
|
||||
|
||||
|
|
|
@ -140,7 +140,7 @@ These are the basic types Tengo runtime supports out of the box:
|
|||
- [Iterators](https://godoc.org/github.com/d5/tengo/objects#Iterator): [StringIterator](https://godoc.org/github.com/d5/tengo/objects#StringIterator), [ArrayIterator](https://godoc.org/github.com/d5/tengo/objects#ArrayIterator), [MapIterator](https://godoc.org/github.com/d5/tengo/objects#MapIterator), [ImmutableMapIterator](https://godoc.org/github.com/d5/tengo/objects#ImmutableMapIterator)
|
||||
- [Error](https://godoc.org/github.com/d5/tengo/objects#Error)
|
||||
- [Undefined](https://godoc.org/github.com/d5/tengo/objects#Undefined)
|
||||
- Other internal objects: [Closure](https://godoc.org/github.com/d5/tengo/objects#Closure), [CompiledModule](https://godoc.org/github.com/d5/tengo/objects#CompiledModule), [Break](https://godoc.org/github.com/d5/tengo/objects#Break), [Continue](https://godoc.org/github.com/d5/tengo/objects#Continue), [ReturnValue](https://godoc.org/github.com/d5/tengo/objects#ReturnValue)
|
||||
- Other internal objects: [Closure](https://godoc.org/github.com/d5/tengo/objects#Closure), [Break](https://godoc.org/github.com/d5/tengo/objects#Break), [Continue](https://godoc.org/github.com/d5/tengo/objects#Continue), [ReturnValue](https://godoc.org/github.com/d5/tengo/objects#ReturnValue)
|
||||
|
||||
See [Runtime Types](https://github.com/d5/tengo/blob/master/docs/runtime-types.md) for more details on these runtime types.
|
||||
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
package objects
|
||||
|
||||
import (
|
||||
"github.com/d5/tengo/compiler/token"
|
||||
)
|
||||
|
||||
// CompiledModule represents a compiled module.
|
||||
type CompiledModule struct {
|
||||
Instructions []byte // compiled instructions
|
||||
NumGlobals int
|
||||
}
|
||||
|
||||
// TypeName returns the name of the type.
|
||||
func (o *CompiledModule) TypeName() string {
|
||||
return "compiled-module"
|
||||
}
|
||||
|
||||
func (o *CompiledModule) String() string {
|
||||
return "<compiled-module>"
|
||||
}
|
||||
|
||||
// BinaryOp returns another object that is the result of
|
||||
// a given binary operator and a right-hand side object.
|
||||
func (o *CompiledModule) BinaryOp(op token.Token, rhs Object) (Object, error) {
|
||||
return nil, ErrInvalidOperator
|
||||
}
|
||||
|
||||
// Copy returns a copy of the type.
|
||||
func (o *CompiledModule) Copy() Object {
|
||||
return &CompiledModule{
|
||||
Instructions: append([]byte{}, o.Instructions...),
|
||||
NumGlobals: o.NumGlobals,
|
||||
}
|
||||
}
|
||||
|
||||
// IsFalsy returns true if the value of the type is falsy.
|
||||
func (o *CompiledModule) IsFalsy() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Equals returns true if the value of the type
|
||||
// is equal to the value of another object.
|
||||
func (o *CompiledModule) Equals(x Object) bool {
|
||||
return false
|
||||
}
|
|
@ -219,4 +219,38 @@ out = func() {
|
|||
}()`, 15)
|
||||
|
||||
expectError(t, `return 5`)
|
||||
|
||||
// closure and block scopes
|
||||
expect(t, `
|
||||
func() {
|
||||
a := 10
|
||||
func() {
|
||||
b := 5
|
||||
if true {
|
||||
out = a + 5
|
||||
}
|
||||
}()
|
||||
}()`, 15)
|
||||
expect(t, `
|
||||
func() {
|
||||
a := 10
|
||||
b := func() { return 5 }
|
||||
func() {
|
||||
if b() {
|
||||
out = a + b()
|
||||
}
|
||||
}()
|
||||
}()`, 15)
|
||||
expect(t, `
|
||||
func() {
|
||||
a := 10
|
||||
func() {
|
||||
b := func() { return 5 }
|
||||
func() {
|
||||
if true {
|
||||
out = a + b()
|
||||
}
|
||||
}()
|
||||
}()
|
||||
}()`, 15)
|
||||
}
|
||||
|
|
|
@ -208,3 +208,41 @@ export func() {
|
|||
"mod1": `export a`,
|
||||
})
|
||||
}
|
||||
|
||||
func TestModuleBlockScopes(t *testing.T) {
|
||||
// block scopes in module
|
||||
expectWithUserModules(t, `out = import("mod1")()`, 1, map[string]string{
|
||||
"mod1": `
|
||||
rand := import("rand")
|
||||
foo := func() { return 1 }
|
||||
export func() {
|
||||
rand.intn(3)
|
||||
return foo()
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
expectWithUserModules(t, `out = import("mod1")()`, 10, map[string]string{
|
||||
"mod1": `
|
||||
rand := import("rand")
|
||||
foo := func() { return 1 }
|
||||
export func() {
|
||||
rand.intn(3)
|
||||
if foo() {}
|
||||
return 10
|
||||
}
|
||||
`,
|
||||
})
|
||||
|
||||
expectWithUserModules(t, `out = import("mod1")()`, 10, map[string]string{
|
||||
"mod1": `
|
||||
rand := import("rand")
|
||||
foo := func() { return 1 }
|
||||
export func() {
|
||||
rand.intn(3)
|
||||
if true { foo() }
|
||||
return 10
|
||||
}
|
||||
`,
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue