rapydscript-ng 0.7.21 → 0.7.23
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/.github/workflows/ci.yml +6 -8
- package/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/publish.py +1 -0
- package/release/baselib-plain-pretty.js +22 -18
- package/release/baselib-plain-ugly.js +3 -3
- package/release/compiler.js +89 -25
- package/release/signatures.json +8 -8
- package/src/ast.pyj +1 -0
- package/src/baselib-containers.pyj +17 -14
- package/src/baselib-internal.pyj +1 -0
- package/src/lib/math.pyj +1 -0
- package/src/lib/random.pyj +27 -3
- package/src/output/operators.pyj +12 -2
- package/src/parse.pyj +4 -1
- package/src/tokenizer.pyj +40 -2
- package/test/baselib.pyj +12 -2
- package/test/collections.pyj +1 -0
- package/test/scoped_flags.pyj +2 -0
- package/test/str.pyj +8 -0
- package/tools/cli.js +6 -1
- package/tools/lint.js +7 -3
package/release/compiler.js
CHANGED
|
@@ -712,7 +712,6 @@ if (!ρσ_list_extend.__argnames__) Object.defineProperties(ρσ_list_extend, {
|
|
|
712
712
|
});
|
|
713
713
|
|
|
714
714
|
function ρσ_list_index(val, start, stop) {
|
|
715
|
-
var idx;
|
|
716
715
|
start = start || 0;
|
|
717
716
|
if (start < 0) {
|
|
718
717
|
start = this.length + start;
|
|
@@ -721,11 +720,7 @@ function ρσ_list_index(val, start, stop) {
|
|
|
721
720
|
throw new ValueError(val + " is not in list");
|
|
722
721
|
}
|
|
723
722
|
if (stop === undefined) {
|
|
724
|
-
|
|
725
|
-
if (idx === -1) {
|
|
726
|
-
throw new ValueError(val + " is not in list");
|
|
727
|
-
}
|
|
728
|
-
return idx;
|
|
723
|
+
stop = this.length;
|
|
729
724
|
}
|
|
730
725
|
if (stop < 0) {
|
|
731
726
|
stop = this.length + stop;
|
|
@@ -762,12 +757,13 @@ if (!ρσ_list_pop.__argnames__) Object.defineProperties(ρσ_list_pop, {
|
|
|
762
757
|
});
|
|
763
758
|
|
|
764
759
|
function ρσ_list_remove(value) {
|
|
765
|
-
var
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
760
|
+
for (var i = 0; i < this.length; i++) {
|
|
761
|
+
if (((ρσ_expr_temp = this)[(typeof i === "number" && i < 0) ? ρσ_expr_temp.length + i : i] === value || typeof (ρσ_expr_temp = this)[(typeof i === "number" && i < 0) ? ρσ_expr_temp.length + i : i] === "object" && ρσ_equals((ρσ_expr_temp = this)[(typeof i === "number" && i < 0) ? ρσ_expr_temp.length + i : i], value))) {
|
|
762
|
+
this.splice(i, 1);
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
769
765
|
}
|
|
770
|
-
|
|
766
|
+
throw new ValueError(value + " not in list");
|
|
771
767
|
};
|
|
772
768
|
if (!ρσ_list_remove.__argnames__) Object.defineProperties(ρσ_list_remove, {
|
|
773
769
|
__argnames__ : {value: ["value"]},
|
|
@@ -2008,7 +2004,7 @@ Object.defineProperties(ρσ_dict.prototype, (function(){
|
|
|
2008
2004
|
});
|
|
2009
2005
|
return ρσ_anonfunc;
|
|
2010
2006
|
})();
|
|
2011
|
-
ρσ_dict.prototype.set_default = (function() {
|
|
2007
|
+
ρσ_dict.prototype.set_default = ρσ_dict.prototype.setdefault = (function() {
|
|
2012
2008
|
var ρσ_anonfunc = function (key, defval) {
|
|
2013
2009
|
var j;
|
|
2014
2010
|
j = this.jsmap;
|
|
@@ -2072,13 +2068,20 @@ Object.defineProperties(ρσ_dict.prototype, (function(){
|
|
|
2072
2068
|
})();
|
|
2073
2069
|
ρσ_dict.prototype.popitem = (function() {
|
|
2074
2070
|
var ρσ_anonfunc = function () {
|
|
2075
|
-
var r;
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2071
|
+
var last, e, r;
|
|
2072
|
+
last = null;
|
|
2073
|
+
e = this.jsmap.entries();
|
|
2074
|
+
while (true) {
|
|
2075
|
+
r = e.next();
|
|
2076
|
+
if (r.done) {
|
|
2077
|
+
if (last === null) {
|
|
2078
|
+
throw new KeyError("dict is empty");
|
|
2079
|
+
}
|
|
2080
|
+
this.jsmap.delete(last.value[0]);
|
|
2081
|
+
return last.value;
|
|
2082
|
+
}
|
|
2083
|
+
last = r;
|
|
2079
2084
|
}
|
|
2080
|
-
this.jsmap.delete(r.value[0]);
|
|
2081
|
-
return r.value;
|
|
2082
2085
|
};
|
|
2083
2086
|
if (!ρσ_anonfunc.__module__) Object.defineProperties(ρσ_anonfunc, {
|
|
2084
2087
|
__module__ : {value: "__main__"}
|
|
@@ -2703,6 +2706,7 @@ function ρσ_setitem(obj, key, val) {
|
|
|
2703
2706
|
}
|
|
2704
2707
|
obj[(typeof key === "number" && key < 0) ? obj.length + key : key] = val;
|
|
2705
2708
|
}
|
|
2709
|
+
return val;
|
|
2706
2710
|
};
|
|
2707
2711
|
if (!ρσ_setitem.__argnames__) Object.defineProperties(ρσ_setitem, {
|
|
2708
2712
|
__argnames__ : {value: ["obj", "key", "val"]},
|
|
@@ -7090,6 +7094,7 @@ return this.__repr__();
|
|
|
7090
7094
|
AST_ItemAccess.prototype.properties = (function(){
|
|
7091
7095
|
var ρσ_d = Object.create(null);
|
|
7092
7096
|
ρσ_d["assignment"] = "[AST_Node or None] Not None if this is an assignment (a[x] = y) rather than a simple access";
|
|
7097
|
+
ρσ_d["assign_operator"] = "[String] The operator for a assignment like += or empty string if plain assignment";
|
|
7093
7098
|
return ρσ_d;
|
|
7094
7099
|
}).call(this);
|
|
7095
7100
|
|
|
@@ -8601,6 +8606,7 @@ return this.__repr__();
|
|
|
8601
8606
|
var SyntaxError = ρσ_modules.errors.SyntaxError;
|
|
8602
8607
|
|
|
8603
8608
|
var interpolate = ρσ_modules.string_interpolation.interpolate;
|
|
8609
|
+
var quoted_string = ρσ_modules.string_interpolation.quoted_string;
|
|
8604
8610
|
|
|
8605
8611
|
RE_HEX_NUMBER = /^0x[0-9a-f]+$/i;
|
|
8606
8612
|
RE_OCT_NUMBER = /^0[0-7]+$/;
|
|
@@ -9247,6 +9253,7 @@ return this.__repr__();
|
|
|
9247
9253
|
return ρσ_anonfunc;
|
|
9248
9254
|
})());
|
|
9249
9255
|
function handle_interpolated_string(string, start_tok) {
|
|
9256
|
+
var parts, ch, stok, j, potential_mod, mods, is_raw, combined;
|
|
9250
9257
|
function raise_error(err) {
|
|
9251
9258
|
throw new SyntaxError(err, filename, start_tok.line, start_tok.col, start_tok.pos, false);
|
|
9252
9259
|
};
|
|
@@ -9255,7 +9262,50 @@ return this.__repr__();
|
|
|
9255
9262
|
__module__ : {value: "tokenizer"}
|
|
9256
9263
|
});
|
|
9257
9264
|
|
|
9258
|
-
|
|
9265
|
+
parts = [interpolate(string, raise_error)];
|
|
9266
|
+
while (true) {
|
|
9267
|
+
while (S.pos < S.text.length && (S.text.charAt(S.pos) === " " || S.text.charAt(S.pos) === "\t")) {
|
|
9268
|
+
next();
|
|
9269
|
+
}
|
|
9270
|
+
ch = S.text.charAt(S.pos);
|
|
9271
|
+
if (!ch) {
|
|
9272
|
+
break;
|
|
9273
|
+
}
|
|
9274
|
+
if (ch === "'" || ch === "\"") {
|
|
9275
|
+
stok = read_string(false, false);
|
|
9276
|
+
parts.push(quoted_string(stok.value));
|
|
9277
|
+
} else if (is_identifier_start(ch.charCodeAt(0))) {
|
|
9278
|
+
j = S.pos;
|
|
9279
|
+
while (j < S.text.length && is_identifier_char(S.text.charAt(j))) {
|
|
9280
|
+
j += 1;
|
|
9281
|
+
}
|
|
9282
|
+
potential_mod = S.text.substring(S.pos, j);
|
|
9283
|
+
if (!is_string_modifier(potential_mod)) {
|
|
9284
|
+
break;
|
|
9285
|
+
}
|
|
9286
|
+
if (j >= S.text.length || "'\"".indexOf(S.text.charAt(j)) === -1) {
|
|
9287
|
+
break;
|
|
9288
|
+
}
|
|
9289
|
+
mods = potential_mod.toLowerCase();
|
|
9290
|
+
if (mods.indexOf("v") !== -1) {
|
|
9291
|
+
break;
|
|
9292
|
+
}
|
|
9293
|
+
while (S.pos < j) {
|
|
9294
|
+
next();
|
|
9295
|
+
}
|
|
9296
|
+
is_raw = mods.indexOf("r") !== -1;
|
|
9297
|
+
stok = read_string(is_raw, false);
|
|
9298
|
+
if (mods.indexOf("f") !== -1) {
|
|
9299
|
+
parts.push(interpolate(stok.value, raise_error));
|
|
9300
|
+
} else {
|
|
9301
|
+
parts.push(quoted_string(stok.value));
|
|
9302
|
+
}
|
|
9303
|
+
} else {
|
|
9304
|
+
break;
|
|
9305
|
+
}
|
|
9306
|
+
}
|
|
9307
|
+
combined = parts.join("+");
|
|
9308
|
+
S.text = S.text.slice(0, S.pos) + "(" + combined + ")" + S.text.slice(S.pos);
|
|
9259
9309
|
return token("punc", next());
|
|
9260
9310
|
};
|
|
9261
9311
|
if (!handle_interpolated_string.__argnames__) Object.defineProperties(handle_interpolated_string, {
|
|
@@ -9646,7 +9696,7 @@ return this.__repr__();
|
|
|
9646
9696
|
var is_token = ρσ_modules.tokenizer.is_token;
|
|
9647
9697
|
var RESERVED_WORDS = ρσ_modules.tokenizer.RESERVED_WORDS;
|
|
9648
9698
|
|
|
9649
|
-
COMPILER_VERSION = "
|
|
9699
|
+
COMPILER_VERSION = "33bc40d444e2a542a0577a3a3b0549d8381795ff";
|
|
9650
9700
|
PYTHON_FLAGS = (function(){
|
|
9651
9701
|
var ρσ_d = Object.create(null);
|
|
9652
9702
|
ρσ_d["dict_literals"] = true;
|
|
@@ -12207,7 +12257,7 @@ return this.__repr__();
|
|
|
12207
12257
|
});
|
|
12208
12258
|
|
|
12209
12259
|
function getitem(expr, allow_calls) {
|
|
12210
|
-
var start, is_py_sub, slice_bounds, is_slice, i, assignment;
|
|
12260
|
+
var start, is_py_sub, slice_bounds, is_slice, i, assignment, assign_operator;
|
|
12211
12261
|
start = expr.start;
|
|
12212
12262
|
next();
|
|
12213
12263
|
is_py_sub = S.scoped_flags.get("overload_getitem", false);
|
|
@@ -12326,7 +12376,9 @@ return this.__repr__();
|
|
|
12326
12376
|
} else {
|
|
12327
12377
|
if (is_py_sub) {
|
|
12328
12378
|
assignment = null;
|
|
12329
|
-
|
|
12379
|
+
assign_operator = "";
|
|
12380
|
+
if (is_("operator") && ASSIGNMENT[ρσ_bound_index(S.token.value, ASSIGNMENT)]) {
|
|
12381
|
+
assign_operator = S.token.value.slice(0, -1);
|
|
12330
12382
|
next();
|
|
12331
12383
|
assignment = expression(true);
|
|
12332
12384
|
}
|
|
@@ -12340,6 +12392,7 @@ return this.__repr__();
|
|
|
12340
12392
|
return ρσ_d;
|
|
12341
12393
|
}).call(this));
|
|
12342
12394
|
ρσ_d["assignment"] = assignment;
|
|
12395
|
+
ρσ_d["assign_operator"] = assign_operator;
|
|
12343
12396
|
ρσ_d["end"] = prev();
|
|
12344
12397
|
return ρσ_d;
|
|
12345
12398
|
}).call(this)), allow_calls);
|
|
@@ -14984,12 +15037,23 @@ return this.__repr__();
|
|
|
14984
15037
|
});
|
|
14985
15038
|
|
|
14986
15039
|
function print_rich_getitem(self, output) {
|
|
14987
|
-
var func;
|
|
15040
|
+
var func, asg, as_op;
|
|
14988
15041
|
func = "ρσ_" + ((self.assignment) ? "setitem" : "getitem");
|
|
14989
15042
|
output.print(func + "(");
|
|
14990
15043
|
[self.expression.print(output), output.comma(), self.property.print(output)];
|
|
14991
15044
|
if (self.assignment) {
|
|
14992
|
-
|
|
15045
|
+
output.comma();
|
|
15046
|
+
asg = self.assignment;
|
|
15047
|
+
as_op = self.assign_operator;
|
|
15048
|
+
if (as_op.length > 0) {
|
|
15049
|
+
self.assignment = null;
|
|
15050
|
+
print_rich_getitem(self, output);
|
|
15051
|
+
self.assignment = asg;
|
|
15052
|
+
output.space();
|
|
15053
|
+
output.print(as_op);
|
|
15054
|
+
output.space();
|
|
15055
|
+
}
|
|
15056
|
+
self.assignment.print(output);
|
|
14993
15057
|
}
|
|
14994
15058
|
output.print(")");
|
|
14995
15059
|
};
|
|
@@ -15356,7 +15420,7 @@ return this.__repr__();
|
|
|
15356
15420
|
var ρσ_Iter89 = ρσ_Iterable(left_hand_sides);
|
|
15357
15421
|
for (var ρσ_Index89 = 0; ρσ_Index89 < ρσ_Iter89.length; ρσ_Index89++) {
|
|
15358
15422
|
lhs = ρσ_Iter89[ρσ_Index89];
|
|
15359
|
-
if (is_node_type(lhs, AST_Seq) || is_node_type(lhs, AST_Array)) {
|
|
15423
|
+
if (is_node_type(lhs, AST_Seq) || is_node_type(lhs, AST_Array) || is_node_type(lhs, AST_ItemAccess)) {
|
|
15360
15424
|
is_compound_assign = true;
|
|
15361
15425
|
break;
|
|
15362
15426
|
}
|
package/release/signatures.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"ast": "
|
|
2
|
+
"ast": "7a1a1800d9ee7af7f7153eee38002e4e9dcfb71e",
|
|
3
3
|
"baselib-builtins": "50927b38fded9bd9dbe14c42a20dd8e930ac021f",
|
|
4
|
-
"baselib-containers": "
|
|
4
|
+
"baselib-containers": "59936060f92bff9c83a70489276f7e2f6edb6630",
|
|
5
5
|
"baselib-errors": "f2423e1e2489bdd7fb8c8725bb76436898c8008c",
|
|
6
|
-
"baselib-internal": "
|
|
6
|
+
"baselib-internal": "7a8544ec19d35ac9f6cea9bf1a8584b105d648b2",
|
|
7
7
|
"baselib-itertools": "ab1f3257642c8d26fab1ff9d392814a459a60cdb",
|
|
8
8
|
"baselib-str": "8c396e4fae02ae34b6d3d805becf7bfdd36625ee",
|
|
9
9
|
"compiler": "cfbfceb0439fed3302f78d80b303dca713b25e7b",
|
|
@@ -17,15 +17,15 @@
|
|
|
17
17
|
"output/literals": "fdbfb744fec8dfea1e1c62cb49767c60160fd402",
|
|
18
18
|
"output/loops": "f59cc623320f57edb01953f7877d712758e9f825",
|
|
19
19
|
"output/modules": "bd3e3f3f6794fb6e401867b4d011c4e3aab98893",
|
|
20
|
-
"output/operators": "
|
|
20
|
+
"output/operators": "bcda6aeab9214523252481c8dba2741c01f725bb",
|
|
21
21
|
"output/statements": "7d8dfdc0b43e3e430be7ce3b23ffaf1b41408d8c",
|
|
22
22
|
"output/stream": "46375cb467477ac898546e818bfdfa5be738c352",
|
|
23
23
|
"output/utils": "595968f96f6fdcc51eb41c34d64c92bb595e3cb1",
|
|
24
|
-
"parse": "
|
|
24
|
+
"parse": "d5c1a77662dfcff841dfcd368d5dbb129a592f5d",
|
|
25
25
|
"string_interpolation": "bff1cc76d772d24d35707f6c794f38734ca08376",
|
|
26
|
-
"tokenizer": "
|
|
26
|
+
"tokenizer": "1b23dc17814989686f4dc5b69f776b127f63c520",
|
|
27
27
|
"unicode_aliases": "79ac6eaa5e6be44a5397d62c561f854a8fe7528e",
|
|
28
28
|
"utils": "c1666db819aa7c8db38697e34e18362e3cb45869",
|
|
29
|
-
"#compiler#": "
|
|
30
|
-
"#compiled_with#": "
|
|
29
|
+
"#compiler#": "0b52100610a7474259047753e409de52cdb3e12c",
|
|
30
|
+
"#compiled_with#": "0b52100610a7474259047753e409de52cdb3e12c"
|
|
31
31
|
}
|
package/src/ast.pyj
CHANGED
|
@@ -719,6 +719,7 @@ class AST_ItemAccess(AST_PropAccess):
|
|
|
719
719
|
'Python index-style property access, i.e. `a.__getitem__("foo")`'
|
|
720
720
|
properties = {
|
|
721
721
|
'assignment': "[AST_Node or None] Not None if this is an assignment (a[x] = y) rather than a simple access",
|
|
722
|
+
'assign_operator': "[String] The operator for a assignment like += or empty string if plain assignment",
|
|
722
723
|
}
|
|
723
724
|
|
|
724
725
|
def _walk(self, visitor):
|
|
@@ -67,10 +67,7 @@ def ρσ_list_index(val, start, stop):
|
|
|
67
67
|
if start < 0:
|
|
68
68
|
raise ValueError(val + ' is not in list')
|
|
69
69
|
if stop is undefined:
|
|
70
|
-
|
|
71
|
-
if idx is -1:
|
|
72
|
-
raise ValueError(val + ' is not in list')
|
|
73
|
-
return idx
|
|
70
|
+
stop = this.length
|
|
74
71
|
if stop < 0:
|
|
75
72
|
stop = this.length + stop
|
|
76
73
|
for v'var i = start; i < stop; i++':
|
|
@@ -89,10 +86,11 @@ def ρσ_list_pop(index):
|
|
|
89
86
|
return ans[0]
|
|
90
87
|
|
|
91
88
|
def ρσ_list_remove(value):
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
89
|
+
for v'var i = 0; i < this.length; i++':
|
|
90
|
+
if this[i] == value:
|
|
91
|
+
this.splice(i, 1)
|
|
92
|
+
return
|
|
93
|
+
raise ValueError(value + ' not in list')
|
|
96
94
|
|
|
97
95
|
def ρσ_list_to_string():
|
|
98
96
|
return '[' + this.join(', ') + ']'
|
|
@@ -606,7 +604,7 @@ Object.defineProperties(ρσ_dict.prototype, {
|
|
|
606
604
|
return None if defval is undefined else defval
|
|
607
605
|
return ans
|
|
608
606
|
|
|
609
|
-
ρσ_dict.prototype.set_default = def (key, defval):
|
|
607
|
+
ρσ_dict.prototype.set_default = ρσ_dict.prototype.setdefault = def (key, defval):
|
|
610
608
|
j = this.jsmap
|
|
611
609
|
if not j.has(key):
|
|
612
610
|
j.set(key, defval)
|
|
@@ -632,11 +630,16 @@ Object.defineProperties(ρσ_dict.prototype, {
|
|
|
632
630
|
return ans
|
|
633
631
|
|
|
634
632
|
ρσ_dict.prototype.popitem = def ():
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
633
|
+
last = None
|
|
634
|
+
e = this.jsmap.entries()
|
|
635
|
+
while True:
|
|
636
|
+
r = e.next()
|
|
637
|
+
if r.done:
|
|
638
|
+
if last is None:
|
|
639
|
+
raise KeyError('dict is empty')
|
|
640
|
+
this.jsmap.delete(last.value[0])
|
|
641
|
+
return last.value
|
|
642
|
+
last = r
|
|
640
643
|
|
|
641
644
|
ρσ_dict.prototype.update = def ():
|
|
642
645
|
if arguments.length is 0:
|
package/src/baselib-internal.pyj
CHANGED
package/src/lib/math.pyj
CHANGED
package/src/lib/random.pyj
CHANGED
|
@@ -51,9 +51,30 @@ def random():
|
|
|
51
51
|
m *= 256
|
|
52
52
|
return v'n / 0x10000000000000000'
|
|
53
53
|
|
|
54
|
-
# unlike the python version, this DOES build a range object, feel free to reimplement
|
|
55
54
|
def randrange():
|
|
56
|
-
|
|
55
|
+
if arguments.length is 1:
|
|
56
|
+
return randbelow(int(arguments[0]))
|
|
57
|
+
start = int(arguments[0])
|
|
58
|
+
stop = int(arguments[1])
|
|
59
|
+
if arguments.length < 3:
|
|
60
|
+
step = 1
|
|
61
|
+
else:
|
|
62
|
+
step = int(arguments[2])
|
|
63
|
+
width = stop - start
|
|
64
|
+
if step is 1:
|
|
65
|
+
if width > 0:
|
|
66
|
+
return start + randbelow(width)
|
|
67
|
+
raise ValueError("empty range for randrange()")
|
|
68
|
+
if step > 0:
|
|
69
|
+
n = (width + step - 1) // step
|
|
70
|
+
elif step < 0:
|
|
71
|
+
n = (width + step + 1) // step
|
|
72
|
+
else:
|
|
73
|
+
raise ValueError("zero step for randrange()")
|
|
74
|
+
if n <= 0:
|
|
75
|
+
raise ValueError(f"empty range in randrange({start}, {stop}, {step})")
|
|
76
|
+
return start + step * randbelow(n)
|
|
77
|
+
|
|
57
78
|
|
|
58
79
|
def randint(a, b):
|
|
59
80
|
return int(random()*(b-a+1) + a)
|
|
@@ -61,9 +82,12 @@ def randint(a, b):
|
|
|
61
82
|
def uniform(a, b):
|
|
62
83
|
return random()*(b-a) + a
|
|
63
84
|
|
|
85
|
+
def randbelow(n):
|
|
86
|
+
return Math.floor(random()*n)
|
|
87
|
+
|
|
64
88
|
def choice(seq):
|
|
65
89
|
if seq.length > 0:
|
|
66
|
-
return seq[
|
|
90
|
+
return seq[randbelow(seq.length)]
|
|
67
91
|
else:
|
|
68
92
|
raise IndexError()
|
|
69
93
|
|
package/src/output/operators.pyj
CHANGED
|
@@ -55,7 +55,17 @@ def print_rich_getitem(self, output): # AST_ItemAccess
|
|
|
55
55
|
output.print(func + '(')
|
|
56
56
|
self.expression.print(output), output.comma(), self.property.print(output)
|
|
57
57
|
if self.assignment:
|
|
58
|
-
output.comma()
|
|
58
|
+
output.comma()
|
|
59
|
+
asg = self.assignment
|
|
60
|
+
as_op = self.assign_operator
|
|
61
|
+
if as_op.length > 0:
|
|
62
|
+
self.assignment = None
|
|
63
|
+
print_rich_getitem(self, output)
|
|
64
|
+
self.assignment = asg
|
|
65
|
+
output.space()
|
|
66
|
+
output.print(as_op)
|
|
67
|
+
output.space()
|
|
68
|
+
self.assignment.print(output)
|
|
59
69
|
output.print(')')
|
|
60
70
|
|
|
61
71
|
def print_splice_assignment(self, output): # AST_Splice
|
|
@@ -286,7 +296,7 @@ def print_assign(self, output):
|
|
|
286
296
|
left_hand_sides, rhs = self.traverse_chain()
|
|
287
297
|
is_compound_assign = False
|
|
288
298
|
for lhs in left_hand_sides:
|
|
289
|
-
if is_node_type(lhs, AST_Seq) or is_node_type(lhs, AST_Array):
|
|
299
|
+
if is_node_type(lhs, AST_Seq) or is_node_type(lhs, AST_Array) or is_node_type(lhs, AST_ItemAccess):
|
|
290
300
|
is_compound_assign = True
|
|
291
301
|
break
|
|
292
302
|
if is_compound_assign:
|
package/src/parse.pyj
CHANGED
|
@@ -1802,7 +1802,9 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1802
1802
|
# regular index (arr[index])
|
|
1803
1803
|
if is_py_sub:
|
|
1804
1804
|
assignment = None
|
|
1805
|
-
|
|
1805
|
+
assign_operator = ''
|
|
1806
|
+
if is_("operator") and ASSIGNMENT[S.token.value]:
|
|
1807
|
+
assign_operator = S.token.value[:-1]
|
|
1806
1808
|
next()
|
|
1807
1809
|
assignment = expression(True)
|
|
1808
1810
|
return subscripts(new AST_ItemAccess({
|
|
@@ -1812,6 +1814,7 @@ def create_parser_ctx(S, import_dirs, module_id, baselib_items, imported_module_
|
|
|
1812
1814
|
'value': 0
|
|
1813
1815
|
}),
|
|
1814
1816
|
'assignment':assignment,
|
|
1817
|
+
'assign_operator': assign_operator,
|
|
1815
1818
|
'end': prev()
|
|
1816
1819
|
}), allow_calls)
|
|
1817
1820
|
|
package/src/tokenizer.pyj
CHANGED
|
@@ -6,7 +6,7 @@ from unicode_aliases import ALIAS_MAP
|
|
|
6
6
|
from utils import make_predicate, characters
|
|
7
7
|
from ast import AST_Token
|
|
8
8
|
from errors import SyntaxError
|
|
9
|
-
from string_interpolation import interpolate
|
|
9
|
+
from string_interpolation import interpolate, quoted_string
|
|
10
10
|
|
|
11
11
|
RE_HEX_NUMBER = /^0x[0-9a-f]+$/i
|
|
12
12
|
RE_OCT_NUMBER = /^0[0-7]+$/
|
|
@@ -486,7 +486,45 @@ def tokenizer(raw_text, filename):
|
|
|
486
486
|
def handle_interpolated_string(string, start_tok):
|
|
487
487
|
def raise_error(err):
|
|
488
488
|
raise new SyntaxError(err, filename, start_tok.line, start_tok.col, start_tok.pos, False)
|
|
489
|
-
|
|
489
|
+
parts = v'[interpolate(string, raise_error)]'
|
|
490
|
+
# Look ahead for consecutive string literals to concatenate (e.g. f'a'f'b' or f'a''b')
|
|
491
|
+
while True:
|
|
492
|
+
# Skip horizontal whitespace (spaces and tabs, not newlines)
|
|
493
|
+
while S.pos < S.text.length and (S.text.charAt(S.pos) is ' ' or S.text.charAt(S.pos) is '\t'):
|
|
494
|
+
next()
|
|
495
|
+
ch = S.text.charAt(S.pos)
|
|
496
|
+
if not ch:
|
|
497
|
+
break
|
|
498
|
+
if ch is "'" or ch is '"':
|
|
499
|
+
# A plain string literal follows; read it and append its quoted value
|
|
500
|
+
stok = read_string(False, False)
|
|
501
|
+
parts.push(quoted_string(stok.value))
|
|
502
|
+
elif is_identifier_start(ch.charCodeAt(0)):
|
|
503
|
+
# Peek ahead (without consuming) to check if it is a string modifier followed by a quote
|
|
504
|
+
j = S.pos
|
|
505
|
+
while j < S.text.length and is_identifier_char(S.text.charAt(j)):
|
|
506
|
+
j += 1
|
|
507
|
+
potential_mod = S.text.substring(S.pos, j)
|
|
508
|
+
if not is_string_modifier(potential_mod):
|
|
509
|
+
break
|
|
510
|
+
if j >= S.text.length or '\'"'.indexOf(S.text.charAt(j)) is -1:
|
|
511
|
+
break
|
|
512
|
+
mods = potential_mod.toLowerCase()
|
|
513
|
+
if mods.indexOf('v') is not -1:
|
|
514
|
+
break # Do not concatenate with verbatim JS literals
|
|
515
|
+
# Consume the modifier characters via next() to keep position tracking correct
|
|
516
|
+
while S.pos < j:
|
|
517
|
+
next()
|
|
518
|
+
is_raw = mods.indexOf('r') is not -1
|
|
519
|
+
stok = read_string(is_raw, False)
|
|
520
|
+
if mods.indexOf('f') is not -1:
|
|
521
|
+
parts.push(interpolate(stok.value, raise_error))
|
|
522
|
+
else:
|
|
523
|
+
parts.push(quoted_string(stok.value))
|
|
524
|
+
else:
|
|
525
|
+
break
|
|
526
|
+
combined = parts.join('+')
|
|
527
|
+
S.text = S.text[:S.pos] + '(' + combined + ')' + S.text[S.pos:]
|
|
490
528
|
return token('punc', next())
|
|
491
529
|
|
|
492
530
|
def read_line_comment(shebang):
|
package/test/baselib.pyj
CHANGED
|
@@ -59,6 +59,14 @@ assrt.deepEqual(['y', 'x'], [x for x in reversed('xy')])
|
|
|
59
59
|
# Test that the iterator created by iter() is itself iterable
|
|
60
60
|
assrt.deepEqual(s, set(iter(s)))
|
|
61
61
|
|
|
62
|
+
# Test list index/remove/in use the same notion of equality
|
|
63
|
+
a = [1, 2]
|
|
64
|
+
b = [list(a), 3, 4]
|
|
65
|
+
assrt.ok(a in b)
|
|
66
|
+
assrt.equal(b.index(a), 0)
|
|
67
|
+
b.remove(a)
|
|
68
|
+
assrt.equal(len(b), 2)
|
|
69
|
+
|
|
62
70
|
assrt.ok('a' in m)
|
|
63
71
|
assrt.ok(1 in s)
|
|
64
72
|
assrt.ok('1' not in s)
|
|
@@ -234,6 +242,8 @@ def test_dicts():
|
|
|
234
242
|
assrt.ok(a is not a.copy()), assrt.deepEqual(a, a.copy())
|
|
235
243
|
a.clear()
|
|
236
244
|
assrt.equal(a.length, 0), assrt.deepEqual(list(a), [])
|
|
245
|
+
a[1] = a[2] = 19
|
|
246
|
+
assrt.deepEqual(a, {1:19, 2:19})
|
|
237
247
|
assrt.deepEqual(set({1:9, 2:8}.keys()), {1, 2})
|
|
238
248
|
assrt.deepEqual(set({1:9, 2:8}.values()), {8, 9})
|
|
239
249
|
items = [list_wrap(x) for x in {1:9, 2:8}.items()]
|
|
@@ -241,8 +251,8 @@ def test_dicts():
|
|
|
241
251
|
assrt.deepEqual(items, [[1,9], [2, 8]])
|
|
242
252
|
a = {1:1, 2:2}
|
|
243
253
|
assrt.equal(a.get(1), 1), assrt.equal(a.get(3), None)
|
|
244
|
-
assrt.equal(a.
|
|
245
|
-
assrt.equal(a.
|
|
254
|
+
assrt.equal(a.setdefault(2, 2), 2)
|
|
255
|
+
assrt.equal(a.setdefault(3, 3), 3), assrt.equal(a[3], 3)
|
|
246
256
|
assrt.deepEqual(dict.fromkeys([1, 2], 3), {1:3, 2:3})
|
|
247
257
|
a = {1:3, 2:3}
|
|
248
258
|
assrt.equal(a.pop(2, 2), 3), assrt.equal(a.pop(2, 2), 2)
|
package/test/collections.pyj
CHANGED
package/test/scoped_flags.pyj
CHANGED
package/test/str.pyj
CHANGED
|
@@ -49,6 +49,14 @@ def test_interpolation():
|
|
|
49
49
|
ae(f'{a=}', 'a=1')
|
|
50
50
|
somevar = {'x': 1}
|
|
51
51
|
ae(f'{somevar.x=}', 'somevar.x=1')
|
|
52
|
+
# Test consecutive f-string concatenation
|
|
53
|
+
ae(f'a'f'b', 'ab')
|
|
54
|
+
ae(f'a' f'b', 'ab')
|
|
55
|
+
ae(f'a'f'{a}', 'a1')
|
|
56
|
+
ae(f'{a}' f'b', '1b')
|
|
57
|
+
ae(f'{a}'f'{a}', '11')
|
|
58
|
+
ae(f'a''b', 'ab')
|
|
59
|
+
ae(f'{a}''b', '1b')
|
|
52
60
|
|
|
53
61
|
somevar = 33
|
|
54
62
|
test('somevar=33', '{somevar=}', somevar=somevar)
|
package/tools/cli.js
CHANGED
|
@@ -350,7 +350,7 @@ it.
|
|
|
350
350
|
create_group('lint', "[input1.pyj input2.pyj ...]", function(){/*
|
|
351
351
|
Run the RapydScript linter. This will find various
|
|
352
352
|
possible problems in the .pyj files you specify and
|
|
353
|
-
write messages about them to stdout.
|
|
353
|
+
write messages about them to stdout. Use - to read from STDIN.
|
|
354
354
|
The main check it performs is for unused/undefined
|
|
355
355
|
symbols, like pyflakes does for python.
|
|
356
356
|
*/}, function() {/*
|
|
@@ -421,6 +421,11 @@ List all available linter checks, with a brief
|
|
|
421
421
|
description, and exit.
|
|
422
422
|
*/});
|
|
423
423
|
|
|
424
|
+
opt('stdin_filename', '', 'string', 'STDIN', function(){/*
|
|
425
|
+
The filename for data read from STDIN. If not specified
|
|
426
|
+
STDIN is used.
|
|
427
|
+
*/});
|
|
428
|
+
|
|
424
429
|
create_group('test', '[test1 test2...]', function(){/*
|
|
425
430
|
Run RapydScript tests. You can specify the name of
|
|
426
431
|
individual test files to only run tests from those
|
package/tools/lint.js
CHANGED
|
@@ -564,7 +564,7 @@ function lint_code(code, options) {
|
|
|
564
564
|
// CLI {{{
|
|
565
565
|
|
|
566
566
|
function read_whole_file(filename, cb) {
|
|
567
|
-
if (!filename) {
|
|
567
|
+
if (!filename || filename === '-') {
|
|
568
568
|
var chunks = [];
|
|
569
569
|
process.stdin.setEncoding('utf-8');
|
|
570
570
|
process.stdin.on('data', function (chunk) {
|
|
@@ -653,6 +653,10 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
|
|
|
653
653
|
if (argv.globals) argv.globals.split(',').forEach(function(sym) { builtins[sym] = true; });
|
|
654
654
|
if (argv.noqa) argv.noqa.split(',').forEach(function(sym) { noqa[sym] = true; });
|
|
655
655
|
|
|
656
|
+
function path_for_filename(x) {
|
|
657
|
+
return x === '-' ? argv.stdin_filename : x;
|
|
658
|
+
}
|
|
659
|
+
|
|
656
660
|
function lint_single_file(err, code) {
|
|
657
661
|
var output, final_builtins = merge(builtins), final_noqa = merge(noqa), rl;
|
|
658
662
|
if (err) {
|
|
@@ -661,7 +665,7 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
|
|
|
661
665
|
}
|
|
662
666
|
|
|
663
667
|
// Read setup.cfg
|
|
664
|
-
rl = get_ini(path.dirname(files[0]));
|
|
668
|
+
rl = get_ini(path.dirname(path_for_filename(files[0])));
|
|
665
669
|
var g = {};
|
|
666
670
|
(rl.globals || rl.builtins || '').split(',').forEach(function (x) { g[x.trim()] = true; });
|
|
667
671
|
final_builtins = merge(final_builtins, g);
|
|
@@ -681,7 +685,7 @@ module.exports.cli = function(argv, base_path, src_path, lib_path) {
|
|
|
681
685
|
});
|
|
682
686
|
|
|
683
687
|
// Lint!
|
|
684
|
-
if (lint_code(code, {filename:files[0], builtins:final_builtins, noqa:final_noqa, errorformat:argv.errorformat || false}).length) all_ok = false;
|
|
688
|
+
if (lint_code(code, {filename:path_for_filename(files[0]), builtins:final_builtins, noqa:final_noqa, errorformat:argv.errorformat || false}).length) all_ok = false;
|
|
685
689
|
|
|
686
690
|
files = files.slice(1);
|
|
687
691
|
if (files.length) {
|