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