rapydscript-ng 0.8.3 → 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/CHANGELOG.md +6 -0
- package/bin/build.ts +29 -0
- package/package.json +1 -1
- package/release/baselib-plain-pretty.js +85 -61
- package/release/baselib-plain-ugly.js +3 -3
- package/release/compiler.js +2543 -2432
- package/release/signatures.json +26 -26
- package/src/ast.pyj +170 -58
- package/src/baselib-builtins.pyj +35 -14
- package/src/baselib-containers.pyj +70 -40
- package/src/baselib-internal.pyj +20 -8
- package/src/baselib-itertools.pyj +6 -2
- package/src/baselib-str.pyj +74 -28
- package/src/errors.pyj +4 -1
- package/src/lib/aes.pyj +664 -35
- package/src/lib/elementmaker.pyj +105 -13
- package/src/lib/encodings.pyj +31 -7
- package/src/lib/gettext.pyj +6 -3
- package/src/lib/math.pyj +38 -22
- package/src/lib/pythonize.pyj +5 -3
- package/src/lib/random.pyj +13 -5
- package/src/lib/re.pyj +81 -18
- package/src/lib/traceback.pyj +42 -10
- package/src/lib/uuid.pyj +2 -1
- package/src/output/classes.pyj +70 -26
- package/src/output/codegen.pyj +92 -20
- package/src/output/comments.pyj +11 -4
- package/src/output/exceptions.pyj +17 -4
- package/src/output/functions.pyj +34 -13
- package/src/output/literals.pyj +7 -2
- package/src/output/loops.pyj +50 -16
- package/src/output/modules.pyj +41 -12
- package/src/output/operators.pyj +154 -31
- package/src/output/statements.pyj +38 -10
- package/src/output/stream.pyj +43 -12
- package/src/output/utils.pyj +10 -3
- package/src/parse.pyj +740 -259
- package/src/string_interpolation.pyj +4 -1
- package/src/tokenizer.pyj +300 -55
- package/src/unicode_aliases.pyj +4 -2
- package/src/utils.pyj +19 -5
- package/test/functions.pyj +8 -0
- package/test/generic.pyj +9 -0
- package/test/lsp.pyj +16 -0
- package/tools/compiler.mjs +0 -6
- package/tools/fmt.mjs +41 -2
- package/tools/lint-worker.mjs +7 -1
- package/tools/lint.mjs +12 -5
- package/tools/lsp.mjs +11 -1
package/src/utils.pyj
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
# License: BSD Copyright: 2016, Kovid Goyal <kovid at kovidgoyal.net>
|
|
3
3
|
from __python__ import hash_literals
|
|
4
4
|
|
|
5
|
-
has_prop = Object.prototype.hasOwnProperty.call.bind(
|
|
5
|
+
has_prop = Object.prototype.hasOwnProperty.call.bind(
|
|
6
|
+
Object.prototype.hasOwnProperty)
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
def array_to_hash(a):
|
|
@@ -41,7 +42,11 @@ def repeat_string(str_, i):
|
|
|
41
42
|
|
|
42
43
|
class DefaultsError(ValueError):
|
|
43
44
|
def __init__(self, name, defs):
|
|
44
|
-
ValueError.__init__(
|
|
45
|
+
ValueError.__init__(
|
|
46
|
+
self,
|
|
47
|
+
name + ' is not a supported option. Supported options are: '
|
|
48
|
+
+ str(Object.keys(defs))
|
|
49
|
+
)
|
|
45
50
|
|
|
46
51
|
|
|
47
52
|
def defaults(args, defs, croak):
|
|
@@ -80,12 +85,18 @@ MAP = def ():
|
|
|
80
85
|
if isinstance(val, AtTop):
|
|
81
86
|
val = val.v
|
|
82
87
|
if isinstance(val, Splice):
|
|
83
|
-
top.push.apply(
|
|
88
|
+
top.push.apply(
|
|
89
|
+
top,
|
|
90
|
+
(val.v.slice().reverse() if backwards else val.v)
|
|
91
|
+
)
|
|
84
92
|
else:
|
|
85
93
|
top.push(val)
|
|
86
94
|
elif val is not skip:
|
|
87
95
|
if isinstance(val, Splice):
|
|
88
|
-
ret.push.apply(
|
|
96
|
+
ret.push.apply(
|
|
97
|
+
ret,
|
|
98
|
+
(val.v.slice().reverse() if backwards else val.v)
|
|
99
|
+
)
|
|
89
100
|
else:
|
|
90
101
|
ret.push(val)
|
|
91
102
|
return is_last
|
|
@@ -205,5 +216,8 @@ def make_predicate(words):
|
|
|
205
216
|
def cache_file_name(src, cache_dir):
|
|
206
217
|
if cache_dir:
|
|
207
218
|
src = str.replace(src, '\\', '/')
|
|
208
|
-
return cache_dir + '/' + str.lstrip(
|
|
219
|
+
return cache_dir + '/' + str.lstrip(
|
|
220
|
+
str.replace(src, '/', '-') + '.bin',
|
|
221
|
+
'-'
|
|
222
|
+
)
|
|
209
223
|
return src + '-cached'
|
package/test/functions.pyj
CHANGED
|
@@ -22,6 +22,14 @@ mul = None
|
|
|
22
22
|
assrt.equal(add(1,2), 3)
|
|
23
23
|
assrt.equal(sub(1,2), -1)
|
|
24
24
|
assrt.equal(mul(2,2), 4)
|
|
25
|
+
|
|
26
|
+
# newline as implicit comma separator in function calls
|
|
27
|
+
assrt.equal(add(1
|
|
28
|
+
2), 3)
|
|
29
|
+
assrt.equal(sub(1
|
|
30
|
+
2), -1)
|
|
31
|
+
assrt.equal(add(list().length
|
|
32
|
+
list().length), 0)
|
|
25
33
|
# for some reason input to throws must be of type block, hence the 'def' wrapper
|
|
26
34
|
assrt.throws(
|
|
27
35
|
def():
|
package/test/generic.pyj
CHANGED
|
@@ -48,6 +48,15 @@ assrt.deepEqual((1,
|
|
|
48
48
|
assrt.deepEqual((1,
|
|
49
49
|
2), [1, 2])
|
|
50
50
|
|
|
51
|
+
# Tuples with newlines as implicit separators (no comma)
|
|
52
|
+
assrt.deepEqual((1
|
|
53
|
+
2), [1, 2])
|
|
54
|
+
assrt.deepEqual((list()
|
|
55
|
+
list()), [[], []])
|
|
56
|
+
assrt.deepEqual((1
|
|
57
|
+
2
|
|
58
|
+
3), [1, 2, 3])
|
|
59
|
+
|
|
51
60
|
# Conditional operators
|
|
52
61
|
assrt.equal(1 if True else 2, 1)
|
|
53
62
|
assrt.equal(1
|
package/test/lsp.pyj
CHANGED
|
@@ -50,6 +50,22 @@ async def test_diagnostics():
|
|
|
50
50
|
assrt.ok(c['import-unresolved'], 'expected import-unresolved for nonexistent_module')
|
|
51
51
|
fs.rmSync(tmp, {'recursive': True})
|
|
52
52
|
|
|
53
|
+
async def test_globals_directive_suppresses_undef():
|
|
54
|
+
tmp = write_workspace()
|
|
55
|
+
ctx = make_ctx(tmp)
|
|
56
|
+
uri = uri_of(path.join(tmp, 'globals_test.pyj'))
|
|
57
|
+
# ext_func is declared via # globals: so it must not produce an undef diagnostic.
|
|
58
|
+
text = '# globals: ext_func\n\nresult = ext_func(42)\n'
|
|
59
|
+
diags = await lsp.compute_diagnostics(ctx, uri, text)
|
|
60
|
+
c = codes(diags)
|
|
61
|
+
assrt.ok(not c['undef'], 'ext_func declared in # globals: must not be flagged as undef')
|
|
62
|
+
# A name NOT in # globals: must still be flagged.
|
|
63
|
+
text2 = '# globals: ext_func\n\nresult = ext_func(42)\nbad = undeclared_thing()\n'
|
|
64
|
+
diags2 = await lsp.compute_diagnostics(ctx, uri, text2)
|
|
65
|
+
c2 = codes(diags2)
|
|
66
|
+
assrt.ok(c2['undef'], 'undeclared_thing not in # globals: must still be flagged as undef')
|
|
67
|
+
fs.rmSync(tmp, {'recursive': True})
|
|
68
|
+
|
|
53
69
|
async def test_hover_and_definition():
|
|
54
70
|
tmp = write_workspace()
|
|
55
71
|
ctx = make_ctx(tmp)
|
package/tools/compiler.mjs
CHANGED
|
@@ -13,7 +13,6 @@ import path from 'path';
|
|
|
13
13
|
import fs from 'fs';
|
|
14
14
|
import crypto from 'crypto';
|
|
15
15
|
import vm from 'vm';
|
|
16
|
-
import * as terser from 'terser';
|
|
17
16
|
import { fileURLToPath } from 'url';
|
|
18
17
|
import { createRequire } from 'module';
|
|
19
18
|
import { generate_source_map } from './sourcemap.mjs';
|
|
@@ -39,11 +38,6 @@ async function path_exists(p) {
|
|
|
39
38
|
}
|
|
40
39
|
}
|
|
41
40
|
|
|
42
|
-
function uglify(code) {
|
|
43
|
-
var ans = terser.minify_sync(code);
|
|
44
|
-
if (ans.error) throw ans.error;
|
|
45
|
-
return ans.code;
|
|
46
|
-
}
|
|
47
41
|
|
|
48
42
|
|
|
49
43
|
async function find_compiler_dir() {
|
package/tools/fmt.mjs
CHANGED
|
@@ -848,13 +848,51 @@ function normalize_opts(options) {
|
|
|
848
848
|
// check-only reporting
|
|
849
849
|
// ---------------------------------------------------------------------------
|
|
850
850
|
|
|
851
|
+
// Returns a Set of 0-based line indices that fall inside vr/v verbatim
|
|
852
|
+
// triple-quoted blocks. The formatter cannot reflow that content (it is
|
|
853
|
+
// raw JS/text), so line-length violations inside those blocks are skipped.
|
|
854
|
+
function verbatim_line_set(lines) {
|
|
855
|
+
var skip = new Set();
|
|
856
|
+
var in_block = false;
|
|
857
|
+
var close_q = null;
|
|
858
|
+
for (var i = 0; i < lines.length; i++) {
|
|
859
|
+
var line = lines[i];
|
|
860
|
+
if (!in_block) {
|
|
861
|
+
// Detect the opening of a verbatim triple-quoted block.
|
|
862
|
+
// Patterns: vr''', vr""", v''', v""" (with any combination of
|
|
863
|
+
// v/r/u/f prefix letters, case-insensitive).
|
|
864
|
+
var m = /\b[vrufVRUF]*(?:'{3}|"{3})/.exec(line);
|
|
865
|
+
if (m) {
|
|
866
|
+
var q = m[0].slice(-3); // ''' or """
|
|
867
|
+
var after = line.slice(m.index + m[0].length);
|
|
868
|
+
if (after.indexOf(q) < 0) {
|
|
869
|
+
// Block does not close on the same line.
|
|
870
|
+
in_block = true;
|
|
871
|
+
close_q = q;
|
|
872
|
+
skip.add(i); // opening line itself may be long
|
|
873
|
+
}
|
|
874
|
+
// If it closes on the same line we leave skip alone —
|
|
875
|
+
// the single-line v'...' case is handled per-line below.
|
|
876
|
+
}
|
|
877
|
+
} else {
|
|
878
|
+
skip.add(i);
|
|
879
|
+
if (line.indexOf(close_q) >= 0) {
|
|
880
|
+
in_block = false;
|
|
881
|
+
close_q = null;
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return skip;
|
|
886
|
+
}
|
|
887
|
+
|
|
851
888
|
export function check_report(file, src, formatted, options) {
|
|
852
889
|
var opts = normalize_opts(options);
|
|
853
890
|
var errs = [];
|
|
854
891
|
if (formatted !== src.replace(/\r\n?/g, '\n')) errs.push(file + ': would be reformatted');
|
|
855
892
|
var lines = formatted.split('\n');
|
|
893
|
+
var skip = verbatim_line_set(lines);
|
|
856
894
|
for (var i = 0; i < lines.length; i++) {
|
|
857
|
-
if (lines[i].length > opts.line_length) {
|
|
895
|
+
if (!skip.has(i) && lines[i].length > opts.line_length) {
|
|
858
896
|
errs.push(file + ':' + (i + 1) + ': line exceeds ' + opts.line_length + ' characters (' + lines[i].length + ')');
|
|
859
897
|
}
|
|
860
898
|
}
|
|
@@ -970,8 +1008,9 @@ export async function cli(argv, base_path, src_path, lib_path) {
|
|
|
970
1008
|
console.log('reformatted ' + f);
|
|
971
1009
|
}
|
|
972
1010
|
var flines = formatted.split('\n');
|
|
1011
|
+
var fskip = verbatim_line_set(flines);
|
|
973
1012
|
for (var li = 0; li < flines.length; li++) {
|
|
974
|
-
if (flines[li].length > opts.line_length) {
|
|
1013
|
+
if (!fskip.has(li) && flines[li].length > opts.line_length) {
|
|
975
1014
|
console.error(f + ':' + (li + 1) + ': line exceeds ' + opts.line_length + ' characters (' + flines[li].length + ')');
|
|
976
1015
|
had_errors = true;
|
|
977
1016
|
}
|
package/tools/lint-worker.mjs
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* instance so parsing can run on multiple CPU cores simultaneously.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { parentPort } from 'worker_threads';
|
|
11
|
+
import { parentPort, workerData } from 'worker_threads';
|
|
12
12
|
import { create_compiler } from './compiler.mjs';
|
|
13
13
|
import { read_config } from './ini.mjs';
|
|
14
14
|
import * as utils from './utils.mjs';
|
|
@@ -18,6 +18,12 @@ import path from 'path';
|
|
|
18
18
|
const merge = utils.merge;
|
|
19
19
|
const has_prop = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
|
|
20
20
|
|
|
21
|
+
// Restore embedded assets forwarded by the main thread (needed in compiled binaries
|
|
22
|
+
// where workers don't inherit the main thread's globalThis).
|
|
23
|
+
if (workerData && workerData.embedded) {
|
|
24
|
+
globalThis.__rapydscript_embedded__ = workerData.embedded;
|
|
25
|
+
}
|
|
26
|
+
|
|
21
27
|
// Initialize the compiler first — lint.mjs reads globalThis.create_rapydscript_compiler
|
|
22
28
|
// at module evaluation time, so the global must be set before the dynamic import.
|
|
23
29
|
const compiler = await create_compiler();
|
package/tools/lint.mjs
CHANGED
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
|
|
8
8
|
import fs from 'fs';
|
|
9
9
|
import path from 'path';
|
|
10
|
-
import { fileURLToPath } from 'url';
|
|
11
10
|
import { read_config } from './ini.mjs';
|
|
12
11
|
import * as utils from './utils.mjs';
|
|
13
12
|
|
|
@@ -805,11 +804,19 @@ export async function cli(argv, base_path, src_path, lib_path) {
|
|
|
805
804
|
// Workers own their own compiler instance so parsing runs in parallel across CPU cores.
|
|
806
805
|
var WORKER_THRESHOLD = 4;
|
|
807
806
|
|
|
808
|
-
|
|
807
|
+
// In compiled binaries lint.mjs is dynamically imported so Bun's static
|
|
808
|
+
// analysis never sees the new Worker() call. build.ts pre-bundles
|
|
809
|
+
// lint-worker.mjs and embeds it via `with { type: 'file' }`, storing the
|
|
810
|
+
// virtual-FS path in __rapydscript_embedded__['lint-worker-url'].
|
|
811
|
+
// Fall back gracefully (single-threaded) if the URL isn't available.
|
|
812
|
+
var embedded = globalThis.__rapydscript_embedded__;
|
|
813
|
+
var worker_url = embedded
|
|
814
|
+
? embedded['lint-worker-url']
|
|
815
|
+
: new URL('./lint-worker.mjs', import.meta.url);
|
|
816
|
+
|
|
817
|
+
if (!has_stdin && all_files.length >= WORKER_THRESHOLD && worker_url) {
|
|
809
818
|
var { Worker } = await import('worker_threads');
|
|
810
819
|
var os_mod = await import('os');
|
|
811
|
-
|
|
812
|
-
var worker_path = path.join(path.dirname(fileURLToPath(import.meta.url)), 'lint-worker.mjs');
|
|
813
820
|
var num_workers = Math.min(os_mod.cpus().length, all_files.length, 8);
|
|
814
821
|
|
|
815
822
|
// Dispatch files to workers dynamically so fast files don't leave workers idle.
|
|
@@ -836,7 +843,7 @@ export async function cli(argv, base_path, src_path, lib_path) {
|
|
|
836
843
|
// waiting for all workers before starting any work.
|
|
837
844
|
var worker_promises = Array.from({length: num_workers}, function() {
|
|
838
845
|
return new Promise(function(resolve) {
|
|
839
|
-
var w = new Worker(
|
|
846
|
+
var w = new Worker(worker_url, { workerData: { embedded: embedded || null } });
|
|
840
847
|
w.once('message', function(m) {
|
|
841
848
|
if (m.type !== 'ready') return;
|
|
842
849
|
w.on('message', function(msg) {
|
package/tools/lsp.mjs
CHANGED
|
@@ -230,7 +230,7 @@ export async function compute_diagnostics(ctx, uri, raw_text) {
|
|
|
230
230
|
// 2. Linter diagnostics -- only when the file parsed cleanly, so we do not
|
|
231
231
|
// emit misleading undefined/unused warnings from a partial AST.
|
|
232
232
|
if (a.toplevel && (!a.recovered_errors || a.recovered_errors.length === 0)) {
|
|
233
|
-
var builtins = utils.merge(BUILTINS);
|
|
233
|
+
var builtins = utils.merge(BUILTINS, file_globals(a.text));
|
|
234
234
|
var messages = lint_parsed(a.toplevel, a.text, { filename: a.file_path, builtins: builtins, noqa: file_noqa(a.text) });
|
|
235
235
|
messages.forEach(function (m) {
|
|
236
236
|
out.push(lint_message_to_diagnostic(doc, m));
|
|
@@ -265,6 +265,16 @@ function file_noqa(code) {
|
|
|
265
265
|
return noqa;
|
|
266
266
|
}
|
|
267
267
|
|
|
268
|
+
// Parse `# globals: a,b` file-level directives from the first lines (mirrors lint cli).
|
|
269
|
+
function file_globals(code) {
|
|
270
|
+
var globals = Object.create(null);
|
|
271
|
+
code.split('\n', 20).forEach(function (line) {
|
|
272
|
+
var lq = line.replace(/\s+/g, '');
|
|
273
|
+
if (lq.slice(0, 9).toLowerCase() === '#globals:') (lq.split(':', 2)[1] || '').split(',').forEach(function (x) { if (x) globals[x] = true; });
|
|
274
|
+
});
|
|
275
|
+
return globals;
|
|
276
|
+
}
|
|
277
|
+
|
|
268
278
|
function lint_message_to_diagnostic(doc, m) {
|
|
269
279
|
var start_line = (m.start_line || 1) - 1;
|
|
270
280
|
var start_col = (m.start_col === undefined || m.start_col === null) ? 0 : m.start_col;
|