Skip to content

Commit 44ee1c2

Browse files
committed
Working towards making classes work
* Implement Cell and None types * Implement __build_class__ builtin (not fully working yet) * Implement globals for modules and __builtin__ globals * Correct spelling of Ellipsis * __doc__ for modules * Add __call__ interface * Rework Call yet again to suport __call__ * Copy a dictionary * Add iterator type * Fill out more Module internals * Opcodes STORE_LOCALS, LOAD_BUILD_CLASS
1 parent c305f37 commit 44ee1c2

26 files changed

+412
-105
lines changed

builtin/builtin.go

+118-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ package builtin
44
import (
55
"fmt"
66
"github.com/ncw/gpython/py"
7+
"github.com/ncw/gpython/vm"
78
)
89

910
const builtin_doc = `Built-in functions, exceptions, and other objects.
@@ -13,7 +14,7 @@ Noteworthy: None is the 'nil' object; Ellipsis represents '...' in slices.`
1314
// Initialise the module
1415
func init() {
1516
methods := []*py.Method{
16-
// py.NewMethod("__build_class__", builtin___build_class__, 0, build_class_doc),
17+
py.NewMethod("__build_class__", builtin___build_class__, 0, build_class_doc),
1718
// py.NewMethod("__import__", builtin___import__, 0, import_doc),
1819
py.NewMethod("abs", builtin_abs, 0, abs_doc),
1920
// py.NewMethod("all", builtin_all, 0, all_doc),
@@ -55,7 +56,40 @@ func init() {
5556
// py.NewMethod("sum", builtin_sum, 0, sum_doc),
5657
// py.NewMethod("vars", builtin_vars, 0, vars_doc),
5758
}
58-
py.NewModule("builtins", builtin_doc, methods)
59+
globals := py.StringDict{
60+
"None": py.None,
61+
"Ellipsis": py.Ellipsis,
62+
"NotImplemented": py.NotImplemented,
63+
"False": py.False,
64+
"True": py.True,
65+
"bool": py.BoolType,
66+
// "memoryview": py.MemoryViewType,
67+
// "bytearray": py.ByteArrayType,
68+
"bytes": py.BytesType,
69+
// "classmethod": py.ClassMethodType,
70+
"complex": py.ComplexType,
71+
"dict": py.StringDictType, // FIXME
72+
// "enumerate": py.EnumType,
73+
// "filter": py.FilterType,
74+
"float": py.FloatType,
75+
"frozenset": py.FrozenSetType,
76+
// "property": py.PropertyType,
77+
"int": py.IntType, // FIXME LongType?
78+
"list": py.ListType,
79+
// "map": py.MapType,
80+
// "object": py.BaseObjectType,
81+
// "range": py.RangeType,
82+
// "reversed": py.ReversedType,
83+
"set": py.SetType,
84+
// "slice": py.SliceType,
85+
// "staticmethod": py.StaticMethodType,
86+
"str": py.StringType,
87+
// "super": py.SuperType,
88+
"tuple": py.TupleType,
89+
"type": py.TypeType,
90+
// "zip": py.ZipType,
91+
}
92+
py.NewModule("builtins", builtin_doc, methods, globals)
5993
}
6094

6195
const print_doc = `print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)
@@ -113,3 +147,85 @@ func builtin_round(self py.Object, args py.Tuple, kwargs py.StringDict) py.Objec
113147

114148
return numberRounder.M__round__(ndigits)
115149
}
150+
151+
const build_class_doc = `__build_class__(func, name, *bases, metaclass=None, **kwds) -> class
152+
153+
Internal helper function used by the class statement.`
154+
155+
func builtin___build_class__(self py.Object, args py.Tuple, kwargs py.StringDict) py.Object {
156+
var prep, cell, cls py.Object
157+
var mkw, ns py.StringDict
158+
var meta, winner *py.Type
159+
var isclass bool
160+
161+
if len(args) < 2 {
162+
// FIXME TypeError
163+
panic(fmt.Sprintf("TypeError: __build_class__: not enough arguments"))
164+
}
165+
166+
// Better be callable
167+
fn, ok := args[0].(*py.Function)
168+
if !ok {
169+
// FIXME TypeError
170+
panic(fmt.Sprintf("TypeError: __build__class__: func must be a function"))
171+
}
172+
173+
name := args[1].(py.String)
174+
if !ok {
175+
// FIXME TypeError
176+
panic(fmt.Sprintf("TypeError: __build_class__: name is not a string"))
177+
}
178+
bases := args[2:]
179+
180+
if kwargs != nil {
181+
mkw = kwargs.Copy() // Don't modify kwds passed in!
182+
meta := mkw["metaclass"] // _PyDict_GetItemId(mkw, &PyId_metaclass)
183+
if meta != nil {
184+
delete(mkw, "metaclass")
185+
// metaclass is explicitly given, check if it's indeed a class
186+
_, isclass = meta.(*py.Type)
187+
}
188+
}
189+
if meta == nil {
190+
// if there are no bases, use type:
191+
if len(bases) == 0 {
192+
meta = py.TypeType
193+
} else {
194+
// else get the type of the first base
195+
meta = bases[0].Type()
196+
}
197+
isclass = true // meta is really a class
198+
}
199+
200+
if isclass {
201+
// meta is really a class, so check for a more derived
202+
// metaclass, or possible metaclass conflicts:
203+
winner = meta.CalculateMetaclass(bases)
204+
if winner != meta {
205+
meta = winner
206+
}
207+
}
208+
// else: meta is not a class, so we cannot do the metaclass
209+
// calculation, so we will use the explicitly given object as it is
210+
prep = meta.Type().Methods["___prepare__"]
211+
if prep == nil {
212+
ns = py.NewStringDict()
213+
} else {
214+
ns = py.Call(prep, py.Tuple{name, bases}, mkw).(py.StringDict)
215+
}
216+
fmt.Printf("Calling %v with %#v and %#v\n", fn.Name, fn.Globals, ns)
217+
cell, err := vm.Run(fn.Globals, ns, fn.Code) // FIXME PyFunction_GET_CLOSURE(fn))
218+
fmt.Printf("result %v %s\n", cell, err)
219+
if err != nil {
220+
// FIXME
221+
panic(err)
222+
}
223+
if cell != nil {
224+
fmt.Printf("Calling %v\n", meta)
225+
cls = py.Call(meta, py.Tuple{name, bases, ns}, mkw)
226+
if c, ok := cell.(*py.Cell); ok {
227+
c.Set(cls)
228+
}
229+
}
230+
return cls
231+
}

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ func main() {
6161
log.Fatal(err)
6262
}
6363
code := obj.(*py.Code)
64-
module := py.NewModule("__main__", "", nil)
64+
module := py.NewModule("__main__", "", nil, nil)
6565
res, err := vm.Run(module.Globals, module.Globals, code)
6666
if err != nil {
6767
log.Fatal(err)

marshal/marshal.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ func ReadObject(r io.Reader) (obj py.Object, err error) {
7777
return py.StopIteration, nil
7878
case TYPE_ELLIPSIS:
7979
// The python elipsis object
80-
return py.Elipsis, nil
80+
return py.Ellipsis, nil
8181
case TYPE_INT:
8282
// 4 bytes of signed integer
8383
var n int32

notes.txt

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
Note byte code is from python 3.3!
2+
13
Put C modules in sub directory
24
Make an all submodule so can insert all of them easily with
35

py/bool.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ package py
55
type Bool bool
66

77
var (
8-
BoolType = NewType("bool")
8+
BoolType = NewType("bool", "bool(x) -> bool\n\nReturns True when the argument x is true, False otherwise.\nThe builtins True and False are the only two instances of the class bool.\nThe class bool is a subclass of the class int, and cannot be subclassed.")
99
// Some well known bools
1010
False = Bool(false)
1111
True = Bool(true)

py/bytes.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
package py
44

5-
var BytesType = NewType("bytes")
5+
var BytesType = NewType("bytes", "bytes(iterable_of_ints) -> bytes\nbytes(string, encoding[, errors]) -> bytes\nbytes(bytes_or_buffer) -> immutable copy of bytes_or_buffer\nbytes(int) -> bytes object of size given by the parameter initialized with null bytes\nbytes() -> empty bytes object\n\nConstruct an immutable array of bytes from:\n - an iterable yielding integers in range(256)\n - a text string encoded using the specified encoding\n - any object implementing the buffer API.\n - an integer")
66

77
type Bytes []byte
88

py/cell.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Cell object
2+
//
3+
// In the Go implementation this is just a pointer to an Object which
4+
// can be nil
5+
6+
package py
7+
8+
// A python Cell object
9+
type Cell struct {
10+
obj *Object
11+
}
12+
13+
var CellType = NewType("cell", "cell object")
14+
15+
// Type of this object
16+
func (o *Cell) Type() *Type {
17+
return CellType
18+
}
19+
20+
// Define a new cell
21+
func NewCell(obj Object) *Cell {
22+
return &Cell{&obj}
23+
}
24+
25+
// Fetch the contents of the Cell or nil if not set
26+
func (c *Cell) Get() Object {
27+
if c.obj == nil {
28+
return nil
29+
}
30+
return *c.obj
31+
}
32+
33+
// Set the contents of the Cell
34+
func (c *Cell) Set(obj Object) {
35+
c.obj = &obj
36+
}

py/code.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ type Code struct {
2929
Weakreflist List // to support weakrefs to code objects
3030
}
3131

32-
var CodeType = NewType("code")
32+
var CodeType = NewType("code", "code(argcount, kwonlyargcount, nlocals, stacksize, flags, codestring,\n constants, names, varnames, filename, name, firstlineno,\n lnotab[, freevars[, cellvars]])\n\nCreate a code object. Not for the faint of heart.")
3333

3434
// Type of this object
3535
func (o *Code) Type() *Type {

py/complex.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import (
88
"math/cmplx"
99
)
1010

11-
var ComplexType = NewType("complex64")
11+
var ComplexType = NewType("complex64", "complex(real[, imag]) -> complex number\n\nCreate a complex number from a real part and an optional imaginary part.\nThis is equivalent to (real + imag*1j) where imag defaults to 0.")
1212

1313
type Complex complex128
1414

py/dict.go

+10-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
package py
77

8-
var StringDictType = NewType("dict")
8+
var StringDictType = NewType("dict", "dict() -> new empty dictionary\ndict(mapping) -> new dictionary initialized from a mapping object's\n (key, value) pairs\ndict(iterable) -> new dictionary initialized as if via:\n d = {}\n for k, v in iterable:\n d[k] = v\ndict(**kwargs) -> new dictionary initialized with the name=value pairs\n in the keyword argument list. For example: dict(one=1, two=2)")
99

1010
// String to object dictionary
1111
//
@@ -21,3 +21,12 @@ func (o StringDict) Type() *Type {
2121
func NewStringDict() StringDict {
2222
return make(StringDict)
2323
}
24+
25+
// Copy a dictionary
26+
func (d StringDict) Copy() StringDict {
27+
e := make(StringDict, len(d))
28+
for k, v := range d {
29+
e[k] = v
30+
}
31+
return e
32+
}

py/exception.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ type Exception struct {
1414
}
1515

1616
var (
17-
ExceptionType = NewType("exception")
17+
// FIXME should be a class probably
18+
ExceptionType = NewType("exception", "Common base class for all exceptions")
1819

1920
// Some well known exceptions - these should be types?
2021
// FIXME exceptions should be created in builtins probably

py/float.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66
"math"
77
)
88

9-
var FloatType = NewType("float")
9+
var FloatType = NewType("float", "float(x) -> floating point number\n\nConvert a string or number to a floating point number, if possible.")
1010

1111
type Float float64
1212

py/frame.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ type Frame struct {
5555
Localsplus []Object // locals+stack, dynamically sized
5656
}
5757

58-
var FrameType = NewType("frame")
58+
var FrameType = NewType("frame", "Represents a stack frame")
5959

6060
// Type of this object
6161
func (o *Frame) Type() *Type {

py/function.go

+21-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ type Function struct {
3131
Qualname string // The qualified name
3232
}
3333

34-
var FunctionType = NewType("function")
34+
var FunctionType = NewType("function", "A python function")
3535

3636
// Type of this object
3737
func (o *Function) Type() *Type {
@@ -106,3 +106,23 @@ func (f *Function) LocalsForCallWithKeywords(args Tuple, kwargs StringDict) Stri
106106
fmt.Printf("FIXME LocalsForCallWithKeywords NOT IMPLEMENTED\n")
107107
return locals
108108
}
109+
110+
// Call a function
111+
func (f *Function) M__call__(args Tuple, kwargs StringDict) Object {
112+
var locals StringDict
113+
if kwargs != nil {
114+
locals = f.LocalsForCallWithKeywords(args, kwargs)
115+
} else {
116+
locals = f.LocalsForCall(args)
117+
}
118+
result, err := Run(f.Globals, locals, f.Code)
119+
if err != nil {
120+
// FIXME - do what exactly!
121+
panic(err)
122+
}
123+
return result
124+
}
125+
126+
// Make sure it satisfies the interface
127+
var _ Object = (*Function)(nil)
128+
var _ I__call__ = (*Function)(nil)

py/int.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import (
77
"math/big"
88
)
99

10-
var IntType = NewType("int")
10+
var IntType = NewType("int", "int(x=0) -> integer\nint(x, base=10) -> integer\n\nConvert a number or string to an integer, or return 0 if no arguments\nare given. If x is a number, return x.__int__(). For floating point\nnumbers, this truncates towards zero.\n\nIf x is not a number or if base is given, then x must be a string,\nbytes, or bytearray instance representing an integer literal in the\ngiven base. The literal can be preceded by '+' or '-' and be surrounded\nby whitespace. The base defaults to 10. Valid bases are 0 and 2-36.\nBase 0 means to interpret the base from the string as an integer literal.\n>>> int('0b100', base=0)\n4")
1111

1212
type Int int64
1313

@@ -18,7 +18,7 @@ func (o Int) Type() *Type {
1818

1919
type BigInt big.Int
2020

21-
var BigIntType = NewType("bigint")
21+
var BigIntType = NewType("bigint", "Holds large integers")
2222

2323
// Type of this BigInt object
2424
func (o *BigInt) Type() *Type {

py/internal.go

+16
Original file line numberDiff line numberDiff line change
@@ -59,3 +59,19 @@ func Not(a Object) Object {
5959
}
6060
panic("bool() didn't return True or False")
6161
}
62+
63+
// Calls function fnObj with args and kwargs in a new vm (or directly
64+
// if Go code)
65+
//
66+
// kwargs should be nil if not required
67+
//
68+
// fnObj must be a callable type such as *py.Method or *py.Function
69+
//
70+
// The result is returned
71+
func Call(fn Object, args Tuple, kwargs StringDict) Object {
72+
if I, ok := fn.(I__call__); ok {
73+
return I.M__call__(args, kwargs)
74+
}
75+
// FIXME should be TypeError
76+
panic(fmt.Sprintf("TypeError: '%s' object is not callable", fn.Type().Name))
77+
}

0 commit comments

Comments
 (0)