Fix a closure-block scope bug (#99)

* fix issue #98

* remove objects.CompiledModule

* remove objects.CompiledModule
This commit is contained in:
Daniel 2019-02-11 17:34:02 -08:00 committed by GitHub
parent 9ccc6dd901
commit fc4e3586c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 53 deletions

View file

@ -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{})
}

View file

@ -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
}

View file

@ -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.

View file

@ -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
}

View file

@ -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)
}

View file

@ -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
}
`,
})
}