123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673 |
- /**
- * @constructor
- * @param {Array.<Object>=} L
- * @param {boolean=} canSuspend (defaults to true in this case, as list() is used directly from Python)
- * @extends Sk.builtin.object
- */
- Sk.builtin.list = function (L, canSuspend) {
- var v, it, thisList;
- if (this instanceof Sk.builtin.list) {
- canSuspend = canSuspend || false;
- } else {
- // Default to true in this case, because 'list' gets called directly from Python
- return new Sk.builtin.list(L, canSuspend || true);
- }
- this.__class__ = Sk.builtin.list;
- if (L === undefined) {
- v = [];
- } else if (Object.prototype.toString.apply(L) === "[object Array]") {
- v = L;
- } else if (Sk.builtin.checkIterable(L)) {
- v = [];
- it = Sk.abstr.iter(L);
- thisList = this;
- return (function next(i) {
- while(true) {
- if (i instanceof Sk.misceval.Suspension) {
- return new Sk.misceval.Suspension(next, i);
- } else if (i === undefined) {
- // done!
- thisList.v = v;
- return thisList;
- } else {
- v.push(i);
- i = it.tp$iternext(canSuspend);
- }
- }
- })(it.tp$iternext(canSuspend));
- } else {
- throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(L)+ "' " +"object is not iterable");
- }
- this["v"] = this.v = v;
- return this;
- };
- Sk.abstr.setUpInheritance("list", Sk.builtin.list, Sk.builtin.seqtype);
- Sk.abstr.markUnhashable(Sk.builtin.list);
- Sk.builtin.list.prototype.list_concat_ = function (other) {
- // other not a list
- var i;
- var ret;
- if (!other.__class__ || other.__class__ != Sk.builtin.list) {
- throw new Sk.builtin.TypeError("can only concatenate list to list");
- }
- ret = this.v.slice();
- for (i = 0; i < other.v.length; ++i) {
- ret.push(other.v[i]);
- }
- return new Sk.builtin.list(ret, false);
- };
- Sk.builtin.list.prototype.list_extend_ = function (other) {
- var it, i;
- var newb;
- if (!Sk.builtin.checkIterable(other)) {
- throw new Sk.builtin.TypeError("'" + Sk.abstr.typeName(other) +
- "' object is not iterable");
- }
- if (this == other) {
- // Handle extending list with itself
- newb = [];
- for (it = Sk.abstr.iter(other), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
- newb.push(i);
- }
- // Concatenate
- this.v.push.apply(this.v, newb);
- } else {
- for (it = Sk.abstr.iter(other), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
- this.v.push(i);
- }
- }
- return this;
- };
- Sk.builtin.list.prototype.list_del_item_ = function (i) {
- i = Sk.builtin.asnum$(i);
- if (i < 0 || i >= this.v.length) {
- throw new Sk.builtin.IndexError("list assignment index out of range");
- }
- this.list_del_slice_(i, i + 1);
- };
- Sk.builtin.list.prototype.list_del_slice_ = function (ilow, ihigh) {
- var args;
- ilow = Sk.builtin.asnum$(ilow);
- ihigh = Sk.builtin.asnum$(ihigh);
- args = [];
- args.unshift(ihigh - ilow);
- args.unshift(ilow);
- this.v.splice.apply(this.v, args);
- };
- Sk.builtin.list.prototype.list_ass_item_ = function (i, v) {
- i = Sk.builtin.asnum$(i);
- if (i < 0 || i >= this.v.length) {
- throw new Sk.builtin.IndexError("list assignment index out of range");
- }
- this.v[i] = v;
- };
- Sk.builtin.list.prototype.list_ass_slice_ = function (ilow, ihigh, v) {
- var args;
- ilow = Sk.builtin.asnum$(ilow);
- ihigh = Sk.builtin.asnum$(ihigh);
- if (Sk.builtin.checkIterable(v)) {
- args = new Sk.builtin.list(v, false).v.slice(0);
- } else {
- throw new Sk.builtin.TypeError("can only assign an iterable");
- }
- args.unshift(ihigh - ilow);
- args.unshift(ilow);
- this.v.splice.apply(this.v, args);
- };
- Sk.builtin.list.prototype["$r"] = function () {
- var it, i;
- var ret = [];
- for (it = Sk.abstr.iter(this), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
- if(i === this) {
- ret.push("[...]");
- } else {
- ret.push(Sk.misceval.objectRepr(i).v);
- }
- }
- return new Sk.builtin.str("[" + ret.join(", ") + "]");
- };
- Sk.builtin.list.prototype.tp$richcompare = function (w, op) {
- // todo; can't figure out where cpy handles this silly case (test/run/t96.py)
- // perhaps by trapping a stack overflow? otherwise i'm not sure for more
- // complicated cases. bleh
- //
- // if the comparison allows for equality then short-circuit it here
- var k;
- var i;
- var wl;
- var vl;
- var v;
- if (this === w && Sk.misceval.opAllowsEquality(op)) {
- return true;
- }
- // w not a list
- if (!w.__class__ || w.__class__ != Sk.builtin.list) {
- // shortcuts for eq/not
- if (op === "Eq") {
- return false;
- }
- if (op === "NotEq") {
- return true;
- }
- // todo; other types should have an arbitrary order
- return false;
- }
- v = this.v;
- w = w.v;
- vl = v.length;
- wl = w.length;
- for (i = 0; i < vl && i < wl; ++i) {
- k = Sk.misceval.richCompareBool(v[i], w[i], "Eq");
- if (!k) {
- break;
- }
- }
- if (i >= vl || i >= wl) {
- // no more items to compare, compare sizes
- switch (op) {
- case "Lt":
- return vl < wl;
- case "LtE":
- return vl <= wl;
- case "Eq":
- return vl === wl;
- case "NotEq":
- return vl !== wl;
- case "Gt":
- return vl > wl;
- case "GtE":
- return vl >= wl;
- default:
- goog.asserts.fail();
- }
- }
- // we have an item that's different
- // shortcuts for eq/not
- if (op === "Eq") {
- return false;
- }
- if (op === "NotEq") {
- return true;
- }
- // or, compare the differing element using the proper operator
- return Sk.misceval.richCompareBool(v[i], w[i], op);
- };
- Sk.builtin.list.prototype.__iter__ = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("__iter__", arguments, 0, 0, true, false);
- return new Sk.builtin.list_iter_(self);
- });
- Sk.builtin.list.prototype.tp$iter = function () {
- return new Sk.builtin.list_iter_(this);
- };
- Sk.builtin.list.prototype.sq$length = function () {
- return this.v.length;
- };
- Sk.builtin.list.prototype.sq$concat = Sk.builtin.list.prototype.list_concat_;
- Sk.builtin.list.prototype.nb$add = Sk.builtin.list.prototype.list_concat_;
- Sk.builtin.list.prototype.nb$inplace_add = Sk.builtin.list.prototype.list_extend_;
- Sk.builtin.list.prototype.sq$repeat = function (n) {
- var j;
- var i;
- var ret;
- if (!Sk.misceval.isIndex(n)) {
- throw new Sk.builtin.TypeError("can't multiply sequence by non-int of type '" + Sk.abstr.typeName(n) + "'");
- }
- n = Sk.misceval.asIndex(n);
- ret = [];
- for (i = 0; i < n; ++i) {
- for (j = 0; j < this.v.length; ++j) {
- ret.push(this.v[j]);
- }
- }
- return new Sk.builtin.list(ret, false);
- };
- Sk.builtin.list.prototype.nb$multiply = Sk.builtin.list.prototype.sq$repeat;
- Sk.builtin.list.prototype.nb$inplace_multiply = function(n) {
- var j;
- var i;
- var len;
- if (!Sk.misceval.isIndex(n)) {
- throw new Sk.builtin.TypeError("can't multiply sequence by non-int of type '" + Sk.abstr.typeName(n) + "'");
- }
- // works on list itself --> inplace
- n = Sk.misceval.asIndex(n);
- len = this.v.length;
- for (i = 1; i < n; ++i) {
- for (j = 0; j < len; ++j) {
- this.v.push(this.v[j]);
- }
- }
- return this;
- };
- /*
- Sk.builtin.list.prototype.sq$item = list_item;
- Sk.builtin.list.prototype.sq$slice = list_slice;
- */
- Sk.builtin.list.prototype.sq$ass_item = Sk.builtin.list.prototype.list_ass_item_;
- Sk.builtin.list.prototype.sq$del_item = Sk.builtin.list.prototype.list_del_item_;
- Sk.builtin.list.prototype.sq$ass_slice = Sk.builtin.list.prototype.list_ass_slice_;
- Sk.builtin.list.prototype.sq$del_slice = Sk.builtin.list.prototype.list_del_slice_;
- Sk.builtin.list.prototype.sq$contains = function (item) {
- var it, i;
- for (it = this.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
- if (Sk.misceval.richCompareBool(i, item, "Eq")) {
- return true;
- }
- }
- return false;
- };
- /*
- Sk.builtin.list.prototype.sq$inplace_concat = list_inplace_concat;
- Sk.builtin.list.prototype.sq$inplace_repeat = list_inplace_repeat;
- */
- Sk.builtin.list.prototype.list_subscript_ = function (index) {
- var ret;
- var i;
- if (Sk.misceval.isIndex(index)) {
- i = Sk.misceval.asIndex(index);
- if (i !== undefined) {
- if (i < 0) {
- i = this.v.length + i;
- }
- if (i < 0 || i >= this.v.length) {
- throw new Sk.builtin.IndexError("list index out of range");
- }
- return this.v[i];
- }
- } else if (index instanceof Sk.builtin.slice) {
- ret = [];
- index.sssiter$(this, function (i, wrt) {
- ret.push(wrt.v[i]);
- });
- return new Sk.builtin.list(ret, false);
- }
- throw new Sk.builtin.TypeError("list indices must be integers, not " + Sk.abstr.typeName(index));
- };
- Sk.builtin.list.prototype.list_ass_subscript_ = function (index, value) {
- var i;
- var j;
- var tosub;
- var indices;
- if (Sk.misceval.isIndex(index)) {
- i = Sk.misceval.asIndex(index);
- if (i !== undefined) {
- if (i < 0) {
- i = this.v.length + i;
- }
- this.list_ass_item_(i, value);
- return;
- }
- } else if (index instanceof Sk.builtin.slice) {
- indices = index.slice_indices_(this.v.length);
- if (indices[2] === 1) {
- this.list_ass_slice_(indices[0], indices[1], value);
- } else {
- tosub = [];
- index.sssiter$(this, function (i, wrt) {
- tosub.push(i);
- });
- j = 0;
- if (tosub.length !== value.v.length) {
- throw new Sk.builtin.ValueError("attempt to assign sequence of size " + value.v.length + " to extended slice of size " + tosub.length);
- }
- for (i = 0; i < tosub.length; ++i) {
- this.v.splice(tosub[i], 1, value.v[j]);
- j += 1;
- }
- }
- return;
- }
- throw new Sk.builtin.TypeError("list indices must be integers, not " + Sk.abstr.typeName(index));
- };
- Sk.builtin.list.prototype.list_del_subscript_ = function (index) {
- var offdir;
- var dec;
- var self;
- var indices;
- var i;
- if (Sk.misceval.isIndex(index)) {
- i = Sk.misceval.asIndex(index);
- if (i !== undefined) {
- if (i < 0) {
- i = this.v.length + i;
- }
- this.list_del_item_(i);
- return;
- }
- } else if (index instanceof Sk.builtin.slice) {
- indices = index.slice_indices_(this.v.length);
- if (indices[2] === 1) {
- this.list_del_slice_(indices[0], indices[1]);
- } else {
- self = this;
- dec = 0; // offset of removal for next index (because we'll have removed, but the iterator is giving orig indices)
- offdir = indices[2] > 0 ? 1 : 0;
- index.sssiter$(this, function (i, wrt) {
- self.v.splice(i - dec, 1);
- dec += offdir;
- });
- }
- return;
- }
- throw new Sk.builtin.TypeError("list indices must be integers, not " + typeof index);
- };
- Sk.builtin.list.prototype.mp$subscript = Sk.builtin.list.prototype.list_subscript_;
- Sk.builtin.list.prototype.mp$ass_subscript = Sk.builtin.list.prototype.list_ass_subscript_;
- Sk.builtin.list.prototype.mp$del_subscript = Sk.builtin.list.prototype.list_del_subscript_;
- Sk.builtin.list.prototype.__getitem__ = new Sk.builtin.func(function (self, index) {
- return Sk.builtin.list.prototype.list_subscript_.call(self, index);
- });
- /**
- * @param {?=} self
- * @param {?=} cmp optional
- * @param {?=} key optional
- * @param {?=} reverse optional
- */
- Sk.builtin.list.prototype.list_sort_ = function (self, cmp, key, reverse) {
- var mucked;
- var j;
- var keyvalue;
- var item;
- var i;
- var zero;
- var timsort;
- var has_key = key !== undefined && key !== null;
- var has_cmp = cmp !== undefined && cmp !== null;
- var rev;
- if (reverse === undefined) {
- rev = false;
- } else if (reverse === Sk.builtin.none.none$) {
- throw new Sk.builtin.TypeError("an integer is required");
- } else {
- rev = Sk.misceval.isTrue(reverse);
- }
- timsort = new Sk.builtin.timSort(self);
- self.v = [];
- zero = new Sk.builtin.int_(0);
- if (has_key) {
- if (has_cmp) {
- timsort.lt = function (a, b) {
- var res = Sk.misceval.callsim(cmp, a[0], b[0]);
- return Sk.misceval.richCompareBool(res, zero, "Lt");
- };
- } else {
- timsort.lt = function (a, b) {
- return Sk.misceval.richCompareBool(a[0], b[0], "Lt");
- };
- }
- for (i = 0; i < timsort.listlength; i++) {
- item = timsort.list.v[i];
- keyvalue = Sk.misceval.callsim(key, item);
- timsort.list.v[i] = [keyvalue, item];
- }
- } else if (has_cmp) {
- timsort.lt = function (a, b) {
- var res = Sk.misceval.callsim(cmp, a, b);
- return Sk.misceval.richCompareBool(res, zero, "Lt");
- };
- }
- if (rev) {
- timsort.list.list_reverse_(timsort.list);
- }
- timsort.sort();
- if (rev) {
- timsort.list.list_reverse_(timsort.list);
- }
- if (has_key) {
- for (j = 0; j < timsort.listlength; j++) {
- item = timsort.list.v[j][1];
- timsort.list.v[j] = item;
- }
- }
- mucked = self.sq$length() > 0;
- self.v = timsort.list.v;
- if (mucked) {
- throw new Sk.builtin.OperationError("list modified during sort");
- }
- return Sk.builtin.none.none$;
- };
- /**
- * @param {Sk.builtin.list=} self optional
- **/
- Sk.builtin.list.prototype.list_reverse_ = function (self) {
- var i;
- var newarr;
- var old;
- var len;
- Sk.builtin.pyCheckArgs("reverse", arguments, 1, 1);
- len = self.v.length;
- old = self.v;
- newarr = [];
- for (i = len - 1; i > -1; --i) {
- newarr.push(old[i]);
- }
- self["v"] = newarr;
- return Sk.builtin.none.none$;
- };
- //Sk.builtin.list.prototype.__reversed__ = todo;
- Sk.builtin.list.prototype["append"] = new Sk.builtin.func(function (self, item) {
- Sk.builtin.pyCheckArgs("append", arguments, 2, 2);
- self.v.push(item);
- return Sk.builtin.none.none$;
- });
- Sk.builtin.list.prototype["insert"] = new Sk.builtin.func(function (self, i, x) {
- Sk.builtin.pyCheckArgs("insert", arguments, 3, 3);
- if (!Sk.builtin.checkNumber(i)) {
- throw new Sk.builtin.TypeError("an integer is required");
- }
- i = Sk.builtin.asnum$(i);
- if (i < 0) {
- i = i + self.v.length;
- }
- if (i < 0) {
- i = 0;
- } else if (i > self.v.length) {
- i = self.v.length;
- }
- self.v.splice(i, 0, x);
- return Sk.builtin.none.none$;
- });
- Sk.builtin.list.prototype["extend"] = new Sk.builtin.func(function (self, b) {
- Sk.builtin.pyCheckArgs("extend", arguments, 2, 2);
- self.list_extend_(b);
- return Sk.builtin.none.none$;
- });
- Sk.builtin.list.prototype["pop"] = new Sk.builtin.func(function (self, i) {
- var ret;
- Sk.builtin.pyCheckArgs("pop", arguments, 1, 2);
- if (i === undefined) {
- i = self.v.length - 1;
- }
- if (!Sk.builtin.checkNumber(i)) {
- throw new Sk.builtin.TypeError("an integer is required");
- }
- i = Sk.builtin.asnum$(i);
- if (i < 0) {
- i = i + self.v.length;
- }
- if ((i < 0) || (i >= self.v.length)) {
- throw new Sk.builtin.IndexError("pop index out of range");
- }
- ret = self.v[i];
- self.v.splice(i, 1);
- return ret;
- });
- Sk.builtin.list.prototype["remove"] = new Sk.builtin.func(function (self, item) {
- var idx;
- Sk.builtin.pyCheckArgs("remove", arguments, 2, 2);
- idx = Sk.builtin.list.prototype["index"].func_code(self, item);
- self.v.splice(Sk.builtin.asnum$(idx), 1);
- return Sk.builtin.none.none$;
- });
- Sk.builtin.list.prototype["index"] = new Sk.builtin.func(function (self, item, start, stop) {
- var i;
- var obj;
- var len;
- Sk.builtin.pyCheckArgs("index", arguments, 2, 4);
- if (start !== undefined && !Sk.builtin.checkInt(start)) {
- throw new Sk.builtin.TypeError("slice indices must be integers");
- }
- if (stop !== undefined && !Sk.builtin.checkInt(stop)) {
- throw new Sk.builtin.TypeError("slice indices must be integers");
- }
- len = self.v.length;
- obj = self.v;
- start = (start === undefined) ? 0 : start.v;
- if (start < 0) {
- start = ((start + len) >= 0) ? start + len : 0;
- }
- stop = (stop === undefined) ? len : stop.v;
- if (stop < 0) {
- stop = ((stop + len) >= 0) ? stop + len : 0;
- }
- for (i = start; i < stop; ++i) {
- if (Sk.misceval.richCompareBool(obj[i], item, "Eq")) {
- return new Sk.builtin.int_(i);
- }
- }
- throw new Sk.builtin.ValueError("list.index(x): x not in list");
- });
- Sk.builtin.list.prototype["count"] = new Sk.builtin.func(function (self, item) {
- var i;
- var count;
- var obj;
- var len;
- Sk.builtin.pyCheckArgs("count", arguments, 2, 2);
- len = self.v.length;
- obj = self.v;
- count = 0;
- for (i = 0; i < len; ++i) {
- if (Sk.misceval.richCompareBool(obj[i], item, "Eq")) {
- count += 1;
- }
- }
- return new Sk.builtin.int_(count);
- });
- Sk.builtin.list.prototype["reverse"] = new Sk.builtin.func(Sk.builtin.list.prototype.list_reverse_);
- Sk.builtin.list.prototype["sort"] = new Sk.builtin.func(Sk.builtin.list.prototype.list_sort_);
- // Make sure that key/value variations of lst.sort() work
- // See issue 45 on github as to possible alternate approaches to this and
- // why this was chosen - csev
- Sk.builtin.list.prototype["sort"].func_code["co_varnames"] = ["__self__", "cmp", "key", "reverse"];
- goog.exportSymbol("Sk.builtin.list", Sk.builtin.list);
- /**
- * @constructor
- * @param {Object} lst
- */
- Sk.builtin.list_iter_ = function (lst) {
- if (!(this instanceof Sk.builtin.list_iter_)) {
- return new Sk.builtin.list_iter_(lst);
- }
- this.$index = 0;
- this.lst = lst.v.slice();
- this.sq$length = this.lst.length;
- this.tp$iter = this;
- this.tp$iternext = function () {
- if (this.$index >= this.sq$length) {
- return undefined;
- }
- return this.lst[this.$index++];
- };
- this.$r = function () {
- return new Sk.builtin.str("listiterator");
- };
- return this;
- };
- Sk.abstr.setUpInheritance("listiterator", Sk.builtin.list_iter_, Sk.builtin.object);
- Sk.builtin.list_iter_.prototype.__class__ = Sk.builtin.list_iter_;
- Sk.builtin.list_iter_.prototype.__iter__ = new Sk.builtin.func(function (self) {
- return self;
- });
- Sk.builtin.list_iter_.prototype["next"] = new Sk.builtin.func(function (self) {
- var ret = self.tp$iternext();
- if (ret === undefined) {
- throw new Sk.builtin.StopIteration();
- }
- return ret;
- });
|