Skip to content
Permalink
Newer
Older
100644 2601 lines (2387 sloc) 82.8 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
// Special management of keyword arguments if str.format is called by
1216
// str.format_map(mapping) : the argument "mapping" might not be a
1217
// dictionary
1218
var last_arg = $B.last(arguments)
1219
if(last_arg.$nat == "mapping"){
1220
var mapping = last_arg.mapping,
1221
getitem = $B.$getattr(mapping, "__getitem__")
1222
// Get the rest of the arguments
1223
var args = []
1224
for(var i = 0, len = arguments.length - 1; i < len; i++){
1225
args.push(arguments[i])
1226
}
1227
var $ = $B.args("format", 1, {self: null}, ["self"],
1228
args, {}, "$args", null)
1229
}else{
1230
var $ = $B.args("format", 1, {self: null}, ["self"],
1231
arguments, {}, "$args", "$kw"),
1232
mapping = $.$kw, // dictionary
1233
getitem = function(key){
1234
return _b_.dict.$getitem(mapping, key)
1235
}
1236
}
1237
var parts = $B.split_format($.self)
1238
1239
// Apply formatting to the values passed to format()
Mar 19, 2018
1240
var res = "",
1241
fmt
Mar 19, 2018
1243
for(var i = 0; i < parts.length; i++){
1244
// Literal text is added unchanged
Mar 19, 2018
1245
if(typeof parts[i] == "string"){res += parts[i]; continue}
1247
// Format objects
1248
fmt = parts[i]
1249
1250
if(fmt.spec !== undefined){
1251
// "spec" may contain "nested replacement fields"
1252
// In this case, evaluate them using the positional
1253
// or keyword arguments passed to format()
1254
function replace_nested(name, key){
1255
if(/\d+/.exec(key)){
1256
// If key is numeric, search in positional
1257
// arguments
1258
return _b_.tuple.__getitem__($.$args,
1259
parseInt(key))
1260
}else{
1261
// Else try in keyword arguments
1262
return _b_.dict.__getitem__($.$kw, key)
1263
}
1264
}
1265
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1266
replace_nested)
1267
}
Mar 21, 2018
1268
if(fmt.name.charAt(0).search(/\d/) > -1){
1269
// Numerical reference : use positional arguments
1270
var pos = parseInt(fmt.name),
Feb 11, 2018
1271
value = _b_.tuple.__getitem__($.$args, pos)
1272
}else{
1273
// Use keyword arguments
1274
var value = getitem(fmt.name)
1275
}
1276
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1277
for(var j = 0; j < fmt.name_ext.length; j++){
1278
var ext = fmt.name_ext[j]
Mar 19, 2018
1279
if(ext.charAt(0) == "."){
1280
// Attribute
1281
value = _b_.getattr(value, ext.substr(1))
1282
}else{
1283
// Subscription
Mar 19, 2018
1284
var key = ext.substr(1, ext.length - 2)
1285
// An index made of digits is transformed into an integer
Mar 19, 2018
1286
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1287
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1290
1291
// If the conversion flag is set, first call a function to convert
1292
// the value
Mar 19, 2018
1293
if(fmt.conv == "a"){value = _b_.ascii(value)}
1294
else if(fmt.conv == "r"){value = _b_.repr(value)}
1295
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1297
// Call attribute __format__ to perform the actual formatting
1298
if(value.$is_class || value.$factory){
1299
// For classes, don't use the class __format__ method
1300
res += value.__class__.__format__(value, fmt.spec)
1302
res += $B.$getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1304
}
Sep 5, 2014
1306
}
1307
1308
str.format_map = function(self, mapping){
1309
var $ = $B.args("format_map", 2, {self: null, mapping: null},
1310
['self', 'mapping'], arguments, {}, null, null)
1311
return str.format(self, {$nat: 'mapping', mapping})
Sep 5, 2014
1312
}
1313
str
Feb 10, 2018
1314
str.index = function(self){
Sep 5, 2014
1315
// Like find(), but raise ValueError when the substring is not found.
1316
var res = str.find.apply(null, arguments)
Mar 19, 2018
1317
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1318
return res
1319
}
1320
1321
str.isascii = function(self){
1322
/* Return true if the string is empty or all characters in the string are
1323
ASCII, false otherwise. ASCII characters have code points in the range
1324
U+0000-U+007F. */
1325
for(var i = 0, len = self.length; i < len; i++){
1326
if(self.charCodeAt(i) > 127){return false}
1327
}
1328
return true
1329
}
1330
1331
str.isalnum = function(self){
1332
/* Return true if all characters in the string are alphanumeric and there
1333
is at least one character, false otherwise. A character c is alphanumeric
1334
if one of the following returns True: c.isalpha(), c.isdecimal(),
1335
c.isdigit(), or c.isnumeric(). */
1336
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1337
arguments, {}, null, null),
1338
char
1339
for(var i = 0, len = self.length; i < len; i++){
1340
char = self.charCodeAt(i)
1341
if(unicode_tables.Ll[char] ||
1342
unicode_tables.Lu[char] ||
1343
unicode_tables.Lm[char] ||
1344
unicode_tables.Lt[char] ||
1345
unicode_tables.Lo[char] ||
1346
unicode_tables.Nd[char] ||
1347
unicode_tables.digits[char] ||
1348
unicode_tables.numeric[char]){
1349
continue
1350
}
1351
return false
1352
}
1353
return true
1354
}
1355
1356
str.isalpha = function(self){
1357
/* Return true if all characters in the string are alphabetic and there is
1358
at least one character, false otherwise. Alphabetic characters are those
1359
characters defined in the Unicode character database as "Letter", i.e.,
1360
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1361
or "Lo". */
1362
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1363
arguments, {}, null, null),
1364
char
1365
for(var i = 0, len = self.length; i < len; i++){
1366
char = self.charCodeAt(i)
1367
if(unicode_tables.Ll[char] ||
1368
unicode_tables.Lu[char] ||
1369
unicode_tables.Lm[char] ||
1370
unicode_tables.Lt[char] ||
1371
unicode_tables.Lo[char]){
1372
continue
1373
}
1374
return false
1375
}
1376
return true
1377
}
1378
1379
str.isdecimal = function(self){
1380
/* Return true if all characters in the string are decimal characters and
1381
there is at least one character, false otherwise. Decimal characters are
1382
those that can be used to form numbers in base 10, e.g. U+0660,
1383
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1384
the Unicode General Category "Nd". */
1385
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1386
arguments, {}, null, null),
1387
char
1388
for(var i = 0, len = self.length; i < len; i++){
1389
char = self.charCodeAt(i)
1390
if(! unicode_tables.Nd[char]){
1391
return false
1392
}
1393
}
1394
return self.length > 0
1395
}
1396
1397
str.isdigit = function(self){
1398
/* Return true if all characters in the string are digits and there is at
1399
least one character, false otherwise. */
1400
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1401
arguments, {}, null, null),
1402
char
1403
for(var i = 0, len = self.length; i < len; i++){
1404
char = self.charCodeAt(i)
1405
if(! unicode_tables.digits[char]){
1406
return false
1407
}
1408
}
1409
return self.length > 0
1410
}
1411
1412
str.isidentifier = function(self){
1413
/* Return true if the string is a valid identifier according to the
1414
language definition. */
1415
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1416
arguments, {}, null, null),
1417
char
1418
if(self.length == 0){return false}
1419
else if(unicode_tables.XID_Start[self.charCodeAt(0)] === undefined){
1420
return false
1421
}else{
1422
for(var i = 1, len = self.length; i < len; i++){
1423
if(unicode_tables.XID_Continue[self.charCodeAt(i)] === undefined){
1424
return false
1425
}
1426
}
1427
}
1428
return true
1429
}
1430
1431
str.islower = function(self){
1432
/* Return true if all cased characters 4 in the string are lowercase and
1433
there is at least one cased character, false otherwise. */
1434
var $ = $B.args("islower", 1, {self: null}, ["self"],
1435
arguments, {}, null, null),
1436
has_cased = false,
1437
char
1438
1439
for(var i = 0, len = self.length; i < len; i++){
1440
char = self.charCodeAt(i)
1441
if(unicode_tables.Ll[char]){has_cased = true; continue}
1442
else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1443
return false
1444
}
1445
}
1446
return has_cased
1447
}
1448
1449
str.isnumeric = function(self){
1450
/* Return true if all characters in the string are numeric characters, and
1451
there is at least one character, false otherwise. Numeric characters
1452
include digit characters, and all characters that have the Unicode numeric
1453
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1454
characters are those with the property value Numeric_Type=Digit,
1455
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1456
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1457
arguments, {}, null, null)
1458
for(var i = 0, len = self.length; i < len; i++){
1459
if(! unicode_tables.numeric[self.charCodeAt(i)]){
1460
return false
1461
}
1462
}
1463
return self.length > 0
1464
}
1465
1466
var unprintable = {},
1467
unprintable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1468
1469
str.isprintable = function(self){
1470
/* Return true if all characters in the string are printable or the string
1471
is empty, false otherwise. Nonprintable characters are those characters
1472
defined in the Unicode character database as "Other" or "Separator",
1473
excepting the ASCII space (0x20) which is considered printable. */
1474
1475
// Set unprintable if not set yet
1476
if(Object.keys(unprintable).length == 0){
1477
for(var i = 0; i < unprintable_gc.length; i++){
1478
var table = unicode_tables[unprintable_gc[i]]
1480
unprintable[cp] = true
1483
unprintable[32] = true
1484
}
1485
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1486
arguments, {}, null, null)
1487
for(var i = 0, len = self.length; i < len; i++){
1488
if(unprintable[self.charCodeAt(i)]){
1489
return false
1490
}
1491
}
1492
return true
1493
}
1494
1495
str.isspace = function(self){
1496
/* Return true if there are only whitespace characters in the string and
1497
there is at least one character, false otherwise.
1498
1499
A character is whitespace if in the Unicode character database, either its
1500
general category is Zs ("Separator, space"), or its bidirectional class is
1501
one of WS, B, or S.*/
1502
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1503
arguments, {}, null, null),
1504
char
1505
for(var i = 0, len = self.length; i < len; i++){
1506
char = self.charCodeAt(i)
1507
if(! unicode_tables.Zs[char] &&
1508
$B.unicode_bidi_whitespace.indexOf(char) == -1){
1509
return false
1510
}
1511
}
1512
return self.length > 0
1513
}
1514
1515
str.istitle = function(self){
1516
/* Return true if the string is a titlecased string and there is at least
1517
one character, for example uppercase characters may only follow uncased
1518
characters and lowercase characters only cased ones. Return false
1519
otherwise. */
1520
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1521
arguments, {}, null, null)
1522
return self.length > 0 && str.title(self) == self
1523
}
1524
1525
str.isupper = function(self){
1526
/* Return true if all cased characters 4 in the string are lowercase and
1527
there is at least one cased character, false otherwise. */
1528
var $ = $B.args("islower", 1, {self: null}, ["self"],
1529
arguments, {}, null, null),
1530
has_cased = false,
1531
char
1532
1533
for(var i = 0, len = self.length; i < len; i++){
1534
char = self.charCodeAt(i)
1535
if(unicode_tables.Lu[char]){has_cased = true; continue}
1536
else if(unicode_tables.Ll[char] || unicode_tables.Lt[char]){
1537
return false
1538
}
1539
}
1540
return has_cased
1541
}
1542
1543
str
Feb 10, 2018
1544
str.join = function(){
Mar 19, 2018
1545
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1546
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1548
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1549
res = [],
Sep 5, 2014
1551
while(1){
1552
try{
1553
var obj2 = _b_.next(iterable)
Mar 19, 2018
1554
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1555
"sequence item " + count + ": expected str instance, " +
1556
$B.class_name(obj2) + " found")}
1557
res.push(obj2)
Sep 5, 2014
1558
}catch(err){
1559
if(_b_.isinstance(err, _b_.StopIteration)){
1560
break
1561
}
Sep 5, 2014
1562
else{throw err}
1563
}
1564
}
1565
return res.join($.self)
Sep 5, 2014
1566
}
1567
str
Feb 10, 2018
1568
str.ljust = function(self) {
Mar 19, 2018
1569
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1570
["self", "width", "fillchar"],
1571
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1573
if($.width <= self.length){return self}
1574
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1575
}
1576
1577
str.lower = function(self){
1578
var $ = $B.args("lower", 1, {self: null}, ["self"],
1579
arguments, {}, null, null)
1580
return self.toLowerCase()
1581
}
1582
str
Feb 10, 2018
1583
str.lstrip = function(self,x){
Mar 19, 2018
1584
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1585
arguments, {chars:_b_.None}, null, null)
1586
if($.chars === _b_.None){return $.self.trimLeft()}
1587
for(var i = 0; i < $.self.length; i++){
1588
if($.chars.indexOf($.self.charAt(i)) === -1){
1589
return $.self.substring(i)
Mar 19, 2018
1592
return ""
Sep 5, 2014
1593
}
1594
1595
// note, maketrans should be a static function.
str
Feb 10, 2018
1596
str.maketrans = function() {
Mar 19, 2018
1597
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1598
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1602
if($.y === null && $.z === null){
1603
// If there is only one argument, it must be a dictionary mapping
1604
// Unicode ordinals (integers) or characters (strings of length 1) to
1605
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1606
// keys will then be converted to ordinals.
Mar 19, 2018
1607
if(! _b_.isinstance($.x, _b_.dict)){
1608
throw _b_.TypeError.$factory(
1609
"maketrans only argument must be a dict")
Feb 11, 2018
1611
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1612
for(var i = 0, len = items.length; i < len; i++){
1613
var k = items[i][0],
1614
v = items[i][1]
1615
if(! _b_.isinstance(k, _b_.int)){
1616
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1617
k = _b_.ord(k)
1618
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1619
" is not int or 1-char string")}
1620
}
Mar 19, 2018
1621
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1622
throw _b_.TypeError.$factory("dictionary value " + v +
1623
" is not None, integer or string")
1624
}
1625
_b_.dict.$setitem(_t, k, v)
1626
}
1627
return _t
1628
}else{
1629
// If there are two arguments, they must be strings of equal length,
1630
// and in the resulting dictionary, each character in x will be mapped
1631
// to the character at the same position in y
Mar 19, 2018
1632
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1633
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1634
}else if($.x.length !== $.y.length){
1635
throw _b_.TypeError.$factory(
1636
"maketrans arguments must be strings or same length")
1637
}else{
1638
var toNone = {}
Mar 19, 2018
1639
if($.z !== null){
1640
// If there is a third argument, it must be a string, whose
1641
// characters will be mapped to None in the result
Mar 19, 2018
1642
if(! _b_.isinstance($.z, _b_.str)){
1643
throw _b_.TypeError.$factory(
1644
"maketrans third argument must be a string")
Mar 19, 2018
1646
for(var i = 0, len = $.z.length; i < len; i++){
1647
toNone[_b_.ord($.z.charAt(i))] = true
1648
}
Mar 19, 2018
1650
for(var i = 0, len = $.x.length; i < len; i++){
1651
var key = _b_.ord($.x.charAt(i)),
1653
_b_.dict.$setitem(_t, key, value)
1654
}
1655
for(var k in toNone){
1656
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1657
}
1658
return _t
1659
}
1660
}
Sep 5, 2014
1661
}
1662
1663
str.maketrans.$type = "staticmethod"
1664
str
Feb 10, 2018
1665
str.partition = function() {
Mar 19, 2018
1666
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1667
arguments, {}, null, null)
Mar 19, 2018
1668
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1669
check_str($.sep)
1670
var i = $.self.indexOf($.sep)
Mar 23, 2018
1671
if(i == -1){return _b_.tuple.$factory([$.self, "", ""])}
Mar 19, 2018
1672
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1673
$.self.substring(i + $.sep.length)])
1674
}
1675
1676
str.removeprefix = function(){
1677
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1678
["self", "prefix"], arguments, {}, null, null)
1679
if(!_b_.isinstance($.prefix, str)){
1680
throw _b_.ValueError.$factory("prefix should be str, not " +
1681
`'${$B.class_name($.prefix)}'`)
1682
}
1683
if(str.startswith($.self, $.prefix)){
1684
return $.self.substr($.prefix.length)
1685
}
1686
return $.self.substr(0)
1687
}
1688
1689
str.removesuffix = function(){
1690
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1691
["self", "suffix"], arguments, {}, null, null)
1692
if(!_b_.isinstance($.suffix, str)){
1693
throw _b_.ValueError.$factory("suffix should be str, not " +
1694
`'${$B.class_name($.prefix)}'`)
1695
}
1696
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1697
return $.self.substr(0, $.self.length - $.suffix.length)
1698
}
1699
return $.self.substr(0)
1700
}
1701
Mar 19, 2018
1702
function $re_escape(str){
1703
var specials = "[.*+?|()$^"
1704
for(var i = 0, len = specials.length; i < len; i++){
1705
var re = new RegExp("\\"+specials.charAt(i), "g")
1706
str = str.replace(re, "\\"+specials.charAt(i))
1707
}
1708
return str
Sep 5, 2014
1709
}
1710
str
Feb 10, 2018
1711
str.replace = function(self, old, _new, count) {
1712
// Replaces occurrences of 'old' by '_new'. Count references
1713
// the number of times to replace. In CPython, negative or undefined
1714
// values of count means replace all.
Mar 19, 2018
1715
var $ = $B.args("replace", 4,
1716
{self: null, old: null, $$new: null, count: null},
1717
["self", "old", "$$new", "count"],
1718
arguments, {count: -1}, null, null),
1719
count = $.count,
1720
self = $.self,
1721
old = $.old,
1722
_new = $.$$new
1723
// Validate type of old
1724
check_str(old)
1725
check_str(_new)
1726
// Validate instance type of 'count'
Mar 23, 2018
1727
if(! isinstance(count,[_b_.int, _b_.float])){
1728
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1729
"' object cannot be interpreted as an integer")
1730
}else if(isinstance(count, _b_.float)){
1731
throw _b_.TypeError.$factory("integer argument expected, got float")
1732
}
1733
if(count == 0){return self}
1734
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1735
if(old == ""){
1736
if(_new == ""){return self}
1737
if(self == ""){return _new}
1738
var elts = self.split("")
1739
if(count > -1 && elts.length >= count){
1740
var rest = elts.slice(count).join("")
1741
return _new + elts.slice(0, count).join(_new) + rest
1742
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1744
var elts = str.split(self, old, count)
Sep 5, 2014
1745
}
Mar 19, 2018
1747
var res = self,
1748
pos = -1
1749
if(old.length == 0){
Mar 19, 2018
1751
for(var i = 0; i < elts.length; i++){
1752
res += elts[i] + _new
Mar 19, 2018
1754
return res + rest
Mar 19, 2018
1757
if(count < 0){count = res.length}
1758
while(count > 0){
1759
pos = res.indexOf(old, pos)
1760
if(pos < 0){break}
1761
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1762
pos = pos + _new.length
1763
count--
Mar 19, 2018
1765
return res
Sep 5, 2014
1766
}
1767
1768
str.rfind = function(self, substr){
1769
// Return the highest index in the string where substring sub is found,
1770
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1771
// start and end are interpreted as in slice notation. Return -1 on failure.
1772
if(arguments.length == 2 && typeof substr == "string"){
1773
return self.lastIndexOf(substr)
1774
}
Mar 19, 2018
1775
var $ = $B.args("rfind", 4,
Mar 19, 2018
1776
{self: null, sub: null, start: null, end: null},
1777
["self", "sub", "start", "end"],
1778
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1779
1782
check_str($.sub)
Mar 19, 2018
1784
if($.sub.length == 0){
1785
if($.start > $.self.length){return -1}
1786
else{return $.self.length}
1787
}
1788
var sublen = $.sub.length
Mar 19, 2018
1790
for(var i = $.end - sublen; i >= $.start; i--){
1791
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1794
}
1795
str
Feb 10, 2018
1796
str.rindex = function(){
Sep 5, 2014
1797
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1798
var res = str.rfind.apply(null, arguments)
1799
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1800
return res
1801
}
1802
str
Feb 10, 2018
1803
str.rjust = function(self) {
Mar 19, 2018
1804
var $ = $B.args("rjust",3,
1805
{self: null, width: null, fillchar: null},
1806
["self", "width", "fillchar"],
1807
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1808
Mar 19, 2018
1809
if($.width <= self.length){return self}
Sep 5, 2014
1810
1811
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1812
}
1813
str
Feb 10, 2018
1814
str.rpartition = function(self,sep) {
Mar 19, 2018
1815
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1816
arguments, {}, null, null)
1817
check_str($.sep)
1818
var self = reverse($.self),
1819
sep = reverse($.sep)
Mar 19, 2018
1820
var items = str.partition(self, sep).reverse()
1821
for(var i = 0; i < items.length; i++){
1822
items[i] = items[i].split("").reverse().join("")
1823
}
1824
return items
Sep 5, 2014
1825
}
1826
str
Feb 10, 2018
1827
str.rsplit = function(self) {
Mar 19, 2018
1828
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1829
["self", "sep", "maxsplit"], arguments,
1830
{sep: _b_.None, maxsplit: -1}, null, null),
1831
sep = $.sep
1832
1833
// Use split on the reverse of the string and of separator
1834
var rev_str = reverse($.self),
1835
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1836
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1838
// Reverse the list, then each string inside the list
1839
rev_res.reverse()
Mar 19, 2018
1840
for(var i = 0; i < rev_res.length; i++){
1841
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1844
}
1845
Mar 19, 2018
1846
str.rstrip = function(self, x){
1847
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1848
arguments, {chars: _b_.None}, null, null)
1849
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1850
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1851
if($.chars.indexOf($.self.charAt(j)) == -1){
1852
return $.self.substring(0, j + 1)
Mar 19, 2018
1855
return ""
Sep 5, 2014
1856
}
1857
str
Feb 10, 2018
1858
str.split = function(){
Mar 19, 2018
1859
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1860
["self", "sep", "maxsplit"], arguments,
1861
{sep: _b_.None, maxsplit: -1}, null, null),
1862
sep = $.sep,
1863
maxsplit = $.maxsplit,
1864
self = $.self,
1865
pos = 0
1866
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1867
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1868
if(sep === _b_.None){
Sep 5, 2014
1869
var res = []
Mar 19, 2018
1870
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1871
if(pos === self.length - 1){return [self]}
1872
var name = ""
Sep 5, 2014
1873
while(1){
Mar 19, 2018
1874
if(self.charAt(pos).search(/\s/) == -1){
1875
if(name == ""){name = self.charAt(pos)}
1876
else{name += self.charAt(pos)}
Sep 5, 2014
1877
}else{
Mar 19, 2018
1878
if(name !== ""){
Sep 5, 2014
1879
res.push(name)
Mar 19, 2018
1880
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1881
res.pop()
Mar 19, 2018
1882
res.push(name + self.substr(pos))
Sep 5, 2014
1883
return res
1884
}
Mar 19, 2018
1885
name = ""
Sep 5, 2014
1886
}
1887
}
1888
pos++
Mar 19, 2018
1889
if(pos > self.length - 1){
Sep 5, 2014
1890
if(name){res.push(name)}
1891
break
1892
}
1893
}
1894
return res
1895
}else{
Mar 19, 2018
1896
var res = [],
1897
s = "",
1898
seplen = sep.length
1899
if(maxsplit == 0){return [self]}
1900
while(pos < self.length){
1901
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1904
if(maxsplit > -1 && res.length >= maxsplit){
1905
res.push(self.substr(pos))
1906
return res
1907
}
Mar 19, 2018
1908
s = ""
1909
}else{
1910
s += self.charAt(pos)
1911
pos++
Sep 5, 2014
1912
}
1913
}
Sep 5, 2014
1916
}
1917
}
1918
1919
str.splitlines = function(self) {
1920
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
1921
['self','keepends'], arguments, {keepends: false},
1922
null, null)
1923
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
1924
throw _b_.TypeError('integer argument expected, got '+
1925
$B.get_class($.keepends).__name)
1926
}
1927
var keepends = _b_.int.$factory($.keepends),
1928
res = [],
1929
self = $.self,
1930
start = 0,
1931
pos = 0
1932
if(!self.length){
1933
return res
1934
}
1935
while (pos < self.length) {
1936
if(self.substr(pos, 2) == '\r\n'){
1937
res.push(self.slice(start, keepends ? pos + 2 : pos))
1938
start = pos = pos+2
1939
}else if(self[pos] == '\r' || self[pos] == '\n'){
1940
res.push(self.slice(start, keepends ? pos+1 : pos))
1941
start = pos = pos+1
1942
}else{
1943
pos++
1944
}
1945
}
1946
if(start < self.length){
1947
res.push(self.slice(start))
1948
}
1949
return res
1950
}
Sep 5, 2014
1951
str
Feb 10, 2018
1952
str.startswith = function(){
1953
// Return True if string starts with the prefix, otherwise return False.
1954
// prefix can also be a tuple of prefixes to look for. With optional
1955
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1956
// stop comparing string at that position.
Mar 19, 2018
1957
var $ = $B.args("startswith", 4,
1958
{self: null, prefix: null, start: null, end: null},
1959
["self", "prefix", "start", "end"],
1960
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1961
1962
normalize_start_end($)
1963
1964
var prefixes = $.prefix
Mar 19, 2018
1965
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1967
var s = $.self.substring($.start, $.end)
1968
for(var i = 0, len = prefixes.length; i < len; i++){
1969
var prefix = prefixes[i]
Mar 19, 2018
1970
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1971
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1972
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1973
}
1974
return false
1975
Sep 5, 2014
1976
}
1977
str
Feb 10, 2018
1978
str.strip = function(){
Mar 19, 2018
1979
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1980
arguments, {chars: _b_.None}, null, null)
1981
if($.chars === _b_.None){return $.self.trim()}
1982
for(var i = 0; i < $.self.length; i++){
1983
if($.chars.indexOf($.self.charAt(i)) == -1){
1984
break
Mar 19, 2018
1987
for(var j = $.self.length - 1; j >= i; j--){
1988
if($.chars.indexOf($.self.charAt(j)) == -1){
1989
break
Mar 19, 2018
1992
return $.self.substring(i, j + 1)
Sep 5, 2014
1993
}
1994
1995
str.swapcase = function(self){
1996
var $ = $B.args("swapcase", 1, {self}, ["self"],
1997
arguments, {}, null, null),
1998
res = "",
1999
char
2000
2001
for(var i = 0, len = self.length; i < len; i++){
2002
char = self.charCodeAt(i)
2003
if(unicode_tables.Ll[char]){
2004
res += self.charAt(i).toUpperCase()
2005
}else if(unicode_tables.Lu[char]){
2006
res += self.charAt(i).toLowerCase()
2007
}else{
2008
res += self.charAt(i)
2009
}
2010
}
2011
return res
2012
}
2013
2014
str.title = function(self){
2015
var $ = $B.args("title", 1, {self}, ["self"],
2016
arguments, {}, null, null),
2017
state,
2018
char,
2019
res = ""
2020
for(var i = 0, len = self.length; i < len; i++){
2021
char = self.charCodeAt(i)
2022
if(unicode_tables.Ll[char]){
2023
if(! state){
2024
res += self.charAt(i).toUpperCase()
2025
state = "word"
2026
}else{
2027
res += self.charAt(i)
2028
}
2029
}else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
2030
res += state ? self.charAt(i).toLowerCase() : self.charAt(i)
2031
state = "word"
2032
}else{
2033
state = null
2034
res += self.charAt(i)
2035
}
2036
}
2037
return res
2038
}
2039
2040
str.translate = function(self, table){
Mar 19, 2018
2041
var res = [],
2042
getitem = $B.$getattr(table, "__getitem__")
2043
for(var i = 0, len = self.length; i < len; i++){
2044
try{
2045
var repl = getitem(self.charCodeAt(i))
2046
if(repl !== _b_.None){
2047
if(typeof repl == "string"){
2048
res.push(repl)
2049
}else if(typeof repl == "number"){
2050
res.push(String.fromCharCode(repl))
2051
}
2052
}
2053
}catch(err){
2054
res.push(self.charAt(i))
2055
}
Sep 5, 2014
2056
}
Mar 19, 2018
2057
return res.join("")
Sep 5, 2014
2058
}
2059
2060
str.upper = function(self){
2061
var $ = $B.args("upper", 1, {self: null}, ["self"],
2062
arguments, {}, null, null)
2063
return self.toUpperCase()
2064
}
2065
Mar 19, 2018
2066
str.zfill = function(self, width){
Mar 19, 2018
2067
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
2068
["self", "width"], arguments, {}, null, null)
2069
if($.width <= self.length){return self}
Mar 19, 2018
2071
case "+":
2072
case "-":
2073
return self.charAt(0) +
2074
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
2076
return "0".repeat(width - self.length) + self
Sep 5, 2014
2078
}
2079
2080
str.$factory = function(arg, encoding, errors){
2081
if(arguments.length == 0){return ""}
2083
return $B.UndefinedClass.__str__()
2085
if(encoding !== undefined){
2086
// Arguments may be passed as keywords (cf. issue #1060)
2087
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2088
["arg", "encoding", "errors"], arguments,
2089
{encoding: "utf-8", errors: "strict"}, null, null),
2090
encoding = $.encoding,
2091
errors = $.errors
2092
}
2093
switch(typeof arg) {
Mar 19, 2018
2094
case "string":
Mar 27, 2019
2095
return str.__str__(arg)
Mar 19, 2018
2096
case "number":
2097
if(isFinite(arg)){return arg.toString()}
2100
if(arg.$is_class || arg.$factory){
2101
// arg is a class
2102
// In this case, str() doesn't use the attribute __str__ of the
2103
// class or its subclasses, but the attribute __str__ of the
2104
// class metaclass (usually "type") or its subclasses (usually
2105
// "object")
2106
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
2107
var func = $B.$getattr(arg.__class__, "__str__")
2109
}
2111
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2112
encoding !== undefined){
2113
// str(bytes, encoding, errors) is equal to
2114
// bytes.decode(encoding, errors)
2115
return _b_.bytes.decode(arg, $.encoding, $.errors)
2117
// Implicit invocation of __str__ uses method __str__ on the class,
2118
// even if arg has an attribute __str__
2119
var klass = arg.__class__ || $B.get_class(arg)
2121
return $B.JSObj.__str__($B.JSObj.$factory(arg))
2123
var method = $B.$getattr(klass , "__str__", null)
2124
if(method === null ||
2125
// if not better than object.__str__, try __repr__
2126
(arg.__class__ && arg.__class__ !== _b_.object &&
2127
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2128
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2130
}
2131
catch(err){
2132
console.log("no __str__ for", arg)
Mar 19, 2018
2133
console.log("err ", err)
2134
if($B.debug > 1){console.log(err)}
2135
console.log("Warning - no method __str__ or __repr__, " +
2136
"default to toString", arg)
May 20, 2019
2137
throw err
Sep 5, 2014
2138
}
2139
return $B.$call(method)(arg)
Sep 5, 2014
2140
}
str
Feb 10, 2018
2141
2142
str.__new__ = function(cls){
Mar 19, 2018
2143
if(cls === undefined){
2144
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2145
}
Mar 19, 2018
2146
return {__class__: cls}
Sep 5, 2014
2147
}
2148
str
Feb 10, 2018
2149
$B.set_func_names(str, "builtins")
Sep 5, 2014
2151
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2152
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2153
__class__: _b_.type,
str
Feb 10, 2018
2154
__mro__: [object],
2155
$infos: {
2156
__module__: "builtins",
2157
__name__: "str"
2158
},
str
Feb 10, 2018
2159
$is_class: true
Sep 5, 2014
2160
}
2161
str
Feb 10, 2018
2162
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2163
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2164
for(var $attr in str){
Mar 19, 2018
2165
if(typeof str[$attr] == "function"){
Mar 19, 2018
2166
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2167
return function(){
Mar 19, 2018
2168
var args = [],
2169
pos = 0
2170
if(arguments.length > 0){
2171
var args = [arguments[0].valueOf()],
2172
pos = 1
2173
for(var i = 1, len = arguments.length; i < len; i++){
2174
args[pos++] = arguments[i]
Sep 5, 2014
2175
}
2176
}
Mar 19, 2018
2177
return str[attr].apply(null, args)
Sep 5, 2014
2178
}
2179
})($attr)
2180
}
2181
}
2182
str
Feb 10, 2018
2183
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2186
str
Feb 10, 2018
2187
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2189
_b_.str = str
2190
2191
// Function to parse the 2nd argument of format()
2192
$B.parse_format_spec = function(spec){
Mar 19, 2018
2193
if(spec == ""){this.empty = true}
2194
else{
Mar 19, 2018
2195
var pos = 0,
2196
aligns = "<>=^",
2197
digits = "0123456789",
2198
types = "bcdeEfFgGnosxX%",
2199
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2200
if(align_pos != -1){
2201
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2202
// If the second char is also an alignment specifier, the
2203
// first char is the fill value
2204
this.fill = spec.charAt(0)
2205
this.align = spec.charAt(1)
2206
pos = 2
2207
}else{
2208
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2209
this.align = aligns[align_pos]
2210
this.fill = " "
2211
pos++
2212
}
2213
}else{
2214
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2215
if(spec.charAt(1) && align_pos != -1){
2216
// The second character defines alignment : fill is the first one
Mar 19, 2018
2217
this.align = aligns[align_pos]
2218
this.fill = spec.charAt(0)
2219
pos = 2
2220
}
2221
}
2222
var car = spec.charAt(pos)
Mar 19, 2018
2223
if(car == "+" || car == "-" || car == " "){
2224
this.sign = car
2225
pos++
2226
car = spec.charAt(pos)
Mar 19, 2018
2228
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
2229
if(car == "0"){
Mar 19, 2018
2230
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2231
this.fill = "0"
2232
if(align_pos == -1){
2233
this.align = "="
2234
}
Mar 19, 2018
2235
pos++
2236
car = spec.charAt(pos)
2237
}
Mar 19, 2018
2238
while(car && digits.indexOf(car) > -1){
2239
if(this.width === undefined){this.width = car}
2240
else{this.width += car}
2241
pos++
2242
car = spec.charAt(pos)
Mar 19, 2018
2244
if(this.width !== undefined){this.width = parseInt(this.width)}
2245
if(this.width === undefined && car == "{"){
2246
// Width is determined by a parameter
2247
var end_param_pos = spec.substr(pos).search("}")
2248
this.width = spec.substring(pos, end_param_pos)
2249
console.log("width", "[" + this.width + "]")
2250
pos += end_param_pos + 1
2251
}
Mar 19, 2018
2252
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
2253
if(car == "."){
2254
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2255
throw _b_.ValueError.$factory(
2256
"Missing precision in format spec")
Mar 19, 2018
2258
this.precision = spec.charAt(pos + 1)
2259
pos += 2
2260
car = spec.charAt(pos)
2261
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2262
this.precision += car
Mar 19, 2018
2263
pos++
2264
car = spec.charAt(pos)
2265
}
2266
this.precision = parseInt(this.precision)
2267
}
Mar 19, 2018
2268
if(car && types.indexOf(car) > -1){
2269
this.type = car
2270
pos++
2271
car = spec.charAt(pos)
2272
}
2273
if(pos !== spec.length){
2274
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2278
this.toString = function(){
Mar 19, 2018
2279
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2280
(this.align || "") +
2281
(this.sign || "") +
2282
(this.alternate ? "#" : "") +
2283
(this.sign_aware ? "0" : "") +
2284
(this.width || "") +
2285
(this.comma ? "," : "") +
2286
(this.precision ? "." + this.precision : "") +
2287
(this.type || "")
2288
}
2289
}
2290
2291
$B.format_width = function(s, fmt){
Mar 19, 2018
2292
if(fmt.width && s.length < fmt.width){
2293
var fill = fmt.fill || " ",
2294
align = fmt.align || "<",
2295
missing = fmt.width - s.length
2296
switch(align){
Mar 19, 2018
2297
case "<":
2298
return s + fill.repeat(missing)
2299
case ">":
2300
return fill.repeat(missing) + s
2301
case "=":
2302
if("+-".indexOf(s.charAt(0)) > -1){
2303
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2304
}else{
Mar 19, 2018
2305
return fill.repeat(missing) + s
Mar 19, 2018
2307
case "^":
2308
var left = parseInt(missing / 2)
2309
return fill.repeat(left) + s + fill.repeat(missing - left)
2310
}
2311
}
2312
return s
2313
}
2314
2315
function fstring_expression(){
Mar 19, 2018
2316
this.type = "expression"
2317
this.expression = ""
2318
this.conversion = null
2319
this.fmt = null
2320
}
2321
2322
$B.parse_fstring = function(string){
2323
// Parse a f-string
2324
var elts = [],
2325
pos = 0,
Mar 19, 2018
2326
current = "",
2327
ctype = null,
2328
nb_braces = 0,
2329
car
2330
Mar 19, 2018
2331
while(pos < string.length){
2332
if(ctype === null){
2333
car = string.charAt(pos)
Mar 19, 2018
2334
if(car == "{"){
Mar 21, 2018
2335
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2336
ctype = "string"
2337
current = "{"
2338
pos += 2
2339
}else{
Mar 19, 2018
2340
ctype = "expression"
2341
nb_braces = 1
2342
pos++
2343
}
Mar 19, 2018
2344
}else if(car == "}"){
Mar 21, 2018
2345
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2346
ctype = "string"
2347
current = "}"
2348
pos += 2
2349
}else{
2350
throw Error(" f-string: single '}' is not allowed")
2351
}
2352
}else{
Mar 19, 2018
2353
ctype = "string"
2354
current = car
2355
pos++
Mar 19, 2018
2357
}else if(ctype == "string"){
2358
// end of string is the first single { or end of string
Mar 19, 2018
2359
var i = pos
2360
while(i < string.length){
2361
car = string.charAt(i)
Mar 19, 2018
2362
if(car == "{"){
Mar 21, 2018
2363
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2364
current += "{"
2365
i += 2
2366
}else{
2367
elts.push(current)
Mar 19, 2018
2368
ctype = "expression"
2369
pos = i + 1
2370
break
2371
}
Mar 19, 2018
2372
}else if(car == "}"){
2373
if(string.charAt(i + 1) == car){
2374
current += car
2375
i += 2
2376
}else{
2377
throw Error(" f-string: single '}' is not allowed")
2378
}
2379
}else{
2380
current += car
2381
i++
2382
}
2383
}
Mar 19, 2018
2384
pos = i + 1
2385
}else if(ctype == "debug"){
2386
// after the equal sign, whitespace are ignored and the only
2387
// valid characters are } and :
2388
while(string.charAt(i) == " "){i++}
2389
if(string.charAt(i) == "}"){
2390
// end of debug expression
2391
elts.push(current)
2392
ctype = null
2393
current = ""
2394
pos = i + 1
2395
}
2396
}else{
2397
// End of expression is the } matching the opening {
2398
// There may be nested braces
2399
var i = pos,
2400
nb_braces = 1,
2401
nb_paren = 0,
2402
current = new fstring_expression()
Mar 19, 2018
2403
while(i < string.length){
2404
car = string.charAt(i)
Mar 19, 2018
2405
if(car == "{" && nb_paren == 0){
2406
nb_braces++
2407
current.expression += car
2408
i++
Mar 19, 2018
2409
}else if(car == "}" && nb_paren == 0){
2410
nb_braces -= 1
Mar 19, 2018
2411
if(nb_braces == 0){
2412
// end of expression
2413
elts.push(current)
2414
ctype = null
Mar 19, 2018
2415
current = ""
2416
pos = i + 1
2419
current.expression += car
2420
i++
Mar 19, 2018
2421
}else if(car == "\\"){
2422
// backslash is not allowed in expressions
2423
throw Error("f-string expression part cannot include a" +
2424
" backslash")
Mar 19, 2018
2425
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2426
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2427
if(current.expression.length == 0){
2428
throw Error("f-string: empty expression not allowed")
2429
}
Mar 19, 2018
2430
if("ars".indexOf(string.charAt(i + 1)) == -1){
2431
throw Error("f-string: invalid conversion character:" +
2432
" expected 's', 'r', or 'a'")
2433
}else{
Mar 19, 2018
2434
current.conversion = string.charAt(i + 1)
2435
i += 2
2436
}
Mar 19, 2018
2437
}else if(car == "("){
2438
nb_paren++
2439
current.expression += car
2440
i++
Mar 19, 2018
2441
}else if(car == ")"){
2442
nb_paren--
2443
current.expression += car
2444
i++
Mar 19, 2018
2445
}else if(car == '"'){
2446
// triple string ?
Mar 19, 2018
2447
if(string.substr(i, 3) == '"""'){
2448
var end = string.indexOf('"""', i + 3)
2449
if(end == -1){
2450
throw Error("f-string: unterminated string")
2451
}else{
2452
var trs = string.substring(i, end + 3)
2453
trs = trs.replace("\n", "\\n\\")
2454
current.expression += trs
Mar 19, 2018
2455
i = end + 3
2456
}
2457
}else{
Mar 19, 2018
2458
var end = string.indexOf('"', i + 1)
2459
if(end == -1){
2460
throw Error("f-string: unterminated string")
2461
}else{
2462
current.expression += string.substring(i, end + 1)
2463
i = end + 1
2464
}
2465
}
Mar 19, 2018
2466
}else if(nb_paren == 0 && car == ":"){
2467
current.fmt = true
2468
current.expression += car
2469
i++
2470
}else if(car == "="){
2471
// might be a "debug expression", eg f"{x=}"
2472
var ce = current.expression,
2473
last_char = ce.charAt(ce.length - 1),
2474
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
2477
string.charAt(i + 1) == "=" ||
2478
"=!<>:".search(last_char_re) > -1){
2479
current.expression += car + string.charAt(i + 1)
2480
i += 2
2481
}else{
2482
// add debug string
2483
tail = car
2484
while(string.charAt(i + 1).match(/\s/)){
2485
tail += string.charAt(i + 1)
2486
i++
2487
}
2488
elts.push(current.expression + tail)
2489
// remove trailing whitespace from expression
2490
while(ce.match(/\s$/)){
2491
ce = ce.substr(0, ce.length - 1)
2492
}
2493
current.expression = ce
2494
ctype = "debug"
2495
i++
2496
}
2497
}else{
2498
current.expression += car
2499
i++
2500
}
2501
}
Mar 21, 2018
2502
if(nb_braces > 0){
2503
throw Error("f-string: expected '}'")
2504
}
2505
}
2506
}
Mar 19, 2018
2507
if(current.length > 0){elts.push(current)}
2508
return elts
2509
}
2510
2511
// Class for strings with surrogate pairs. We can't rely on Javascript
2512
// strings in this case because they don't count characters like Python
2513
2514
var surrogate = str.$surrogate = $B.make_class("surrogate_string", function(s){
2515
// create an instance of str subclass for strings with surrogate pairs
2516
var items = []
2517
for(var i = 0, len = s.length; i < len; i++){
2518
var code = s.charCodeAt(i)
2519
if(code >= 0xD800 && code <= 0xDBFF){
2520
i++
2521
var low = s.charCodeAt(i)
2522
code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000
2523
}
2524
items.push(String.fromCodePoint(code))
2525
}
2526
return {
2527
__class__: str.$surrogate,
2528
items: items
2529
}
2530
})
2531
2532
surrogate.__mro__ = [str, object]
2533
2534
surrogate.__contains__ = function(self, other){
2535
return str.__contains__(self.items.join(''), other)
2536
}
2537
2538
surrogate.__getitem__ = function(self, arg){
2539
if(isinstance(arg, _b_.int)){
2540
var pos = arg
2541
if(arg < 0){
2542
pos += self.items.length
2543
}
2544
if(pos >= 0 && pos < self.items.length){
2545
if(self.items[pos].length == 2){
2546
return surrogate.$factory(self.items[pos])
2547
}
2548
return self.items[pos]
2549
}
2550
throw _b_.IndexError.$factory("string index out of range")
2551
}
2552
if(isinstance(arg, slice)) {
2553
var s = _b_.slice.$conv_for_seq(arg, self.items.length),
2554
start = s.start,
2555
stop = s.stop,
2556
step = s.step
2557
var res = "",
2558
i = null
2559
if(step > 0){
2560
if(stop <= start){return ""}
2561
for(var i = start; i < stop; i += step){
2562
res += self.items[i]
2563
}
2564
}else{
2565
if(stop >= start){return ''}
2566
for(var i = start; i > stop; i += step){
2567
res += self.items[i]
2568
}
2569
}
2570
return res
2571
}
2572
if(isinstance(arg, _b_.bool)){
2573
return surrogate.__getitem__(self, _b_.int.$factory(arg))
2574
}
2575
throw _b_.TypeError.$factory("string indices must be integers")
2576
}
2577
2578
surrogate.__hash__ = function(self){
2579
return str.__hash__(self.items.join(''))
2580
}
2581
2582
surrogate.__iter__ = function(self){
2583
return str_iterator.$factory(self.items)
2584
}
2585
2586
surrogate.__len__ = function(self){
2587
return self.items.length
2588
}
2589
2590
surrogate.__repr__ = function(self){
2591
return str.__repr__(self.items.join(''))
2592
}
2593
2594
surrogate.__str__ = function(self){
2595
return str.__str__(self.items.join(''))
2596
}
2597
2598
$B.set_func_names(surrogate, "builtins")
2599
2600
Sep 5, 2014
2601
})(__BRYTHON__)