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