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.
Files changed (72) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1351 -141
  3. package/TODO.md +12 -6
  4. package/language-service/index.js +184 -26
  5. package/package.json +1 -1
  6. package/release/baselib-plain-pretty.js +5895 -1928
  7. package/release/baselib-plain-ugly.js +140 -3
  8. package/release/compiler.js +16282 -5408
  9. package/release/signatures.json +25 -22
  10. package/src/ast.pyj +94 -1
  11. package/src/baselib-builtins.pyj +362 -3
  12. package/src/baselib-bytes.pyj +664 -0
  13. package/src/baselib-containers.pyj +99 -0
  14. package/src/baselib-errors.pyj +45 -1
  15. package/src/baselib-internal.pyj +346 -49
  16. package/src/baselib-itertools.pyj +17 -4
  17. package/src/baselib-str.pyj +46 -4
  18. package/src/lib/abc.pyj +317 -0
  19. package/src/lib/copy.pyj +120 -0
  20. package/src/lib/dataclasses.pyj +532 -0
  21. package/src/lib/enum.pyj +125 -0
  22. package/src/lib/pythonize.pyj +1 -1
  23. package/src/lib/re.pyj +35 -1
  24. package/src/lib/react.pyj +74 -0
  25. package/src/lib/typing.pyj +577 -0
  26. package/src/monaco-language-service/builtins.js +19 -4
  27. package/src/monaco-language-service/diagnostics.js +40 -19
  28. package/src/output/classes.pyj +161 -25
  29. package/src/output/codegen.pyj +16 -2
  30. package/src/output/exceptions.pyj +97 -1
  31. package/src/output/functions.pyj +87 -5
  32. package/src/output/jsx.pyj +164 -0
  33. package/src/output/literals.pyj +28 -2
  34. package/src/output/loops.pyj +5 -2
  35. package/src/output/modules.pyj +1 -1
  36. package/src/output/operators.pyj +108 -36
  37. package/src/output/statements.pyj +2 -2
  38. package/src/output/stream.pyj +1 -0
  39. package/src/parse.pyj +496 -128
  40. package/src/tokenizer.pyj +38 -4
  41. package/test/abc.pyj +291 -0
  42. package/test/arithmetic_nostrict.pyj +88 -0
  43. package/test/arithmetic_types.pyj +169 -0
  44. package/test/baselib.pyj +91 -0
  45. package/test/bytes.pyj +467 -0
  46. package/test/classes.pyj +1 -0
  47. package/test/comparison_ops.pyj +173 -0
  48. package/test/dataclasses.pyj +253 -0
  49. package/test/enum.pyj +134 -0
  50. package/test/eval_exec.pyj +56 -0
  51. package/test/format.pyj +148 -0
  52. package/test/object.pyj +64 -0
  53. package/test/python_compat.pyj +17 -15
  54. package/test/python_features.pyj +89 -21
  55. package/test/regexp.pyj +29 -1
  56. package/test/tuples.pyj +96 -0
  57. package/test/typing.pyj +469 -0
  58. package/test/unit/index.js +2292 -70
  59. package/test/unit/language-service.js +674 -4
  60. package/test/unit/web-repl.js +1106 -0
  61. package/test/vars_locals_globals.pyj +94 -0
  62. package/tools/cli.js +11 -0
  63. package/tools/compile.js +5 -0
  64. package/tools/embedded_compiler.js +15 -4
  65. package/tools/lint.js +16 -19
  66. package/tools/repl.js +1 -1
  67. package/web-repl/env.js +122 -0
  68. package/web-repl/main.js +1 -3
  69. package/web-repl/rapydscript.js +125 -3
  70. package/PYTHON_DIFFERENCES_REPORT.md +0 -291
  71. package/PYTHON_FEATURE_COVERAGE.md +0 -200
  72. package/hack_demo.pyj +0 -112
@@ -0,0 +1,94 @@
1
+ # vim:fileencoding=utf-8
2
+ # globals: assrt
3
+ from __python__ import overload_getitem
4
+
5
+ ae = assrt.equal
6
+ ade = assrt.deepEqual
7
+ ok = assrt.ok
8
+
9
+ # ── vars(obj) — instance attribute snapshot ───────────────────────────────────
10
+
11
+ class Point:
12
+ def __init__(self, x, y):
13
+ self.x = x
14
+ self.y = y
15
+
16
+ p = Point(3, 4)
17
+ d = vars(p)
18
+ ae(d['x'], 3)
19
+ ae(d['y'], 4)
20
+
21
+ # all instance attrs present, no extras
22
+ keys = list(d.keys())
23
+ keys.sort()
24
+ ade(keys, ['x', 'y'])
25
+
26
+ # snapshot: mutating the result does NOT affect the original object
27
+ d['x'] = 99
28
+ ae(p.x, 3)
29
+
30
+ # works for arbitrary objects with instance attrs
31
+ class Config:
32
+ def __init__(self):
33
+ self.debug = True
34
+ self.level = 5
35
+ self.name = 'test'
36
+
37
+ cfg = Config()
38
+ cv = vars(cfg)
39
+ ae(cv['debug'], True)
40
+ ae(cv['level'], 5)
41
+ ae(cv['name'], 'test')
42
+
43
+ # ── vars(obj) — object updated after snapshot ─────────────────────────────────
44
+
45
+ class Box:
46
+ def __init__(self, value):
47
+ self.value = value
48
+
49
+ b = Box(10)
50
+ snap1 = vars(b)
51
+ b.value = 20
52
+ snap2 = vars(b)
53
+ ae(snap1['value'], 10) # old snapshot unchanged
54
+ ae(snap2['value'], 20) # new snapshot reflects update
55
+
56
+ # ── vars() with no argument — returns vars(this) ─────────────────────────────
57
+
58
+ class WithMethod:
59
+ def __init__(self):
60
+ self.a = 1
61
+ self.b = 2
62
+
63
+ def get_vars(self):
64
+ return vars()
65
+
66
+ wm = WithMethod()
67
+ wv = wm.get_vars()
68
+ ae(wv['a'], 1)
69
+ ae(wv['b'], 2)
70
+
71
+ # ── locals() — returns empty dict (JS scope not introspectable) ───────────────
72
+
73
+ loc = locals()
74
+ ok(loc is not None)
75
+ ok(len(list(loc.keys())) is 0)
76
+
77
+ # ── globals() — returns a dict of the JS global namespace ────────────────────
78
+
79
+ g = globals()
80
+ ok(g is not None)
81
+ # Should be dict-like (has .keys())
82
+ gkeys = list(g.keys())
83
+ ok(gkeys.length >= 0)
84
+ # Built-in globals (non-enumerable on globalThis) must be present
85
+ ok('Math' in g)
86
+ ok('Object' in g)
87
+ ok('Array' in g)
88
+
89
+ # ── vars/locals/globals return proper dict instances ─────────────────────────
90
+
91
+ ok(isinstance(vars(Point(1, 2)), dict))
92
+ ok(isinstance(vars(), dict))
93
+ ok(isinstance(locals(), dict))
94
+ ok(isinstance(globals(), dict))
package/tools/cli.js CHANGED
@@ -360,6 +360,17 @@ hash_literals, overload_operators. Prefix a flag with no_ to
360
360
  explicitly disable it (e.g. no_bound_methods).
361
361
  */});
362
362
 
363
+ opt("legacy_rapydscript", "L", 'bool', false, function(){/*
364
+ Use legacy RapydScript behavior (disabled by default). When set to
365
+ true (--legacy-rapydscript), preserves legacy RapydScript behavior
366
+ with no Python compatibility flags enabled by default. When false
367
+ (the default), enables all Python compatibility flags globally
368
+ (dict_literals, overload_getitem, bound_methods, hash_literals,
369
+ overload_operators, truthiness, jsx) and patches String.prototype
370
+ with Python string methods at startup, equivalent to:
371
+ from pythonize import strings; strings()
372
+ */});
373
+
363
374
  create_group('repl', '', function(){/*
364
375
  Run a Read-Eval-Print-Loop (REPL). This allows
365
376
  you to type and run RapydScript at a live
package/tools/compile.js CHANGED
@@ -75,6 +75,11 @@ module.exports = function(start_time, argv, base_path, src_path, lib_path) {
75
75
  var num_of_files = files.length || 1;
76
76
 
77
77
  var global_scoped_flags = build_scoped_flags(argv.python_flags);
78
+ if (!argv.legacy_rapydscript) {
79
+ var python_mode_flags = ['dict_literals', 'overload_getitem', 'bound_methods', 'hash_literals', 'overload_operators', 'truthiness', 'jsx'];
80
+ python_mode_flags.forEach(function(f) { if (!(f in global_scoped_flags)) global_scoped_flags[f] = true; });
81
+ if (!argv.pythonize_strings) OUTPUT_OPTIONS.pythonize_strings = true;
82
+ }
78
83
 
79
84
  function parse_file(code, file, toplevel) {
80
85
  return RapydScript.parse(code, {
@@ -7,6 +7,7 @@
7
7
  "use strict"; /*jshint node:true */
8
8
 
9
9
  var has_prop = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
10
+ var PYTHON_MODE_FLAGS = ['dict_literals', 'overload_getitem', 'bound_methods', 'hash_literals', 'overload_operators', 'truthiness', 'jsx'];
10
11
 
11
12
  function build_scoped_flags(flags_str) {
12
13
  var result = Object.create(null);
@@ -134,8 +135,12 @@ module.exports = function(compiler, baselib, runjs, name, vf_context) {
134
135
  opts = opts || {};
135
136
  var classes = (this.toplevel) ? this.toplevel.classes : undefined;
136
137
  var inherited_flags = (this.toplevel) ? this.toplevel.scoped_flags : undefined;
138
+ var base_flags = Object.create(null);
139
+ if (opts.legacy_rapydscript !== true) {
140
+ PYTHON_MODE_FLAGS.forEach(function(f) { base_flags[f] = true; });
141
+ }
137
142
  var scoped_flags = Object.assign(
138
- Object.create(null),
143
+ base_flags,
139
144
  opts.python_flags ? build_scoped_flags(opts.python_flags) : {},
140
145
  inherited_flags || {}
141
146
  );
@@ -165,7 +170,8 @@ module.exports = function(compiler, baselib, runjs, name, vf_context) {
165
170
  libdir: undefined,
166
171
  });
167
172
  }
168
- var ans = print_ast(this.toplevel, opts.keep_baselib, opts.keep_docstrings, opts.js_version, opts.private_scope, opts.write_name, opts.omit_function_metadata, opts.pythonize_strings);
173
+ var pythonize_strings = (opts.legacy_rapydscript !== true) ? true : !!opts.pythonize_strings;
174
+ var ans = print_ast(this.toplevel, opts.keep_baselib, opts.keep_docstrings, opts.js_version, opts.private_scope, opts.write_name, opts.omit_function_metadata, pythonize_strings);
169
175
  if (opts.export_main) {
170
176
  ans = ans.replace(/^(function\smain)/gm, 'export $1')
171
177
  .replace(/^(async\sfunction\smain)/gm, 'export $1');
@@ -188,8 +194,12 @@ module.exports = function(compiler, baselib, runjs, name, vf_context) {
188
194
  opts = opts || {};
189
195
  var classes = (this.toplevel) ? this.toplevel.classes : undefined;
190
196
  var inherited_flags = (this.toplevel) ? this.toplevel.scoped_flags : undefined;
197
+ var base_flags_sm = Object.create(null);
198
+ if (opts.legacy_rapydscript !== true) {
199
+ PYTHON_MODE_FLAGS.forEach(function(f) { base_flags_sm[f] = true; });
200
+ }
191
201
  var scoped_flags = Object.assign(
192
- Object.create(null),
202
+ base_flags_sm,
193
203
  opts.python_flags ? build_scoped_flags(opts.python_flags) : {},
194
204
  inherited_flags || {}
195
205
  );
@@ -219,11 +229,12 @@ module.exports = function(compiler, baselib, runjs, name, vf_context) {
219
229
  libdir: undefined,
220
230
  });
221
231
  }
232
+ var pythonize_strings_sm = (opts.legacy_rapydscript !== true) ? true : !!opts.pythonize_strings;
222
233
  var result = print_ast_with_sourcemap(
223
234
  this.toplevel,
224
235
  opts.keep_baselib, opts.keep_docstrings, opts.js_version,
225
236
  opts.private_scope, opts.write_name, opts.omit_function_metadata,
226
- opts.pythonize_strings,
237
+ pythonize_strings_sm,
227
238
  opts.filename || '<input>',
228
239
  code
229
240
  );
package/tools/lint.js CHANGED
@@ -39,7 +39,7 @@ var BUILTINS = Object.create(null);
39
39
  ' NodeList alert console Node Symbol NamedNodeMap ρσ_eslice ρσ_delslice Number' +
40
40
  ' Boolean encodeURIComponent decodeURIComponent setTimeout setInterval' +
41
41
  ' setImmediate clearTimeout clearInterval clearImmediate requestAnimationFrame' +
42
- ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN Ellipsis'
42
+ ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN Ellipsis bytes bytearray'
43
43
  ).split(' ').forEach(function(x) { BUILTINS[x] = true; });
44
44
 
45
45
  Object.keys(RapydScript.NATIVE_CLASSES).forEach(function (name) { BUILTINS[name] = true; });
@@ -353,28 +353,25 @@ function Linter(toplevel, filename, code, options) {
353
353
 
354
354
  this.handle_for_in = function() {
355
355
  var node = this.current_node;
356
+ var self = this;
357
+ var add_loop_var = function(cnode) {
358
+ if (cnode instanceof RapydScript.AST_Seq) {
359
+ cnode.to_array().forEach(add_loop_var);
360
+ } else if (cnode instanceof RapydScript.AST_Array) {
361
+ cnode.elements.forEach(add_loop_var);
362
+ } else if (cnode instanceof RapydScript.AST_SymbolRef) {
363
+ self.current_node = cnode;
364
+ cnode.lint_visited = true;
365
+ self.add_binding(cnode.name).is_loop = true;
366
+ self.current_node = node;
367
+ }
368
+ };
356
369
  if (node.init instanceof RapydScript.AST_SymbolRef) {
357
370
  this.add_binding(node.init.name).is_loop = true;
358
371
  node.init.lint_visited = true;
359
372
  } else if (node.init instanceof RapydScript.AST_Array) {
360
- // destructuring assignment: for a, b in []
361
- for (var i = 0; i < node.init.elements.length; i++) {
362
- var cnode = node.init.elements[i];
363
- if (cnode instanceof RapydScript.AST_Seq) cnode = cnode.to_array();
364
- if (cnode instanceof RapydScript.AST_SymbolRef) cnode = [cnode];
365
- if (Array.isArray(cnode)) {
366
- for (var j = 0; j < cnode.length; j++) {
367
- var elem = cnode[j];
368
- if (elem instanceof RapydScript.AST_SymbolRef) {
369
- this.current_node = elem;
370
- elem.lint_visited = true;
371
- this.add_binding(elem.name).is_loop = true;
372
- this.current_node = node;
373
- }
374
- }
375
- }
376
- }
377
-
373
+ // destructuring assignment: for a, b in [] or for (a, b), c in []
374
+ node.init.elements.forEach(add_loop_var);
378
375
  }
379
376
  };
380
377
 
package/tools/repl.js CHANGED
@@ -93,7 +93,7 @@ module.exports = function(options) {
93
93
  options.console.log();
94
94
 
95
95
  function print_ast(ast, keep_baselib) {
96
- var output_options = {omit_baselib:!keep_baselib, write_name:false, private_scope:false, beautify:true, keep_docstrings:true};
96
+ var output_options = {omit_baselib:!keep_baselib, write_name:false, private_scope:false, beautify:true, keep_docstrings:true, repl_mode:true};
97
97
  if (keep_baselib) output_options.baselib_plain = fs.readFileSync(path.join(options.lib_path, 'baselib-plain-pretty.js'), 'utf-8');
98
98
  var output = new RapydScript.OutputStream(output_options);
99
99
  ast.print(output);
package/web-repl/env.js CHANGED
@@ -27,6 +27,128 @@ var builtin_modules = {
27
27
  if(!ctx) ctx = {};
28
28
  if (!ctx.sha1sum) ctx.sha1sum = sha1sum;
29
29
  if (!ctx.require) ctx.require = require;
30
+ if (!ctx.React) ctx.React = (function() {
31
+ var Fragment = Symbol('React.Fragment');
32
+
33
+ function createElement(type, props) {
34
+ var children = Array.prototype.slice.call(arguments, 2);
35
+ return {
36
+ type: type,
37
+ props: Object.assign({children: children.length === 1 ? children[0] : children}, props)
38
+ };
39
+ }
40
+
41
+ // Minimal hook stubs — enough to run REPL snippets without React DOM.
42
+ function useState(initial) {
43
+ var state = (typeof initial === 'function') ? initial() : initial;
44
+ return [state, function(v) { state = (typeof v === 'function') ? v(state) : v; }];
45
+ }
46
+
47
+ function useEffect(fn /*, deps */) {
48
+ var cleanup = fn();
49
+ // cleanup would be called on unmount; ignored in stub
50
+ }
51
+
52
+ function useLayoutEffect(fn /*, deps */) { fn(); }
53
+
54
+ function useMemo(fn /*, deps */) { return fn(); }
55
+
56
+ function useCallback(fn /*, deps */) { return fn; }
57
+
58
+ function useRef(initial) { return { current: initial }; }
59
+
60
+ function useContext(ctx) { return ctx && ctx._currentValue !== undefined ? ctx._currentValue : undefined; }
61
+
62
+ function useReducer(reducer, initial, init) {
63
+ var state = (init !== undefined) ? init(initial) : initial;
64
+ return [state, function(action) { state = reducer(state, action); }];
65
+ }
66
+
67
+ function useImperativeHandle(ref, create /*, deps */) {
68
+ if (ref) ref.current = create();
69
+ }
70
+
71
+ function useDebugValue() {}
72
+
73
+ function useId() { return ':r' + (Math.random() * 1e9 | 0) + ':'; }
74
+
75
+ function useTransition() { return [false, function(fn) { fn(); }]; }
76
+
77
+ function useDeferredValue(value) { return value; }
78
+
79
+ function useSyncExternalStore(subscribe, getSnapshot) { return getSnapshot(); }
80
+
81
+ function useInsertionEffect(fn /*, deps */) { fn(); }
82
+
83
+ function createContext(defaultValue) {
84
+ return { _currentValue: defaultValue, Provider: function(props) { return props.children; }, Consumer: function(props) { return props.children(defaultValue); } };
85
+ }
86
+
87
+ function createRef() { return { current: null }; }
88
+
89
+ function forwardRef(render) {
90
+ return function(props) { return render(props, null); };
91
+ }
92
+
93
+ function memo(Component /*, compare */) { return Component; }
94
+
95
+ function lazy(factory) { return factory; }
96
+
97
+ function cloneElement(element, props) {
98
+ return Object.assign({}, element, { props: Object.assign({}, element.props, props) });
99
+ }
100
+
101
+ function isValidElement(obj) {
102
+ return obj !== null && typeof obj === 'object' && obj.type !== undefined;
103
+ }
104
+
105
+ function Component() {}
106
+ Component.prototype.render = function() { return null; };
107
+ Component.prototype.setState = function(update) {
108
+ var next = (typeof update === 'function') ? update(this.state) : update;
109
+ this.state = Object.assign({}, this.state, next);
110
+ };
111
+
112
+ function PureComponent() {}
113
+ PureComponent.prototype = Object.create(Component.prototype);
114
+ PureComponent.prototype.constructor = PureComponent;
115
+
116
+ var StrictMode = { type: Symbol('React.StrictMode') };
117
+ var Suspense = { type: Symbol('React.Suspense') };
118
+ var Profiler = { type: Symbol('React.Profiler') };
119
+
120
+ return {
121
+ Fragment: Fragment,
122
+ createElement: createElement,
123
+ useState: useState,
124
+ useEffect: useEffect,
125
+ useLayoutEffect: useLayoutEffect,
126
+ useMemo: useMemo,
127
+ useCallback: useCallback,
128
+ useRef: useRef,
129
+ useContext: useContext,
130
+ useReducer: useReducer,
131
+ useImperativeHandle: useImperativeHandle,
132
+ useDebugValue: useDebugValue,
133
+ useId: useId,
134
+ useTransition: useTransition,
135
+ useDeferredValue: useDeferredValue,
136
+ useSyncExternalStore: useSyncExternalStore,
137
+ useInsertionEffect: useInsertionEffect,
138
+ createContext: createContext,
139
+ createRef: createRef,
140
+ forwardRef: forwardRef,
141
+ memo: memo,
142
+ lazy: lazy,
143
+ cloneElement: cloneElement,
144
+ isValidElement: isValidElement,
145
+ Component: Component,
146
+ PureComponent: PureComponent,
147
+ StrictMode: StrictMode,
148
+ Suspense: Suspense,
149
+ Profiler: Profiler,
150
+ };
151
+ })();
30
152
  Object.keys(ctx).forEach(function(k) { win[k] = ctx[k]; });
31
153
  return win;
32
154
  },
package/web-repl/main.js CHANGED
@@ -18,9 +18,7 @@
18
18
  };
19
19
 
20
20
  function compile(code) {
21
- const codeWithoutVariableTypeDefinitions = code.replace(/^ *(?!def\s)([\w.-]+) *: *[\w.-]+ *[:+*\/%&|^><-]*=/gm, '$1');
22
- var pythonize_strings = !!(document.getElementById('pythonize_strings') || {}).checked;
23
- return web_repl.compile(codeWithoutVariableTypeDefinitions, {omit_function_metadata: false, tree_shake: false, export_main: true, virtual_files: VIRTUAL_FILES, pythonize_strings: pythonize_strings});
21
+ return web_repl.compile(code, {omit_function_metadata: false, tree_shake: false, export_main: true, virtual_files: VIRTUAL_FILES, legacy_rapydscript: false});
24
22
  }
25
23
 
26
24
  function runjs(code) {