forked from skulpt/skulpt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmappingproxy.js
More file actions
186 lines (185 loc) · 6.5 KB
/
Copy pathmappingproxy.js
File metadata and controls
186 lines (185 loc) · 6.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
/**
*
* @constructor
*
* @param {Object} d
*
* @description
* This should be called with the prototype of a type object
* It returns a mapping proxy
* useful for when we do typeobject.__dict__
* or module.__dict__ since a module $d is an object literal
*
* Internally this should be called with an object literal
* from python this can be called with a dict instance (or @todo other mapping type)
*
* For internal object literals we create a dict object whose internal representation of
* this.entries is created on the fly (when requested)
*
* We could potentially memoise the entries for static objects (builtin types @todo)
* The problem with memoising for all type objects is that the mappingproxy
* is a live view of the mapping rather than a static copy
*
* ```python
* >>> x = A.__dict__
* >>> A.foo = 'bar'
* >>> x['foo']
* 'bar'
* ```
*
*/
Sk.builtin.mappingproxy = Sk.abstr.buildNativeClass("mappingproxy", {
constructor: function mappingproxy(d) {
Sk.asserts.assert(this instanceof Sk.builtin.mappingproxy, "bad call to mapping proxy, use 'new'");
if (d !== undefined) {
const constructor = d.constructor;
if (constructor === Object || constructor === null || d.hasOwnProperty("sk$object")) {
// then we are not a mapping but js object to be proxied
this.mapping = new Sk.builtin.dict([]);
// internal call so d is an object literal
// adust this.mapping.entries to be a custom getter
// allowing support for dynamic object literals
customEntriesGetter(this.mapping, d);
} else if (Sk.builtin.checkMapping(d)) {
this.mapping = d;
} else {
Sk.asserts.fail("unhandled case for mappingproxy");
}
}
},
slots: {
tp$getattr: Sk.generic.getAttr,
tp$as_sequence_or_mapping: true,
tp$hash: Sk.builtin.none.none$,
tp$new(args, kwargs) {
Sk.abstr.checkNoKwargs("mappingproxy", kwargs);
Sk.abstr.checkOneArg("mappingproxy", args, kwargs);
const mapping = args[0];
if (!Sk.builtin.checkMapping(mapping)) {
throw new Sk.builtin.TypeError("mappingproxy() argument must be a mapping, not " + Sk.abstr.typeName(mapping));
}
const mp = new Sk.builtin.mappingproxy();
mp.mapping = mapping;
return mp;
},
tp$richcompare(other, op) {
return Sk.misceval.richCompareBool(this.mapping, other, op);
},
tp$str() {
return this.mapping.tp$str();
},
$r() {
return new Sk.builtin.str("mappingproxy(" + Sk.misceval.objectRepr(this.mapping) + ")");
},
mp$subscript(key, canSuspend) {
return this.mapping.mp$subscript(key, canSuspend);
},
sq$contains(key) {
return this.mapping.sq$contains(key);
},
sq$length() {
return this.mapping.sq$length();
},
tp$iter() {
return this.mapping.tp$iter();
},
tp$as_number: true,
nb$or(other) {
if (other instanceof Sk.builtin.mappingproxy) {
other = other.mapping;
}
return Sk.abstr.numberBinOp(this.mapping, other, "BitOr");
},
nb$reflected_or(other) {
if (other instanceof Sk.builtin.mappingproxy) {
other = other.mapping;
}
return Sk.abstr.numberBinOp(other, this.mapping, "BitOr");
},
nb$inplace_or(other) {
throw new Sk.builtin.TypeError("'|=' is not supported by " + Sk.abstr.typeName(this) + "; use '|' instead");
},
},
methods: {
get: {
$meth(args, kwargs) {
return Sk.misceval.callsimArray(this.mapping.tp$getattr(this.str$get), args, kwargs);
},
$flags: { FastCall: true },
$textsig: null,
$doc: "D.get(k[,d]) -> D[k] if k in D, else d. d defaults to None.",
},
keys: {
$meth() {
return Sk.misceval.callsimArray(this.mapping.tp$getattr(this.str$keys), []);
},
$flags: { NoArgs: true },
$textsig: null,
$doc: "D.keys() -> a set-like object providing a view on D's keys",
},
items: {
$meth() {
return Sk.misceval.callsimArray(this.mapping.tp$getattr(this.str$items), []);
},
$flags: { NoArgs: true },
$textsig: null,
$doc: "D.items() -> a set-like object providing a view on D's items",
},
values: {
$meth() {
return Sk.misceval.callsimArray(this.mapping.tp$getattr(this.str$values), []);
},
$flags: { NoArgs: true },
$textsig: null,
$doc: "D.values() -> a set-like object providing a view on D's values",
},
copy: {
$meth() {
return Sk.misceval.callsimArray(this.mapping.tp$getattr(this.str$copy), []);
},
$flags: { NoArgs: true },
$textsig: null,
$doc: "D.copy() -> a shallow copy of D",
},
},
classmethods: Sk.generic.classGetItem,
proto: {
str$get: new Sk.builtin.str("get"),
str$copy: new Sk.builtin.str("copy"),
str$keys: new Sk.builtin.str("keys"),
str$items: new Sk.builtin.str("items"),
str$values: new Sk.builtin.str("values"),
mp$lookup(key) {
return this.mapping.mp$lookup(key);
},
},
flags: {
sk$unacceptableBase: true,
},
});
function customEntriesGetter(mapping, d) {
Object.defineProperties(mapping, {
entries: {
get: () => {
const entries = Object.create(null);
Object.entries(d).forEach(([key, val]) => {
key = Sk.unfixReserved(key);
if (!key.includes("$")) {
key = new Sk.builtin.str(key);
entries[key.$savedKeyHash] = [key, val];
}
});
return entries;
},
configurable: true,
},
size: {
get: () => {
return Object.keys(d)
.map((k) => Sk.unfixReserved(k))
.filter((k) => !k.includes("$")).length;
},
configurable: true,
},
});
}