Permalink
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Dec 20, 2018
Dec 20, 2018
Jan 14, 2015
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Jan 14, 2015
Mar 19, 2018
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Mar 19, 2018
Jan 14, 2015
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Jan 14, 2015
Mar 19, 2018
Jan 14, 2015
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Jan 14, 2015
Jan 14, 2015
Mar 19, 2018
Mar 19, 2018
Jan 14, 2015
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 27, 2019
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Apr 2, 2019
Mar 19, 2018
Aug 31, 2017
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Aug 31, 2017
Apr 16, 2019
Mar 19, 2018
Apr 16, 2019
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Nov 12, 2018
Nov 12, 2018
Nov 12, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Apr 2, 2019
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Aug 31, 2017
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Jan 6, 2016
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Aug 31, 2017
May 24, 2019
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Aug 31, 2017
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Nov 14, 2018
Mar 19, 2018
Mar 19, 2018
Jul 28, 2018
Mar 19, 2019
Oct 27, 2019
Nov 2, 2018
Oct 27, 2019
Nov 2, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Nov 12, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Jun 29, 2017
Jun 29, 2017
Jun 29, 2017
Oct 13, 2019
Jun 29, 2017
Jul 10, 2017
Jul 10, 2017
Mar 19, 2018
Mar 19, 2018
Oct 13, 2019
Oct 13, 2019
Newer
100644
2382 lines (2184 sloc)
76.1 KB
21
if($.start === null || $.start === _b_.None){$.start = 0}
22
else if($.start < 0){
23
$.start += $.self.length
24
$.start = Math.max(0, $.start)
25
}
26
if($.end === null || $.end === _b_.None){$.end = $.self.length}
27
else if($.end < 0){
28
$.end += $.self.length
29
$.end = Math.max(0, $.end)
30
}
32
if(! isinstance($.start, _b_.int) || ! isinstance($.end, _b_.int)){
33
throw _b_.TypeError.$factory("slice indices must be integers " +
34
"or None or have an __index__ method")
35
}
52
if(!(typeof other === "string")){
53
try{return getattr(other, "__radd__")(self)}
54
catch(err){
55
throw _b_.TypeError.$factory("Can't convert " +
61
str.__contains__ = function(self, item){
62
if(!(typeof item == "string")){
63
throw _b_.TypeError.$factory("'in <string>' requires " +
64
"string as left operand, not " + item.__class__)
65
}
67
if(nbcar == 0) {return true} // a string contains the empty string
68
if(self.length == 0){return nbcar == 0}
69
for(var i = 0, len = self.length; i < len; i++){
70
if(self.substr(i, nbcar) == item){return true}
79
// __dir__must be assigned explicitely because attribute resolution for
80
// builtin classes doesn't use __mro__
84
if(other === undefined){ // compare object "self" to class "str"
85
return self === str
95
if(fmt.type && fmt.type != "s"){
96
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
104
if(fmt.sign !== undefined){
105
throw _b_.ValueError.$factory(
106
"Sign not allowed in string format specifier")
116
if(arg < 0) {pos += self.length}
117
if(pos >= 0 && pos < self.length){return self.charAt(pos)}
118
throw _b_.IndexError.$factory("string index out of range")
119
}
120
if(isinstance(arg, slice)) {
121
var s = _b_.slice.$conv_for_seq(arg, self.length),
122
start = s.start,
123
stop = s.stop,
124
step = s.step
125
var res = "",
127
if(step > 0){
128
if(stop <= start){return ""}
129
for(var i = start; i < stop; i += step){res += self.charAt(i)}
131
if(stop >= start){return ''}
132
for(var i = start; i > stop; i += step){res += self.charAt(i)}
140
var prefix = 2,
141
suffix = 3,
142
mask = (2 ** 32 - 1)
143
function fnv(p){
144
if(p.length == 0){
145
return 0
146
}
148
var x = prefix
149
x = (x ^ (p.charCodeAt(0) << 7)) & mask
150
for(var i = 0, len = p.length; i < len; i++){
151
x = ((1000003 * x) ^ p.charCodeAt(i)) & mask
152
}
153
x = (x ^ p.length) & mask
154
x = (x ^ suffix) & mask
212
// left adjusted
213
return s + get_char_array(padding - s.length, flags.pad_char)
214
}
215
}
216
224
if(val.__class__ === $B.long_int){
225
s = $B.long_int.to_base(val, 10)
226
}else{
227
s = val.toString()
229
if(s[0] === "-"){
230
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
241
if(val === Infinity){
242
val = "inf"
243
}else if(val === -Infinity){
244
val = "-inf"
245
}else{
246
val = "nan"
268
var str_format = function(val, flags) {
269
// string format supports left and right padding
270
flags.pad_char = " " // even if 0 padding is defined, don't use it
276
if(val.__class__ === $B.long_int){
277
val = $B.long_int.to_base(val, 10)
278
}else{
279
val = parseInt(val)
297
var repr_format = function(val, flags) {
298
flags.pad_char = " " // even if 0 padding is defined, don't use it
299
return format_padding(repr(val), flags)
300
}
302
var ascii_format = function(val, flags) {
303
flags.pad_char = " " // even if 0 padding is defined, don't use it
304
return format_padding(ascii(val), flags)
305
}
317
flags.precision = parseInt(flags.precision, 10)
318
validate_precision(flags.precision)
319
}
320
return parseFloat(val)
321
}
324
var trailing_zeros = /(.*?)(0+)([eE].*)/,
325
leading_zeros = /\.(0*)/,
326
trailing_dot = /\.$/
328
var validate_precision = function(precision) {
329
// force precision to limits of javascript
334
var floating_point_format = function(val, upper, flags){
335
val = _float_helper(val, flags),
336
v = val.toString(),
337
v_len = v.length,
338
dot_idx = v.indexOf('.')
339
if(dot_idx < 0){dot_idx = v_len}
340
if(val < 1 && val > -1){
341
var zeros = leading_zeros.exec(v),
342
numzeros
343
if(zeros){
348
if(numzeros >= 4){
349
val = format_sign(val, flags) + format_float_precision(val, upper,
350
flags, _floating_g_exp_helper)
351
if(!flags.alternate){
364
return format_padding(format_sign(val, flags) +
365
format_float_precision(val, upper, flags,
366
function(val, precision) {
367
return val.toFixed(min(precision, v_len - dot_idx) +
368
numzeros)
369
}),
370
flags
371
)
372
}
373
374
if(dot_idx > flags.precision){
375
val = format_sign(val, flags) + format_float_precision(val, upper,
376
flags, _floating_g_exp_helper)
377
if(! flags.alternate){
389
return format_padding(format_sign(val, flags) +
390
format_float_precision(val, upper, flags,
391
function(val, precision) {
392
if(!flags.decimal_point){
393
precision = min(v_len - 1, 6)
394
}else if (precision > v_len){
395
if(! flags.alternate){
396
precision = v_len
397
}
399
if(precision < dot_idx){
400
precision = dot_idx
401
}
402
return val.toFixed(precision - dot_idx)
403
}),
404
flags
405
)
408
var _floating_g_exp_helper = function(val, precision, flags, upper){
409
if(precision){--precision}
412
var e_idx = val.lastIndexOf("e")
413
if(e_idx > val.length - 4){
414
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
417
return val
418
}
419
420
// fF
421
var floating_point_decimal_format = function(val, upper, flags) {
422
val = _float_helper(val, flags)
423
return format_padding(format_sign(val, flags) +
424
format_float_precision(val, upper, flags,
425
function(val, precision, flags) {
426
val = val.toFixed(precision)
427
if(precision === 0 && flags.alternate){
428
val += '.'
429
}
430
return val
431
}),
432
flags
433
)
434
}
435
436
var _floating_exp_helper = function(val, precision, flags, upper) {
437
val = val.toExponential(precision)
438
// pad exponent to two digits
451
return format_padding(format_sign(val, flags) +
452
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
478
if(flags.alternate){
479
if(ret.charAt(0) === "-"){
480
if(upper){ret = "-0X" + ret.slice(1)}
481
else{ret = "-0x" + ret.slice(1)}
482
}else{
483
if(upper){ret = "0X" + ret}
484
else{ret = "0x" + ret}
494
if(val.__class__ === $B.long_int){
495
ret = $B.long_int.to_base(8)
496
}else{
497
ret = parseInt(val)
498
ret = ret.toString(8)
514
if(flags.alternate){
515
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
516
else{ret = "0o" + ret}
521
var single_char_format = function(val, flags){
522
if(isinstance(val, str) && val.length == 1) return val
523
try{
531
var num_flag = function(c, flags){
532
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
533
flags.pad_char = "0"
539
flags.precision = (flags.precision || "") + c
540
}
541
}
542
543
var decimal_point_flag = function(val, flags) {
545
// can only have one decimal point
546
throw new UnsupportedChar()
547
}
548
flags.decimal_point = true
549
}
550
551
var neg_flag = function(val, flags){
552
flags.pad_char = " " // overrides '0' flag
569
"s": str_format,
570
"d": num_format,
571
"i": num_format,
572
"u": num_format,
573
"o": octal_format,
574
"r": repr_format,
575
"a": ascii_format,
576
"g": function(val, flags){
577
return floating_point_format(val, false, flags)
578
},
579
"G": function(val, flags){return floating_point_format(val, true, flags)},
580
"f": function(val, flags){
581
return floating_point_decimal_format(val, false, flags)
582
},
583
"F": function(val, flags){
584
return floating_point_decimal_format(val, true, flags)
585
},
586
"e": function(val, flags){
587
return floating_point_exponential_format(val, false, flags)
588
},
589
"E": function(val, flags){
590
return floating_point_exponential_format(val, true, flags)
591
},
592
"x": function(val, flags){return signed_hex_format(val, false, flags)},
593
"X": function(val, flags){return signed_hex_format(val, true, flags)},
594
"c": single_char_format,
595
"0": function(val, flags){return num_flag("0", flags)},
596
"1": function(val, flags){return num_flag("1", flags)},
597
"2": function(val, flags){return num_flag("2", flags)},
598
"3": function(val, flags){return num_flag("3", flags)},
599
"4": function(val, flags){return num_flag("4", flags)},
600
"5": function(val, flags){return num_flag("5", flags)},
601
"6": function(val, flags){return num_flag("6", flags)},
602
"7": function(val, flags){return num_flag("7", flags)},
603
"8": function(val, flags){return num_flag("8", flags)},
604
"9": function(val, flags){return num_flag("9", flags)},
605
"-": neg_flag,
606
" ": space_flag,
607
"+": sign_flag,
608
".": decimal_point_flag,
609
"#": alternate_flag
610
}
611
612
// exception thrown when an unsupported char is encountered in legacy format
659
if(self === undefined){
660
throw _b_.TypeError.$factory(
661
"not enough arguments for format string")
688
throw _b_.ValueError.$factory(
689
"unsupported format character '" + invalid_char +
690
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
691
") at index " + newpos)
692
}else if(err.name === "NotANumber"){
693
var try_char = s[newpos],
694
cls = self.__class__
695
if(!cls){
696
if(typeof(self) === "string"){
697
cls = "str"
698
}else{
704
throw _b_.TypeError.$factory("%" + try_char +
705
" format: a number is required, not " + cls)
706
}else{
738
}while(pos < length)
739
740
if(argpos !== null){
741
if(args.length > argpos){
742
throw _b_.TypeError.$factory(
743
"not enough arguments for format string")
744
}else if(args.length < argpos){
745
throw _b_.TypeError.$factory(
746
"not all arguments converted during string formatting")
748
}else if(nbph == 0){
749
throw _b_.TypeError.$factory(
750
"not all arguments converted during string formatting")
758
var $ = $B.args("__mul__", 2, {self: null, other: null},
759
["self", "other"], arguments, {}, null, null)
760
if(! isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
761
"Can't multiply sequence by non-int of type '" +
773
res = self.replace(/\\/g, "\\\\")
774
// special cases
775
res = res.replace(new RegExp("\u0007", "g"), "\\x07").
776
replace(new RegExp("\b", "g"), "\\x08").
777
replace(new RegExp("\f", "g"), "\\x0c").
778
replace(new RegExp("\n", "g"), "\\n").
779
replace(new RegExp("\r", "g"), "\\r").
780
replace(new RegExp("\t", "g"), "\\t")
783
if(res.search('"') == -1 && res.search("'") == -1){
784
return "'" + res + "'"
785
}else if(self.search('"') == -1){
786
return '"' + res + '"'
787
}
788
var qesc = new RegExp("'", "g") // to escape single quote
789
res = "'" + res.replace(qesc, "\\'") + "'"
793
str.__setitem__ = function(self, attr, value){
794
throw _b_.TypeError.$factory(
795
"'str' object does not support item assignment")
797
var combining = []
798
for(var cp = 0x300; cp <= 0x36F; cp++){
799
combining.push(String.fromCharCode(cp))
800
}
801
var combining_re = new RegExp("(" + combining.join("|") + ")")
813
$comp_func += "" // source code
814
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
823
var $notimplemented = function(self, other){
824
throw NotImplementedError.$factory(
825
"OPERATOR not implemented for class str")
828
str.capitalize = function(self){
829
var $ = $B.args("capitalize", 1, {self}, ["self"],
830
arguments, {}, null, null)
831
if(self.length == 0){return ""}
832
return self.charAt(0).toUpperCase() + self.substr(1)
833
}
834
835
str.casefold = function(self){
836
var $ = $B.args("casefold", 1, {self}, ["self"],
837
arguments, {}, null, null),
838
res = "",
839
char,
840
cf
841
for(var i = 0, len = self.length; i < len; i++){
842
char = self.charCodeAt(i)
843
cf = $B.unicode_casefold[char]
844
if(cf){
845
cf.forEach(function(cp){
846
res += String.fromCharCode(cp)
847
})
848
}else{
849
res += self.charAt(i).toLowerCase()
850
}
851
}
852
return res
853
}
855
str.center = function(){
856
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
857
["self", "width", "fillchar"],
858
arguments, {fillchar:" "}, null, null),
859
self = $.self
871
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
872
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
880
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
881
else{_slice = _b_.slice.$factory($.start, $.self.length)}
886
if($.sub.length == 0){
887
if($.start == $.self.length){return 1}
888
else if(substr.length == 0){return 0}
889
return substr.length + 1
891
var n = 0,
892
pos = 0
893
while(pos < substr.length){
894
pos = substr.indexOf($.sub, pos)
895
if(pos >= 0){n++; pos += $.sub.length}
896
else{break}
901
str.encode = function(){
902
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
903
["self", "encoding", "errors"], arguments,
904
{encoding: "utf-8", errors: "strict"}, null, null)
905
if($.encoding == "rot13" || $.encoding == "rot_13"){
910
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
911
res += String.fromCharCode(String.charCodeAt(char) + 13)
912
}else if(("m" < char && char <= "z") ||
913
("M" < char && char <= "Z")){
914
res += String.fromCharCode(String.charCodeAt(char) - 13)
923
// Return True if the string ends with the specified suffix, otherwise
924
// return False. suffix can also be a tuple of suffixes to look for.
925
// With optional start, test beginning at that position. With optional
929
["self", "suffix", "start", "end"],
930
arguments, {start: 0, end: null}, null, null)
937
var s = $.self.substring($.start, $.end)
938
for(var i = 0, len = suffixes.length; i < len; i++){
942
if(suffix.length <= s.length &&
943
s.substr(s.length - suffix.length) == suffix){return true}
949
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
950
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
951
var s = $B.$GetInt($.tabsize),
952
col = 0,
953
pos = 0,
954
res = ""
955
if(s == 1){return self.replace(/\t/g," ")}
956
while(pos < self.length){
964
res += car
965
col = 0
966
break
967
default:
968
res += car
969
col++
970
break
971
}
972
pos++
973
}
979
// Return the lowest index in the string where substring sub is found,
980
// such that sub is contained in the slice s[start:end]. Optional
981
// arguments start and end are interpreted as in slice notation.
984
{self: null, sub: null, start: null, end: null},
985
["self", "sub", "start", "end"],
986
arguments, {start: 0, end: null}, null, null)
990
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
991
throw _b_.TypeError.$factory("slice indices must be " +
992
"integers or None or have an __index__ method")}
993
// Can't use string.substring(start, end) because if end < start,
994
// Javascript transforms it into substring(end, start)...
995
var s = ""
996
for(var i = $.start; i < $.end; i++){
997
s += $.self.charAt(i)
998
}
1000
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1001
if(s.length + $.sub.length == 0){return -1}
1003
var last_search = s.length - $.sub.length
1004
for(var i = 0; i <= last_search; i++){
1005
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
1016
// a.x[z]!r:...
1017
// the object has attributes :
1018
// - name : "a"
1019
// - name_ext : [".x", "[z]"]
1020
// - conv : r
1021
// - spec : rest of string after :
1029
// No : in the string : it only contains a name
1030
name = fmt_string
1031
}else{
1032
// name is before the first ":"
1033
// spec (the format specification) is after
1034
name = elts[0]
1038
var elts = name.split("!")
1039
if(elts.length > 1){
1040
name = elts[0]
1041
conv = elts[1] // conversion flag
1045
// "name' may be a subscription or attribute
1046
// Put these "extensions" in the list "name_ext"
1047
function name_repl(match){
1048
name_ext.push(match)
1050
}
1051
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1052
name = name.replace(name_ext_re, name_repl)
1053
}
1060
// Parse self to detect formatting instructions
1061
// Create a list "parts" made of sections of the string :
1062
// - elements of even rank are literal text
1063
// - elements of odd rank are "format objects", built from the
1064
// format strings in self (of the form {...})
1075
text += "{"
1076
pos += 2
1077
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1084
// Store current literal text
1085
parts.push(text)
1086
1087
// Search the end of the format string, ie the } closing the
1088
// opening {. Since the string can contain other pairs {} for
1089
// nested formatting, an integer nb is incremented for each { and
1090
// decremented for each } ; the end of the format string is
1091
// reached when nb == 0
1092
var end = pos + 1,
1093
nb = 1
1094
while(end < _len){
1095
if(self.charAt(end) == "{"){nb++; end++}
1096
else if(self.charAt(end) == "}"){
1097
nb--; end++
1098
if(nb == 0){
1103
var fmt_obj = $B.parse_format(fmt_string)
1104
fmt_obj.raw_name = fmt_obj.name
1105
fmt_obj.raw_spec = fmt_obj.spec
1140
return parts
1141
}
1142
1143
str.format = function(self) {
1144
var $ = $B.args("format", 1, {self: null}, ["self"],
1145
arguments, {}, "$args", "$kw")
1146
1147
var parts = $B.split_format($.self)
1148
1159
1160
if(fmt.spec !== undefined){
1161
// "spec" may contain "nested replacement fields"
1162
// In this case, evaluate them using the positional
1163
// or keyword arguments passed to format()
1164
function replace_nested(name, key){
1165
if(/\d+/.exec(key)){
1166
// If key is numeric, search in positional
1167
// arguments
1168
return _b_.tuple.__getitem__($.$args,
1169
parseInt(key))
1170
}else{
1171
// Else try in keyword arguments
1172
return _b_.dict.__getitem__($.$kw, key)
1173
}
1174
}
1175
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1176
replace_nested)
1177
}
1179
// Numerical reference : use positional arguments
1180
var pos = parseInt(fmt.name),
1190
// Attribute
1191
value = _b_.getattr(value, ext.substr(1))
1192
}else{
1193
// Subscription
1196
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1197
value = _b_.getattr(value, "__getitem__")(key)
1201
// If the conversion flag is set, first call a function to convert
1202
// the value
1203
if(fmt.conv == "a"){value = _b_.ascii(value)}
1204
else if(fmt.conv == "r"){value = _b_.repr(value)}
1205
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1219
throw NotImplementedError.$factory(
1220
"function format_map not implemented yet")
1231
/* Return true if the string is empty or all characters in the string are
1232
ASCII, false otherwise. ASCII characters have code points in the range
1233
U+0000-U+007F. */
1234
for(var i = 0, len = self.length; i < len; i++){
1235
if(self.charCodeAt(i) > 127){return false}
1236
}
1237
return true
1238
}
1239
1240
str.isalnum = function(self){
1241
/* Return true if all characters in the string are alphanumeric and there
1242
is at least one character, false otherwise. A character c is alphanumeric
1243
if one of the following returns True: c.isalpha(), c.isdecimal(),
1244
c.isdigit(), or c.isnumeric(). */
1245
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1246
arguments, {}, null, null),
1247
char
1248
for(var i = 0, len = self.length; i < len; i++){
1249
char = self.charCodeAt(i)
1250
if(unicode_tables.Ll[char] ||
1251
unicode_tables.Lu[char] ||
1252
unicode_tables.Lm[char] ||
1253
unicode_tables.Lt[char] ||
1254
unicode_tables.Lo[char] ||
1255
unicode_tables.Nd[char] ||
1256
unicode_tables.digits[char] ||
1257
unicode_tables.numeric[char]){
1258
continue
1259
}
1260
return false
1261
}
1262
return true
1263
}
1264
1265
str.isalpha = function(self){
1266
/* Return true if all characters in the string are alphabetic and there is
1267
at least one character, false otherwise. Alphabetic characters are those
1268
characters defined in the Unicode character database as "Letter", i.e.,
1269
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1270
or "Lo". */
1271
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1272
arguments, {}, null, null),
1273
char
1274
for(var i = 0, len = self.length; i < len; i++){
1275
char = self.charCodeAt(i)
1276
if(unicode_tables.Ll[char] ||
1277
unicode_tables.Lu[char] ||
1278
unicode_tables.Lm[char] ||
1279
unicode_tables.Lt[char] ||
1280
unicode_tables.Lo[char]){
1281
continue
1282
}
1283
return false
1284
}
1285
return true
1286
}
1287
1288
str.isdecimal = function(self){
1289
/* Return true if all characters in the string are decimal characters and
1290
there is at least one character, false otherwise. Decimal characters are
1291
those that can be used to form numbers in base 10, e.g. U+0660,
1292
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1293
the Unicode General Category "Nd". */
1294
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1295
arguments, {}, null, null),
1296
char
1297
for(var i = 0, len = self.length; i < len; i++){
1298
char = self.charCodeAt(i)
1299
if(! unicode_tables.Nd[char]){
1300
return false
1301
}
1302
}
1303
return self.length > 0
1304
}
1305
1306
str.isdigit = function(self){
1307
/* Return true if all characters in the string are digits and there is at
1308
least one character, false otherwise. */
1309
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1310
arguments, {}, null, null),
1311
char
1312
for(var i = 0, len = self.length; i < len; i++){
1313
char = self.charCodeAt(i)
1314
if(! unicode_tables.digits[char]){
1315
return false
1316
}
1317
}
1318
return self.length > 0
1319
}
1320
1321
str.isidentifier = function(self){
1322
/* Return true if the string is a valid identifier according to the
1323
language definition. */
1324
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1325
arguments, {}, null, null),
1326
char
1327
if(self.length == 0){return false}
1328
else if(unicode_tables.XID_Start[self.charCodeAt(0)] === undefined){
1329
return false
1330
}else{
1331
for(var i = 1, len = self.length; i < len; i++){
1332
if(unicode_tables.XID_Continue[self.charCodeAt(i)] === undefined){
1333
return false
1334
}
1335
}
1336
}
1337
return true
1338
}
1339
1340
str.islower = function(self){
1341
/* Return true if all cased characters 4 in the string are lowercase and
1342
there is at least one cased character, false otherwise. */
1343
var $ = $B.args("islower", 1, {self: null}, ["self"],
1344
arguments, {}, null, null),
1345
has_cased = false,
1346
char
1347
1348
for(var i = 0, len = self.length; i < len; i++){
1349
char = self.charCodeAt(i)
1350
if(unicode_tables.Ll[char]){has_cased = true; continue}
1351
else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1352
return false
1353
}
1354
}
1355
return has_cased
1356
}
1357
1358
str.isnumeric = function(self){
1359
/* Return true if all characters in the string are numeric characters, and
1360
there is at least one character, false otherwise. Numeric characters
1361
include digit characters, and all characters that have the Unicode numeric
1362
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1363
characters are those with the property value Numeric_Type=Digit,
1364
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1365
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1366
arguments, {}, null, null)
1367
for(var i = 0, len = self.length; i < len; i++){
1368
if(! unicode_tables.numeric[self.charCodeAt(i)]){
1369
return false
1370
}
1371
}
1372
return self.length > 0
1373
}
1374
1375
var printable,
1376
printable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1377
1378
str.isprintable = function(self){
1379
/* Return true if all characters in the string are printable or the string
1380
is empty, false otherwise. Nonprintable characters are those characters
1381
defined in the Unicode character database as "Other" or "Separator",
1382
excepting the ASCII space (0x20) which is considered printable. */
1383
1384
// Set printable if not set yet
1385
if(printable === undefined){
1386
for(var i = 0; i < printable_gc.length; i++){
1387
var table = unicode_tables[printable_gc[i]]
1388
for(var cp in table){
1389
printable[cp] = true
1390
}
1391
}
1392
printable[32] = true
1393
}
1394
1395
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1396
arguments, {}, null, null),
1397
char,
1398
flag
1399
for(var i = 0, len = self.length; i < len; i++){
1400
char = self.charCodeAt(i)
1401
if(! printable[char]){
1402
return false
1403
}
1404
}
1405
return true
1406
}
1407
1408
str.isspace = function(self){
1409
/* Return true if there are only whitespace characters in the string and
1410
there is at least one character, false otherwise.
1411
1412
A character is whitespace if in the Unicode character database, either its
1413
general category is Zs ("Separator, space"), or its bidirectional class is
1414
one of WS, B, or S.*/
1415
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1416
arguments, {}, null, null),
1417
char
1418
for(var i = 0, len = self.length; i < len; i++){
1419
char = self.charCodeAt(i)
1420
if(! unicode_tables.Zs[char] &&
1421
$B.unicode_bidi_whitespace.indexOf(char) == -1){
1422
return false
1423
}
1424
}
1425
return self.length > 0
1426
}
1427
1428
str.istitle = function(self){
1429
/* Return true if the string is a titlecased string and there is at least
1430
one character, for example uppercase characters may only follow uncased
1431
characters and lowercase characters only cased ones. Return false
1432
otherwise. */
1433
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1434
arguments, {}, null, null)
1435
return self.length > 0 && str.title(self) == self
1436
}
1437
1438
str.isupper = function(self){
1439
/* Return true if all cased characters 4 in the string are lowercase and
1440
there is at least one cased character, false otherwise. */
1441
var $ = $B.args("islower", 1, {self: null}, ["self"],
1442
arguments, {}, null, null),
1443
has_cased = false,
1444
char
1445
1446
for(var i = 0, len = self.length; i < len; i++){
1447
char = self.charCodeAt(i)
1448
if(unicode_tables.Lu[char]){has_cased = true; continue}
1449
else if(unicode_tables.Ll[char] || unicode_tables.Lt[char]){
1467
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1468
"sequence item " + count + ": expected str instance, " +
1482
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1483
["self", "width", "fillchar"],
1484
arguments, {fillchar: " "}, null, null)
1490
str.lower = function(self){
1491
var $ = $B.args("lower", 1, {self: null}, ["self"],
1492
arguments, {}, null, null)
1493
return self.toLowerCase()
1494
}
1495
1497
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1498
arguments, {chars:_b_.None}, null, null)
1499
if($.chars === _b_.None){return $.self.trimLeft()}
1500
for(var i = 0; i < $.self.length; i++){
1501
if($.chars.indexOf($.self.charAt(i)) === -1){
1502
return $.self.substring(i)
1510
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1511
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
1516
// If there is only one argument, it must be a dictionary mapping
1517
// Unicode ordinals (integers) or characters (strings of length 1) to
1518
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1520
if(! _b_.isinstance($.x, _b_.dict)){
1521
throw _b_.TypeError.$factory(
1522
"maketrans only argument must be a dict")
1525
for(var i = 0, len = items.length; i < len; i++){
1526
var k = items[i][0],
1527
v = items[i][1]
1528
if(! _b_.isinstance(k, _b_.int)){
1529
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1530
k = _b_.ord(k)
1531
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1534
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1535
throw _b_.TypeError.$factory("dictionary value " + v +
1543
// and in the resulting dictionary, each character in x will be mapped
1544
// to the character at the same position in y
1547
}else if($.x.length !== $.y.length){
1548
throw _b_.TypeError.$factory(
1549
"maketrans arguments must be strings or same length")
1555
if(! _b_.isinstance($.z, _b_.str)){
1556
throw _b_.TypeError.$factory(
1557
"maketrans third argument must be a string")
1579
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1580
arguments, {}, null, null)
1585
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1586
$.self.substring(i + $.sep.length)])
1587
}
1588
1589
function $re_escape(str){
1590
var specials = "[.*+?|()$^"
1591
for(var i = 0, len = specials.length; i < len; i++){
1592
var re = new RegExp("\\"+specials.charAt(i), "g")
1593
str = str.replace(re, "\\"+specials.charAt(i))
1594
}
1595
return str
1602
var $ = $B.args("replace", 4,
1603
{self: null, old: null, $$new: null, count: null},
1604
["self", "old", "$$new", "count"],
1605
arguments, {count: -1}, null, null),
1606
count = $.count,
1607
self = $.self,
1608
old = $.old,
1609
_new = $.$$new
1616
"' object cannot be interpreted as an integer")
1617
}else if(isinstance(count, _b_.float)){
1618
throw _b_.TypeError.$factory("integer argument expected, got float")
1619
}
1620
if(count == 0){return self}
1621
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1622
if(old == ""){
1623
if(_new == ""){return self}
1624
if(self == ""){return _new}
1625
var elts = self.split("")
1626
if(count > -1 && elts.length >= count){
1627
var rest = elts.slice(count).join("")
1628
return _new + elts.slice(0, count).join(_new) + rest
1629
}else{return _new + elts.join(_new) + _new}
1644
if(count < 0){count = res.length}
1645
while(count > 0){
1646
pos = res.indexOf(old, pos)
1647
if(pos < 0){break}
1648
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1649
pos = pos + _new.length
1650
count--
1656
// Return the highest index in the string where substring sub is found,
1657
// such that sub is contained within s[start:end]. Optional arguments
1659
if(arguments.length == 2 && typeof substr == "string"){
1660
return self.lastIndexOf(substr)
1661
}
1663
{self: null, sub: null, start: null, end: null},
1664
["self", "sub", "start", "end"],
1665
arguments, {start: 0, end: null}, null, null)
1677
for(var i = $.end - sublen; i >= $.start; i--){
1678
if($.self.substr(i, sublen) == $.sub){return i}
1685
var res = str.rfind.apply(null, arguments)
1686
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
1691
var $ = $B.args("rjust",3,
1692
{self: null, width: null, fillchar: null},
1693
["self", "width", "fillchar"],
1694
arguments, {fillchar: " "}, null, null)
1702
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1703
arguments, {}, null, null)
1707
var items = str.partition(self, sep).reverse()
1708
for(var i = 0; i < items.length; i++){
1709
items[i] = items[i].split("").reverse().join("")
1715
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1716
["self", "sep", "maxsplit"], arguments,
1717
{sep: _b_.None, maxsplit: -1}, null, null),
1718
sep = $.sep
1721
var rev_str = reverse($.self),
1722
rev_sep = sep === _b_.None ? sep : reverse($.sep),
1733
str.rstrip = function(self, x){
1734
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
1735
arguments, {chars: _b_.None}, null, null)
1736
if($.chars === _b_.None){return $.self.trimRight()}
1738
if($.chars.indexOf($.self.charAt(j)) == -1){
1739
return $.self.substring(0, j + 1)
1746
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1747
["self", "sep", "maxsplit"], arguments,
1748
{sep: _b_.None, maxsplit: -1}, null, null),
1749
sep = $.sep,
1750
maxsplit = $.maxsplit,
1751
self = $.self,
1752
pos = 0
1753
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1754
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1755
if(sep === _b_.None){
1757
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1758
if(pos === self.length - 1){return [self]}
1759
var name = ""
1761
if(self.charAt(pos).search(/\s/) == -1){
1762
if(name == ""){name = self.charAt(pos)}
1763
else{name += self.charAt(pos)}
1783
var res = [],
1784
s = "",
1785
seplen = sep.length
1786
if(maxsplit == 0){return [self]}
1787
while(pos < self.length){
1788
if(self.substr(pos, seplen) == sep){
1808
["self", "keepends"], arguments, {keepends: false}, null, null)
1809
if(! _b_.isinstance($.keepends, [_b_.bool, _b_.int])){
1810
throw _b_.TypeError.$factory("integer argument expected, got " +
1817
start = pos,
1818
pos = 0,
1819
self = $.self
1820
while(pos < self.length){
1821
if(self.substr(pos, 2) == "\r\n"){
1822
res.push(self.substring(start, pos + 2))
1823
start = pos + 2
1825
}else if(self.charAt(pos) == "\r" || self.charAt(pos) == "\n"){
1826
res.push(self.substring(start, pos + 1))
1827
start = pos + 1
1828
pos = start
1829
}else{pos++}
1830
}
1831
var rest = self.substr(start)
1832
if(rest){res.push(rest)}
1833
return res
1834
}else{
1841
// Return True if string starts with the prefix, otherwise return False.
1842
// prefix can also be a tuple of prefixes to look for. With optional
1843
// start, test string beginning at that position. With optional end,
1845
var $ = $B.args("startswith", 4,
1846
{self: null, prefix: null, start: null, end: null},
1847
["self", "prefix", "start", "end"],
1848
arguments, {start: 0, end: null}, null, null)
1855
var s = $.self.substring($.start, $.end)
1856
for(var i = 0, len = prefixes.length; i < len; i++){
1867
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1868
arguments, {chars: _b_.None}, null, null)
1869
if($.chars === _b_.None){return $.self.trim()}
1870
for(var i = 0; i < $.self.length; i++){
1871
if($.chars.indexOf($.self.charAt(i)) == -1){
1872
break
1875
for(var j = $.self.length - 1; j >= i; j--){
1876
if($.chars.indexOf($.self.charAt(j)) == -1){
1877
break
1883
str.swapcase = function(self){
1884
var $ = $B.args("swapcase", 1, {self}, ["self"],
1885
arguments, {}, null, null),
1886
res = "",
1887
char
1888
1889
for(var i = 0, len = self.length; i < len; i++){
1890
char = self.charCodeAt(i)
1891
if(unicode_tables.Ll[char]){
1892
res += self.charAt(i).toUpperCase()
1893
}else if(unicode_tables.Lu[char]){
1894
res += self.charAt(i).toLowerCase()
1895
}else{
1896
res += self.charAt(i)
1897
}
1898
}
1899
return res
1900
}
1901
1902
str.title = function(self){
1903
var $ = $B.args("title", 1, {self}, ["self"],
1904
arguments, {}, null, null),
1905
state,
1906
char,
1907
res = ""
1908
for(var i = 0, len = self.length; i < len; i++){
1909
char = self.charCodeAt(i)
1910
if(unicode_tables.Ll[char]){
1911
if(! state){
1912
res += self.charAt(i).toUpperCase()
1913
state = "word"
1914
}else{
1915
res += self.charAt(i)
1916
}
1917
}else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1918
res += state ? self.charAt(i).toLowerCase() : self.charAt(i)
1919
state = "word"
1920
}else{
1921
state = null
1922
res += self.charAt(i)
1923
}
1924
}
1925
return res
1926
}
1927
1930
getitem = $B.$getattr(table, "__getitem__")
1931
for(var i = 0, len = self.length; i < len; i++){
1932
try{
1933
var repl = getitem(self.charCodeAt(i))
1934
if(repl !== _b_.None){
1944
str.upper = function(self){
1945
var $ = $B.args("upper", 1, {self: null}, ["self"],
1946
arguments, {}, null, null)
1947
return self.toUpperCase()
1948
}
1949
1952
["self", "width"], arguments, {}, null, null)
1953
if($.width <= self.length){return self}
1955
case "+":
1956
case "-":
1957
return self.charAt(0) +
1958
"0".repeat($.width - self.length) + self.substr(1)
1966
if(arg === undefined){
1967
throw _b_.TypeError.$factory("str() argument is undefined")
1968
}
1979
// class or its subclasses, but the attribute __str__ of the
1980
// class metaclass (usually "type") or its subclasses (usually
1981
// "object")
1982
// The metaclass is the attribute __class__ of the class dictionary
1986
if(arg.__class__ && arg.__class__ === _b_.bytes &&
1987
encoding !== undefined){
1988
// str(bytes, encoding, errors) is equal to
1989
// bytes.decode(encoding, errors)
1990
// Arguments may be passed as keywords (cf. issue #1060)
1991
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
1992
["arg", "encoding", "errors"], arguments,
1993
{encoding: "utf-8", errors: "strict"}, null, null)
1994
return _b_.bytes.decode(arg, $.encoding, $.errors)
1996
// Implicit invocation of __str__ uses method __str__ on the class,
1997
// even if arg has an attribute __str__
1998
var klass = arg.__class__ || $B.get_class(arg)
1999
var method = $B.$getattr(klass , "__str__", null)
2000
if(method === null ||
2001
// if not better than object.__str__, try __repr__
2002
(arg.__class__ && arg.__class__ !== _b_.object &&
2003
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2004
var method = $B.$getattr(klass, "__repr__")
2010
if($B.debug > 1){console.log(err)}
2011
console.log("Warning - no method __str__ or __repr__, " +
2012
"default to toString", arg)
2019
if(cls === undefined){
2020
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
2044
var args = [],
2045
pos = 0
2046
if(arguments.length > 0){
2047
var args = [arguments[0].valueOf()],
2048
pos = 1
2049
for(var i = 1, len = arguments.length; i < len; i++){
2050
args[pos++] = arguments[i]
2066
// Function to parse the 2nd argument of format()
2067
$B.parse_format_spec = function(spec){
2070
var pos = 0,
2071
aligns = "<>=^",
2072
digits = "0123456789",
2073
types = "bcdeEfFgGnosxX%",
2075
if(align_pos != -1){
2076
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2077
// If the second char is also an alignment specifier, the
2078
// first char is the fill value
2079
this.fill = spec.charAt(0)
2080
this.align = spec.charAt(1)
2081
pos = 2
2082
}else{
2083
// The first character defines alignment : fill defaults to ' '
2098
if(car == "+" || car == "-" || car == " "){
2099
this.sign = car
2100
pos++
2101
car = spec.charAt(pos)
2103
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
2104
if(car == "0"){
2113
while(car && digits.indexOf(car) > -1){
2114
if(this.width === undefined){this.width = car}
2115
else{this.width += car}
2116
pos++
2117
car = spec.charAt(pos)
2120
if(this.width === undefined && car == "{"){
2121
// Width is determined by a parameter
2122
var end_param_pos = spec.substr(pos).search("}")
2123
this.width = spec.substring(pos, end_param_pos)
2124
console.log("width", "[" + this.width + "]")
2125
pos += end_param_pos + 1
2126
}
2127
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
2128
if(car == "."){
2129
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2130
throw _b_.ValueError.$factory(
2131
"Missing precision in format spec")
2133
this.precision = spec.charAt(pos + 1)
2134
pos += 2
2135
car = spec.charAt(pos)
2136
while(car && digits.indexOf(car) > -1){
2143
if(car && types.indexOf(car) > -1){
2144
this.type = car
2145
pos++
2146
car = spec.charAt(pos)
2147
}
2148
if(pos !== spec.length){
2154
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2155
(this.align || "") +
2156
(this.sign || "") +
2157
(this.alternate ? "#" : "") +
2158
(this.sign_aware ? "0" : "") +
2159
(this.width || "") +
2160
(this.comma ? "," : "") +
2161
(this.precision ? "." + this.precision : "") +
2162
(this.type || "")
2167
if(fmt.width && s.length < fmt.width){
2168
var fill = fmt.fill || " ",
2169
align = fmt.align || "<",
2170
missing = fmt.width - s.length
2172
case "<":
2173
return s + fill.repeat(missing)
2174
case ">":
2175
return fill.repeat(missing) + s
2176
case "=":
2177
if("+-".indexOf(s.charAt(0)) > -1){
2178
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2182
case "^":
2183
var left = parseInt(missing / 2)
2184
return fill.repeat(left) + s + fill.repeat(missing - left)
2197
$B.parse_fstring = function(string){
2198
// Parse a f-string
2199
var elts = [],
2200
pos = 0,
2224
}else{
2225
throw Error(" f-string: single '}' is not allowed")
2226
}
2227
}else{
2249
current += car
2250
i += 2
2251
}else{
2252
throw Error(" f-string: single '}' is not allowed")
2253
}
2254
}else{
2255
current += car
2256
i++
2257
}
2258
}
2260
}else if(ctype == "debug"){
2261
// after the equal sign, whitespace are ignored and the only
2262
// valid characters are } and :
2263
while(string.charAt(i) == " "){i++}
2264
if(string.charAt(i) == "}"){
2265
// end of debug expression
2266
elts.push(current)
2267
ctype = null
2268
current = ""
2269
pos = i + 1
2270
}
2271
}else{
2272
// End of expression is the } matching the opening {
2273
// There may be nested braces
2274
var i = pos,
2275
nb_braces = 1,
2297
// backslash is not allowed in expressions
2298
throw Error("f-string expression part cannot include a" +
2299
" backslash")
2306
throw Error("f-string: invalid conversion character:" +
2307
" expected 's', 'r', or 'a'")
2308
}else{
2322
if(string.substr(i, 3) == '"""'){
2323
var end = string.indexOf('"""', i + 3)
2324
if(end == -1){
2325
throw Error("f-string: unterminated string")
2326
}else{
2327
var trs = string.substring(i, end + 3)
2328
trs = trs.replace("\n", "\\n\\")
2333
var end = string.indexOf('"', i + 1)
2334
if(end == -1){
2335
throw Error("f-string: unterminated string")
2336
}else{
2337
current.expression += string.substring(i, end + 1)
2338
i = end + 1
2345
}else if(car == "="){
2346
// might be a "debug expression", eg f"{x=}"
2347
var ce = current.expression
2348
if(ce.length == 0 ||
2350
current.expression += car
2351
i++
2352
}else{
2353
// add debug string
2354
tail = car
2355
while(string.charAt(i + 1).match(/\s/)){
2356
tail += string.charAt(i + 1)
2357
i++
2358
}
2359
elts.push(current.expression + tail)
2360
// remove trailing whitespace from expression
2361
while(ce.match(/\s$/)){
2362
ce = ce.substr(0, ce.length - 1)
2363
}
2364
current.expression = ce
2365
ctype = "debug"
2366
i++
2367
}