Skip to content

Commit 4c48b1f

Browse files
committed
First commit - work in progress only
0 parents  commit 4c48b1f

File tree

5 files changed

+1324
-0
lines changed

5 files changed

+1324
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
*~

marshal/marshal.go

Lines changed: 319 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,319 @@
1+
// Implement unmarshal and marshal
2+
package marshal
3+
4+
import (
5+
"encoding/binary"
6+
"errors"
7+
"github.com/ncw/gpython/py"
8+
"io"
9+
"strconv"
10+
"fmt"
11+
)
12+
13+
const (
14+
TYPE_NULL = '0'
15+
TYPE_NONE = 'N'
16+
TYPE_FALSE = 'F'
17+
TYPE_TRUE = 'T'
18+
TYPE_STOPITER = 'S'
19+
TYPE_ELLIPSIS = '.'
20+
TYPE_INT = 'i'
21+
TYPE_FLOAT = 'f'
22+
TYPE_BINARY_FLOAT = 'g'
23+
TYPE_COMPLEX = 'x'
24+
TYPE_BINARY_COMPLEX = 'y'
25+
TYPE_LONG = 'l'
26+
TYPE_STRING = 's'
27+
TYPE_INTERNED = 't'
28+
TYPE_REF = 'r'
29+
TYPE_TUPLE = '('
30+
TYPE_LIST = '['
31+
TYPE_DICT = '{'
32+
TYPE_CODE = 'c'
33+
TYPE_UNICODE = 'u'
34+
TYPE_UNKNOWN = '?'
35+
TYPE_SET = '<'
36+
TYPE_FROZENSET = '>'
37+
FLAG_REF = 0x80 // with a type, add obj to index
38+
SIZE32_MAX = 0x7FFFFFFF
39+
40+
// We assume that Python ints are stored internally in base some power of
41+
// 2**15; for the sake of portability we'll always read and write them in base
42+
// exactly 2**15.
43+
44+
PyLong_MARSHAL_SHIFT = 15
45+
PyLong_MARSHAL_BASE = (1 << PyLong_MARSHAL_SHIFT)
46+
PyLong_MARSHAL_MASK = (PyLong_MARSHAL_BASE - 1)
47+
)
48+
49+
// Reads an object from the input
50+
func ReadObject(r io.Reader) (obj py.Object, err error) {
51+
var code byte
52+
err = binary.Read(r, binary.LittleEndian, &code)
53+
if err != nil {
54+
return
55+
}
56+
57+
//flag := code & FLAG_REF
58+
Type := code &^ FLAG_REF
59+
60+
switch Type {
61+
case TYPE_NULL:
62+
// A null object
63+
return nil, nil
64+
case TYPE_NONE:
65+
// The Python None object
66+
return py.None, nil
67+
case TYPE_FALSE:
68+
// The python False object
69+
return py.False, nil
70+
case TYPE_TRUE:
71+
// The python True object
72+
return py.True, nil
73+
case TYPE_STOPITER:
74+
// The python StopIteration Exception
75+
return py.StopIteration, nil
76+
case TYPE_ELLIPSIS:
77+
// The python elipsis object
78+
return py.Elipsis, nil
79+
case TYPE_INT:
80+
// 4 bytes of signed integer
81+
var n int32
82+
err = binary.Read(r, binary.LittleEndian, &n)
83+
if err != nil {
84+
return n, nil
85+
}
86+
case TYPE_FLOAT:
87+
// Floating point number as a string
88+
var length uint8
89+
err = binary.Read(r, binary.LittleEndian, &length)
90+
if err != nil {
91+
return
92+
}
93+
buf := make([]byte, int(length))
94+
_, err = io.ReadFull(r, buf)
95+
if err != nil {
96+
return
97+
}
98+
var f float64
99+
f, err = strconv.ParseFloat(string(buf), 64)
100+
if err != nil {
101+
return
102+
}
103+
return f, nil
104+
case TYPE_BINARY_FLOAT:
105+
var f float64
106+
err = binary.Read(r, binary.LittleEndian, &f)
107+
if err != nil {
108+
return
109+
}
110+
return f, nil
111+
case TYPE_COMPLEX:
112+
// Complex number as a string
113+
// FIXME this is using Go conversion not Python conversion which may differ
114+
var length uint8
115+
err = binary.Read(r, binary.LittleEndian, &length)
116+
if err != nil {
117+
return
118+
}
119+
buf := make([]byte, int(length))
120+
_, err = io.ReadFull(r, buf)
121+
if err != nil {
122+
return
123+
}
124+
var c complex64
125+
// FIXME c, err = strconv.ParseComplex(string(buf), 64)
126+
if err != nil {
127+
return
128+
}
129+
return c, nil
130+
case TYPE_BINARY_COMPLEX:
131+
var c complex64
132+
err = binary.Read(r, binary.LittleEndian, &c)
133+
if err != nil {
134+
return
135+
}
136+
return c, nil
137+
case TYPE_LONG:
138+
var size int32
139+
err = binary.Read(r, binary.LittleEndian, &size)
140+
if err != nil {
141+
return
142+
}
143+
// FIXME negative := false
144+
if size < 0 {
145+
// FIXME negative = true
146+
size = -size
147+
}
148+
if size < 0 || size > SIZE32_MAX {
149+
return nil, errors.New("bad marshal data (long size out of range)")
150+
}
151+
// FIXME not sure what -ve size means!
152+
// Now read shorts which have 15 bits of the number in
153+
digits := make([]int16, size)
154+
err = binary.Read(r, binary.LittleEndian, &size)
155+
if err != nil {
156+
return
157+
}
158+
if digits[0] == 0 {
159+
// FIXME should be ValueError
160+
return nil, errors.New("bad marshal data (digit out of range in long)")
161+
}
162+
// FIXME actually convert into something...
163+
return digits, nil
164+
case TYPE_STRING, TYPE_INTERNED, TYPE_UNICODE:
165+
var size int32
166+
err = binary.Read(r, binary.LittleEndian, &size)
167+
if err != nil {
168+
return
169+
}
170+
if size < 0 || size > SIZE32_MAX {
171+
return nil, errors.New("bad marshal data (string size out of range)")
172+
}
173+
buf := make([]byte, int(size))
174+
_, err = io.ReadFull(r, buf)
175+
if err != nil {
176+
return
177+
}
178+
// FIXME do something different for unicode & interned?
179+
return string(buf), nil
180+
case TYPE_TUPLE, TYPE_LIST, TYPE_SET, TYPE_FROZENSET:
181+
var size int32
182+
err = binary.Read(r, binary.LittleEndian, &size)
183+
if err != nil {
184+
return
185+
}
186+
if size < 0 || size > SIZE32_MAX {
187+
return nil, errors.New("bad marshal data (tuple size out of range)")
188+
}
189+
tuple := make([]py.Object, int(size))
190+
for i := range tuple {
191+
tuple[i], err = ReadObject(r)
192+
if err != nil {
193+
return
194+
}
195+
}
196+
// FIXME differentiate the types TYPE_TUPLE, TYPE_LIST, TYPE_SET, TYPE_FROZENSET
197+
return tuple, nil
198+
case TYPE_DICT:
199+
dict := make(map[py.Object]py.Object)
200+
var key, value py.Object
201+
for {
202+
key, err = ReadObject(r)
203+
if err != nil {
204+
return
205+
}
206+
if key == nil {
207+
break
208+
}
209+
value, err = ReadObject(r)
210+
if err != nil {
211+
return
212+
}
213+
if value != nil {
214+
dict[key] = value
215+
}
216+
}
217+
return dict, nil
218+
case TYPE_REF:
219+
// Reference to something???
220+
var n int32
221+
err = binary.Read(r, binary.LittleEndian, &n)
222+
if err != nil {
223+
return
224+
}
225+
// FIXME
226+
case TYPE_CODE:
227+
var argcount int32
228+
var kwonlyargcount int32
229+
var nlocals int32
230+
var stacksize int32
231+
var flags int32
232+
var code py.Object
233+
var consts py.Object
234+
var names py.Object
235+
var varnames py.Object
236+
var freevars py.Object
237+
var cellvars py.Object
238+
var filename py.Object
239+
var name py.Object
240+
var firstlineno int32
241+
var lnotab py.Object
242+
243+
if err = binary.Read(r, binary.LittleEndian, &argcount); err != nil {
244+
return
245+
}
246+
if err = binary.Read(r, binary.LittleEndian, &kwonlyargcount); err != nil {
247+
return
248+
}
249+
if err = binary.Read(r, binary.LittleEndian, &nlocals); err != nil {
250+
return
251+
}
252+
if err = binary.Read(r, binary.LittleEndian, &stacksize); err != nil {
253+
return
254+
}
255+
if err = binary.Read(r, binary.LittleEndian, &flags); err != nil {
256+
return
257+
}
258+
if code, err = ReadObject(r); err != nil {
259+
return
260+
}
261+
if consts, err = ReadObject(r); err != nil {
262+
return
263+
}
264+
if names, err = ReadObject(r); err != nil {
265+
return
266+
}
267+
if varnames, err = ReadObject(r); err != nil {
268+
return
269+
}
270+
if freevars, err = ReadObject(r); err != nil {
271+
return
272+
}
273+
if cellvars, err = ReadObject(r); err != nil {
274+
return
275+
}
276+
if filename, err = ReadObject(r); err != nil {
277+
return
278+
}
279+
if name, err = ReadObject(r); err != nil {
280+
return
281+
}
282+
if err = binary.Read(r, binary.LittleEndian, &firstlineno); err != nil {
283+
return
284+
}
285+
if lnotab, err = ReadObject(r); err != nil {
286+
return
287+
}
288+
289+
fmt.Printf("argcount = %v\n", argcount)
290+
fmt.Printf("kwonlyargcount = %v\n", kwonlyargcount)
291+
fmt.Printf("nlocals = %v\n", nlocals)
292+
fmt.Printf("stacksize = %v\n", stacksize)
293+
fmt.Printf("flags = %v\n", flags)
294+
fmt.Printf("code = %v\n", code)
295+
fmt.Printf("consts = %v\n", consts)
296+
fmt.Printf("names = %v\n", names)
297+
fmt.Printf("varnames = %v\n", varnames)
298+
fmt.Printf("freevars = %v\n", freevars)
299+
fmt.Printf("cellvars = %v\n", cellvars)
300+
fmt.Printf("filename = %v\n", filename)
301+
fmt.Printf("name = %v\n", name)
302+
fmt.Printf("firstlineno = %v\n", firstlineno)
303+
fmt.Printf("lnotab = %v\n", lnotab)
304+
305+
/*
306+
v = (PyObject *) PyCode_New(
307+
argcount, kwonlyargcount,
308+
nlocals, stacksize, flags,
309+
code, consts, names, varnames,
310+
freevars, cellvars, filename, name,
311+
firstlineno, lnotab);
312+
*/
313+
return code, nil // FIXME
314+
default:
315+
return nil, errors.New("bad marshal data (unknown type code)")
316+
}
317+
318+
return
319+
}

py/py.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Python global definitions
2+
package py
3+
4+
// A python object
5+
type Object interface{}
6+
7+
// Some well known objects
8+
var (
9+
None, False, True, StopIteration, Elipsis Object
10+
)

0 commit comments

Comments
 (0)