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