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