Skip to content
Permalink
Newer
Older
100644 2585 lines (2369 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) {
676
var length = self.length,
Mar 19, 2018
677
pos = 0 | 0,
678
argpos = null,
679
getitem
Mar 19, 2018
680
if(_b_.isinstance(args, _b_.tuple)){
681
argpos = 0 | 0
Mar 19, 2018
683
getitem = _b_.getattr(args, "__getitem__", _b_.None)
684
}
685
var ret = ''
686
var $get_kwarg_string = function(s) {
687
// returns [self, newpos]
688
++pos
689
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
690
if(! rslt){
691
throw _b_.ValueError.$factory("incomplete format key")
692
}
693
var key = rslt[1]
694
newpos += rslt[0].length
Mar 23, 2018
695
try{
696
var self = getitem(key)
Mar 19, 2018
697
}catch(err){
698
if(err.name === "KeyError"){
699
throw err
700
}
701
throw _b_.TypeError.$factory("format requires a mapping")
703
return get_string_value(s, self)
704
}
705
706
var $get_arg_string = function(s) {
707
// returns [self, newpos]
708
var self
710
// non-tuple args
Mar 19, 2018
711
if(argpos === null){
712
// args is the value
Mar 19, 2018
714
}else{
715
self = args[argpos++]
Mar 19, 2018
716
if(self === undefined){
717
throw _b_.TypeError.$factory(
718
"not enough arguments for format string")
Sep 5, 2014
719
}
720
}
721
return get_string_value(s, self)
723
var get_string_value = function(s, self) {
724
// todo: get flags, type
725
// todo: string value based on flags, type, value
Mar 19, 2018
726
var flags = {"pad_char": " "}
727
do{
728
var func = char_mapping[s[newpos]]
Mar 23, 2018
729
try{
Mar 19, 2018
730
if(func === undefined){
731
throw new UnsupportedChar()
Mar 19, 2018
732
}else{
733
var ret = func(self, flags)
Mar 19, 2018
734
if(ret !== undefined){
735
return ret
736
}
737
++newpos
738
}
Mar 19, 2018
739
}catch (err){
740
if(err.name == "UnsupportedChar"){
741
invalid_char = s[newpos]
Mar 19, 2018
742
if(invalid_char === undefined){
743
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
745
throw _b_.ValueError.$factory(
746
"unsupported format character '" + invalid_char +
747
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
748
") at index " + newpos)
749
}else if(err.name === "NotANumber"){
750
var try_char = s[newpos],
751
cls = self.__class__
752
if(!cls){
753
if(typeof(self) === "string"){
754
cls = "str"
755
}else{
756
cls = typeof(self)
Mar 19, 2018
758
}else{
Mar 19, 2018
761
throw _b_.TypeError.$factory("%" + try_char +
762
" format: a number is required, not " + cls)
763
}else{
764
throw err
765
}
Sep 5, 2014
766
}
Mar 19, 2018
767
}while (true)
Sep 5, 2014
768
}
769
var nbph = 0 // number of placeholders
Mar 19, 2018
770
do{
771
var newpos = self.indexOf("%", pos)
772
if(newpos < 0){
773
ret += self.substring(pos)
774
break
775
}
776
ret += self.substring(pos, newpos)
777
++newpos
Mar 19, 2018
778
if(newpos < length){
779
if(self[newpos] === "%"){
780
ret += "%"
781
}else{
Mar 19, 2018
783
if(self[newpos] === "("){
784
++newpos
785
ret += $get_kwarg_string(self)
Mar 23, 2018
786
}else{
787
ret += $get_arg_string(self)
788
}
789
}
Mar 19, 2018
790
}else{
791
// % at end of string
792
throw _b_.ValueError.$factory("incomplete format")
793
}
794
pos = newpos + 1
Mar 19, 2018
795
}while(pos < length)
796
797
if(argpos !== null){
798
if(args.length > argpos){
799
throw _b_.TypeError.$factory(
800
"not enough arguments for format string")
801
}else if(args.length < argpos){
802
throw _b_.TypeError.$factory(
803
"not all arguments converted during string formatting")
Mar 19, 2018
805
}else if(nbph == 0){
806
throw _b_.TypeError.$factory(
807
"not all arguments converted during string formatting")
Sep 5, 2014
811
str
Feb 10, 2018
812
str.__mro__ = [object]
Sep 5, 2014
813
str
Feb 10, 2018
814
str.__mul__ = function(){
Mar 19, 2018
815
var $ = $B.args("__mul__", 2, {self: null, other: null},
816
["self", "other"], arguments, {}, null, null)
817
if(! isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
818
"Can't multiply sequence by non-int of type '" +
Mar 19, 2018
820
var $res = ""
821
for(var i = 0; i< $.other; i++){$res += $.self.valueOf()}
Sep 5, 2014
822
return $res
823
}
824
Mar 19, 2018
825
str.__ne__ = function(self,other){return other !== self.valueOf()}
Sep 5, 2014
826
str
Feb 10, 2018
827
str.__repr__ = function(self){
829
// escape the escape char
830
res = self.replace(/\\/g, "\\\\")
831
// special cases
832
res = res.replace(new RegExp("\u0007", "g"), "\\x07").
833
replace(new RegExp("\b", "g"), "\\x08").
834
replace(new RegExp("\u000b", "g"), "\\x0b").
835
replace(new RegExp("\f", "g"), "\\x0c").
836
replace(new RegExp("\n", "g"), "\\n").
837
replace(new RegExp("\r", "g"), "\\r").
838
replace(new RegExp("\t", "g"), "\\t")
Mar 27, 2019
839
res = res.replace(combining_re, "\u200B$1")
840
// Replace unassigned code point by \uabcd...
841
// Uses function $B.is_unicode_cn() in unicode_data.js
842
var repl = ''
843
for(var i = 0; i < res.length; i++){
844
if($B.is_unicode_cn(res.codePointAt(i))){
845
var s = res.codePointAt(i).toString(16)
846
while(s.length < 4){
847
s = '0' + s
848
}
849
repl += '\\u' + s
850
}else{
851
repl += res.charAt(i)
852
}
853
}
854
res = repl
Mar 19, 2018
855
if(res.search('"') == -1 && res.search("'") == -1){
856
return "'" + res + "'"
857
}else if(self.search('"') == -1){
858
return '"' + res + '"'
859
}
860
var qesc = new RegExp("'", "g") // to escape single quote
861
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
862
return res
863
}
864
Mar 19, 2018
865
str.__setitem__ = function(self, attr, value){
866
throw _b_.TypeError.$factory(
867
"'str' object does not support item assignment")
Sep 5, 2014
868
}
Mar 27, 2019
869
var combining = []
870
for(var cp = 0x300; cp <= 0x36F; cp++){
871
combining.push(String.fromCharCode(cp))
872
}
873
var combining_re = new RegExp("(" + combining.join("|") + ")")
str
Feb 10, 2018
875
str.__str__ = function(self){
Mar 27, 2019
876
return self.replace(combining_re, "\u200B$1")
Sep 5, 2014
877
}
Mar 19, 2018
878
str.toString = function(){return "string!"}
Sep 5, 2014
879
880
// generate comparison methods
881
var $comp_func = function(self,other){
882
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
883
return self > other
884
}
Mar 19, 2018
885
$comp_func += "" // source code
886
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
887
for(var $op in $comps){
Mar 19, 2018
888
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
889
}
890
891
// add "reflected" methods
str
Feb 10, 2018
892
$B.make_rmethods(str)
Sep 5, 2014
893
894
// unsupported operations
Mar 19, 2018
895
var $notimplemented = function(self, other){
896
throw NotImplementedError.$factory(
897
"OPERATOR not implemented for class str")
Sep 5, 2014
898
}
899
900
str.capitalize = function(self){
901
var $ = $B.args("capitalize", 1, {self}, ["self"],
902
arguments, {}, null, null)
903
if(self.length == 0){return ""}
904
return self.charAt(0).toUpperCase() + self.substr(1)
905
}
906
907
str.casefold = function(self){
908
var $ = $B.args("casefold", 1, {self}, ["self"],
909
arguments, {}, null, null),
910
res = "",
911
char,
912
cf
913
for(var i = 0, len = self.length; i < len; i++){
914
char = self.charCodeAt(i)
915
cf = $B.unicode_casefold[char]
916
if(cf){
917
cf.forEach(function(cp){
918
res += String.fromCharCode(cp)
919
})
920
}else{
921
res += self.charAt(i).toLowerCase()
922
}
923
}
924
return res
925
}
Sep 5, 2014
926
Mar 19, 2018
927
str.center = function(){
928
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
929
["self", "width", "fillchar"],
930
arguments, {fillchar:" "}, null, null),
931
self = $.self
Mar 19, 2018
933
if($.width <= self.length) {return self}
Mar 19, 2018
935
var pad = parseInt(($.width - self.length) / 2),
936
res = $.fillchar.repeat(pad)
Sep 5, 2014
937
res += self + res
Mar 19, 2018
938
if(res.length < $.width){res += $.fillchar}
Sep 5, 2014
939
return res
940
}
941
str
Feb 10, 2018
942
str.count = function(){
Mar 19, 2018
943
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
944
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
Mar 19, 2018
946
if(!(typeof $.sub == "string")){throw _b_.TypeError.$factory(
947
"Can't convert '" + $B.class_name($.sub) +
Mar 19, 2018
948
"' object to str implicitly")}
Mar 19, 2018
950
if($.start !== null){
Mar 19, 2018
952
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
953
else{_slice = _b_.slice.$factory($.start, $.self.length)}
str
Feb 10, 2018
954
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
Mar 19, 2018
956
if($.self.length + $.sub.length == 0){return 1}
Mar 19, 2018
958
if($.sub.length == 0){
959
if($.start == $.self.length){return 1}
960
else if(substr.length == 0){return 0}
961
return substr.length + 1
Mar 19, 2018
963
var n = 0,
964
pos = 0
965
while(pos < substr.length){
966
pos = substr.indexOf($.sub, pos)
967
if(pos >= 0){n++; pos += $.sub.length}
968
else{break}
Sep 5, 2014
969
}
970
return n
971
}
972
973
str.encode = function(){
974
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
975
["self", "encoding", "errors"], arguments,
976
{encoding: "utf-8", errors: "strict"}, null, null)
977
if($.encoding == "rot13" || $.encoding == "rot_13"){
978
// Special case : returns a string
Mar 19, 2018
979
var res = ""
980
for(var i = 0, len = $.self.length; i < len ; i++){
981
var char = $.self.charAt(i)
Mar 19, 2018
982
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
983
res += String.fromCharCode(String.charCodeAt(char) + 13)
984
}else if(("m" < char && char <= "z") ||
985
("M" < char && char <= "Z")){
986
res += String.fromCharCode(String.charCodeAt(char) - 13)
987
}else{res += char}
988
}
989
return res
990
}
991
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
Sep 5, 2014
992
}
993
str
Feb 10, 2018
994
str.endswith = function(){
995
// Return True if the string ends with the specified suffix, otherwise
996
// return False. suffix can also be a tuple of suffixes to look for.
997
// With optional start, test beginning at that position. With optional
Sep 5, 2014
998
// end, stop comparing at that position.
Mar 19, 2018
999
var $ = $B.args("endswith", 4,
1000
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
1001
["self", "suffix", "start", "end"],
1002
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
1003
1004
normalize_start_end($)
1005
1006
var suffixes = $.suffix
Mar 19, 2018
1007
if(! isinstance(suffixes,_b_.tuple)){suffixes = [suffixes]}
Mar 19, 2018
1009
var s = $.self.substring($.start, $.end)
1010
for(var i = 0, len = suffixes.length; i < len; i++){
1011
var suffix = suffixes[i]
Mar 19, 2018
1012
if(! _b_.isinstance(suffix, str)){throw _b_.TypeError.$factory(
Sep 20, 2015
1013
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1014
if(suffix.length <= s.length &&
1015
s.substr(s.length - suffix.length) == suffix){return true}
Sep 5, 2014
1016
}
1017
return false
1018
}
1019
str
Feb 10, 2018
1020
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
1021
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1022
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1023
var s = $B.$GetInt($.tabsize),
1024
col = 0,
1025
pos = 0,
1026
res = ""
1027
if(s == 1){return self.replace(/\t/g," ")}
1028
while(pos < self.length){
1029
var car = self.charAt(pos)
1030
switch(car){
Mar 19, 2018
1031
case "\t":
Mar 21, 2018
1032
while(col % s > 0){res += " "; col++}
Mar 19, 2018
1034
case "\r":
1035
case "\n":
1036
res += car
1037
col = 0
1038
break
1039
default:
1040
res += car
1041
col++
1042
break
1043
}
1044
pos++
1045
}
Sep 5, 2014
1048
}
1049
str
Feb 10, 2018
1050
str.find = function(){
1051
// Return the lowest index in the string where substring sub is found,
1052
// such that sub is contained in the slice s[start:end]. Optional
1053
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1054
// Return -1 if sub is not found.
Mar 19, 2018
1055
var $ = $B.args("str.find", 4,
1056
{self: null, sub: null, start: null, end: null},
1057
["self", "sub", "start", "end"],
1058
arguments, {start: 0, end: null}, null, null)
1059
check_str($.sub)
Mar 19, 2018
1062
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
1063
throw _b_.TypeError.$factory("slice indices must be " +
1064
"integers or None or have an __index__ method")}
1065
// Can't use string.substring(start, end) because if end < start,
1066
// Javascript transforms it into substring(end, start)...
1067
var s = ""
1068
for(var i = $.start; i < $.end; i++){
1069
s += $.self.charAt(i)
1070
}
Mar 19, 2018
1072
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1073
if(s.length + $.sub.length == 0){return -1}
Mar 19, 2018
1075
var last_search = s.length - $.sub.length
1076
for(var i = 0; i <= last_search; i++){
1077
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
Sep 5, 2014
1078
}
Sep 5, 2014
1080
}
1081
1082
// Next function used by method .format()
1083
1084
$B.parse_format = function(fmt_string){
Sep 5, 2014
1085
1086
// Parse a "format string", as described in the Python documentation
1087
// Return a format object. For the format string
1088
// a.x[z]!r:...
1089
// the object has attributes :
1090
// - name : "a"
1091
// - name_ext : [".x", "[z]"]
1092
// - conv : r
1093
// - spec : rest of string after :
Sep 5, 2014
1094
Mar 19, 2018
1095
var elts = fmt_string.split(":"),
1096
name,
1097
conv,
1098
spec,
Mar 19, 2018
1099
name_ext = []
Mar 19, 2018
1100
if(elts.length == 1){
1101
// No : in the string : it only contains a name
1102
name = fmt_string
1103
}else{
1104
// name is before the first ":"
1105
// spec (the format specification) is after
1106
name = elts[0]
Mar 19, 2018
1107
spec = elts.splice(1).join(":")
Mar 19, 2018
1110
var elts = name.split("!")
1111
if(elts.length > 1){
1112
name = elts[0]
1113
conv = elts[1] // conversion flag
Sep 5, 2014
1115
Mar 19, 2018
1116
if(name !== undefined){
1117
// "name' may be a subscription or attribute
1118
// Put these "extensions" in the list "name_ext"
1119
function name_repl(match){
1120
name_ext.push(match)
Mar 19, 2018
1121
return ""
1122
}
1123
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1124
name = name.replace(name_ext_re, name_repl)
1125
}
Sep 5, 2014
1126
1127
return {name: name, name_ext: name_ext,
1128
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1130
1131
$B.split_format = function(self){
1132
// Parse self to detect formatting instructions
1133
// Create a list "parts" made of sections of the string :
1134
// - elements of even rank are literal text
1135
// - elements of odd rank are "format objects", built from the
1136
// format strings in self (of the form {...})
Mar 19, 2018
1137
var pos = 0,
1138
_len = self.length,
Mar 19, 2018
1140
text = "",
1141
parts = [],
1142
rank = 0
1143
while(pos < _len){
1144
car = self.charAt(pos)
Mar 21, 2018
1145
if(car == "{" && self.charAt(pos + 1) == "{"){
1146
// replace {{ by literal {
Mar 19, 2018
1147
text += "{"
1148
pos += 2
1149
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1150
// replace }} by literal }
Mar 19, 2018
1151
text += "}"
1152
pos += 2
1153
}else if(car == "{"){
1154
// Start of a format string
1156
// Store current literal text
1157
parts.push(text)
1158
1159
// Search the end of the format string, ie the } closing the
1160
// opening {. Since the string can contain other pairs {} for
1161
// nested formatting, an integer nb is incremented for each { and
1162
// decremented for each } ; the end of the format string is
Mar 19, 2018
1163
// reached when nb == 0
1164
var end = pos + 1,
1165
nb = 1
1166
while(end < _len){
1167
if(self.charAt(end) == "{"){nb++; end++}
1168
else if(self.charAt(end) == "}"){
1169
nb--; end++
1170
if(nb == 0){
1171
// End of format string
Mar 19, 2018
1172
var fmt_string = self.substring(pos + 1, end - 1)
1173
1174
// Create a format object, by function parse_format
1175
var fmt_obj = $B.parse_format(fmt_string)
1176
fmt_obj.raw_name = fmt_obj.name
1177
fmt_obj.raw_spec = fmt_obj.spec
1178
1179
// If no name is explicitely provided, use the rank
1180
if(!fmt_obj.name){
Mar 19, 2018
1181
fmt_obj.name = rank + ""
Sep 5, 2014
1184
Mar 19, 2018
1185
if(fmt_obj.spec !== undefined){
1186
// "spec" may contain "nested replacement fields"
1187
// Replace empty fields by the rank in positional
1188
// arguments
1189
function replace_nested(name, key){
1190
if(key == ""){
1191
// Use implicit rank
1192
return "{" + rank++ + "}"
1196
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1197
replace_nested)
1198
}
1200
// Store format object in list "parts"
1201
parts.push(fmt_obj)
Mar 19, 2018
1202
text = ""
1203
break
1204
}
1205
}else{end++}
Sep 5, 2014
1206
}
Mar 19, 2018
1207
if(nb > 0){throw ValueError.$factory("wrong format " + self)}
Mar 19, 2018
1209
}else{text += car; pos++}
Sep 5, 2014
1210
}
1211
if(text){parts.push(text)}
1212
return parts
1213
}
1214
1215
str.format = function(self) {
1216
var $ = $B.args("format", 1, {self: null}, ["self"],
1217
arguments, {}, "$args", "$kw")
1218
1219
var parts = $B.split_format($.self)
1220
1221
// Apply formatting to the values passed to format()
Mar 19, 2018
1222
var res = "",
1223
fmt
Mar 19, 2018
1225
for(var i = 0; i < parts.length; i++){
1226
// Literal text is added unchanged
Mar 19, 2018
1227
if(typeof parts[i] == "string"){res += parts[i]; continue}
1229
// Format objects
1230
fmt = parts[i]
1231
1232
if(fmt.spec !== undefined){
1233
// "spec" may contain "nested replacement fields"
1234
// In this case, evaluate them using the positional
1235
// or keyword arguments passed to format()
1236
function replace_nested(name, key){
1237
if(/\d+/.exec(key)){
1238
// If key is numeric, search in positional
1239
// arguments
1240
return _b_.tuple.__getitem__($.$args,
1241
parseInt(key))
1242
}else{
1243
// Else try in keyword arguments
1244
return _b_.dict.__getitem__($.$kw, key)
1245
}
1246
}
1247
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1248
replace_nested)
1249
}
Mar 21, 2018
1250
if(fmt.name.charAt(0).search(/\d/) > -1){
1251
// Numerical reference : use positional arguments
1252
var pos = parseInt(fmt.name),
Feb 11, 2018
1253
value = _b_.tuple.__getitem__($.$args, pos)
1254
}else{
1255
// Use keyword arguments
Feb 11, 2018
1256
var value = _b_.dict.__getitem__($.$kw, fmt.name)
1257
}
1258
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1259
for(var j = 0; j < fmt.name_ext.length; j++){
1260
var ext = fmt.name_ext[j]
Mar 19, 2018
1261
if(ext.charAt(0) == "."){
1262
// Attribute
1263
value = _b_.getattr(value, ext.substr(1))
1264
}else{
1265
// Subscription
Mar 19, 2018
1266
var key = ext.substr(1, ext.length - 2)
1267
// An index made of digits is transformed into an integer
Mar 19, 2018
1268
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1269
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1272
1273
// If the conversion flag is set, first call a function to convert
1274
// the value
Mar 19, 2018
1275
if(fmt.conv == "a"){value = _b_.ascii(value)}
1276
else if(fmt.conv == "r"){value = _b_.repr(value)}
1277
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1279
// Call attribute __format__ to perform the actual formatting
1280
if(value.$is_class || value.$factory){
1281
// For classes, don't use the class __format__ method
1282
res += value.__class__.__format__(value, fmt.spec)
1284
res += $B.$getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1286
}
Sep 5, 2014
1288
}
1289
str
Feb 10, 2018
1290
str.format_map = function(self) {
Mar 19, 2018
1291
throw NotImplementedError.$factory(
1292
"function format_map not implemented yet")
Sep 5, 2014
1293
}
1294
str
Feb 10, 2018
1295
str.index = function(self){
Sep 5, 2014
1296
// Like find(), but raise ValueError when the substring is not found.
1297
var res = str.find.apply(null, arguments)
Mar 19, 2018
1298
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1299
return res
1300
}
1301
1302
str.isascii = function(self){
1303
/* Return true if the string is empty or all characters in the string are
1304
ASCII, false otherwise. ASCII characters have code points in the range
1305
U+0000-U+007F. */
1306
for(var i = 0, len = self.length; i < len; i++){
1307
if(self.charCodeAt(i) > 127){return false}
1308
}
1309
return true
1310
}
1311
1312
str.isalnum = function(self){
1313
/* Return true if all characters in the string are alphanumeric and there
1314
is at least one character, false otherwise. A character c is alphanumeric
1315
if one of the following returns True: c.isalpha(), c.isdecimal(),
1316
c.isdigit(), or c.isnumeric(). */
1317
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1318
arguments, {}, null, null),
1319
char
1320
for(var i = 0, len = self.length; i < len; i++){
1321
char = self.charCodeAt(i)
1322
if(unicode_tables.Ll[char] ||
1323
unicode_tables.Lu[char] ||
1324
unicode_tables.Lm[char] ||
1325
unicode_tables.Lt[char] ||
1326
unicode_tables.Lo[char] ||
1327
unicode_tables.Nd[char] ||
1328
unicode_tables.digits[char] ||
1329
unicode_tables.numeric[char]){
1330
continue
1331
}
1332
return false
1333
}
1334
return true
1335
}
1336
1337
str.isalpha = function(self){
1338
/* Return true if all characters in the string are alphabetic and there is
1339
at least one character, false otherwise. Alphabetic characters are those
1340
characters defined in the Unicode character database as "Letter", i.e.,
1341
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1342
or "Lo". */
1343
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1344
arguments, {}, null, null),
1345
char
1346
for(var i = 0, len = self.length; i < len; i++){
1347
char = self.charCodeAt(i)
1348
if(unicode_tables.Ll[char] ||
1349
unicode_tables.Lu[char] ||
1350
unicode_tables.Lm[char] ||
1351
unicode_tables.Lt[char] ||
1352
unicode_tables.Lo[char]){
1353
continue
1354
}
1355
return false
1356
}
1357
return true
1358
}
1359
1360
str.isdecimal = function(self){
1361
/* Return true if all characters in the string are decimal characters and
1362
there is at least one character, false otherwise. Decimal characters are
1363
those that can be used to form numbers in base 10, e.g. U+0660,
1364
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1365
the Unicode General Category "Nd". */
1366
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1367
arguments, {}, null, null),
1368
char
1369
for(var i = 0, len = self.length; i < len; i++){
1370
char = self.charCodeAt(i)
1371
if(! unicode_tables.Nd[char]){
1372
return false
1373
}
1374
}
1375
return self.length > 0
1376
}
1377
1378
str.isdigit = function(self){
1379
/* Return true if all characters in the string are digits and there is at
1380
least one character, false otherwise. */
1381
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1382
arguments, {}, null, null),
1383
char
1384
for(var i = 0, len = self.length; i < len; i++){
1385
char = self.charCodeAt(i)
1386
if(! unicode_tables.digits[char]){
1387
return false
1388
}
1389
}
1390
return self.length > 0
1391
}
1392
1393
str.isidentifier = function(self){
1394
/* Return true if the string is a valid identifier according to the
1395
language definition. */
1396
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1397
arguments, {}, null, null),
1398
char
1399
if(self.length == 0){return false}
1400
else if(unicode_tables.XID_Start[self.charCodeAt(0)] === undefined){
1401
return false
1402
}else{
1403
for(var i = 1, len = self.length; i < len; i++){
1404
if(unicode_tables.XID_Continue[self.charCodeAt(i)] === undefined){
1405
return false
1406
}
1407
}
1408
}
1409
return true
1410
}
1411
1412
str.islower = function(self){
1413
/* Return true if all cased characters 4 in the string are lowercase and
1414
there is at least one cased character, false otherwise. */
1415
var $ = $B.args("islower", 1, {self: null}, ["self"],
1416
arguments, {}, null, null),
1417
has_cased = false,
1418
char
1419
1420
for(var i = 0, len = self.length; i < len; i++){
1421
char = self.charCodeAt(i)
1422
if(unicode_tables.Ll[char]){has_cased = true; continue}
1423
else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1424
return false
1425
}
1426
}
1427
return has_cased
1428
}
1429
1430
str.isnumeric = function(self){
1431
/* Return true if all characters in the string are numeric characters, and
1432
there is at least one character, false otherwise. Numeric characters
1433
include digit characters, and all characters that have the Unicode numeric
1434
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1435
characters are those with the property value Numeric_Type=Digit,
1436
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1437
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1438
arguments, {}, null, null)
1439
for(var i = 0, len = self.length; i < len; i++){
1440
if(! unicode_tables.numeric[self.charCodeAt(i)]){
1441
return false
1442
}
1443
}
1444
return self.length > 0
1445
}
1446
1447
var printable,
1448
printable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1449
1450
str.isprintable = function(self){
1451
/* Return true if all characters in the string are printable or the string
1452
is empty, false otherwise. Nonprintable characters are those characters
1453
defined in the Unicode character database as "Other" or "Separator",
1454
excepting the ASCII space (0x20) which is considered printable. */
1455
1456
// Set printable if not set yet
1457
if(printable === undefined){
1458
for(var i = 0; i < printable_gc.length; i++){
1459
var table = unicode_tables[printable_gc[i]]
1460
for(var cp in table){
1461
printable[cp] = true
1462
}
1463
}
1464
printable[32] = true
1465
}
1466
1467
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1468
arguments, {}, null, null),
1469
char,
1470
flag
1471
for(var i = 0, len = self.length; i < len; i++){
1472
char = self.charCodeAt(i)
1473
if(! printable[char]){
1474
return false
1475
}
1476
}
1477
return true
1478
}
1479
1480
str.isspace = function(self){
1481
/* Return true if there are only whitespace characters in the string and
1482
there is at least one character, false otherwise.
1483
1484
A character is whitespace if in the Unicode character database, either its
1485
general category is Zs ("Separator, space"), or its bidirectional class is
1486
one of WS, B, or S.*/
1487
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1488
arguments, {}, null, null),
1489
char
1490
for(var i = 0, len = self.length; i < len; i++){
1491
char = self.charCodeAt(i)
1492
if(! unicode_tables.Zs[char] &&
1493
$B.unicode_bidi_whitespace.indexOf(char) == -1){
1494
return false
1495
}
1496
}
1497
return self.length > 0
1498
}
1499
1500
str.istitle = function(self){
1501
/* Return true if the string is a titlecased string and there is at least
1502
one character, for example uppercase characters may only follow uncased
1503
characters and lowercase characters only cased ones. Return false
1504
otherwise. */
1505
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1506
arguments, {}, null, null)
1507
return self.length > 0 && str.title(self) == self
1508
}
1509
1510
str.isupper = function(self){
1511
/* Return true if all cased characters 4 in the string are lowercase and
1512
there is at least one cased character, false otherwise. */
1513
var $ = $B.args("islower", 1, {self: null}, ["self"],
1514
arguments, {}, null, null),
1515
has_cased = false,
1516
char
1517
1518
for(var i = 0, len = self.length; i < len; i++){
1519
char = self.charCodeAt(i)
1520
if(unicode_tables.Lu[char]){has_cased = true; continue}
1521
else if(unicode_tables.Ll[char] || unicode_tables.Lt[char]){
1522
return false
1523
}
1524
}
1525
return has_cased
1526
}
1527
1528
str
Feb 10, 2018
1529
str.join = function(){
Mar 19, 2018
1530
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1531
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1533
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1534
res = [],
Sep 5, 2014
1536
while(1){
1537
try{
1538
var obj2 = _b_.next(iterable)
Mar 19, 2018
1539
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1540
"sequence item " + count + ": expected str instance, " +
1541
$B.class_name(obj2) + " found")}
1542
res.push(obj2)
Sep 5, 2014
1543
}catch(err){
1544
if(_b_.isinstance(err, _b_.StopIteration)){
1545
break
1546
}
Sep 5, 2014
1547
else{throw err}
1548
}
1549
}
1550
return res.join($.self)
Sep 5, 2014
1551
}
1552
str
Feb 10, 2018
1553
str.ljust = function(self) {
Mar 19, 2018
1554
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1555
["self", "width", "fillchar"],
1556
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1558
if($.width <= self.length){return self}
1559
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1560
}
1561
1562
str.lower = function(self){
1563
var $ = $B.args("lower", 1, {self: null}, ["self"],
1564
arguments, {}, null, null)
1565
return self.toLowerCase()
1566
}
1567
str
Feb 10, 2018
1568
str.lstrip = function(self,x){
Mar 19, 2018
1569
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1570
arguments, {chars:_b_.None}, null, null)
1571
if($.chars === _b_.None){return $.self.trimLeft()}
1572
for(var i = 0; i < $.self.length; i++){
1573
if($.chars.indexOf($.self.charAt(i)) === -1){
1574
return $.self.substring(i)
Mar 19, 2018
1577
return ""
Sep 5, 2014
1578
}
1579
1580
// note, maketrans should be a static function.
str
Feb 10, 2018
1581
str.maketrans = function() {
Mar 19, 2018
1582
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1583
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1587
if($.y === null && $.z === null){
1588
// If there is only one argument, it must be a dictionary mapping
1589
// Unicode ordinals (integers) or characters (strings of length 1) to
1590
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1591
// keys will then be converted to ordinals.
Mar 19, 2018
1592
if(! _b_.isinstance($.x, _b_.dict)){
1593
throw _b_.TypeError.$factory(
1594
"maketrans only argument must be a dict")
Feb 11, 2018
1596
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1597
for(var i = 0, len = items.length; i < len; i++){
1598
var k = items[i][0],
1599
v = items[i][1]
1600
if(! _b_.isinstance(k, _b_.int)){
1601
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1602
k = _b_.ord(k)
1603
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1604
" is not int or 1-char string")}
1605
}
Mar 19, 2018
1606
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1607
throw _b_.TypeError.$factory("dictionary value " + v +
1608
" is not None, integer or string")
1609
}
1610
_b_.dict.$setitem(_t, k, v)
1611
}
1612
return _t
1613
}else{
1614
// If there are two arguments, they must be strings of equal length,
1615
// and in the resulting dictionary, each character in x will be mapped
1616
// to the character at the same position in y
Mar 19, 2018
1617
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1618
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1619
}else if($.x.length !== $.y.length){
1620
throw _b_.TypeError.$factory(
1621
"maketrans arguments must be strings or same length")
1622
}else{
1623
var toNone = {}
Mar 19, 2018
1624
if($.z !== null){
1625
// If there is a third argument, it must be a string, whose
1626
// characters will be mapped to None in the result
Mar 19, 2018
1627
if(! _b_.isinstance($.z, _b_.str)){
1628
throw _b_.TypeError.$factory(
1629
"maketrans third argument must be a string")
Mar 19, 2018
1631
for(var i = 0, len = $.z.length; i < len; i++){
1632
toNone[_b_.ord($.z.charAt(i))] = true
1633
}
Mar 19, 2018
1635
for(var i = 0, len = $.x.length; i < len; i++){
1636
var key = _b_.ord($.x.charAt(i)),
1638
_b_.dict.$setitem(_t, key, value)
1639
}
1640
for(var k in toNone){
1641
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1642
}
1643
return _t
1644
}
1645
}
Sep 5, 2014
1646
}
1647
1648
str.maketrans.$type = "staticmethod"
1649
str
Feb 10, 2018
1650
str.partition = function() {
Mar 19, 2018
1651
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1652
arguments, {}, null, null)
Mar 19, 2018
1653
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1654
check_str($.sep)
1655
var i = $.self.indexOf($.sep)
Mar 23, 2018
1656
if(i == -1){return _b_.tuple.$factory([$.self, "", ""])}
Mar 19, 2018
1657
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1658
$.self.substring(i + $.sep.length)])
1659
}
1660
1661
str.removeprefix = function(){
1662
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1663
["self", "prefix"], arguments, {}, null, null)
1664
if(!_b_.isinstance($.prefix, str)){
1665
throw _b_.ValueError.$factory("prefix should be str, not " +
1666
`'${$B.class_name($.prefix)}'`)
1667
}
1668
if(str.startswith($.self, $.prefix)){
1669
return $.self.substr($.prefix.length)
1670
}
1671
return $.self.substr(0)
1672
}
1673
1674
str.removesuffix = function(){
1675
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1676
["self", "suffix"], arguments, {}, null, null)
1677
if(!_b_.isinstance($.suffix, str)){
1678
throw _b_.ValueError.$factory("suffix should be str, not " +
1679
`'${$B.class_name($.prefix)}'`)
1680
}
1681
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1682
return $.self.substr(0, $.self.length - $.suffix.length)
1683
}
1684
return $.self.substr(0)
1685
}
1686
Mar 19, 2018
1687
function $re_escape(str){
1688
var specials = "[.*+?|()$^"
1689
for(var i = 0, len = specials.length; i < len; i++){
1690
var re = new RegExp("\\"+specials.charAt(i), "g")
1691
str = str.replace(re, "\\"+specials.charAt(i))
1692
}
1693
return str
Sep 5, 2014
1694
}
1695
str
Feb 10, 2018
1696
str.replace = function(self, old, _new, count) {
1697
// Replaces occurrences of 'old' by '_new'. Count references
1698
// the number of times to replace. In CPython, negative or undefined
1699
// values of count means replace all.
Mar 19, 2018
1700
var $ = $B.args("replace", 4,
1701
{self: null, old: null, $$new: null, count: null},
1702
["self", "old", "$$new", "count"],
1703
arguments, {count: -1}, null, null),
1704
count = $.count,
1705
self = $.self,
1706
old = $.old,
1707
_new = $.$$new
1708
// Validate type of old
1709
check_str(old)
1710
check_str(_new)
1711
// Validate instance type of 'count'
Mar 23, 2018
1712
if(! isinstance(count,[_b_.int, _b_.float])){
1713
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1714
"' object cannot be interpreted as an integer")
1715
}else if(isinstance(count, _b_.float)){
1716
throw _b_.TypeError.$factory("integer argument expected, got float")
1717
}
1718
if(count == 0){return self}
1719
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1720
if(old == ""){
1721
if(_new == ""){return self}
1722
if(self == ""){return _new}
1723
var elts = self.split("")
1724
if(count > -1 && elts.length >= count){
1725
var rest = elts.slice(count).join("")
1726
return _new + elts.slice(0, count).join(_new) + rest
1727
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1729
var elts = str.split(self, old, count)
Sep 5, 2014
1730
}
Mar 19, 2018
1732
var res = self,
1733
pos = -1
1734
if(old.length == 0){
Mar 19, 2018
1736
for(var i = 0; i < elts.length; i++){
1737
res += elts[i] + _new
Mar 19, 2018
1739
return res + rest
Mar 19, 2018
1742
if(count < 0){count = res.length}
1743
while(count > 0){
1744
pos = res.indexOf(old, pos)
1745
if(pos < 0){break}
1746
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1747
pos = pos + _new.length
1748
count--
Mar 19, 2018
1750
return res
Sep 5, 2014
1751
}
1752
1753
str.rfind = function(self, substr){
1754
// Return the highest index in the string where substring sub is found,
1755
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1756
// start and end are interpreted as in slice notation. Return -1 on failure.
1757
if(arguments.length == 2 && typeof substr == "string"){
1758
return self.lastIndexOf(substr)
1759
}
Mar 19, 2018
1760
var $ = $B.args("rfind", 4,
Mar 19, 2018
1761
{self: null, sub: null, start: null, end: null},
1762
["self", "sub", "start", "end"],
1763
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1764
1767
check_str($.sub)
Mar 19, 2018
1769
if($.sub.length == 0){
1770
if($.start > $.self.length){return -1}
1771
else{return $.self.length}
1772
}
1773
var sublen = $.sub.length
Mar 19, 2018
1775
for(var i = $.end - sublen; i >= $.start; i--){
1776
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1779
}
1780
str
Feb 10, 2018
1781
str.rindex = function(){
Sep 5, 2014
1782
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1783
var res = str.rfind.apply(null, arguments)
1784
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1785
return res
1786
}
1787
str
Feb 10, 2018
1788
str.rjust = function(self) {
Mar 19, 2018
1789
var $ = $B.args("rjust",3,
1790
{self: null, width: null, fillchar: null},
1791
["self", "width", "fillchar"],
1792
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1793
Mar 19, 2018
1794
if($.width <= self.length){return self}
Sep 5, 2014
1795
1796
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1797
}
1798
str
Feb 10, 2018
1799
str.rpartition = function(self,sep) {
Mar 19, 2018
1800
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1801
arguments, {}, null, null)
1802
check_str($.sep)
1803
var self = reverse($.self),
1804
sep = reverse($.sep)
Mar 19, 2018
1805
var items = str.partition(self, sep).reverse()
1806
for(var i = 0; i < items.length; i++){
1807
items[i] = items[i].split("").reverse().join("")
1808
}
1809
return items
Sep 5, 2014
1810
}
1811
str
Feb 10, 2018
1812
str.rsplit = function(self) {
Mar 19, 2018
1813
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1814
["self", "sep", "maxsplit"], arguments,
1815
{sep: _b_.None, maxsplit: -1}, null, null),
1816
sep = $.sep
1817
1818
// Use split on the reverse of the string and of separator
1819
var rev_str = reverse($.self),
1820
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1821
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1823
// Reverse the list, then each string inside the list
1824
rev_res.reverse()
Mar 19, 2018
1825
for(var i = 0; i < rev_res.length; i++){
1826
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1829
}
1830
Mar 19, 2018
1831
str.rstrip = function(self, x){
1832
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1833
arguments, {chars: _b_.None}, null, null)
1834
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1835
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1836
if($.chars.indexOf($.self.charAt(j)) == -1){
1837
return $.self.substring(0, j + 1)
Mar 19, 2018
1840
return ""
Sep 5, 2014
1841
}
1842
str
Feb 10, 2018
1843
str.split = function(){
Mar 19, 2018
1844
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1845
["self", "sep", "maxsplit"], arguments,
1846
{sep: _b_.None, maxsplit: -1}, null, null),
1847
sep = $.sep,
1848
maxsplit = $.maxsplit,
1849
self = $.self,
1850
pos = 0
1851
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1852
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1853
if(sep === _b_.None){
Sep 5, 2014
1854
var res = []
Mar 19, 2018
1855
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1856
if(pos === self.length - 1){return [self]}
1857
var name = ""
Sep 5, 2014
1858
while(1){
Mar 19, 2018
1859
if(self.charAt(pos).search(/\s/) == -1){
1860
if(name == ""){name = self.charAt(pos)}
1861
else{name += self.charAt(pos)}
Sep 5, 2014
1862
}else{
Mar 19, 2018
1863
if(name !== ""){
Sep 5, 2014
1864
res.push(name)
Mar 19, 2018
1865
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1866
res.pop()
Mar 19, 2018
1867
res.push(name + self.substr(pos))
Sep 5, 2014
1868
return res
1869
}
Mar 19, 2018
1870
name = ""
Sep 5, 2014
1871
}
1872
}
1873
pos++
Mar 19, 2018
1874
if(pos > self.length - 1){
Sep 5, 2014
1875
if(name){res.push(name)}
1876
break
1877
}
1878
}
1879
return res
1880
}else{
Mar 19, 2018
1881
var res = [],
1882
s = "",
1883
seplen = sep.length
1884
if(maxsplit == 0){return [self]}
1885
while(pos < self.length){
1886
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1889
if(maxsplit > -1 && res.length >= maxsplit){
1890
res.push(self.substr(pos))
1891
return res
1892
}
Mar 19, 2018
1893
s = ""
1894
}else{
1895
s += self.charAt(pos)
1896
pos++
Sep 5, 2014
1897
}
1898
}
Sep 5, 2014
1901
}
1902
}
1903
1904
str.splitlines = function(self) {
1905
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
1906
['self','keepends'], arguments, {keepends: false},
1907
null, null)
1908
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
1909
throw _b_.TypeError('integer argument expected, got '+
1910
$B.get_class($.keepends).__name)
1911
}
1912
var keepends = _b_.int.$factory($.keepends),
1913
res = [],
1914
self = $.self,
1915
start = 0,
1916
pos = 0
1917
if(!self.length){
1918
return res
1919
}
1920
while (pos < self.length) {
1921
if(self.substr(pos, 2) == '\r\n'){
1922
res.push(self.slice(start, keepends ? pos + 2 : pos))
1923
start = pos = pos+2
1924
}else if(self[pos] == '\r' || self[pos] == '\n'){
1925
res.push(self.slice(start, keepends ? pos+1 : pos))
1926
start = pos = pos+1
1927
}else{
1928
pos++
1929
}
1930
}
1931
if(start < self.length){
1932
res.push(self.slice(start))
1933
}
1934
return res
1935
}
Sep 5, 2014
1936
str
Feb 10, 2018
1937
str.startswith = function(){
1938
// Return True if string starts with the prefix, otherwise return False.
1939
// prefix can also be a tuple of prefixes to look for. With optional
1940
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1941
// stop comparing string at that position.
Mar 19, 2018
1942
var $ = $B.args("startswith", 4,
1943
{self: null, prefix: null, start: null, end: null},
1944
["self", "prefix", "start", "end"],
1945
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1946
1947
normalize_start_end($)
1948
1949
var prefixes = $.prefix
Mar 19, 2018
1950
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1952
var s = $.self.substring($.start, $.end)
1953
for(var i = 0, len = prefixes.length; i < len; i++){
1954
var prefix = prefixes[i]
Mar 19, 2018
1955
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1956
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1957
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1958
}
1959
return false
1960
Sep 5, 2014
1961
}
1962
str
Feb 10, 2018
1963
str.strip = function(){
Mar 19, 2018
1964
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1965
arguments, {chars: _b_.None}, null, null)
1966
if($.chars === _b_.None){return $.self.trim()}
1967
for(var i = 0; i < $.self.length; i++){
1968
if($.chars.indexOf($.self.charAt(i)) == -1){
1969
break
Mar 19, 2018
1972
for(var j = $.self.length - 1; j >= i; j--){
1973
if($.chars.indexOf($.self.charAt(j)) == -1){
1974
break
Mar 19, 2018
1977
return $.self.substring(i, j + 1)
Sep 5, 2014
1978
}
1979
1980
str.swapcase = function(self){
1981
var $ = $B.args("swapcase", 1, {self}, ["self"],
1982
arguments, {}, null, null),
1983
res = "",
1984
char
1985
1986
for(var i = 0, len = self.length; i < len; i++){
1987
char = self.charCodeAt(i)
1988
if(unicode_tables.Ll[char]){
1989
res += self.charAt(i).toUpperCase()
1990
}else if(unicode_tables.Lu[char]){
1991
res += self.charAt(i).toLowerCase()
1992
}else{
1993
res += self.charAt(i)
1994
}
1995
}
1996
return res
1997
}
1998
1999
str.title = function(self){
2000
var $ = $B.args("title", 1, {self}, ["self"],
2001
arguments, {}, null, null),
2002
state,
2003
char,
2004
res = ""
2005
for(var i = 0, len = self.length; i < len; i++){
2006
char = self.charCodeAt(i)
2007
if(unicode_tables.Ll[char]){
2008
if(! state){
2009
res += self.charAt(i).toUpperCase()
2010
state = "word"
2011
}else{
2012
res += self.charAt(i)
2013
}
2014
}else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
2015
res += state ? self.charAt(i).toLowerCase() : self.charAt(i)
2016
state = "word"
2017
}else{
2018
state = null
2019
res += self.charAt(i)
2020
}
2021
}
2022
return res
2023
}
2024
2025
str.translate = function(self, table){
Mar 19, 2018
2026
var res = [],
2027
getitem = $B.$getattr(table, "__getitem__")
2028
for(var i = 0, len = self.length; i < len; i++){
2029
try{
2030
var repl = getitem(self.charCodeAt(i))
2031
if(repl !== _b_.None){
2032
if(typeof repl == "string"){
2033
res.push(repl)
2034
}else if(typeof repl == "number"){
2035
res.push(String.fromCharCode(repl))
2036
}
2037
}
2038
}catch(err){
2039
res.push(self.charAt(i))
2040
}
Sep 5, 2014
2041
}
Mar 19, 2018
2042
return res.join("")
Sep 5, 2014
2043
}
2044
2045
str.upper = function(self){
2046
var $ = $B.args("upper", 1, {self: null}, ["self"],
2047
arguments, {}, null, null)
2048
return self.toUpperCase()
2049
}
2050
Mar 19, 2018
2051
str.zfill = function(self, width){
Mar 19, 2018
2052
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
2053
["self", "width"], arguments, {}, null, null)
2054
if($.width <= self.length){return self}
Mar 19, 2018
2056
case "+":
2057
case "-":
2058
return self.charAt(0) +
2059
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
2061
return "0".repeat(width - self.length) + self
Sep 5, 2014
2063
}
2064
2065
str.$factory = function(arg, encoding, errors){
2066
if(arguments.length == 0){return ""}
2068
return $B.UndefinedClass.__str__()
2070
if(encoding !== undefined){
2071
// Arguments may be passed as keywords (cf. issue #1060)
2072
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2073
["arg", "encoding", "errors"], arguments,
2074
{encoding: "utf-8", errors: "strict"}, null, null),
2075
encoding = $.encoding,
2076
errors = $.errors
2077
}
2078
switch(typeof arg) {
Mar 19, 2018
2079
case "string":
Mar 27, 2019
2080
return str.__str__(arg)
Mar 19, 2018
2081
case "number":
2082
if(isFinite(arg)){return arg.toString()}
2085
if(arg.$is_class || arg.$factory){
2086
// arg is a class
2087
// In this case, str() doesn't use the attribute __str__ of the
2088
// class or its subclasses, but the attribute __str__ of the
2089
// class metaclass (usually "type") or its subclasses (usually
2090
// "object")
2091
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
2092
var func = $B.$getattr(arg.__class__, "__str__")
2094
}
2096
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2097
encoding !== undefined){
2098
// str(bytes, encoding, errors) is equal to
2099
// bytes.decode(encoding, errors)
2100
return _b_.bytes.decode(arg, $.encoding, $.errors)
2102
// Implicit invocation of __str__ uses method __str__ on the class,
2103
// even if arg has an attribute __str__
2104
var klass = arg.__class__ || $B.get_class(arg)
2105
if(klass === undefined){
2106
return $B.JSObject.__str__($B.JSObject.$factory(arg))
2107
}
2108
var method = $B.$getattr(klass , "__str__", null)
2109
if(method === null ||
2110
// if not better than object.__str__, try __repr__
2111
(arg.__class__ && arg.__class__ !== _b_.object &&
2112
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2113
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2115
}
2116
catch(err){
2117
console.log("no __str__ for", arg)
Mar 19, 2018
2118
console.log("err ", err)
2119
if($B.debug > 1){console.log(err)}
2120
console.log("Warning - no method __str__ or __repr__, " +
2121
"default to toString", arg)
May 20, 2019
2122
throw err
Sep 5, 2014
2123
}
2124
return $B.$call(method)(arg)
Sep 5, 2014
2125
}
str
Feb 10, 2018
2126
2127
str.__new__ = function(cls){
Mar 19, 2018
2128
if(cls === undefined){
2129
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2130
}
Mar 19, 2018
2131
return {__class__: cls}
Sep 5, 2014
2132
}
2133
str
Feb 10, 2018
2134
$B.set_func_names(str, "builtins")
Sep 5, 2014
2136
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2137
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2138
__class__: _b_.type,
str
Feb 10, 2018
2139
__mro__: [object],
2140
$infos: {
2141
__module__: "builtins",
2142
__name__: "str"
2143
},
str
Feb 10, 2018
2144
$is_class: true
Sep 5, 2014
2145
}
2146
str
Feb 10, 2018
2147
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2148
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2149
for(var $attr in str){
Mar 19, 2018
2150
if(typeof str[$attr] == "function"){
Mar 19, 2018
2151
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2152
return function(){
Mar 19, 2018
2153
var args = [],
2154
pos = 0
2155
if(arguments.length > 0){
2156
var args = [arguments[0].valueOf()],
2157
pos = 1
2158
for(var i = 1, len = arguments.length; i < len; i++){
2159
args[pos++] = arguments[i]
Sep 5, 2014
2160
}
2161
}
Mar 19, 2018
2162
return str[attr].apply(null, args)
Sep 5, 2014
2163
}
2164
})($attr)
2165
}
2166
}
str
Feb 10, 2018
2167
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2170
str
Feb 10, 2018
2171
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2173
_b_.str = str
2174
2175
// Function to parse the 2nd argument of format()
2176
$B.parse_format_spec = function(spec){
Mar 19, 2018
2177
if(spec == ""){this.empty = true}
2178
else{
Mar 19, 2018
2179
var pos = 0,
2180
aligns = "<>=^",
2181
digits = "0123456789",
2182
types = "bcdeEfFgGnosxX%",
2183
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2184
if(align_pos != -1){
2185
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2186
// If the second char is also an alignment specifier, the
2187
// first char is the fill value
2188
this.fill = spec.charAt(0)
2189
this.align = spec.charAt(1)
2190
pos = 2
2191
}else{
2192
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2193
this.align = aligns[align_pos]
2194
this.fill = " "
2195
pos++
2196
}
2197
}else{
2198
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2199
if(spec.charAt(1) && align_pos != -1){
2200
// The second character defines alignment : fill is the first one
Mar 19, 2018
2201
this.align = aligns[align_pos]
2202
this.fill = spec.charAt(0)
2203
pos = 2
2204
}
2205
}
2206
var car = spec.charAt(pos)
Mar 19, 2018
2207
if(car == "+" || car == "-" || car == " "){
2208
this.sign = car
2209
pos++
2210
car = spec.charAt(pos)
Mar 19, 2018
2212
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
2213
if(car == "0"){
Mar 19, 2018
2214
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2215
this.fill = "0"
2216
if(align_pos == -1){
2217
this.align = "="
2218
}
Mar 19, 2018
2219
pos++
2220
car = spec.charAt(pos)
2221
}
Mar 19, 2018
2222
while(car && digits.indexOf(car) > -1){
2223
if(this.width === undefined){this.width = car}
2224
else{this.width += car}
2225
pos++
2226
car = spec.charAt(pos)
Mar 19, 2018
2228
if(this.width !== undefined){this.width = parseInt(this.width)}
2229
if(this.width === undefined && car == "{"){
2230
// Width is determined by a parameter
2231
var end_param_pos = spec.substr(pos).search("}")
2232
this.width = spec.substring(pos, end_param_pos)
2233
console.log("width", "[" + this.width + "]")
2234
pos += end_param_pos + 1
2235
}
Mar 19, 2018
2236
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
2237
if(car == "."){
2238
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2239
throw _b_.ValueError.$factory(
2240
"Missing precision in format spec")
Mar 19, 2018
2242
this.precision = spec.charAt(pos + 1)
2243
pos += 2
2244
car = spec.charAt(pos)
2245
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2246
this.precision += car
Mar 19, 2018
2247
pos++
2248
car = spec.charAt(pos)
2249
}
2250
this.precision = parseInt(this.precision)
2251
}
Mar 19, 2018
2252
if(car && types.indexOf(car) > -1){
2253
this.type = car
2254
pos++
2255
car = spec.charAt(pos)
2256
}
2257
if(pos !== spec.length){
2258
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2262
this.toString = function(){
Mar 19, 2018
2263
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2264
(this.align || "") +
2265
(this.sign || "") +
2266
(this.alternate ? "#" : "") +
2267
(this.sign_aware ? "0" : "") +
2268
(this.width || "") +
2269
(this.comma ? "," : "") +
2270
(this.precision ? "." + this.precision : "") +
2271
(this.type || "")
2272
}
2273
}
2274
2275
$B.format_width = function(s, fmt){
Mar 19, 2018
2276
if(fmt.width && s.length < fmt.width){
2277
var fill = fmt.fill || " ",
2278
align = fmt.align || "<",
2279
missing = fmt.width - s.length
2280
switch(align){
Mar 19, 2018
2281
case "<":
2282
return s + fill.repeat(missing)
2283
case ">":
2284
return fill.repeat(missing) + s
2285
case "=":
2286
if("+-".indexOf(s.charAt(0)) > -1){
2287
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2288
}else{
Mar 19, 2018
2289
return fill.repeat(missing) + s
Mar 19, 2018
2291
case "^":
2292
var left = parseInt(missing / 2)
2293
return fill.repeat(left) + s + fill.repeat(missing - left)
2294
}
2295
}
2296
return s
2297
}
2298
2299
function fstring_expression(){
Mar 19, 2018
2300
this.type = "expression"
2301
this.expression = ""
2302
this.conversion = null
2303
this.fmt = null
2304
}
2305
2306
$B.parse_fstring = function(string){
2307
// Parse a f-string
2308
var elts = [],
2309
pos = 0,
Mar 19, 2018
2310
current = "",
2311
ctype = null,
2312
nb_braces = 0,
2313
car
2314
Mar 19, 2018
2315
while(pos < string.length){
2316
if(ctype === null){
2317
car = string.charAt(pos)
Mar 19, 2018
2318
if(car == "{"){
Mar 21, 2018
2319
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2320
ctype = "string"
2321
current = "{"
2322
pos += 2
2323
}else{
Mar 19, 2018
2324
ctype = "expression"
2325
nb_braces = 1
2326
pos++
2327
}
Mar 19, 2018
2328
}else if(car == "}"){
Mar 21, 2018
2329
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2330
ctype = "string"
2331
current = "}"
2332
pos += 2
2333
}else{
2334
throw Error(" f-string: single '}' is not allowed")
2335
}
2336
}else{
Mar 19, 2018
2337
ctype = "string"
2338
current = car
2339
pos++
Mar 19, 2018
2341
}else if(ctype == "string"){
2342
// end of string is the first single { or end of string
Mar 19, 2018
2343
var i = pos
2344
while(i < string.length){
2345
car = string.charAt(i)
Mar 19, 2018
2346
if(car == "{"){
Mar 21, 2018
2347
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2348
current += "{"
2349
i += 2
2350
}else{
2351
elts.push(current)
Mar 19, 2018
2352
ctype = "expression"
2353
pos = i + 1
2354
break
2355
}
Mar 19, 2018
2356
}else if(car == "}"){
2357
if(string.charAt(i + 1) == car){
2358
current += car
2359
i += 2
2360
}else{
2361
throw Error(" f-string: single '}' is not allowed")
2362
}
2363
}else{
2364
current += car
2365
i++
2366
}
2367
}
Mar 19, 2018
2368
pos = i + 1
2369
}else if(ctype == "debug"){
2370
// after the equal sign, whitespace are ignored and the only
2371
// valid characters are } and :
2372
while(string.charAt(i) == " "){i++}
2373
if(string.charAt(i) == "}"){
2374
// end of debug expression
2375
elts.push(current)
2376
ctype = null
2377
current = ""
2378
pos = i + 1
2379
}
2380
}else{
2381
// End of expression is the } matching the opening {
2382
// There may be nested braces
2383
var i = pos,
2384
nb_braces = 1,
2385
nb_paren = 0,
2386
current = new fstring_expression()
Mar 19, 2018
2387
while(i < string.length){
2388
car = string.charAt(i)
Mar 19, 2018
2389
if(car == "{" && nb_paren == 0){
2390
nb_braces++
2391
current.expression += car
2392
i++
Mar 19, 2018
2393
}else if(car == "}" && nb_paren == 0){
2394
nb_braces -= 1
Mar 19, 2018
2395
if(nb_braces == 0){
2396
// end of expression
2397
elts.push(current)
2398
ctype = null
Mar 19, 2018
2399
current = ""
2400
pos = i + 1
2403
current.expression += car
2404
i++
Mar 19, 2018
2405
}else if(car == "\\"){
2406
// backslash is not allowed in expressions
2407
throw Error("f-string expression part cannot include a" +
2408
" backslash")
Mar 19, 2018
2409
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2410
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2411
if(current.expression.length == 0){
2412
throw Error("f-string: empty expression not allowed")
2413
}
Mar 19, 2018
2414
if("ars".indexOf(string.charAt(i + 1)) == -1){
2415
throw Error("f-string: invalid conversion character:" +
2416
" expected 's', 'r', or 'a'")
2417
}else{
Mar 19, 2018
2418
current.conversion = string.charAt(i + 1)
2419
i += 2
2420
}
Mar 19, 2018
2421
}else if(car == "("){
2422
nb_paren++
2423
current.expression += car
2424
i++
Mar 19, 2018
2425
}else if(car == ")"){
2426
nb_paren--
2427
current.expression += car
2428
i++
Mar 19, 2018
2429
}else if(car == '"'){
2430
// triple string ?
Mar 19, 2018
2431
if(string.substr(i, 3) == '"""'){
2432
var end = string.indexOf('"""', i + 3)
2433
if(end == -1){
2434
throw Error("f-string: unterminated string")
2435
}else{
2436
var trs = string.substring(i, end + 3)
2437
trs = trs.replace("\n", "\\n\\")
2438
current.expression += trs
Mar 19, 2018
2439
i = end + 3
2440
}
2441
}else{
Mar 19, 2018
2442
var end = string.indexOf('"', i + 1)
2443
if(end == -1){
2444
throw Error("f-string: unterminated string")
2445
}else{
2446
current.expression += string.substring(i, end + 1)
2447
i = end + 1
2448
}
2449
}
Mar 19, 2018
2450
}else if(nb_paren == 0 && car == ":"){
2451
current.fmt = true
2452
current.expression += car
2453
i++
2454
}else if(car == "="){
2455
// might be a "debug expression", eg f"{x=}"
2456
var ce = current.expression,
2457
last_char = ce.charAt(ce.length - 1),
2458
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
2461
string.charAt(i + 1) == "=" ||
2462
"=!<>:".search(last_char_re) > -1){
2463
current.expression += car + string.charAt(i + 1)
2464
i += 2
2465
}else{
2466
// add debug string
2467
tail = car
2468
while(string.charAt(i + 1).match(/\s/)){
2469
tail += string.charAt(i + 1)
2470
i++
2471
}
2472
elts.push(current.expression + tail)
2473
// remove trailing whitespace from expression
2474
while(ce.match(/\s$/)){
2475
ce = ce.substr(0, ce.length - 1)
2476
}
2477
current.expression = ce
2478
ctype = "debug"
2479
i++
2480
}
2481
}else{
2482
current.expression += car
2483
i++
2484
}
2485
}
Mar 21, 2018
2486
if(nb_braces > 0){
2487
throw Error("f-string: expected '}'")
2488
}
2489
}
2490
}
Mar 19, 2018
2491
if(current.length > 0){elts.push(current)}
2492
return elts
2493
}
2494
2495
// Class for strings with surrogate pairs. We can't rely on Javascript
2496
// strings in this case because they don't count characters like Python
2497
2498
var surrogate = str.$surrogate = $B.make_class("surrogate_string", function(s){
2499
// create an instance of str subclass for strings with surrogate pairs
2500
var items = []
2501
for(var i = 0, len = s.length; i < len; i++){
2502
var code = s.charCodeAt(i)
2503
if(code >= 0xD800 && code <= 0xDBFF){
2504
i++
2505
var low = s.charCodeAt(i)
2506
code = ((code - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000
2507
}
2508
items.push(String.fromCodePoint(code))
2509
}
2510
return {
2511
__class__: str.$surrogate,
2512
items: items
2513
}
2514
})
2515
2516
surrogate.__mro__ = [str, object]
2517
2518
surrogate.__contains__ = function(self, other){
2519
return str.__contains__(self.items.join(''), other)
2520
}
2521
2522
surrogate.__getitem__ = function(self, arg){
2523
if(isinstance(arg, _b_.int)){
2524
var pos = arg
2525
if(arg < 0){
2526
pos += self.items.length
2527
}
2528
if(pos >= 0 && pos < self.items.length){
2529
if(self.items[pos].length == 2){
2530
return surrogate.$factory(self.items[pos])
2531
}
2532
return self.items[pos]
2533
}
2534
throw _b_.IndexError.$factory("string index out of range")
2535
}
2536
if(isinstance(arg, slice)) {
2537
var s = _b_.slice.$conv_for_seq(arg, self.items.length),
2538
start = s.start,
2539
stop = s.stop,
2540
step = s.step
2541
var res = "",
2542
i = null
2543
if(step > 0){
2544
if(stop <= start){return ""}
2545
for(var i = start; i < stop; i += step){
2546
res += self.items[i]
2547
}
2548
}else{
2549
if(stop >= start){return ''}
2550
for(var i = start; i > stop; i += step){
2551
res += self.items[i]
2552
}
2553
}
2554
return res
2555
}
2556
if(isinstance(arg, _b_.bool)){
2557
return surrogate.__getitem__(self, _b_.int.$factory(arg))
2558
}
2559
throw _b_.TypeError.$factory("string indices must be integers")
2560
}
2561
2562
surrogate.__hash__ = function(self){
2563
return str.__hash__(self.items.join(''))
2564
}
2565
2566
surrogate.__iter__ = function(self){
2567
return str_iterator.$factory(self.items)
2568
}
2569
2570
surrogate.__len__ = function(self){
2571
return self.items.length
2572
}
2573
2574
surrogate.__repr__ = function(self){
2575
return str.__repr__(self.items.join(''))
2576
}
2577
2578
surrogate.__str__ = function(self){
2579
return str.__str__(self.items.join(''))
2580
}
2581
2582
$B.set_func_names(surrogate, "builtins")
2583
2584
Sep 5, 2014
2585
})(__BRYTHON__)