rapydscript-ns 0.8.0 → 0.8.2

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/TODO.md CHANGED
@@ -1,62 +1,30 @@
1
1
 
2
2
  ### libraries
3
- - allow var etc as property name
4
- - revert numpy variance method to be var
5
3
 
6
- - omit_function_metadata breaks imports - it needs to be changed to only affect imported modules, maybe?
4
+ - bitburner - handle missed await / concurrency errors gracefully?
5
+ - two space tabs
6
+
7
+ - fix error from vuln report
8
+ - https://socket.dev/npm/package/rapydscript-ns/alerts/0.8.1?tab=dependencies
9
+ - https://snyk.io/test/github/ficocelliguy/rapydscript-ns
7
10
 
8
- - variables just say (variable) on hover, not their type?
11
+ - omit_function_metadata breaks imports - it needs to be changed to only affect imported modules, maybe?
9
12
 
10
13
  - vscode plugin based on language service
11
14
 
12
- - export language service to npm module
13
- - update url links
14
- - make npm module
15
+ - export .t.ds for language service
15
16
 
17
+ - add opt-out for python truthyness
18
+ - add web-repl flag for python truthiness?
19
+ - include python truthiness in compiler call
16
20
 
21
+ - update changelist for 8.0
17
22
 
18
23
  I would like you to add support for [ Python's extended subscript syntax where commas inside [] implicitly form a tuple ] to rapydscript. It should have the same syntax as the Python implementation, and be transpiled into equivalent javascript. Please ensure with unit tests that it transpiles and the output JS runs correctly, and that the language service correctly handles it in parsed code. Please make sure it works in the web-repl too. Please also update the README to mention this support.
19
24
 
20
25
 
21
26
 
22
27
 
23
- # 1. Placeholder body (like pass)
24
- def todo():
25
- ...
26
-
27
- class MyProtocol:
28
- def method(self) -> int: ...
29
-
30
-
31
- # 3. Sentinel / default marker
32
- _MISSING = ...
33
-
34
- def greet(name=...):
35
- if name is ...:
36
- name = "World"
37
- print(f"Hello, {name}!")
38
-
39
- greet() # Hello, World!
40
- greet("Alice") # Hello, Alice!
41
-
42
-
43
- # 4. NumPy-style slice shorthand (all leading dimensions)
44
- import numpy as np
45
- arr = np.zeros((2, 3, 4))
46
- print(arr[..., 0] ) # shape (2, 3) — first element of last axis
47
- print(arr[1, ...]) # shape (3, 4) — entire second "sheet"
48
-
49
- # 5. Identity check
50
- print(... is ...) # True (singleton)
51
- print(... is Ellipsis) # True
52
- print(type(...).__name__) # ellipsis
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
28
  Python Feature Gap Report: RapydScript-NS
61
29
 
62
30
  Summary
@@ -76,7 +44,7 @@ differences.
76
44
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
77
45
  │ lambda keyword │ all │ -tested │
78
46
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
79
- │ Variable type annotations x: int = 1 │ 3.6+ │ needs testing
47
+ │ Variable type annotations x: int = 1 │ 3.6+ │ -tested
80
48
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
81
49
  │ Positional-only parameters (def f(a, /, b):) │ 3.8+ │ -tested │
82
50
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
@@ -88,7 +56,7 @@ differences.
88
56
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
89
57
  │ Parenthesized with (multi-context) │ 3.10+ │ - doesn't make sense in a web context │
90
58
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
91
- │ Exception chaining raise X from Y │ 3.0+ │ Plain raise only
59
+ │ Exception chaining raise X from Y │ 3.0+ │ - done
92
60
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
93
61
  │ except* (exception groups) │ 3.11+ │ No support │
94
62
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
@@ -96,7 +64,7 @@ differences.
96
64
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
97
65
  │ Complex number literals 3+4j │ all │ No j suffix │
98
66
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
99
- │ Ellipsis literal ... as expression │ all │ Only valid as slice (a[...])
67
+ │ Ellipsis literal ... as expression │ all │ -tested
100
68
  ├───────────────────────────────────────────────┼────────────────┼──────────────────────────────────────────────────────────────┤
101
69
  │ b'...' bytes literals │ all │ No b prefix; encoding module exists but no native bytes type │
102
70
  └───────────────────────────────────────────────┴────────────────┴──────────────────────────────────────────────────────────────┘
@@ -313,7 +281,8 @@ If prioritizing what to implement next, these have the highest user impact:
313
281
 
314
282
  1. super() — required for idiomatic OOP code - done
315
283
  2. Operator overloading (__add__, __lt__, etc.) — blocks numerical/scientific code - done
316
- 3. __bool__ / truthiness fix — silent Python compatibility trap
284
+ 3. __bool__ / truthiness fix — silent Python compatibility trap - done
285
+ → frozenset — first medium-priority missing builtin - done
317
286
  4. lambda keyword — commonly expected - done
318
287
  5. all() / any() — extremely common builtins - done
319
288
  6. functools.reduce / partial — core functional programming tools - done
package/hack_demo.pyj ADDED
@@ -0,0 +1,112 @@
1
+ # Over-engineered RapydScript hacking script — Python features on parade
2
+
3
+ class HackAction:
4
+ """Enum-like action namespace."""
5
+ WEAKEN = 'weaken'
6
+ GROW = 'grow'
7
+ HACK = 'hack'
8
+
9
+ @staticmethod
10
+ def all():
11
+ return [HackAction.WEAKEN, HackAction.GROW, HackAction.HACK]
12
+
13
+
14
+ class ServerConfig:
15
+ """Data-class-style target config with property + fluent builder."""
16
+
17
+ def __init__(self, name, money_factor=1.0, sec_buffer=0.0):
18
+ self._name = name
19
+ self.money_factor = money_factor
20
+ self.sec_buffer = sec_buffer
21
+ self._tags = {'auto', 'hack'} # set literal
22
+
23
+ @property
24
+ def name(self):
25
+ return self._name
26
+
27
+ def __repr__(self):
28
+ return "ServerConfig(name={}, tags={})".format(
29
+ repr(self._name), sorted(list(self._tags))
30
+ )
31
+
32
+ def add_tags(self, *tags): # *args + fluent return
33
+ for t in tags:
34
+ self._tags.add(t)
35
+ return self
36
+
37
+
38
+ def decide_action(ns, target, money_thresh, sec_thresh):
39
+ """next() + generator expression to pick highest-priority action."""
40
+ checks = [
41
+ (ns.getServerSecurityLevel(target) > sec_thresh, HackAction.WEAKEN),
42
+ (ns.getServerMoneyAvailable(target) < money_thresh, HackAction.GROW),
43
+ ]
44
+ return next((action for cond, action in checks if cond), HackAction.HACK)
45
+
46
+
47
+ async def breach(ns, target, exploits):
48
+ """Apply available exploits via (exe, fn) tuple list, nuke, return summary."""
49
+ # list of (exe filename, bound ns method) tuples
50
+ exe_methods = [
51
+ ('BruteSSH.exe', ns.brutessh),
52
+ ('FTPCrack.exe', ns.ftpcrack),
53
+ ('relaySMTP.exe', ns.relaysmtp),
54
+ ]
55
+ applied = [fn for exe, fn in exe_methods if ns.fileExists(exe, "home")]
56
+ missing = [exe for exe, fn in exe_methods if not ns.fileExists(exe, "home")]
57
+
58
+ if missing:
59
+ ns.tprint("Missing: {}".format(', '.join(missing)))
60
+
61
+ for fn in applied:
62
+ fn(target)
63
+ ns.nuke(target)
64
+
65
+ return {'applied': len(applied), 'total': len(exploits),
66
+ 'rooted': ns.hasRootAccess(target)}
67
+
68
+
69
+ async def main(ns):
70
+ config = ServerConfig("n00dles").add_tags('target', 'beginner') # fluent
71
+ ns.tprint(repr(config)) # __repr__
72
+
73
+ target = config.name # @property
74
+ money_thresh = ns.getServerMaxMoney(target) * config.money_factor
75
+ sec_thresh = ns.getServerMinSecurityLevel(target) + config.sec_buffer
76
+
77
+ def by_name_len(p): # named key fn (required for
78
+ return len(p[0]) # anonymous fns in call args)
79
+ exploits = sorted([
80
+ ('brutessh', 'BruteSSH.exe'),
81
+ ('ftpcrack', 'FTPCrack.exe'),
82
+ ('relaysmtp', 'relaySMTP.exe'),
83
+ ], key=by_name_len)
84
+
85
+ result = await breach(ns, target, exploits)
86
+ ns.tprint("Breach: {applied}/{total} applied, rooted={rooted}".format(**result))
87
+ assert result['rooted'], "Root access denied on {}!".format(target)
88
+
89
+ dispatch = { # dict literal
90
+ 'weaken': ns.weaken,
91
+ 'grow': ns.grow,
92
+ 'hack': ns.hack,
93
+ }
94
+ stats = {a: 0 for a in HackAction.all()} # dict comprehension
95
+
96
+ cycle = 0
97
+ while True:
98
+ cycle += 1
99
+ action = decide_action(ns, target, money_thresh, sec_thresh)
100
+ stats[action] += 1
101
+
102
+ if cycle % 10 is 0: # periodic summary
103
+ counts = [stats[a] for a in HackAction.all()]
104
+ summary = ', '.join(["{}: {}".format(a, v)
105
+ for a, v in zip(HackAction.all(), counts)])
106
+ ns.tprint("Cycle {} | {} any={} all={}".format(
107
+ cycle, summary,
108
+ any([v > 0 for v in counts]), # any()
109
+ all([v > 0 for v in counts]) # all()
110
+ ))
111
+
112
+ await dispatch[action](target)
package/package.json CHANGED
@@ -9,6 +9,10 @@
9
9
  "compiler"
10
10
  ],
11
11
  "main": "tools/compiler.js",
12
+ "exports": {
13
+ ".": "./tools/compiler.js",
14
+ "./language-service": "./web-repl/language-service.js"
15
+ },
12
16
  "scripts": {
13
17
  "test": "node bin/rapydscript self --complete --test && npm run test:unit && npm run test:ls",
14
18
  "test:unit": "node test/unit/index.js",
@@ -16,9 +20,10 @@
16
20
  "start": "node bin/rapydscript",
17
21
  "build-self": "node bin/rapydscript self --complete",
18
22
  "build:ls": "node tools/build-language-service.js",
19
- "build": "rm -rf **/*pyj-cached dev && node bin/rapydscript self --complete && node bin/web-repl-export web-repl && node tools/build-language-service.js"
23
+ "build": "rm -rf **/*pyj-cached dev && node bin/rapydscript self --complete && node bin/web-repl-export web-repl && node tools/build-language-service.js",
24
+ "prepublishOnly": "node tools/build-language-service.js"
20
25
  },
21
- "version": "0.8.0",
26
+ "version": "0.8.2",
22
27
  "license": "BSD-2-Clause",
23
28
  "engines": {
24
29
  "node": ">=0.12.0"
@@ -37,9 +42,6 @@
37
42
  "regenerator": ">= 0.12.1",
38
43
  "uglify-js": ">= 3.0.15"
39
44
  },
40
- "optionalDependencies": {
41
- "v8-profiler": ">= 5.2.9"
42
- },
43
45
  "bin": {
44
46
  "rapydscript": "bin/rapydscript"
45
47
  }
package/src/ast.pyj CHANGED
@@ -159,6 +159,7 @@ class AST_Assert(AST_Statement):
159
159
  properties = {
160
160
  'condition': "[AST_Node] the expression that should be tested",
161
161
  'message': "[AST_Node*] the expression that is the error message or None",
162
+ 'python_truthiness': "[bool] Whether to use Python truthiness (from __python__ import truthiness)"
162
163
  }
163
164
 
164
165
  def _walk(self, visitor):
@@ -213,7 +214,8 @@ class AST_StatementWithBody(AST_Statement):
213
214
  class AST_DWLoop(AST_StatementWithBody):
214
215
  "Base class for do/while statements"
215
216
  properties = {
216
- 'condition': "[AST_Node] the loop condition. Should not be instanceof AST_Statement"
217
+ 'condition': "[AST_Node] the loop condition. Should not be instanceof AST_Statement",
218
+ 'python_truthiness': "[bool] Whether to use Python truthiness (from __python__ import truthiness)"
217
219
  }
218
220
 
219
221
  def _walk(self, visitor):
@@ -227,13 +229,25 @@ class AST_Do(AST_DWLoop):
227
229
 
228
230
  class AST_While(AST_DWLoop):
229
231
  "A `while` statement"
232
+ properties = {
233
+ 'belse': "[AST_Else?] the `else` clause, run when loop exits without `break`"
234
+ }
235
+
236
+ def _walk(self, visitor):
237
+ return visitor._visit(self, def():
238
+ self.condition._walk(visitor)
239
+ self.body._walk(visitor)
240
+ if self.belse:
241
+ self.belse._walk(visitor)
242
+ )
230
243
 
231
244
  class AST_ForIn(AST_StatementWithBody):
232
245
  "A `for ... in` statement"
233
246
  properties = {
234
247
  'init': "[AST_Node] the `for/in` initialization code",
235
248
  'name': "[AST_SymbolRef?] the loop variable, only if `init` is AST_Var",
236
- 'object': "[AST_Node] the object that we're looping through"
249
+ 'object': "[AST_Node] the object that we're looping through",
250
+ 'belse': "[AST_Else?] the `else` clause, run when no break occurred"
237
251
  }
238
252
 
239
253
  def _walk(self, visitor):
@@ -243,6 +257,8 @@ class AST_ForIn(AST_StatementWithBody):
243
257
  self.object._walk(visitor)
244
258
  if self.body:
245
259
  self.body._walk(visitor)
260
+ if self.belse:
261
+ self.belse._walk(visitor)
246
262
  )
247
263
 
248
264
  class AST_ForJS(AST_StatementWithBody):
@@ -647,6 +663,9 @@ class AST_Await(AST_Node):
647
663
 
648
664
  class AST_Throw(AST_Exit):
649
665
  "A `throw` statement"
666
+ properties = {
667
+ 'cause': "[AST_Node?] the __cause__ of the exception (from `raise X from Y`); may be None"
668
+ }
650
669
 
651
670
  class AST_LoopControl(AST_Jump):
652
671
  "Base class for loop control statements (`break` and `continue`)"
@@ -663,7 +682,8 @@ class AST_If(AST_StatementWithBody):
663
682
  "A `if` statement"
664
683
  properties = {
665
684
  'condition': "[AST_Node] the `if` condition",
666
- 'alternative': "[AST_Statement?] the `else` part, or null if not present"
685
+ 'alternative': "[AST_Statement?] the `else` part, or null if not present",
686
+ 'python_truthiness': "[bool] Whether to use Python truthiness (from __python__ import truthiness)"
667
687
  }
668
688
 
669
689
  def _walk(self, visitor):
@@ -767,7 +787,8 @@ class AST_BaseCall(AST_Node):
767
787
  class AST_Call(AST_BaseCall):
768
788
  "A function call expression"
769
789
  properties = {
770
- 'expression': "[AST_Node] expression to invoke as function"
790
+ 'expression': "[AST_Node] expression to invoke as function",
791
+ 'python_truthiness': "[bool] Whether to use Python truthiness for __call__ dispatch"
771
792
  }
772
793
 
773
794
  def _walk(self, visitor):
@@ -941,7 +962,8 @@ class AST_Unary(AST_Node):
941
962
  'operator': "[string] the operator",
942
963
  'expression': "[AST_Node] expression that this unary operator applies to",
943
964
  'parenthesized': "[bool] Whether this unary expression was parenthesized",
944
- 'overloaded': "[bool] Whether to use Python-style operator overloading dispatch"
965
+ 'overloaded': "[bool] Whether to use Python-style operator overloading dispatch",
966
+ 'python_truthiness': "[bool] Whether to use Python truthiness (from __python__ import truthiness)"
945
967
  }
946
968
 
947
969
  def _walk(self, visitor):
@@ -958,7 +980,8 @@ class AST_Binary(AST_Node):
958
980
  'left': "[AST_Node] left-hand side expression",
959
981
  'operator': "[string] the operator",
960
982
  'right': "[AST_Node] right-hand side expression",
961
- 'overloaded': "[bool] Whether to use Python-style operator overloading dispatch"
983
+ 'overloaded': "[bool] Whether to use Python-style operator overloading dispatch",
984
+ 'python_truthiness': "[bool] Whether to use Python truthiness (from __python__ import truthiness)"
962
985
  }
963
986
 
964
987
  def _walk(self, visitor):
@@ -987,6 +1010,7 @@ class AST_Conditional(AST_Node):
987
1010
  'condition': "[AST_Node]",
988
1011
  'consequent': "[AST_Node]",
989
1012
  'alternative': "[AST_Node]",
1013
+ 'python_truthiness': "[bool] Whether to use Python truthiness (from __python__ import truthiness)"
990
1014
  }
991
1015
 
992
1016
  def _walk(self, visitor):
@@ -5,7 +5,21 @@
5
5
  # globals: exports, console, ρσ_iterator_symbol, ρσ_kwargs_symbol, ρσ_arraylike, ρσ_list_contains
6
6
 
7
7
  def ρσ_bool(val):
8
- return v'!!val'
8
+ # Python truthiness — written entirely with verbatim JS so that the
9
+ # compiled ρσ_bool function never calls itself (no bootstrap recursion).
10
+ v'if (val === null || val === undefined) return false'
11
+ v'var ρσ_bool_t = typeof val'
12
+ v'if (ρσ_bool_t === "boolean") return val'
13
+ v'if (ρσ_bool_t === "number") return val !== 0'
14
+ v'if (ρσ_bool_t === "string") return val.length > 0'
15
+ v'if (ρσ_bool_t === "function") return true'
16
+ v'if (val.constructor && val.constructor.prototype === val) return true'
17
+ v'if (typeof val.__bool__ === "function") return !!val.__bool__()'
18
+ v'if (Array.isArray(val)) return val.length > 0'
19
+ v'if (typeof val.__len__ === "function") return val.__len__() > 0'
20
+ v'if ((typeof Set === "function" && val instanceof Set) || (typeof Map === "function" && val instanceof Map)) return val.size > 0'
21
+ v'if (!val.constructor || val.constructor === Object) return Object.keys(val).length > 0'
22
+ return True
9
23
 
10
24
  def ρσ_print(*args, **kwargs):
11
25
  if v'typeof console' is 'object':
@@ -73,7 +87,24 @@ def ρσ_chr(code):
73
87
  return String.fromCharCode(0xD800+(code>>10), 0xDC00+(code&0x3FF))
74
88
 
75
89
  def ρσ_callable(x):
76
- return v'typeof x === "function"'
90
+ return v'typeof x === "function" || (x !== null && x !== undefined && typeof x.__call__ === "function")'
91
+
92
+ def ρσ_callable_call(fn):
93
+ # Dispatch fn(args): check __call__ first (callable objects), then direct call.
94
+ # __call__ is checked first so callable objects (not functions) are dispatched correctly.
95
+ args = v'Array.prototype.slice.call(arguments, 1)'
96
+ if v'fn !== null && fn !== undefined && typeof fn.__call__ === "function"':
97
+ return v'fn.__call__.apply(fn, args)'
98
+ if v'typeof fn === "function"':
99
+ return v'fn.apply(undefined, args)'
100
+ raise TypeError('object is not callable')
101
+
102
+
103
+ def ρσ_round(x, ndigits):
104
+ if ndigits is undefined or ndigits is 0:
105
+ return Math.round(x)
106
+ factor = Math.pow(10, ndigits)
107
+ return Math.round(x * factor) / factor
77
108
 
78
109
  def ρσ_bin(x):
79
110
  if jstype(x) is not 'number' or x % 1 is not 0:
@@ -95,15 +126,17 @@ def ρσ_hex(x):
95
126
  ans = '0x' + ans
96
127
  return ans
97
128
 
98
- def ρσ_enumerate(iterable):
99
- ans = v'{"_i":-1}'
129
+ def ρσ_enumerate(iterable, start):
130
+ offset = 0 if start is undefined else start
131
+ ans = {'_i': offset - 1}
100
132
  ans[ρσ_iterator_symbol] = def():
101
133
  return this
102
134
  if ρσ_arraylike(iterable):
103
135
  ans['next'] = def():
104
136
  this._i += 1
105
- if this._i < iterable.length:
106
- return v"{'done':false, 'value':[this._i, iterable[this._i]]}"
137
+ idx = this._i - offset
138
+ if idx < iterable.length:
139
+ return {'done': False, 'value': [this._i, iterable[idx]]}
107
140
  return v"{'done':true}"
108
141
  return ans
109
142
  if jstype(iterable[ρσ_iterator_symbol]) is 'function':
@@ -114,9 +147,9 @@ def ρσ_enumerate(iterable):
114
147
  if r.done:
115
148
  return v"{'done':true}"
116
149
  this._i += 1
117
- return v"{'done':false, 'value':[this._i, r.value]}"
150
+ return {'done': False, 'value': [this._i, r.value]}
118
151
  return ans
119
- return ρσ_enumerate(Object.keys(iterable))
152
+ return ρσ_enumerate(Object.keys(iterable), start)
120
153
 
121
154
  def ρσ_reversed(iterable):
122
155
  if ρσ_arraylike(iterable):
@@ -244,6 +277,67 @@ def ρσ_type(x):
244
277
  return x.constructor
245
278
 
246
279
 
280
+ def ρσ_issubclass(cls, base):
281
+ if Array.isArray(base):
282
+ for b in base:
283
+ if ρσ_issubclass(cls, b):
284
+ return True
285
+ return False
286
+ if jstype(cls) is not 'function':
287
+ raise TypeError('issubclass() arg 1 must be a class')
288
+ if jstype(base) is not 'function':
289
+ raise TypeError('issubclass() arg 2 must be a class')
290
+ if cls is base:
291
+ return True
292
+ v'var proto = cls.prototype; while (proto !== null && proto !== undefined) { if (proto === base.prototype) return true; proto = Object.getPrototypeOf(proto); }'
293
+ return False
294
+
295
+
296
+ v'var ρσ_hash_id_counter = 0'
297
+
298
+ def ρσ_hash(obj):
299
+ v'var ρσ_t = typeof obj'
300
+ v'if (obj === null || obj === undefined) return 0'
301
+ v'if (ρσ_t === "boolean") return obj ? 1 : 0'
302
+ v'if (ρσ_t === "number") { return (obj === Math.floor(obj)) ? (obj | 0) : ((obj * 2654435761) | 0); }'
303
+ v'''if (ρσ_t === "string") {
304
+ var ρσ_h = 5381;
305
+ for (var ρσ_i = 0; ρσ_i < obj.length; ρσ_i++) {
306
+ ρσ_h = (((ρσ_h << 5) + ρσ_h) ^ obj.charCodeAt(ρσ_i)) | 0;
307
+ }
308
+ return ρσ_h;
309
+ }'''
310
+ v'if (typeof obj.__hash__ === "function") return obj.__hash__()'
311
+ v'if (Array.isArray(obj)) throw new TypeError("unhashable type: \'list\'")'
312
+ v'if (typeof ρσ_set === "function" && obj instanceof ρσ_set) throw new TypeError("unhashable type: \'set\'")'
313
+ v'if (typeof Set === "function" && obj instanceof Set) throw new TypeError("unhashable type: \'set\'")'
314
+ v'if (typeof ρσ_dict === "function" && obj instanceof ρσ_dict) throw new TypeError("unhashable type: \'dict\'")'
315
+ v'if (typeof Map === "function" && obj instanceof Map) throw new TypeError("unhashable type: \'dict\'")'
316
+ v'if (!obj.constructor || obj.constructor === Object) throw new TypeError("unhashable type: \'dict\'")'
317
+ v'if (obj.ρσ_object_id === undefined) obj.ρσ_object_id = ++ρσ_hash_id_counter'
318
+ v'return obj.ρσ_object_id'
319
+
320
+
321
+ def ρσ_next(iterator, defval):
322
+ if iterator is None or iterator is undefined:
323
+ raise TypeError('object is not an iterator')
324
+ if jstype(iterator.next) is 'function':
325
+ r = iterator.next()
326
+ if r.done:
327
+ if arguments.length > 1:
328
+ return defval
329
+ raise StopIteration()
330
+ return r.value
331
+ if jstype(iterator.__next__) is 'function':
332
+ try:
333
+ return iterator.__next__()
334
+ except StopIteration:
335
+ if arguments.length > 1:
336
+ return defval
337
+ raise
338
+ raise TypeError("object is not an iterator")
339
+
340
+
247
341
  def ρσ_divmod(x, y):
248
342
  if y is 0:
249
343
  raise ZeroDivisionError('integer division or modulo by zero')
@@ -272,8 +366,8 @@ def ρσ_max(*args, **kwargs):
272
366
  v'var abs = Math.abs, max = ρσ_max.bind(Math.max), min = ρσ_max.bind(Math.min), bool = ρσ_bool, type = ρσ_type'
273
367
  v'var float = ρσ_float, int = ρσ_int, arraylike = ρσ_arraylike_creator(), ρσ_arraylike = arraylike'
274
368
  v'var id = ρσ_id, get_module = ρσ_get_module, pow = ρσ_pow, divmod = ρσ_divmod'
275
- v'var dir = ρσ_dir, ord = ρσ_ord, chr = ρσ_chr, bin = ρσ_bin, hex = ρσ_hex, callable = ρσ_callable'
369
+ v'var dir = ρσ_dir, ord = ρσ_ord, chr = ρσ_chr, bin = ρσ_bin, hex = ρσ_hex, callable = ρσ_callable, round = ρσ_round'
276
370
  v'var enumerate = ρσ_enumerate, iter = ρσ_iter, reversed = ρσ_reversed, len = ρσ_len'
277
- v'var range = ρσ_range, getattr = ρσ_getattr, setattr = ρσ_setattr, hasattr = ρσ_hasattr'
371
+ v'var range = ρσ_range, getattr = ρσ_getattr, setattr = ρσ_setattr, hasattr = ρσ_hasattr, issubclass = ρσ_issubclass, hash = ρσ_hash, next = ρσ_next'
278
372
  v'var ρσ_Ellipsis = Object.freeze({toString: function(){return "Ellipsis";}, __repr__: function(){return "Ellipsis";}})'
279
373
  v'var Ellipsis = ρσ_Ellipsis'