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) {
|
for _, l := range FormatInstructions(cn.Instructions, 0) {
|
||||||
output = append(output, fmt.Sprintf(" %s", l))
|
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:
|
default:
|
||||||
output = append(output, fmt.Sprintf("[% 3d] %s (%s|%p)", cidx, cn, reflect.TypeOf(cn).Elem().Name(), &cn))
|
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.MapIterator{})
|
||||||
gob.Register(&objects.ArrayIterator{})
|
gob.Register(&objects.ArrayIterator{})
|
||||||
gob.Register(&objects.Time{})
|
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
|
// if symbol is defined in parent table and if it's not global/builtin
|
||||||
// then it's free variable.
|
// 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
|
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)
|
- [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)
|
- [Error](https://godoc.org/github.com/d5/tengo/objects#Error)
|
||||||
- [Undefined](https://godoc.org/github.com/d5/tengo/objects#Undefined)
|
- [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.
|
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)
|
}()`, 15)
|
||||||
|
|
||||||
expectError(t, `return 5`)
|
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`,
|
"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