Skip to content

Commit 3f14f3d

Browse files
committed
py, builtin, vm: make str() and repr() and implement some __str__ and __repr__
* builtin: implement repr * buitin and py/str: make str() work * py: str, int, bigint: __str__ and __repr__ for * py: Internal Str, Repr methods * vm: Make REPL use Repr for printing
1 parent de8c04a commit 3f14f3d

File tree

12 files changed

+329
-32
lines changed

12 files changed

+329
-32
lines changed

builtin/builtin.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ func init() {
5252
py.MustNewMethod("ord", builtin_ord, 0, ord_doc),
5353
py.MustNewMethod("pow", builtin_pow, 0, pow_doc),
5454
py.MustNewMethod("print", builtin_print, 0, print_doc),
55-
// py.MustNewMethod("repr", builtin_repr, 0, repr_doc),
55+
py.MustNewMethod("repr", builtin_repr, 0, repr_doc),
5656
py.MustNewMethod("round", builtin_round, 0, round_doc),
5757
py.MustNewMethod("setattr", builtin_setattr, 0, setattr_doc),
5858
// py.MustNewMethod("sorted", builtin_sorted, 0, sorted_doc),
@@ -194,6 +194,15 @@ func builtin_print(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Obje
194194
return py.None, nil
195195
}
196196

197+
const repr_doc = `repr(object) -> string
198+
199+
Return the canonical string representation of the object.
200+
For most object types, eval(repr(object)) == object.`
201+
202+
func builtin_repr(self py.Object, obj py.Object) (py.Object, error) {
203+
return py.Repr(obj)
204+
}
205+
197206
const pow_doc = `pow(x, y[, z]) -> number
198207
199208
With two arguments, equivalent to x**y. With three arguments,

builtin/tests/builtin.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ def gen2():
111111

112112
doc="pow"
113113
assert pow(2, 10) == 1024
114-
# FIXME assert pow(2, 10, 17) == 4
114+
assert pow(2, 10, 17) == 4
115+
116+
doc="repr"
117+
assert repr(5) == "5"
118+
assert repr("hello") == "'hello'"
115119

116120
doc="print"
117121
# FIXME - need io redirection to test

notes.txt

Lines changed: 90 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,110 @@ Code Quality
44
* errchk ./...
55
* go vet ./...
66

7-
Limitations
8-
===========
7+
IDEA replace all .(cast) with CheckExactString or whatever python calls it...
8+
9+
Then can use CheckString later...
10+
11+
Limitations & Missing parts
12+
===========================
913
* string keys only in dictionaries
1014
* intermediate fix - stop it panicing!
1115
* line numbers missing in SyntaxErrors
1216
* \N{...} escapes not implemented
1317
* Interactive interpreter does single lines only
1418
* compile(..., "single") not working
1519
* lots of builtins still to implement
20+
* FIXME eq && ne should throw an error for a type which doesn' have eq implemented
21+
* repr/str
22+
* subclassing built in types - how? Need to make sure we have called the appropriate method everywhere rather than just .(String)
23+
* FIXME how do mapping types work?
1624

17-
Todo
18-
====
25+
Type ideas
26+
==========
1927

20-
FIXME move the whole of Vm into Frame! Perhaps decode the extended args inline.
28+
* Embed a zero sized struct with default implementations of all the methods to avoid interface bloat
29+
* would have a pointer to the start of the object so could do comparisons
30+
* however don't know anything about the object - can't call Type() for instance
31+
* except for String/Int/Bool/Tuple/Float/Bytes and possibly some others...
32+
* can embed this default interface whether we do fat interfaces or not...
33+
* can have heirachies of embedding
2134

22-
Speedup
2335
* Make Object a fat interface so it defines all the M__method__ or at least all the common ones
24-
* Embed a zero sized struct with default implementations of all the methods to avoid interface bloat
25-
* except for String/Int/Bool/Tuple/Float/Bytes and possibly some others...
36+
* would make the M__call__ quicker than needing a type assertion
2637
* Or Make the methods be pointers in *Type more like python
27-
* Function pointers would have to be func(a Object) (Object, error) which would mean a type assertion :-(
38+
* Closer to the way python does it and would be faster than type assertion
39+
* Function pointers would have to be func(a Object) (Object,
40+
error) which would mean a type assertion which we are trying to
41+
avoid :-(
2842
* An interface is the go way of doing this
2943

44+
What methods are a default implementation useful for?
45+
__eq__
46+
__ne__
47+
__repr__
48+
__str__
49+
__lt__ __add__ etc - could return NotImplemented
50+
__hash__ - based on pointer?
51+
52+
Minimum set of methods / attributes (eg on None)
53+
54+
Attributes
55+
56+
__class__
57+
__doc__
58+
59+
Methods
60+
61+
__bool__
62+
__delattr__
63+
__dir__
64+
__format__
65+
__getattribute__
66+
__hash__
67+
__init__
68+
__new__
69+
__reduce__ - pickle protocol - missing!
70+
__reduce_ex__ - pickle protocol - missing!
71+
__repr__
72+
__setattr__
73+
__sizeof__ - missing from py.go
74+
__str__
75+
__subclasshook__ - missing from py.go
76+
77+
Comparison
78+
79+
__eq__
80+
__ge__
81+
__gt__
82+
__le__
83+
__lt__
84+
__ne__
85+
86+
87+
genpy
88+
=====
89+
90+
Code automation to help with the boilerplate of making types and modules
91+
92+
* For modules
93+
* instrospect code
94+
* make module table
95+
* fill in arguments
96+
* fill in docstr (from comments)
97+
* Module methods should be exportable with capital letter
98+
99+
* For a type
100+
* create getters/setters from struct comments
101+
* create default implementations
102+
* independent of use 0 sized embedded struct idea
103+
104+
105+
Todo
106+
====
107+
108+
FIXME move the whole of Vm into Frame! Perhaps decode the extended args inline.
109+
110+
Speedup
30111

31112
* Getting rid of panic/defer error handling
32113

@@ -37,7 +118,6 @@ After 3278 pystone/s
37118
After compile debug out with a constant 9293 pystones/s + 180%
38119
Keep locals 9789 local 5% improvement
39120

40-
41121
Still to do
42122
* think about exception handling - do nested tracebacks work?
43123
* write a test for it!
@@ -57,12 +137,6 @@ CAN now inline the do_XXX functions into the EvalFrame which will probably speed
57137
* "select" - no idea how to implement!
58138
* "mutex"
59139

60-
* Write gengpy tool to
61-
* instrospect code
62-
* fill in module table
63-
* fill in arguments
64-
* fill in docstr (from comments)
65-
66140
FIXME need to be able to tell classes an instances apart!
67141

68142
Put C modules in sub directory
@@ -122,15 +196,6 @@ Exceptions
122196

123197
panic/recover only within single modules (like compiler/parser)
124198

125-
Missing parts
126-
=============
127-
* repr/str
128-
* subclassing built in types
129-
* integers > 64 bit
130-
* make py.Int be a wrapper for int
131-
* make it promote to py.BigInt
132-
* StringDict vs Dict
133-
134199
Polymorphism
135200
============
136201

py/bigint.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package py
44

55
import (
6+
"fmt"
67
"math"
78
"math/big"
89
)
@@ -16,6 +17,14 @@ func (o *BigInt) Type() *Type {
1617
return BigIntType
1718
}
1819

20+
func (a *BigInt) M__str__() (Object, error) {
21+
return String(fmt.Sprintf("%d", (*big.Int)(a))), nil
22+
}
23+
24+
func (a *BigInt) M__repr__() (Object, error) {
25+
return a.M__str__()
26+
}
27+
1928
// Some common BigInts
2029
var (
2130
bigInt0 = (*BigInt)(big.NewInt(0))

py/dict.go

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,20 @@
55

66
package py
77

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)")
8+
const dictDoc = `dict() -> new empty dictionary
9+
dict(mapping) -> new dictionary initialized from a mapping object's
10+
(key, value) pairs
11+
dict(iterable) -> new dictionary initialized as if via:
12+
d = {}
13+
for k, v in iterable:
14+
d[k] = v
15+
dict(**kwargs) -> new dictionary initialized with the name=value pairs
16+
in the keyword argument list. For example: dict(one=1, two=2)`
917

10-
var DictType = 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)")
18+
var (
19+
StringDictType = NewType("dict", dictDoc)
20+
DictType = NewType("dict", dictDoc)
21+
)
1122

1223
// String to object dictionary
1324
//

py/float.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package py
44

55
import (
6+
"fmt"
67
"math"
78
"math/big"
89
"strconv"
@@ -41,6 +42,14 @@ func FloatNew(metatype *Type, args Tuple, kwargs StringDict) (Object, error) {
4142
return MakeFloat(xObj)
4243
}
4344

45+
func (a Float) M__str__() (Object, error) {
46+
return String(fmt.Sprintf("%g", a)), nil
47+
}
48+
49+
func (a Float) M__repr__() (Object, error) {
50+
return a.M__str__()
51+
}
52+
4453
// FloatFromString turns a string into a Float
4554
func FloatFromString(str string) (Object, error) {
4655
f, err := strconv.ParseFloat(str, 64)

py/int.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
package py
44

55
import (
6+
"fmt"
67
"math"
78
"math/big"
89
"strconv"
@@ -174,6 +175,14 @@ func (x Int) GoInt() (int, error) {
174175
return int(r), nil
175176
}
176177

178+
func (a Int) M__str__() (Object, error) {
179+
return String(fmt.Sprintf("%d", a)), nil
180+
}
181+
182+
func (a Int) M__repr__() (Object, error) {
183+
return a.M__str__()
184+
}
185+
177186
// Arithmetic
178187

179188
// Errors

py/internal.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
package py
66

7+
import "fmt"
8+
79
// AttributeName converts an Object to a string, raising a TypeError
810
// if it wasn't a String
911
func AttributeName(keyObj Object) (string, error) {
@@ -321,3 +323,55 @@ func DeleteAttr(self Object, keyObj Object) error {
321323
}
322324
return DeleteAttrString(self, key)
323325
}
326+
327+
// Calls __str__ on the object
328+
//
329+
// If no method was found, returns ok as false
330+
func str(self Object) (res Object, ok bool, err error) {
331+
if _, ok = self.(String); ok {
332+
return self, true, nil
333+
}
334+
if I, ok := self.(I__str__); ok {
335+
res, err = I.M__str__()
336+
return res, true, err
337+
} else if res, ok, err := TypeCall0(self, "__str__"); ok {
338+
return res, true, err
339+
}
340+
return nil, false, nil
341+
}
342+
343+
// Calls __str__ on the object
344+
func Str(self Object) (Object, error) {
345+
res, ok, err := str(self)
346+
if err != nil {
347+
return nil, err
348+
}
349+
if !ok {
350+
return nil, ExceptionNewf(TypeError, "object of type '%s' has no __str__()", self.Type().Name)
351+
}
352+
return res, err
353+
}
354+
355+
// Calls __repr__ on the object or returns a sensible default
356+
func Repr(self Object) (Object, error) {
357+
if I, ok := self.(I__repr__); ok {
358+
return I.M__repr__()
359+
} else if res, ok, err := TypeCall0(self, "__repr__"); ok {
360+
return res, err
361+
}
362+
return String(fmt.Sprintf("<%s instance at %p>", self.Type().Name, self)), nil
363+
}
364+
365+
// Returns object as a string
366+
//
367+
// Calls __str__ then __repr__ on the object then makes something up
368+
func AsString(self Object) (Object, error) {
369+
res, ok, err := str(self)
370+
if err != nil {
371+
return nil, err
372+
}
373+
if ok {
374+
return res, err
375+
}
376+
return Repr(self)
377+
}

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