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