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