rapydscript-ns 0.8.3 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/README.md +1351 -141
- package/TODO.md +12 -6
- package/language-service/index.js +184 -26
- package/package.json +1 -1
- package/release/baselib-plain-pretty.js +5895 -1928
- package/release/baselib-plain-ugly.js +140 -3
- package/release/compiler.js +16282 -5408
- package/release/signatures.json +25 -22
- package/src/ast.pyj +94 -1
- package/src/baselib-builtins.pyj +362 -3
- package/src/baselib-bytes.pyj +664 -0
- package/src/baselib-containers.pyj +99 -0
- package/src/baselib-errors.pyj +45 -1
- package/src/baselib-internal.pyj +346 -49
- package/src/baselib-itertools.pyj +17 -4
- package/src/baselib-str.pyj +46 -4
- package/src/lib/abc.pyj +317 -0
- package/src/lib/copy.pyj +120 -0
- package/src/lib/dataclasses.pyj +532 -0
- package/src/lib/enum.pyj +125 -0
- package/src/lib/pythonize.pyj +1 -1
- package/src/lib/re.pyj +35 -1
- package/src/lib/react.pyj +74 -0
- package/src/lib/typing.pyj +577 -0
- package/src/monaco-language-service/builtins.js +19 -4
- package/src/monaco-language-service/diagnostics.js +40 -19
- package/src/output/classes.pyj +161 -25
- package/src/output/codegen.pyj +16 -2
- package/src/output/exceptions.pyj +97 -1
- package/src/output/functions.pyj +87 -5
- package/src/output/jsx.pyj +164 -0
- package/src/output/literals.pyj +28 -2
- package/src/output/loops.pyj +5 -2
- package/src/output/modules.pyj +1 -1
- package/src/output/operators.pyj +108 -36
- package/src/output/statements.pyj +2 -2
- package/src/output/stream.pyj +1 -0
- package/src/parse.pyj +496 -128
- package/src/tokenizer.pyj +38 -4
- package/test/abc.pyj +291 -0
- package/test/arithmetic_nostrict.pyj +88 -0
- package/test/arithmetic_types.pyj +169 -0
- package/test/baselib.pyj +91 -0
- package/test/bytes.pyj +467 -0
- package/test/classes.pyj +1 -0
- package/test/comparison_ops.pyj +173 -0
- package/test/dataclasses.pyj +253 -0
- package/test/enum.pyj +134 -0
- package/test/eval_exec.pyj +56 -0
- package/test/format.pyj +148 -0
- package/test/object.pyj +64 -0
- package/test/python_compat.pyj +17 -15
- package/test/python_features.pyj +89 -21
- package/test/regexp.pyj +29 -1
- package/test/tuples.pyj +96 -0
- package/test/typing.pyj +469 -0
- package/test/unit/index.js +2292 -70
- package/test/unit/language-service.js +674 -4
- package/test/unit/web-repl.js +1106 -0
- package/test/vars_locals_globals.pyj +94 -0
- package/tools/cli.js +11 -0
- package/tools/compile.js +5 -0
- package/tools/embedded_compiler.js +15 -4
- package/tools/lint.js +16 -19
- package/tools/repl.js +1 -1
- package/web-repl/env.js +122 -0
- package/web-repl/main.js +1 -3
- package/web-repl/rapydscript.js +125 -3
- package/PYTHON_DIFFERENCES_REPORT.md +0 -291
- package/PYTHON_FEATURE_COVERAGE.md +0 -200
- package/hack_demo.pyj +0 -112
package/src/lib/abc.pyj
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD
|
|
3
|
+
# RapydScript implementation of Python's abc standard library.
|
|
4
|
+
#
|
|
5
|
+
# Supported:
|
|
6
|
+
# ABC — base class for abstract base classes
|
|
7
|
+
# @abstractmethod — decorator marking a method as abstract
|
|
8
|
+
# Protocol — base class for structural subtyping (PEP 544)
|
|
9
|
+
# @runtime_checkable — allow isinstance() structural checks on Protocol
|
|
10
|
+
# ABCMeta — informational placeholder (not a real metaclass)
|
|
11
|
+
# get_cache_token() — returns 0
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# from abc import ABC, abstractmethod
|
|
15
|
+
#
|
|
16
|
+
# class Shape(ABC):
|
|
17
|
+
# @abstractmethod
|
|
18
|
+
# def area(self): pass
|
|
19
|
+
#
|
|
20
|
+
# class Circle(Shape):
|
|
21
|
+
# def __init__(self, r):
|
|
22
|
+
# self.r = r
|
|
23
|
+
# def area(self):
|
|
24
|
+
# return 3.14159 * self.r * self.r
|
|
25
|
+
#
|
|
26
|
+
# c = Circle(5) # OK
|
|
27
|
+
# Shape() # TypeError: Can't instantiate abstract class Shape
|
|
28
|
+
# # with abstract method area
|
|
29
|
+
#
|
|
30
|
+
# Protocol usage:
|
|
31
|
+
# from abc import Protocol, runtime_checkable
|
|
32
|
+
#
|
|
33
|
+
# @runtime_checkable
|
|
34
|
+
# class Drawable(Protocol):
|
|
35
|
+
# def draw(self): ...
|
|
36
|
+
#
|
|
37
|
+
# class Canvas:
|
|
38
|
+
# def draw(self): pass
|
|
39
|
+
#
|
|
40
|
+
# isinstance(Canvas(), Drawable) # True (structural check)
|
|
41
|
+
# isinstance(42, Drawable) # False
|
|
42
|
+
#
|
|
43
|
+
# Implementation notes:
|
|
44
|
+
# - @abstractmethod sets func.__isabstractmethod__ = True.
|
|
45
|
+
# - ABC.__init_subclass__ is called for every subclass (directly or transitively)
|
|
46
|
+
# because ρσ_extends calls Object.setPrototypeOf(child, parent), making
|
|
47
|
+
# constructor-chain lookup find the parent's __init_subclass__.
|
|
48
|
+
# - A __init__ guard is installed on cls.prototype when abstract methods remain;
|
|
49
|
+
# the guard checks this.__class__.__abstractmethods__ at runtime so concrete
|
|
50
|
+
# subclasses that inherit the guard pass cleanly.
|
|
51
|
+
# - ABC.register() stores class constructors in a native JS Set; Symbol.hasInstance
|
|
52
|
+
# is installed to make isinstance(obj, SomeABC) respect the registry.
|
|
53
|
+
# - Protocol collects __protocol_attrs__ (non-dunder callable own-properties).
|
|
54
|
+
# @runtime_checkable installs Symbol.hasInstance for structural isinstance().
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def abstractmethod(func):
|
|
58
|
+
"""Decorator to declare a method as abstract."""
|
|
59
|
+
func.__isabstractmethod__ = True
|
|
60
|
+
return func
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _collect_abstract_methods(cls):
|
|
64
|
+
"""
|
|
65
|
+
Return a Python set of still-abstract method names in cls.
|
|
66
|
+
|
|
67
|
+
Merges base classes' __abstractmethods__ sets, then walks cls.prototype's
|
|
68
|
+
own properties: methods with __isabstractmethod__ are added; concrete
|
|
69
|
+
implementations remove the name from the set.
|
|
70
|
+
"""
|
|
71
|
+
abstract = set()
|
|
72
|
+
|
|
73
|
+
v"""
|
|
74
|
+
var ρσ_bases = (cls.prototype && cls.prototype.__bases__) || [];
|
|
75
|
+
for (var ρσ_bi = 0; ρσ_bi < ρσ_bases.length; ρσ_bi++) {
|
|
76
|
+
var ρσ_base = ρσ_bases[ρσ_bi];
|
|
77
|
+
if (ρσ_base && ρσ_base.__abstractmethods__) {
|
|
78
|
+
for (var ρσ_n of ρσ_base.__abstractmethods__) {
|
|
79
|
+
abstract.add(ρσ_n);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
var ρσ_proto = cls.prototype;
|
|
84
|
+
var ρσ_keys = Object.getOwnPropertyNames(ρσ_proto);
|
|
85
|
+
for (var ρσ_ki = 0; ρσ_ki < ρσ_keys.length; ρσ_ki++) {
|
|
86
|
+
var ρσ_k = ρσ_keys[ρσ_ki];
|
|
87
|
+
if (ρσ_k.startsWith('ρσ') || ρσ_k === '__class__') continue;
|
|
88
|
+
var ρσ_desc = Object.getOwnPropertyDescriptor(ρσ_proto, ρσ_k);
|
|
89
|
+
if (!ρσ_desc) continue;
|
|
90
|
+
if (typeof ρσ_desc.value === 'function') {
|
|
91
|
+
if (ρσ_desc.value.__isabstractmethod__) {
|
|
92
|
+
abstract.add(ρσ_k);
|
|
93
|
+
} else {
|
|
94
|
+
abstract.discard(ρσ_k);
|
|
95
|
+
}
|
|
96
|
+
} else if (ρσ_desc.get && ρσ_desc.get.__isabstractmethod__) {
|
|
97
|
+
abstract.add(ρσ_k);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
"""
|
|
101
|
+
|
|
102
|
+
return abstract
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _install_abstract_guard(cls):
|
|
106
|
+
"""
|
|
107
|
+
Replace cls.prototype.__init__ with a wrapper that raises TypeError if the
|
|
108
|
+
concrete class being instantiated still has un-overridden abstract methods.
|
|
109
|
+
The check uses this.__class__.__abstractmethods__ at call-time, so a
|
|
110
|
+
concrete subclass that inherits this guard from an abstract parent passes.
|
|
111
|
+
"""
|
|
112
|
+
v"""
|
|
113
|
+
var ρσ_orig_init = Object.prototype.hasOwnProperty.call(cls.prototype, '__init__')
|
|
114
|
+
? cls.prototype.__init__
|
|
115
|
+
: null;
|
|
116
|
+
cls.prototype.__init__ = function() {
|
|
117
|
+
var ρσ_actual_cls = (this && (this.__class__ || this.constructor)) || cls;
|
|
118
|
+
var ρσ_am = ρσ_actual_cls && ρσ_actual_cls.__abstractmethods__;
|
|
119
|
+
if (ρσ_am && ρσ_am.size > 0) {
|
|
120
|
+
var ρσ_names = Array.from(ρσ_am).sort().join(', ');
|
|
121
|
+
var ρσ_s = ρσ_am.size > 1 ? 's' : '';
|
|
122
|
+
throw new TypeError(
|
|
123
|
+
"Can't instantiate abstract class " + ρσ_actual_cls.__name__ +
|
|
124
|
+
" with abstract method" + ρσ_s + " " + ρσ_names
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
if (typeof ρσ_orig_init === 'function') {
|
|
128
|
+
ρσ_orig_init.apply(this, arguments);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class ABCMeta:
|
|
135
|
+
"""
|
|
136
|
+
Metaclass for defining Abstract Base Classes (informational in RapydScript).
|
|
137
|
+
|
|
138
|
+
In Python, ABCMeta is the true metaclass that powers abstract classes.
|
|
139
|
+
RapydScript does not support metaclasses; use ABC as a regular base class
|
|
140
|
+
instead. ABCMeta is provided for compatibility with code that references it.
|
|
141
|
+
"""
|
|
142
|
+
pass
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class ABC:
|
|
146
|
+
"""
|
|
147
|
+
Helper class for defining Abstract Base Classes via inheritance.
|
|
148
|
+
|
|
149
|
+
Any class that inherits from ABC (directly or transitively) and still has
|
|
150
|
+
un-overridden @abstractmethod declarations cannot be instantiated — a
|
|
151
|
+
TypeError is raised at construction time.
|
|
152
|
+
|
|
153
|
+
Use ABC.register(subclass) to declare a virtual subclass that passes
|
|
154
|
+
isinstance() checks without actual inheritance.
|
|
155
|
+
|
|
156
|
+
Example::
|
|
157
|
+
|
|
158
|
+
class Vehicle(ABC):
|
|
159
|
+
@abstractmethod
|
|
160
|
+
def drive(self): ...
|
|
161
|
+
|
|
162
|
+
class Car(Vehicle):
|
|
163
|
+
def drive(self):
|
|
164
|
+
print('vroom')
|
|
165
|
+
|
|
166
|
+
Car() # OK
|
|
167
|
+
Vehicle() # TypeError: Can't instantiate abstract class Vehicle
|
|
168
|
+
# with abstract method drive
|
|
169
|
+
"""
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def __init_subclass__(cls, **kwargs):
|
|
173
|
+
am = _collect_abstract_methods(cls)
|
|
174
|
+
cls.__abstractmethods__ = am
|
|
175
|
+
|
|
176
|
+
v"""
|
|
177
|
+
cls.__abc_registry__ = new Set();
|
|
178
|
+
var ρσ_registry = cls.__abc_registry__;
|
|
179
|
+
// Two install sites for register():
|
|
180
|
+
//
|
|
181
|
+
// 1. cls.register (constructor property): used when @MyABC.register is
|
|
182
|
+
// written as a class decorator — RapydScript stores the expression value
|
|
183
|
+
// [_MyABC.register] in ρσ_decorators, then calls ρσ_decorators[0](Cls).
|
|
184
|
+
// Here 'subclass' receives the class being decorated.
|
|
185
|
+
cls.register = function(subclass) {
|
|
186
|
+
ρσ_registry.add(subclass);
|
|
187
|
+
return subclass;
|
|
188
|
+
};
|
|
189
|
+
// 2. cls.prototype.register (prototype method): used when the user writes
|
|
190
|
+
// MyABC.register(Cls) as a plain call — RapydScript compiles this to
|
|
191
|
+
// MyABC.prototype.register.call(Cls), so 'this' is the class to register.
|
|
192
|
+
cls.prototype.register = function() {
|
|
193
|
+
ρσ_registry.add(this);
|
|
194
|
+
return this;
|
|
195
|
+
};
|
|
196
|
+
Object.defineProperty(cls, Symbol.hasInstance, {
|
|
197
|
+
configurable: true,
|
|
198
|
+
value: function(instance) {
|
|
199
|
+
if (instance === null || instance === undefined) return false;
|
|
200
|
+
if (Object.prototype.isPrototypeOf.call(cls.prototype, instance)) return true;
|
|
201
|
+
var reg = cls.__abc_registry__;
|
|
202
|
+
if (reg && reg.size > 0) {
|
|
203
|
+
var ctor = instance.__class__ || instance.constructor;
|
|
204
|
+
while (ctor && ctor !== Function.prototype) {
|
|
205
|
+
if (reg.has(ctor)) return true;
|
|
206
|
+
ctor = Object.getPrototypeOf(ctor);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
"""
|
|
213
|
+
|
|
214
|
+
if am.size > 0:
|
|
215
|
+
_install_abstract_guard(cls)
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
class Protocol:
|
|
219
|
+
"""
|
|
220
|
+
Base class for protocol classes (structural subtyping — PEP 544).
|
|
221
|
+
|
|
222
|
+
Define a Protocol to specify a structural interface: any class that has
|
|
223
|
+
the required methods satisfies the protocol at runtime. Use
|
|
224
|
+
@runtime_checkable to enable isinstance() checks based on method presence
|
|
225
|
+
rather than inheritance.
|
|
226
|
+
|
|
227
|
+
Example::
|
|
228
|
+
|
|
229
|
+
from abc import Protocol, runtime_checkable
|
|
230
|
+
|
|
231
|
+
@runtime_checkable
|
|
232
|
+
class Drawable(Protocol):
|
|
233
|
+
def draw(self): ...
|
|
234
|
+
|
|
235
|
+
class Canvas:
|
|
236
|
+
def draw(self):
|
|
237
|
+
print('drawing...')
|
|
238
|
+
|
|
239
|
+
isinstance(Canvas(), Drawable) # True
|
|
240
|
+
isinstance(42, Drawable) # False
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
@classmethod
|
|
244
|
+
def __init_subclass__(cls, **kwargs):
|
|
245
|
+
am = _collect_abstract_methods(cls)
|
|
246
|
+
cls.__abstractmethods__ = am
|
|
247
|
+
|
|
248
|
+
v"""
|
|
249
|
+
var ρσ_proto_attrs = new Set();
|
|
250
|
+
var ρσ_pbases = (cls.prototype && cls.prototype.__bases__) || [];
|
|
251
|
+
for (var ρσ_pbi = 0; ρσ_pbi < ρσ_pbases.length; ρσ_pbi++) {
|
|
252
|
+
var ρσ_pbase = ρσ_pbases[ρσ_pbi];
|
|
253
|
+
if (ρσ_pbase && ρσ_pbase.__protocol_attrs__) {
|
|
254
|
+
for (var ρσ_pa of ρσ_pbase.__protocol_attrs__) {
|
|
255
|
+
ρσ_proto_attrs.add(ρσ_pa);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
var ρσ_pproto = cls.prototype;
|
|
260
|
+
var ρσ_pkeys = Object.getOwnPropertyNames(ρσ_pproto);
|
|
261
|
+
for (var ρσ_pki = 0; ρσ_pki < ρσ_pkeys.length; ρσ_pki++) {
|
|
262
|
+
var ρσ_pk = ρσ_pkeys[ρσ_pki];
|
|
263
|
+
if (ρσ_pk.startsWith('_') || ρσ_pk.startsWith('ρσ')) continue;
|
|
264
|
+
var ρσ_pd = Object.getOwnPropertyDescriptor(ρσ_pproto, ρσ_pk);
|
|
265
|
+
if (ρσ_pd && typeof ρσ_pd.value === 'function') {
|
|
266
|
+
ρσ_proto_attrs.add(ρσ_pk);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
cls.__protocol_attrs__ = ρσ_proto_attrs;
|
|
270
|
+
"""
|
|
271
|
+
|
|
272
|
+
if am.size > 0:
|
|
273
|
+
_install_abstract_guard(cls)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def runtime_checkable(cls):
|
|
277
|
+
"""
|
|
278
|
+
Decorator for Protocol subclasses to allow isinstance() structural checks.
|
|
279
|
+
|
|
280
|
+
After applying @runtime_checkable, isinstance(obj, MyProtocol) returns True
|
|
281
|
+
if *obj* has all the non-dunder methods declared in the Protocol, regardless
|
|
282
|
+
of inheritance.
|
|
283
|
+
|
|
284
|
+
Example::
|
|
285
|
+
|
|
286
|
+
@runtime_checkable
|
|
287
|
+
class Closeable(Protocol):
|
|
288
|
+
def close(self): ...
|
|
289
|
+
|
|
290
|
+
class File:
|
|
291
|
+
def close(self): ...
|
|
292
|
+
|
|
293
|
+
isinstance(File(), Closeable) # True
|
|
294
|
+
isinstance(42, Closeable) # False
|
|
295
|
+
"""
|
|
296
|
+
cls.__runtime_checkable__ = True
|
|
297
|
+
|
|
298
|
+
v"""
|
|
299
|
+
var ρσ_attrs = cls.__protocol_attrs__ || new Set();
|
|
300
|
+
Object.defineProperty(cls, Symbol.hasInstance, {
|
|
301
|
+
configurable: true,
|
|
302
|
+
value: function(instance) {
|
|
303
|
+
if (instance === null || instance === undefined) return false;
|
|
304
|
+
for (var ρσ_attr of ρσ_attrs) {
|
|
305
|
+
if (typeof instance[ρσ_attr] !== 'function') return false;
|
|
306
|
+
}
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
"""
|
|
311
|
+
|
|
312
|
+
return cls
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
def get_cache_token():
|
|
316
|
+
"""Return the current ABC cache invalidation token (always 0 in RapydScript)."""
|
|
317
|
+
return 0
|
package/src/lib/copy.pyj
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD
|
|
3
|
+
# RapydScript implementation of Python's copy standard library.
|
|
4
|
+
#
|
|
5
|
+
# Supported: copy, deepcopy
|
|
6
|
+
# Classes may define __copy__() and __deepcopy__(memo) for custom behaviour.
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _is_primitive(x):
|
|
10
|
+
t = jstype(x)
|
|
11
|
+
return x is None or t is 'number' or t is 'boolean' or t is 'string' or t is 'undefined'
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def copy(x):
|
|
15
|
+
"""Return a shallow copy of x.
|
|
16
|
+
|
|
17
|
+
For immutable primitives (numbers, strings, booleans, None) the object
|
|
18
|
+
itself is returned unchanged. For containers a new container of the same
|
|
19
|
+
type is created whose top-level items are the same objects as in the
|
|
20
|
+
original.
|
|
21
|
+
|
|
22
|
+
Dispatch order:
|
|
23
|
+
1. Primitive → return as-is.
|
|
24
|
+
2. ``__copy__`` method → call and return.
|
|
25
|
+
3. list → ``list(x)`` (slice).
|
|
26
|
+
4. set → ``set(x)``.
|
|
27
|
+
5. frozenset → ``frozenset(x)``.
|
|
28
|
+
6. dict (ρσ_dict) → ``x.copy()``.
|
|
29
|
+
7. Plain JS object (constructor is Object or null-proto) → Object.assign.
|
|
30
|
+
8. Other object (class instance) → Object.create + Object.assign.
|
|
31
|
+
"""
|
|
32
|
+
if _is_primitive(x):
|
|
33
|
+
return x
|
|
34
|
+
if jstype(x.__copy__) is 'function':
|
|
35
|
+
return x.__copy__()
|
|
36
|
+
if Array.isArray(x):
|
|
37
|
+
return list(x)
|
|
38
|
+
if isinstance(x, set):
|
|
39
|
+
return set(x)
|
|
40
|
+
if isinstance(x, frozenset):
|
|
41
|
+
return frozenset(x)
|
|
42
|
+
if isinstance(x, dict):
|
|
43
|
+
return x.copy()
|
|
44
|
+
proto = Object.getPrototypeOf(x)
|
|
45
|
+
if x.constructor is Object or proto is None:
|
|
46
|
+
return Object.assign({}, x)
|
|
47
|
+
# Class instance: create a same-prototype object and copy own properties.
|
|
48
|
+
result = Object.create(proto)
|
|
49
|
+
Object.assign(result, x)
|
|
50
|
+
return result
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def deepcopy(x, memo=None):
|
|
54
|
+
"""Return a deep (recursive) copy of x.
|
|
55
|
+
|
|
56
|
+
Circular references are handled via the *memo* mapping (a JS Map), which
|
|
57
|
+
stores already-copied objects so that they are only copied once.
|
|
58
|
+
|
|
59
|
+
Dispatch order (same structure as ``copy`` but recursive):
|
|
60
|
+
1. Primitive → return as-is.
|
|
61
|
+
2. Memo hit → return the previously copied object.
|
|
62
|
+
3. ``__deepcopy__(memo)`` method → call and return.
|
|
63
|
+
4. list → recurse into elements.
|
|
64
|
+
5. set → recurse into elements, build new set.
|
|
65
|
+
6. frozenset → recurse into elements, build new frozenset.
|
|
66
|
+
7. dict → recurse into keys and values.
|
|
67
|
+
8. Plain JS object → recurse into own-enumerable properties.
|
|
68
|
+
9. Class instance → recurse into own-enumerable properties.
|
|
69
|
+
"""
|
|
70
|
+
if memo is None:
|
|
71
|
+
memo = v'new Map()'
|
|
72
|
+
if _is_primitive(x):
|
|
73
|
+
return x
|
|
74
|
+
if memo.has(x):
|
|
75
|
+
return memo.get(x)
|
|
76
|
+
if jstype(x.__deepcopy__) is 'function':
|
|
77
|
+
result = x.__deepcopy__(memo)
|
|
78
|
+
memo.set(x, result)
|
|
79
|
+
return result
|
|
80
|
+
if Array.isArray(x):
|
|
81
|
+
result = []
|
|
82
|
+
memo.set(x, result)
|
|
83
|
+
for i in range(x.length):
|
|
84
|
+
result.push(deepcopy(x[i], memo))
|
|
85
|
+
return result
|
|
86
|
+
if isinstance(x, set):
|
|
87
|
+
result = set()
|
|
88
|
+
memo.set(x, result)
|
|
89
|
+
iterator = x[ρσ_iterator_symbol]()
|
|
90
|
+
r = iterator.next()
|
|
91
|
+
while not r.done:
|
|
92
|
+
result.add(deepcopy(r.value, memo))
|
|
93
|
+
r = iterator.next()
|
|
94
|
+
return result
|
|
95
|
+
if isinstance(x, frozenset):
|
|
96
|
+
items = []
|
|
97
|
+
iterator = x[ρσ_iterator_symbol]()
|
|
98
|
+
r = iterator.next()
|
|
99
|
+
while not r.done:
|
|
100
|
+
items.push(deepcopy(r.value, memo))
|
|
101
|
+
r = iterator.next()
|
|
102
|
+
result = frozenset(items)
|
|
103
|
+
memo.set(x, result)
|
|
104
|
+
return result
|
|
105
|
+
if isinstance(x, dict):
|
|
106
|
+
result = dict()
|
|
107
|
+
memo.set(x, result)
|
|
108
|
+
iterator = x.items()
|
|
109
|
+
r = iterator.next()
|
|
110
|
+
while not r.done:
|
|
111
|
+
result.set(deepcopy(r.value[0], memo), deepcopy(r.value[1], memo))
|
|
112
|
+
r = iterator.next()
|
|
113
|
+
return result
|
|
114
|
+
proto = Object.getPrototypeOf(x)
|
|
115
|
+
result = Object.create(proto)
|
|
116
|
+
memo.set(x, result)
|
|
117
|
+
keys = Object.keys(x)
|
|
118
|
+
for i in range(keys.length):
|
|
119
|
+
result[keys[i]] = deepcopy(x[keys[i]], memo)
|
|
120
|
+
return result
|