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

Lines changed: 16 additions & 23 deletions
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

Lines changed: 11 additions & 0 deletions
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

Lines changed: 133 additions & 0 deletions
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

Lines changed: 12 additions & 0 deletions
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

Lines changed: 9 additions & 0 deletions
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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy