Skip to content

Commit 9d45873

Browse files
committed
vm, builtin, py: locals(), globals() and builtin fixes
* builtin: Implement locals(), globals() and fix __import__() * builtin: Fix ord() * builtin: Tests * py: frame: add FastToLocals and LocalsToFast * vm: Use the above in IMPORT_STAR * vm: Implementation for locals(), globals() and call for __import__
1 parent 4f76837 commit 9d45873

File tree

9 files changed

+382
-29
lines changed

9 files changed

+382
-29
lines changed

builtin/builtin.go

+16-23
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Noteworthy: None is the 'nil' object; Ellipsis represents '...' in slices.`
1818
func init() {
1919
methods := []*py.Method{
2020
py.NewMethod("__build_class__", builtin___build_class__, 0, build_class_doc),
21-
py.NewMethod("__import__", builtin___import__, 0, import_doc),
21+
py.NewMethod("__import__", py.InternalMethodImport, 0, import_doc),
2222
py.NewMethod("abs", builtin_abs, 0, abs_doc),
2323
// py.NewMethod("all", builtin_all, 0, all_doc),
2424
// py.NewMethod("any", builtin_any, 0, any_doc),
@@ -34,7 +34,7 @@ func init() {
3434
// py.NewMethod("exec", builtin_exec, 0, exec_doc),
3535
// py.NewMethod("format", builtin_format, 0, format_doc),
3636
py.NewMethod("getattr", builtin_getattr, 0, getattr_doc),
37-
// py.NewMethod("globals", builtin_globals, py.METH_NOARGS, globals_doc),
37+
py.NewMethod("globals", py.InternalMethodGlobals, 0, globals_doc),
3838
py.NewMethod("hasattr", builtin_hasattr, 0, hasattr_doc),
3939
// py.NewMethod("hash", builtin_hash, 0, hash_doc),
4040
// py.NewMethod("hex", builtin_hex, 0, hex_doc),
@@ -44,7 +44,7 @@ func init() {
4444
// py.NewMethod("issubclass", builtin_issubclass, 0, issubclass_doc),
4545
// py.NewMethod("iter", builtin_iter, 0, iter_doc),
4646
py.NewMethod("len", builtin_len, 0, len_doc),
47-
// py.NewMethod("locals", builtin_locals, py.METH_NOARGS, locals_doc),
47+
py.NewMethod("locals", py.InternalMethodLocals, 0, locals_doc),
4848
// py.NewMethod("max", builtin_max, 0, max_doc),
4949
// py.NewMethod("min", builtin_min, 0, min_doc),
5050
py.NewMethod("next", builtin_next, 0, next_doc),
@@ -351,21 +351,6 @@ fromlist is not empty. Level is used to determine whether to perform
351351
absolute or relative imports. 0 is absolute while a positive number
352352
is the number of parent directories to search relative to the current module.`
353353

354-
func builtin___import__(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
355-
kwlist := []string{"name", "globals", "locals", "fromlist", "level"}
356-
var name py.Object
357-
var globals py.Object = py.NewStringDict()
358-
var locals py.Object = py.NewStringDict()
359-
var fromlist py.Object = py.Tuple{}
360-
var level py.Object = py.Int(0)
361-
362-
py.ParseTupleAndKeywords(args, kwargs, "U|OOOi:__import__", kwlist, &name, &globals, &locals, &fromlist, &level)
363-
if fromlist == py.None {
364-
fromlist = py.Tuple{}
365-
}
366-
return py.ImportModuleLevelObject(string(name.(py.String)), globals.(py.StringDict), locals.(py.StringDict), fromlist.(py.Tuple), int(level.(py.Int)))
367-
}
368-
369354
const ord_doc = `ord(c) -> integer
370355
371356
Return the integer ordinal of a one-character string.`
@@ -375,13 +360,13 @@ func builtin_ord(self, obj py.Object) py.Object {
375360
switch x := obj.(type) {
376361
case py.Bytes:
377362
size = len(x)
378-
if len(x) == 1 {
363+
if size == 1 {
379364
return py.Int(x[0])
380365
}
381366
case py.String:
382-
var rune rune
383-
rune, size = utf8.DecodeRuneInString(string(x))
384-
if len(x) == size && rune != utf8.RuneError {
367+
size = len(x)
368+
rune, runeSize := utf8.DecodeRuneInString(string(x))
369+
if size == runeSize && rune != utf8.RuneError {
385370
return py.Int(rune)
386371
}
387372
//case py.ByteArray:
@@ -396,7 +381,7 @@ func builtin_ord(self, obj py.Object) py.Object {
396381
panic(py.ExceptionNewf(py.TypeError, "ord() expected string of length 1, but %s found", obj.Type().Name))
397382
}
398383

399-
panic(py.ExceptionNewf(py.TypeError, "ord() expected a character, but string of length %zd found", size))
384+
panic(py.ExceptionNewf(py.TypeError, "ord() expected a character, but string of length %d found", size))
400385
}
401386

402387
const getattr_doc = `getattr(object, name[, default]) -> value
@@ -575,3 +560,11 @@ func builtin_chr(self py.Object, args py.Tuple) py.Object {
575560
n := utf8.EncodeRune(buf, rune(x))
576561
return py.String(buf[:n])
577562
}
563+
564+
const locals_doc = `locals() -> dictionary
565+
566+
Update and return a dictionary containing the current scope's local variables.`
567+
568+
const globals_doc = `globals() -> dictionary
569+
570+
Return the dictionary containing the current scope's global variables.`

builtin/builtin_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package builtin_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/ncw/gpython/pytest"
7+
)
8+
9+
func TestVm(t *testing.T) {
10+
pytest.RunTests(t, "tests")
11+
}

builtin/tests/builtin.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
doc="abs"
2+
assert abs(0) == 0
3+
assert abs(10) == 10
4+
assert abs(-10) == 10
5+
6+
doc="chr"
7+
assert chr(65) == "A"
8+
assert chr(163) == "£"
9+
assert chr(0x263A) == "☺"
10+
11+
doc="compile"
12+
code = compile("pass", "<string>", "exec")
13+
# FIXME
14+
15+
doc="getattr"
16+
class C:
17+
def __init__(self):
18+
self.potato = 42
19+
c = C()
20+
assert getattr(c, "potato") == 42
21+
assert getattr(c, "potato", 43) == 42
22+
assert getattr(c, "sausage", 43) == 43
23+
24+
doc="globals"
25+
a = 1
26+
assert globals()["a"] == 1
27+
28+
doc="hasattr"
29+
assert hasattr(c, "potato")
30+
assert not hasattr(c, "sausage")
31+
32+
doc="len"
33+
assert len(()) == 0
34+
assert len((1,2,3)) == 3
35+
assert len("hello") == 5
36+
assert len("£☺") == 2
37+
38+
doc="locals"
39+
def fn(x):
40+
print(locals())
41+
assert locals()["x"] == 1
42+
fn(1)
43+
44+
doc="next no default"
45+
def gen():
46+
yield 1
47+
yield 2
48+
g = gen()
49+
assert next(g) == 1
50+
assert next(g) == 2
51+
ok = False
52+
try:
53+
next(g)
54+
except StopIteration:
55+
ok = True
56+
assert ok, "StopIteration not raised"
57+
58+
doc="next with default"
59+
g = gen()
60+
assert next(g, 42) == 1
61+
assert next(g, 42) == 2
62+
assert next(g, 42) == 42
63+
assert next(g, 42) == 42
64+
65+
doc="next no default with exception"
66+
def gen2():
67+
yield 1
68+
raise ValueError("potato")
69+
g = gen2()
70+
assert next(g) == 1
71+
ok = False
72+
try:
73+
next(g)
74+
except ValueError:
75+
ok = True
76+
assert ok, "ValueError not raised"
77+
78+
doc="next with default and exception"
79+
g = gen2()
80+
assert next(g, 42) == 1
81+
ok = False
82+
try:
83+
next(g)
84+
except ValueError:
85+
ok = True
86+
assert ok, "ValueError not raised"
87+
88+
doc="ord"
89+
assert 65 == ord("A")
90+
assert 163 == ord("£")
91+
assert 0x263A == ord("☺")
92+
assert 65 == ord(b"A")
93+
ok = False
94+
try:
95+
ord("AA")
96+
except TypeError as e:
97+
if e.args[0] != "ord() expected a character, but string of length 2 found":
98+
raise
99+
ok = True
100+
assert ok, "TypeError not raised"
101+
try:
102+
ord(None)
103+
except TypeError as e:
104+
if e.args[0] != "ord() expected string of length 1, but NoneType found":
105+
raise
106+
ok = True
107+
assert ok, "TypeError not raised"
108+
109+
doc="pow"
110+
assert pow(2, 10) == 1024
111+
# FIXME assert pow(2, 10, 17) == 4
112+
113+
doc="print"
114+
# FIXME
115+
116+
doc="round"
117+
assert round(1.1) == 1.0
118+
119+
doc="setattr"
120+
class C: pass
121+
c = C()
122+
assert not hasattr(c, "potato")
123+
setattr(c, "potato", "spud")
124+
assert getattr(c, "potato") == "spud"
125+
assert c.potato == "spud"
126+
127+
doc="__import__"
128+
lib = __import__("lib")
129+
assert lib.libfn() == 42
130+
assert lib.libvar == 43
131+
assert lib.libclass().method() == 44
132+
133+
doc="finished"

builtin/tests/lib.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Some targets to be imported
2+
3+
def libfn():
4+
return 42
5+
6+
libvar = 43
7+
8+
class libclass:
9+
def method(self):
10+
return 44
11+
12+
_libprivate = 45

notes.txt

+9
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,15 @@ Make a gpython-minimal with no built in stdlib
1616

1717
Bytecode compile the standard library and embed into go files - can then make a gpython with no external files.
1818

19+
NB Would probably be a lot quicker to define
20+
21+
Arg struct {
22+
Name string
23+
Value Object
24+
}
25+
26+
And pass args using []Arg instead of StringDict
27+
1928
Testing
2029
=======
2130

0 commit comments

Comments
 (0)