Skip to content

Commit f7bc949

Browse files
committed
Make List mutable - type is now *List
1 parent ced6726 commit f7bc949

File tree

7 files changed

+111
-70
lines changed

7 files changed

+111
-70
lines changed

marshal/marshal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ func ReadObject(r io.Reader) (obj py.Object, err error) {
208208
case TYPE_TUPLE:
209209
return py.Tuple(tuple), nil
210210
case TYPE_LIST:
211-
return py.List(tuple), nil
211+
return py.NewListFromItems(tuple), nil
212212
}
213213

214214
set := make(py.Set, len(tuple))

notes.txt

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -43,23 +43,14 @@ Polymorphism
4343

4444
ok, res := obj.Type().Call0("__XXX__")
4545
ok, res := obj.Type().Call1("__XXX__", a)
46-
ok, res := obj.Type().Call2("__XXX__", b)
46+
ok, res := obj.Type().Call2("__XXX__", a, b)
4747
ok is method found
4848
res is valid if found (or maybe NotImplemented)
4949

5050
Call() looks up name in methods and if found calls it either C wise or py-wise
5151

5252
Calling C-wise is easy enough, but how to call py-wise?
5353

54-
Assuming we are being called from the VM we would like to use the
55-
same VM to execute it? Or could make a new one which seems a little
56-
expensive and what is going to happen to exceptions and unwinding
57-
the stack?
58-
59-
Looks like python makes a new vm with PyEval_EvalCode so will need
60-
to make sure we store the unwinding stack frame in the exception
61-
(which is what python does I think)
62-
6354
all together
6455

6556
var ok bool
@@ -77,16 +68,28 @@ ObjectType in *Type is probably redundant
7768
Todo
7869
====
7970

80-
* Closures
8171
* With statements
8272
* Import
73+
* Dict
74+
* Set
75+
* Tracebacks - need to update the traceback object when unwinding the stack - could include go traceback too
8376

8477
Difference between gpython and cpython
8578
======================================
8679

8780
Uses native types for some of the objects, eg String, Int, Tuple, StringDict
8881

89-
Does not support threading, so no thread state or thread local variables
82+
The immutable types String, Int are passed by value. Tuple is an
83+
[]Object which is a reference type as is StringDict which is a
84+
map[string]Object. Note that Tuples can't be appended to.
85+
86+
List is a struct with a []Object in it so append can mutate the list.
87+
88+
All other types are pointers to structures.
89+
90+
Does not support threading, so no thread state or thread local
91+
variables as the intention is to support go routines and channels via
92+
the threading module.
9093

9194
Attributes of built in types
9295
============================

py/code.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ type Code struct {
2626
Firstlineno int32 // first source line number
2727
Lnotab string // string (encoding addr<->lineno mapping) See Objects/lnotab_notes.txt for details.
2828

29-
Weakreflist List // to support weakrefs to code objects
29+
Weakreflist *List // to support weakrefs to code objects
3030
}
3131

3232
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.")

py/list.go

Lines changed: 66 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -5,50 +5,90 @@ package py
55
var ListType = NewType("list", "list() -> new empty list\nlist(iterable) -> new list initialized from iterable's items")
66

77
// FIXME lists are mutable so this should probably be struct { Tuple } then can use the sub methods on Tuple
8-
type List []Object
8+
type List struct {
9+
Items []Object
10+
}
911

1012
// Type of this List object
11-
func (o List) Type() *Type {
13+
func (o *List) Type() *Type {
1214
return ListType
1315
}
1416

15-
// Copy a list object
16-
func (l List) Copy() List {
17-
newL := make(List, len(l))
18-
for i := range l {
19-
newL[i] = l[i]
17+
// Make a new empty list
18+
func NewList() *List {
19+
return &List{}
20+
}
21+
22+
// Make a new empty list with given capacity
23+
func NewListWithCapacity(n int) *List {
24+
l := &List{}
25+
if n != 0 {
26+
l.Items = make([]Object, 0, n)
2027
}
21-
return newL
28+
return l
29+
}
30+
31+
// Make a list with n nil elements
32+
func NewListSized(n int) *List {
33+
l := &List{}
34+
if n != 0 {
35+
l.Items = make([]Object, n)
36+
}
37+
return l
38+
}
39+
40+
// Make a new list from an []Object
41+
//
42+
// The []Object is copied into the list
43+
func NewListFromItems(items []Object) *List {
44+
l := NewListSized(len(items))
45+
copy(l.Items, items)
46+
return l
47+
}
48+
49+
// Copy a list object
50+
func (l *List) Copy() *List {
51+
return NewListFromItems(l.Items)
52+
}
53+
54+
// Append an item
55+
func (l *List) Append(item Object) {
56+
l.Items = append(l.Items, item)
57+
}
58+
59+
// Extend the list with items
60+
func (l *List) Extend(items []Object) {
61+
l.Items = append(l.Items, items...)
2262
}
2363

24-
func (t List) M__len__() Object {
25-
return Int(len(t))
64+
func (l *List) M__len__() Object {
65+
return Int(len(l.Items))
2666
}
2767

28-
func (t List) M__bool__() Object {
29-
return NewBool(len(t) > 0)
68+
func (l *List) M__bool__() Object {
69+
return NewBool(len(l.Items) > 0)
3070
}
3171

32-
func (t List) M__iter__() Object {
33-
return NewIterator(t)
72+
func (l *List) M__iter__() Object {
73+
return NewIterator(l.Items)
3474
}
3575

36-
func (t List) M__getitem__(key Object) Object {
37-
i := IndexIntCheck(key, len(t))
38-
return t[i]
76+
func (l *List) M__getitem__(key Object) Object {
77+
i := IndexIntCheck(key, len(l.Items))
78+
return l.Items[i]
3979
}
4080

41-
func (t List) M__setitem__(key, value Object) Object {
42-
i := IndexIntCheck(key, len(t))
43-
t[i] = value
81+
func (l *List) M__setitem__(key, value Object) Object {
82+
i := IndexIntCheck(key, len(l.Items))
83+
l.Items[i] = value
4484
return None
4585
}
4686

4787
// Check interface is satisfied
48-
var _ I__len__ = List(nil)
49-
var _ I__bool__ = List(nil)
50-
var _ I__iter__ = List(nil)
51-
var _ I__getitem__ = List(nil)
52-
var _ I__setitem__ = List(nil)
88+
var _ I__len__ = (*List)(nil)
89+
var _ I__bool__ = (*List)(nil)
90+
var _ I__iter__ = (*List)(nil)
91+
var _ I__getitem__ = (*List)(nil)
92+
var _ I__setitem__ = (*List)(nil)
5393

54-
// var _ richComparison = List(nil)
94+
// var _ richComparison = (*List)(nil)

py/sequence.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,19 @@ func SequenceTuple(v Object) Tuple {
88
switch x := v.(type) {
99
case Tuple:
1010
return x
11-
case List:
12-
return Tuple(x.Copy())
11+
case *List:
12+
return Tuple(x.Items).Copy()
1313
}
1414
panic("SequenceTuple not fully implemented")
1515
}
1616

1717
// Converts a sequence object v into a List
18-
func SequenceList(v Object) List {
18+
func SequenceList(v Object) *List {
1919
// FIXME need to support iterable objects etc!
2020
switch x := v.(type) {
2121
case Tuple:
22-
return List(x).Copy()
23-
case List:
22+
return NewListFromItems(x)
23+
case *List:
2424
return x.Copy()
2525
}
2626
panic("SequenceList not fully implemented")

py/tuple.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ func (o Tuple) Type() *Type {
1414
// Copy a tuple object
1515
func (t Tuple) Copy() Tuple {
1616
newT := make(Tuple, len(t))
17-
for i := range t {
18-
newT[i] = t[i]
19-
}
17+
copy(newT, t)
2018
return newT
2119
}
2220
func (t Tuple) M__len__() Object {

py/type.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -536,9 +536,9 @@ func lookup_method(self Object, attr string) Object {
536536
// each class to all its successors in the linearization. See
537537
// the paper for definition of EPG.
538538

539-
func tail_contains(list List, whence int, o Object) bool {
540-
for j := whence + 1; j < len(list); j++ {
541-
if list[j] == o {
539+
func tail_contains(list *List, whence int, o Object) bool {
540+
for j := whence + 1; j < len(list.Items); j++ {
541+
if list.Items[j] == o {
542542
return true
543543
}
544544
}
@@ -557,13 +557,13 @@ func class_name(cls Object) string {
557557
return string(nameString)
558558
}
559559

560-
func check_duplicates(list List) {
560+
func check_duplicates(list *List) {
561561
// Let's use a quadratic time algorithm,
562562
// assuming that the bases lists is short.
563-
for i := range list {
564-
o := list[i]
565-
for j := i + 1; j < len(list); j++ {
566-
if list[j] == o {
563+
for i := range list.Items {
564+
o := list.Items[i]
565+
for j := i + 1; j < len(list.Items); j++ {
566+
if list.Items[j] == o {
567567
panic(ExceptionNewf(TypeError, "duplicate base class %s", class_name(o)))
568568
}
569569
}
@@ -577,7 +577,7 @@ func check_duplicates(list List) {
577577
// to be put next into the MRO. There is some conflict between the
578578
// order in which they should be put in the MRO, but it's hard to
579579
// diagnose what constraint can't be satisfied.
580-
func set_mro_error(to_merge List, remain []int) {
580+
func set_mro_error(to_merge *List, remain []int) {
581581
panic(ExceptionNewf(TypeError, "mro is wonky"))
582582
/* FIXME implement this!
583583
Py_ssize_t i, n, off, to_merge_size;
@@ -623,12 +623,12 @@ func set_mro_error(to_merge List, remain []int) {
623623
*/
624624
}
625625

626-
func pmerge(acc, to_merge List) {
626+
func pmerge(acc, to_merge *List) {
627627
// Py_ssize_t i, j, to_merge_size, empty_cnt;
628628
// int *remain;
629629
// int ok;
630630

631-
to_merge_size := len(to_merge)
631+
to_merge_size := len(to_merge.Items)
632632

633633
// remain stores an index into each sublist of to_merge.
634634
// remain[i] is the index of the next base in to_merge[i]
@@ -638,9 +638,9 @@ func pmerge(acc, to_merge List) {
638638
again:
639639
empty_cnt := 0
640640
for i := 0; i < to_merge_size; i++ {
641-
cur_list := to_merge[i].(List)
641+
cur_list := to_merge.Items[i].(*List)
642642

643-
if remain[i] >= len(cur_list) {
643+
if remain[i] >= len(cur_list.Items) {
644644
empty_cnt++
645645
continue
646646
}
@@ -651,17 +651,17 @@ again:
651651
// If not, choose the class which appears in the MRO
652652
// of the earliest direct superclass of the new class.
653653

654-
candidate := cur_list[remain[i]]
654+
candidate := cur_list.Items[remain[i]]
655655
for j := 0; j < to_merge_size; j++ {
656-
j_lst := to_merge[j].(List)
656+
j_lst := to_merge.Items[j].(*List)
657657
if tail_contains(j_lst, remain[j], candidate) {
658658
goto skip // continue outer loop
659659
}
660660
}
661-
acc = append(acc, candidate)
661+
acc.Append(candidate)
662662
for j := 0; j < to_merge_size; j++ {
663-
j_lst := to_merge[j].(List)
664-
if remain[j] < len(j_lst) && j_lst[remain[j]] == candidate {
663+
j_lst := to_merge.Items[j].(*List)
664+
if remain[j] < len(j_lst.Items) && j_lst.Items[remain[j]] == candidate {
665665
remain[j]++
666666
}
667667
}
@@ -695,22 +695,22 @@ func (t *Type) mro_implementation() Object {
695695

696696
bases := t.Bases
697697
n := len(bases)
698-
to_merge := make(List, n+1)
698+
to_merge := NewListSized(n + 1)
699699

700700
for i := range bases {
701701
base := bases[i].(*Type)
702702
parentMRO := SequenceList(base.Mro)
703-
to_merge[i] = parentMRO
703+
to_merge.Items[i] = parentMRO
704704
}
705705

706706
bases_aslist := SequenceList(bases)
707707

708708
// This is just a basic sanity check.
709709
check_duplicates(bases_aslist)
710710

711-
to_merge[n] = bases_aslist
711+
to_merge.Items[n] = bases_aslist
712712

713-
result := List{t}
713+
result := NewListFromItems([]Object{t})
714714

715715
pmerge(result, to_merge)
716716

0 commit comments

Comments
 (0)