rapydscript-ns 0.8.2 → 0.8.4

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 (141) hide show
  1. package/.agignore +1 -1
  2. package/.github/workflows/ci.yml +38 -38
  3. package/=template.pyj +5 -5
  4. package/CHANGELOG.md +39 -0
  5. package/HACKING.md +103 -103
  6. package/LICENSE +24 -24
  7. package/PYTHON_DIFFERENCES_REPORT.md +291 -0
  8. package/PYTHON_FEATURE_COVERAGE.md +106 -15
  9. package/README.md +831 -52
  10. package/TODO.md +4 -286
  11. package/add-toc-to-readme +2 -2
  12. package/bin/export +75 -75
  13. package/bin/rapydscript +70 -70
  14. package/bin/web-repl-export +102 -102
  15. package/build +2 -2
  16. package/language-service/index.js +4623 -0
  17. package/language-service/language-service.d.ts +40 -0
  18. package/package.json +9 -7
  19. package/publish.py +37 -37
  20. package/release/baselib-plain-pretty.js +2006 -229
  21. package/release/baselib-plain-ugly.js +70 -3
  22. package/release/compiler.js +11554 -3870
  23. package/release/signatures.json +31 -29
  24. package/session.vim +4 -4
  25. package/setup.cfg +2 -2
  26. package/src/ast.pyj +93 -1
  27. package/src/baselib-builtins.pyj +99 -2
  28. package/src/baselib-containers.pyj +107 -4
  29. package/src/baselib-errors.pyj +44 -0
  30. package/src/baselib-internal.pyj +124 -5
  31. package/src/baselib-itertools.pyj +97 -97
  32. package/src/baselib-str.pyj +32 -1
  33. package/src/compiler.pyj +36 -36
  34. package/src/errors.pyj +30 -30
  35. package/src/lib/aes.pyj +646 -646
  36. package/src/lib/collections.pyj +1 -1
  37. package/src/lib/copy.pyj +120 -0
  38. package/src/lib/elementmaker.pyj +83 -83
  39. package/src/lib/encodings.pyj +126 -126
  40. package/src/lib/gettext.pyj +569 -569
  41. package/src/lib/itertools.pyj +580 -580
  42. package/src/lib/math.pyj +193 -193
  43. package/src/lib/numpy.pyj +10 -10
  44. package/src/lib/operator.pyj +11 -11
  45. package/src/lib/pythonize.pyj +20 -20
  46. package/src/lib/random.pyj +118 -118
  47. package/src/lib/re.pyj +470 -470
  48. package/src/lib/react.pyj +74 -0
  49. package/src/lib/traceback.pyj +63 -63
  50. package/src/lib/uuid.pyj +77 -77
  51. package/src/monaco-language-service/analyzer.js +131 -9
  52. package/src/monaco-language-service/builtins.js +17 -2
  53. package/src/monaco-language-service/completions.js +170 -1
  54. package/src/monaco-language-service/diagnostics.js +25 -3
  55. package/src/monaco-language-service/dts.js +550 -550
  56. package/src/monaco-language-service/index.js +17 -0
  57. package/src/monaco-language-service/scope.js +3 -0
  58. package/src/output/classes.pyj +128 -11
  59. package/src/output/codegen.pyj +17 -3
  60. package/src/output/comments.pyj +45 -45
  61. package/src/output/exceptions.pyj +201 -105
  62. package/src/output/functions.pyj +13 -16
  63. package/src/output/jsx.pyj +164 -0
  64. package/src/output/literals.pyj +28 -2
  65. package/src/output/loops.pyj +0 -9
  66. package/src/output/modules.pyj +2 -5
  67. package/src/output/operators.pyj +22 -2
  68. package/src/output/statements.pyj +2 -2
  69. package/src/output/stream.pyj +1 -13
  70. package/src/output/treeshake.pyj +182 -182
  71. package/src/output/utils.pyj +72 -72
  72. package/src/parse.pyj +434 -114
  73. package/src/string_interpolation.pyj +72 -72
  74. package/src/tokenizer.pyj +29 -0
  75. package/src/unicode_aliases.pyj +576 -576
  76. package/src/utils.pyj +192 -192
  77. package/test/_import_one.pyj +37 -37
  78. package/test/_import_two/__init__.pyj +11 -11
  79. package/test/_import_two/level2/deep.pyj +4 -4
  80. package/test/_import_two/other.pyj +6 -6
  81. package/test/_import_two/sub.pyj +13 -13
  82. package/test/aes_vectors.pyj +421 -421
  83. package/test/annotations.pyj +80 -80
  84. package/test/baselib.pyj +4 -4
  85. package/test/classes.pyj +56 -17
  86. package/test/collections.pyj +5 -5
  87. package/test/decorators.pyj +77 -77
  88. package/test/docstrings.pyj +39 -39
  89. package/test/elementmaker_test.pyj +45 -45
  90. package/test/functions.pyj +151 -151
  91. package/test/generators.pyj +41 -41
  92. package/test/generic.pyj +370 -370
  93. package/test/imports.pyj +72 -72
  94. package/test/internationalization.pyj +73 -73
  95. package/test/lint.pyj +164 -164
  96. package/test/loops.pyj +85 -85
  97. package/test/numpy.pyj +734 -734
  98. package/test/omit_function_metadata.pyj +20 -20
  99. package/test/python_compat.pyj +326 -0
  100. package/test/python_features.pyj +129 -29
  101. package/test/regexp.pyj +55 -55
  102. package/test/repl.pyj +121 -121
  103. package/test/scoped_flags.pyj +76 -76
  104. package/test/slice.pyj +105 -0
  105. package/test/str.pyj +25 -0
  106. package/test/unit/fixtures/fibonacci_expected.js +1 -1
  107. package/test/unit/index.js +2296 -71
  108. package/test/unit/language-service-builtins.js +70 -0
  109. package/test/unit/language-service-bundle.js +5 -5
  110. package/test/unit/language-service-completions.js +180 -0
  111. package/test/unit/language-service-dts.js +543 -543
  112. package/test/unit/language-service-hover.js +455 -455
  113. package/test/unit/language-service-index.js +350 -0
  114. package/test/unit/language-service-scope.js +255 -0
  115. package/test/unit/language-service.js +625 -4
  116. package/test/unit/run-language-service.js +1 -0
  117. package/test/unit/web-repl.js +437 -0
  118. package/tools/build-language-service.js +2 -2
  119. package/tools/cli.js +547 -547
  120. package/tools/compile.js +219 -219
  121. package/tools/compiler.js +0 -24
  122. package/tools/completer.js +131 -131
  123. package/tools/embedded_compiler.js +251 -251
  124. package/tools/export.js +3 -37
  125. package/tools/gettext.js +185 -185
  126. package/tools/ini.js +65 -65
  127. package/tools/msgfmt.js +187 -187
  128. package/tools/repl.js +223 -223
  129. package/tools/test.js +118 -118
  130. package/tools/utils.js +128 -128
  131. package/tools/web_repl.js +95 -95
  132. package/try +41 -41
  133. package/web-repl/env.js +196 -74
  134. package/web-repl/index.html +163 -163
  135. package/web-repl/main.js +252 -254
  136. package/web-repl/prism.css +139 -139
  137. package/web-repl/prism.js +113 -113
  138. package/web-repl/rapydscript.js +227 -139
  139. package/web-repl/sha1.js +25 -25
  140. package/hack_demo.pyj +0 -112
  141. package/web-repl/language-service.js +0 -4187
@@ -45,6 +45,13 @@ export const KEYWORDS = [
45
45
  * @returns {{ type: string, objectName?: string, moduleName?: string, prefix: string }}
46
46
  */
47
47
  export function detect_context(linePrefix) {
48
+ // `obj.method().attr` — dot access on a call result (single-level call expression).
49
+ // Must be checked before the plain dot match since `[\w.]+` cannot span `()`.
50
+ const call_result_match = linePrefix.match(/([\w.]+)\([^)]*\)\.([\w]*)$/);
51
+ if (call_result_match) {
52
+ return { type: 'call_result', callPath: call_result_match[1], prefix: call_result_match[2] };
53
+ }
54
+
48
55
  // `obj.attr` or `obj.sub.attr` — dot access (captures multi-level path)
49
56
  const dot_match = linePrefix.match(/([\w.]+)\.([\w]*)$/);
50
57
  if (dot_match) {
@@ -265,6 +272,9 @@ export class CompletionEngine {
265
272
  getCompletions(scopeMap, position, linePrefix, monacoKind) {
266
273
  const ctx = detect_context(linePrefix);
267
274
 
275
+ if (ctx.type === 'call_result') {
276
+ return { suggestions: this._call_result_completions(position, ctx, monacoKind, scopeMap) };
277
+ }
268
278
  if (ctx.type === 'dot') {
269
279
  return { suggestions: this._dot_completions(scopeMap, position, ctx, monacoKind) };
270
280
  }
@@ -346,6 +356,82 @@ export class CompletionEngine {
346
356
  return items;
347
357
  }
348
358
 
359
+ // ---- Return-type helpers -----------------------------------------------
360
+
361
+ /**
362
+ * Analyze a module and return the `return_type` of a named function.
363
+ * @param {string} func_name
364
+ * @param {string} module_name
365
+ * @returns {string|null}
366
+ */
367
+ _get_return_type_from_module(func_name, module_name) {
368
+ const src = this._virtualFiles[module_name] || this._stdlibFiles[module_name];
369
+ if (!src) return null;
370
+ let mod_map;
371
+ try {
372
+ mod_map = this._analyzer.analyze(src, {});
373
+ } catch (_e) {
374
+ return null;
375
+ }
376
+ const mod_frame = mod_map.frames.find(f => f.kind === 'module');
377
+ if (!mod_frame) return null;
378
+ const fn_sym = mod_frame.getSymbol(func_name);
379
+ if (fn_sym && fn_sym.return_type) return fn_sym.return_type;
380
+ return null;
381
+ }
382
+
383
+ /**
384
+ * Resolve a type name (e.g. from inferred_class) through function return annotations,
385
+ * including cross-file imports. Returns the resolved type name, or null if unresolvable.
386
+ * @param {string} name
387
+ * @param {import('./scope.js').ScopeMap} scopeMap
388
+ * @returns {string|null}
389
+ */
390
+ _resolve_type_through_functions(name, scopeMap) {
391
+ let sym = null;
392
+ for (const frame of scopeMap.frames) {
393
+ const s = frame.getSymbol(name);
394
+ if (s) { sym = s; break; }
395
+ }
396
+ if (!sym) return null;
397
+
398
+ if (sym.kind === 'function' || sym.kind === 'method') {
399
+ // return_type is set by explicit annotation or inferred by the analyzer
400
+ if (sym.return_type) return sym.return_type;
401
+ return null;
402
+ }
403
+
404
+ if (sym.kind === 'import' && sym.source_module) {
405
+ const orig = sym.original_name || sym.name;
406
+ return this._get_return_type_from_module(orig, sym.source_module);
407
+ }
408
+
409
+ return null;
410
+ }
411
+
412
+ /**
413
+ * Get the member map for a given type name.
414
+ * Checks builtins, then user class frames. Returns null if unknown.
415
+ * @param {string} type_name
416
+ * @param {import('./scope.js').ScopeMap|null} scopeMap
417
+ * @returns {Map|null}
418
+ */
419
+ _get_members_for_type(type_name, scopeMap) {
420
+ if (!type_name) return null;
421
+ if (this._builtins) {
422
+ const m = this._builtins.getTypeMembers(type_name);
423
+ if (m) return m;
424
+ }
425
+ if (scopeMap) {
426
+ for (const frame of scopeMap.frames) {
427
+ if (frame.kind === 'class' && frame.name === type_name) {
428
+ return frame.symbols;
429
+ }
430
+ }
431
+ }
432
+ return null;
433
+ }
434
+
349
435
  // ---- Dot completions ---------------------------------------------------
350
436
 
351
437
  _dot_completions(scopeMap, position, ctx, monacoKind) {
@@ -413,6 +499,13 @@ export class CompletionEngine {
413
499
  }
414
500
  }
415
501
 
502
+ // Resolve class_name through function return type annotations.
503
+ // e.g. x = getAllServers() → inferred_class='getAllServers' → resolve 'list'
504
+ if (class_name) {
505
+ const resolved = this._resolve_type_through_functions(class_name, scopeMap);
506
+ if (resolved) class_name = resolved;
507
+ }
508
+
416
509
  if (class_name) {
417
510
  for (const frame of scopeMap.frames) {
418
511
  if (frame.kind === 'class' && frame.name === class_name) {
@@ -433,7 +526,13 @@ export class CompletionEngine {
433
526
  // 1.5. Built-in type members — list, str, dict, number.
434
527
  // Used when inferred_class names a built-in type, not a user class.
435
528
  if (!scope_matched && this._builtins && obj_sym && obj_sym.inferred_class) {
436
- const members = this._builtins.getTypeMembers(obj_sym.inferred_class);
529
+ // Re-resolve in case inferred_class itself is a function name.
530
+ let type_name = obj_sym.inferred_class;
531
+ if (scopeMap) {
532
+ const resolved = this._resolve_type_through_functions(type_name, scopeMap);
533
+ if (resolved) type_name = resolved;
534
+ }
535
+ const members = this._builtins.getTypeMembers(type_name);
437
536
  if (members) {
438
537
  scope_matched = true;
439
538
  for (const [name, member] of members) {
@@ -496,6 +595,76 @@ export class CompletionEngine {
496
595
  return items;
497
596
  }
498
597
 
598
+ // ---- Call-result dot completions (e.g. ns.self().attr) -----------------
599
+
600
+ _call_result_completions(position, ctx, monacoKind, scopeMap) {
601
+ const range = word_range(position, ctx.prefix);
602
+ const items = [];
603
+ const seen = new Set();
604
+ const call_path = ctx.callPath;
605
+ const last_dot = call_path.lastIndexOf('.');
606
+
607
+ // --- DTS path (existing logic) ---
608
+ if (this._dts) {
609
+ let member_ti = null;
610
+ if (last_dot > 0) {
611
+ const object_path = call_path.slice(0, last_dot);
612
+ const method_name = call_path.slice(last_dot + 1);
613
+ member_ti = this._dts.getMemberInfo(object_path, method_name);
614
+ } else {
615
+ member_ti = this._dts.getGlobal(call_path);
616
+ }
617
+ if (member_ti && member_ti.return_type) {
618
+ const return_ti = this._dts.getGlobal(resolve_first_type(member_ti.return_type));
619
+ if (return_ti && return_ti.members) {
620
+ for (const [name, member] of return_ti.members) {
621
+ if (!ctx.prefix || name.startsWith(ctx.prefix)) {
622
+ seen.add(name);
623
+ items.push(_dts_member_to_item(member, range, monacoKind));
624
+ }
625
+ }
626
+ }
627
+ }
628
+ }
629
+
630
+ // --- User-defined function return types (scopeMap) ---
631
+ if (scopeMap && last_dot < 0) {
632
+ // Simple call like getAllServers() — look up function in scope
633
+ let sym = null;
634
+ for (const frame of scopeMap.frames) {
635
+ const s = frame.getSymbol(call_path);
636
+ if (s) { sym = s; break; }
637
+ }
638
+ if (sym) {
639
+ let return_type = null;
640
+ if (sym.kind === 'function' || sym.kind === 'method') {
641
+ return_type = sym.return_type;
642
+ } else if (sym.kind === 'import' && sym.source_module) {
643
+ const orig = sym.original_name || sym.name;
644
+ return_type = this._get_return_type_from_module(orig, sym.source_module);
645
+ }
646
+ if (return_type) {
647
+ const members = this._get_members_for_type(return_type, scopeMap);
648
+ if (members) {
649
+ for (const [name, member] of members) {
650
+ if (!seen.has(name) && (!ctx.prefix || name.startsWith(ctx.prefix))) {
651
+ seen.add(name);
652
+ // members may be SymbolInfo (class frame) or TypeInfo/BuiltinInfo
653
+ const item = member.kind === 'function' || member.kind === 'method' ||
654
+ member.kind === 'variable' || member.kind === 'parameter'
655
+ ? symbol_to_item(member, range, monacoKind, '0')
656
+ : _dts_member_to_item(member, range, monacoKind);
657
+ items.push(item);
658
+ }
659
+ }
660
+ }
661
+ }
662
+ }
663
+ }
664
+
665
+ return items;
666
+ }
667
+
499
668
  // ---- from X import completions -----------------------------------------
500
669
 
501
670
  _from_import_completions(position, ctx, monacoKind) {
@@ -22,6 +22,20 @@ const MESSAGES = {
22
22
  'dup-method': 'The method "{name}" was defined previously at line: {line}',
23
23
  };
24
24
 
25
+ // Built-in stdlib modules that are always available in RapydScript (bundled
26
+ // with the compiler from src/lib/). These should never produce 'Unknown module'
27
+ // errors regardless of what virtualFiles or stdlibFiles are configured.
28
+ export const STDLIB_MODULES = [
29
+ 'aes', 'collections', 'copy', 'elementmaker', 'encodings', 'functools',
30
+ 'gettext', 'itertools', 'math', 'numpy', 'operator', 'pythonize',
31
+ 'random', 're', 'react', 'traceback', 'uuid',
32
+ // Pseudo-modules for language feature flags (from __python__ import ...)
33
+ '__python__', '__builtins__',
34
+ ];
35
+
36
+ const _STDLIB_MODULE_SET = Object.create(null);
37
+ STDLIB_MODULES.forEach(m => { _STDLIB_MODULE_SET[m] = true; });
38
+
25
39
  // Symbols always available in RapydScript (from tools/lint.js BUILTINS list).
26
40
  export const BASE_BUILTINS = (
27
41
  'this self window document chr ord iterator_symbol print len range dir' +
@@ -30,11 +44,11 @@ export const BASE_BUILTINS = (
30
44
  ' isNaN JSON Math list set list_wrap ρσ_modules require bool int bin' +
31
45
  ' float iter Error EvalError set_wrap frozenset RangeError ReferenceError SyntaxError' +
32
46
  ' str TypeError URIError Exception AssertionError IndexError AttributeError KeyError' +
33
- ' ValueError ZeroDivisionError map hex filter zip dict dict_wrap UnicodeDecodeError HTMLCollection' +
47
+ ' ValueError ZeroDivisionError ImportError ModuleNotFoundError StopIteration map hex filter zip dict dict_wrap UnicodeDecodeError HTMLCollection' +
34
48
  ' NodeList alert console Node Symbol NamedNodeMap ρσ_eslice ρσ_delslice Number' +
35
49
  ' Boolean encodeURIComponent decodeURIComponent setTimeout setInterval' +
36
50
  ' setImmediate clearTimeout clearInterval clearImmediate requestAnimationFrame' +
37
- ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN super Ellipsis'
51
+ ' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN super Ellipsis slice all any next __import__ ρσ_new ρσ_object_new hash ρσ_object_setattr ρσ_object_getattr ρσ_object_delattr ExceptionGroup BaseExceptionGroup tuple'
38
52
  ).split(' ');
39
53
 
40
54
  // ---------------------------------------------------------------------------
@@ -384,7 +398,13 @@ function Linter(RS, toplevel, code, builtins, knownModules) {
384
398
  };
385
399
 
386
400
  this.handle_symbol_funarg = function() {
387
- this.add_binding(this.current_node.name);
401
+ const node = this.current_node;
402
+ this.add_binding(node.name);
403
+ // Suppress undefined-symbol errors for type names used in argument
404
+ // annotations: `def foo(x: MyType):` — MyType is a hint, not a ref.
405
+ if (node.annotation instanceof RS.AST_SymbolRef) {
406
+ node.annotation.lint_visited = true;
407
+ }
388
408
  };
389
409
 
390
410
  this.handle_comprehension = function() {
@@ -681,6 +701,8 @@ export class Diagnostics {
681
701
  const sf = options.stdlibFiles;
682
702
  if ((vf && Object.keys(vf).length > 0) || (sf && Object.keys(sf).length > 0)) {
683
703
  knownModules = Object.create(null);
704
+ // Always include built-in stdlib so they never produce bad-import errors.
705
+ Object.assign(knownModules, _STDLIB_MODULE_SET);
684
706
  if (vf) Object.keys(vf).forEach(k => { knownModules[k] = true; });
685
707
  if (sf) Object.keys(sf).forEach(k => { knownModules[k] = true; });
686
708
  }