rapydscript-ng 0.7.23 → 0.8.0
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 +24 -0
- package/README.md +72 -26
- package/bin/package.json +1 -0
- package/bin/rapydscript +65 -62
- package/editor-plugins/nvim/rapydscript/README.md +184 -0
- package/editor-plugins/nvim/rapydscript/bin/rapydscript.so +0 -0
- package/editor-plugins/nvim/rapydscript/ftdetect/rapydscript.lua +10 -0
- package/editor-plugins/nvim/rapydscript/lua/rapydscript/health.lua +88 -0
- package/editor-plugins/nvim/rapydscript/lua/rapydscript/init.lua +279 -0
- package/local-agent.md +28 -0
- package/package.json +4 -5
- package/release/baselib-plain-pretty.js +448 -326
- package/release/baselib-plain-ugly.js +3 -3
- package/release/compiler.js +2528 -1672
- package/release/signatures.json +17 -17
- package/src/ast.pyj +73 -25
- package/src/baselib-builtins.pyj +2 -2
- package/src/baselib-containers.pyj +153 -151
- package/src/baselib-internal.pyj +3 -3
- package/src/baselib-str.pyj +5 -5
- package/src/lib/aes.pyj +1 -1
- package/src/lib/encodings.pyj +1 -1
- package/src/lib/pythonize.pyj +1 -1
- package/src/lib/re.pyj +2 -2
- package/src/lib/traceback.pyj +165 -28
- package/src/lib/uuid.pyj +1 -1
- package/src/output/codegen.pyj +10 -3
- package/src/output/functions.pyj +31 -40
- package/src/output/literals.pyj +11 -14
- package/src/output/loops.pyj +25 -87
- package/src/output/modules.pyj +5 -47
- package/src/output/statements.pyj +1 -1
- package/src/output/stream.pyj +58 -31
- package/src/parse.pyj +777 -427
- package/src/tokenizer.pyj +16 -4
- package/src/utils.pyj +1 -1
- package/test/_treeshake_mod.pyj +30 -0
- package/test/_treeshake_side_effect.pyj +9 -0
- package/test/ast_serialization.pyj +392 -0
- package/test/async.pyj +95 -0
- package/test/baselib.pyj +1 -2
- package/test/embedded_compiler.pyj +57 -0
- package/test/fmt.pyj +201 -0
- package/test/generic.pyj +7 -3
- package/test/imports.pyj +8 -6
- package/test/internationalization.pyj +38 -37
- package/test/lint.pyj +120 -115
- package/test/lsp.pyj +222 -0
- package/test/repl.pyj +70 -65
- package/test/sourcemaps.pyj +315 -0
- package/test/starargs.pyj +46 -39
- package/test/traceback.pyj +263 -0
- package/test/treeshaking.pyj +181 -0
- package/test/web_repl_export.pyj +88 -0
- package/tools/ast_serialize.mjs +557 -0
- package/tools/cli.mjs +510 -0
- package/tools/compile.mjs +201 -0
- package/tools/compiler.mjs +127 -0
- package/tools/{completer.js → completer.mjs} +6 -6
- package/tools/{embedded_compiler.js → embedded_compiler.mjs} +17 -13
- package/tools/export.js +109 -56
- package/tools/fmt.mjs +735 -0
- package/tools/{gettext.js → gettext.mjs} +46 -53
- package/tools/{ini.js → ini.mjs} +9 -10
- package/tools/{lint.js → lint.mjs} +107 -56
- package/tools/lsp.mjs +914 -0
- package/tools/lsp_protocol.mjs +259 -0
- package/tools/lsp_symbols.mjs +418 -0
- package/tools/{msgfmt.js → msgfmt.mjs} +18 -18
- package/tools/{repl.js → repl.mjs} +52 -41
- package/tools/{self.js → self.mjs} +56 -46
- package/tools/sourcemap.mjs +123 -0
- package/tools/test.mjs +152 -0
- package/tools/treeshake.mjs +400 -0
- package/tools/{utils.js → utils.mjs} +26 -23
- package/tools/{web_repl.js → web_repl.mjs} +15 -13
- package/tools/web_repl_export.mjs +93 -0
- package/tree-sitter/README.md +101 -0
- package/tree-sitter/grammar.js +992 -0
- package/tree-sitter/package.json +43 -0
- package/tree-sitter/queries/rapydscript/highlights.scm +232 -0
- package/tree-sitter/queries/rapydscript/indents.scm +64 -0
- package/tree-sitter/queries/rapydscript/injections.scm +14 -0
- package/tree-sitter/queries/rapydscript/locals.scm +108 -0
- package/tree-sitter/src/grammar.json +4976 -0
- package/tree-sitter/src/node-types.json +2901 -0
- package/tree-sitter/src/parser.c +196465 -0
- package/tree-sitter/src/scanner.c +294 -0
- package/tree-sitter/src/tree_sitter/alloc.h +54 -0
- package/tree-sitter/src/tree_sitter/array.h +330 -0
- package/tree-sitter/src/tree_sitter/parser.h +286 -0
- package/tree-sitter/test/corpus/chaining.txt +99 -0
- package/tree-sitter/test/corpus/classes.txt +147 -0
- package/tree-sitter/test/corpus/comprehensions.txt +155 -0
- package/tree-sitter/test/corpus/containers.txt +242 -0
- package/tree-sitter/test/corpus/control_flow.txt +361 -0
- package/tree-sitter/test/corpus/decorators.txt +64 -0
- package/tree-sitter/test/corpus/existential.txt +102 -0
- package/tree-sitter/test/corpus/functions.txt +293 -0
- package/tree-sitter/test/corpus/imports.txt +117 -0
- package/tree-sitter/test/corpus/literals.txt +135 -0
- package/tree-sitter/test/corpus/operators.txt +296 -0
- package/tree-sitter/test/corpus/statements.txt +189 -0
- package/tree-sitter/test/corpus/strings.txt +90 -0
- package/tree-sitter/test/corpus/subscripts.txt +227 -0
- package/tree-sitter/tree-sitter.json +36 -0
- package/web-repl/env.js +35 -23
- package/web-repl/main.js +8 -8
- package/bin/export +0 -75
- package/bin/web-repl-export +0 -102
- package/tools/cli.js +0 -523
- package/tools/compile.js +0 -184
- package/tools/compiler.js +0 -84
- package/tools/test.js +0 -110
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
/* vim:fileencoding=utf-8
|
|
2
|
-
*
|
|
2
|
+
*
|
|
3
3
|
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
|
|
4
4
|
*
|
|
5
5
|
* Distributed under terms of the BSD license
|
|
6
6
|
*/
|
|
7
|
-
"use strict";
|
|
7
|
+
"use strict";
|
|
8
|
+
|
|
9
|
+
import fs from 'fs';
|
|
10
|
+
import path from 'path';
|
|
8
11
|
|
|
9
|
-
var
|
|
10
|
-
var RapydScript = (
|
|
11
|
-
var path = require('path');
|
|
12
|
+
var _rapydscript_compiler = typeof create_rapydscript_compiler !== 'undefined' ? create_rapydscript_compiler : globalThis.create_rapydscript_compiler;
|
|
13
|
+
var RapydScript = _rapydscript_compiler();
|
|
12
14
|
|
|
13
|
-
function parse_file(code, filename) {
|
|
14
|
-
return RapydScript.parse(code, {
|
|
15
|
+
async function parse_file(code, filename) {
|
|
16
|
+
return await RapydScript.parse(code, {
|
|
15
17
|
filename: filename,
|
|
16
18
|
basedir: path.dirname(filename),
|
|
17
19
|
libdir: path.dirname(filename),
|
|
@@ -27,18 +29,19 @@ function detect_format(msgid) {
|
|
|
27
29
|
|
|
28
30
|
function Gettext(catalog, filename) {
|
|
29
31
|
this._visit = function (node, cont) {
|
|
30
|
-
if (node instanceof RapydScript.AST_Call && node.args && node.args.length && node.expression instanceof RapydScript.AST_Symbol) {
|
|
32
|
+
if (node instanceof RapydScript.AST_Call && node.args && node.args.args && node.args.args.length && node.expression instanceof RapydScript.AST_Symbol) {
|
|
31
33
|
var name = node.expression.name;
|
|
32
34
|
if (name === '_' || name === 'gettext' || name === 'ngettext') {
|
|
33
35
|
var nargs = (name === 'ngettext') ? 2 : 1;
|
|
34
36
|
var line = node.start.line;
|
|
37
|
+
var pargs = node.args.args;
|
|
35
38
|
for (var i = 0; i < nargs; i++) {
|
|
36
|
-
if (!(
|
|
39
|
+
if (!(pargs[i].value instanceof RapydScript.AST_String)) {
|
|
37
40
|
console.error('Translation function: ' + name + ' does not have a string literal argument at line: ' + line + ' of ' + filename);
|
|
38
41
|
process.exit(1);
|
|
39
42
|
}
|
|
40
43
|
}
|
|
41
|
-
var msgid =
|
|
44
|
+
var msgid = pargs[0].value.value;
|
|
42
45
|
if (!Object.prototype.hasOwnProperty.call(catalog, msgid)) {
|
|
43
46
|
catalog[msgid] = {
|
|
44
47
|
'locations': [],
|
|
@@ -46,20 +49,20 @@ function Gettext(catalog, filename) {
|
|
|
46
49
|
'format': detect_format(msgid),
|
|
47
50
|
};
|
|
48
51
|
}
|
|
49
|
-
if (name === 'ngettext') catalog[msgid].plural =
|
|
52
|
+
if (name === 'ngettext') catalog[msgid].plural = pargs[1].value.value;
|
|
50
53
|
if (filename) catalog[msgid].locations.push(filename + ':' + line);
|
|
51
54
|
}
|
|
52
|
-
|
|
55
|
+
|
|
53
56
|
}
|
|
54
57
|
if (cont !== undefined) cont();
|
|
55
58
|
};
|
|
56
59
|
}
|
|
57
60
|
|
|
58
|
-
function gettext(catalog, code, filename) {
|
|
61
|
+
async function gettext(catalog, code, filename) {
|
|
59
62
|
var toplevel;
|
|
60
63
|
|
|
61
64
|
try {
|
|
62
|
-
toplevel = parse_file(code, filename);
|
|
65
|
+
toplevel = await parse_file(code, filename);
|
|
63
66
|
} catch(e) {
|
|
64
67
|
if (e instanceof RapydScript.SyntaxError) {
|
|
65
68
|
console.error('Failed to parse: ' + filename + ' with error: ' + e.line + ':' + e.col + ':' + e.message);
|
|
@@ -125,61 +128,51 @@ function write_output(catalog, options, write) {
|
|
|
125
128
|
|
|
126
129
|
// CLI {{{
|
|
127
130
|
|
|
128
|
-
function read_whole_file(filename
|
|
131
|
+
async function read_whole_file(filename) {
|
|
129
132
|
if (!filename) {
|
|
130
133
|
var chunks = [];
|
|
131
134
|
process.stdin.setEncoding('utf-8');
|
|
132
|
-
|
|
133
|
-
chunks.push(chunk);
|
|
134
|
-
|
|
135
|
-
|
|
135
|
+
await new Promise((resolve, reject) => {
|
|
136
|
+
process.stdin.on('data', chunk => chunks.push(chunk));
|
|
137
|
+
process.stdin.on('end', resolve);
|
|
138
|
+
process.stdin.on('error', reject);
|
|
136
139
|
});
|
|
137
140
|
process.openStdin();
|
|
141
|
+
return chunks.join('');
|
|
138
142
|
} else {
|
|
139
|
-
fs.readFile(filename,
|
|
143
|
+
return await fs.promises.readFile(filename, 'utf-8');
|
|
140
144
|
}
|
|
141
145
|
}
|
|
142
146
|
|
|
143
|
-
|
|
147
|
+
export async function cli(argv, base_path, src_path, lib_path) {
|
|
144
148
|
var files = [];
|
|
145
|
-
var num_of_files = files.length || 1;
|
|
146
149
|
var catalog = {};
|
|
147
150
|
|
|
148
|
-
function read_files(src) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
fs.
|
|
153
|
-
read_files(children);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
});
|
|
151
|
+
async function read_files(src) {
|
|
152
|
+
for (const f of src) {
|
|
153
|
+
var stat = await fs.promises.lstat(f);
|
|
154
|
+
if (stat.isDirectory()) {
|
|
155
|
+
var children = (await fs.promises.readdir(f)).map(x => path.join(f, x));
|
|
156
|
+
await read_files(children);
|
|
157
|
+
} else files.push(f);
|
|
158
|
+
}
|
|
157
159
|
}
|
|
158
|
-
read_files(argv.files);
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
160
|
+
await read_files(argv.files);
|
|
161
|
+
|
|
162
|
+
for (const f of (files.length ? files : [null])) {
|
|
163
|
+
var code;
|
|
164
|
+
try {
|
|
165
|
+
code = await read_whole_file(f);
|
|
166
|
+
} catch(e) {
|
|
167
|
+
console.error("ERROR: can't read file: " + f);
|
|
163
168
|
process.exit(1);
|
|
164
169
|
}
|
|
165
|
-
|
|
166
|
-
gettext(catalog, code, files[0]);
|
|
167
|
-
|
|
168
|
-
files = files.slice(1);
|
|
169
|
-
if (files.length) {
|
|
170
|
-
setImmediate(read_whole_file, files[0], process_single_file);
|
|
171
|
-
return;
|
|
172
|
-
} else {
|
|
173
|
-
write_output(catalog, argv);
|
|
174
|
-
process.exit(0);
|
|
175
|
-
}
|
|
170
|
+
await gettext(catalog, code, f);
|
|
176
171
|
}
|
|
177
|
-
|
|
178
|
-
setImmediate(read_whole_file, files[0], process_single_file);
|
|
179
172
|
|
|
180
|
-
|
|
173
|
+
write_output(catalog, argv);
|
|
174
|
+
process.exit(0);
|
|
175
|
+
}
|
|
181
176
|
|
|
182
|
-
|
|
183
|
-
module.exports.entry_to_string = entry_to_string;
|
|
184
|
-
module.exports.write_output = write_output;
|
|
177
|
+
export { gettext, entry_to_string, write_output };
|
|
185
178
|
// }}}
|
package/tools/{ini.js → ini.mjs}
RENAMED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/* vim:fileencoding=utf-8
|
|
2
|
-
*
|
|
2
|
+
*
|
|
3
3
|
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
|
|
4
4
|
*
|
|
5
5
|
* Distributed under terms of the BSD license
|
|
6
6
|
*/
|
|
7
|
-
"use strict"; /*jshint node:true */
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
11
10
|
|
|
12
11
|
function parse_ini_data(data) {
|
|
13
|
-
// Based on MIT licensed code from:
|
|
12
|
+
// Based on MIT licensed code from:
|
|
14
13
|
// https://github.com/shockie/node-iniparser/blob/master/lib/node-iniparser.js
|
|
15
14
|
var ans = {}, match;
|
|
16
15
|
var lines = data.split(/\r\n|\r|\n/);
|
|
@@ -40,11 +39,11 @@ function parse_ini_data(data) {
|
|
|
40
39
|
return ans;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
function find_cfg_file(toplevel_dir) {
|
|
42
|
+
async function find_cfg_file(toplevel_dir) {
|
|
44
43
|
var current_dir = toplevel_dir, previous_dir = toplevel_dir;
|
|
45
44
|
do {
|
|
46
45
|
try {
|
|
47
|
-
return fs.
|
|
46
|
+
return await fs.promises.readFile(path.join(current_dir, 'setup.cfg'), 'utf-8');
|
|
48
47
|
} catch (e) {
|
|
49
48
|
if (e.code !== 'ENOENT') throw e;
|
|
50
49
|
}
|
|
@@ -55,11 +54,11 @@ function find_cfg_file(toplevel_dir) {
|
|
|
55
54
|
return null;
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
function read_config(toplevel_dir) {
|
|
59
|
-
var data = find_cfg_file(toplevel_dir);
|
|
57
|
+
async function read_config(toplevel_dir) {
|
|
58
|
+
var data = await find_cfg_file(toplevel_dir);
|
|
60
59
|
if (!data) return {};
|
|
61
60
|
return parse_ini_data(data);
|
|
62
61
|
}
|
|
63
62
|
|
|
64
63
|
|
|
65
|
-
|
|
64
|
+
export { read_config };
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/* vim:fileencoding=utf-8
|
|
2
|
-
*
|
|
2
|
+
*
|
|
3
3
|
* Copyright (C) 2015 Kovid Goyal <kovid at kovidgoyal.net>
|
|
4
4
|
*
|
|
5
5
|
* Distributed under terms of the BSD license
|
|
6
6
|
*/
|
|
7
|
-
"use strict"; /*jshint node:true */
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
import fs from 'fs';
|
|
9
|
+
import path from 'path';
|
|
10
|
+
import { read_config } from './ini.mjs';
|
|
11
|
+
import * as utils from './utils.mjs';
|
|
12
|
+
|
|
13
|
+
// Use the compiler instance pre-created by bin/rapydscript. It is set as a
|
|
14
|
+
// synchronous global before any dynamic imports, so this module can be
|
|
15
|
+
// require()'d without top-level await.
|
|
16
|
+
const RapydScript = globalThis.create_rapydscript_compiler();
|
|
13
17
|
var colored = utils.safe_colored;
|
|
14
18
|
|
|
15
|
-
var WARN = 1, ERROR = 2;
|
|
16
|
-
var MESSAGES = {
|
|
19
|
+
export var WARN = 1, ERROR = 2;
|
|
20
|
+
export var MESSAGES = {
|
|
17
21
|
'undef': 'undefined symbol: "{name}"',
|
|
18
22
|
'unused-import': '"{name}" is imported but not used',
|
|
19
23
|
'unused-local' : '"{name}" is defined but not used',
|
|
@@ -29,8 +33,8 @@ var MESSAGES = {
|
|
|
29
33
|
};
|
|
30
34
|
|
|
31
35
|
var BUILTINS = Object.create(null);
|
|
32
|
-
('this self window document chr ord iterator_symbol print len range dir' +
|
|
33
|
-
' eval undefined arguments abs max min enumerate pow callable reversed sum' +
|
|
36
|
+
('this self window document chr ord iterator_symbol print len range dir' +
|
|
37
|
+
' eval undefined arguments abs max min enumerate pow callable reversed sum' +
|
|
34
38
|
' getattr isFinite setattr hasattr parseInt parseFloat options_object' +
|
|
35
39
|
' isNaN JSON Math list set list_wrap ρσ_modules require bool int bin' +
|
|
36
40
|
' float iter Error EvalError set_wrap RangeError ReferenceError SyntaxError' +
|
|
@@ -39,7 +43,7 @@ var BUILTINS = Object.create(null);
|
|
|
39
43
|
' NodeList alert console Node Symbol NamedNodeMap ρσ_eslice ρσ_delslice Number' +
|
|
40
44
|
' Boolean encodeURIComponent decodeURIComponent setTimeout setInterval' +
|
|
41
45
|
' setImmediate clearTimeout clearInterval clearImmediate requestAnimationFrame' +
|
|
42
|
-
' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN'
|
|
46
|
+
' id repr sorted __name__ equals get_module ρσ_str jstype divmod NaN no_prune'
|
|
43
47
|
).split(' ').forEach(function(x) { BUILTINS[x] = true; });
|
|
44
48
|
|
|
45
49
|
Object.keys(RapydScript.NATIVE_CLASSES).forEach(function (name) { BUILTINS[name] = true; });
|
|
@@ -56,8 +60,8 @@ function cmp(a, b) {
|
|
|
56
60
|
return (a < b) ? -1 : ((a > b) ? 1 : 0);
|
|
57
61
|
}
|
|
58
62
|
|
|
59
|
-
function parse_file(code, filename) {
|
|
60
|
-
return RapydScript.parse(code, {
|
|
63
|
+
async function parse_file(code, filename) {
|
|
64
|
+
return await RapydScript.parse(code, {
|
|
61
65
|
filename: filename,
|
|
62
66
|
basedir: path.dirname(filename),
|
|
63
67
|
libdir: path.dirname(filename),
|
|
@@ -70,7 +74,7 @@ function msg_from_node(filename, ident, name, node, level, line) {
|
|
|
70
74
|
if (node instanceof RapydScript.AST_Lambda && node.name) name = node.name.name;
|
|
71
75
|
var msg = MESSAGES[ident].replace('{name}', name || '').replace('{line}', line || '');
|
|
72
76
|
return {
|
|
73
|
-
filename: filename,
|
|
77
|
+
filename: filename,
|
|
74
78
|
start_line: (node.start) ? node.start.line : undefined,
|
|
75
79
|
start_col: (node.start) ? node.start.col : undefined,
|
|
76
80
|
end_line: (node.end) ? node.end.line : undefined,
|
|
@@ -157,7 +161,7 @@ function Scope(is_toplevel, parent_scope, filename, is_class) {
|
|
|
157
161
|
this.for_descendants(function (scope) {
|
|
158
162
|
if (has_prop(scope.undefined_references, name)) {
|
|
159
163
|
found = true;
|
|
160
|
-
// Remove from childs' undefined references
|
|
164
|
+
// Remove from childs' undefined references
|
|
161
165
|
delete scope.undefined_references[name];
|
|
162
166
|
} else if (has_prop(scope.nonlocals, name) && has_prop(scope.bindings, name)) found = true;
|
|
163
167
|
});
|
|
@@ -295,7 +299,7 @@ function Linter(toplevel, filename, code, options) {
|
|
|
295
299
|
if (node.left instanceof RapydScript.AST_SymbolRef) {
|
|
296
300
|
node.left.lint_visited = node.operator === '='; // Could be compound assignment like: +=
|
|
297
301
|
if (node.operator === '=') {
|
|
298
|
-
// Only create a binding if the operator is not
|
|
302
|
+
// Only create a binding if the operator is not
|
|
299
303
|
// a compound assignment operator
|
|
300
304
|
this.current_node = node.left;
|
|
301
305
|
this.add_binding(node.left.name);
|
|
@@ -374,7 +378,7 @@ function Linter(toplevel, filename, code, options) {
|
|
|
374
378
|
}
|
|
375
379
|
}
|
|
376
380
|
}
|
|
377
|
-
|
|
381
|
+
|
|
378
382
|
}
|
|
379
383
|
};
|
|
380
384
|
|
|
@@ -419,7 +423,7 @@ function Linter(toplevel, filename, code, options) {
|
|
|
419
423
|
(node.properties || []).forEach(function (prop) {
|
|
420
424
|
if (prop.key instanceof RapydScript.AST_Constant) {
|
|
421
425
|
var val = prop.key.value;
|
|
422
|
-
if (has_prop(seen, val))
|
|
426
|
+
if (has_prop(seen, val))
|
|
423
427
|
this.messages.push(msg_from_node(filename, 'dup-key', val, prop));
|
|
424
428
|
seen[val] = true;
|
|
425
429
|
}
|
|
@@ -483,7 +487,7 @@ function Linter(toplevel, filename, code, options) {
|
|
|
483
487
|
|
|
484
488
|
if (node instanceof RapydScript.AST_Scope) {
|
|
485
489
|
this.handle_scope();
|
|
486
|
-
}
|
|
490
|
+
}
|
|
487
491
|
|
|
488
492
|
if (cont !== undefined) cont();
|
|
489
493
|
|
|
@@ -498,11 +502,39 @@ function Linter(toplevel, filename, code, options) {
|
|
|
498
502
|
this.resolve = function() {
|
|
499
503
|
var messages = this.messages;
|
|
500
504
|
var line_filters = {};
|
|
505
|
+
var in_multiline_str = false;
|
|
506
|
+
var ml_quote = null;
|
|
501
507
|
|
|
502
508
|
code.split('\n').forEach(function(line, num) {
|
|
503
509
|
line = line.trimRight();
|
|
504
510
|
num++;
|
|
505
|
-
|
|
511
|
+
|
|
512
|
+
// Track triple-quoted multiline string state so we can skip
|
|
513
|
+
// eol-semicolon checks for lines that are inside string literals.
|
|
514
|
+
var line_starts_in_multiline = in_multiline_str;
|
|
515
|
+
var pos = 0, close_pos;
|
|
516
|
+
while (pos < line.length) {
|
|
517
|
+
if (!in_multiline_str) {
|
|
518
|
+
var dq = line.indexOf('"""', pos);
|
|
519
|
+
var sq = line.indexOf("'''", pos);
|
|
520
|
+
var first, quote;
|
|
521
|
+
if (dq !== -1 && (sq === -1 || dq < sq)) { first = dq; quote = '"""'; }
|
|
522
|
+
else if (sq !== -1) { first = sq; quote = "'''"; }
|
|
523
|
+
else break;
|
|
524
|
+
in_multiline_str = true;
|
|
525
|
+
ml_quote = quote;
|
|
526
|
+
pos = first + 3;
|
|
527
|
+
close_pos = line.indexOf(ml_quote, pos);
|
|
528
|
+
if (close_pos !== -1) { in_multiline_str = false; ml_quote = null; pos = close_pos + 3; }
|
|
529
|
+
else break;
|
|
530
|
+
} else {
|
|
531
|
+
close_pos = line.indexOf(ml_quote, pos);
|
|
532
|
+
if (close_pos !== -1) { in_multiline_str = false; ml_quote = null; pos = close_pos + 3; }
|
|
533
|
+
else break;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
if (!line_starts_in_multiline && !in_multiline_str && line[line.length - 1] === ';') {
|
|
506
538
|
var ident = 'eol-semicolon';
|
|
507
539
|
messages.push({filename:filename, ident:ident, message:MESSAGES[ident],
|
|
508
540
|
level:WARN, name:';', start_line:num, start_col:line.lastIndexOf(';')});
|
|
@@ -535,7 +567,18 @@ function Linter(toplevel, filename, code, options) {
|
|
|
535
567
|
|
|
536
568
|
}
|
|
537
569
|
|
|
538
|
-
|
|
570
|
+
// Run only the linter analysis over an already parsed toplevel. Used by both
|
|
571
|
+
// lint_code and the LSP (which parses once, in error-recovery mode, and reuses
|
|
572
|
+
// the resulting AST for all of its services).
|
|
573
|
+
export function lint_parsed(toplevel, code, options) {
|
|
574
|
+
options = options || {};
|
|
575
|
+
var filename = options.filename || '<eval>';
|
|
576
|
+
var linter = new Linter(toplevel, filename, code, options);
|
|
577
|
+
toplevel.walk(linter);
|
|
578
|
+
return linter.resolve();
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
export async function lint_code(code, options) {
|
|
539
582
|
options = options || {};
|
|
540
583
|
var reportcb = {'json':cli_json_report, 'vim': cli_vim_report, 'undef': cli_undef_report}[options.errorformat] || (options.report || cli_report);
|
|
541
584
|
var filename = options.filename || '<eval>';
|
|
@@ -543,7 +586,7 @@ function lint_code(code, options) {
|
|
|
543
586
|
var lines = code.split('\n'); // Can be used (in the future) to display extract from code corresponding to error location
|
|
544
587
|
|
|
545
588
|
try {
|
|
546
|
-
toplevel = parse_file(code, filename);
|
|
589
|
+
toplevel = await parse_file(code, filename);
|
|
547
590
|
} catch(e) {
|
|
548
591
|
if (e instanceof RapydScript.ImportError) {
|
|
549
592
|
messages = [{filename:filename, start_line:e.line, start_col:e.col, level:ERROR, ident:'import-err', message:e.message}];
|
|
@@ -553,28 +596,29 @@ function lint_code(code, options) {
|
|
|
553
596
|
}
|
|
554
597
|
|
|
555
598
|
if (toplevel) {
|
|
556
|
-
|
|
557
|
-
toplevel.walk(linter);
|
|
558
|
-
messages = linter.resolve();
|
|
599
|
+
messages = lint_parsed(toplevel, code, options);
|
|
559
600
|
}
|
|
560
601
|
messages.forEach(function(msg, i) { msg.code_lines = lines; reportcb(msg, i, messages); });
|
|
561
602
|
return messages;
|
|
562
603
|
}
|
|
563
604
|
|
|
605
|
+
export { BUILTINS };
|
|
606
|
+
|
|
564
607
|
// CLI {{{
|
|
565
608
|
|
|
566
|
-
function read_whole_file(filename
|
|
609
|
+
async function read_whole_file(filename) {
|
|
567
610
|
if (!filename || filename === '-') {
|
|
568
611
|
var chunks = [];
|
|
569
612
|
process.stdin.setEncoding('utf-8');
|
|
570
|
-
|
|
571
|
-
chunks.push(chunk);
|
|
572
|
-
|
|
573
|
-
|
|
613
|
+
await new Promise((resolve, reject) => {
|
|
614
|
+
process.stdin.on('data', chunk => chunks.push(chunk));
|
|
615
|
+
process.stdin.on('end', resolve);
|
|
616
|
+
process.stdin.on('error', reject);
|
|
574
617
|
});
|
|
575
618
|
process.openStdin();
|
|
619
|
+
return chunks.join('');
|
|
576
620
|
} else {
|
|
577
|
-
fs.readFile(filename,
|
|
621
|
+
return await fs.promises.readFile(filename, 'utf-8');
|
|
578
622
|
}
|
|
579
623
|
}
|
|
580
624
|
|
|
@@ -619,17 +663,15 @@ function cli_vim_report(r) {
|
|
|
619
663
|
|
|
620
664
|
var ini_cache = {};
|
|
621
665
|
|
|
622
|
-
function get_ini(toplevel_dir) {
|
|
666
|
+
async function get_ini(toplevel_dir) {
|
|
623
667
|
if (has_prop(ini_cache, toplevel_dir)) return ini_cache[toplevel_dir];
|
|
624
|
-
var rl =
|
|
668
|
+
var rl = (await read_config(toplevel_dir)).rapydscript || {};
|
|
625
669
|
ini_cache[toplevel_dir] = rl;
|
|
626
670
|
return rl;
|
|
627
671
|
}
|
|
628
672
|
|
|
629
|
-
|
|
673
|
+
export async function cli(argv, base_path, src_path, lib_path) {
|
|
630
674
|
var files = argv.files.slice();
|
|
631
|
-
var num_of_files = files.length || 1;
|
|
632
|
-
var read_config = require('./ini');
|
|
633
675
|
|
|
634
676
|
if (argv.noqa_list) {
|
|
635
677
|
Object.keys(MESSAGES).forEach(function(ident) {
|
|
@@ -642,6 +684,23 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
|
|
|
642
684
|
process.exit(0);
|
|
643
685
|
}
|
|
644
686
|
|
|
687
|
+
if (argv.input_list) {
|
|
688
|
+
// Check for conflict: --input-list=- and - as an input file
|
|
689
|
+
if (argv.input_list === '-' && files.indexOf('-') !== -1) {
|
|
690
|
+
console.error("ERROR: Cannot use - as both --input-list source and an input file");
|
|
691
|
+
process.exit(1);
|
|
692
|
+
}
|
|
693
|
+
var list_data;
|
|
694
|
+
try {
|
|
695
|
+
list_data = await read_whole_file(argv.input_list === '-' ? null : argv.input_list);
|
|
696
|
+
} catch(e) {
|
|
697
|
+
console.error("ERROR: can't read input list file: " + argv.input_list);
|
|
698
|
+
process.exit(1);
|
|
699
|
+
}
|
|
700
|
+
var list_files = list_data.split('\n').map(function(l) { return l.trim(); }).filter(function(l) { return l.length > 0; });
|
|
701
|
+
files = files.concat(list_files);
|
|
702
|
+
}
|
|
703
|
+
|
|
645
704
|
if (files.filter(function(el){ return el === "-"; }).length > 1) {
|
|
646
705
|
console.error("ERROR: Can read a single file from STDIN (two or more dashes specified)");
|
|
647
706
|
process.exit(1);
|
|
@@ -657,15 +716,19 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
|
|
|
657
716
|
return x === '-' ? argv.stdin_filename : x;
|
|
658
717
|
}
|
|
659
718
|
|
|
660
|
-
|
|
661
|
-
var
|
|
662
|
-
|
|
663
|
-
|
|
719
|
+
for (const filename of (files.length ? files : [null])) {
|
|
720
|
+
var code;
|
|
721
|
+
try {
|
|
722
|
+
code = await read_whole_file(filename === '-' ? null : filename);
|
|
723
|
+
} catch(e) {
|
|
724
|
+
console.error("ERROR: can't read file: " + filename);
|
|
664
725
|
process.exit(1);
|
|
665
726
|
}
|
|
666
727
|
|
|
728
|
+
var final_builtins = merge(builtins), final_noqa = merge(noqa);
|
|
729
|
+
|
|
667
730
|
// Read setup.cfg
|
|
668
|
-
rl = get_ini(path.dirname(path_for_filename(
|
|
731
|
+
var rl = await get_ini(path.dirname(path_for_filename(filename || '-')));
|
|
669
732
|
var g = {};
|
|
670
733
|
(rl.globals || rl.builtins || '').split(',').forEach(function (x) { g[x.trim()] = true; });
|
|
671
734
|
final_builtins = merge(final_builtins, g);
|
|
@@ -685,21 +748,9 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
|
|
|
685
748
|
});
|
|
686
749
|
|
|
687
750
|
// Lint!
|
|
688
|
-
if (lint_code(code, {filename:path_for_filename(
|
|
689
|
-
|
|
690
|
-
files = files.slice(1);
|
|
691
|
-
if (files.length) {
|
|
692
|
-
setImmediate(read_whole_file, files[0], lint_single_file);
|
|
693
|
-
return;
|
|
694
|
-
} else process.exit((all_ok) ? 0 : 1);
|
|
751
|
+
if ((await lint_code(code, {filename:path_for_filename(filename || '-'), builtins:final_builtins, noqa:final_noqa, errorformat:argv.errorformat || false})).length) all_ok = false;
|
|
695
752
|
}
|
|
696
|
-
|
|
697
|
-
setImmediate(read_whole_file, files[0], lint_single_file);
|
|
698
753
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
module.exports.lint_code = lint_code;
|
|
702
|
-
module.exports.WARN = WARN;
|
|
703
|
-
module.exports.ERROR = ERROR;
|
|
704
|
-
module.exports.MESSAGES = MESSAGES;
|
|
754
|
+
process.exit((all_ok) ? 0 : 1);
|
|
755
|
+
}
|
|
705
756
|
// }}}
|