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