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.
- package/.agignore +1 -1
- package/.github/workflows/ci.yml +38 -38
- package/=template.pyj +5 -5
- package/CHANGELOG.md +39 -0
- package/HACKING.md +103 -103
- package/LICENSE +24 -24
- package/PYTHON_DIFFERENCES_REPORT.md +291 -0
- package/PYTHON_FEATURE_COVERAGE.md +106 -15
- package/README.md +831 -52
- package/TODO.md +4 -286
- package/add-toc-to-readme +2 -2
- package/bin/export +75 -75
- package/bin/rapydscript +70 -70
- package/bin/web-repl-export +102 -102
- package/build +2 -2
- package/language-service/index.js +4623 -0
- package/language-service/language-service.d.ts +40 -0
- package/package.json +9 -7
- package/publish.py +37 -37
- package/release/baselib-plain-pretty.js +2006 -229
- package/release/baselib-plain-ugly.js +70 -3
- package/release/compiler.js +11554 -3870
- package/release/signatures.json +31 -29
- package/session.vim +4 -4
- package/setup.cfg +2 -2
- package/src/ast.pyj +93 -1
- package/src/baselib-builtins.pyj +99 -2
- package/src/baselib-containers.pyj +107 -4
- package/src/baselib-errors.pyj +44 -0
- package/src/baselib-internal.pyj +124 -5
- package/src/baselib-itertools.pyj +97 -97
- package/src/baselib-str.pyj +32 -1
- package/src/compiler.pyj +36 -36
- package/src/errors.pyj +30 -30
- package/src/lib/aes.pyj +646 -646
- package/src/lib/collections.pyj +1 -1
- package/src/lib/copy.pyj +120 -0
- package/src/lib/elementmaker.pyj +83 -83
- package/src/lib/encodings.pyj +126 -126
- package/src/lib/gettext.pyj +569 -569
- package/src/lib/itertools.pyj +580 -580
- package/src/lib/math.pyj +193 -193
- package/src/lib/numpy.pyj +10 -10
- package/src/lib/operator.pyj +11 -11
- package/src/lib/pythonize.pyj +20 -20
- package/src/lib/random.pyj +118 -118
- package/src/lib/re.pyj +470 -470
- package/src/lib/react.pyj +74 -0
- package/src/lib/traceback.pyj +63 -63
- package/src/lib/uuid.pyj +77 -77
- package/src/monaco-language-service/analyzer.js +131 -9
- package/src/monaco-language-service/builtins.js +17 -2
- package/src/monaco-language-service/completions.js +170 -1
- package/src/monaco-language-service/diagnostics.js +25 -3
- package/src/monaco-language-service/dts.js +550 -550
- package/src/monaco-language-service/index.js +17 -0
- package/src/monaco-language-service/scope.js +3 -0
- package/src/output/classes.pyj +128 -11
- package/src/output/codegen.pyj +17 -3
- package/src/output/comments.pyj +45 -45
- package/src/output/exceptions.pyj +201 -105
- package/src/output/functions.pyj +13 -16
- package/src/output/jsx.pyj +164 -0
- package/src/output/literals.pyj +28 -2
- package/src/output/loops.pyj +0 -9
- package/src/output/modules.pyj +2 -5
- package/src/output/operators.pyj +22 -2
- package/src/output/statements.pyj +2 -2
- package/src/output/stream.pyj +1 -13
- package/src/output/treeshake.pyj +182 -182
- package/src/output/utils.pyj +72 -72
- package/src/parse.pyj +434 -114
- package/src/string_interpolation.pyj +72 -72
- package/src/tokenizer.pyj +29 -0
- package/src/unicode_aliases.pyj +576 -576
- package/src/utils.pyj +192 -192
- package/test/_import_one.pyj +37 -37
- package/test/_import_two/__init__.pyj +11 -11
- package/test/_import_two/level2/deep.pyj +4 -4
- package/test/_import_two/other.pyj +6 -6
- package/test/_import_two/sub.pyj +13 -13
- package/test/aes_vectors.pyj +421 -421
- package/test/annotations.pyj +80 -80
- package/test/baselib.pyj +4 -4
- package/test/classes.pyj +56 -17
- package/test/collections.pyj +5 -5
- package/test/decorators.pyj +77 -77
- package/test/docstrings.pyj +39 -39
- package/test/elementmaker_test.pyj +45 -45
- package/test/functions.pyj +151 -151
- package/test/generators.pyj +41 -41
- package/test/generic.pyj +370 -370
- package/test/imports.pyj +72 -72
- package/test/internationalization.pyj +73 -73
- package/test/lint.pyj +164 -164
- package/test/loops.pyj +85 -85
- package/test/numpy.pyj +734 -734
- package/test/omit_function_metadata.pyj +20 -20
- package/test/python_compat.pyj +326 -0
- package/test/python_features.pyj +129 -29
- package/test/regexp.pyj +55 -55
- package/test/repl.pyj +121 -121
- package/test/scoped_flags.pyj +76 -76
- package/test/slice.pyj +105 -0
- package/test/str.pyj +25 -0
- package/test/unit/fixtures/fibonacci_expected.js +1 -1
- package/test/unit/index.js +2296 -71
- package/test/unit/language-service-builtins.js +70 -0
- package/test/unit/language-service-bundle.js +5 -5
- package/test/unit/language-service-completions.js +180 -0
- package/test/unit/language-service-dts.js +543 -543
- package/test/unit/language-service-hover.js +455 -455
- package/test/unit/language-service-index.js +350 -0
- package/test/unit/language-service-scope.js +255 -0
- package/test/unit/language-service.js +625 -4
- package/test/unit/run-language-service.js +1 -0
- package/test/unit/web-repl.js +437 -0
- package/tools/build-language-service.js +2 -2
- package/tools/cli.js +547 -547
- package/tools/compile.js +219 -219
- package/tools/compiler.js +0 -24
- package/tools/completer.js +131 -131
- package/tools/embedded_compiler.js +251 -251
- package/tools/export.js +3 -37
- package/tools/gettext.js +185 -185
- package/tools/ini.js +65 -65
- package/tools/msgfmt.js +187 -187
- package/tools/repl.js +223 -223
- package/tools/test.js +118 -118
- package/tools/utils.js +128 -128
- package/tools/web_repl.js +95 -95
- package/try +41 -41
- package/web-repl/env.js +196 -74
- package/web-repl/index.html +163 -163
- package/web-repl/main.js +252 -254
- package/web-repl/prism.css +139 -139
- package/web-repl/prism.js +113 -113
- package/web-repl/rapydscript.js +227 -139
- package/web-repl/sha1.js +25 -25
- package/hack_demo.pyj +0 -112
- package/web-repl/language-service.js +0 -4187
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD
|
|
3
|
+
# RapydScript bindings for React.
|
|
4
|
+
#
|
|
5
|
+
# Supported: all standard hooks (useState, useEffect, useContext, useReducer,
|
|
6
|
+
# useCallback, useMemo, useRef, useImperativeHandle, useLayoutEffect,
|
|
7
|
+
# useDebugValue, useId, useTransition, useDeferredValue), core classes
|
|
8
|
+
# (Component, PureComponent), special elements (Fragment, StrictMode,
|
|
9
|
+
# Suspense, Profiler), and utilities (createElement, cloneElement,
|
|
10
|
+
# createContext, createRef, forwardRef, isValidElement, memo, lazy).
|
|
11
|
+
#
|
|
12
|
+
# Requires React to be available as a global variable. Load it via a CDN
|
|
13
|
+
# <script> tag, a bundler global shim, or any other mechanism before your
|
|
14
|
+
# compiled script runs.
|
|
15
|
+
#
|
|
16
|
+
# Usage:
|
|
17
|
+
# from __python__ import jsx
|
|
18
|
+
# from react import useState, useEffect, useRef
|
|
19
|
+
#
|
|
20
|
+
# def Counter():
|
|
21
|
+
# count, setCount = useState(0)
|
|
22
|
+
# def handleClick():
|
|
23
|
+
# setCount(count + 1)
|
|
24
|
+
# return <button onClick={handleClick}>{count}</button>
|
|
25
|
+
#
|
|
26
|
+
# For class components extend React.Component directly (no import needed):
|
|
27
|
+
#
|
|
28
|
+
# class MyComponent(React.Component):
|
|
29
|
+
# def render(self):
|
|
30
|
+
# return <div>{self.props.title}</div>
|
|
31
|
+
|
|
32
|
+
# ── Hooks (React 16.8+) ───────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
useState = React.useState
|
|
35
|
+
useEffect = React.useEffect
|
|
36
|
+
useContext = React.useContext
|
|
37
|
+
useReducer = React.useReducer
|
|
38
|
+
useCallback = React.useCallback
|
|
39
|
+
useMemo = React.useMemo
|
|
40
|
+
useRef = React.useRef
|
|
41
|
+
useImperativeHandle = React.useImperativeHandle
|
|
42
|
+
useLayoutEffect = React.useLayoutEffect
|
|
43
|
+
useDebugValue = React.useDebugValue
|
|
44
|
+
|
|
45
|
+
# ── Hooks (React 18+) ────────────────────────────────────────────────────────
|
|
46
|
+
|
|
47
|
+
useId = React.useId
|
|
48
|
+
useTransition = React.useTransition
|
|
49
|
+
useDeferredValue = React.useDeferredValue
|
|
50
|
+
useSyncExternalStore = React.useSyncExternalStore
|
|
51
|
+
useInsertionEffect = React.useInsertionEffect
|
|
52
|
+
|
|
53
|
+
# ── Core classes ─────────────────────────────────────────────────────────────
|
|
54
|
+
|
|
55
|
+
Component = React.Component
|
|
56
|
+
PureComponent = React.PureComponent
|
|
57
|
+
|
|
58
|
+
# ── Special elements ─────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
Fragment = React.Fragment
|
|
61
|
+
StrictMode = React.StrictMode
|
|
62
|
+
Suspense = React.Suspense
|
|
63
|
+
Profiler = React.Profiler
|
|
64
|
+
|
|
65
|
+
# ── Utilities ────────────────────────────────────────────────────────────────
|
|
66
|
+
|
|
67
|
+
createElement = React.createElement
|
|
68
|
+
cloneElement = React.cloneElement
|
|
69
|
+
createContext = React.createContext
|
|
70
|
+
createRef = React.createRef
|
|
71
|
+
forwardRef = React.forwardRef
|
|
72
|
+
isValidElement = React.isValidElement
|
|
73
|
+
memo = React.memo
|
|
74
|
+
lazy = React.lazy
|
package/src/lib/traceback.pyj
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
# vim:fileencoding=utf-8
|
|
2
|
-
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
-
# globals: ρσ_str, ρσ_last_exception
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def _get_internal_traceback(err):
|
|
7
|
-
if isinstance(err, Exception) and err.stack:
|
|
8
|
-
lines = ρσ_str.splitlines(err.stack)
|
|
9
|
-
final_lines = v'[]'
|
|
10
|
-
found_sentinel = False
|
|
11
|
-
for i, line in enumerate(lines):
|
|
12
|
-
sline = ρσ_str.strip(line)
|
|
13
|
-
if i is 0:
|
|
14
|
-
final_lines.push(line)
|
|
15
|
-
continue
|
|
16
|
-
if found_sentinel:
|
|
17
|
-
final_lines.push(line)
|
|
18
|
-
continue
|
|
19
|
-
# These two conditions work on desktop Chrome and Firefox to identify the correct
|
|
20
|
-
# line in the traceback.
|
|
21
|
-
if sline.startsWith('at new ' + err.name) or sline.startsWith(err.name + '@'):
|
|
22
|
-
found_sentinel = True
|
|
23
|
-
return final_lines.join('\n')
|
|
24
|
-
return err and err.stack
|
|
25
|
-
|
|
26
|
-
def format_exception(exc, limit):
|
|
27
|
-
if jstype(exc) is 'undefined':
|
|
28
|
-
exc = ρσ_last_exception
|
|
29
|
-
if not isinstance(exc, Error):
|
|
30
|
-
if exc and exc.toString:
|
|
31
|
-
return [exc.toString()]
|
|
32
|
-
return []
|
|
33
|
-
tb = _get_internal_traceback(exc)
|
|
34
|
-
if tb:
|
|
35
|
-
lines = ρσ_str.splitlines(tb)
|
|
36
|
-
e = lines[0]
|
|
37
|
-
lines = lines[1:]
|
|
38
|
-
if limit:
|
|
39
|
-
lines = lines[:limit+1] if limit > 0 else lines[limit:]
|
|
40
|
-
lines.reverse()
|
|
41
|
-
lines.push(e)
|
|
42
|
-
lines.insert(0, 'Traceback (most recent call last):')
|
|
43
|
-
return [l+'\n' for l in lines]
|
|
44
|
-
return [exc.toString()]
|
|
45
|
-
|
|
46
|
-
def format_exc(limit):
|
|
47
|
-
return format_exception(ρσ_last_exception, limit).join('')
|
|
48
|
-
|
|
49
|
-
def print_exc(limit):
|
|
50
|
-
print(format_exc(limit))
|
|
51
|
-
|
|
52
|
-
def format_stack(limit):
|
|
53
|
-
stack = Error().stack
|
|
54
|
-
if not stack:
|
|
55
|
-
return []
|
|
56
|
-
lines = str.splitlines(stack)[2:]
|
|
57
|
-
lines.reverse()
|
|
58
|
-
if limit:
|
|
59
|
-
lines = lines[:limit+1] if limit > 0 else lines[limit:]
|
|
60
|
-
return [l + '\n' for l in lines]
|
|
61
|
-
|
|
62
|
-
def print_stack(limit):
|
|
63
|
-
print(format_stack(limit).join(''))
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
+
# globals: ρσ_str, ρσ_last_exception
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def _get_internal_traceback(err):
|
|
7
|
+
if isinstance(err, Exception) and err.stack:
|
|
8
|
+
lines = ρσ_str.splitlines(err.stack)
|
|
9
|
+
final_lines = v'[]'
|
|
10
|
+
found_sentinel = False
|
|
11
|
+
for i, line in enumerate(lines):
|
|
12
|
+
sline = ρσ_str.strip(line)
|
|
13
|
+
if i is 0:
|
|
14
|
+
final_lines.push(line)
|
|
15
|
+
continue
|
|
16
|
+
if found_sentinel:
|
|
17
|
+
final_lines.push(line)
|
|
18
|
+
continue
|
|
19
|
+
# These two conditions work on desktop Chrome and Firefox to identify the correct
|
|
20
|
+
# line in the traceback.
|
|
21
|
+
if sline.startsWith('at new ' + err.name) or sline.startsWith(err.name + '@'):
|
|
22
|
+
found_sentinel = True
|
|
23
|
+
return final_lines.join('\n')
|
|
24
|
+
return err and err.stack
|
|
25
|
+
|
|
26
|
+
def format_exception(exc, limit):
|
|
27
|
+
if jstype(exc) is 'undefined':
|
|
28
|
+
exc = ρσ_last_exception
|
|
29
|
+
if not isinstance(exc, Error):
|
|
30
|
+
if exc and exc.toString:
|
|
31
|
+
return [exc.toString()]
|
|
32
|
+
return []
|
|
33
|
+
tb = _get_internal_traceback(exc)
|
|
34
|
+
if tb:
|
|
35
|
+
lines = ρσ_str.splitlines(tb)
|
|
36
|
+
e = lines[0]
|
|
37
|
+
lines = lines[1:]
|
|
38
|
+
if limit:
|
|
39
|
+
lines = lines[:limit+1] if limit > 0 else lines[limit:]
|
|
40
|
+
lines.reverse()
|
|
41
|
+
lines.push(e)
|
|
42
|
+
lines.insert(0, 'Traceback (most recent call last):')
|
|
43
|
+
return [l+'\n' for l in lines]
|
|
44
|
+
return [exc.toString()]
|
|
45
|
+
|
|
46
|
+
def format_exc(limit):
|
|
47
|
+
return format_exception(ρσ_last_exception, limit).join('')
|
|
48
|
+
|
|
49
|
+
def print_exc(limit):
|
|
50
|
+
print(format_exc(limit))
|
|
51
|
+
|
|
52
|
+
def format_stack(limit):
|
|
53
|
+
stack = Error().stack
|
|
54
|
+
if not stack:
|
|
55
|
+
return []
|
|
56
|
+
lines = str.splitlines(stack)[2:]
|
|
57
|
+
lines.reverse()
|
|
58
|
+
if limit:
|
|
59
|
+
lines = lines[:limit+1] if limit > 0 else lines[limit:]
|
|
60
|
+
return [l + '\n' for l in lines]
|
|
61
|
+
|
|
62
|
+
def print_stack(limit):
|
|
63
|
+
print(format_stack(limit).join(''))
|
package/src/lib/uuid.pyj
CHANGED
|
@@ -1,77 +1,77 @@
|
|
|
1
|
-
# vim:fileencoding=utf-8
|
|
2
|
-
# License: BSD Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
-
# globals: crypto
|
|
4
|
-
from __python__ import hash_literals
|
|
5
|
-
|
|
6
|
-
from encodings import hexlify, urlsafe_b64decode, urlsafe_b64encode
|
|
7
|
-
|
|
8
|
-
RFC_4122 = 1
|
|
9
|
-
|
|
10
|
-
if jstype(crypto) is 'object' and crypto.getRandomValues:
|
|
11
|
-
random_bytes = def (num):
|
|
12
|
-
ans = Uint8Array(num or 16)
|
|
13
|
-
crypto.getRandomValues(ans)
|
|
14
|
-
return ans
|
|
15
|
-
else:
|
|
16
|
-
random_bytes = def (num):
|
|
17
|
-
ans = Uint8Array(num or 16)
|
|
18
|
-
for i in range(ans.length):
|
|
19
|
-
ans[i] = Math.floor(Math.random() * 256)
|
|
20
|
-
return ans
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def uuid4_bytes():
|
|
24
|
-
data = random_bytes()
|
|
25
|
-
data[6] = 0b01000000 | (data[6] & 0b1111)
|
|
26
|
-
data[8] = (((data[8] >> 4) & 0b11 | 0b1000) << 4) | (data[8] & 0b1111)
|
|
27
|
-
return data
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def as_str():
|
|
31
|
-
h = this.hex
|
|
32
|
-
return h[:8] + '-' + h[8:12] + '-' + h[12:16] + '-' + h[16:20] + '-' + h[20:]
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
def uuid4():
|
|
36
|
-
b = uuid4_bytes()
|
|
37
|
-
return {
|
|
38
|
-
'hex': hexlify(b),
|
|
39
|
-
'bytes': b,
|
|
40
|
-
'variant': RFC_4122,
|
|
41
|
-
'version': 4,
|
|
42
|
-
'__str__': as_str,
|
|
43
|
-
'toString': as_str,
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
def num_to_string(numbers, alphabet, pad_to_length):
|
|
48
|
-
ans = v'[]'
|
|
49
|
-
alphabet_len = alphabet.length
|
|
50
|
-
numbers = Array.prototype.slice.call(numbers)
|
|
51
|
-
for v'var i = 0; i < numbers.length - 1; i++':
|
|
52
|
-
x = divmod(numbers[i], alphabet_len)
|
|
53
|
-
numbers[i] = x[0]
|
|
54
|
-
numbers[i+1] += x[1]
|
|
55
|
-
for v'var i = 0; i < numbers.length; i++':
|
|
56
|
-
number = numbers[i]
|
|
57
|
-
while number:
|
|
58
|
-
x = divmod(number, alphabet_len)
|
|
59
|
-
number = x[0]
|
|
60
|
-
ans.push(alphabet[x[1]])
|
|
61
|
-
if pad_to_length and pad_to_length > ans.length:
|
|
62
|
-
ans.push(alphabet[0].repeat(pad_to_length - ans.length))
|
|
63
|
-
return ans.join('')
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
def short_uuid():
|
|
67
|
-
# A totally random uuid encoded using only URL and filename safe characters
|
|
68
|
-
return urlsafe_b64encode(random_bytes(), '')
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def short_uuid4():
|
|
72
|
-
# A uuid4 encoded using only URL and filename safe characters
|
|
73
|
-
return urlsafe_b64encode(uuid4_bytes(), '')
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
def decode_short_uuid(val):
|
|
77
|
-
return urlsafe_b64decode(val + '==')
|
|
1
|
+
# vim:fileencoding=utf-8
|
|
2
|
+
# License: BSD Copyright: 2017, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
|
+
# globals: crypto
|
|
4
|
+
from __python__ import hash_literals
|
|
5
|
+
|
|
6
|
+
from encodings import hexlify, urlsafe_b64decode, urlsafe_b64encode
|
|
7
|
+
|
|
8
|
+
RFC_4122 = 1
|
|
9
|
+
|
|
10
|
+
if jstype(crypto) is 'object' and crypto.getRandomValues:
|
|
11
|
+
random_bytes = def (num):
|
|
12
|
+
ans = Uint8Array(num or 16)
|
|
13
|
+
crypto.getRandomValues(ans)
|
|
14
|
+
return ans
|
|
15
|
+
else:
|
|
16
|
+
random_bytes = def (num):
|
|
17
|
+
ans = Uint8Array(num or 16)
|
|
18
|
+
for i in range(ans.length):
|
|
19
|
+
ans[i] = Math.floor(Math.random() * 256)
|
|
20
|
+
return ans
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def uuid4_bytes():
|
|
24
|
+
data = random_bytes()
|
|
25
|
+
data[6] = 0b01000000 | (data[6] & 0b1111)
|
|
26
|
+
data[8] = (((data[8] >> 4) & 0b11 | 0b1000) << 4) | (data[8] & 0b1111)
|
|
27
|
+
return data
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def as_str():
|
|
31
|
+
h = this.hex
|
|
32
|
+
return h[:8] + '-' + h[8:12] + '-' + h[12:16] + '-' + h[16:20] + '-' + h[20:]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def uuid4():
|
|
36
|
+
b = uuid4_bytes()
|
|
37
|
+
return {
|
|
38
|
+
'hex': hexlify(b),
|
|
39
|
+
'bytes': b,
|
|
40
|
+
'variant': RFC_4122,
|
|
41
|
+
'version': 4,
|
|
42
|
+
'__str__': as_str,
|
|
43
|
+
'toString': as_str,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def num_to_string(numbers, alphabet, pad_to_length):
|
|
48
|
+
ans = v'[]'
|
|
49
|
+
alphabet_len = alphabet.length
|
|
50
|
+
numbers = Array.prototype.slice.call(numbers)
|
|
51
|
+
for v'var i = 0; i < numbers.length - 1; i++':
|
|
52
|
+
x = divmod(numbers[i], alphabet_len)
|
|
53
|
+
numbers[i] = x[0]
|
|
54
|
+
numbers[i+1] += x[1]
|
|
55
|
+
for v'var i = 0; i < numbers.length; i++':
|
|
56
|
+
number = numbers[i]
|
|
57
|
+
while number:
|
|
58
|
+
x = divmod(number, alphabet_len)
|
|
59
|
+
number = x[0]
|
|
60
|
+
ans.push(alphabet[x[1]])
|
|
61
|
+
if pad_to_length and pad_to_length > ans.length:
|
|
62
|
+
ans.push(alphabet[0].repeat(pad_to_length - ans.length))
|
|
63
|
+
return ans.join('')
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def short_uuid():
|
|
67
|
+
# A totally random uuid encoded using only URL and filename safe characters
|
|
68
|
+
return urlsafe_b64encode(random_bytes(), '')
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def short_uuid4():
|
|
72
|
+
# A uuid4 encoded using only URL and filename safe characters
|
|
73
|
+
return urlsafe_b64encode(uuid4_bytes(), '')
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def decode_short_uuid(val):
|
|
77
|
+
return urlsafe_b64decode(val + '==')
|
|
@@ -46,6 +46,95 @@ function dot_path_from_node(node, RS) {
|
|
|
46
46
|
return null;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Infer the type of a single return-value expression.
|
|
51
|
+
* Returns a type string ('list', 'dict', 'str', 'number', 'bool', or a class name),
|
|
52
|
+
* or null if the type cannot be determined from this expression alone.
|
|
53
|
+
*
|
|
54
|
+
* @param {object} node - The AST expression node (return value)
|
|
55
|
+
* @param {ScopeFrame} scope - The function's own scope frame (fully populated)
|
|
56
|
+
* @param {object} RS - RapydScript compiler object
|
|
57
|
+
* @returns {string|null}
|
|
58
|
+
*/
|
|
59
|
+
function infer_expr_type(node, scope, RS) {
|
|
60
|
+
if (node instanceof RS.AST_Array) return 'list';
|
|
61
|
+
if (node instanceof RS.AST_Object) return 'dict';
|
|
62
|
+
if (node instanceof RS.AST_String) return 'str';
|
|
63
|
+
if (node instanceof RS.AST_Number) return 'number';
|
|
64
|
+
if ((RS.AST_True && node instanceof RS.AST_True) ||
|
|
65
|
+
(RS.AST_False && node instanceof RS.AST_False)) return 'bool';
|
|
66
|
+
if (RS.AST_Null && node instanceof RS.AST_Null) return null; // None → not counted
|
|
67
|
+
|
|
68
|
+
if (node instanceof RS.AST_SymbolRef) {
|
|
69
|
+
const sym = scope ? scope.getSymbol(node.name) : null;
|
|
70
|
+
return (sym && sym.inferred_class) ? sym.inferred_class : null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (node instanceof RS.AST_BaseCall && node.expression instanceof RS.AST_SymbolRef) {
|
|
74
|
+
const name = node.expression.name;
|
|
75
|
+
// PascalCase → assume class constructor, use name as type
|
|
76
|
+
if (/^[A-Z]/.test(name)) return name;
|
|
77
|
+
// Known local function with an already-resolved return_type
|
|
78
|
+
const sym = scope ? scope.getSymbol(name) : null;
|
|
79
|
+
if (sym && sym.return_type) return sym.return_type;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Walk a function node's body, collect all return-expression types, and return
|
|
87
|
+
* the single inferred type if every non-None return agrees on one type.
|
|
88
|
+
* Skips nested function bodies (their returns don't belong to this function).
|
|
89
|
+
* Returns null if returns disagree, are unrecognised, or the body has no typed returns.
|
|
90
|
+
*
|
|
91
|
+
* @param {object} func_node - AST_Lambda node
|
|
92
|
+
* @param {ScopeFrame} func_scope - The function's own scope frame (already populated)
|
|
93
|
+
* @param {object} RS - RapydScript compiler object
|
|
94
|
+
* @returns {string|null}
|
|
95
|
+
*/
|
|
96
|
+
function collect_return_type(func_node, func_scope, RS) {
|
|
97
|
+
const types = new Set();
|
|
98
|
+
// Use a plain visitor object (same pattern as ScopeBuilder): _visit(node, descend)
|
|
99
|
+
// receives the node and a closure that walks its children; call descend() to recurse.
|
|
100
|
+
func_node.walk({
|
|
101
|
+
_visit: function (node, descend) {
|
|
102
|
+
// Stop descent into nested functions — their returns are not ours.
|
|
103
|
+
if (node !== func_node && node instanceof RS.AST_Lambda) return;
|
|
104
|
+
if (node instanceof RS.AST_Return && node.value) {
|
|
105
|
+
const t = infer_expr_type(node.value, func_scope, RS);
|
|
106
|
+
if (t) types.add(t);
|
|
107
|
+
}
|
|
108
|
+
if (descend) descend(); // recurse into children
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
return types.size === 1 ? [...types][0] : null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Extract the return type annotation from a function node as a normalized string.
|
|
116
|
+
* Maps `-> [X]` to 'list', `-> {k: v}` to 'dict', `-> str` to 'str', etc.
|
|
117
|
+
* Returns null if no annotation or unrecognised shape.
|
|
118
|
+
* @param {object} func_node
|
|
119
|
+
* @param {object} RS
|
|
120
|
+
* @returns {string|null}
|
|
121
|
+
*/
|
|
122
|
+
function extract_return_type(func_node, RS) {
|
|
123
|
+
const ann = func_node.return_annotation;
|
|
124
|
+
if (!ann) return null;
|
|
125
|
+
if (ann instanceof RS.AST_Array) return 'list';
|
|
126
|
+
if (ann instanceof RS.AST_Object) return 'dict';
|
|
127
|
+
if (ann instanceof RS.AST_SymbolRef ||
|
|
128
|
+
(RS.AST_SymbolVar && ann instanceof RS.AST_SymbolVar)) {
|
|
129
|
+
const n = ann.name;
|
|
130
|
+
if (n === 'str' || n === 'string') return 'str';
|
|
131
|
+
if (n === 'int' || n === 'float' || n === 'number') return 'number';
|
|
132
|
+
if (n === 'bool' || n === 'boolean') return 'bool';
|
|
133
|
+
return n; // user-defined class name or 'list'/'dict' spelled out
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
|
|
49
138
|
/**
|
|
50
139
|
* Collect parameter descriptors from an AST_Lambda node.
|
|
51
140
|
* Handles regular args, positional-only (/), keyword-only (*), *args, and **kwargs.
|
|
@@ -94,10 +183,11 @@ function extract_params(lambda_node) {
|
|
|
94
183
|
|
|
95
184
|
class ScopeBuilder {
|
|
96
185
|
constructor(RS, map) {
|
|
97
|
-
this._RS
|
|
98
|
-
this._map
|
|
99
|
-
this._scopes
|
|
100
|
-
this.current_node
|
|
186
|
+
this._RS = RS;
|
|
187
|
+
this._map = map;
|
|
188
|
+
this._scopes = []; // stack of ScopeFrame
|
|
189
|
+
this.current_node = null;
|
|
190
|
+
this._current_from_module = null; // set while inside an AST_Import with argnames
|
|
101
191
|
}
|
|
102
192
|
|
|
103
193
|
_current_scope() {
|
|
@@ -143,6 +233,9 @@ class ScopeBuilder {
|
|
|
143
233
|
params: opts.params || null,
|
|
144
234
|
inferred_class: opts.inferred_class || null,
|
|
145
235
|
dts_call_path: opts.dts_call_path || null,
|
|
236
|
+
return_type: opts.return_type || null,
|
|
237
|
+
source_module: opts.source_module || null,
|
|
238
|
+
original_name: opts.original_name || null,
|
|
146
239
|
});
|
|
147
240
|
scope.addSymbol(sym);
|
|
148
241
|
return sym;
|
|
@@ -176,6 +269,7 @@ class ScopeBuilder {
|
|
|
176
269
|
scope_depth: parent.depth,
|
|
177
270
|
doc: extract_doc(node),
|
|
178
271
|
params: extract_params(node),
|
|
272
|
+
return_type: extract_return_type(node, RS),
|
|
179
273
|
});
|
|
180
274
|
parent.addSymbol(sym);
|
|
181
275
|
}
|
|
@@ -239,18 +333,28 @@ class ScopeBuilder {
|
|
|
239
333
|
defined_at: pos_from_token(node.start),
|
|
240
334
|
});
|
|
241
335
|
|
|
336
|
+
} else if (node instanceof RS.AST_Import && node.argnames) {
|
|
337
|
+
// `from X import name [as alias], ...` — record module name so children can use it.
|
|
338
|
+
const mod_node = node.module;
|
|
339
|
+
this._current_from_module = mod_node
|
|
340
|
+
? (mod_node.name || mod_node.value || null)
|
|
341
|
+
: null;
|
|
342
|
+
|
|
242
343
|
} else if (node instanceof RS.AST_ImportedVar) {
|
|
243
344
|
// `from X import name` or `from X import name as alias`
|
|
244
|
-
const
|
|
245
|
-
if (
|
|
345
|
+
const alias = (node.alias && node.alias.name) ? node.alias.name : node.name;
|
|
346
|
+
if (alias) {
|
|
246
347
|
this._add_symbol({
|
|
247
|
-
name,
|
|
248
|
-
kind:
|
|
249
|
-
defined_at:
|
|
348
|
+
name: alias,
|
|
349
|
+
kind: 'import',
|
|
350
|
+
defined_at: pos_from_token(node.start),
|
|
351
|
+
source_module: this._current_from_module || null,
|
|
352
|
+
original_name: (node.name !== alias) ? node.name : null,
|
|
250
353
|
});
|
|
251
354
|
}
|
|
252
355
|
|
|
253
356
|
} else if (node instanceof RS.AST_Import && !node.argnames) {
|
|
357
|
+
this._current_from_module = null;
|
|
254
358
|
// `import X` or `import X as Y` (no from-clause)
|
|
255
359
|
const name = (node.alias && node.alias.name)
|
|
256
360
|
? node.alias.name
|
|
@@ -456,6 +560,24 @@ class ScopeBuilder {
|
|
|
456
560
|
|
|
457
561
|
if (cont) cont();
|
|
458
562
|
|
|
563
|
+
// ------------------------------------------------------------------
|
|
564
|
+
// 3b. Post-traversal: infer return type for unannotated functions.
|
|
565
|
+
// The function's own scope is fully populated at this point, so
|
|
566
|
+
// local variable inferred_class values are available for lookup.
|
|
567
|
+
// ------------------------------------------------------------------
|
|
568
|
+
|
|
569
|
+
if (node instanceof RS.AST_Lambda && this._scopes.length > prev_depth) {
|
|
570
|
+
const func_scope = this._current_scope();
|
|
571
|
+
const parent_frame = func_scope ? func_scope.parent : null;
|
|
572
|
+
const fname = node.name ? node.name.name : null;
|
|
573
|
+
if (fname && parent_frame) {
|
|
574
|
+
const sym = parent_frame.getSymbol(fname);
|
|
575
|
+
if (sym && !sym.return_type) {
|
|
576
|
+
sym.return_type = collect_return_type(node, func_scope, RS);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
459
581
|
// ------------------------------------------------------------------
|
|
460
582
|
// 4. Pop the scope we pushed (if any).
|
|
461
583
|
// ------------------------------------------------------------------
|
|
@@ -104,6 +104,11 @@ const STUBS = [
|
|
|
104
104
|
return_type: 'iterable',
|
|
105
105
|
doc: 'Return an iterator of elements from iterable for which function returns true.' }),
|
|
106
106
|
|
|
107
|
+
new BuiltinInfo({ name: 'format',
|
|
108
|
+
params: [p('value'), p('spec', { type: 'str', optional: true })],
|
|
109
|
+
return_type: 'str',
|
|
110
|
+
doc: 'Return value formatted according to the format spec string.\n\nEquivalent to calling `value.__format__(spec)` or applying spec as a `str.format()` format-spec field. The spec mini-language is the same as what follows `:` in f-strings and `str.format()` fields: alignment (`<>^=`), sign (`+-`), width, grouping (`,_`), precision (`.N`), and type (`bcdoxXeEfFgGns%`).\n\nExamples:\n\n format(42, \'08b\') # \'00101010\'\n format(3.14, \'.2f\') # \'3.14\'\n format(\'hi\', \'>10\') # \' hi\'\n format(42) # \'42\'' }),
|
|
111
|
+
|
|
107
112
|
new BuiltinInfo({ name: 'float', kind: 'class',
|
|
108
113
|
params: [p('x', { optional: true })],
|
|
109
114
|
return_type: 'float',
|
|
@@ -150,9 +155,9 @@ const STUBS = [
|
|
|
150
155
|
doc: 'Return True if cls is a subclass of classinfo. classinfo may be a class or tuple of classes.' }),
|
|
151
156
|
|
|
152
157
|
new BuiltinInfo({ name: 'iter',
|
|
153
|
-
params: [p('obj')],
|
|
158
|
+
params: [p('obj'), p('sentinel', { optional: true })],
|
|
154
159
|
return_type: 'iterator',
|
|
155
|
-
doc: '
|
|
160
|
+
doc: 'iter(iterable) → iterator over iterable. iter(callable, sentinel) → calls callable repeatedly until it returns sentinel.' }),
|
|
156
161
|
|
|
157
162
|
new BuiltinInfo({ name: 'len',
|
|
158
163
|
params: [p('s')],
|
|
@@ -164,6 +169,11 @@ const STUBS = [
|
|
|
164
169
|
return_type: 'list',
|
|
165
170
|
doc: 'Create a list from an iterable, or an empty list.' }),
|
|
166
171
|
|
|
172
|
+
new BuiltinInfo({ name: 'next',
|
|
173
|
+
params: [p('iterator'), p('default', { optional: true })],
|
|
174
|
+
return_type: 'any',
|
|
175
|
+
doc: 'Retrieve the next item from an iterator. If the iterator is exhausted, return default; if default is not given, raise StopIteration.' }),
|
|
176
|
+
|
|
167
177
|
new BuiltinInfo({ name: 'map',
|
|
168
178
|
params: [p('function'), p('iterable'), p('*iterables', { rest: true })],
|
|
169
179
|
return_type: 'iterable',
|
|
@@ -219,6 +229,11 @@ const STUBS = [
|
|
|
219
229
|
return_type: 'set',
|
|
220
230
|
doc: 'Create a new set, optionally populated from an iterable.' }),
|
|
221
231
|
|
|
232
|
+
new BuiltinInfo({ name: 'slice', kind: 'class',
|
|
233
|
+
params: [p('start_or_stop', { type: 'int' }), p('stop', { type: 'int', optional: true }), p('step', { type: 'int', optional: true })],
|
|
234
|
+
return_type: 'slice',
|
|
235
|
+
doc: 'Create a slice object representing the set of indices specified by range(start, stop, step).\n\nForms:\n- `slice(stop)` — equivalent to `slice(None, stop, None)`\n- `slice(start, stop)` — equivalent to `slice(start, stop, None)`\n- `slice(start, stop, step)` — full form\n\nAttributes: `.start`, `.stop`, `.step` (each may be `None`).\n\nMethod: `.indices(length)` — returns `(start, stop, step)` normalized for a sequence of the given length.\n\nExample:\n\n s = slice(1, 5)\n lst[s] # same as lst[1:5]\n s.indices(10) # (1, 5, 1)' }),
|
|
236
|
+
|
|
222
237
|
new BuiltinInfo({ name: 'setattr',
|
|
223
238
|
params: [p('obj'), p('name', { type: 'str' }), p('value')],
|
|
224
239
|
return_type: 'None',
|