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