Skip to content

Commit

Permalink
vm: implement IMPORT_NAME, IMPORT_FROM, IMPORT_STAR; py: factor Attri…
Browse files Browse the repository at this point in the history
…bute code

  * Re-arrange and factor Attribute handling
  * Fix bug in import from curent directory
  * Implement IMPORT_*
  • Loading branch information
ncw committed May 23, 2015
1 parent a20d443 commit d059504
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 37 deletions.
15 changes: 2 additions & 13 deletions builtin/builtin.go
Expand Up @@ -411,12 +411,7 @@ func builtin_getattr(self py.Object, args py.Tuple) py.Object {

py.UnpackTuple(args, nil, "getattr", 2, 3, &v, &name, &dflt)

nameStr, ok := name.(py.String)
if !ok {
panic(py.ExceptionNewf(py.TypeError, "getattr(): attribute name must be string"))
}

result, err := py.GetAttrErr(v, string(nameStr))
result, err := py.GetAttrErr(v, name)
if err != nil {
if dflt == nil {
panic(err)
Expand All @@ -435,13 +430,7 @@ func builtin_hasattr(self py.Object, args py.Tuple) py.Object {
var v py.Object
var name py.Object
py.UnpackTuple(args, nil, "hasattr", 2, 2, &v, &name)

nameStr, ok := name.(py.String)
if !ok {
panic(py.ExceptionNewf(py.TypeError, "hasattr(): attribute name must be string"))
}

_, err := py.GetAttrErr(v, string(nameStr))
_, err := py.GetAttrErr(v, name)
return py.NewBool(err == nil)
}

Expand Down
6 changes: 3 additions & 3 deletions py/import.go
Expand Up @@ -12,7 +12,7 @@ import (

var (
// This will become sys.path one day ;-)
modulePath = []string{"", "/usr/lib/python3.3", "/usr/local/lib/python3.3/dist-packages", "/usr/lib/python3/dist-packages"}
modulePath = []string{"", "/usr/lib/python3.4", "/usr/local/lib/python3.4/dist-packages", "/usr/lib/python3/dist-packages"}
)

// The workings of __import__
Expand Down Expand Up @@ -93,7 +93,7 @@ func ImportModuleLevelObject(name string, globals, locals StringDict, fromlist T
if !ok {
panic(ExceptionNewf(SystemError, "Couldn't find __file__ in globals"))
}
mpath = string(mpathObj.(String))
mpath = path.Dir(string(mpathObj.(String)))
}
fullPath := path.Join(mpath, pathParts)
// FIXME Read pyc/pyo too
Expand Down Expand Up @@ -277,7 +277,7 @@ func XImportModuleLevelObject(nameObj, given_globals, locals, given_fromlist Obj
// NOTE: because of this, __initializing__ must be set *before*
// stuffing the new module in sys.modules.

value, err = GetAttrErr(mod, "__initializing__")
value, err = GetAttrStringErr(mod, "__initializing__")
if err == nil {
initializing = bool(MakeBool(value).(Bool))
}
Expand Down
38 changes: 22 additions & 16 deletions py/internal.go
Expand Up @@ -4,6 +4,15 @@

package py

// AttributeName converts an Object to a string, raising a TypeError
// if it wasn't a String
func AttributeName(keyObj Object) string {
if key, ok := keyObj.(String); ok {
return string(key)
}
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", keyObj.Type().Name))
}

// Bool is called to implement truth value testing and the built-in
// operation bool(); should return False or True. When this method is
// not defined, __len__() is called, if it is defined, and the object
Expand Down Expand Up @@ -142,10 +151,10 @@ func DelItem(self Object, key Object) Object {
panic(ExceptionNewf(TypeError, "'%s' object does not support item deletion", self.Type().Name))
}

// GetAttrErr - returns the result or an err to be raised if not found
// GetAttrStringErr - returns the result or an err to be raised if not found
//
// Only AttributeErrors will be returned in err, everything else will be raised
func GetAttrErr(self Object, key string) (res Object, err error) {
func GetAttrStringErr(self Object, key string) (res Object, err error) {
defer func() {
if r := recover(); r != nil {
if IsException(AttributeError, r) {
Expand Down Expand Up @@ -201,9 +210,16 @@ func GetAttrErr(self Object, key string) (res Object, err error) {
return
}

// GetAttrErr - returns the result or an err to be raised if not found
//
// Only AttributeErrors will be returned in err, everything else will be raised
func GetAttrErr(self Object, keyObj Object) (res Object, err error) {
return GetAttrStringErr(self, AttributeName(keyObj))
}

// GetAttrString gets the attribute, raising an error if not found
func GetAttrString(self Object, key string) Object {
res, err := GetAttrErr(self, key)
res, err := GetAttrStringErr(self, key)
if err != nil {
panic(err)
}
Expand All @@ -213,10 +229,7 @@ func GetAttrString(self Object, key string) Object {
// GetAttr gets the attribute rasing an error if key isn't a string or
// attribute not found
func GetAttr(self Object, keyObj Object) Object {
if key, ok := keyObj.(String); ok {
return GetAttrString(self, string(key))
}
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
return GetAttrString(self, AttributeName(keyObj))
}

// SetAttrString
Expand Down Expand Up @@ -255,10 +268,7 @@ func SetAttrString(self Object, key string, value Object) Object {

// SetAttr
func SetAttr(self Object, keyObj Object, value Object) Object {
if key, ok := keyObj.(String); ok {
return GetAttrString(self, string(key))
}
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
return GetAttrString(self, AttributeName(keyObj))
}

// DeleteAttrString
Expand Down Expand Up @@ -301,9 +311,5 @@ func DeleteAttrString(self Object, key string) {

// DeleteAttr
func DeleteAttr(self Object, keyObj Object) {
if key, ok := keyObj.(String); ok {
DeleteAttrString(self, string(key))
return
}
panic(ExceptionNewf(TypeError, "attribute name must be string, not '%s'", self.Type().Name))
DeleteAttrString(self, AttributeName(keyObj))
}
20 changes: 18 additions & 2 deletions vm/eval.go
Expand Up @@ -35,6 +35,7 @@ objects so they can be GCed

import (
"runtime/debug"
"strings"

"github.com/ncw/gpython/py"
)
Expand Down Expand Up @@ -673,7 +674,22 @@ func do_YIELD_VALUE(vm *Vm, arg int32) {
// names. This opcode implements from module import *.
func do_IMPORT_STAR(vm *Vm, arg int32) {
defer vm.CheckException()
vm.NotImplemented("IMPORT_STAR", arg)
from := vm.POP()
module := from.(*py.Module)
if all, ok := module.Globals["__all__"]; ok {
py.Iterate(all, func(item py.Object) bool {
name := py.AttributeName(item)
vm.frame.Locals[name] = py.GetAttrString(module, name)
return false
})
} else {
for name, value := range module.Globals {
if !strings.HasPrefix(name, "_") {
vm.frame.Locals[name] = value
}
}
}
// FIXME implement STORE_FAST stuff
}

// Removes one block from the block stack. Per frame, there is a stack
Expand Down Expand Up @@ -1010,7 +1026,7 @@ func do_IMPORT_FROM(vm *Vm, namei int32) {
defer vm.CheckException()
name := vm.frame.Code.Names[namei]
module := vm.TOP()
res, err := py.GetAttrErr(module, name)
res, err := py.GetAttrStringErr(module, name)
if err != nil {
// Catch AttributeError and rethrow as ImportError
if py.IsException(py.AttributeError, err) {
Expand Down
12 changes: 12 additions & 0 deletions vm/tests/import_from.py
@@ -0,0 +1,12 @@
#!/usr/bin/env python3.4

# test IMPORT_FROM

from lib import libfn, libvar, libclass

assert libfn() == 42
assert libvar == 43
assert libclass().method() == 44

# End with this
finished = True
12 changes: 12 additions & 0 deletions vm/tests/import_name.py
@@ -0,0 +1,12 @@
#!/usr/bin/env python3.4

# test IMPORT_NAME

import lib

assert lib.libfn() == 42
assert lib.libvar == 43
assert lib.libclass().method() == 44

# End with this
finished = True
41 changes: 41 additions & 0 deletions vm/tests/import_star.py
@@ -0,0 +1,41 @@
#!/usr/bin/env python3.4

# test IMPORT_STAR

from lib import *

assert libfn() == 42
assert libvar == 43
assert libclass().method() == 44

# FIXME - exception catching not working
# ok = False
# try:
# _libprivate
# except NameError:
# ok = True
# assert ok

from lib1 import *

assert lib1fn() == 42
assert lib1var == 43

# FIXME - exception handling broken
# ok = False
# try:
# lib1class
# except NameError:
# ok = True
# assert ok

# FIXME - exception handling broken
# ok = False
# try:
# _libprivate
# except NameError:
# ok = True
# assert ok

# End with this
finished = True
14 changes: 14 additions & 0 deletions vm/tests/lib.py
@@ -0,0 +1,14 @@
#!/usr/bin/env python3.4

# Some targets to be imported

def libfn():
return 42

libvar = 43

class libclass:
def method(self):
return 44

_libprivate = 45
19 changes: 19 additions & 0 deletions vm/tests/lib1.py
@@ -0,0 +1,19 @@
#!/usr/bin/env python3.4

# Some targets to be imported

__all__ = [
"lib1fn",
"lib1var",
]

def lib1fn():
return 42

lib1var = 43

class lib1class:
def method(self):
return 44

_lib1private = 45
7 changes: 4 additions & 3 deletions vm/vm_test.go
Expand Up @@ -55,9 +55,10 @@ func TestVm(t *testing.T) {
t.Fatalf("ReadDir failed: %v", err)
}
for _, f := range files {
name := path.Join(testDir, f.Name())
if strings.HasSuffix(name, ".py") {
t.Logf("%s: Starting", name)
name := f.Name()
if !strings.HasPrefix(name, "lib") && strings.HasSuffix(name, ".py") {
name := path.Join(testDir, name)
t.Logf("%s: Running", name)
run(t, name)
}
}
Expand Down

0 comments on commit d059504

Please sign in to comment.