Skip to content
Permalink
Newer
Older
100644 2566 lines (2351 sloc) 81.3 KB
Sep 5, 2014
1
;(function($B){
2
3
var bltns = $B.InjectBuiltins()
4
eval(bltns)
Sep 5, 2014
5
6
// build tables from data in unicode_data.js
7
var unicode_tables = $B.unicode_tables
Sep 5, 2014
8
str
Feb 10, 2018
9
var str = {
Mar 19, 2018
10
__class__: _b_.type,
11
__dir__: object.__dir__,
12
$infos: {
13
__module__: "builtins",
14
__name__: "str"
15
},
str
Feb 10, 2018
16
$is_class: true,
Mar 19, 2018
17
$native: true
Sep 5, 2014
18
}
19
Mar 19, 2018
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
}
Mar 19, 2018
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
}
39
function reverse(s){
40
// Reverse a string
Mar 19, 2018
41
return s.split("").reverse().join("")
42
}
43
44
function check_str(obj){
Mar 19, 2018
45
if(! _b_.isinstance(obj, str)){
Mar 21, 2018
46
throw _b_.TypeError.$factory("can't convert '" +
47
$B.class_name(obj) + "' object to str implicitly")
Mar 19, 2018
48
}
str
Feb 10, 2018
51
str.__add__ = function(self,other){
Mar 19, 2018
52
if(!(typeof other === "string")){
53
try{return getattr(other, "__radd__")(self)}
54
catch(err){
55
throw _b_.TypeError.$factory("Can't convert " +
56
$B.class_name(other) + " to str implicitly")}
Sep 5, 2014
57
}
Mar 19, 2018
58
return self + other
Sep 5, 2014
59
}
60
Mar 19, 2018
61
str.__contains__ = function(self, item){
62
if(! _b_.isinstance(item, str)){
Mar 19, 2018
63
throw _b_.TypeError.$factory("'in <string>' requires " +
64
"string as left operand, not " + item.__class__)
65
}
66
if(typeof item == "string"){
67
var nbcar = item.length
68
}else{
69
var nbcar = _b_.len(item)
70
}
Mar 19, 2018
71
if(nbcar == 0) {return true} // a string contains the empty string
72
if(self.length == 0){return nbcar == 0}
73
for(var i = 0, len = self.length; i < len; i++){
74
if(self.substr(i, nbcar) == item){return true}
Sep 5, 2014
75
}
76
return false
77
}
78
str
Feb 10, 2018
79
str.__delitem__ = function(){
80
throw _b_.TypeError.$factory("'str' object doesn't support item deletion")
Sep 5, 2014
81
}
82
Mar 19, 2018
83
// __dir__must be assigned explicitely because attribute resolution for
84
// builtin classes doesn't use __mro__
str
Feb 10, 2018
85
str.__dir__ = object.__dir__
str
Feb 10, 2018
87
str.__eq__ = function(self,other){
Mar 19, 2018
88
if(other === undefined){ // compare object "self" to class "str"
89
return self === str
Sep 5, 2014
90
}
Mar 23, 2018
91
if(_b_.isinstance(other, _b_.str)){
92
return other.valueOf() == self.valueOf()
93
}
94
return _b_.NotImplemented
Sep 5, 2014
95
}
96
97
function preformat(self, fmt){
str
Feb 10, 2018
98
if(fmt.empty){return _b_.str.$factory(self)}
Mar 19, 2018
99
if(fmt.type && fmt.type != "s"){
100
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
101
"' for object of type 'str'")
103
return self
104
}
105
str
Feb 10, 2018
106
str.__format__ = function(self, format_spec) {
107
var fmt = new $B.parse_format_spec(format_spec)
Mar 19, 2018
108
if(fmt.sign !== undefined){
109
throw _b_.ValueError.$factory(
110
"Sign not allowed in string format specifier")
112
if(fmt.precision){
113
self = self.substr(0, fmt.precision)
114
}
115
// For strings, alignment default to left
Mar 19, 2018
116
fmt.align = fmt.align || "<"
117
return $B.format_width(preformat(self, fmt), fmt)
Sep 5, 2014
118
}
119
str
Feb 10, 2018
120
str.__getitem__ = function(self,arg){
Mar 19, 2018
121
if(isinstance(arg, _b_.int)){
Sep 5, 2014
122
var pos = arg
Mar 19, 2018
123
if(arg < 0) {pos += self.length}
124
if(pos >= 0 && pos < self.length){return self.charAt(pos)}
125
throw _b_.IndexError.$factory("string index out of range")
126
}
127
if(isinstance(arg, slice)) {
128
var s = _b_.slice.$conv_for_seq(arg, self.length),
129
start = s.start,
130
stop = s.stop,
131
step = s.step
132
var res = "",
Mar 19, 2018
133
i = null
Mar 19, 2018
134
if(step > 0){
135
if(stop <= start){return ""}
136
for(var i = start; i < stop; i += step){res += self.charAt(i)}
Mar 23, 2018
137
}else{
Mar 19, 2018
138
if(stop >= start){return ''}
139
for(var i = start; i > stop; i += step){res += self.charAt(i)}
Sep 5, 2014
141
return res
142
}
143
if(isinstance(arg, _b_.bool)){return self.__getitem__(_b_.int.$factory(arg))}
Mar 19, 2018
144
throw _b_.TypeError.$factory("string indices must be integers")
Sep 5, 2014
145
}
146
147
var prefix = 2,
148
suffix = 3,
Jun 12, 2020
149
mask = (2 ** 32 - 1),
150
str_hash_cache = {}
151
152
var nb_str_hash_cache = 0
Jun 12, 2020
153
154
function fnv(p){
155
if(p.length == 0){
156
return 0
157
}
Sep 5, 2014
158
159
var x = prefix
160
x = (x ^ (p.charCodeAt(0) << 7)) & mask
161
for(var i = 0, len = p.length; i < len; i++){
162
x = ((1000003 * x) ^ p.charCodeAt(i)) & mask
163
}
164
x = (x ^ p.length) & mask
165
x = (x ^ suffix) & mask
Sep 5, 2014
166
167
if(x == -1){
168
x = -2
169
}
170
return x
171
}
173
str.__hash__ = function(self) {
Jun 12, 2020
174
if(str_hash_cache[self] !== undefined){
175
return str_hash_cache[self]
176
}
177
nb_str_hash_cache++
178
if(nb_str_hash_cache > 100000){
179
// Avoid memory overflow
180
str_hash_cache = {}
181
}
Jun 12, 2020
182
return str_hash_cache[self] = fnv(self)
Sep 5, 2014
183
}
184
Mar 19, 2018
185
str.__init__ = function(self, arg){
Sep 5, 2014
186
self.valueOf = function(){return arg}
187
self.toString = function(){return arg}
Sep 5, 2014
189
}
190
191
var str_iterator = $B.make_iterator_class("str_iterator")
str
Feb 10, 2018
192
str.__iter__ = function(self){
194
return str_iterator.$factory(items)
Sep 5, 2014
195
}
196
197
str.__len__ = function(self){
198
return self.length
199
}
Sep 5, 2014
200
201
// Start of section for legacy formatting (with %)
202
Mar 19, 2018
203
var kwarg_key = new RegExp("([^\\)]*)\\)")
204
205
var NotANumber = function() {
Mar 19, 2018
206
this.name = "NotANumber"
207
}
208
Mar 19, 2018
209
var number_check = function(s){
210
if(! isinstance(s, [_b_.int, _b_.float])){
211
throw new NotANumber()
212
}
213
}
214
Mar 19, 2018
215
var get_char_array = function(size, char){
Mar 23, 2018
216
if(size <= 0){return ""}
217
return new Array(size + 1).join(char)
218
}
219
Mar 19, 2018
220
var format_padding = function(s, flags, minus_one){
221
var padding = flags.padding
Mar 23, 2018
222
if(! padding){ // undefined
223
return s
224
}
225
s = s.toString()
226
padding = parseInt(padding, 10)
Mar 23, 2018
227
if(minus_one){ // numeric formatting where sign goes in front of padding
228
padding -= 1
229
}
Mar 19, 2018
230
if(! flags.left){
231
return get_char_array(padding - s.length, flags.pad_char) + s
Mar 19, 2018
232
}else{
233
// left adjusted
234
return s + get_char_array(padding - s.length, flags.pad_char)
235
}
236
}
237
Mar 19, 2018
238
var format_int_precision = function(val, flags){
239
var precision = flags.precision
Mar 19, 2018
240
if(!precision){
241
return val.toString()
242
}
243
precision = parseInt(precision, 10)
Mar 19, 2018
245
if(val.__class__ === $B.long_int){
246
s = $B.long_int.to_base(val, 10)
247
}else{
248
s = val.toString()
Mar 19, 2018
250
if(s[0] === "-"){
251
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
Mar 19, 2018
253
return get_char_array(precision - s.length, "0") + s
254
}
255
Mar 19, 2018
256
var format_float_precision = function(val, upper, flags, modifier){
257
var precision = flags.precision
258
// val is a float
Mar 19, 2018
259
if(isFinite(val)){
260
return modifier(val, precision, flags, upper)
Mar 19, 2018
262
if(val === Infinity){
263
val = "inf"
264
}else if(val === -Infinity){
265
val = "-inf"
266
}else{
267
val = "nan"
Mar 19, 2018
269
if(upper){
270
return val.toUpperCase()
271
}
272
return val
274
}
275
Mar 19, 2018
276
var format_sign = function(val, flags){
277
if(flags.sign){
278
if(val >= 0){
279
return "+"
Sep 5, 2014
280
}
Mar 19, 2018
281
}else if (flags.space){
282
if(val >= 0){
283
return " "
284
}
285
}
286
return ""
287
}
Sep 5, 2014
288
289
var str_format = function(val, flags) {
290
// string format supports left and right padding
291
flags.pad_char = " " // even if 0 padding is defined, don't use it
str
Feb 10, 2018
292
return format_padding(str.$factory(val), flags)
Sep 5, 2014
294
295
var num_format = function(val, flags) {
296
number_check(val)
Mar 19, 2018
297
if(val.__class__ === $B.long_int){
298
val = $B.long_int.to_base(val, 10)
299
}else{
300
val = parseInt(val)
303
var s = format_int_precision(val, flags)
Mar 19, 2018
304
if(flags.pad_char === "0"){
305
if(val < 0){
306
s = s.substring(1)
Mar 19, 2018
307
return "-" + format_padding(s, flags, true)
308
}
309
var sign = format_sign(val, flags)
Mar 19, 2018
310
if(sign !== ""){
311
return sign + format_padding(s, flags, true)
312
}
313
}
315
return format_padding(format_sign(val, flags) + s, flags)
316
}
Sep 5, 2014
317
318
var repr_format = function(val, flags) {
319
flags.pad_char = " " // even if 0 padding is defined, don't use it
320
return format_padding(repr(val), flags)
321
}
Sep 5, 2014
322
323
var ascii_format = function(val, flags) {
324
flags.pad_char = " " // even if 0 padding is defined, don't use it
325
return format_padding(ascii(val), flags)
326
}
Sep 5, 2014
327
328
// converts val to float and sets precision if missing
Mar 19, 2018
329
var _float_helper = function(val, flags){
330
number_check(val)
Mar 19, 2018
331
if(! flags.precision){
332
if(! flags.decimal_point){
333
flags.precision = 6
Mar 19, 2018
334
}else{
335
flags.precision = 0
336
}
Mar 19, 2018
337
}else{
338
flags.precision = parseInt(flags.precision, 10)
339
validate_precision(flags.precision)
340
}
341
return parseFloat(val)
342
}
Sep 5, 2014
343
344
// used to capture and remove trailing zeroes
Mar 19, 2018
345
var trailing_zeros = /(.*?)(0+)([eE].*)/,
346
leading_zeros = /\.(0*)/,
347
trailing_dot = /\.$/
Sep 5, 2014
348
349
var validate_precision = function(precision) {
350
// force precision to limits of javascript
Mar 19, 2018
351
if(precision > 20){precision = 20}
352
}
353
354
// gG
Mar 19, 2018
355
var floating_point_format = function(val, upper, flags){
356
val = _float_helper(val, flags),
357
v = val.toString(),
358
v_len = v.length,
359
dot_idx = v.indexOf('.')
360
if(dot_idx < 0){dot_idx = v_len}
361
if(val < 1 && val > -1){
362
var zeros = leading_zeros.exec(v),
363
numzeros
364
if(zeros){
365
numzeros = zeros[1].length
Mar 19, 2018
366
}else{
367
numzeros = 0
368
}
Mar 19, 2018
369
if(numzeros >= 4){
370
val = format_sign(val, flags) + format_float_precision(val, upper,
371
flags, _floating_g_exp_helper)
372
if(!flags.alternate){
373
var trl = trailing_zeros.exec(val)
Mar 19, 2018
374
if(trl){
375
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
377
}else{
378
if(flags.precision <= 1){
379
val = val[0] + "." + val.substring(1)
381
}
382
return format_padding(val, flags)
383
}
384
flags.precision = (flags.precision || 0) + numzeros
Mar 19, 2018
385
return format_padding(format_sign(val, flags) +
386
format_float_precision(val, upper, flags,
387
function(val, precision) {
388
return val.toFixed(min(precision, v_len - dot_idx) +
389
numzeros)
390
}),
391
flags
392
)
393
}
394
395
if(dot_idx > flags.precision){
396
val = format_sign(val, flags) + format_float_precision(val, upper,
397
flags, _floating_g_exp_helper)
398
if(! flags.alternate){
399
var trl = trailing_zeros.exec(val)
Mar 19, 2018
400
if(trl){
401
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
403
}else{
404
if(flags.precision <= 1){
405
val = val[0] + "." + val.substring(1)
406
}
407
}
408
return format_padding(val, flags)
409
}
Mar 19, 2018
410
return format_padding(format_sign(val, flags) +
411
format_float_precision(val, upper, flags,
412
function(val, precision) {
413
if(!flags.decimal_point){
414
precision = min(v_len - 1, 6)
415
}else if (precision > v_len){
416
if(! flags.alternate){
417
precision = v_len
418
}
Sep 5, 2014
419
}
Mar 19, 2018
420
if(precision < dot_idx){
421
precision = dot_idx
422
}
423
return val.toFixed(precision - dot_idx)
424
}),
425
flags
426
)
Sep 5, 2014
428
Mar 19, 2018
429
var _floating_g_exp_helper = function(val, precision, flags, upper){
430
if(precision){--precision}
431
val = val.toExponential(precision)
432
// pad exponent to two digits
Mar 19, 2018
433
var e_idx = val.lastIndexOf("e")
434
if(e_idx > val.length - 4){
435
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
437
if(upper){return val.toUpperCase()}
438
return val
439
}
440
441
// fF
442
var floating_point_decimal_format = function(val, upper, flags) {
443
val = _float_helper(val, flags)
Mar 19, 2018
444
return format_padding(format_sign(val, flags) +
445
format_float_precision(val, upper, flags,
446
function(val, precision, flags) {
447
val = val.toFixed(precision)
448
if(precision === 0 && flags.alternate){
449
val += '.'
450
}
451
return val
452
}),
453
flags
454
)
455
}
456
457
var _floating_exp_helper = function(val, precision, flags, upper) {
458
val = val.toExponential(precision)
459
// pad exponent to two digits
Mar 19, 2018
460
var e_idx = val.lastIndexOf("e")
Mar 23, 2018
461
if(e_idx > val.length - 4){
Mar 19, 2018
462
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
464
if(upper){return val.toUpperCase()}
465
return val
466
}
467
468
// eE
Mar 19, 2018
469
var floating_point_exponential_format = function(val, upper, flags){
470
val = _float_helper(val, flags)
Mar 19, 2018
472
return format_padding(format_sign(val, flags) +
473
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
474
}
475
Mar 19, 2018
476
var signed_hex_format = function(val, upper, flags){
478
number_check(val)
Mar 23, 2018
480
if(val.__class__ === $B.long_int){
Mar 19, 2018
481
ret = $B.long_int.to_base(val, 16)
482
}else{
483
ret = parseInt(val)
484
ret = ret.toString(16)
485
}
486
ret = format_int_precision(ret, flags)
Mar 19, 2018
487
if(upper){ret = ret.toUpperCase()}
Mar 23, 2018
488
if(flags.pad_char === "0"){
Mar 19, 2018
489
if(val < 0){
490
ret = ret.substring(1)
Mar 19, 2018
491
ret = "-" + format_padding(ret, flags, true)
492
}
493
var sign = format_sign(val, flags)
Mar 19, 2018
494
if(sign !== ""){
495
ret = sign + format_padding(ret, flags, true)
Sep 5, 2014
496
}
Mar 19, 2018
499
if(flags.alternate){
500
if(ret.charAt(0) === "-"){
501
if(upper){ret = "-0X" + ret.slice(1)}
502
else{ret = "-0x" + ret.slice(1)}
503
}else{
504
if(upper){ret = "0X" + ret}
505
else{ret = "0x" + ret}
506
}
507
}
508
return format_padding(format_sign(val, flags) + ret, flags)
509
}
Sep 5, 2014
510
511
var octal_format = function(val, flags) {
512
number_check(val)
Mar 19, 2018
515
if(val.__class__ === $B.long_int){
516
ret = $B.long_int.to_base(8)
517
}else{
518
ret = parseInt(val)
519
ret = ret.toString(8)
522
ret = format_int_precision(ret, flags)
Mar 19, 2018
524
if(flags.pad_char === "0"){
525
if(val < 0){
526
ret = ret.substring(1)
Mar 19, 2018
527
ret = "-" + format_padding(ret, flags, true)
528
}
529
var sign = format_sign(val, flags)
Mar 19, 2018
530
if(sign !== ""){
531
ret = sign + format_padding(ret, flags, true)
532
}
Sep 5, 2014
533
}
Mar 19, 2018
535
if(flags.alternate){
536
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
537
else{ret = "0o" + ret}
Sep 5, 2014
538
}
539
return format_padding(ret, flags)
540
}
541
542
function series_of_bytes(val, flags){
543
if(val.__class__ && val.__class__.$buffer_protocol){
544
var it = _b_.iter(val),
545
ints = []
546
while(true){
547
try{
548
ints.push(_b_.next(it))
549
}catch(err){
550
if(err.__class__ === _b_.StopIteration){
551
var b = _b_.bytes.$factory(ints)
552
return format_padding(_b_.bytes.decode(b, "ascii"), flags)
553
}
554
throw err
555
}
556
}
557
}else{
558
try{
559
bytes_obj = $B.$getattr(val, "__bytes__")
560
return format_padding(_b_.bytes.decode(bytes_obj), flags)
561
}catch(err){
562
if(err.__class__ === _b_.AttributeError){
563
throw _b_.TypeError.$factory("%b does not accept '" +
564
$B.class_name(val) + "'")
565
}
566
throw err
567
}
568
}
569
}
570
Mar 19, 2018
571
var single_char_format = function(val, flags){
572
if(isinstance(val, str) && val.length == 1){
573
return val
574
}else if(isinstance(val, bytes) && val.source.length == 1){
575
val = val.source[0]
576
}else{
577
try{
578
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
579
}catch (err){
580
throw _b_.TypeError.$factory("%c requires int or char")
581
}
582
}
583
return format_padding(chr(val), flags)
584
}
585
Mar 19, 2018
586
var num_flag = function(c, flags){
587
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
588
flags.pad_char = "0"
589
return
590
}
Mar 19, 2018
591
if(!flags.decimal_point){
592
flags.padding = (flags.padding || "") + c
Mar 19, 2018
593
}else{
594
flags.precision = (flags.precision || "") + c
595
}
596
}
597
598
var decimal_point_flag = function(val, flags) {
Mar 23, 2018
599
if(flags.decimal_point){
600
// can only have one decimal point
601
throw new UnsupportedChar()
602
}
603
flags.decimal_point = true
604
}
605
Mar 19, 2018
606
var neg_flag = function(val, flags){
607
flags.pad_char = " " // overrides '0' flag
608
flags.left = true
609
}
610
Mar 19, 2018
611
var space_flag = function(val, flags){
612
flags.space = true
613
}
614
Mar 19, 2018
615
var sign_flag = function(val, flags){
616
flags.sign = true
617
}
618
Mar 19, 2018
619
var alternate_flag = function(val, flags){
620
flags.alternate = true
621
}
622
623
var char_mapping = {
Mar 19, 2018
625
"s": str_format,
626
"d": num_format,
627
"i": num_format,
628
"u": num_format,
629
"o": octal_format,
630
"r": repr_format,
631
"a": ascii_format,
632
"g": function(val, flags){
633
return floating_point_format(val, false, flags)
634
},
635
"G": function(val, flags){return floating_point_format(val, true, flags)},
636
"f": function(val, flags){
637
return floating_point_decimal_format(val, false, flags)
638
},
639
"F": function(val, flags){
640
return floating_point_decimal_format(val, true, flags)
641
},
642
"e": function(val, flags){
643
return floating_point_exponential_format(val, false, flags)
644
},
645
"E": function(val, flags){
646
return floating_point_exponential_format(val, true, flags)
647
},
648
"x": function(val, flags){return signed_hex_format(val, false, flags)},
649
"X": function(val, flags){return signed_hex_format(val, true, flags)},
650
"c": single_char_format,
651
"0": function(val, flags){return num_flag("0", flags)},
652
"1": function(val, flags){return num_flag("1", flags)},
653
"2": function(val, flags){return num_flag("2", flags)},
654
"3": function(val, flags){return num_flag("3", flags)},
655
"4": function(val, flags){return num_flag("4", flags)},
656
"5": function(val, flags){return num_flag("5", flags)},
657
"6": function(val, flags){return num_flag("6", flags)},
658
"7": function(val, flags){return num_flag("7", flags)},
659
"8": function(val, flags){return num_flag("8", flags)},
660
"9": function(val, flags){return num_flag("9", flags)},
661
"-": neg_flag,
662
" ": space_flag,
663
"+": sign_flag,
664
".": decimal_point_flag,
665
"#": alternate_flag
666
}
667
668
// exception thrown when an unsupported char is encountered in legacy format
Mar 19, 2018
669
var UnsupportedChar = function(){
670
this.name = "UnsupportedChar"
671
}
672
str
Feb 10, 2018
673
str.__mod__ = function(self, args) {
675
var length = self.length,
Mar 19, 2018
676
pos = 0 | 0,
677
argpos = null,
678
getitem
Mar 19, 2018
679
if(_b_.isinstance(args, _b_.tuple)){
680
argpos = 0 | 0
Mar 19, 2018
682
getitem = _b_.getattr(args, "__getitem__", _b_.None)
683
}
684
var ret = ''
685
var $get_kwarg_string = function(s) {
686
// returns [self, newpos]
687
++pos
688
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
689
if(! rslt){
690
throw _b_.ValueError.$factory("incomplete format key")
691
}
692
var key = rslt[1]
693
newpos += rslt[0].length
Mar 23, 2018
694
try{
695
var self = getitem(key)
Mar 19, 2018
696
}catch(err){
697
if(err.name === "KeyError"){
698
throw err
699
}
700
throw _b_.TypeError.$factory("format requires a mapping")
702
return get_string_value(s, self)
703
}
704
705
var $get_arg_string = function(s) {
706
// returns [self, newpos]
707
var self
709
// non-tuple args
Mar 19, 2018
710
if(argpos === null){
711
// args is the value
Mar 19, 2018
713
}else{
714
self = args[argpos++]
Mar 19, 2018
715
if(self === undefined){
716
throw _b_.TypeError.$factory(
717
"not enough arguments for format string")
Sep 5, 2014
718
}
719
}
720
return get_string_value(s, self)
722
var get_string_value = function(s, self) {
723
// todo: get flags, type
724
// todo: string value based on flags, type, value
Mar 19, 2018
725
var flags = {"pad_char": " "}
726
do{
727
var func = char_mapping[s[newpos]]
Mar 23, 2018
728
try{
Mar 19, 2018
729
if(func === undefined){
730
throw new UnsupportedChar()
Mar 19, 2018
731
}else{
732
var ret = func(self, flags)
Mar 19, 2018
733
if(ret !== undefined){
734
return ret
735
}
736
++newpos
737
}
Mar 19, 2018
738
}catch (err){
739
if(err.name == "UnsupportedChar"){
740
invalid_char = s[newpos]
Mar 19, 2018
741
if(invalid_char === undefined){
742
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
744
throw _b_.ValueError.$factory(
745
"unsupported format character '" + invalid_char +
746
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
747
") at index " + newpos)
748
}else if(err.name === "NotANumber"){
749
var try_char = s[newpos],
750
cls = self.__class__
751
if(!cls){
752
if(typeof(self) === "string"){
753
cls = "str"
754
}else{
755
cls = typeof(self)
Mar 19, 2018
757
}else{
Mar 19, 2018
760
throw _b_.TypeError.$factory("%" + try_char +
761
" format: a number is required, not " + cls)
762
}else{
763
throw err
764
}
Sep 5, 2014
765
}
Mar 19, 2018
766
}while (true)
Sep 5, 2014
767
}
768
var nbph = 0 // number of placeholders
Mar 19, 2018
769
do{
770
var newpos = self.indexOf("%", pos)
771
if(newpos < 0){
772
ret += self.substring(pos)
773
break
774
}
775
ret += self.substring(pos, newpos)
776
++newpos
Mar 19, 2018
777
if(newpos < length){
778
if(self[newpos] === "%"){
779
ret += "%"
780
}else{
Mar 19, 2018
782
if(self[newpos] === "("){
783
++newpos
784
ret += $get_kwarg_string(self)
Mar 23, 2018
785
}else{
786
ret += $get_arg_string(self)
787
}
788
}
Mar 19, 2018
789
}else{
790
// % at end of string
791
throw _b_.ValueError.$factory("incomplete format")
792
}
793
pos = newpos + 1
Mar 19, 2018
794
}while(pos < length)
795
796
if(argpos !== null){
797
if(args.length > argpos){
798
throw _b_.TypeError.$factory(
799
"not enough arguments for format string")
800
}else if(args.length < argpos){
801
throw _b_.TypeError.$factory(
802
"not all arguments converted during string formatting")
Mar 19, 2018
804
}else if(nbph == 0){
805
throw _b_.TypeError.$factory(
806
"not all arguments converted during string formatting")
Sep 5, 2014
810
str
Feb 10, 2018
811
str.__mro__ = [object]
Sep 5, 2014
812
str
Feb 10, 2018
813
str.__mul__ = function(){
Mar 19, 2018
814
var $ = $B.args("__mul__", 2, {self: null, other: null},
815
["self", "other"], arguments, {}, null, null)
816
if(! isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
817
"Can't multiply sequence by non-int of type '" +
Mar 19, 2018
819
var $res = ""
820
for(var i = 0; i< $.other; i++){$res += $.self.valueOf()}
Sep 5, 2014
821
return $res
822
}
823
Mar 19, 2018
824
str.__ne__ = function(self,other){return other !== self.valueOf()}
Sep 5, 2014
825
str
Feb 10, 2018
826
str.__repr__ = function(self){
828
// escape the escape char
829
res = self.replace(/\\/g, "\\\\")
830
// special cases
831
res = res.replace(new RegExp("\u0007", "g"), "\\x07").
832
replace(new RegExp("\b", "g"), "\\x08").
833
replace(new RegExp("\u000b", "g"), "\\x0b").
834
replace(new RegExp("\f", "g"), "\\x0c").
835
replace(new RegExp("\n", "g"), "\\n").
836
replace(new RegExp("\r", "g"), "\\r").
837
replace(new RegExp("\t", "g"), "\\t")
Mar 27, 2019
838
res = res.replace(combining_re, "\u200B$1")
Mar 19, 2018
839
if(res.search('"') == -1 && res.search("'") == -1){
840
return "'" + res + "'"
841
}else if(self.search('"') == -1){
842
return '"' + res + '"'
843
}
844
var qesc = new RegExp("'", "g") // to escape single quote
845
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
846
return res
847
}
848
Mar 19, 2018
849
str.__setitem__ = function(self, attr, value){
850
throw _b_.TypeError.$factory(
851
"'str' object does not support item assignment")
Sep 5, 2014
852
}
Mar 27, 2019
853
var combining = []
854
for(var cp = 0x300; cp <= 0x36F; cp++){
855
combining.push(String.fromCharCode(cp))
856
}
857
var combining_re = new RegExp("(" + combining.join("|") + ")")
str
Feb 10, 2018
859
str.__str__ = function(self){
Mar 27, 2019
860
return self.replace(combining_re, "\u200B$1")
Sep 5, 2014
861
}
Mar 19, 2018
862
str.toString = function(){return "string!"}
Sep 5, 2014
863
864
// generate comparison methods
865
var $comp_func = function(self,other){
866
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
867
return self > other
868
}
Mar 19, 2018
869
$comp_func += "" // source code
870
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
871
for(var $op in $comps){
Mar 19, 2018
872
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
873
}
874
875
// add "reflected" methods
str
Feb 10, 2018
876
$B.make_rmethods(str)
Sep 5, 2014
877
878
// unsupported operations
Mar 19, 2018
879
var $notimplemented = function(self, other){
880
throw NotImplementedError.$factory(
881
"OPERATOR not implemented for class str")
Sep 5, 2014
882
}
883
884
str.capitalize = function(self){
885
var $ = $B.args("capitalize", 1, {self}, ["self"],
886
arguments, {}, null, null)
887
if(self.length == 0){return ""}
888
return self.charAt(0).toUpperCase() + self.substr(1)
889
}
890
891
str.casefold = function(self){
892
var $ = $B.args("casefold", 1, {self}, ["self"],
893
arguments, {}, null, null),
894
res = "",
895
char,
896
cf
897
for(var i = 0, len = self.length; i < len; i++){
898
char = self.charCodeAt(i)
899
cf = $B.unicode_casefold[char]
900
if(cf){
901
cf.forEach(function(cp){
902
res += String.fromCharCode(cp)
903
})
904
}else{
905
res += self.charAt(i).toLowerCase()
906
}
907
}
908
return res
909
}
Sep 5, 2014
910
Mar 19, 2018
911
str.center = function(){
912
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
913
["self", "width", "fillchar"],
914
arguments, {fillchar:" "}, null, null),
915
self = $.self
Mar 19, 2018
917
if($.width <= self.length) {return self}
Mar 19, 2018
919
var pad = parseInt(($.width - self.length) / 2),
920
res = $.fillchar.repeat(pad)
Sep 5, 2014
921
res += self + res
Mar 19, 2018
922
if(res.length < $.width){res += $.fillchar}
Sep 5, 2014
923
return res
924
}
925
str
Feb 10, 2018
926
str.count = function(){
Mar 19, 2018
927
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
928
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
Mar 19, 2018
930
if(!(typeof $.sub == "string")){throw _b_.TypeError.$factory(
931
"Can't convert '" + $B.class_name($.sub) +
Mar 19, 2018
932
"' object to str implicitly")}
Mar 19, 2018
934
if($.start !== null){
Mar 19, 2018
936
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
937
else{_slice = _b_.slice.$factory($.start, $.self.length)}
str
Feb 10, 2018
938
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
Mar 19, 2018
940
if($.self.length + $.sub.length == 0){return 1}
Mar 19, 2018
942
if($.sub.length == 0){
943
if($.start == $.self.length){return 1}
944
else if(substr.length == 0){return 0}
945
return substr.length + 1
Mar 19, 2018
947
var n = 0,
948
pos = 0
949
while(pos < substr.length){
950
pos = substr.indexOf($.sub, pos)
951
if(pos >= 0){n++; pos += $.sub.length}
952
else{break}
Sep 5, 2014
953
}
954
return n
955
}
956
957
str.encode = function(){
958
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
959
["self", "encoding", "errors"], arguments,
960
{encoding: "utf-8", errors: "strict"}, null, null)
961
if($.encoding == "rot13" || $.encoding == "rot_13"){
962
// Special case : returns a string
Mar 19, 2018
963
var res = ""
964
for(var i = 0, len = $.self.length; i < len ; i++){
965
var char = $.self.charAt(i)
Mar 19, 2018
966
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
967
res += String.fromCharCode(String.charCodeAt(char) + 13)
968
}else if(("m" < char && char <= "z") ||
969
("M" < char && char <= "Z")){
970
res += String.fromCharCode(String.charCodeAt(char) - 13)
971
}else{res += char}
972
}
973
return res
974
}
975
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
Sep 5, 2014
976
}
977
str
Feb 10, 2018
978
str.endswith = function(){
979
// Return True if the string ends with the specified suffix, otherwise
980
// return False. suffix can also be a tuple of suffixes to look for.
981
// With optional start, test beginning at that position. With optional
Sep 5, 2014
982
// end, stop comparing at that position.
Mar 19, 2018
983
var $ = $B.args("endswith", 4,
984
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
985
["self", "suffix", "start", "end"],
986
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
987
988
normalize_start_end($)
989
990
var suffixes = $.suffix
Mar 19, 2018
991
if(! isinstance(suffixes,_b_.tuple)){suffixes = [suffixes]}
Mar 19, 2018
993
var s = $.self.substring($.start, $.end)
994
for(var i = 0, len = suffixes.length; i < len; i++){
995
var suffix = suffixes[i]
Mar 19, 2018
996
if(! _b_.isinstance(suffix, str)){throw _b_.TypeError.$factory(
Sep 20, 2015
997
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
998
if(suffix.length <= s.length &&
999
s.substr(s.length - suffix.length) == suffix){return true}
Sep 5, 2014
1000
}
1001
return false
1002
}
1003
str
Feb 10, 2018
1004
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
1005
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1006
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1007
var s = $B.$GetInt($.tabsize),
1008
col = 0,
1009
pos = 0,
1010
res = ""
1011
if(s == 1){return self.replace(/\t/g," ")}
1012
while(pos < self.length){
1013
var car = self.charAt(pos)
1014
switch(car){
Mar 19, 2018
1015
case "\t":
Mar 21, 2018
1016
while(col % s > 0){res += " "; col++}
Mar 19, 2018
1018
case "\r":
1019
case "\n":
1020
res += car
1021
col = 0
1022
break
1023
default:
1024
res += car
1025
col++
1026
break
1027
}
1028
pos++
1029
}
Sep 5, 2014
1032
}
1033
str
Feb 10, 2018
1034
str.find = function(){
1035
// Return the lowest index in the string where substring sub is found,
1036
// such that sub is contained in the slice s[start:end]. Optional
1037
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1038
// Return -1 if sub is not found.
Mar 19, 2018
1039
var $ = $B.args("str.find", 4,
1040
{self: null, sub: null, start: null, end: null},
1041
["self", "sub", "start", "end"],
1042
arguments, {start: 0, end: null}, null, null)
1043
check_str($.sub)
Mar 19, 2018
1046
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
1047
throw _b_.TypeError.$factory("slice indices must be " +
1048
"integers or None or have an __index__ method")}
1049
// Can't use string.substring(start, end) because if end < start,
1050
// Javascript transforms it into substring(end, start)...
1051
var s = ""
1052
for(var i = $.start; i < $.end; i++){
1053
s += $.self.charAt(i)
1054
}
Mar 19, 2018
1056
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1057
if(s.length + $.sub.length == 0){return -1}
Mar 19, 2018
1059
var last_search = s.length - $.sub.length
1060
for(var i = 0; i <= last_search; i++){
1061
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
Sep 5, 2014
1062
}
Sep 5, 2014
1064
}
1065
1066
// Next function used by method .format()
1067
1068
$B.parse_format = function(fmt_string){
Sep 5, 2014
1069
1070
// Parse a "format string", as described in the Python documentation
1071
// Return a format object. For the format string
1072
// a.x[z]!r:...
1073
// the object has attributes :
1074
// - name : "a"
1075
// - name_ext : [".x", "[z]"]
1076
// - conv : r
1077
// - spec : rest of string after :
Sep 5, 2014
1078
Mar 19, 2018
1079
var elts = fmt_string.split(":"),
1080
name,
1081
conv,
1082
spec,
Mar 19, 2018
1083
name_ext = []
Mar 19, 2018
1084
if(elts.length == 1){
1085
// No : in the string : it only contains a name
1086
name = fmt_string
1087
}else{
1088
// name is before the first ":"
1089
// spec (the format specification) is after
1090
name = elts[0]
Mar 19, 2018
1091
spec = elts.splice(1).join(":")
Mar 19, 2018
1094
var elts = name.split("!")
1095
if(elts.length > 1){
1096
name = elts[0]
1097
conv = elts[1] // conversion flag
Sep 5, 2014
1099
Mar 19, 2018
1100
if(name !== undefined){
1101
// "name' may be a subscription or attribute
1102
// Put these "extensions" in the list "name_ext"
1103
function name_repl(match){
1104
name_ext.push(match)
Mar 19, 2018
1105
return ""
1106
}
1107
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1108
name = name.replace(name_ext_re, name_repl)
1109
}
Sep 5, 2014
1110
1111
return {name: name, name_ext: name_ext,
1112
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1114
1115
$B.split_format = function(self){
1116
// Parse self to detect formatting instructions
1117
// Create a list "parts" made of sections of the string :
1118
// - elements of even rank are literal text
1119
// - elements of odd rank are "format objects", built from the
1120
// format strings in self (of the form {...})
Mar 19, 2018
1121
var pos = 0,
1122
_len = self.length,
Mar 19, 2018
1124
text = "",
1125
parts = [],
1126
rank = 0
1127
while(pos < _len){
1128
car = self.charAt(pos)
Mar 21, 2018
1129
if(car == "{" && self.charAt(pos + 1) == "{"){
1130
// replace {{ by literal {
Mar 19, 2018
1131
text += "{"
1132
pos += 2
1133
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1134
// replace }} by literal }
Mar 19, 2018
1135
text += "}"
1136
pos += 2
1137
}else if(car == "{"){
1138
// Start of a format string
1140
// Store current literal text
1141
parts.push(text)
1142
1143
// Search the end of the format string, ie the } closing the
1144
// opening {. Since the string can contain other pairs {} for
1145
// nested formatting, an integer nb is incremented for each { and
1146
// decremented for each } ; the end of the format string is
Mar 19, 2018
1147
// reached when nb == 0
1148
var end = pos + 1,
1149
nb = 1
1150
while(end < _len){
1151
if(self.charAt(end) == "{"){nb++; end++}
1152
else if(self.charAt(end) == "}"){
1153
nb--; end++
1154
if(nb == 0){
1155
// End of format string
Mar 19, 2018
1156
var fmt_string = self.substring(pos + 1, end - 1)
1157
1158
// Create a format object, by function parse_format
1159
var fmt_obj = $B.parse_format(fmt_string)
1160
fmt_obj.raw_name = fmt_obj.name
1161
fmt_obj.raw_spec = fmt_obj.spec
1162
1163
// If no name is explicitely provided, use the rank
1164
if(!fmt_obj.name){
Mar 19, 2018
1165
fmt_obj.name = rank + ""
Sep 5, 2014
1168
Mar 19, 2018
1169
if(fmt_obj.spec !== undefined){
1170
// "spec" may contain "nested replacement fields"
1171
// Replace empty fields by the rank in positional
1172
// arguments
1173
function replace_nested(name, key){
1174
if(key == ""){
1175
// Use implicit rank
1176
return "{" + rank++ + "}"
1180
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1181
replace_nested)
1182
}
1184
// Store format object in list "parts"
1185
parts.push(fmt_obj)
Mar 19, 2018
1186
text = ""
1187
break
1188
}
1189
}else{end++}
Sep 5, 2014
1190
}
Mar 19, 2018
1191
if(nb > 0){throw ValueError.$factory("wrong format " + self)}
Mar 19, 2018
1193
}else{text += car; pos++}
Sep 5, 2014
1194
}
1195
if(text){parts.push(text)}
1196
return parts
1197
}
1198
1199
str.format = function(self) {
1200
var $ = $B.args("format", 1, {self: null}, ["self"],
1201
arguments, {}, "$args", "$kw")
1202
1203
var parts = $B.split_format($.self)
1204
1205
// Apply formatting to the values passed to format()
Mar 19, 2018
1206
var res = "",
1207
fmt
Mar 19, 2018
1209
for(var i = 0; i < parts.length; i++){
1210
// Literal text is added unchanged
Mar 19, 2018
1211
if(typeof parts[i] == "string"){res += parts[i]; continue}
1213
// Format objects
1214
fmt = parts[i]
1215
1216
if(fmt.spec !== undefined){
1217
// "spec" may contain "nested replacement fields"
1218
// In this case, evaluate them using the positional
1219
// or keyword arguments passed to format()
1220
function replace_nested(name, key){
1221
if(/\d+/.exec(key)){
1222
// If key is numeric, search in positional
1223
// arguments
1224
return _b_.tuple.__getitem__($.$args,
1225
parseInt(key))
1226
}else{
1227
// Else try in keyword arguments
1228
return _b_.dict.__getitem__($.$kw, key)
1229
}
1230
}
1231
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1232
replace_nested)
1233
}
Mar 21, 2018
1234
if(fmt.name.charAt(0).search(/\d/) > -1){
1235
// Numerical reference : use positional arguments
1236
var pos = parseInt(fmt.name),
Feb 11, 2018
1237
value = _b_.tuple.__getitem__($.$args, pos)
1238
}else{
1239
// Use keyword arguments
Feb 11, 2018
1240
var value = _b_.dict.__getitem__($.$kw, fmt.name)
1241
}
1242
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1243
for(var j = 0; j < fmt.name_ext.length; j++){
1244
var ext = fmt.name_ext[j]
Mar 19, 2018
1245
if(ext.charAt(0) == "."){
1246
// Attribute
1247
value = _b_.getattr(value, ext.substr(1))
1248
}else{
1249
// Subscription
Mar 19, 2018
1250
var key = ext.substr(1, ext.length - 2)
1251
// An index made of digits is transformed into an integer
Mar 19, 2018
1252
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1253
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1256
1257
// If the conversion flag is set, first call a function to convert
1258
// the value
Mar 19, 2018
1259
if(fmt.conv == "a"){value = _b_.ascii(value)}
1260
else if(fmt.conv == "r"){value = _b_.repr(value)}
1261
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1263
// Call attribute __format__ to perform the actual formatting
1264
if(value.$is_class || value.$factory){
1265
// For classes, don't use the class __format__ method
1266
res += value.__class__.__format__(value, fmt.spec)
1268
res += $B.$getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1270
}
Sep 5, 2014
1272
}
1273
str
Feb 10, 2018
1274
str.format_map = function(self) {
Mar 19, 2018
1275
throw NotImplementedError.$factory(
1276
"function format_map not implemented yet")
Sep 5, 2014
1277
}
1278
str
Feb 10, 2018
1279
str.index = function(self){
Sep 5, 2014
1280
// Like find(), but raise ValueError when the substring is not found.
1281
var res = str.find.apply(null, arguments)
Mar 19, 2018
1282
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1283
return res
1284
}
1285
1286
str.isascii = function(self){
1287
/* Return true if the string is empty or all characters in the string are
1288
ASCII, false otherwise. ASCII characters have code points in the range
1289
U+0000-U+007F. */
1290
for(var i = 0, len = self.length; i < len; i++){
1291
if(self.charCodeAt(i) > 127){return false}
1292
}
1293
return true
1294
}
1295
1296
str.isalnum = function(self){
1297
/* Return true if all characters in the string are alphanumeric and there
1298
is at least one character, false otherwise. A character c is alphanumeric
1299
if one of the following returns True: c.isalpha(), c.isdecimal(),
1300
c.isdigit(), or c.isnumeric(). */
1301
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1302
arguments, {}, null, null),
1303
char
1304
for(var i = 0, len = self.length; i < len; i++){
1305
char = self.charCodeAt(i)
1306
if(unicode_tables.Ll[char] ||
1307
unicode_tables.Lu[char] ||
1308
unicode_tables.Lm[char] ||
1309
unicode_tables.Lt[char] ||
1310
unicode_tables.Lo[char] ||
1311
unicode_tables.Nd[char] ||
1312
unicode_tables.digits[char] ||
1313
unicode_tables.numeric[char]){
1314
continue
1315
}
1316
return false
1317
}
1318
return true
1319
}
1320
1321
str.isalpha = function(self){
1322
/* Return true if all characters in the string are alphabetic and there is
1323
at least one character, false otherwise. Alphabetic characters are those
1324
characters defined in the Unicode character database as "Letter", i.e.,
1325
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1326
or "Lo". */
1327
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1328
arguments, {}, null, null),
1329
char
1330
for(var i = 0, len = self.length; i < len; i++){
1331
char = self.charCodeAt(i)
1332
if(unicode_tables.Ll[char] ||
1333
unicode_tables.Lu[char] ||
1334
unicode_tables.Lm[char] ||
1335
unicode_tables.Lt[char] ||
1336
unicode_tables.Lo[char]){
1337
continue
1338
}
1339
return false
1340
}
1341
return true
1342
}
1343
1344
str.isdecimal = function(self){
1345
/* Return true if all characters in the string are decimal characters and
1346
there is at least one character, false otherwise. Decimal characters are
1347
those that can be used to form numbers in base 10, e.g. U+0660,
1348
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1349
the Unicode General Category "Nd". */
1350
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1351
arguments, {}, null, null),
1352
char
1353
for(var i = 0, len = self.length; i < len; i++){
1354
char = self.charCodeAt(i)
1355
if(! unicode_tables.Nd[char]){
1356
return false
1357
}
1358
}
1359
return self.length > 0
1360
}
1361
1362
str.isdigit = function(self){
1363
/* Return true if all characters in the string are digits and there is at
1364
least one character, false otherwise. */
1365
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1366
arguments, {}, null, null),
1367
char
1368
for(var i = 0, len = self.length; i < len; i++){
1369
char = self.charCodeAt(i)
1370
if(! unicode_tables.digits[char]){
1371
return false
1372
}
1373
}
1374
return self.length > 0
1375
}
1376
1377
str.isidentifier = function(self){
1378
/* Return true if the string is a valid identifier according to the
1379
language definition. */
1380
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1381
arguments, {}, null, null),
1382
char
1383
if(self.length == 0){return false}
1384
else if(unicode_tables.XID_Start[self.charCodeAt(0)] === undefined){
1385
return false
1386
}else{
1387
for(var i = 1, len = self.length; i < len; i++){
1388
if(unicode_tables.XID_Continue[self.charCodeAt(i)] === undefined){
1389
return false
1390
}
1391
}
1392
}
1393
return true
1394
}
1395
1396
str.islower = function(self){
1397
/* Return true if all cased characters 4 in the string are lowercase and
1398
there is at least one cased character, false otherwise. */
1399
var $ = $B.args("islower", 1, {self: null}, ["self"],
1400
arguments, {}, null, null),
1401
has_cased = false,
1402
char
1403
1404
for(var i = 0, len = self.length; i < len; i++){
1405
char = self.charCodeAt(i)
1406
if(unicode_tables.Ll[char]){has_cased = true; continue}
1407
else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1408
return false
1409
}
1410
}
1411
return has_cased
1412
}
1413
1414
str.isnumeric = function(self){
1415
/* Return true if all characters in the string are numeric characters, and
1416
there is at least one character, false otherwise. Numeric characters
1417
include digit characters, and all characters that have the Unicode numeric
1418
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1419
characters are those with the property value Numeric_Type=Digit,
1420
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1421
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1422
arguments, {}, null, null)
1423
for(var i = 0, len = self.length; i < len; i++){
1424
if(! unicode_tables.numeric[self.charCodeAt(i)]){
1425
return false
1426
}
1427
}
1428
return self.length > 0
1429
}
1430
1431
var printable,
1432
printable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1433
1434
str.isprintable = function(self){
1435
/* Return true if all characters in the string are printable or the string
1436
is empty, false otherwise. Nonprintable characters are those characters
1437
defined in the Unicode character database as "Other" or "Separator",
1438
excepting the ASCII space (0x20) which is considered printable. */
1439
1440
// Set printable if not set yet
1441
if(printable === undefined){
1442
for(var i = 0; i < printable_gc.length; i++){
1443
var table = unicode_tables[printable_gc[i]]
1444
for(var cp in table){
1445
printable[cp] = true
1446
}
1447
}
1448
printable[32] = true
1449
}
1450
1451
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1452
arguments, {}, null, null),
1453
char,
1454
flag
1455
for(var i = 0, len = self.length; i < len; i++){
1456
char = self.charCodeAt(i)
1457
if(! printable[char]){
1458
return false
1459
}
1460
}
1461
return true
1462
}
1463
1464
str.isspace = function(self){
1465
/* Return true if there are only whitespace characters in the string and
1466
there is at least one character, false otherwise.
1467
1468
A character is whitespace if in the Unicode character database, either its
1469
general category is Zs ("Separator, space"), or its bidirectional class is
1470
one of WS, B, or S.*/
1471
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1472
arguments, {}, null, null),
1473
char
1474
for(var i = 0, len = self.length; i < len; i++){
1475
char = self.charCodeAt(i)
1476
if(! unicode_tables.Zs[char] &&
1477
$B.unicode_bidi_whitespace.indexOf(char) == -1){
1478
return false
1479
}
1480
}
1481
return self.length > 0
1482
}
1483
1484
str.istitle = function(self){
1485
/* Return true if the string is a titlecased string and there is at least
1486
one character, for example uppercase characters may only follow uncased
1487
characters and lowercase characters only cased ones. Return false
1488
otherwise. */
1489
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1490
arguments, {}, null, null)
1491
return self.length > 0 && str.title(self) == self
1492
}
1493
1494
str.isupper = function(self){
1495
/* Return true if all cased characters 4 in the string are lowercase and
1496
there is at least one cased character, false otherwise. */
1497
var $ = $B.args("islower", 1, {self: null}, ["self"],
1498
arguments, {}, null, null),
1499
has_cased = false,
1500
char
1501
1502
for(var i = 0, len = self.length; i < len; i++){
1503
char = self.charCodeAt(i)
1504
if(unicode_tables.Lu[char]){has_cased = true; continue}
1505
else if(unicode_tables.Ll[char] || unicode_tables.Lt[char]){
1506
return false
1507
}
1508
}
1509
return has_cased
1510
}
1511
1512
str
Feb 10, 2018
1513
str.join = function(){
Mar 19, 2018
1514
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1515
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1517
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1518
res = [],
Sep 5, 2014
1520
while(1){
1521
try{
1522
var obj2 = _b_.next(iterable)
Mar 19, 2018
1523
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1524
"sequence item " + count + ": expected str instance, " +
1525
$B.class_name(obj2) + " found")}
1526
res.push(obj2)
Sep 5, 2014
1527
}catch(err){
1528
if(_b_.isinstance(err, _b_.StopIteration)){
1529
break
1530
}
Sep 5, 2014
1531
else{throw err}
1532
}
1533
}
1534
return res.join($.self)
Sep 5, 2014
1535
}
1536
str
Feb 10, 2018
1537
str.ljust = function(self) {
Mar 19, 2018
1538
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1539
["self", "width", "fillchar"],
1540
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1542
if($.width <= self.length){return self}
1543
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1544
}
1545
1546
str.lower = function(self){
1547
var $ = $B.args("lower", 1, {self: null}, ["self"],
1548
arguments, {}, null, null)
1549
return self.toLowerCase()
1550
}
1551
str
Feb 10, 2018
1552
str.lstrip = function(self,x){
Mar 19, 2018
1553
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1554
arguments, {chars:_b_.None}, null, null)
1555
if($.chars === _b_.None){return $.self.trimLeft()}
1556
for(var i = 0; i < $.self.length; i++){
1557
if($.chars.indexOf($.self.charAt(i)) === -1){
1558
return $.self.substring(i)
Mar 19, 2018
1561
return ""
Sep 5, 2014
1562
}
1563
1564
// note, maketrans should be a static function.
str
Feb 10, 2018
1565
str.maketrans = function() {
Mar 19, 2018
1566
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1567
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1569
var _t = _b_.dict.$factory()
Mar 19, 2018
1571
if($.y === null && $.z === null){
1572
// If there is only one argument, it must be a dictionary mapping
1573
// Unicode ordinals (integers) or characters (strings of length 1) to
1574
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1575
// keys will then be converted to ordinals.
Mar 19, 2018
1576
if(! _b_.isinstance($.x, _b_.dict)){
1577
throw _b_.TypeError.$factory(
1578
"maketrans only argument must be a dict")
Feb 11, 2018
1580
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1581
for(var i = 0, len = items.length; i < len; i++){
1582
var k = items[i][0],
1583
v = items[i][1]
1584
if(! _b_.isinstance(k, _b_.int)){
1585
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1586
k = _b_.ord(k)
1587
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1588
" is not int or 1-char string")}
1589
}
Mar 19, 2018
1590
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1591
throw _b_.TypeError.$factory("dictionary value " + v +
1592
" is not None, integer or string")
1593
}
1594
_b_.dict.$setitem(_t, k, v)
1595
}
1596
return _t
1597
}else{
1598
// If there are two arguments, they must be strings of equal length,
1599
// and in the resulting dictionary, each character in x will be mapped
1600
// to the character at the same position in y
Mar 19, 2018
1601
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1602
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1603
}else if($.x.length !== $.y.length){
1604
throw _b_.TypeError.$factory(
1605
"maketrans arguments must be strings or same length")
1606
}else{
1607
var toNone = {}
Mar 19, 2018
1608
if($.z !== null){
1609
// If there is a third argument, it must be a string, whose
1610
// characters will be mapped to None in the result
Mar 19, 2018
1611
if(! _b_.isinstance($.z, _b_.str)){
1612
throw _b_.TypeError.$factory(
1613
"maketrans third argument must be a string")
Mar 19, 2018
1615
for(var i = 0, len = $.z.length; i < len; i++){
1616
toNone[_b_.ord($.z.charAt(i))] = true
1617
}
Mar 19, 2018
1619
for(var i = 0, len = $.x.length; i < len; i++){
1620
var key = _b_.ord($.x.charAt(i)),
1622
_b_.dict.$setitem(_t, key, value)
1623
}
1624
for(var k in toNone){
1625
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1626
}
1627
return _t
1628
}
1629
}
Sep 5, 2014
1630
}
1631
1632
str.maketrans.$type = "staticmethod"
1633
str
Feb 10, 2018
1634
str.partition = function() {
Mar 19, 2018
1635
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1636
arguments, {}, null, null)
Mar 19, 2018
1637
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1638
check_str($.sep)
1639
var i = $.self.indexOf($.sep)
Mar 23, 2018
1640
if(i == -1){return _b_.tuple.$factory([$.self, "", ""])}
Mar 19, 2018
1641
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1642
$.self.substring(i + $.sep.length)])
1643
}
1644
1645
str.removeprefix = function(){
1646
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1647
["self", "prefix"], arguments, {}, null, null)
1648
if(!_b_.isinstance($.prefix, str)){
1649
throw _b_.ValueError.$factory("prefix should be str, not " +
1650
`'${$B.class_name($.prefix)}'`)
1651
}
1652
if(str.startswith($.self, $.prefix)){
1653
return $.self.substr($.prefix.length)
1654
}
1655
return $.self.substr(0)
1656
}
1657
1658
str.removesuffix = function(){
1659
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1660
["self", "suffix"], arguments, {}, null, null)
1661
if(!_b_.isinstance($.suffix, str)){
1662
throw _b_.ValueError.$factory("suffix should be str, not " +
1663
`'${$B.class_name($.prefix)}'`)
1664
}
1665
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1666
return $.self.substr(0, $.self.length - $.suffix.length)
1667
}
1668
return $.self.substr(0)
1669
}
1670
Mar 19, 2018
1671
function $re_escape(str){
1672
var specials = "[.*+?|()$^"
1673
for(var i = 0, len = specials.length; i < len; i++){
1674
var re = new RegExp("\\"+specials.charAt(i), "g")
1675
str = str.replace(re, "\\"+specials.charAt(i))
1676
}
1677
return str
Sep 5, 2014
1678
}
1679
str
Feb 10, 2018
1680
str.replace = function(self, old, _new, count) {
1681
// Replaces occurrences of 'old' by '_new'. Count references
1682
// the number of times to replace. In CPython, negative or undefined
1683
// values of count means replace all.
Mar 19, 2018
1684
var $ = $B.args("replace", 4,
1685
{self: null, old: null, $$new: null, count: null},
1686
["self", "old", "$$new", "count"],
1687
arguments, {count: -1}, null, null),
1688
count = $.count,
1689
self = $.self,
1690
old = $.old,
1691
_new = $.$$new
1692
// Validate type of old
1693
check_str(old)
1694
check_str(_new)
1695
// Validate instance type of 'count'
Mar 23, 2018
1696
if(! isinstance(count,[_b_.int, _b_.float])){
1697
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1698
"' object cannot be interpreted as an integer")
1699
}else if(isinstance(count, _b_.float)){
1700
throw _b_.TypeError.$factory("integer argument expected, got float")
1701
}
1702
if(count == 0){return self}
1703
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1704
if(old == ""){
1705
if(_new == ""){return self}
1706
if(self == ""){return _new}
1707
var elts = self.split("")
1708
if(count > -1 && elts.length >= count){
1709
var rest = elts.slice(count).join("")
1710
return _new + elts.slice(0, count).join(_new) + rest
1711
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1713
var elts = str.split(self, old, count)
Sep 5, 2014
1714
}
Mar 19, 2018
1716
var res = self,
1717
pos = -1
1718
if(old.length == 0){
Mar 19, 2018
1720
for(var i = 0; i < elts.length; i++){
1721
res += elts[i] + _new
Mar 19, 2018
1723
return res + rest
Mar 19, 2018
1726
if(count < 0){count = res.length}
1727
while(count > 0){
1728
pos = res.indexOf(old, pos)
1729
if(pos < 0){break}
1730
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1731
pos = pos + _new.length
1732
count--
Mar 19, 2018
1734
return res
Sep 5, 2014
1735
}
1736
1737
str.rfind = function(self, substr){
1738
// Return the highest index in the string where substring sub is found,
1739
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1740
// start and end are interpreted as in slice notation. Return -1 on failure.
1741
if(arguments.length == 2 && typeof substr == "string"){
1742
return self.lastIndexOf(substr)
1743
}
Mar 19, 2018
1744
var $ = $B.args("rfind", 4,
Mar 19, 2018
1745
{self: null, sub: null, start: null, end: null},
1746
["self", "sub", "start", "end"],
1747
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1748
1751
check_str($.sub)
Mar 19, 2018
1753
if($.sub.length == 0){
1754
if($.start > $.self.length){return -1}
1755
else{return $.self.length}
1756
}
1757
var sublen = $.sub.length
Mar 19, 2018
1759
for(var i = $.end - sublen; i >= $.start; i--){
1760
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1763
}
1764
str
Feb 10, 2018
1765
str.rindex = function(){
Sep 5, 2014
1766
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1767
var res = str.rfind.apply(null, arguments)
1768
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1769
return res
1770
}
1771
str
Feb 10, 2018
1772
str.rjust = function(self) {
Mar 19, 2018
1773
var $ = $B.args("rjust",3,
1774
{self: null, width: null, fillchar: null},
1775
["self", "width", "fillchar"],
1776
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1777
Mar 19, 2018
1778
if($.width <= self.length){return self}
Sep 5, 2014
1779
1780
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1781
}
1782
str
Feb 10, 2018
1783
str.rpartition = function(self,sep) {
Mar 19, 2018
1784
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1785
arguments, {}, null, null)
1786
check_str($.sep)
1787
var self = reverse($.self),
1788
sep = reverse($.sep)
Mar 19, 2018
1789
var items = str.partition(self, sep).reverse()
1790
for(var i = 0; i < items.length; i++){
1791
items[i] = items[i].split("").reverse().join("")
1792
}
1793
return items
Sep 5, 2014
1794
}
1795
str
Feb 10, 2018
1796
str.rsplit = function(self) {
Mar 19, 2018
1797
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1798
["self", "sep", "maxsplit"], arguments,
1799
{sep: _b_.None, maxsplit: -1}, null, null),
1800
sep = $.sep
1801
1802
// Use split on the reverse of the string and of separator
1803
var rev_str = reverse($.self),
1804
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1805
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1807
// Reverse the list, then each string inside the list
1808
rev_res.reverse()
Mar 19, 2018
1809
for(var i = 0; i < rev_res.length; i++){
1810
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1813
}
1814
Mar 19, 2018
1815
str.rstrip = function(self, x){
1816
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1817
arguments, {chars: _b_.None}, null, null)
1818
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1819
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1820
if($.chars.indexOf($.self.charAt(j)) == -1){
1821
return $.self.substring(0, j + 1)
Mar 19, 2018
1824
return ""
Sep 5, 2014
1825
}
1826
str
Feb 10, 2018
1827
str.split = function(){
Mar 19, 2018
1828
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1829
["self", "sep", "maxsplit"], arguments,
1830
{sep: _b_.None, maxsplit: -1}, null, null),
1831
sep = $.sep,
1832
maxsplit = $.maxsplit,
1833
self = $.self,
1834
pos = 0
1835
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1836
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1837
if(sep === _b_.None){
Sep 5, 2014
1838
var res = []
Mar 19, 2018
1839
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1840
if(pos === self.length - 1){return [self]}
1841
var name = ""
Sep 5, 2014
1842
while(1){
Mar 19, 2018
1843
if(self.charAt(pos).search(/\s/) == -1){
1844
if(name == ""){name = self.charAt(pos)}
1845
else{name += self.charAt(pos)}
Sep 5, 2014
1846
}else{
Mar 19, 2018
1847
if(name !== ""){
Sep 5, 2014
1848
res.push(name)
Mar 19, 2018
1849
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1850
res.pop()
Mar 19, 2018
1851
res.push(name + self.substr(pos))
Sep 5, 2014
1852
return res
1853
}
Mar 19, 2018
1854
name = ""
Sep 5, 2014
1855
}
1856
}
1857
pos++
Mar 19, 2018
1858
if(pos > self.length - 1){
Sep 5, 2014
1859
if(name){res.push(name)}
1860
break
1861
}
1862
}
1863
return res
1864
}else{
Mar 19, 2018
1865
var res = [],
1866
s = "",
1867
seplen = sep.length
1868
if(maxsplit == 0){return [self]}
1869
while(pos < self.length){
1870
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1873
if(maxsplit > -1 && res.length >= maxsplit){
1874
res.push(self.substr(pos))
1875
return res
1876
}
Mar 19, 2018
1877
s = ""
1878
}else{
1879
s += self.charAt(pos)
1880
pos++
Sep 5, 2014
1881
}
1882
}
Sep 5, 2014
1885
}
1886
}
1887
1888
str.splitlines = function(self) {
1889
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
1890
['self','keepends'], arguments, {keepends: false},
1891
null, null)
1892
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
1893
throw _b_.TypeError('integer argument expected, got '+
1894
$B.get_class($.keepends).__name)
1895
}
1896
var keepends = _b_.int.$factory($.keepends),
1897
res = [],
1898
self = $.self,
1899
start = 0,
1900
pos = 0
1901
if(!self.length){
1902
return res
1903
}
1904
while (pos < self.length) {
1905
if(self.substr(pos, 2) == '\r\n'){
1906
res.push(self.slice(start, keepends ? pos + 2 : pos))
1907
start = pos = pos+2
1908
}else if(self[pos] == '\r' || self[pos] == '\n'){
1909
res.push(self.slice(start, keepends ? pos+1 : pos))
1910
start = pos = pos+1
1911
}else{
1912
pos++
1913
}
1914
}
1915
if(start < self.length){
1916
res.push(self.slice(start))
1917
}
1918
return res
1919
}
Sep 5, 2014
1920
str
Feb 10, 2018
1921
str.startswith = function(){
1922
// Return True if string starts with the prefix, otherwise return False.
1923
// prefix can also be a tuple of prefixes to look for. With optional
1924
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1925
// stop comparing string at that position.
Mar 19, 2018
1926
var $ = $B.args("startswith", 4,
1927
{self: null, prefix: null, start: null, end: null},
1928
["self", "prefix", "start", "end"],
1929
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1930
1931
normalize_start_end($)
1932
1933
var prefixes = $.prefix
Mar 19, 2018
1934
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1936
var s = $.self.substring($.start, $.end)
1937
for(var i = 0, len = prefixes.length; i < len; i++){
1938
var prefix = prefixes[i]
Mar 19, 2018
1939
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1940
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1941
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1942
}
1943
return false
1944
Sep 5, 2014
1945
}
1946
str
Feb 10, 2018
1947
str.strip = function(){
Mar 19, 2018
1948
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1949
arguments, {chars: _b_.None}, null, null)
1950
if($.chars === _b_.None){return $.self.trim()}
1951
for(var i = 0; i < $.self.length; i++){
1952
if($.chars.indexOf($.self.charAt(i)) == -1){
1953
break
Mar 19, 2018
1956
for(var j = $.self.length - 1; j >= i; j--){
1957
if($.chars.indexOf($.self.charAt(j)) == -1){
1958
break
Mar 19, 2018
1961
return $.self.substring(i, j + 1)
Sep 5, 2014
1962
}
1963
1964
str.swapcase = function(self){
1965
var $ = $B.args("swapcase", 1, {self}, ["self"],
1966
arguments, {}, null, null),
1967
res = "",
1968
char
1969
1970
for(var i = 0, len = self.length; i < len; i++){
1971
char = self.charCodeAt(i)
1972
if(unicode_tables.Ll[char]){
1973
res += self.charAt(i).toUpperCase()
1974
}else if(unicode_tables.Lu[char]){
1975
res += self.charAt(i).toLowerCase()
1976
}else{
1977
res += self.charAt(i)
1978
}
1979
}
1980
return res
1981
}
1982
1983
str.title = function(self){
1984
var $ = $B.args("title", 1, {self}, ["self"],
1985
arguments, {}, null, null),
1986
state,
1987
char,
1988
res = ""
1989
for(var i = 0, len = self.length; i < len; i++){
1990
char = self.charCodeAt(i)
1991
if(unicode_tables.Ll[char]){
1992
if(! state){
1993
res += self.charAt(i).toUpperCase()
1994
state = "word"
1995
}else{
1996
res += self.charAt(i)
1997
}
1998
}else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1999
res += state ? self.charAt(i).toLowerCase() : self.charAt(i)
2000
state = "word"
2001
}else{
2002
state = null
2003
res += self.charAt(i)
2004
}
2005
}
2006
return res
2007
}
2008
2009
str.translate = function(self, table){
Mar 19, 2018
2010
var res = [],
2011
getitem = $B.$getattr(table, "__getitem__")
2012
for(var i = 0, len = self.length; i < len; i++){
2013
try{
2014
var repl = getitem(self.charCodeAt(i))
2015
if(repl !== _b_.None){
2016
if(typeof repl == "string"){
2017
res.push(repl)
2018
}else if(typeof repl == "number"){
2019
res.push(String.fromCharCode(repl))
2020
}
2021
}
2022
}catch(err){
2023
res.push(self.charAt(i))
2024
}
Sep 5, 2014
2025
}
Mar 19, 2018
2026
return res.join("")
Sep 5, 2014
2027
}
2028
2029
str.upper = function(self){
2030
var $ = $B.args("upper", 1, {self: null}, ["self"],
2031
arguments, {}, null, null)
2032
return self.toUpperCase()
2033
}
2034
Mar 19, 2018
2035
str.zfill = function(self, width){
Mar 19, 2018
2036
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
2037
["self", "width"], arguments, {}, null, null)
2038
if($.width <= self.length){return self}
Mar 19, 2018
2040
case "+":
2041
case "-":
2042
return self.charAt(0) +
2043
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
2045
return "0".repeat(width - self.length) + self
Sep 5, 2014
2047
}
2048
2049
str.$factory = function(arg, encoding, errors){
2050
if(arguments.length == 0){return ""}
2052
return $B.UndefinedClass.__str__()
2054
if(encoding !== undefined){
2055
// Arguments may be passed as keywords (cf. issue #1060)
2056
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2057
["arg", "encoding", "errors"], arguments,
2058
{encoding: "utf-8", errors: "strict"}, null, null),
2059
encoding = $.encoding,
2060
errors = $.errors
2061
}
2062
switch(typeof arg) {
Mar 19, 2018
2063
case "string":
Mar 27, 2019
2064
return str.__str__(arg)
Mar 19, 2018
2065
case "number":
2066
if(isFinite(arg)){return arg.toString()}
2069
if(arg.$is_class || arg.$factory){
2070
// arg is a class
2071
// In this case, str() doesn't use the attribute __str__ of the
2072
// class or its subclasses, but the attribute __str__ of the
2073
// class metaclass (usually "type") or its subclasses (usually
2074
// "object")
2075
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
2076
var func = $B.$getattr(arg.__class__, "__str__")
2078
}
2080
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2081
encoding !== undefined){
2082
// str(bytes, encoding, errors) is equal to
2083
// bytes.decode(encoding, errors)
2084
return _b_.bytes.decode(arg, $.encoding, $.errors)
2086
// Implicit invocation of __str__ uses method __str__ on the class,
2087
// even if arg has an attribute __str__
2088
var klass = arg.__class__ || $B.get_class(arg)
2089
if(klass === undefined){
2090
return $B.JSObject.__str__($B.JSObject.$factory(arg))
2091
}
2092
var method = $B.$getattr(klass , "__str__", null)
2093
if(method === null ||
2094
// if not better than object.__str__, try __repr__
2095
(arg.__class__ && arg.__class__ !== _b_.object &&
2096
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2097
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2099
}
2100
catch(err){
2101
console.log("no __str__ for", arg)
Mar 19, 2018
2102
console.log("err ", err)
2103
if($B.debug > 1){console.log(err)}
2104
console.log("Warning - no method __str__ or __repr__, " +
2105
"default to toString", arg)
May 20, 2019
2106
throw err
Sep 5, 2014
2107
}
2108
return $B.$call(method)(arg)
Sep 5, 2014
2109
}
str
Feb 10, 2018
2110
2111
str.__new__ = function(cls){
Mar 19, 2018
2112
if(cls === undefined){
2113
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2114
}
Mar 19, 2018
2115
return {__class__: cls}
Sep 5, 2014
2116
}
2117
str
Feb 10, 2018
2118
$B.set_func_names(str, "builtins")
Sep 5, 2014
2120
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2121
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2122
__class__: _b_.type,
str
Feb 10, 2018
2123
__mro__: [object],
2124
$infos: {
2125
__module__: "builtins",
2126
__name__: "str"
2127
},
str
Feb 10, 2018
2128
$is_class: true
Sep 5, 2014
2129
}
2130
str
Feb 10, 2018
2131
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2132
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2133
for(var $attr in str){
Mar 19, 2018
2134
if(typeof str[$attr] == "function"){
Mar 19, 2018
2135
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2136
return function(){
Mar 19, 2018
2137
var args = [],
2138
pos = 0
2139
if(arguments.length > 0){
2140
var args = [arguments[0].valueOf()],
2141
pos = 1
2142
for(var i = 1, len = arguments.length; i < len; i++){
2143
args[pos++] = arguments[i]
Sep 5, 2014
2144
}
2145
}
Mar 19, 2018
2146
return str[attr].apply(null, args)
Sep 5, 2014
2147
}
2148
})($attr)
2149
}
2150
}
str
Feb 10, 2018
2151
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2154
str
Feb 10, 2018
2155
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2157
_b_.str = str
2158
2159
// Function to parse the 2nd argument of format()
2160
$B.parse_format_spec = function(spec){
Mar 19, 2018
2161
if(spec == ""){this.empty = true}
2162
else{
Mar 19, 2018
2163
var pos = 0,
2164
aligns = "<>=^",
2165
digits = "0123456789",
2166
types = "bcdeEfFgGnosxX%",
2167
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2168
if(align_pos != -1){
2169
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2170
// If the second char is also an alignment specifier, the
2171
// first char is the fill value
2172
this.fill = spec.charAt(0)
2173
this.align = spec.charAt(1)
2174
pos = 2
2175
}else{
2176
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2177
this.align = aligns[align_pos]
2178
this.fill = " "
2179
pos++
2180
}
2181
}else{
2182
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2183
if(spec.charAt(1) && align_pos != -1){
2184
// The second character defines alignment : fill is the first one
Mar 19, 2018
2185
this.align = aligns[align_pos]
2186
this.fill = spec.charAt(0)
2187
pos = 2
2188
}
2189
}
2190
var car = spec.charAt(pos)
Mar 19, 2018
2191
if(car == "+" || car == "-" || car == " "){
2192
this.sign = car
2193
pos++
2194
car = spec.charAt(pos)
Mar 19, 2018
2196
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
2197
if(car == "0"){
Mar 19, 2018
2198
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2199
this.fill = "0"
2200
if(align_pos == -1){
2201
this.align = "="
2202
}
Mar 19, 2018
2203
pos++
2204
car = spec.charAt(pos)
2205
}
Mar 19, 2018
2206
while(car && digits.indexOf(car) > -1){
2207
if(this.width === undefined){this.width = car}
2208
else{this.width += car}
2209
pos++
2210
car = spec.charAt(pos)
Mar 19, 2018
2212
if(this.width !== undefined){this.width = parseInt(this.width)}
2213
if(this.width === undefined && car == "{"){
2214
// Width is determined by a parameter
2215
var end_param_pos = spec.substr(pos).search("}")
2216
this.width = spec.substring(pos, end_param_pos)
2217
console.log("width", "[" + this.width + "]")
2218
pos += end_param_pos + 1
2219
}
Mar 19, 2018
2220
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
2221
if(car == "."){
2222
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2223
throw _b_.ValueError.$factory(
2224
"Missing precision in format spec")
Mar 19, 2018
2226
this.precision = spec.charAt(pos + 1)
2227
pos += 2
2228
car = spec.charAt(pos)
2229
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2230
this.precision += car
Mar 19, 2018
2231
pos++
2232
car = spec.charAt(pos)
2233
}
2234
this.precision = parseInt(this.precision)
2235
}
Mar 19, 2018
2236
if(car && types.indexOf(car) > -1){
2237
this.type = car
2238
pos++
2239
car = spec.charAt(pos)
2240
}
2241
if(pos !== spec.length){
2242
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2246
this.toString = function(){
Mar 19, 2018
2247
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2248
(this.align || "") +
2249
(this.sign || "") +
2250
(this.alternate ? "#" : "") +
2251
(this.sign_aware ? "0" : "") +
2252
(this.width || "") +
2253
(this.comma ? "," : "") +
2254
(this.precision ? "." + this.precision : "") +
2255
(this.type || "")
2256
}
2257
}
2258
2259
$B.format_width = function(s, fmt){
Mar 19, 2018
2260
if(fmt.width && s.length < fmt.width){
2261
var fill = fmt.fill || " ",
2262
align = fmt.align || "<",
2263
missing = fmt.width - s.length
2264
switch(align){
Mar 19, 2018
2265
case "<":
2266
return s + fill.repeat(missing)
2267
case ">":
2268
return fill.repeat(missing) + s
2269
case "=":
2270
if("+-".indexOf(s.charAt(0)) > -1){
2271
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2272
}else{
Mar 19, 2018
2273
return fill.repeat(missing) + s
Mar 19, 2018
2275
case "^":
2276
var left = parseInt(missing / 2)
2277
return fill.repeat(left) + s + fill.repeat(missing - left)
2278
}
2279
}
2280
return s
2281
}
2282
2283
function fstring_expression(){
Mar 19, 2018
2284
this.type = "expression"
2285
this.expression = ""
2286
this.conversion = null
2287
this.fmt = null
2288
}
2289
2290
$B.parse_fstring = function(string){
2291
// Parse a f-string
2292
var elts = [],
2293
pos = 0,
Mar 19, 2018
2294
current = "",
2295
ctype = null,
2296
nb_braces = 0,
2297
car
2298
Mar 19, 2018
2299
while(pos < string.length){
2300
if(ctype === null){
2301
car = string.charAt(pos)
Mar 19, 2018
2302
if(car == "{"){
Mar 21, 2018
2303
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2304
ctype = "string"
2305
current = "{"
2306
pos += 2
2307
}else{
Mar 19, 2018
2308
ctype = "expression"
2309
nb_braces = 1
2310
pos++
2311
}
Mar 19, 2018
2312
}else if(car == "}"){
Mar 21, 2018
2313
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2314
ctype = "string"
2315
current = "}"
2316
pos += 2
2317
}else{
2318
throw Error(" f-string: single '}' is not allowed")
2319
}
2320
}else{
Mar 19, 2018
2321
ctype = "string"
2322
current = car
2323
pos++
Mar 19, 2018
2325
}else if(ctype == "string"){
2326
// end of string is the first single { or end of string
Mar 19, 2018
2327
var i = pos
2328
while(i < string.length){
2329
car = string.charAt(i)
Mar 19, 2018
2330
if(car == "{"){
Mar 21, 2018
2331
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2332
current += "{"
2333
i += 2
2334
}else{
2335
elts.push(current)
Mar 19, 2018
2336
ctype = "expression"
2337
pos = i + 1
2338
break
2339
}
Mar 19, 2018
2340
}else if(car == "}"){
2341
if(string.charAt(i + 1) == car){
2342
current += car
2343
i += 2
2344
}else{
2345
throw Error(" f-string: single '}' is not allowed")
2346
}
2347
}else{
2348
current += car
2349
i++
2350
}
2351
}
Mar 19, 2018
2352
pos = i + 1
2353
}else if(ctype == "debug"){
2354
// after the equal sign, whitespace are ignored and the only
2355
// valid characters are } and :
2356
while(string.charAt(i) == " "){i++}
2357
if(string.charAt(i) == "}"){
2358
// end of debug expression
2359
elts.push(current)
2360
ctype = null
2361
current = ""
2362
pos = i + 1
2363
}
2364
}else{
2365
// End of expression is the } matching the opening {
2366
// There may be nested braces
2367
var i = pos,
2368
nb_braces = 1,
2369
nb_paren = 0,
2370
current = new fstring_expression()
Mar 19, 2018
2371
while(i < string.length){
2372
car = string.charAt(i)
Mar 19, 2018
2373
if(car == "{" && nb_paren == 0){
2374
nb_braces++
2375
current.expression += car
2376
i++
Mar 19, 2018
2377
}else if(car == "}" && nb_paren == 0){
2378
nb_braces -= 1
Mar 19, 2018
2379
if(nb_braces == 0){
2380
// end of expression
2381
elts.push(current)
2382
ctype = null
Mar 19, 2018
2383
current = ""
2384
pos = i + 1
2387
current.expression += car
2388
i++
Mar 19, 2018
2389
}else if(car == "\\"){
2390
// backslash is not allowed in expressions
2391
throw Error("f-string expression part cannot include a" +
2392
" backslash")
Mar 19, 2018
2393
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2394
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2395
if(current.expression.length == 0){
2396
throw Error("f-string: empty expression not allowed")
2397
}
Mar 19, 2018
2398
if("ars".indexOf(string.charAt(i + 1)) == -1){
2399
throw Error("f-string: invalid conversion character:" +
2400
" expected 's', 'r', or 'a'")
2401
}else{
Mar 19, 2018
2402
current.conversion = string.charAt(i + 1)
2403
i += 2
2404
}
Mar 19, 2018
2405
}else if(car == "("){
2406
nb_paren++
2407
current.expression += car
2408
i++
Mar 19, 2018
2409
}else if(car == ")"){
2410
nb_paren--
2411
current.expression += car
2412
i++
Mar 19, 2018
2413
}else if(car == '"'){
2414
// triple string ?
Mar 19, 2018
2415
if(string.substr(i, 3) == '"""'){
2416
var end = string.indexOf('"""', i + 3)
2417
if(end == -1){
2418
throw Error("f-string: unterminated string")
2419
}else{
2420
var trs = string.substring(i, end + 3)
2421
trs = trs.replace("\n", "\\n\\")
2422
current.expression += trs
Mar 19, 2018
2423
i = end + 3
2424
}
2425
}else{
Mar 19, 2018
2426
var end = string.indexOf('"', i + 1)
2427
if(end == -1){
2428
throw Error("f-string: unterminated string")
2429
}else{
2430
current.expression += string.substring(i, end + 1)
2431
i = end + 1
2432
}
2433
}
Mar 19, 2018
2434
}else if(nb_paren == 0 && car == ":"){
2435
current.fmt = true
2436
current.expression += car
2437
i++
2438
}else if(car == "="){
2439
// might be a "debug expression", eg f"{x=}"
2440
var ce = current.expression
2441
if(ce.length == 0 ||
2442
string.charAt(i + 1) == "=" ||
2443
"=!<>:".search(ce.charAt(ce.length - 1)) > -1){
2444
current.expression += car + string.charAt(i + 1)
2445
i += 2
2446
}else{
2447
// add debug string
2448
tail = car
2449
while(string.charAt(i + 1).match(/\s/)){
2450
tail += string.charAt(i + 1)
2451
i++
2452
}
2453
elts.push(current.expression + tail)
2454
// remove trailing whitespace from expression
2455
while(ce.match(/\s$/)){
2456
ce = ce.substr(0, ce.length - 1)
2457
}
2458
current.expression = ce
2459
ctype = "debug"
2460
i++
2461
}
2462
}else{
2463
current.expression += car
2464
i++
2465
}
2466
}
Mar 21, 2018
2467
if(nb_braces > 0){
2468
throw Error("f-string: expected '}'")
2469
}
2470
}
2471
}
Mar 19, 2018
2472
if(current.length > 0){elts.push(current)}
2473
return elts
2474
}
2475
2476
// Class for strings with surrogate pairs. We can't rely on Javascript
2477
// strings in this case because they don't count characters like Python
2478
2479
var surrogate = str.$surrogate = $B.make_class("surrogate_string", function(s){
2480
// create an instance of str subclass for strings with surrogate pairs
2481
var items = []
2482
for(var i = 0, len = s.length; i < len; i++){
2483
var code = s.charCodeAt(i)
2484
if(code >= 0xD800 && code <= 0xDBFF){
2485
i++
2486
var low = s.charCodeAt(i)
2487
code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000
2488
}
2489
items.push(String.fromCodePoint(code))
2490
}
2491
return {
2492
__class__: str.$surrogate,
2493
items: items
2494
}
2495
})
2496
2497
surrogate.__mro__ = [str, object]
2498
2499
surrogate.__contains__ = function(self, other){
2500
return str.__contains__(self.items.join(''), other)
2501
}
2502
2503
surrogate.__getitem__ = function(self, arg){
2504
if(isinstance(arg, _b_.int)){
2505
var pos = arg
2506
if(arg < 0){
2507
pos += self.items.length
2508
}
2509
if(pos >= 0 && pos < self.items.length){
2510
if(self.items[pos].length == 2){
2511
return surrogate.$factory(self.items[pos])
2512
}
2513
return self.items[pos]
2514
}
2515
throw _b_.IndexError.$factory("string index out of range")
2516
}
2517
if(isinstance(arg, slice)) {
2518
var s = _b_.slice.$conv_for_seq(arg, self.items.length),
2519
start = s.start,
2520
stop = s.stop,
2521
step = s.step
2522
var res = "",
2523
i = null
2524
if(step > 0){
2525
if(stop <= start){return ""}
2526
for(var i = start; i < stop; i += step){
2527
res += self.items[i]
2528
}
2529
}else{
2530
if(stop >= start){return ''}
2531
for(var i = start; i > stop; i += step){
2532
res += self.items[i]
2533
}
2534
}
2535
return res
2536
}
2537
if(isinstance(arg, _b_.bool)){
2538
return surrogate.__getitem__(self, _b_.int.$factory(arg))
2539
}
2540
throw _b_.TypeError.$factory("string indices must be integers")
2541
}
2542
2543
surrogate.__hash__ = function(self){
2544
return str.__hash__(self.items.join(''))
2545
}
2546
2547
surrogate.__iter__ = function(self){
2548
return str_iterator.$factory(self.items)
2549
}
2550
2551
surrogate.__len__ = function(self){
2552
return self.items.length
2553
}
2554
2555
surrogate.__repr__ = function(self){
2556
return str.__repr__(self.items.join(''))
2557
}
2558
2559
surrogate.__str__ = function(self){
2560
return str.__str__(self.items.join(''))
2561
}
2562
2563
$B.set_func_names(surrogate, "builtins")
2564
2565
Sep 5, 2014
2566
})(__BRYTHON__)