| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601 |
- /**
- * @constructor
- * @param {Array.<Object>} L
- */
- Sk.builtin.dict = function dict (L) {
- var v;
- var it, k;
- var i;
- if (!(this instanceof Sk.builtin.dict)) {
- return new Sk.builtin.dict(L);
- }
- if (L === undefined) {
- L = [];
- }
- this.size = 0;
- this.buckets = {};
- if (Object.prototype.toString.apply(L) === "[object Array]") {
- // Handle dictionary literals
- for (i = 0; i < L.length; i += 2) {
- this.mp$ass_subscript(L[i], L[i + 1]);
- }
- } else if (L instanceof Sk.builtin.dict) {
- // Handle calls of type "dict(mapping)" from Python code
- for (it = Sk.abstr.iter(L), k = it.tp$iternext();
- k !== undefined;
- k = it.tp$iternext()) {
- v = L.mp$subscript(k);
- if (v === undefined) {
- //print(k, "had undefined v");
- v = null;
- }
- this.mp$ass_subscript(k, v);
- }
- } else if (Sk.builtin.checkIterable(L)) {
- // Handle calls of type "dict(iterable)" from Python code
- for (it = Sk.abstr.iter(L), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
- if (i.mp$subscript) {
- this.mp$ass_subscript(i.mp$subscript(0), i.mp$subscript(1));
- } else {
- throw new Sk.builtin.TypeError("element " + this.size + " is not a sequence");
- }
- }
- } else {
- throw new Sk.builtin.TypeError("object is not iterable");
- }
- this.__class__ = Sk.builtin.dict;
- return this;
- };
- Sk.abstr.setUpInheritance("dict", Sk.builtin.dict, Sk.builtin.object);
- Sk.abstr.markUnhashable(Sk.builtin.dict);
- var kf = Sk.builtin.hash;
- Sk.builtin.dict.prototype.key$lookup = function (bucket, key) {
- var item;
- var eq;
- var i;
- for (i = 0; i < bucket.items.length; i++) {
- item = bucket.items[i];
- eq = Sk.misceval.richCompareBool(item.lhs, key, "Eq");
- if (eq) {
- return item;
- }
- }
- return null;
- };
- Sk.builtin.dict.prototype.key$pop = function (bucket, key) {
- var item;
- var eq;
- var i;
- for (i = 0; i < bucket.items.length; i++) {
- item = bucket.items[i];
- eq = Sk.misceval.richCompareBool(item.lhs, key, "Eq");
- if (eq) {
- bucket.items.splice(i, 1);
- this.size -= 1;
- return item;
- }
- }
- return undefined;
- };
- // Perform dictionary lookup, either return value or undefined if key not in dictionary
- Sk.builtin.dict.prototype.mp$lookup = function (key) {
- var k = kf(key);
- var bucket = this.buckets[k.v];
- var item;
- // todo; does this need to go through mp$ma_lookup
- if (bucket !== undefined) {
- item = this.key$lookup(bucket, key);
- if (item) {
- return item.rhs;
- }
- }
- // Not found in dictionary
- return undefined;
- };
- Sk.builtin.dict.prototype.mp$subscript = function (key) {
- Sk.builtin.pyCheckArgs("[]", arguments, 1, 2, false, false);
- var s;
- var res = this.mp$lookup(key);
- if (res !== undefined) {
- // Found in dictionary
- return res;
- } else {
- // Not found in dictionary
- s = new Sk.builtin.str(key);
- throw new Sk.builtin.KeyError(s.v);
- }
- };
- Sk.builtin.dict.prototype.sq$contains = function (ob) {
- Sk.builtin.pyCheckArgs("__contains__()", arguments, 1, 1, false, false);
- var res = this.mp$lookup(ob);
- return (res !== undefined);
- };
- Sk.builtin.dict.prototype.mp$ass_subscript = function (key, w) {
- var k = kf(key);
- var bucket = this.buckets[k.v];
- var item;
- if (bucket === undefined) {
- // New bucket
- bucket = {$hash: k, items: [
- {lhs: key, rhs: w}
- ]};
- this.buckets[k.v] = bucket;
- this.size += 1;
- return;
- }
- item = this.key$lookup(bucket, key);
- if (item) {
- item.rhs = w;
- return;
- }
- // Not found in dictionary
- bucket.items.push({lhs: key, rhs: w});
- this.size += 1;
- };
- Sk.builtin.dict.prototype.mp$del_subscript = function (key) {
- Sk.builtin.pyCheckArgs("del", arguments, 1, 1, false, false);
- var k = kf(key);
- var bucket = this.buckets[k.v];
- var item;
- var s;
- // todo; does this need to go through mp$ma_lookup
- if (bucket !== undefined) {
- item = this.key$pop(bucket, key);
- if (item !== undefined) {
- return;
- }
- }
- // Not found in dictionary
- s = new Sk.builtin.str(key);
- throw new Sk.builtin.KeyError(s.v);
- };
- Sk.builtin.dict.prototype["$r"] = function () {
- var v;
- var iter, k;
- var ret = [];
- for (iter = Sk.abstr.iter(this), k = iter.tp$iternext();
- k !== undefined;
- k = iter.tp$iternext()) {
- v = this.mp$subscript(k);
- if (v === undefined) {
- //print(k, "had undefined v");
- v = null;
- }
- // we need to check if value is same as object
- // otherwise it would cause an stack overflow
- if(v === this) {
- ret.push(Sk.misceval.objectRepr(k).v + ": {...}");
- } else {
- ret.push(Sk.misceval.objectRepr(k).v + ": " + Sk.misceval.objectRepr(v).v);
- }
- }
- return new Sk.builtin.str("{" + ret.join(", ") + "}");
- };
- Sk.builtin.dict.prototype.mp$length = function () {
- return this.size;
- };
- Sk.builtin.dict.prototype["get"] = new Sk.builtin.func(function (self, k, d) {
- Sk.builtin.pyCheckArgs("get()", arguments, 1, 2, false, true);
- var ret;
- if (d === undefined) {
- d = Sk.builtin.none.none$;
- }
- ret = self.mp$lookup(k);
- if (ret === undefined) {
- ret = d;
- }
- return ret;
- });
- Sk.builtin.dict.prototype["pop"] = new Sk.builtin.func(function (self, key, d) {
- Sk.builtin.pyCheckArgs("pop()", arguments, 1, 2, false, true);
- var k = kf(key);
- var bucket = self.buckets[k.v];
- var item;
- var s;
- // todo; does this need to go through mp$ma_lookup
- if (bucket !== undefined) {
- item = self.key$pop(bucket, key);
- if (item !== undefined) {
- return item.rhs;
- }
- }
- // Not found in dictionary
- if (d !== undefined) {
- return d;
- }
- s = new Sk.builtin.str(key);
- throw new Sk.builtin.KeyError(s.v);
- });
- Sk.builtin.dict.prototype["has_key"] = new Sk.builtin.func(function (self, k) {
- Sk.builtin.pyCheckArgs("has_key()", arguments, 1, 1, false, true);
- return new Sk.builtin.bool( self.sq$contains(k));
- });
- Sk.builtin.dict.prototype["items"] = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("items()", arguments, 0, 0, false, true);
- var v;
- var iter, k;
- var ret = [];
- for (iter = Sk.abstr.iter(self), k = iter.tp$iternext();
- k !== undefined;
- k = iter.tp$iternext()) {
- v = self.mp$subscript(k);
- if (v === undefined) {
- //print(k, "had undefined v");
- v = null;
- }
- ret.push(new Sk.builtin.tuple([k, v]));
- }
- return new Sk.builtin.list(ret);
- });
- Sk.builtin.dict.prototype["keys"] = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("keys()", arguments, 0, 0, false, true);
- var iter, k;
- var ret = [];
- for (iter = Sk.abstr.iter(self), k = iter.tp$iternext();
- k !== undefined;
- k = iter.tp$iternext()) {
- ret.push(k);
- }
- return new Sk.builtin.list(ret);
- });
- Sk.builtin.dict.prototype["values"] = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("values()", arguments, 0, 0, false, true);
- var v;
- var iter, k;
- var ret = [];
- for (iter = Sk.abstr.iter(self), k = iter.tp$iternext();
- k !== undefined;
- k = iter.tp$iternext()) {
- v = self.mp$subscript(k);
- if (v === undefined) {
- v = null;
- }
- ret.push(v);
- }
- return new Sk.builtin.list(ret);
- });
- Sk.builtin.dict.prototype["clear"] = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("clear()", arguments, 0, 0, false, true);
- var k;
- var iter;
- for (iter = Sk.abstr.iter(self), k = iter.tp$iternext();
- k !== undefined;
- k = iter.tp$iternext()) {
- self.mp$del_subscript(k);
- }
- });
- Sk.builtin.dict.prototype["setdefault"] = new Sk.builtin.func(function (self, key, default_) {
- try {
- return self.mp$subscript(key);
- }
- catch (e) {
- if (default_ === undefined) {
- default_ = Sk.builtin.none.none$;
- }
- self.mp$ass_subscript(key, default_);
- return default_;
- }
- });
- /*
- this function mimics the cpython implementation, which is also the reason for the
- almost similar code, this may be changed in future
- */
- Sk.builtin.dict.prototype.dict_merge = function(b) {
- var iter;
- var k, v;
- if(b instanceof Sk.builtin.dict) {
- // fast way
- for (iter = b.tp$iter(), k = iter.tp$iternext(); k !== undefined; k = iter.tp$iternext()) {
- v = b.mp$subscript(k);
- if (v === undefined) {
- throw new Sk.builtin.AttributeError("cannot get item for key: " + k.v);
- }
- this.mp$ass_subscript(k, v);
- }
- } else {
- // generic slower way
- var keys = Sk.misceval.callsim(b["keys"], b);
- for (iter = Sk.abstr.iter(keys), k = iter.tp$iternext(); k !== undefined; k = iter.tp$iternext()) {
- v = b.tp$getitem(k); // get value
- if (v === undefined) {
- throw new Sk.builtin.AttributeError("cannot get item for key: " + k.v);
- }
- this.mp$ass_subscript(k, v);
- }
- }
- };
- /**
- * update() accepts either another dictionary object or an iterable of key/value pairs (as tuples or other iterables of length two).
- * If keyword arguments are specified, the dictionary is then updated with those key/value pairs: d.update(red=1, blue=2).
- * https://hg.python.org/cpython/file/4ff865976bb9/Objects/dictobject.c
- */
- var update_f = function (kwargs, self, other) {
- // case another dict or obj with keys and getitem has been provided
- if(other !== undefined && (other.tp$name === "dict" || other["keys"])) {
- self.dict_merge(other); // we merge with override
- } else if(other !== undefined && Sk.builtin.checkIterable(other)) {
- // 2nd case, we expect an iterable that contains another iterable of length 2
- var iter;
- var k, v;
- var seq_i = 0; // index of current sequence item
- for (iter = Sk.abstr.iter(other), k = iter.tp$iternext(); k !== undefined; k = iter.tp$iternext(), seq_i++) {
- // check if value is iter
- if (!Sk.builtin.checkIterable(k)) {
- throw new Sk.builtin.TypeError("cannot convert dictionary update sequence element #" + seq_i + " to a sequence");
- }
- // cpython impl. would transform iterable into sequence
- // we just call iternext twice if k has length of 2
- if(k.sq$length() === 2) {
- var k_iter = Sk.abstr.iter(k);
- var k_key = k_iter.tp$iternext();
- var k_value = k_iter.tp$iternext();
- self.mp$ass_subscript(k_key, k_value);
- } else {
- // throw exception
- throw new Sk.builtin.ValueError("dictionary update sequence element #" + seq_i + " has length " + k.sq$length() + "; 2 is required");
- }
- }
- } else if(other !== undefined) {
- // other is not a dict or iterable
- throw new Sk.builtin.TypeError("'" +Sk.abstr.typeName(other) + "' object is not iterable");
- }
- // apply all key/value pairs of kwargs
- // create here kwargs_dict, there could be exceptions in other cases before
- var kwargs_dict = new Sk.builtins.dict(kwargs);
- self.dict_merge(kwargs_dict);
- // returns none, when successful or throws exception
- return Sk.builtin.none.none$;
- };
- update_f.co_kwargs = true;
- Sk.builtin.dict.prototype.update = new Sk.builtin.func(update_f);
- Sk.builtin.dict.prototype.__contains__ = new Sk.builtin.func(function (self, item) {
- Sk.builtin.pyCheckArgs("__contains__", arguments, 1, 1, false, true);
- return Sk.builtin.dict.prototype.sq$contains.call(self, item);
- });
- Sk.builtin.dict.prototype.__cmp__ = new Sk.builtin.func(function (self, other, op) {
- // __cmp__ cannot be supported until dict lt/le/gt/ge operations are supported
- return Sk.builtin.NotImplemented.NotImplemented$;
- });
- Sk.builtin.dict.prototype.__delitem__ = new Sk.builtin.func(function (self, item) {
- Sk.builtin.pyCheckArgs("__delitem__", arguments, 1, 1, false, true);
- return Sk.builtin.dict.prototype.mp$del_subscript.call(self, item);
- });
- Sk.builtin.dict.prototype.__getitem__ = new Sk.builtin.func(function (self, item) {
- Sk.builtin.pyCheckArgs("__getitem__", arguments, 1, 1, false, true);
- return Sk.builtin.dict.prototype.mp$subscript.call(self, item);
- });
- Sk.builtin.dict.prototype.__setitem__ = new Sk.builtin.func(function (self, item, value) {
- Sk.builtin.pyCheckArgs("__setitem__", arguments, 2, 2, false, true);
- return Sk.builtin.dict.prototype.mp$ass_subscript.call(self, item, value);
- });
- Sk.builtin.dict.prototype.__hash__ = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("__hash__", arguments, 0, 0, false, true);
- return Sk.builtin.dict.prototype.tp$hash.call(self);
- });
- Sk.builtin.dict.prototype.__len__ = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("__len__", arguments, 0, 0, false, true);
- return Sk.builtin.dict.prototype.mp$length.call(self);
- });
- Sk.builtin.dict.prototype.__getattr__ = new Sk.builtin.func(function (self, attr) {
- Sk.builtin.pyCheckArgs("__getattr__", arguments, 1, 1, false, true);
- if (!Sk.builtin.checkString(attr)) { throw new Sk.builtin.TypeError("__getattr__ requires a string"); }
- return Sk.builtin.dict.prototype.tp$getattr.call(self, Sk.ffi.remapToJs(attr));
- });
- Sk.builtin.dict.prototype.__iter__ = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("__iter__", arguments, 0, 0, false, true);
- return new Sk.builtin.dict_iter_(self);
- });
- Sk.builtin.dict.prototype.tp$iter = function () {
- return new Sk.builtin.dict_iter_(this);
- };
- Sk.builtin.dict.prototype.__repr__ = new Sk.builtin.func(function (self) {
- Sk.builtin.pyCheckArgs("__repr__", arguments, 0, 0, false, true);
- return Sk.builtin.dict.prototype["$r"].call(self);
- });
- /* python3 recommends implementing simple ops */
- Sk.builtin.dict.prototype.ob$eq = function (other) {
- var iter, k, v, otherv;
- if (this === other) {
- return Sk.builtin.bool.true$;
- }
- if (!(other instanceof Sk.builtin.dict)) {
- return Sk.builtin.NotImplemented.NotImplemented$;
- }
- if (this.size !== other.size) {
- return Sk.builtin.bool.false$;
- }
- for (iter = this.tp$iter(), k = iter.tp$iternext();
- k !== undefined;
- k = iter.tp$iternext()) {
- v = this.mp$subscript(k);
- otherv = other.mp$subscript(k);
- if (!Sk.misceval.richCompareBool(v, otherv, "Eq")) {
- return Sk.builtin.bool.false$;
- }
- }
- return Sk.builtin.bool.true$;
- };
- Sk.builtin.dict.prototype.ob$ne = function (other) {
- var isEqual = this.ob$eq(other);
- if (isEqual instanceof Sk.builtin.NotImplemented) {
- return isEqual;
- } else if (isEqual.v) {
- return Sk.builtin.bool.false$;
- } else {
- return Sk.builtin.bool.true$;
- }
- };
- Sk.builtin.dict.prototype["copy"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.copy is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["fromkeys"] = new Sk.builtin.func(function (seq, value) {
- throw new Sk.builtin.NotImplementedError("dict.fromkeys is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["iteritems"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.iteritems is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["iterkeys"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.iterkeys is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["itervalues"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.itervalues is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["popitem"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.popitem is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["viewitems"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.viewitems is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["viewkeys"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.viewkeys is not yet implemented in Skulpt");
- });
- Sk.builtin.dict.prototype["viewvalues"] = new Sk.builtin.func(function (self) {
- throw new Sk.builtin.NotImplementedError("dict.viewvalues is not yet implemented in Skulpt");
- });
- goog.exportSymbol("Sk.builtin.dict", Sk.builtin.dict);
- /**
- * @constructor
- * @param {Object} obj
- */
- Sk.builtin.dict_iter_ = function (obj) {
- var k, i, bucket, allkeys, buckets;
- if (!(this instanceof Sk.builtin.dict_iter_)) {
- return new Sk.builtin.dict_iter_(obj);
- }
- this.$index = 0;
- this.$obj = obj;
- allkeys = [];
- buckets = obj.buckets;
- for (k in buckets) {
- if (buckets.hasOwnProperty(k)) {
- bucket = buckets[k];
- if (bucket && bucket.$hash !== undefined && bucket.items !== undefined) {
- // skip internal stuff. todo; merge pyobj and this
- for (i = 0; i < bucket.items.length; i++) {
- allkeys.push(bucket.items[i].lhs);
- }
- }
- }
- }
- this.$keys = allkeys;
- this.tp$iter = this;
- this.tp$iternext = function () {
- // todo; StopIteration
- if (this.$index >= this.$keys.length) {
- return undefined;
- }
- return this.$keys[this.$index++];
- // return this.$obj[this.$keys[this.$index++]].lhs;
- };
- this.$r = function () {
- return new Sk.builtin.str("dictionary-keyiterator");
- };
- return this;
- };
- Sk.abstr.setUpInheritance("dictionary-keyiterator", Sk.builtin.dict_iter_, Sk.builtin.object);
- Sk.builtin.dict_iter_.prototype.__class__ = Sk.builtin.dict_iter_;
- Sk.builtin.dict_iter_.prototype.__iter__ = new Sk.builtin.func(function (self) {
- return self;
- });
- Sk.builtin.dict_iter_.prototype["next"] = new Sk.builtin.func(function (self) {
- var ret = self.tp$iternext();
- if (ret === undefined) {
- throw new Sk.builtin.StopIteration();
- }
- return ret;
- });
|