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