rapydscript-ng 0.8.0 → 0.8.2
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 +14 -0
- package/README.md +8 -0
- package/bin/build.ts +117 -0
- package/build_wheels.py +133 -0
- package/editor-plugins/README.md +80 -0
- package/editor-plugins/nvim.lua +321 -0
- package/package.json +1 -1
- package/publish.py +27 -17
- package/release/compiler.js +8125 -8093
- package/release/signatures.json +27 -27
- package/release/stdlib_modules.json +1 -0
- package/src/ast.pyj +379 -279
- package/src/baselib-builtins.pyj +47 -26
- package/src/baselib-containers.pyj +105 -92
- package/src/baselib-errors.pyj +8 -1
- package/src/baselib-internal.pyj +35 -20
- package/src/baselib-itertools.pyj +13 -7
- package/src/baselib-str.pyj +55 -80
- package/src/compiler.pyj +4 -4
- package/src/errors.pyj +3 -4
- package/src/lib/aes.pyj +46 -32
- package/src/lib/elementmaker.pyj +11 -9
- package/src/lib/encodings.pyj +15 -5
- package/src/lib/gettext.pyj +9 -4
- package/src/lib/math.pyj +106 -45
- package/src/lib/operator.pyj +10 -10
- package/src/lib/pythonize.pyj +2 -1
- package/src/lib/random.pyj +28 -21
- package/src/lib/re.pyj +490 -17
- package/src/lib/traceback.pyj +7 -2
- package/src/lib/uuid.pyj +2 -2
- package/src/output/classes.pyj +28 -27
- package/src/output/codegen.pyj +80 -83
- package/src/output/comments.pyj +8 -8
- package/src/output/exceptions.pyj +20 -21
- package/src/output/functions.pyj +37 -26
- package/src/output/literals.pyj +14 -10
- package/src/output/loops.pyj +63 -59
- package/src/output/modules.pyj +52 -23
- package/src/output/operators.pyj +40 -29
- package/src/output/statements.pyj +20 -14
- package/src/output/stream.pyj +33 -34
- package/src/output/utils.pyj +12 -8
- package/src/parse.pyj +234 -233
- package/src/string_interpolation.pyj +5 -3
- package/src/tokenizer.pyj +176 -148
- package/src/utils.pyj +31 -14
- package/test/fmt.pyj +94 -4
- package/test/generic.pyj +9 -0
- package/test/lsp.pyj +35 -0
- package/test/str.pyj +8 -0
- package/tools/cli.mjs +25 -4
- package/tools/compile.mjs +7 -3
- package/tools/compiler.mjs +34 -2
- package/tools/fmt.mjs +269 -22
- package/tools/ini.mjs +112 -1
- package/tools/lsp.mjs +56 -6
- package/tools/repl.mjs +5 -2
- package/tools/self.mjs +15 -0
- package/tools/test.mjs +100 -0
- package/tools/web_repl_export.mjs +4 -0
- package/tree-sitter/package.json +1 -1
- package/tree-sitter/tree-sitter.json +1 -1
- package/editor-plugins/nvim/rapydscript/README.md +0 -184
- package/editor-plugins/nvim/rapydscript/bin/rapydscript.so +0 -0
- package/editor-plugins/nvim/rapydscript/ftdetect/rapydscript.lua +0 -10
- package/editor-plugins/nvim/rapydscript/lua/rapydscript/health.lua +0 -88
- package/editor-plugins/nvim/rapydscript/lua/rapydscript/init.lua +0 -279
- /package/tree-sitter/queries/{rapydscript/highlights.scm → highlights.scm} +0 -0
- /package/tree-sitter/queries/{rapydscript/indents.scm → indents.scm} +0 -0
- /package/tree-sitter/queries/{rapydscript/injections.scm → injections.scm} +0 -0
- /package/tree-sitter/queries/{rapydscript/locals.scm → locals.scm} +0 -0
package/src/utils.pyj
CHANGED
|
@@ -4,27 +4,32 @@ from __python__ import hash_literals
|
|
|
4
4
|
|
|
5
5
|
has_prop = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty)
|
|
6
6
|
|
|
7
|
+
|
|
7
8
|
def array_to_hash(a):
|
|
8
9
|
ret = Object.create(None)
|
|
9
10
|
for i in range(len(a)):
|
|
10
11
|
ret[a[i]] = True
|
|
11
12
|
return ret
|
|
12
13
|
|
|
14
|
+
|
|
13
15
|
def slice(a, start):
|
|
14
16
|
return Array.prototype.slice.call(a, start or 0)
|
|
15
17
|
|
|
18
|
+
|
|
16
19
|
def characters(str_):
|
|
17
|
-
return str_.split(
|
|
20
|
+
return str_.split('')
|
|
21
|
+
|
|
18
22
|
|
|
19
23
|
def member(name, array):
|
|
20
|
-
for i in range(array.length-1, -1, -1):
|
|
24
|
+
for i in range(array.length - 1, -1, -1):
|
|
21
25
|
if array[i] is name:
|
|
22
26
|
return True
|
|
23
27
|
return False
|
|
24
28
|
|
|
29
|
+
|
|
25
30
|
def repeat_string(str_, i):
|
|
26
31
|
if i <= 0:
|
|
27
|
-
return
|
|
32
|
+
return ''
|
|
28
33
|
if i is 1:
|
|
29
34
|
return str_
|
|
30
35
|
d = repeat_string(str_, i >> 1)
|
|
@@ -33,11 +38,12 @@ def repeat_string(str_, i):
|
|
|
33
38
|
d += str_
|
|
34
39
|
return d
|
|
35
40
|
|
|
36
|
-
class DefaultsError(ValueError):
|
|
37
41
|
|
|
42
|
+
class DefaultsError(ValueError):
|
|
38
43
|
def __init__(self, name, defs):
|
|
39
44
|
ValueError.__init__(self, name + ' is not a supported option. Supported options are: ' + str(Object.keys(defs)))
|
|
40
45
|
|
|
46
|
+
|
|
41
47
|
def defaults(args, defs, croak):
|
|
42
48
|
if args is True:
|
|
43
49
|
args = {}
|
|
@@ -51,15 +57,17 @@ def defaults(args, defs, croak):
|
|
|
51
57
|
ret[i] = args[i] if args and has_prop(args, i) else defs[i]
|
|
52
58
|
return ret
|
|
53
59
|
|
|
60
|
+
|
|
54
61
|
def merge(obj, ext):
|
|
55
62
|
for i in ext:
|
|
56
63
|
obj[i] = ext[i]
|
|
57
64
|
return obj
|
|
58
65
|
|
|
66
|
+
|
|
59
67
|
def noop():
|
|
60
68
|
pass
|
|
61
69
|
|
|
62
|
-
MAP = def():
|
|
70
|
+
MAP = def ():
|
|
63
71
|
def MAP(a, f, backwards):
|
|
64
72
|
ret = []
|
|
65
73
|
top = []
|
|
@@ -84,7 +92,7 @@ MAP = def():
|
|
|
84
92
|
|
|
85
93
|
if Array.isArray(a):
|
|
86
94
|
if backwards:
|
|
87
|
-
for i in range(a.length-1, -1, -1):
|
|
95
|
+
for i in range(a.length - 1, -1, -1):
|
|
88
96
|
if doit():
|
|
89
97
|
break
|
|
90
98
|
ret.reverse()
|
|
@@ -99,14 +107,15 @@ MAP = def():
|
|
|
99
107
|
break
|
|
100
108
|
return top.concat(ret)
|
|
101
109
|
|
|
102
|
-
MAP.at_top = def(val):
|
|
110
|
+
MAP.at_top = def (val):
|
|
103
111
|
return new AtTop(val)
|
|
104
|
-
MAP.splice = def(val):
|
|
112
|
+
MAP.splice = def (val):
|
|
105
113
|
return new Splice(val)
|
|
106
|
-
MAP.last = def(val):
|
|
114
|
+
MAP.last = def (val):
|
|
107
115
|
return new Last(val)
|
|
108
116
|
|
|
109
117
|
skip = MAP.skip = {}
|
|
118
|
+
|
|
110
119
|
def AtTop(val):
|
|
111
120
|
this.v = val
|
|
112
121
|
|
|
@@ -119,20 +128,24 @@ MAP = def():
|
|
|
119
128
|
return MAP
|
|
120
129
|
.call(this)
|
|
121
130
|
|
|
131
|
+
|
|
122
132
|
def push_uniq(array, el):
|
|
123
133
|
if array.indexOf(el) < 0:
|
|
124
134
|
array.push(el)
|
|
125
135
|
|
|
136
|
+
|
|
126
137
|
def string_template(text, props):
|
|
127
|
-
return text.replace(/\{(.+?)\}/g, def(str_, p):
|
|
138
|
+
return text.replace(/\{(.+?)\}/g, def (str_, p):
|
|
128
139
|
return props[p]
|
|
129
140
|
)
|
|
130
141
|
|
|
142
|
+
|
|
131
143
|
def remove(array, el):
|
|
132
|
-
for i in range(array.length-1, -1, -1):
|
|
144
|
+
for i in range(array.length - 1, -1, -1):
|
|
133
145
|
if array[i] is el:
|
|
134
146
|
array.splice(i, 1)
|
|
135
147
|
|
|
148
|
+
|
|
136
149
|
def mergeSort(array, cmp):
|
|
137
150
|
if array.length < 2:
|
|
138
151
|
return array.slice()
|
|
@@ -167,24 +180,28 @@ def mergeSort(array, cmp):
|
|
|
167
180
|
return merge(left, right)
|
|
168
181
|
return _ms(array)
|
|
169
182
|
|
|
183
|
+
|
|
170
184
|
def set_difference(a, b):
|
|
171
|
-
return a.filter(def(el):
|
|
185
|
+
return a.filter(def (el):
|
|
172
186
|
return b.indexOf(el) < 0
|
|
173
187
|
)
|
|
174
188
|
|
|
189
|
+
|
|
175
190
|
def set_intersection(a, b):
|
|
176
|
-
return a.filter(def(el):
|
|
191
|
+
return a.filter(def (el):
|
|
177
192
|
return b.indexOf(el) >= 0
|
|
178
193
|
)
|
|
179
194
|
|
|
195
|
+
|
|
180
196
|
def make_predicate(words):
|
|
181
197
|
if jstype(words) is 'string':
|
|
182
|
-
words = words.split(
|
|
198
|
+
words = words.split(' ')
|
|
183
199
|
a = Object.create(None)
|
|
184
200
|
for k in words:
|
|
185
201
|
a[k] = True
|
|
186
202
|
return a
|
|
187
203
|
|
|
204
|
+
|
|
188
205
|
def cache_file_name(src, cache_dir):
|
|
189
206
|
if cache_dir:
|
|
190
207
|
src = str.replace(src, '\\', '/')
|
package/test/fmt.pyj
CHANGED
|
@@ -129,14 +129,36 @@ async def run_tests():
|
|
|
129
129
|
{'line_length': 40})
|
|
130
130
|
|
|
131
131
|
# --- reflow of simple multi-line statements ----------------------------
|
|
132
|
+
# By default, source line breaks are preserved (no joining).
|
|
133
|
+
await check('no-join-default',
|
|
134
|
+
'x = fn(\n a,\n b,\n c\n)\n',
|
|
135
|
+
'x = fn(\n a,\n b,\n c\n)\n')
|
|
136
|
+
# With join_lines=True the statement is collapsed onto one line.
|
|
132
137
|
await check('reflow-simple-call',
|
|
133
138
|
'x = fn(\n a,\n b,\n c\n)\n',
|
|
134
|
-
'x = fn(a, b, c)\n'
|
|
139
|
+
'x = fn(a, b, c)\n',
|
|
140
|
+
{'join_lines': True})
|
|
141
|
+
# A multi-line statement that is too long even in source form gets wrapped
|
|
142
|
+
# regardless of join_lines.
|
|
143
|
+
await check('no-join-wrap-long',
|
|
144
|
+
'x = very_long_function_name(\n argument_one,\n argument_two,\n argument_three\n)\n',
|
|
145
|
+
'x = very_long_function_name(\n argument_one,\n argument_two,\n argument_three\n)\n',
|
|
146
|
+
{'line_length': 40})
|
|
135
147
|
|
|
136
148
|
# --- RapydScript specific constructs are preserved ----------------------
|
|
137
149
|
await check('preserve-anon-function',
|
|
138
|
-
"params = {\n 'onclick': def(event):\n alert('hi')\n ,\n 'x': 5\n}\n",
|
|
139
|
-
"params = {\n 'onclick': def(event):\n alert('hi')\n ,\n 'x': 5\n}\n")
|
|
150
|
+
"params = {\n 'onclick': def (event):\n alert('hi')\n ,\n 'x': 5\n}\n",
|
|
151
|
+
"params = {\n 'onclick': def (event):\n alert('hi')\n ,\n 'x': 5\n}\n")
|
|
152
|
+
# Assignments inside an anonymous def passed as an argument must keep spaces
|
|
153
|
+
# around '='; they are not kwargs even though they are inside the outer call.
|
|
154
|
+
await check('anon-def-arg-assignment',
|
|
155
|
+
"window.addEventListener('beforeunload', def (event):\n self.disable=True\n self.ws.close()\n)\n",
|
|
156
|
+
"window.addEventListener('beforeunload', def (event):\n self.disable = True\n self.ws.close()\n)\n")
|
|
157
|
+
# Inline anonymous def inside a call: kwargs that follow the def must not
|
|
158
|
+
# gain spaces (they are not assignments in the def body).
|
|
159
|
+
await check('inline-anon-def-arg-kwargs',
|
|
160
|
+
"xhr = ajax('url', def ():pass;, method='POST', flag=False)\n",
|
|
161
|
+
"xhr = ajax('url', def (): pass;, method='POST', flag=False)\n")
|
|
140
162
|
await check('preserve-chain',
|
|
141
163
|
"$(element)\n.css('background-color', 'red')\n.show()\n",
|
|
142
164
|
"$(element)\n.css('background-color', 'red')\n.show()\n")
|
|
@@ -160,7 +182,14 @@ async def run_tests():
|
|
|
160
182
|
|
|
161
183
|
# --- inline anonymous function on a single line -------------------------
|
|
162
184
|
await check('inline-anon', 'add = def(a,b): return a+b\n',
|
|
163
|
-
'add = def(a, b): return a + b\n')
|
|
185
|
+
'add = def (a, b): return a + b\n')
|
|
186
|
+
# --- anonymous function assignment: space always inserted between def and ( --
|
|
187
|
+
await check('anon-def-assignment',
|
|
188
|
+
"func = def(event):\n pass\n",
|
|
189
|
+
"func = def (event):\n pass\n")
|
|
190
|
+
await check('anon-def-assignment-already-spaced',
|
|
191
|
+
"func = def (event):\n pass\n",
|
|
192
|
+
"func = def (event):\n pass\n")
|
|
164
193
|
|
|
165
194
|
# --- shebang preserved --------------------------------------------------
|
|
166
195
|
await check('shebang', '#!/usr/bin/env rapydscript\nx=1\n',
|
|
@@ -183,6 +212,67 @@ async def run_tests():
|
|
|
183
212
|
assrt.ok(errs3.length >= 1, 'check_report must flag over-length lines')
|
|
184
213
|
assrt.ok(errs3.join('\n').indexOf('exceeds') >= 0, 'check_report over-length message content')
|
|
185
214
|
|
|
215
|
+
# --- import organization ------------------------------------------------
|
|
216
|
+
# __python__ group is first; stdlib group is second; other group is third.
|
|
217
|
+
# Blank line separates each non-empty group from the next.
|
|
218
|
+
await check('import-organize-three-groups',
|
|
219
|
+
'import my_module\nimport math\nfrom __python__ import os\n',
|
|
220
|
+
'from __python__ import os\n\nimport math\n\nimport my_module\n')
|
|
221
|
+
# stdlib (math, re, ...) in group 2; other imports in group 3, blank line between.
|
|
222
|
+
await check('import-organize-two-groups',
|
|
223
|
+
'import my_module\nimport math\n',
|
|
224
|
+
'import math\n\nimport my_module\n')
|
|
225
|
+
# from-imports in stdlib group follow bare imports (isort convention).
|
|
226
|
+
await check('import-organize-from-after-bare',
|
|
227
|
+
'from re import match\nimport math\nimport my_module\n',
|
|
228
|
+
'import math\nfrom re import match\n\nimport my_module\n')
|
|
229
|
+
# Sorting within a group: alphabetical by module then by names.
|
|
230
|
+
await check('import-organize-sort-stdlib',
|
|
231
|
+
'import re\nimport math\n',
|
|
232
|
+
'import math\nimport re\n')
|
|
233
|
+
await check('import-organize-sort-other',
|
|
234
|
+
'import zebra\nimport apple\n',
|
|
235
|
+
'import apple\nimport zebra\n')
|
|
236
|
+
# Only stdlib: no blank-line separator.
|
|
237
|
+
await check('import-organize-stdlib-only',
|
|
238
|
+
'import re\nimport math\n',
|
|
239
|
+
'import math\nimport re\n')
|
|
240
|
+
# Only other: no blank-line separator.
|
|
241
|
+
await check('import-organize-other-only',
|
|
242
|
+
'import zebra\nimport apple\n',
|
|
243
|
+
'import apple\nimport zebra\n')
|
|
244
|
+
# Only __python__: no blank-line separator.
|
|
245
|
+
await check('import-organize-python-only',
|
|
246
|
+
'from __python__ import sys\nfrom __python__ import os\n',
|
|
247
|
+
'from __python__ import os\nfrom __python__ import sys\n')
|
|
248
|
+
# __python__ with stdlib only: blank line between them.
|
|
249
|
+
await check('import-organize-python-and-stdlib',
|
|
250
|
+
'import math\nfrom __python__ import os\n',
|
|
251
|
+
'from __python__ import os\n\nimport math\n')
|
|
252
|
+
# __python__ with other only: blank line between them.
|
|
253
|
+
await check('import-organize-python-and-other',
|
|
254
|
+
'import my_module\nfrom __python__ import os\n',
|
|
255
|
+
'from __python__ import os\n\nimport my_module\n')
|
|
256
|
+
# Already organized: idempotent (checked automatically by check()).
|
|
257
|
+
await check('import-organize-already-organized',
|
|
258
|
+
'import math\n\nimport my_module\n',
|
|
259
|
+
'import math\n\nimport my_module\n')
|
|
260
|
+
await check('import-organize-python-already-organized',
|
|
261
|
+
'from __python__ import os\n\nimport math\n\nimport my_module\n',
|
|
262
|
+
'from __python__ import os\n\nimport math\n\nimport my_module\n')
|
|
263
|
+
# Code after imports is untouched; blank line between imports and code is preserved.
|
|
264
|
+
await check('import-organize-with-code',
|
|
265
|
+
'import my_module\nimport math\n\nx = 1\n',
|
|
266
|
+
'import math\n\nimport my_module\n\nx = 1\n')
|
|
267
|
+
# from-imports within other group are sorted by module then names.
|
|
268
|
+
await check('import-organize-from-other',
|
|
269
|
+
'from zebra import z\nfrom apple import a\n',
|
|
270
|
+
'from apple import a\nfrom zebra import z\n')
|
|
271
|
+
# Mixed bare and from-imports across groups.
|
|
272
|
+
await check('import-organize-mixed',
|
|
273
|
+
'from my_mod import func\nimport re\nimport math\n',
|
|
274
|
+
'import math\nimport re\n\nfrom my_mod import func\n')
|
|
275
|
+
|
|
186
276
|
# --- collect_pyj_files (directory recursion) ----------------------------
|
|
187
277
|
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'rs-fmt-'))
|
|
188
278
|
fs.mkdirSync(path.join(tmp, 'sub'))
|
package/test/generic.pyj
CHANGED
|
@@ -39,6 +39,15 @@ assrt.equal(-1 < 0 == 1 < 0, False)
|
|
|
39
39
|
# Empty tuple
|
|
40
40
|
assrt.deepEqual((), [])
|
|
41
41
|
|
|
42
|
+
# Tuples with newlines inside parentheses
|
|
43
|
+
assrt.deepEqual((1,
|
|
44
|
+
2), [1, 2])
|
|
45
|
+
assrt.deepEqual((1,
|
|
46
|
+
2,
|
|
47
|
+
3), [1, 2, 3])
|
|
48
|
+
assrt.deepEqual((1,
|
|
49
|
+
2), [1, 2])
|
|
50
|
+
|
|
42
51
|
# Conditional operators
|
|
43
52
|
assrt.equal(1 if True else 2, 1)
|
|
44
53
|
assrt.equal(1
|
package/test/lsp.pyj
CHANGED
|
@@ -206,6 +206,40 @@ async def test_configuration_change():
|
|
|
206
206
|
lsp.apply_configuration(ctx, {'importPath': ''})
|
|
207
207
|
assrt.equal(ctx.import_dirs.length, 0, 'empty importPath string should clear import_dirs')
|
|
208
208
|
|
|
209
|
+
async def test_organize_imports():
|
|
210
|
+
tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'rs-lsp-org-'))
|
|
211
|
+
ctx = lsp.create_server_context({
|
|
212
|
+
'import_dirs': [tmp], 'libdir': libdir, 'workspace_roots': [tmp],
|
|
213
|
+
'line_length': 80, 'preferred_quote': 'single',
|
|
214
|
+
})
|
|
215
|
+
# Unorganized: stdlib after other -> edits are produced.
|
|
216
|
+
unorganized = 'import my_module\nimport math\n\nx = 1\n'
|
|
217
|
+
edits = lsp.organize_imports_document(ctx, unorganized)
|
|
218
|
+
assrt.ok(Array.isArray(edits) and edits.length > 0,
|
|
219
|
+
'organize_imports_document must return edits for unorganized imports')
|
|
220
|
+
assrt.ok(edits[0].newText.indexOf('import math') < edits[0].newText.indexOf('import my_module'),
|
|
221
|
+
'stdlib import (math) must come before other import in organized output')
|
|
222
|
+
assrt.ok(edits[0].newText.indexOf('\n\n') >= 0,
|
|
223
|
+
'organized output must have a blank line between stdlib and other groups')
|
|
224
|
+
# from __python__ import ... goes first, before stdlib.
|
|
225
|
+
with_python = 'import math\nfrom __python__ import os\n\nx = 1\n'
|
|
226
|
+
edits_py = lsp.organize_imports_document(ctx, with_python)
|
|
227
|
+
assrt.ok(Array.isArray(edits_py) and edits_py.length > 0,
|
|
228
|
+
'organize_imports_document must return edits when __python__ import is out of place')
|
|
229
|
+
assrt.ok(edits_py[0].newText.indexOf('from __python__') < edits_py[0].newText.indexOf('import math'),
|
|
230
|
+
'__python__ group must come before stdlib group in organized output')
|
|
231
|
+
# Already organized: no edits.
|
|
232
|
+
organized = 'import math\n\nimport my_module\n\nx = 1\n'
|
|
233
|
+
edits2 = lsp.organize_imports_document(ctx, organized)
|
|
234
|
+
assrt.equal(edits2.length, 0,
|
|
235
|
+
'organize_imports_document must return no edits for already-organized imports')
|
|
236
|
+
# No imports: no edits.
|
|
237
|
+
no_imports = 'x = 1\ny = 2\n'
|
|
238
|
+
edits3 = lsp.organize_imports_document(ctx, no_imports)
|
|
239
|
+
assrt.equal(edits3.length, 0,
|
|
240
|
+
'organize_imports_document must return no edits when there are no imports')
|
|
241
|
+
fs.rmSync(tmp, {'recursive': True})
|
|
242
|
+
|
|
209
243
|
async def run_tests():
|
|
210
244
|
await test_diagnostics()
|
|
211
245
|
await test_hover_and_definition()
|
|
@@ -218,5 +252,6 @@ async def run_tests():
|
|
|
218
252
|
await test_error_recovery_still_analyzes()
|
|
219
253
|
await test_parser_recovery_flag()
|
|
220
254
|
await test_configuration_change()
|
|
255
|
+
await test_organize_imports()
|
|
221
256
|
|
|
222
257
|
__test_async_done__ = run_tests()
|
package/test/str.pyj
CHANGED
|
@@ -57,6 +57,14 @@ def test_interpolation():
|
|
|
57
57
|
ae(f'{a}'f'{a}', '11')
|
|
58
58
|
ae(f'a''b', 'ab')
|
|
59
59
|
ae(f'{a}''b', '1b')
|
|
60
|
+
# Test plain string followed by f-string (regression: was parsed as a call expression)
|
|
61
|
+
ae('a' f'b', 'ab')
|
|
62
|
+
ae('a' f'{a}', 'a1')
|
|
63
|
+
ae('prefix ' f'{a}', 'prefix 1')
|
|
64
|
+
ae('a' f'{a}', 'a1')
|
|
65
|
+
ae('a' f'{a}' 'b', 'a1b')
|
|
66
|
+
ae('a' f'{a}' f'{a}', 'a11')
|
|
67
|
+
ae(rf'raw{a}' f' and {a}', 'raw1 and 1')
|
|
60
68
|
|
|
61
69
|
somevar = 33
|
|
62
70
|
test('somevar=33', '{somevar=}', somevar=somevar)
|
package/tools/cli.mjs
CHANGED
|
@@ -449,18 +449,29 @@ If no files or directories are specified, the source code is read from
|
|
|
449
449
|
STDIN and the formatted result is written to STDOUT.`);
|
|
450
450
|
|
|
451
451
|
opt("line_length", 'l', 'string', '80', `The maximum allowed line length. Lines longer than this
|
|
452
|
-
are wrapped where it is safe to do so. Defaults to 80
|
|
452
|
+
are wrapped where it is safe to do so. Defaults to 80.
|
|
453
|
+
If not specified, the value is read from pyproject.toml
|
|
454
|
+
(searched upward from the current directory) under
|
|
455
|
+
[tool.ruff], [tool.black], or [tool.isort].`);
|
|
453
456
|
|
|
454
457
|
opt("preferred_quote", 'q', 'string', 'single', `The preferred quote character for string literals. Either
|
|
455
458
|
"single" or "double". A string is only re-quoted when doing
|
|
456
459
|
so does not increase the number of backslash escapes.
|
|
457
|
-
Defaults to single
|
|
460
|
+
Defaults to single. If not specified, the value is read from
|
|
461
|
+
pyproject.toml (searched upward from the current directory)
|
|
462
|
+
under [tool.ruff.format], [tool.ruff.lint.flake8-quotes],
|
|
463
|
+
or [tool.flake8].`, ['single', 'double']);
|
|
458
464
|
|
|
459
465
|
opt("check_only", 'c', 'bool', false, `Do not modify files. Instead, print the names of files that
|
|
460
466
|
would be reformatted (and any lines that exceed the maximum
|
|
461
467
|
length) to STDERR. Exit with a status of 1 if any issues are
|
|
462
468
|
found, otherwise 0.`);
|
|
463
469
|
|
|
470
|
+
opt("join_lines", 'j', 'bool', false, `Join multi-line statements that fit within the maximum line
|
|
471
|
+
length onto a single line. Disabled by default: source line
|
|
472
|
+
breaks inside statements are preserved as long as no line
|
|
473
|
+
exceeds the maximum length.`);
|
|
474
|
+
|
|
464
475
|
create_group('lsp', "", `Run a Language Server Protocol (LSP) server for RapydScript.
|
|
465
476
|
The server communicates over stdin/stdout using the standard
|
|
466
477
|
LSP JSON-RPC framing and provides code completion, diagnostics,
|
|
@@ -484,10 +495,20 @@ RAPYDSCRIPT_IMPORT_PATH for this, with identical syntax.`);
|
|
|
484
495
|
|
|
485
496
|
opt("line_length", 'l', 'string', '80', `The maximum allowed line length used by the document formatter.
|
|
486
497
|
Lines longer than this are wrapped where it is safe to do so.
|
|
487
|
-
Defaults to 80
|
|
498
|
+
Defaults to 80. If not specified, the value is read from
|
|
499
|
+
pyproject.toml (searched upward from the working directory)
|
|
500
|
+
under [tool.ruff], [tool.black], or [tool.isort].`);
|
|
488
501
|
|
|
489
502
|
opt("preferred_quote", 'q', 'string', 'single', `The preferred quote character used by the document formatter.
|
|
490
|
-
Either "single" or "double". Defaults to single
|
|
503
|
+
Either "single" or "double". Defaults to single. If not
|
|
504
|
+
specified, the value is read from pyproject.toml (searched
|
|
505
|
+
upward from the working directory) under [tool.ruff.format],
|
|
506
|
+
[tool.ruff.lint.flake8-quotes], or [tool.flake8].`, ['single', 'double']);
|
|
507
|
+
|
|
508
|
+
opt("join_lines", 'j', 'bool', false, `Join multi-line statements that fit within the maximum line
|
|
509
|
+
length onto a single line. Disabled by default: source line
|
|
510
|
+
breaks inside statements are preserved as long as no line
|
|
511
|
+
exceeds the maximum length.`);
|
|
491
512
|
|
|
492
513
|
|
|
493
514
|
export var argv = parse_args();
|
package/tools/compile.mjs
CHANGED
|
@@ -9,7 +9,7 @@ import fs from 'fs';
|
|
|
9
9
|
import path from 'path';
|
|
10
10
|
import vm from 'vm';
|
|
11
11
|
import { createRequire } from 'module';
|
|
12
|
-
import { create_compiler } from './compiler.mjs';
|
|
12
|
+
import { create_compiler, EMBEDDED_STDLIB_PREFIX } from './compiler.mjs';
|
|
13
13
|
import * as utils from './utils.mjs';
|
|
14
14
|
import { generate_source_map } from './sourcemap.mjs';
|
|
15
15
|
import tree_shake from './treeshake.mjs';
|
|
@@ -83,7 +83,10 @@ export default async function(start_time, argv, base_path, src_path, lib_path) {
|
|
|
83
83
|
|
|
84
84
|
if (!argv.omit_baselib) {
|
|
85
85
|
var which = (OUTPUT_OPTIONS.beautify) ? 'pretty' : 'ugly';
|
|
86
|
-
|
|
86
|
+
const baselib_key = 'baselib-plain-' + which + '.js';
|
|
87
|
+
const embedded = globalThis.__rapydscript_embedded__;
|
|
88
|
+
OUTPUT_OPTIONS.baselib_plain = embedded?.[baselib_key] ??
|
|
89
|
+
await fs.promises.readFile(path.join(lib_path, baselib_key), 'utf-8');
|
|
87
90
|
}
|
|
88
91
|
|
|
89
92
|
var files = argv.files.slice();
|
|
@@ -96,11 +99,12 @@ export default async function(start_time, argv, base_path, src_path, lib_path) {
|
|
|
96
99
|
}
|
|
97
100
|
|
|
98
101
|
async function parse_file(code, file, toplevel) {
|
|
102
|
+
const embedded = globalThis.__rapydscript_embedded__;
|
|
99
103
|
return await RapydScript.parse(code, {
|
|
100
104
|
filename: file,
|
|
101
105
|
toplevel: toplevel,
|
|
102
106
|
basedir: (file !== '<stdin>') ? path.dirname(file) : undefined,
|
|
103
|
-
libdir: path.join(src_path, 'lib'),
|
|
107
|
+
libdir: embedded ? EMBEDDED_STDLIB_PREFIX : path.join(src_path, 'lib'),
|
|
104
108
|
import_dirs: utils.get_import_dirs(argv.import_path),
|
|
105
109
|
discard_asserts: argv.discard_asserts,
|
|
106
110
|
module_cache_dir: cache_dir,
|
package/tools/compiler.mjs
CHANGED
|
@@ -53,9 +53,15 @@ async function find_compiler_dir() {
|
|
|
53
53
|
return { base, compiler_dir };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// Sentinel libdir value used when stdlib files come from the embedded asset VFS
|
|
57
|
+
// rather than the real filesystem. The compiler's readfile/stat_file callbacks
|
|
58
|
+
// intercept paths that start with this prefix.
|
|
59
|
+
const EMBEDDED_STDLIB_PREFIX = '__stdlib__';
|
|
60
|
+
|
|
56
61
|
async function create_compiler(opts) {
|
|
57
62
|
opts = opts || {};
|
|
58
63
|
var vfs = opts.virtual_file_system;
|
|
64
|
+
const embedded = globalThis.__rapydscript_embedded__;
|
|
59
65
|
|
|
60
66
|
const { base, compiler_dir } = await find_compiler_dir();
|
|
61
67
|
|
|
@@ -83,6 +89,32 @@ async function create_compiler(opts) {
|
|
|
83
89
|
const content = await readfile(p, 'utf-8');
|
|
84
90
|
return { mtimeMs: null, content };
|
|
85
91
|
};
|
|
92
|
+
} else if (embedded) {
|
|
93
|
+
// Compiled standalone binary: stdlib lives in the embedded asset VFS.
|
|
94
|
+
// Paths prefixed with EMBEDDED_STDLIB_PREFIX are served from memory;
|
|
95
|
+
// all other paths (user source files, cache) still hit the real filesystem.
|
|
96
|
+
readfile = async (p, enc) => {
|
|
97
|
+
if (p.startsWith('__stdlib__/')) {
|
|
98
|
+
const name = p.slice('__stdlib__/'.length);
|
|
99
|
+
if (embedded.stdlib && embedded.stdlib[name] !== undefined) return embedded.stdlib[name];
|
|
100
|
+
}
|
|
101
|
+
return fs.promises.readFile(p, enc);
|
|
102
|
+
};
|
|
103
|
+
// Silently drop writes that target embedded virtual paths (e.g. stdlib cache files).
|
|
104
|
+
writefile = async (p, data) => {
|
|
105
|
+
if (p.startsWith('__stdlib__/')) return;
|
|
106
|
+
return fs.promises.writeFile(p, data);
|
|
107
|
+
};
|
|
108
|
+
stat_file = async (p) => {
|
|
109
|
+
if (p.startsWith('__stdlib__/')) {
|
|
110
|
+
const name = p.slice('__stdlib__/'.length);
|
|
111
|
+
if (embedded.stdlib && embedded.stdlib[name] !== undefined) return { mtimeMs: null };
|
|
112
|
+
const err = Object.assign(new Error(`stdlib not found: ${name}`), { code: 'ENOENT' });
|
|
113
|
+
throw err;
|
|
114
|
+
}
|
|
115
|
+
const st = await fs.promises.stat(p);
|
|
116
|
+
return { mtimeMs: st.mtimeMs };
|
|
117
|
+
};
|
|
86
118
|
} else {
|
|
87
119
|
readfile = async (p, enc) => fs.promises.readFile(p, enc);
|
|
88
120
|
writefile = async (p, data) => fs.promises.writeFile(p, data);
|
|
@@ -103,7 +135,7 @@ async function create_compiler(opts) {
|
|
|
103
135
|
exports : compiler_exports,
|
|
104
136
|
});
|
|
105
137
|
var compiler_file = path.join(compiler_dir, 'compiler.js');
|
|
106
|
-
var compilerjs = await fs.promises.readFile(compiler_file, 'utf-8');
|
|
138
|
+
var compilerjs = embedded?.['compiler.js'] ?? await fs.promises.readFile(compiler_file, 'utf-8');
|
|
107
139
|
vm.runInContext(compilerjs, compiler_context, path.relative(base, compiler_file));
|
|
108
140
|
const { ast_to_json, ast_from_json, make_lazy_ast_module, encode_cache, decode_cache } = make_ast_serializer(compiler_exports);
|
|
109
141
|
compiler_exports.ast_to_json = ast_to_json;
|
|
@@ -124,4 +156,4 @@ async function create_embedded_compiler(compiler, baselib, runjs, name) {
|
|
|
124
156
|
return await embedded_compiler_factory(compiler || await create_compiler(), baselib, runjs, name, tree_shake, generate_source_map);
|
|
125
157
|
}
|
|
126
158
|
|
|
127
|
-
export { create_compiler, create_embedded_compiler, generate_source_map };
|
|
159
|
+
export { create_compiler, create_embedded_compiler, generate_source_map, EMBEDDED_STDLIB_PREFIX };
|