Permalink
Mar 6, 2021
Aug 7, 2021
Mar 19, 2018
Apr 5, 2021
Mar 6, 2021
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 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
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
Dec 18, 2019
Dec 18, 2019
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
Nov 8, 2021
Mar 6, 2021
Mar 19, 2018
Mar 16, 2021
Mar 16, 2021
Mar 19, 2018
Mar 27, 2019
Mar 6, 2021
Mar 19, 2018
Mar 6, 2021
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 19, 2018
Apr 2, 2019
Apr 2, 2019
Mar 19, 2018
Aug 31, 2017
Mar 19, 2018
Mar 6, 2021
Mar 19, 2018
Mar 6, 2021
Aug 31, 2017
Apr 16, 2019
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Nov 12, 2018
Nov 22, 2020
Nov 12, 2018
Mar 19, 2018
Nov 22, 2020
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Sep 27, 2020
Sep 27, 2020
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 19, 2018
Mar 6, 2021
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 6, 2021
Jun 11, 2020
Mar 19, 2018
Mar 19, 2018
Apr 5, 2021
Mar 6, 2021
Mar 6, 2021
Mar 19, 2018
Mar 19, 2018
Aug 31, 2017
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Feb 27, 2020
Feb 27, 2020
Feb 27, 2020
Aug 31, 2017
Mar 19, 2018
Mar 6, 2021
Mar 19, 2018
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Mar 6, 2021
Jan 26, 2020
Mar 6, 2021
Nov 15, 2019
Jul 28, 2018
Oct 27, 2019
Nov 2, 2018
Nov 2, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 6, 2021
Nov 12, 2018
Mar 6, 2021
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Mar 19, 2018
Dec 12, 2020
Jun 29, 2017
Oct 13, 2019
Jun 29, 2017
Dec 12, 2020
Jul 10, 2017
Jul 10, 2017
Mar 19, 2018
Mar 19, 2018
Jun 20, 2020
Oct 13, 2019
Oct 13, 2019
Jul 31, 2021
Jan 18, 2021
Jan 18, 2021
Newer
100644
2935 lines (2722 sloc)
88.6 KB
8
9
$B.has_surrogate = function(s){
10
// Check if there are "surrogate pairs" characters in string s
11
for(var i = 0; i < s.length; i++){
12
code = s.charCodeAt(i)
13
if(code >= 0xD800 && code <= 0xDBFF){
14
return true
15
}
16
}
17
return false
18
}
19
24
for(var i = 0, len = s.length; i < len; i++){
25
var cp = s.codePointAt(i)
26
if(cp >= 0x10000){
35
var res = new String(s)
36
res.__class__ = str
37
res.surrogates = surrogates
38
return res
39
}
40
41
function pypos2jspos(s, pypos){
42
// convert Python position to JS position
43
if(s.surrogates === undefined){
44
return pypos
45
}
46
var nb = 0
47
while(s.surrogates[nb] < pypos){
48
nb++
49
}
50
return pypos + nb
53
function jspos2pypos(s, jspos){
54
// convert JS position to Python position
55
if(s.surrogates === undefined){
56
return jspos
57
}
58
var nb = 0
59
while(s.surrogates[nb] + nb < jspos){
60
nb++
61
}
62
return jspos - nb
63
}
64
82
}
83
if($.start === null || $.start === _b_.None){
84
$.start = 0
85
}else if($.start < 0){
86
$.start += len
89
if($.end === null || $.end === _b_.None){
90
$.end = len
91
}else if($.end < 0){
92
$.end += len
97
throw _b_.TypeError.$factory("slice indices must be integers " +
98
"or None or have an __index__ method")
99
}
100
if($.self.surrogates){
101
$.js_start = pypos2jspos($.self, $.start)
102
$.js_end = pypos2jspos($.self, $.end)
103
}
116
throw _b_.TypeError.$factory((prefix || '') +
117
"must be str, not " + $B.class_name(obj))
121
function to_chars(s){
122
// Transform Javascript string s into a list of Python characters
123
// (2 JS chars if surrogate, 1 otherwise)
124
var chars = []
125
for(var i = 0, len = s.length; i < len; i++){
126
var code = s.charCodeAt(i)
127
if(code >= 0xD800 && code <= 0xDBFF){
128
chars.push(s.substr(i, 2))
129
i++
130
}else{
131
chars.push(s.charAt(i))
132
}
133
}
134
return chars
135
}
136
137
function to_codepoints(s){
138
// Transform Javascript string s into a list of codepoints
142
var cps = []
143
for(var i = 0, len = s.length; i < len; i++){
144
var code = s.charCodeAt(i)
145
if(code >= 0xD800 && code <= 0xDBFF){
146
var v = 0x10000
147
v += (code & 0x03FF) << 10
148
v += (s.charCodeAt(i + 1) & 0x03FF)
149
cps.push(v)
150
i++
151
}else{
152
cps.push(code)
153
}
154
}
159
if(! _b_.isinstance(other, str)){
160
try{
161
return $B.$getattr(other, "__radd__")(self)
162
}catch(err){
171
throw _b_.TypeError.$factory("'in <string>' requires " +
172
"string as left operand, not " + item.__class__)
173
}
199
// __dir__must be assigned explicitely because attribute resolution for
200
// builtin classes doesn't use __mro__
214
if(fmt.type && fmt.type != "s"){
215
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
223
if(fmt.sign !== undefined){
224
throw _b_.ValueError.$factory(
225
"Sign not allowed in string format specifier")
242
if(pos >= 0 && pos < len){
243
var jspos = pypos2jspos(self, pos)
244
if(self.codePointAt(jspos) >= 0x10000){
245
return $B.String(self.substr(jspos, 2))
246
}else{
253
var s = _b_.slice.$conv_for_seq(arg, len),
254
start = pypos2jspos(self, s.start),
255
stop = pypos2jspos(self, s.stop),
318
try{
319
return str_hash_cache[self] = fnv(to_codepoints(self))
320
}catch(err){
321
console.log('error hash, cps', self, to_codepoints(self))
322
throw err
323
}
341
if(self.len !== undefined){
342
return self.len
343
}
344
var len = self.len = self.valueOf().length - self.surrogates.length
345
return len
382
// left adjusted
383
return s + get_char_array(padding - s.length, flags.pad_char)
384
}
385
}
386
394
if(val.__class__ === $B.long_int){
395
s = $B.long_int.to_base(val, 10)
396
}else{
397
s = val.toString()
399
if(s[0] === "-"){
400
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
411
if(val === Infinity){
412
val = "inf"
413
}else if(val === -Infinity){
414
val = "-inf"
415
}else{
416
val = "nan"
438
var str_format = function(val, flags) {
439
// string format supports left and right padding
440
flags.pad_char = " " // even if 0 padding is defined, don't use it
446
if(val.__class__ === $B.long_int){
447
val = $B.long_int.to_base(val, 10)
448
}else{
449
val = parseInt(val)
467
var repr_format = function(val, flags) {
468
flags.pad_char = " " // even if 0 padding is defined, don't use it
472
var ascii_format = function(val, flags) {
473
flags.pad_char = " " // even if 0 padding is defined, don't use it
487
flags.precision = parseInt(flags.precision, 10)
488
validate_precision(flags.precision)
489
}
490
return parseFloat(val)
491
}
494
var trailing_zeros = /(.*?)(0+)([eE].*)/,
495
leading_zeros = /\.(0*)/,
496
trailing_dot = /\.$/
498
var validate_precision = function(precision) {
499
// force precision to limits of javascript
504
var floating_point_format = function(val, upper, flags){
505
val = _float_helper(val, flags),
506
v = val.toString(),
507
v_len = v.length,
508
dot_idx = v.indexOf('.')
509
if(dot_idx < 0){dot_idx = v_len}
510
if(val < 1 && val > -1){
511
var zeros = leading_zeros.exec(v),
512
numzeros
513
if(zeros){
518
if(numzeros >= 4){
519
val = format_sign(val, flags) + format_float_precision(val, upper,
520
flags, _floating_g_exp_helper)
521
if(!flags.alternate){
534
return format_padding(format_sign(val, flags) +
535
format_float_precision(val, upper, flags,
536
function(val, precision) {
538
numzeros)
539
}),
540
flags
541
)
542
}
543
544
if(dot_idx > flags.precision){
545
val = format_sign(val, flags) + format_float_precision(val, upper,
546
flags, _floating_g_exp_helper)
547
if(! flags.alternate){
559
return format_padding(format_sign(val, flags) +
560
format_float_precision(val, upper, flags,
561
function(val, precision) {
562
if(!flags.decimal_point){
564
}else if (precision > v_len){
565
if(! flags.alternate){
566
precision = v_len
567
}
569
if(precision < dot_idx){
570
precision = dot_idx
571
}
572
return val.toFixed(precision - dot_idx)
573
}),
574
flags
575
)
578
var _floating_g_exp_helper = function(val, precision, flags, upper){
579
if(precision){--precision}
582
var e_idx = val.lastIndexOf("e")
583
if(e_idx > val.length - 4){
584
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
587
return val
588
}
589
590
// fF
591
var floating_point_decimal_format = function(val, upper, flags) {
592
val = _float_helper(val, flags)
593
return format_padding(format_sign(val, flags) +
594
format_float_precision(val, upper, flags,
595
function(val, precision, flags) {
596
val = val.toFixed(precision)
597
if(precision === 0 && flags.alternate){
598
val += '.'
599
}
600
return val
601
}),
602
flags
603
)
604
}
605
606
var _floating_exp_helper = function(val, precision, flags, upper) {
607
val = val.toExponential(precision)
608
// pad exponent to two digits
621
return format_padding(format_sign(val, flags) +
622
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
648
if(flags.alternate){
649
if(ret.charAt(0) === "-"){
650
if(upper){ret = "-0X" + ret.slice(1)}
651
else{ret = "-0x" + ret.slice(1)}
652
}else{
653
if(upper){ret = "0X" + ret}
654
else{ret = "0x" + ret}
664
if(val.__class__ === $B.long_int){
665
ret = $B.long_int.to_base(8)
666
}else{
667
ret = parseInt(val)
668
ret = ret.toString(8)
684
if(flags.alternate){
685
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
686
else{ret = "0o" + ret}
691
function series_of_bytes(val, flags){
692
if(val.__class__ && val.__class__.$buffer_protocol){
693
var it = _b_.iter(val),
694
ints = []
695
while(true){
696
try{
697
ints.push(_b_.next(it))
698
}catch(err){
699
if(err.__class__ === _b_.StopIteration){
700
var b = _b_.bytes.$factory(ints)
701
return format_padding(_b_.bytes.decode(b, "ascii"), flags)
702
}
703
throw err
704
}
705
}
706
}else{
707
try{
708
bytes_obj = $B.$getattr(val, "__bytes__")
709
return format_padding(_b_.bytes.decode(bytes_obj), flags)
710
}catch(err){
711
if(err.__class__ === _b_.AttributeError){
712
throw _b_.TypeError.$factory("%b does not accept '" +
713
$B.class_name(val) + "'")
714
}
715
throw err
716
}
717
}
718
}
719
724
val = val.source[0]
725
}else{
726
try{
727
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
728
}catch (err){
729
throw _b_.TypeError.$factory("%c requires int or char")
730
}
735
var num_flag = function(c, flags){
736
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
737
flags.pad_char = "0"
743
flags.precision = (flags.precision || "") + c
744
}
745
}
746
747
var decimal_point_flag = function(val, flags) {
749
// can only have one decimal point
750
throw new UnsupportedChar()
751
}
752
flags.decimal_point = true
753
}
754
755
var neg_flag = function(val, flags){
756
flags.pad_char = " " // overrides '0' flag
774
"s": str_format,
775
"d": num_format,
776
"i": num_format,
777
"u": num_format,
778
"o": octal_format,
779
"r": repr_format,
780
"a": ascii_format,
781
"g": function(val, flags){
782
return floating_point_format(val, false, flags)
783
},
784
"G": function(val, flags){return floating_point_format(val, true, flags)},
785
"f": function(val, flags){
786
return floating_point_decimal_format(val, false, flags)
787
},
788
"F": function(val, flags){
789
return floating_point_decimal_format(val, true, flags)
790
},
791
"e": function(val, flags){
792
return floating_point_exponential_format(val, false, flags)
793
},
794
"E": function(val, flags){
795
return floating_point_exponential_format(val, true, flags)
796
},
797
"x": function(val, flags){return signed_hex_format(val, false, flags)},
798
"X": function(val, flags){return signed_hex_format(val, true, flags)},
799
"c": single_char_format,
800
"0": function(val, flags){return num_flag("0", flags)},
801
"1": function(val, flags){return num_flag("1", flags)},
802
"2": function(val, flags){return num_flag("2", flags)},
803
"3": function(val, flags){return num_flag("3", flags)},
804
"4": function(val, flags){return num_flag("4", flags)},
805
"5": function(val, flags){return num_flag("5", flags)},
806
"6": function(val, flags){return num_flag("6", flags)},
807
"7": function(val, flags){return num_flag("7", flags)},
808
"8": function(val, flags){return num_flag("8", flags)},
809
"9": function(val, flags){return num_flag("9", flags)},
810
"-": neg_flag,
811
" ": space_flag,
812
"+": sign_flag,
813
".": decimal_point_flag,
814
"#": alternate_flag
815
}
816
817
// exception thrown when an unsupported char is encountered in legacy format
863
if(self === undefined){
864
throw _b_.TypeError.$factory(
865
"not enough arguments for format string")
892
throw _b_.ValueError.$factory(
893
"unsupported format character '" + invalid_char +
894
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
895
") at index " + newpos)
896
}else if(err.name === "NotANumber"){
897
var try_char = s[newpos],
898
cls = self.__class__
899
if(!cls){
900
if(typeof(self) === "string"){
901
cls = "str"
902
}else{
908
throw _b_.TypeError.$factory("%" + try_char +
909
" format: a number is required, not " + cls)
910
}else{
942
}while(pos < length)
943
944
if(argpos !== null){
945
if(args.length > argpos){
946
throw _b_.TypeError.$factory(
947
"not enough arguments for format string")
948
}else if(args.length < argpos){
949
throw _b_.TypeError.$factory(
950
"not all arguments converted during string formatting")
952
}else if(nbph == 0){
953
throw _b_.TypeError.$factory(
954
"not all arguments converted during string formatting")
962
var $ = $B.args("__mul__", 2, {self: null, other: null},
963
["self", "other"], arguments, {}, null, null)
967
$B.class_name($.other) + "'")
968
}
969
return $.self.valueOf().repeat($.other < 0 ? 0 : $.other)
976
function __newobj__(){
977
// __newobj__ is called with a generator as only argument
978
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
979
args = $.args
980
var res = args[1]
981
res.__class__ = args[0]
982
return res
983
}
984
985
str.__reduce_ex__ = function(self){
986
return $B.fast_tuple([
987
__newobj__,
988
$B.fast_tuple([self.__class__ || _b_.str, self]),
989
_b_.None,
990
_b_.None])
991
}
992
997
chars = to_chars(self)
998
for(var i = 0; i < chars.length; i++){
999
var cp = _b_.ord(chars[i])
1000
if(t[cp] !== undefined){
1001
repl += t[cp]
1002
}else if($B.is_unicode_cn(cp)){
1015
repl += "\u200B" + chars[i] + ' '
1016
}else if(cp.toString(16) == 'feff'){
1017
repl += '\\ufeff'
1023
if(res.search('"') == -1 && res.search("'") == -1){
1024
return "'" + res + "'"
1025
}else if(self.search('"') == -1){
1026
return '"' + res + '"'
1027
}
1028
var qesc = new RegExp("'", "g") // to escape single quote
1029
res = "'" + res.replace(qesc, "\\'") + "'"
1033
str.__rmul__ = function(self, other){
1034
if(_b_.isinstance(other, _b_.int)){
1035
other = _b_.int.numerator(other)
1036
var res = ''
1037
while(other > 0){
1038
res += self
1039
other--
1040
}
1041
return res
1042
}
1043
return _b_.NotImplemented
1044
}
1045
1046
str.__setattr__ = function(self, attr, value){
1047
if(typeof self === "string"){
1048
if(str.hasOwnProperty(attr)){
1050
attr + "' is read-only")
1051
}else{
1052
throw _b_.AttributeError.$factory(
1053
"'str' object has no attribute '" + attr + "'")
1054
}
1055
}
1056
// str subclass : use __dict__
1057
_b_.dict.$setitem(self.__dict__, attr, value)
1058
return $N
1059
}
1060
1061
str.__setitem__ = function(self, attr, value){
1062
throw _b_.TypeError.$factory(
1063
"'str' object does not support item assignment")
1066
var combining = []
1067
for(var cp = 0x300; cp <= 0x36F; cp++){
1068
combining.push(String.fromCharCode(cp))
1069
}
1073
var repl = '',
1074
chars = to_chars(self)
1075
if(chars.length == self.length){
1076
return self.replace(combining_re, "\u200B$1")
1077
}
1078
for(var i = 0; i < chars.length; i++){
1079
var cp = _b_.ord(chars[i])
1080
if(cp >= 0x300 && cp <= 0x36F){
1081
repl += "\u200B" + chars[i]
1082
}else{
1083
repl += chars[i]
1084
}
1085
}
1086
return repl
1096
$comp_func += "" // source code
1097
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
1108
str.capitalize = function(self){
1109
var $ = $B.args("capitalize", 1, {self}, ["self"],
1110
arguments, {}, null, null)
1114
return self.charAt(0).toUpperCase() + self.substr(1)
1115
}
1116
1117
str.casefold = function(self){
1118
var $ = $B.args("casefold", 1, {self}, ["self"],
1119
arguments, {}, null, null),
1120
res = "",
1121
char,
1122
cf,
1123
chars = to_chars($.self)
1124
1125
for(var i = 0, len = chars.length; i < len; i++){
1126
char = chars[i]
1127
cf = $B.unicode_casefold[char]
1128
if(cf){
1129
cf.forEach(function(cp){
1130
res += String.fromCharCode(cp)
1131
})
1132
}else{
1139
str.center = function(){
1140
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
1141
["self", "width", "fillchar"],
1142
arguments, {fillchar:" "}, null, null),
1143
self = $.self
1147
var pad = parseInt(($.width - self.length) / 2),
1148
res = $.fillchar.repeat(pad)
1157
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
1158
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
1161
throw _b_.TypeError.$factory("Can't convert '" + $B.class_name($.sub) +
1162
"' object to str implicitly")
1163
}
1167
if($.stop !== null){
1168
_slice = _b_.slice.$factory($.start, $.stop)
1169
}else{
1170
_slice = _b_.slice.$factory($.start, $.self.length)
1171
}
1179
if($.start == $.self.length){
1180
return 1
1181
}else if(substr.length == 0){
1182
return 0
1183
}
1186
var n = 0,
1187
pos = 0
1188
while(pos < substr.length){
1189
pos = substr.indexOf($.sub, pos)
1200
str.encode = function(){
1201
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
1202
["self", "encoding", "errors"], arguments,
1203
{encoding: "utf-8", errors: "strict"}, null, null)
1204
if($.encoding == "rot13" || $.encoding == "rot_13"){
1207
for(var i = 0, len = $.self.length; i < len ; i++){
1208
var char = $.self.charAt(i)
1209
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
1210
res += String.fromCharCode(String.charCodeAt(char) + 13)
1211
}else if(("m" < char && char <= "z") ||
1212
("M" < char && char <= "Z")){
1213
res += String.fromCharCode(String.charCodeAt(char) - 13)
1222
// Return True if the string ends with the specified suffix, otherwise
1223
// return False. suffix can also be a tuple of suffixes to look for.
1224
// With optional start, test beginning at that position. With optional
1228
["self", "suffix", "start", "end"],
1229
arguments, {start: 0, end: null}, null, null)
1242
if(! _b_.isinstance(suffix, str)){
1243
throw _b_.TypeError.$factory(
1244
"endswith first arg must be str or a tuple of str, not int")
1245
}
1255
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1256
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1257
var s = $B.$GetInt($.tabsize),
1258
col = 0,
1259
pos = 0,
1260
res = "",
1261
chars = to_chars(self)
1262
if(s == 1){
1263
return self.replace(/\t/g," ")
1264
}
1265
while(pos < chars.length){
1266
var car = chars[pos]
1276
res += car
1277
col = 0
1278
break
1279
default:
1280
res += car
1281
col++
1282
break
1283
}
1284
pos++
1285
}
1286
return res
1290
// Return the lowest index in the string where substring sub is found,
1291
// such that sub is contained in the slice s[start:end]. Optional
1292
// arguments start and end are interpreted as in slice notation.
1295
{self: null, sub: null, start: null, end: null},
1296
["self", "sub", "start", "end"],
1297
arguments, {start: 0, end: null}, null, null)
1310
// Use .indexOf(), not .search(), to avoid conversion to reg exp
1311
var js_start = pypos2jspos($.self, $.start),
1312
js_end = pypos2jspos($.self, $.end),
1313
ix = $.self.substring(js_start, js_end).indexOf($.sub)
1314
if(ix == -1){
1315
return -1
1326
// a.x[z]!r:...
1327
// the object has attributes :
1328
// - name : "a"
1329
// - name_ext : [".x", "[z]"]
1330
// - conv : r
1331
// - spec : rest of string after :
1339
// No : in the string : it only contains a name
1340
name = fmt_string
1341
}else{
1342
// name is before the first ":"
1343
// spec (the format specification) is after
1344
name = elts[0]
1348
var elts = name.split("!")
1349
if(elts.length > 1){
1350
name = elts[0]
1351
conv = elts[1] // conversion flag
1355
// "name' may be a subscription or attribute
1356
// Put these "extensions" in the list "name_ext"
1357
function name_repl(match){
1358
name_ext.push(match)
1360
}
1361
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1362
name = name.replace(name_ext_re, name_repl)
1363
}
1370
// Parse self to detect formatting instructions
1371
// Create a list "parts" made of sections of the string :
1372
// - elements of even rank are literal text
1373
// - elements of odd rank are "format objects", built from the
1374
// format strings in self (of the form {...})
1385
text += "{"
1386
pos += 2
1387
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1394
// Store current literal text
1395
parts.push(text)
1396
1397
// Search the end of the format string, ie the } closing the
1398
// opening {. Since the string can contain other pairs {} for
1399
// nested formatting, an integer nb is incremented for each { and
1400
// decremented for each } ; the end of the format string is
1401
// reached when nb == 0
1402
var end = pos + 1,
1403
nb = 1
1404
while(end < _len){
1405
if(self.charAt(end) == "{"){nb++; end++}
1406
else if(self.charAt(end) == "}"){
1407
nb--; end++
1408
if(nb == 0){
1413
var fmt_obj = $B.parse_format(fmt_string)
1414
fmt_obj.raw_name = fmt_obj.name
1415
fmt_obj.raw_spec = fmt_obj.spec
1449
}else{
1450
text += car
1451
pos++
1452
}
1453
}
1454
if(text){
1455
parts.push(text)
1461
// Special management of keyword arguments if str.format is called by
1462
// str.format_map(mapping) : the argument "mapping" might not be a
1463
// dictionary
1464
var last_arg = $B.last(arguments)
1465
if(last_arg.$nat == "mapping"){
1466
var mapping = last_arg.mapping,
1467
getitem = $B.$getattr(mapping, "__getitem__")
1468
// Get the rest of the arguments
1469
var args = []
1470
for(var i = 0, len = arguments.length - 1; i < len; i++){
1471
args.push(arguments[i])
1472
}
1473
var $ = $B.args("format", 1, {self: null}, ["self"],
1474
args, {}, "$args", null)
1475
}else{
1476
var $ = $B.args("format", 1, {self: null}, ["self"],
1477
arguments, {}, "$args", "$kw"),
1478
mapping = $.$kw, // dictionary
1479
getitem = function(key){
1480
return _b_.dict.$getitem(mapping, key)
1481
}
1482
}
1498
1499
if(fmt.spec !== undefined){
1500
// "spec" may contain "nested replacement fields"
1501
// In this case, evaluate them using the positional
1502
// or keyword arguments passed to format()
1503
function replace_nested(name, key){
1504
if(/\d+/.exec(key)){
1505
// If key is numeric, search in positional
1506
// arguments
1507
return _b_.tuple.__getitem__($.$args,
1508
parseInt(key))
1509
}else{
1510
// Else try in keyword arguments
1511
return _b_.dict.__getitem__($.$kw, key)
1512
}
1513
}
1514
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1515
replace_nested)
1516
}
1518
// Numerical reference : use positional arguments
1519
var pos = parseInt(fmt.name),
1540
// If the conversion flag is set, first call a function to convert
1541
// the value
1542
if(fmt.conv == "a"){value = _b_.ascii(value)}
1543
else if(fmt.conv == "r"){value = _b_.repr(value)}
1544
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1557
str.format_map = function(self, mapping){
1558
var $ = $B.args("format_map", 2, {self: null, mapping: null},
1559
['self', 'mapping'], arguments, {}, null, null)
1560
return str.format(self, {$nat: 'mapping', mapping})
1573
/* Return true if the string is empty or all characters in the string are
1574
ASCII, false otherwise. ASCII characters have code points in the range
1575
U+0000-U+007F. */
1584
str.isalnum = function(self){
1585
/* Return true if all characters in the string are alphanumeric and there
1586
is at least one character, false otherwise. A character c is alphanumeric
1587
if one of the following returns True: c.isalpha(), c.isdecimal(),
1588
c.isdigit(), or c.isnumeric(). */
1589
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1590
arguments, {}, null, null),
1591
cp
1592
for(var char of to_chars(self)){
1593
cp = _b_.ord(char)
1594
if(unicode_tables.Ll[cp] ||
1595
unicode_tables.Lu[cp] ||
1596
unicode_tables.Lm[cp] ||
1597
unicode_tables.Lt[cp] ||
1598
unicode_tables.Lo[cp] ||
1599
unicode_tables.Nd[cp] ||
1600
unicode_tables.digits[cp] ||
1601
unicode_tables.numeric[cp]){
1602
continue
1603
}
1604
return false
1605
}
1606
return true
1607
}
1608
1609
str.isalpha = function(self){
1610
/* Return true if all characters in the string are alphabetic and there is
1611
at least one character, false otherwise. Alphabetic characters are those
1612
characters defined in the Unicode character database as "Letter", i.e.,
1613
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1614
or "Lo". */
1615
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1616
arguments, {}, null, null),
1617
cp
1618
for(var char of to_chars(self)){
1619
cp = _b_.ord(char)
1620
if(unicode_tables.Ll[cp] ||
1621
unicode_tables.Lu[cp] ||
1622
unicode_tables.Lm[cp] ||
1623
unicode_tables.Lt[cp] ||
1624
unicode_tables.Lo[cp]){
1625
continue
1626
}
1627
return false
1628
}
1629
return true
1630
}
1631
1632
str.isdecimal = function(self){
1633
/* Return true if all characters in the string are decimal characters and
1634
there is at least one character, false otherwise. Decimal characters are
1635
those that can be used to form numbers in base 10, e.g. U+0660,
1636
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1637
the Unicode General Category "Nd". */
1638
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1639
arguments, {}, null, null),
1640
cp
1641
for(var char of to_chars(self)){
1642
cp = _b_.ord(char)
1643
if(! unicode_tables.Nd[cp]){
1644
return false
1645
}
1646
}
1647
return self.length > 0
1648
}
1649
1650
str.isdigit = function(self){
1651
/* Return true if all characters in the string are digits and there is at
1652
least one character, false otherwise. */
1653
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1654
arguments, {}, null, null),
1655
cp
1656
for(var char of to_chars(self)){
1657
cp = _b_.ord(char)
1658
if(! unicode_tables.digits[cp]){
1659
return false
1660
}
1661
}
1662
return self.length > 0
1663
}
1664
1665
str.isidentifier = function(self){
1666
/* Return true if the string is a valid identifier according to the
1667
language definition. */
1668
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1672
}
1673
var chars = to_chars(self)
1674
if(unicode_tables.XID_Start[_b_.ord(chars[0])] === undefined){
1677
for(var char of chars){
1678
var cp = _b_.ord(char)
1679
if(unicode_tables.XID_Continue[cp] === undefined){
1680
return false
1681
}
1682
}
1683
}
1684
return true
1685
}
1686
1687
str.islower = function(self){
1688
/* Return true if all cased characters 4 in the string are lowercase and
1689
there is at least one cased character, false otherwise. */
1690
var $ = $B.args("islower", 1, {self: null}, ["self"],
1691
arguments, {}, null, null),
1692
has_cased = false,
1695
for(var char of to_chars(self)){
1696
cp = _b_.ord(char)
1697
if(unicode_tables.Ll[cp]){
1698
has_cased = true
1699
continue
1700
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
1701
return false
1702
}
1703
}
1704
return has_cased
1705
}
1706
1707
str.isnumeric = function(self){
1708
/* Return true if all characters in the string are numeric characters, and
1709
there is at least one character, false otherwise. Numeric characters
1710
include digit characters, and all characters that have the Unicode numeric
1711
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1712
characters are those with the property value Numeric_Type=Digit,
1713
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1714
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1715
arguments, {}, null, null)
1724
var unprintable = {},
1725
unprintable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1726
1727
str.isprintable = function(self){
1728
/* Return true if all characters in the string are printable or the string
1729
is empty, false otherwise. Nonprintable characters are those characters
1730
defined in the Unicode character database as "Other" or "Separator",
1731
excepting the ASCII space (0x20) which is considered printable. */
1732
1733
// Set unprintable if not set yet
1734
if(Object.keys(unprintable).length == 0){
1735
for(var i = 0; i < unprintable_gc.length; i++){
1736
var table = unicode_tables[unprintable_gc[i]]
1747
return false
1748
}
1749
}
1750
return true
1751
}
1752
1753
str.isspace = function(self){
1754
/* Return true if there are only whitespace characters in the string and
1755
there is at least one character, false otherwise.
1756
1757
A character is whitespace if in the Unicode character database, either its
1758
general category is Zs ("Separator, space"), or its bidirectional class is
1759
one of WS, B, or S.*/
1760
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1761
arguments, {}, null, null),
1762
cp
1763
for(var char of to_chars(self)){
1764
cp = _b_.ord(char)
1765
if(! unicode_tables.Zs[cp] &&
1766
$B.unicode_bidi_whitespace.indexOf(cp) == -1){
1767
return false
1768
}
1769
}
1770
return self.length > 0
1771
}
1772
1773
str.istitle = function(self){
1774
/* Return true if the string is a titlecased string and there is at least
1775
one character, for example uppercase characters may only follow uncased
1776
characters and lowercase characters only cased ones. Return false
1777
otherwise. */
1778
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1779
arguments, {}, null, null)
1780
return self.length > 0 && str.title(self) == self
1781
}
1782
1783
str.isupper = function(self){
1784
/* Return true if all cased characters 4 in the string are lowercase and
1785
there is at least one cased character, false otherwise. */
1786
var $ = $B.args("islower", 1, {self: null}, ["self"],
1787
arguments, {}, null, null),
1791
for(var char of to_chars(self)){
1792
cp = _b_.ord(char)
1793
if(unicode_tables.Lu[cp]){
1794
is_upper = true
1795
continue
1796
}else if(unicode_tables.Ll[cp] || unicode_tables.Lt[cp]){
1815
throw _b_.TypeError.$factory("sequence item " + count +
1816
": expected str instance, " + $B.class_name(obj2) +
1817
" found")
1818
}
1831
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1832
["self", "width", "fillchar"],
1836
if($.width <= len){
1837
return self
1838
}
1839
return self + $.fillchar.repeat($.width - len)
1842
str.lower = function(self){
1843
var $ = $B.args("lower", 1, {self: null}, ["self"],
1844
arguments, {}, null, null)
1845
return self.toLowerCase()
1846
}
1847
1850
arguments, {chars:_b_.None}, null, null),
1851
self = $.self,
1852
chars = $.chars
1853
if(chars === _b_.None){
1854
return self.trimStart()
1856
while(self.length > 0){
1857
var flag = false
1858
for(var char of chars){
1859
if(self.startsWith(char)){
1860
self = self.substr(char.length)
1861
flag = true
1862
break
1863
}
1864
}
1865
if(! flag){
1866
return $.self.surrogates ? $B.String(self) : self
1874
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1875
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
1880
// If there is only one argument, it must be a dictionary mapping
1881
// Unicode ordinals (integers) or characters (strings of length 1) to
1882
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1884
if(! _b_.isinstance($.x, _b_.dict)){
1885
throw _b_.TypeError.$factory(
1886
"maketrans only argument must be a dict")
1889
for(var i = 0, len = items.length; i < len; i++){
1890
var k = items[i][0],
1891
v = items[i][1]
1892
if(! _b_.isinstance(k, _b_.int)){
1893
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1894
k = _b_.ord(k)
1895
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1898
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1899
throw _b_.TypeError.$factory("dictionary value " + v +
1907
// and in the resulting dictionary, each character in x will be mapped
1908
// to the character at the same position in y
1911
}else if($.x.length !== $.y.length){
1912
throw _b_.TypeError.$factory(
1913
"maketrans arguments must be strings or same length")
1919
if(! _b_.isinstance($.z, _b_.str)){
1920
throw _b_.TypeError.$factory(
1921
"maketrans third argument must be a string")
1943
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1944
arguments, {}, null, null)
1951
if(i == -1){
1952
return _b_.tuple.$factory([$.self, "", ""])
1953
}
1954
return _b_.tuple.$factory([chars.slice(0, i).join(''), $.sep,
1955
chars.slice(i + $.sep.length).join('')])
1958
str.removeprefix = function(){
1959
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1960
["self", "prefix"], arguments, {}, null, null)
1961
if(!_b_.isinstance($.prefix, str)){
1962
throw _b_.ValueError.$factory("prefix should be str, not " +
1963
`'${$B.class_name($.prefix)}'`)
1964
}
1965
if(str.startswith($.self, $.prefix)){
1966
return $.self.substr($.prefix.length)
1967
}
1968
return $.self.substr(0)
1969
}
1970
1971
str.removesuffix = function(){
1972
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1973
["self", "suffix"], arguments, {}, null, null)
1974
if(!_b_.isinstance($.suffix, str)){
1975
throw _b_.ValueError.$factory("suffix should be str, not " +
1976
`'${$B.class_name($.prefix)}'`)
1977
}
1978
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1979
return $.self.substr(0, $.self.length - $.suffix.length)
1980
}
1981
return $.self.substr(0)
1982
}
1983
1984
function $re_escape(str){
1985
var specials = "[.*+?|()$^"
1986
for(var i = 0, len = specials.length; i < len; i++){
1987
var re = new RegExp("\\"+specials.charAt(i), "g")
1988
str = str.replace(re, "\\"+specials.charAt(i))
1989
}
1990
return str
1998
{self: null, old: null, new: null, count: null},
1999
["self", "old", "new", "count"],
2000
arguments, {count: -1}, null, null),
2001
count = $.count,
2002
self = $.self,
2003
old = $.old,
2006
check_str(old, "replace() argument 1 ")
2007
check_str(_new, "replace() argument 2 ")
2015
if(count == 0){
2016
return self
2017
}
2018
if(count.__class__ == $B.long_int){
2019
count = parseInt(count.value)
2020
}
2022
if(_new == ""){
2023
return self
2024
}
2025
if(self == ""){
2026
return _new
2027
}
2028
var elts = self.split("")
2029
if(count > -1 && elts.length >= count){
2030
var rest = elts.slice(count).join("")
2031
return _new + elts.slice(0, count).join(_new) + rest
2057
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
2058
pos = pos + _new.length
2059
count--
2065
// Return the highest index in the string where substring sub is found,
2066
// such that sub is contained within s[start:end]. Optional arguments
2069
{self: null, sub: null, start: null, end: null},
2070
["self", "sub", "start", "end"],
2071
arguments, {start: 0, end: null}, null, null)
2076
var len = str.__len__($.self),
2077
sub_len = str.__len__($.sub)
2078
2079
if(sub_len == 0){
2080
if($.js_start > len){
2087
// Use .indexOf(), not .search(), to avoid conversion to reg exp
2088
var js_start = pypos2jspos($.self, $.start),
2089
js_end = pypos2jspos($.self, $.end),
2090
ix = $.self.substring(js_start, js_end).lastIndexOf($.sub)
2091
if(ix == -1){
2092
return -1
2107
var $ = $B.args("rjust",3,
2108
{self: null, width: null, fillchar: null},
2109
["self", "width", "fillchar"],
2110
arguments, {fillchar: " "}, null, null)
2120
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
2121
arguments, {}, null, null)
2125
var items = str.partition(self, sep).reverse()
2126
for(var i = 0; i < items.length; i++){
2127
items[i] = items[i].split("").reverse().join("")
2133
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
2134
["self", "sep", "maxsplit"], arguments,
2135
{sep: _b_.None, maxsplit: -1}, null, null),
2136
sep = $.sep
2139
var rev_str = reverse($.self),
2140
rev_sep = sep === _b_.None ? sep : reverse($.sep),
2151
str.rstrip = function(self, x){
2152
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
2153
arguments, {chars: _b_.None}, null, null),
2154
self = $.self,
2155
chars = $.chars
2156
if(chars === _b_.None){
2157
return self.trimEnd()
2159
while(self.length > 0){
2160
var flag = false
2161
for(var char of chars){
2162
if(self.endsWith(char)){
2163
self = self.substr(0, self.length - char.length)
2164
flag = true
2165
break
2166
}
2167
}
2168
if(! flag){
2169
return $.self.surrogates ? $B.String(self) : self
2176
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
2177
["self", "sep", "maxsplit"], arguments,
2178
{sep: _b_.None, maxsplit: -1}, null, null),
2179
sep = $.sep,
2180
maxsplit = $.maxsplit,
2181
self = $.self,
2182
pos = 0
2183
if(maxsplit.__class__ === $B.long_int){
2184
maxsplit = parseInt(maxsplit.value)
2185
}
2186
if(sep == ""){
2187
throw _b_.ValueError.$factory("empty separator")
2188
}
2192
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){
2193
pos++
2194
}
2195
if(pos === self.length - 1){
2196
return [self]
2197
}
2201
if(name == ""){
2202
name = self.charAt(pos)
2203
}else{
2204
name += self.charAt(pos)
2205
}
2252
str.splitlines = function(self) {
2253
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
2254
['self','keepends'], arguments, {keepends: false},
2255
null, null)
2256
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
2257
throw _b_.TypeError('integer argument expected, got '+
2260
var keepends = _b_.int.$factory($.keepends),
2261
res = [],
2262
self = $.self,
2263
start = 0,
2264
pos = 0
2265
if(!self.length){
2269
if(self.substr(pos, 2) == '\r\n'){
2270
res.push(self.slice(start, keepends ? pos + 2 : pos))
2271
start = pos = pos+2
2272
}else if(self[pos] == '\r' || self[pos] == '\n'){
2273
res.push(self.slice(start, keepends ? pos+1 : pos))
2274
start = pos = pos+1
2275
}else{
2276
pos++
2277
}
2278
}
2279
if(start < self.length){
2280
res.push(self.slice(start))
2281
}
2286
// Return True if string starts with the prefix, otherwise return False.
2287
// prefix can also be a tuple of prefixes to look for. With optional
2288
// start, test string beginning at that position. With optional end,
2290
var $ = $B.args("startswith", 4,
2291
{self: null, prefix: null, start: null, end: null},
2292
["self", "prefix", "start", "end"],
2293
arguments, {start: 0, end: null}, null, null)
2303
if(! _b_.isinstance(prefix, str)){
2304
throw _b_.TypeError.$factory("endswith first arg must be str " +
2305
"or a tuple of str, not int")
2306
}
2307
if(s.substr(0, prefix.length) == prefix){
2308
return true
2309
}
2315
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
2316
arguments, {chars: _b_.None}, null, null)
2323
str.swapcase = function(self){
2324
var $ = $B.args("swapcase", 1, {self}, ["self"],
2325
arguments, {}, null, null),
2326
res = "",
2327
cp
2328
2329
for(var char of to_chars(self)){
2330
cp = _b_.ord(char)
2331
if(unicode_tables.Ll[cp]){
2332
res += char.toUpperCase()
2333
}else if(unicode_tables.Lu[cp]){
2334
res += char.toLowerCase()
2337
}
2338
}
2339
return res
2340
}
2341
2342
str.title = function(self){
2343
var $ = $B.args("title", 1, {self}, ["self"],
2344
arguments, {}, null, null),
2345
state,
2348
for(var char of to_chars(self)){
2349
cp = _b_.ord(char)
2350
if(unicode_tables.Ll[cp]){
2357
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
2358
res += state ? char.toLowerCase() : char
2370
getitem = $B.$getattr(table, "__getitem__"),
2371
cp
2372
for(var char of to_chars(self)){
2373
cp = _b_.ord(char)
2377
if(typeof repl == "string"){
2378
res.push(repl)
2379
}else if(typeof repl == "number"){
2380
res.push(String.fromCharCode(repl))
2381
}
2390
str.upper = function(self){
2391
var $ = $B.args("upper", 1, {self: null}, ["self"],
2392
arguments, {}, null, null)
2393
return self.toUpperCase()
2394
}
2395
2398
["self", "width"], arguments, {}, null, null),
2399
len = str.__len__(self)
2400
if($.width <= len){
2401
return self
2402
}
2422
if(encoding !== undefined){
2423
// Arguments may be passed as keywords (cf. issue #1060)
2424
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2425
["arg", "encoding", "errors"], arguments,
2426
{encoding: "utf-8", errors: "strict"}, null, null),
2427
encoding = $.encoding,
2428
errors = $.errors
2429
}
2430
if(typeof arg == "string" || arg instanceof String ||
2431
typeof arg == "number"){
2432
if(isFinite(arg)){
2433
return arg.toString()
2434
}
2440
// class or its subclasses, but the attribute __str__ of the
2441
// class metaclass (usually "type") or its subclasses (usually
2442
// "object")
2443
// The metaclass is the attribute __class__ of the class dictionary
2448
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2449
encoding !== undefined){
2450
// str(bytes, encoding, errors) is equal to
2451
// bytes.decode(encoding, errors)
2454
// Implicit invocation of __str__ uses method __str__ on the class,
2455
// even if arg has an attribute __str__
2456
var klass = arg.__class__ || $B.get_class(arg)
2462
// if not better than object.__str__, try __repr__
2463
(arg.__class__ && arg.__class__ !== _b_.object &&
2471
if($B.debug > 1){console.log(err)}
2472
console.log("Warning - no method __str__ or __repr__, " +
2473
"default to toString", arg)
2480
if(cls === undefined){
2481
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
2505
var args = [],
2506
pos = 0
2507
if(arguments.length > 0){
2508
var args = [arguments[0].valueOf()],
2509
pos = 1
2510
for(var i = 1, len = arguments.length; i < len; i++){
2511
args[pos++] = arguments[i]
2528
// Function to parse the 2nd argument of format()
2529
$B.parse_format_spec = function(spec){
2533
var pos = 0,
2534
aligns = "<>=^",
2535
digits = "0123456789",
2536
types = "bcdeEfFgGnosxX%",
2538
if(align_pos != -1){
2539
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2540
// If the second char is also an alignment specifier, the
2541
// first char is the fill value
2542
this.fill = spec.charAt(0)
2543
this.align = spec.charAt(1)
2544
pos = 2
2545
}else{
2546
// The first character defines alignment : fill defaults to ' '
2561
if(car == "+" || car == "-" || car == " "){
2562
this.sign = car
2563
pos++
2564
car = spec.charAt(pos)
2579
if(this.width === undefined){
2580
this.width = car
2581
}else{
2582
this.width += car
2583
}
2590
if(this.width === undefined && car == "{"){
2591
// Width is determined by a parameter
2592
var end_param_pos = spec.substr(pos).search("}")
2593
this.width = spec.substring(pos, end_param_pos)
2594
console.log("width", "[" + this.width + "]")
2595
pos += end_param_pos + 1
2596
}
2597
if(car == ","){
2598
this.comma = true
2599
pos++
2600
car = spec.charAt(pos)
2601
}
2602
if(car == "."){
2603
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2604
throw _b_.ValueError.$factory(
2605
"Missing precision in format spec")
2607
this.precision = spec.charAt(pos + 1)
2608
pos += 2
2609
car = spec.charAt(pos)
2610
while(car && digits.indexOf(car) > -1){
2617
if(car && types.indexOf(car) > -1){
2618
this.type = car
2619
pos++
2620
car = spec.charAt(pos)
2621
}
2622
if(pos !== spec.length){
2628
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2629
(this.align || "") +
2630
(this.sign || "") +
2631
(this.alternate ? "#" : "") +
2632
(this.sign_aware ? "0" : "") +
2633
(this.width || "") +
2634
(this.comma ? "," : "") +
2635
(this.precision ? "." + this.precision : "") +
2636
(this.type || "")
2641
if(fmt.width && s.length < fmt.width){
2642
var fill = fmt.fill || " ",
2643
align = fmt.align || "<",
2644
missing = fmt.width - s.length
2646
case "<":
2647
return s + fill.repeat(missing)
2648
case ">":
2649
return fill.repeat(missing) + s
2650
case "=":
2651
if("+-".indexOf(s.charAt(0)) > -1){
2652
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2656
case "^":
2657
var left = parseInt(missing / 2)
2658
return fill.repeat(left) + s + fill.repeat(missing - left)
2672
function fstring_error(msg, pos){
2673
error = Error(msg)
2674
error.position = pos
2675
throw error
2676
}
2677
2678
$B.parse_fstring = function(string){
2679
// Parse a f-string
2680
var elts = [],
2681
pos = 0,
2746
}else if(ctype == "debug"){
2747
// after the equal sign, whitespace are ignored and the only
2748
// valid characters are } and :
2749
while(string.charAt(i) == " "){i++}
2750
if(string.charAt(i) == "}"){
2751
// end of debug expression
2752
elts.push(current)
2753
ctype = null
2754
current = ""
2755
pos = i + 1
2756
}
2757
}else{
2758
// End of expression is the } matching the opening {
2759
// There may be nested braces
2760
var i = pos,
2761
nb_braces = 1,
2774
if(current.expression == ""){
2775
fstring_error("f-string: empty expression not allowed",
2776
pos)
2777
}
2787
// backslash is not allowed in expressions
2788
throw Error("f-string expression part cannot include a" +
2789
" backslash")
2796
throw Error("f-string: invalid conversion character:" +
2797
" expected 's', 'r', or 'a'")
2798
}else{
2812
if(string.substr(i, 3) == '"""'){
2813
var end = string.indexOf('"""', i + 3)
2814
if(end == -1){
2816
}else{
2817
var trs = string.substring(i, end + 3)
2818
trs = trs.replace("\n", "\\n\\")
2834
var cb = 0,
2835
fmt_complete = false
2836
for(var j = i + 1; j < string.length; j++){
2837
if(string[j] == '{'){
2838
if(string[j + 1] == '{'){
2839
j += 2
2840
}else{
2841
cb++
2842
}
2843
}else if(string[j] == '}'){
2844
if(string[j + 1] == '}'){
2845
j += 2
2846
}else if(cb == 0){
2847
fmt_complete = true
2848
var fmt = string.substring(i + 1, j)
2849
current.format = $B.parse_fstring(fmt)
2850
i = j
2851
break
2852
}else{
2853
cb--
2854
}
2855
}
2856
}
2857
if(! fmt_complete){
2858
fstring_error('invalid format', pos)
2859
}
2862
var ce = current.expression,
2863
last_char = ce.charAt(ce.length - 1),
2864
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
2873
}else{
2874
// add debug string
2875
tail = car
2876
while(string.charAt(i + 1).match(/\s/)){
2877
tail += string.charAt(i + 1)
2878
i++
2879
}
2881
elts.push(current.expression + tail)
2882
// remove trailing whitespace from expression
2883
while(ce.match(/\s$/)){
2884
ce = ce.substr(0, ce.length - 1)
2885
}
2886
current.expression = ce
2887
ctype = "debug"
2888
i++
2889
}
2903
for(var elt of elts){
2904
if(typeof elt == "object"){
2905
if(elt.fmt_pos !== undefined &&
2906
elt.expression.charAt(elt.fmt_pos) != ':'){
2907
console.log('mauvais format', string, elts)
2908
throw Error()
2909
}
2910
}
2911
}
2916
if(i >= 0x10000 && i <= 0x10FFFF){
2917
var code = (i - 0x10000)
2918
return String.fromCodePoint(0xD800 | (code >> 10)) +
2919
String.fromCodePoint(0xDC00 | (code & 0x3FF))
2920
}else{
2921
return String.fromCodePoint(i)
2922
}
2923
}
2926
if(c.length == 1){
2927
return c.charCodeAt(0)
2928
}
2929
var code = 0x10000
2930
code += (c.charCodeAt(0) & 0x03FF) << 10
2931
code += (c.charCodeAt(1) & 0x03FF)
2932
return code
2933
}
2934