rapydscript-ns 0.9.2 → 0.9.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 (88) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/PYTHON_GAPS.md +352 -0
  3. package/README.md +176 -32
  4. package/TODO.md +1 -128
  5. package/bin/rapydscript +70 -70
  6. package/language-service/index.js +242 -11
  7. package/memory/project_string_impl.md +43 -0
  8. package/package.json +1 -1
  9. package/release/baselib-plain-pretty.js +248 -38
  10. package/release/baselib-plain-ugly.js +8 -8
  11. package/release/compiler.js +778 -277
  12. package/release/signatures.json +30 -30
  13. package/src/ast.pyj +10 -1
  14. package/src/baselib-builtins.pyj +56 -2
  15. package/src/baselib-containers.pyj +25 -1
  16. package/src/baselib-errors.pyj +7 -3
  17. package/src/baselib-internal.pyj +51 -6
  18. package/src/baselib-str.pyj +18 -5
  19. package/src/lib/asyncio.pyj +534 -0
  20. package/src/lib/base64.pyj +399 -0
  21. package/src/lib/bisect.pyj +73 -0
  22. package/src/lib/collections.pyj +228 -4
  23. package/src/lib/csv.pyj +494 -0
  24. package/src/lib/heapq.pyj +98 -0
  25. package/src/lib/html.pyj +382 -0
  26. package/src/lib/http/__init__.pyj +98 -0
  27. package/src/lib/http/client.pyj +304 -0
  28. package/src/lib/http/cookies.pyj +236 -0
  29. package/src/lib/logging.pyj +672 -0
  30. package/src/lib/pprint.pyj +455 -0
  31. package/src/lib/pythonize.pyj +20 -20
  32. package/src/lib/statistics.pyj +0 -0
  33. package/src/lib/string.pyj +357 -0
  34. package/src/lib/textwrap.pyj +329 -0
  35. package/src/lib/urllib/__init__.pyj +14 -0
  36. package/src/lib/urllib/error.pyj +66 -0
  37. package/src/lib/urllib/parse.pyj +475 -0
  38. package/src/lib/urllib/request.pyj +86 -0
  39. package/src/monaco-language-service/analyzer.js +5 -2
  40. package/src/monaco-language-service/completions.js +26 -0
  41. package/src/monaco-language-service/diagnostics.js +203 -4
  42. package/src/monaco-language-service/scope.js +1 -0
  43. package/src/output/codegen.pyj +4 -1
  44. package/src/output/functions.pyj +152 -6
  45. package/src/output/loops.pyj +17 -2
  46. package/src/output/modules.pyj +1 -1
  47. package/src/output/operators.pyj +15 -0
  48. package/src/output/stream.pyj +0 -1
  49. package/src/parse.pyj +108 -24
  50. package/src/tokenizer.pyj +19 -3
  51. package/test/async_generators.pyj +144 -0
  52. package/test/asyncio.pyj +307 -0
  53. package/test/base64.pyj +202 -0
  54. package/test/baselib.pyj +23 -0
  55. package/test/bisect.pyj +178 -0
  56. package/test/chainmap.pyj +185 -0
  57. package/test/csv.pyj +405 -0
  58. package/test/float_special.pyj +64 -0
  59. package/test/heapq.pyj +174 -0
  60. package/test/html.pyj +212 -0
  61. package/test/http.pyj +259 -0
  62. package/test/imports.pyj +79 -72
  63. package/test/logging.pyj +356 -0
  64. package/test/long.pyj +130 -0
  65. package/test/parenthesized_with.pyj +141 -0
  66. package/test/pprint.pyj +232 -0
  67. package/test/python_compat.pyj +3 -5
  68. package/test/python_modulo.pyj +76 -0
  69. package/test/python_modulo_off.pyj +21 -0
  70. package/test/statistics.pyj +224 -0
  71. package/test/str.pyj +14 -0
  72. package/test/string.pyj +245 -0
  73. package/test/textwrap.pyj +172 -0
  74. package/test/type_display.pyj +48 -0
  75. package/test/type_enforcement.pyj +164 -0
  76. package/test/unit/index.js +94 -6
  77. package/test/unit/language-service-completions.js +121 -0
  78. package/test/unit/language-service-scope.js +32 -0
  79. package/test/unit/language-service.js +190 -5
  80. package/test/unit/run-language-service.js +17 -3
  81. package/test/unit/web-repl.js +2401 -13
  82. package/test/urllib.pyj +193 -0
  83. package/tools/compile.js +1 -1
  84. package/tools/embedded_compiler.js +7 -7
  85. package/tools/export.js +4 -2
  86. package/web-repl/main.js +1 -1
  87. package/web-repl/rapydscript.js +7 -5
  88. package/test/omit_function_metadata.pyj +0 -20
@@ -2,10 +2,11 @@
2
2
  # License: BSD
3
3
  # RapydScript implementation of Python's collections standard library.
4
4
  #
5
- # Supported: namedtuple, deque, Counter, OrderedDict, defaultdict
5
+ # Supported: namedtuple, deque, Counter, OrderedDict, defaultdict, ChainMap
6
6
  #
7
- # Note: Counter, OrderedDict, and defaultdict use __getitem__/__setitem__.
8
- # For Python-compatible subscript syntax (obj[key]) in user code, add:
7
+ # Note: Counter, OrderedDict, defaultdict, and ChainMap use
8
+ # __getitem__/__setitem__. For Python-compatible subscript syntax (obj[key])
9
+ # in user code, add:
9
10
  # from __python__ import overload_getitem
10
11
 
11
12
 
@@ -13,7 +14,7 @@ def namedtuple(typename, field_names):
13
14
  """Return a new class with named fields, like Python's collections.namedtuple."""
14
15
  if isinstance(field_names, str):
15
16
  # Use explicit JS regex split for cross-environment safety
16
- fields = v"field_names.replace(/,/g, ' ').trim().split(/\\s+/).filter(function(s){return s.length>0;})"
17
+ fields = v"field_names.replace(/,/g, ' ').trim().split(/\s+/).filter(function(s){return s.length>0;})"
17
18
  else:
18
19
  fields = list(field_names)
19
20
  n = fields.length
@@ -693,3 +694,226 @@ class defaultdict:
693
694
  if self._data[k] != src[k]:
694
695
  return False
695
696
  return True
697
+
698
+
699
+ class ChainMap:
700
+ """Combine several mappings into a single, updateable view.
701
+
702
+ Lookups search the underlying mappings in order, so the first mapping
703
+ wins. Writes, updates, and deletions affect only the first mapping.
704
+ Mirrors Python's collections.ChainMap.
705
+ """
706
+
707
+ def __init__(self, *maps):
708
+ if maps.length == 0:
709
+ self.maps = [{}]
710
+ else:
711
+ self.maps = list(maps)
712
+
713
+ # ── internal mapping-access helpers ───────────────────────────────────
714
+ # A "map" may be a plain JS object, a RapydScript dict (ρσ_dict, used for
715
+ # {...} literals in the web-repl), or any RapydScript mapping defining
716
+ # __getitem__/__setitem__/__contains__ (OrderedDict, defaultdict, Counter,
717
+ # or a nested ChainMap).
718
+
719
+ def _is_rdict(self, m):
720
+ return v'!!(m && m.jsmap && typeof m.jsmap.get === "function")'
721
+
722
+ def _is_mapping(self, m):
723
+ return v'!!(m && typeof m.__getitem__ === "function" && typeof m.__contains__ === "function")'
724
+
725
+ def _mkeys(self, m):
726
+ if self._is_rdict(m):
727
+ return v'Array.from(m.jsmap.keys())'
728
+ if self._is_mapping(m):
729
+ return list(m.keys())
730
+ return Object.keys(m)
731
+
732
+ def _mhas(self, m, key):
733
+ if self._is_rdict(m):
734
+ return v'm.jsmap.has(key)'
735
+ if self._is_mapping(m):
736
+ return m.__contains__(key)
737
+ return v'Object.prototype.hasOwnProperty.call(m, key)'
738
+
739
+ def _mget(self, m, key):
740
+ if self._is_rdict(m):
741
+ return v'm.jsmap.get(key)'
742
+ if self._is_mapping(m):
743
+ return m.__getitem__(key)
744
+ return v'm[key]'
745
+
746
+ def _mset(self, m, key, value):
747
+ if self._is_rdict(m):
748
+ v'm.jsmap.set(key, value)'
749
+ elif self._is_mapping(m):
750
+ m.__setitem__(key, value)
751
+ else:
752
+ v'm[key] = value'
753
+
754
+ def _mdel(self, m, key):
755
+ if self._is_rdict(m):
756
+ v'm.jsmap["delete"](key)'
757
+ elif self._is_mapping(m):
758
+ m.__delitem__(key)
759
+ else:
760
+ v'delete m[key]'
761
+
762
+ def _all_keys(self):
763
+ # Unique keys across every map. Maps are scanned last-to-first so that
764
+ # earlier maps keep their key positions, matching Python's iteration.
765
+ seen = {}
766
+ result = []
767
+ i = self.maps.length - 1
768
+ while i >= 0:
769
+ for k in self._mkeys(self.maps[i]):
770
+ if k not in seen:
771
+ seen[k] = True
772
+ result.push(k)
773
+ i -= 1
774
+ return result
775
+
776
+ def __getitem__(self, key):
777
+ for m in self.maps:
778
+ if self._mhas(m, key):
779
+ return self._mget(m, key)
780
+ raise KeyError(repr(key))
781
+
782
+ def __setitem__(self, key, value):
783
+ self._mset(self.maps[0], key, value)
784
+
785
+ def __delitem__(self, key):
786
+ if not self._mhas(self.maps[0], key):
787
+ raise KeyError('Key not found in the first mapping: ' + repr(key))
788
+ self._mdel(self.maps[0], key)
789
+
790
+ def __contains__(self, key):
791
+ for m in self.maps:
792
+ if self._mhas(m, key):
793
+ return True
794
+ return False
795
+
796
+ def __len__(self):
797
+ return self._all_keys().length
798
+
799
+ def __iter__(self):
800
+ return iter(self._all_keys())
801
+
802
+ def __bool__(self):
803
+ for m in self.maps:
804
+ if self._mkeys(m).length > 0:
805
+ return True
806
+ return False
807
+
808
+ def _map_repr(self, m):
809
+ pairs = [repr(k) + ': ' + repr(self._mget(m, k)) for k in self._mkeys(m)]
810
+ return '{' + pairs.join(', ') + '}'
811
+
812
+ def __repr__(self):
813
+ parts = [self._map_repr(m) for m in self.maps]
814
+ return 'ChainMap(' + parts.join(', ') + ')'
815
+
816
+ def __eq__(self, other):
817
+ if other is None:
818
+ return False
819
+ is_mapish = self._is_rdict(other) or self._is_mapping(other) or (jstype(other) is 'object' and not Array.isArray(other))
820
+ if not is_mapish:
821
+ return False
822
+ a = self._all_keys()
823
+ b = self._mkeys(other)
824
+ if a.length != b.length:
825
+ return False
826
+ for k in a:
827
+ if not self._mhas(other, k):
828
+ return False
829
+ if self.__getitem__(k) != self._mget(other, k):
830
+ return False
831
+ return True
832
+
833
+ def get(self, key, dflt=None):
834
+ if self.__contains__(key):
835
+ return self.__getitem__(key)
836
+ return dflt
837
+
838
+ def keys(self):
839
+ return self._all_keys()
840
+
841
+ def values(self):
842
+ return [self.__getitem__(k) for k in self._all_keys()]
843
+
844
+ def items(self):
845
+ return [[k, self.__getitem__(k)] for k in self._all_keys()]
846
+
847
+ @property
848
+ def parents(self):
849
+ cm = ChainMap()
850
+ cm.maps = self.maps.slice(1)
851
+ return cm
852
+
853
+ def new_child(self, m=None):
854
+ if m is None:
855
+ m = {}
856
+ cm = ChainMap()
857
+ cm.maps = [m].concat(self.maps)
858
+ return cm
859
+
860
+ def _copy_map(self, m):
861
+ if jstype(m.copy) is 'function':
862
+ return m.copy()
863
+ result = {}
864
+ for k in Object.keys(m):
865
+ result[k] = m[k]
866
+ return result
867
+
868
+ def copy(self):
869
+ cm = ChainMap()
870
+ cm.maps = [self._copy_map(self.maps[0])].concat(self.maps.slice(1))
871
+ return cm
872
+
873
+ def pop(self, key, *rest):
874
+ first = self.maps[0]
875
+ if self._mhas(first, key):
876
+ val = self._mget(first, key)
877
+ self._mdel(first, key)
878
+ return val
879
+ if len(rest) > 0:
880
+ return rest[0]
881
+ raise KeyError('Key not found in the first mapping: ' + repr(key))
882
+
883
+ def popitem(self):
884
+ first = self.maps[0]
885
+ keys = self._mkeys(first)
886
+ if keys.length == 0:
887
+ raise KeyError('No keys found in the first mapping.')
888
+ k = keys[keys.length - 1]
889
+ val = self._mget(first, k)
890
+ self._mdel(first, k)
891
+ return [k, val]
892
+
893
+ def setdefault(self, key, dflt=None):
894
+ if not self.__contains__(key):
895
+ self._mset(self.maps[0], key, dflt)
896
+ return self.__getitem__(key)
897
+
898
+ def clear(self):
899
+ first = self.maps[0]
900
+ if jstype(first.clear) is 'function':
901
+ first.clear()
902
+ else:
903
+ for k in Object.keys(first):
904
+ v'delete first[k]'
905
+
906
+ def update(self, other=None, **kwargs):
907
+ first = self.maps[0]
908
+ if other is not None:
909
+ if self._is_rdict(other) or self._is_mapping(other):
910
+ for k in self._mkeys(other):
911
+ self._mset(first, k, self._mget(other, k))
912
+ elif jstype(other) is 'object' and not Array.isArray(other):
913
+ for k in Object.keys(other):
914
+ self._mset(first, k, other[k])
915
+ else:
916
+ for pair in other:
917
+ self._mset(first, pair[0], pair[1])
918
+ for k in kwargs:
919
+ self._mset(first, k, kwargs[k])