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