Skip to content
Permalink
Newer
Older
100644 2387 lines (2188 sloc) 76.2 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
Mar 19, 2018
521
var single_char_format = function(val, flags){
522
if(isinstance(val, str) && val.length == 1) return val
523
try{
524
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
Mar 19, 2018
525
}catch (err){
526
throw _b_.TypeError.$factory("%c requires int or char")
527
}
528
return format_padding(chr(val), flags)
529
}
530
Mar 19, 2018
531
var num_flag = function(c, flags){
532
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
533
flags.pad_char = "0"
534
return
535
}
Mar 19, 2018
536
if(!flags.decimal_point){
537
flags.padding = (flags.padding || "") + c
Mar 19, 2018
538
}else{
539
flags.precision = (flags.precision || "") + c
540
}
541
}
542
543
var decimal_point_flag = function(val, flags) {
Mar 23, 2018
544
if(flags.decimal_point){
545
// can only have one decimal point
546
throw new UnsupportedChar()
547
}
548
flags.decimal_point = true
549
}
550
Mar 19, 2018
551
var neg_flag = function(val, flags){
552
flags.pad_char = " " // overrides '0' flag
553
flags.left = true
554
}
555
Mar 19, 2018
556
var space_flag = function(val, flags){
557
flags.space = true
558
}
559
Mar 19, 2018
560
var sign_flag = function(val, flags){
561
flags.sign = true
562
}
563
Mar 19, 2018
564
var alternate_flag = function(val, flags){
565
flags.alternate = true
566
}
567
568
var char_mapping = {
Mar 19, 2018
569
"s": str_format,
570
"d": num_format,
571
"i": num_format,
572
"u": num_format,
573
"o": octal_format,
574
"r": repr_format,
575
"a": ascii_format,
576
"g": function(val, flags){
577
return floating_point_format(val, false, flags)
578
},
579
"G": function(val, flags){return floating_point_format(val, true, flags)},
580
"f": function(val, flags){
581
return floating_point_decimal_format(val, false, flags)
582
},
583
"F": function(val, flags){
584
return floating_point_decimal_format(val, true, flags)
585
},
586
"e": function(val, flags){
587
return floating_point_exponential_format(val, false, flags)
588
},
589
"E": function(val, flags){
590
return floating_point_exponential_format(val, true, flags)
591
},
592
"x": function(val, flags){return signed_hex_format(val, false, flags)},
593
"X": function(val, flags){return signed_hex_format(val, true, flags)},
594
"c": single_char_format,
595
"0": function(val, flags){return num_flag("0", flags)},
596
"1": function(val, flags){return num_flag("1", flags)},
597
"2": function(val, flags){return num_flag("2", flags)},
598
"3": function(val, flags){return num_flag("3", flags)},
599
"4": function(val, flags){return num_flag("4", flags)},
600
"5": function(val, flags){return num_flag("5", flags)},
601
"6": function(val, flags){return num_flag("6", flags)},
602
"7": function(val, flags){return num_flag("7", flags)},
603
"8": function(val, flags){return num_flag("8", flags)},
604
"9": function(val, flags){return num_flag("9", flags)},
605
"-": neg_flag,
606
" ": space_flag,
607
"+": sign_flag,
608
".": decimal_point_flag,
609
"#": alternate_flag
610
}
611
612
// exception thrown when an unsupported char is encountered in legacy format
Mar 19, 2018
613
var UnsupportedChar = function(){
614
this.name = "UnsupportedChar"
615
}
616
str
Feb 10, 2018
617
str.__mod__ = function(self, args) {
619
var length = self.length,
Mar 19, 2018
620
pos = 0 | 0,
621
argpos = null,
622
getitem
Mar 19, 2018
623
if(_b_.isinstance(args, _b_.tuple)){
624
argpos = 0 | 0
Mar 19, 2018
626
getitem = _b_.getattr(args, "__getitem__", _b_.None)
627
}
628
var ret = ''
629
var $get_kwarg_string = function(s) {
630
// returns [self, newpos]
631
++pos
632
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
633
if(! rslt){
634
throw _b_.ValueError.$factory("incomplete format key")
635
}
636
var key = rslt[1]
637
newpos += rslt[0].length
Mar 23, 2018
638
try{
639
var self = getitem(key)
Mar 19, 2018
640
}catch(err){
641
if(err.name === "KeyError"){
642
throw err
643
}
644
throw _b_.TypeError.$factory("format requires a mapping")
646
return get_string_value(s, self)
647
}
648
649
var $get_arg_string = function(s) {
650
// returns [self, newpos]
651
var self
653
// non-tuple args
Mar 19, 2018
654
if(argpos === null){
655
// args is the value
Mar 19, 2018
657
}else{
658
self = args[argpos++]
Mar 19, 2018
659
if(self === undefined){
660
throw _b_.TypeError.$factory(
661
"not enough arguments for format string")
Sep 5, 2014
662
}
663
}
664
return get_string_value(s, self)
666
var get_string_value = function(s, self) {
667
// todo: get flags, type
668
// todo: string value based on flags, type, value
Mar 19, 2018
669
var flags = {"pad_char": " "}
670
do{
671
var func = char_mapping[s[newpos]]
Mar 23, 2018
672
try{
Mar 19, 2018
673
if(func === undefined){
674
throw new UnsupportedChar()
Mar 19, 2018
675
}else{
676
var ret = func(self, flags)
Mar 19, 2018
677
if(ret !== undefined){
678
return ret
679
}
680
++newpos
681
}
Mar 19, 2018
682
}catch (err){
683
if(err.name == "UnsupportedChar"){
684
invalid_char = s[newpos]
Mar 19, 2018
685
if(invalid_char === undefined){
686
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
688
throw _b_.ValueError.$factory(
689
"unsupported format character '" + invalid_char +
690
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
691
") at index " + newpos)
692
}else if(err.name === "NotANumber"){
693
var try_char = s[newpos],
694
cls = self.__class__
695
if(!cls){
696
if(typeof(self) === "string"){
697
cls = "str"
698
}else{
699
cls = typeof(self)
Mar 19, 2018
701
}else{
Mar 19, 2018
704
throw _b_.TypeError.$factory("%" + try_char +
705
" format: a number is required, not " + cls)
706
}else{
707
throw err
708
}
Sep 5, 2014
709
}
Mar 19, 2018
710
}while (true)
Sep 5, 2014
711
}
712
var nbph = 0 // number of placeholders
Mar 19, 2018
713
do{
714
var newpos = self.indexOf("%", pos)
715
if(newpos < 0){
716
ret += self.substring(pos)
717
break
718
}
719
ret += self.substring(pos, newpos)
720
++newpos
Mar 19, 2018
721
if(newpos < length){
722
if(self[newpos] === "%"){
723
ret += "%"
724
}else{
Mar 19, 2018
726
if(self[newpos] === "("){
727
++newpos
728
ret += $get_kwarg_string(self)
Mar 23, 2018
729
}else{
730
ret += $get_arg_string(self)
731
}
732
}
Mar 19, 2018
733
}else{
734
// % at end of string
735
throw _b_.ValueError.$factory("incomplete format")
736
}
737
pos = newpos + 1
Mar 19, 2018
738
}while(pos < length)
739
740
if(argpos !== null){
741
if(args.length > argpos){
742
throw _b_.TypeError.$factory(
743
"not enough arguments for format string")
744
}else if(args.length < argpos){
745
throw _b_.TypeError.$factory(
746
"not all arguments converted during string formatting")
Mar 19, 2018
748
}else if(nbph == 0){
749
throw _b_.TypeError.$factory(
750
"not all arguments converted during string formatting")
Sep 5, 2014
754
str
Feb 10, 2018
755
str.__mro__ = [object]
Sep 5, 2014
756
str
Feb 10, 2018
757
str.__mul__ = function(){
Mar 19, 2018
758
var $ = $B.args("__mul__", 2, {self: null, other: null},
759
["self", "other"], arguments, {}, null, null)
760
if(! isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
761
"Can't multiply sequence by non-int of type '" +
Mar 19, 2018
763
var $res = ""
764
for(var i = 0; i< $.other; i++){$res += $.self.valueOf()}
Sep 5, 2014
765
return $res
766
}
767
Mar 19, 2018
768
str.__ne__ = function(self,other){return other !== self.valueOf()}
Sep 5, 2014
769
str
Feb 10, 2018
770
str.__repr__ = function(self){
772
// escape the escape char
773
res = self.replace(/\\/g, "\\\\")
774
// special cases
775
res = res.replace(new RegExp("\u0007", "g"), "\\x07").
776
replace(new RegExp("\b", "g"), "\\x08").
777
replace(new RegExp("\f", "g"), "\\x0c").
778
replace(new RegExp("\n", "g"), "\\n").
779
replace(new RegExp("\r", "g"), "\\r").
780
replace(new RegExp("\t", "g"), "\\t")
Mar 27, 2019
781
782
res = res.replace(combining_re, "\u200B$1")
Mar 19, 2018
783
if(res.search('"') == -1 && res.search("'") == -1){
784
return "'" + res + "'"
785
}else if(self.search('"') == -1){
786
return '"' + res + '"'
787
}
788
var qesc = new RegExp("'", "g") // to escape single quote
789
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
790
return res
791
}
792
Mar 19, 2018
793
str.__setitem__ = function(self, attr, value){
794
throw _b_.TypeError.$factory(
795
"'str' object does not support item assignment")
Sep 5, 2014
796
}
Mar 27, 2019
797
var combining = []
798
for(var cp = 0x300; cp <= 0x36F; cp++){
799
combining.push(String.fromCharCode(cp))
800
}
801
var combining_re = new RegExp("(" + combining.join("|") + ")")
str
Feb 10, 2018
803
str.__str__ = function(self){
Mar 27, 2019
804
return self.replace(combining_re, "\u200B$1")
Sep 5, 2014
805
}
Mar 19, 2018
806
str.toString = function(){return "string!"}
Sep 5, 2014
807
808
// generate comparison methods
809
var $comp_func = function(self,other){
810
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
811
return self > other
812
}
Mar 19, 2018
813
$comp_func += "" // source code
814
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
815
for(var $op in $comps){
Mar 19, 2018
816
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
817
}
818
819
// add "reflected" methods
str
Feb 10, 2018
820
$B.make_rmethods(str)
Sep 5, 2014
821
822
// unsupported operations
Mar 19, 2018
823
var $notimplemented = function(self, other){
824
throw NotImplementedError.$factory(
825
"OPERATOR not implemented for class str")
Sep 5, 2014
826
}
827
828
str.capitalize = function(self){
829
var $ = $B.args("capitalize", 1, {self}, ["self"],
830
arguments, {}, null, null)
831
if(self.length == 0){return ""}
832
return self.charAt(0).toUpperCase() + self.substr(1)
833
}
834
835
str.casefold = function(self){
836
var $ = $B.args("casefold", 1, {self}, ["self"],
837
arguments, {}, null, null),
838
res = "",
839
char,
840
cf
841
for(var i = 0, len = self.length; i < len; i++){
842
char = self.charCodeAt(i)
843
cf = $B.unicode_casefold[char]
844
if(cf){
845
cf.forEach(function(cp){
846
res += String.fromCharCode(cp)
847
})
848
}else{
849
res += self.charAt(i).toLowerCase()
850
}
851
}
852
return res
853
}
Sep 5, 2014
854
Mar 19, 2018
855
str.center = function(){
856
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
857
["self", "width", "fillchar"],
858
arguments, {fillchar:" "}, null, null),
859
self = $.self
Mar 19, 2018
861
if($.width <= self.length) {return self}
Mar 19, 2018
863
var pad = parseInt(($.width - self.length) / 2),
864
res = $.fillchar.repeat(pad)
Sep 5, 2014
865
res += self + res
Mar 19, 2018
866
if(res.length < $.width){res += $.fillchar}
Sep 5, 2014
867
return res
868
}
869
str
Feb 10, 2018
870
str.count = function(){
Mar 19, 2018
871
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
872
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
Mar 19, 2018
874
if(!(typeof $.sub == "string")){throw _b_.TypeError.$factory(
875
"Can't convert '" + $B.class_name($.sub) +
Mar 19, 2018
876
"' object to str implicitly")}
Mar 19, 2018
878
if($.start !== null){
Mar 19, 2018
880
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
881
else{_slice = _b_.slice.$factory($.start, $.self.length)}
str
Feb 10, 2018
882
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
Mar 19, 2018
884
if($.self.length + $.sub.length == 0){return 1}
Mar 19, 2018
886
if($.sub.length == 0){
887
if($.start == $.self.length){return 1}
888
else if(substr.length == 0){return 0}
889
return substr.length + 1
Mar 19, 2018
891
var n = 0,
892
pos = 0
893
while(pos < substr.length){
894
pos = substr.indexOf($.sub, pos)
895
if(pos >= 0){n++; pos += $.sub.length}
896
else{break}
Sep 5, 2014
897
}
898
return n
899
}
900
901
str.encode = function(){
902
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
903
["self", "encoding", "errors"], arguments,
904
{encoding: "utf-8", errors: "strict"}, null, null)
905
if($.encoding == "rot13" || $.encoding == "rot_13"){
906
// Special case : returns a string
Mar 19, 2018
907
var res = ""
908
for(var i = 0, len = $.self.length; i < len ; i++){
909
var char = $.self.charAt(i)
Mar 19, 2018
910
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
911
res += String.fromCharCode(String.charCodeAt(char) + 13)
912
}else if(("m" < char && char <= "z") ||
913
("M" < char && char <= "Z")){
914
res += String.fromCharCode(String.charCodeAt(char) - 13)
915
}else{res += char}
916
}
917
return res
918
}
919
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
Sep 5, 2014
920
}
921
str
Feb 10, 2018
922
str.endswith = function(){
923
// Return True if the string ends with the specified suffix, otherwise
924
// return False. suffix can also be a tuple of suffixes to look for.
925
// With optional start, test beginning at that position. With optional
Sep 5, 2014
926
// end, stop comparing at that position.
Mar 19, 2018
927
var $ = $B.args("endswith", 4,
928
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
929
["self", "suffix", "start", "end"],
930
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
931
932
normalize_start_end($)
933
934
var suffixes = $.suffix
Mar 19, 2018
935
if(! isinstance(suffixes,_b_.tuple)){suffixes = [suffixes]}
Mar 19, 2018
937
var s = $.self.substring($.start, $.end)
938
for(var i = 0, len = suffixes.length; i < len; i++){
939
var suffix = suffixes[i]
Mar 19, 2018
940
if(! _b_.isinstance(suffix, str)){throw _b_.TypeError.$factory(
Sep 20, 2015
941
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
942
if(suffix.length <= s.length &&
943
s.substr(s.length - suffix.length) == suffix){return true}
Sep 5, 2014
944
}
945
return false
946
}
947
str
Feb 10, 2018
948
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
949
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
950
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
951
var s = $B.$GetInt($.tabsize),
952
col = 0,
953
pos = 0,
954
res = ""
955
if(s == 1){return self.replace(/\t/g," ")}
956
while(pos < self.length){
957
var car = self.charAt(pos)
958
switch(car){
Mar 19, 2018
959
case "\t":
Mar 21, 2018
960
while(col % s > 0){res += " "; col++}
Mar 19, 2018
962
case "\r":
963
case "\n":
964
res += car
965
col = 0
966
break
967
default:
968
res += car
969
col++
970
break
971
}
972
pos++
973
}
Sep 5, 2014
976
}
977
str
Feb 10, 2018
978
str.find = function(){
979
// Return the lowest index in the string where substring sub is found,
980
// such that sub is contained in the slice s[start:end]. Optional
981
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
982
// Return -1 if sub is not found.
Mar 19, 2018
983
var $ = $B.args("str.find", 4,
984
{self: null, sub: null, start: null, end: null},
985
["self", "sub", "start", "end"],
986
arguments, {start: 0, end: null}, null, null)
987
check_str($.sub)
Mar 19, 2018
990
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
991
throw _b_.TypeError.$factory("slice indices must be " +
992
"integers or None or have an __index__ method")}
993
// Can't use string.substring(start, end) because if end < start,
994
// Javascript transforms it into substring(end, start)...
995
var s = ""
996
for(var i = $.start; i < $.end; i++){
997
s += $.self.charAt(i)
998
}
Mar 19, 2018
1000
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1001
if(s.length + $.sub.length == 0){return -1}
Mar 19, 2018
1003
var last_search = s.length - $.sub.length
1004
for(var i = 0; i <= last_search; i++){
1005
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
Sep 5, 2014
1006
}
Sep 5, 2014
1008
}
1009
1010
// Next function used by method .format()
1011
1012
$B.parse_format = function(fmt_string){
Sep 5, 2014
1013
1014
// Parse a "format string", as described in the Python documentation
1015
// Return a format object. For the format string
1016
// a.x[z]!r:...
1017
// the object has attributes :
1018
// - name : "a"
1019
// - name_ext : [".x", "[z]"]
1020
// - conv : r
1021
// - spec : rest of string after :
Sep 5, 2014
1022
Mar 19, 2018
1023
var elts = fmt_string.split(":"),
1024
name,
1025
conv,
1026
spec,
Mar 19, 2018
1027
name_ext = []
Mar 19, 2018
1028
if(elts.length == 1){
1029
// No : in the string : it only contains a name
1030
name = fmt_string
1031
}else{
1032
// name is before the first ":"
1033
// spec (the format specification) is after
1034
name = elts[0]
Mar 19, 2018
1035
spec = elts.splice(1).join(":")
Mar 19, 2018
1038
var elts = name.split("!")
1039
if(elts.length > 1){
1040
name = elts[0]
1041
conv = elts[1] // conversion flag
Sep 5, 2014
1043
Mar 19, 2018
1044
if(name !== undefined){
1045
// "name' may be a subscription or attribute
1046
// Put these "extensions" in the list "name_ext"
1047
function name_repl(match){
1048
name_ext.push(match)
Mar 19, 2018
1049
return ""
1050
}
1051
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1052
name = name.replace(name_ext_re, name_repl)
1053
}
Sep 5, 2014
1054
1055
return {name: name, name_ext: name_ext,
1056
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1058
1059
$B.split_format = function(self){
1060
// Parse self to detect formatting instructions
1061
// Create a list "parts" made of sections of the string :
1062
// - elements of even rank are literal text
1063
// - elements of odd rank are "format objects", built from the
1064
// format strings in self (of the form {...})
Mar 19, 2018
1065
var pos = 0,
1066
_len = self.length,
Mar 19, 2018
1068
text = "",
1069
parts = [],
1070
rank = 0
1071
while(pos < _len){
1072
car = self.charAt(pos)
Mar 21, 2018
1073
if(car == "{" && self.charAt(pos + 1) == "{"){
1074
// replace {{ by literal {
Mar 19, 2018
1075
text += "{"
1076
pos += 2
1077
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1078
// replace }} by literal }
Mar 19, 2018
1079
text += "}"
1080
pos += 2
1081
}else if(car == "{"){
1082
// Start of a format string
1084
// Store current literal text
1085
parts.push(text)
1086
1087
// Search the end of the format string, ie the } closing the
1088
// opening {. Since the string can contain other pairs {} for
1089
// nested formatting, an integer nb is incremented for each { and
1090
// decremented for each } ; the end of the format string is
Mar 19, 2018
1091
// reached when nb == 0
1092
var end = pos + 1,
1093
nb = 1
1094
while(end < _len){
1095
if(self.charAt(end) == "{"){nb++; end++}
1096
else if(self.charAt(end) == "}"){
1097
nb--; end++
1098
if(nb == 0){
1099
// End of format string
Mar 19, 2018
1100
var fmt_string = self.substring(pos + 1, end - 1)
1101
1102
// Create a format object, by function parse_format
1103
var fmt_obj = $B.parse_format(fmt_string)
1104
fmt_obj.raw_name = fmt_obj.name
1105
fmt_obj.raw_spec = fmt_obj.spec
1106
1107
// If no name is explicitely provided, use the rank
1108
if(!fmt_obj.name){
Mar 19, 2018
1109
fmt_obj.name = rank + ""
Sep 5, 2014
1112
Mar 19, 2018
1113
if(fmt_obj.spec !== undefined){
1114
// "spec" may contain "nested replacement fields"
1115
// Replace empty fields by the rank in positional
1116
// arguments
1117
function replace_nested(name, key){
1118
if(key == ""){
1119
// Use implicit rank
1120
return "{" + rank++ + "}"
1124
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1125
replace_nested)
1126
}
1128
// Store format object in list "parts"
1129
parts.push(fmt_obj)
Mar 19, 2018
1130
text = ""
1131
break
1132
}
1133
}else{end++}
Sep 5, 2014
1134
}
Mar 19, 2018
1135
if(nb > 0){throw ValueError.$factory("wrong format " + self)}
Mar 19, 2018
1137
}else{text += car; pos++}
Sep 5, 2014
1138
}
1139
if(text){parts.push(text)}
1140
return parts
1141
}
1142
1143
str.format = function(self) {
1144
var $ = $B.args("format", 1, {self: null}, ["self"],
1145
arguments, {}, "$args", "$kw")
1146
1147
var parts = $B.split_format($.self)
1148
1149
// Apply formatting to the values passed to format()
Mar 19, 2018
1150
var res = "",
1151
fmt
Mar 19, 2018
1153
for(var i = 0; i < parts.length; i++){
1154
// Literal text is added unchanged
Mar 19, 2018
1155
if(typeof parts[i] == "string"){res += parts[i]; continue}
1157
// Format objects
1158
fmt = parts[i]
1159
1160
if(fmt.spec !== undefined){
1161
// "spec" may contain "nested replacement fields"
1162
// In this case, evaluate them using the positional
1163
// or keyword arguments passed to format()
1164
function replace_nested(name, key){
1165
if(/\d+/.exec(key)){
1166
// If key is numeric, search in positional
1167
// arguments
1168
return _b_.tuple.__getitem__($.$args,
1169
parseInt(key))
1170
}else{
1171
// Else try in keyword arguments
1172
return _b_.dict.__getitem__($.$kw, key)
1173
}
1174
}
1175
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1176
replace_nested)
1177
}
Mar 21, 2018
1178
if(fmt.name.charAt(0).search(/\d/) > -1){
1179
// Numerical reference : use positional arguments
1180
var pos = parseInt(fmt.name),
Feb 11, 2018
1181
value = _b_.tuple.__getitem__($.$args, pos)
1182
}else{
1183
// Use keyword arguments
Feb 11, 2018
1184
var value = _b_.dict.__getitem__($.$kw, fmt.name)
1185
}
1186
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1187
for(var j = 0; j < fmt.name_ext.length; j++){
1188
var ext = fmt.name_ext[j]
Mar 19, 2018
1189
if(ext.charAt(0) == "."){
1190
// Attribute
1191
value = _b_.getattr(value, ext.substr(1))
1192
}else{
1193
// Subscription
Mar 19, 2018
1194
var key = ext.substr(1, ext.length - 2)
1195
// An index made of digits is transformed into an integer
Mar 19, 2018
1196
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1197
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1200
1201
// If the conversion flag is set, first call a function to convert
1202
// the value
Mar 19, 2018
1203
if(fmt.conv == "a"){value = _b_.ascii(value)}
1204
else if(fmt.conv == "r"){value = _b_.repr(value)}
1205
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1207
// Call attribute __format__ to perform the actual formatting
1208
if(value.$is_class || value.$factory){
1209
// For classes, don't use the class __format__ method
1210
res += value.__class__.__format__(value, fmt.spec)
Mar 19, 2018
1212
res += _b_.getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1214
}
Sep 5, 2014
1216
}
1217
str
Feb 10, 2018
1218
str.format_map = function(self) {
Mar 19, 2018
1219
throw NotImplementedError.$factory(
1220
"function format_map not implemented yet")
Sep 5, 2014
1221
}
1222
str
Feb 10, 2018
1223
str.index = function(self){
Sep 5, 2014
1224
// Like find(), but raise ValueError when the substring is not found.
1225
var res = str.find.apply(null, arguments)
Mar 19, 2018
1226
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1227
return res
1228
}
1229
1230
str.isascii = function(self){
1231
/* Return true if the string is empty or all characters in the string are
1232
ASCII, false otherwise. ASCII characters have code points in the range
1233
U+0000-U+007F. */
1234
for(var i = 0, len = self.length; i < len; i++){
1235
if(self.charCodeAt(i) > 127){return false}
1236
}
1237
return true
1238
}
1239
1240
str.isalnum = function(self){
1241
/* Return true if all characters in the string are alphanumeric and there
1242
is at least one character, false otherwise. A character c is alphanumeric
1243
if one of the following returns True: c.isalpha(), c.isdecimal(),
1244
c.isdigit(), or c.isnumeric(). */
1245
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1246
arguments, {}, null, null),
1247
char
1248
for(var i = 0, len = self.length; i < len; i++){
1249
char = self.charCodeAt(i)
1250
if(unicode_tables.Ll[char] ||
1251
unicode_tables.Lu[char] ||
1252
unicode_tables.Lm[char] ||
1253
unicode_tables.Lt[char] ||
1254
unicode_tables.Lo[char] ||
1255
unicode_tables.Nd[char] ||
1256
unicode_tables.digits[char] ||
1257
unicode_tables.numeric[char]){
1258
continue
1259
}
1260
return false
1261
}
1262
return true
1263
}
1264
1265
str.isalpha = function(self){
1266
/* Return true if all characters in the string are alphabetic and there is
1267
at least one character, false otherwise. Alphabetic characters are those
1268
characters defined in the Unicode character database as "Letter", i.e.,
1269
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1270
or "Lo". */
1271
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1272
arguments, {}, null, null),
1273
char
1274
for(var i = 0, len = self.length; i < len; i++){
1275
char = self.charCodeAt(i)
1276
if(unicode_tables.Ll[char] ||
1277
unicode_tables.Lu[char] ||
1278
unicode_tables.Lm[char] ||
1279
unicode_tables.Lt[char] ||
1280
unicode_tables.Lo[char]){
1281
continue
1282
}
1283
return false
1284
}
1285
return true
1286
}
1287
1288
str.isdecimal = function(self){
1289
/* Return true if all characters in the string are decimal characters and
1290
there is at least one character, false otherwise. Decimal characters are
1291
those that can be used to form numbers in base 10, e.g. U+0660,
1292
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1293
the Unicode General Category "Nd". */
1294
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1295
arguments, {}, null, null),
1296
char
1297
for(var i = 0, len = self.length; i < len; i++){
1298
char = self.charCodeAt(i)
1299
if(! unicode_tables.Nd[char]){
1300
return false
1301
}
1302
}
1303
return self.length > 0
1304
}
1305
1306
str.isdigit = function(self){
1307
/* Return true if all characters in the string are digits and there is at
1308
least one character, false otherwise. */
1309
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1310
arguments, {}, null, null),
1311
char
1312
for(var i = 0, len = self.length; i < len; i++){
1313
char = self.charCodeAt(i)
1314
if(! unicode_tables.digits[char]){
1315
return false
1316
}
1317
}
1318
return self.length > 0
1319
}
1320
1321
str.isidentifier = function(self){
1322
/* Return true if the string is a valid identifier according to the
1323
language definition. */
1324
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1325
arguments, {}, null, null),
1326
char
1327
if(self.length == 0){return false}
1328
else if(unicode_tables.XID_Start[self.charCodeAt(0)] === undefined){
1329
return false
1330
}else{
1331
for(var i = 1, len = self.length; i < len; i++){
1332
if(unicode_tables.XID_Continue[self.charCodeAt(i)] === undefined){
1333
return false
1334
}
1335
}
1336
}
1337
return true
1338
}
1339
1340
str.islower = function(self){
1341
/* Return true if all cased characters 4 in the string are lowercase and
1342
there is at least one cased character, false otherwise. */
1343
var $ = $B.args("islower", 1, {self: null}, ["self"],
1344
arguments, {}, null, null),
1345
has_cased = false,
1346
char
1347
1348
for(var i = 0, len = self.length; i < len; i++){
1349
char = self.charCodeAt(i)
1350
if(unicode_tables.Ll[char]){has_cased = true; continue}
1351
else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1352
return false
1353
}
1354
}
1355
return has_cased
1356
}
1357
1358
str.isnumeric = function(self){
1359
/* Return true if all characters in the string are numeric characters, and
1360
there is at least one character, false otherwise. Numeric characters
1361
include digit characters, and all characters that have the Unicode numeric
1362
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1363
characters are those with the property value Numeric_Type=Digit,
1364
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1365
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1366
arguments, {}, null, null)
1367
for(var i = 0, len = self.length; i < len; i++){
1368
if(! unicode_tables.numeric[self.charCodeAt(i)]){
1369
return false
1370
}
1371
}
1372
return self.length > 0
1373
}
1374
1375
var printable,
1376
printable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1377
1378
str.isprintable = function(self){
1379
/* Return true if all characters in the string are printable or the string
1380
is empty, false otherwise. Nonprintable characters are those characters
1381
defined in the Unicode character database as "Other" or "Separator",
1382
excepting the ASCII space (0x20) which is considered printable. */
1383
1384
// Set printable if not set yet
1385
if(printable === undefined){
1386
for(var i = 0; i < printable_gc.length; i++){
1387
var table = unicode_tables[printable_gc[i]]
1388
for(var cp in table){
1389
printable[cp] = true
1390
}
1391
}
1392
printable[32] = true
1393
}
1394
1395
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1396
arguments, {}, null, null),
1397
char,
1398
flag
1399
for(var i = 0, len = self.length; i < len; i++){
1400
char = self.charCodeAt(i)
1401
if(! printable[char]){
1402
return false
1403
}
1404
}
1405
return true
1406
}
1407
1408
str.isspace = function(self){
1409
/* Return true if there are only whitespace characters in the string and
1410
there is at least one character, false otherwise.
1411
1412
A character is whitespace if in the Unicode character database, either its
1413
general category is Zs ("Separator, space"), or its bidirectional class is
1414
one of WS, B, or S.*/
1415
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1416
arguments, {}, null, null),
1417
char
1418
for(var i = 0, len = self.length; i < len; i++){
1419
char = self.charCodeAt(i)
1420
if(! unicode_tables.Zs[char] &&
1421
$B.unicode_bidi_whitespace.indexOf(char) == -1){
1422
return false
1423
}
1424
}
1425
return self.length > 0
1426
}
1427
1428
str.istitle = function(self){
1429
/* Return true if the string is a titlecased string and there is at least
1430
one character, for example uppercase characters may only follow uncased
1431
characters and lowercase characters only cased ones. Return false
1432
otherwise. */
1433
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1434
arguments, {}, null, null)
1435
return self.length > 0 && str.title(self) == self
1436
}
1437
1438
str.isupper = function(self){
1439
/* Return true if all cased characters 4 in the string are lowercase and
1440
there is at least one cased character, false otherwise. */
1441
var $ = $B.args("islower", 1, {self: null}, ["self"],
1442
arguments, {}, null, null),
1443
has_cased = false,
1444
char
1445
1446
for(var i = 0, len = self.length; i < len; i++){
1447
char = self.charCodeAt(i)
1448
if(unicode_tables.Lu[char]){has_cased = true; continue}
1449
else if(unicode_tables.Ll[char] || unicode_tables.Lt[char]){
1450
return false
1451
}
1452
}
1453
return has_cased
1454
}
1455
1456
str
Feb 10, 2018
1457
str.join = function(){
Mar 19, 2018
1458
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1459
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1461
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1462
res = [],
Sep 5, 2014
1464
while(1){
1465
try{
1466
var obj2 = _b_.next(iterable)
Mar 19, 2018
1467
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1468
"sequence item " + count + ": expected str instance, " +
1469
$B.class_name(obj2) + " found")}
1470
res.push(obj2)
Sep 5, 2014
1471
}catch(err){
1472
if(_b_.isinstance(err, _b_.StopIteration)){
1473
break
1474
}
Sep 5, 2014
1475
else{throw err}
1476
}
1477
}
1478
return res.join($.self)
Sep 5, 2014
1479
}
1480
str
Feb 10, 2018
1481
str.ljust = function(self) {
Mar 19, 2018
1482
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1483
["self", "width", "fillchar"],
1484
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1486
if($.width <= self.length){return self}
1487
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1488
}
1489
1490
str.lower = function(self){
1491
var $ = $B.args("lower", 1, {self: null}, ["self"],
1492
arguments, {}, null, null)
1493
return self.toLowerCase()
1494
}
1495
str
Feb 10, 2018
1496
str.lstrip = function(self,x){
Mar 19, 2018
1497
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1498
arguments, {chars:_b_.None}, null, null)
1499
if($.chars === _b_.None){return $.self.trimLeft()}
1500
for(var i = 0; i < $.self.length; i++){
1501
if($.chars.indexOf($.self.charAt(i)) === -1){
1502
return $.self.substring(i)
Mar 19, 2018
1505
return ""
Sep 5, 2014
1506
}
1507
1508
// note, maketrans should be a static function.
str
Feb 10, 2018
1509
str.maketrans = function() {
Mar 19, 2018
1510
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1511
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1513
var _t = _b_.dict.$factory()
Mar 19, 2018
1515
if($.y === null && $.z === null){
1516
// If there is only one argument, it must be a dictionary mapping
1517
// Unicode ordinals (integers) or characters (strings of length 1) to
1518
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1519
// keys will then be converted to ordinals.
Mar 19, 2018
1520
if(! _b_.isinstance($.x, _b_.dict)){
1521
throw _b_.TypeError.$factory(
1522
"maketrans only argument must be a dict")
Feb 11, 2018
1524
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1525
for(var i = 0, len = items.length; i < len; i++){
1526
var k = items[i][0],
1527
v = items[i][1]
1528
if(! _b_.isinstance(k, _b_.int)){
1529
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1530
k = _b_.ord(k)
1531
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1532
" is not int or 1-char string")}
1533
}
Mar 19, 2018
1534
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1535
throw _b_.TypeError.$factory("dictionary value " + v +
1536
" is not None, integer or string")
1537
}
1538
_b_.dict.$setitem(_t, k, v)
1539
}
1540
return _t
1541
}else{
1542
// If there are two arguments, they must be strings of equal length,
1543
// and in the resulting dictionary, each character in x will be mapped
1544
// to the character at the same position in y
Mar 19, 2018
1545
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1546
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1547
}else if($.x.length !== $.y.length){
1548
throw _b_.TypeError.$factory(
1549
"maketrans arguments must be strings or same length")
1550
}else{
1551
var toNone = {}
Mar 19, 2018
1552
if($.z !== null){
1553
// If there is a third argument, it must be a string, whose
1554
// characters will be mapped to None in the result
Mar 19, 2018
1555
if(! _b_.isinstance($.z, _b_.str)){
1556
throw _b_.TypeError.$factory(
1557
"maketrans third argument must be a string")
Mar 19, 2018
1559
for(var i = 0, len = $.z.length; i < len; i++){
1560
toNone[_b_.ord($.z.charAt(i))] = true
1561
}
Mar 19, 2018
1563
for(var i = 0, len = $.x.length; i < len; i++){
1564
var key = _b_.ord($.x.charAt(i)),
1566
_b_.dict.$setitem(_t, key, value)
1567
}
1568
for(var k in toNone){
1569
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1570
}
1571
return _t
1572
}
1573
}
Sep 5, 2014
1574
}
1575
1576
str.maketrans.$type = "staticmethod"
1577
str
Feb 10, 2018
1578
str.partition = function() {
Mar 19, 2018
1579
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1580
arguments, {}, null, null)
Mar 19, 2018
1581
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1582
check_str($.sep)
1583
var i = $.self.indexOf($.sep)
Mar 23, 2018
1584
if(i == -1){return _b_.tuple.$factory([$.self, "", ""])}
Mar 19, 2018
1585
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1586
$.self.substring(i + $.sep.length)])
1587
}
1588
1589
function $re_escape(str){
1590
var specials = "[.*+?|()$^"
1591
for(var i = 0, len = specials.length; i < len; i++){
1592
var re = new RegExp("\\"+specials.charAt(i), "g")
1593
str = str.replace(re, "\\"+specials.charAt(i))
1594
}
1595
return str
Sep 5, 2014
1596
}
1597
str
Feb 10, 2018
1598
str.replace = function(self, old, _new, count) {
1599
// Replaces occurrences of 'old' by '_new'. Count references
1600
// the number of times to replace. In CPython, negative or undefined
1601
// values of count means replace all.
Mar 19, 2018
1602
var $ = $B.args("replace", 4,
1603
{self: null, old: null, $$new: null, count: null},
1604
["self", "old", "$$new", "count"],
1605
arguments, {count: -1}, null, null),
1606
count = $.count,
1607
self = $.self,
1608
old = $.old,
1609
_new = $.$$new
1610
// Validate type of old
1611
check_str(old)
1612
check_str(_new)
1613
// Validate instance type of 'count'
Mar 23, 2018
1614
if(! isinstance(count,[_b_.int, _b_.float])){
1615
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1616
"' object cannot be interpreted as an integer")
1617
}else if(isinstance(count, _b_.float)){
1618
throw _b_.TypeError.$factory("integer argument expected, got float")
1619
}
1620
if(count == 0){return self}
1621
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1622
if(old == ""){
1623
if(_new == ""){return self}
1624
if(self == ""){return _new}
1625
var elts = self.split("")
1626
if(count > -1 && elts.length >= count){
1627
var rest = elts.slice(count).join("")
1628
return _new + elts.slice(0, count).join(_new) + rest
1629
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1631
var elts = str.split(self, old, count)
Sep 5, 2014
1632
}
Mar 19, 2018
1634
var res = self,
1635
pos = -1
1636
if(old.length == 0){
Mar 19, 2018
1638
for(var i = 0; i < elts.length; i++){
1639
res += elts[i] + _new
Mar 19, 2018
1641
return res + rest
Mar 19, 2018
1644
if(count < 0){count = res.length}
1645
while(count > 0){
1646
pos = res.indexOf(old, pos)
1647
if(pos < 0){break}
1648
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1649
pos = pos + _new.length
1650
count--
Mar 19, 2018
1652
return res
Sep 5, 2014
1653
}
1654
1655
str.rfind = function(self, substr){
1656
// Return the highest index in the string where substring sub is found,
1657
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1658
// start and end are interpreted as in slice notation. Return -1 on failure.
1659
if(arguments.length == 2 && typeof substr == "string"){
1660
return self.lastIndexOf(substr)
1661
}
Mar 19, 2018
1662
var $ = $B.args("rfind", 4,
Mar 19, 2018
1663
{self: null, sub: null, start: null, end: null},
1664
["self", "sub", "start", "end"],
1665
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1666
1669
check_str($.sub)
Mar 19, 2018
1671
if($.sub.length == 0){
1672
if($.start > $.self.length){return -1}
1673
else{return $.self.length}
1674
}
1675
var sublen = $.sub.length
Mar 19, 2018
1677
for(var i = $.end - sublen; i >= $.start; i--){
1678
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1681
}
1682
str
Feb 10, 2018
1683
str.rindex = function(){
Sep 5, 2014
1684
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1685
var res = str.rfind.apply(null, arguments)
1686
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1687
return res
1688
}
1689
str
Feb 10, 2018
1690
str.rjust = function(self) {
Mar 19, 2018
1691
var $ = $B.args("rjust",3,
1692
{self: null, width: null, fillchar: null},
1693
["self", "width", "fillchar"],
1694
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1695
Mar 19, 2018
1696
if($.width <= self.length){return self}
Sep 5, 2014
1697
1698
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1699
}
1700
str
Feb 10, 2018
1701
str.rpartition = function(self,sep) {
Mar 19, 2018
1702
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1703
arguments, {}, null, null)
1704
check_str($.sep)
1705
var self = reverse($.self),
1706
sep = reverse($.sep)
Mar 19, 2018
1707
var items = str.partition(self, sep).reverse()
1708
for(var i = 0; i < items.length; i++){
1709
items[i] = items[i].split("").reverse().join("")
1710
}
1711
return items
Sep 5, 2014
1712
}
1713
str
Feb 10, 2018
1714
str.rsplit = function(self) {
Mar 19, 2018
1715
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1716
["self", "sep", "maxsplit"], arguments,
1717
{sep: _b_.None, maxsplit: -1}, null, null),
1718
sep = $.sep
1719
1720
// Use split on the reverse of the string and of separator
1721
var rev_str = reverse($.self),
1722
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1723
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1725
// Reverse the list, then each string inside the list
1726
rev_res.reverse()
Mar 19, 2018
1727
for(var i = 0; i < rev_res.length; i++){
1728
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1731
}
1732
Mar 19, 2018
1733
str.rstrip = function(self, x){
1734
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1735
arguments, {chars: _b_.None}, null, null)
1736
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1737
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1738
if($.chars.indexOf($.self.charAt(j)) == -1){
1739
return $.self.substring(0, j + 1)
Mar 19, 2018
1742
return ""
Sep 5, 2014
1743
}
1744
str
Feb 10, 2018
1745
str.split = function(){
Mar 19, 2018
1746
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1747
["self", "sep", "maxsplit"], arguments,
1748
{sep: _b_.None, maxsplit: -1}, null, null),
1749
sep = $.sep,
1750
maxsplit = $.maxsplit,
1751
self = $.self,
1752
pos = 0
1753
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1754
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1755
if(sep === _b_.None){
Sep 5, 2014
1756
var res = []
Mar 19, 2018
1757
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1758
if(pos === self.length - 1){return [self]}
1759
var name = ""
Sep 5, 2014
1760
while(1){
Mar 19, 2018
1761
if(self.charAt(pos).search(/\s/) == -1){
1762
if(name == ""){name = self.charAt(pos)}
1763
else{name += self.charAt(pos)}
Sep 5, 2014
1764
}else{
Mar 19, 2018
1765
if(name !== ""){
Sep 5, 2014
1766
res.push(name)
Mar 19, 2018
1767
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1768
res.pop()
Mar 19, 2018
1769
res.push(name + self.substr(pos))
Sep 5, 2014
1770
return res
1771
}
Mar 19, 2018
1772
name = ""
Sep 5, 2014
1773
}
1774
}
1775
pos++
Mar 19, 2018
1776
if(pos > self.length - 1){
Sep 5, 2014
1777
if(name){res.push(name)}
1778
break
1779
}
1780
}
1781
return res
1782
}else{
Mar 19, 2018
1783
var res = [],
1784
s = "",
1785
seplen = sep.length
1786
if(maxsplit == 0){return [self]}
1787
while(pos < self.length){
1788
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1791
if(maxsplit > -1 && res.length >= maxsplit){
1792
res.push(self.substr(pos))
1793
return res
1794
}
Mar 19, 2018
1795
s = ""
1796
}else{
1797
s += self.charAt(pos)
1798
pos++
Sep 5, 2014
1799
}
1800
}
Sep 5, 2014
1803
}
1804
}
1805
str
Feb 10, 2018
1806
str.splitlines = function(self){
Mar 19, 2018
1807
var $ = $B.args("splitlines", 2, {self: null, keepends: null},
Mar 19, 2018
1808
["self", "keepends"], arguments, {keepends: false}, null, null)
1809
if(! _b_.isinstance($.keepends, [_b_.bool, _b_.int])){
1810
throw _b_.TypeError.$factory("integer argument expected, got " +
1811
$B.get_class($.keepends).__name)
1812
}
1813
var keepends = _b_.int.$factory($.keepends)
1814
// Remove trailing line breaks
1815
if(keepends){
1816
var res = [],
Mar 19, 2018
1817
start = pos,
1818
pos = 0,
1819
self = $.self
1820
while(pos < self.length){
1821
if(self.substr(pos, 2) == "\r\n"){
1822
res.push(self.substring(start, pos + 2))
1823
start = pos + 2
1824
pos = start
Mar 19, 2018
1825
}else if(self.charAt(pos) == "\r" || self.charAt(pos) == "\n"){
1826
res.push(self.substring(start, pos + 1))
1827
start = pos + 1
1828
pos = start
1829
}else{pos++}
1830
}
1831
var rest = self.substr(start)
1832
if(rest){res.push(rest)}
1833
return res
1834
}else{
Mar 19, 2018
1835
var self = $.self.replace(/[\r\n]$/, "")
1836
return self.split(/\n|\r\n|\r/)
1837
}
1838
}
Sep 5, 2014
1839
str
Feb 10, 2018
1840
str.startswith = function(){
1841
// Return True if string starts with the prefix, otherwise return False.
1842
// prefix can also be a tuple of prefixes to look for. With optional
1843
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1844
// stop comparing string at that position.
Mar 19, 2018
1845
var $ = $B.args("startswith", 4,
1846
{self: null, prefix: null, start: null, end: null},
1847
["self", "prefix", "start", "end"],
1848
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1849
1850
normalize_start_end($)
1851
1852
var prefixes = $.prefix
Mar 19, 2018
1853
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1855
var s = $.self.substring($.start, $.end)
1856
for(var i = 0, len = prefixes.length; i < len; i++){
1857
var prefix = prefixes[i]
Mar 19, 2018
1858
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1859
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1860
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1861
}
1862
return false
1863
Sep 5, 2014
1864
}
1865
str
Feb 10, 2018
1866
str.strip = function(){
Mar 19, 2018
1867
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1868
arguments, {chars: _b_.None}, null, null)
1869
if($.chars === _b_.None){return $.self.trim()}
1870
for(var i = 0; i < $.self.length; i++){
1871
if($.chars.indexOf($.self.charAt(i)) == -1){
1872
break
Mar 19, 2018
1875
for(var j = $.self.length - 1; j >= i; j--){
1876
if($.chars.indexOf($.self.charAt(j)) == -1){
1877
break
Mar 19, 2018
1880
return $.self.substring(i, j + 1)
Sep 5, 2014
1881
}
1882
1883
str.swapcase = function(self){
1884
var $ = $B.args("swapcase", 1, {self}, ["self"],
1885
arguments, {}, null, null),
1886
res = "",
1887
char
1888
1889
for(var i = 0, len = self.length; i < len; i++){
1890
char = self.charCodeAt(i)
1891
if(unicode_tables.Ll[char]){
1892
res += self.charAt(i).toUpperCase()
1893
}else if(unicode_tables.Lu[char]){
1894
res += self.charAt(i).toLowerCase()
1895
}else{
1896
res += self.charAt(i)
1897
}
1898
}
1899
return res
1900
}
1901
1902
str.title = function(self){
1903
var $ = $B.args("title", 1, {self}, ["self"],
1904
arguments, {}, null, null),
1905
state,
1906
char,
1907
res = ""
1908
for(var i = 0, len = self.length; i < len; i++){
1909
char = self.charCodeAt(i)
1910
if(unicode_tables.Ll[char]){
1911
if(! state){
1912
res += self.charAt(i).toUpperCase()
1913
state = "word"
1914
}else{
1915
res += self.charAt(i)
1916
}
1917
}else if(unicode_tables.Lu[char] || unicode_tables.Lt[char]){
1918
res += state ? self.charAt(i).toLowerCase() : self.charAt(i)
1919
state = "word"
1920
}else{
1921
state = null
1922
res += self.charAt(i)
1923
}
1924
}
1925
return res
1926
}
1927
1928
str.translate = function(self, table){
Mar 19, 2018
1929
var res = [],
1930
getitem = $B.$getattr(table, "__getitem__")
1931
for(var i = 0, len = self.length; i < len; i++){
1932
try{
1933
var repl = getitem(self.charCodeAt(i))
1934
if(repl !== _b_.None){
1935
res.push(String.fromCharCode(repl))
1936
}
1937
}catch(err){
1938
res.push(self.charAt(i))
1939
}
Sep 5, 2014
1940
}
Mar 19, 2018
1941
return res.join("")
Sep 5, 2014
1942
}
1943
1944
str.upper = function(self){
1945
var $ = $B.args("upper", 1, {self: null}, ["self"],
1946
arguments, {}, null, null)
1947
return self.toUpperCase()
1948
}
1949
Mar 19, 2018
1950
str.zfill = function(self, width){
Mar 19, 2018
1951
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
1952
["self", "width"], arguments, {}, null, null)
1953
if($.width <= self.length){return self}
Mar 19, 2018
1955
case "+":
1956
case "-":
1957
return self.charAt(0) +
1958
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
1960
return "0".repeat(width - self.length) + self
Sep 5, 2014
1962
}
1963
1964
str.$factory = function(arg, encoding, errors){
1965
if(arguments.length == 0){return ""}
1966
if(arg === undefined){
1967
throw _b_.TypeError.$factory("str() argument is undefined")
1968
}
1969
if(encoding !== undefined){
1970
// Arguments may be passed as keywords (cf. issue #1060)
1971
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
1972
["arg", "encoding", "errors"], arguments,
1973
{encoding: "utf-8", errors: "strict"}, null, null),
1974
encoding = $.encoding,
1975
errors = $.errors
1976
}
1977
switch(typeof arg) {
Mar 19, 2018
1978
case "string":
Mar 27, 2019
1979
return str.__str__(arg)
Mar 19, 2018
1980
case "number":
1981
if(isFinite(arg)){return arg.toString()}
1984
if(arg.$is_class || arg.$factory){
1985
// arg is a class
1986
// In this case, str() doesn't use the attribute __str__ of the
1987
// class or its subclasses, but the attribute __str__ of the
1988
// class metaclass (usually "type") or its subclasses (usually
1989
// "object")
1990
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
1991
var func = $B.$getattr(arg.__class__, "__str__")
1993
}
1995
if(arg.__class__ && arg.__class__ === _b_.bytes &&
1996
encoding !== undefined){
1997
// str(bytes, encoding, errors) is equal to
1998
// bytes.decode(encoding, errors)
1999
return _b_.bytes.decode(arg, $.encoding, $.errors)
2001
// Implicit invocation of __str__ uses method __str__ on the class,
2002
// even if arg has an attribute __str__
2003
var klass = arg.__class__ || $B.get_class(arg)
2004
var method = $B.$getattr(klass , "__str__", null)
2005
if(method === null ||
2006
// if not better than object.__str__, try __repr__
2007
(arg.__class__ && arg.__class__ !== _b_.object &&
2008
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2009
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2011
}
2012
catch(err){
2013
console.log("no __str__ for", arg)
Mar 19, 2018
2014
console.log("err ", err)
2015
if($B.debug > 1){console.log(err)}
2016
console.log("Warning - no method __str__ or __repr__, " +
2017
"default to toString", arg)
May 20, 2019
2018
throw err
Sep 5, 2014
2019
}
2020
return $B.$call(method)(arg)
Sep 5, 2014
2021
}
str
Feb 10, 2018
2022
2023
str.__new__ = function(cls){
Mar 19, 2018
2024
if(cls === undefined){
2025
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2026
}
Mar 19, 2018
2027
return {__class__: cls}
Sep 5, 2014
2028
}
2029
str
Feb 10, 2018
2030
$B.set_func_names(str, "builtins")
Sep 5, 2014
2032
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2033
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2034
__class__: _b_.type,
str
Feb 10, 2018
2035
__mro__: [object],
2036
$infos: {
2037
__module__: "builtins",
2038
__name__: "str"
2039
},
str
Feb 10, 2018
2040
$is_class: true
Sep 5, 2014
2041
}
2042
str
Feb 10, 2018
2043
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2044
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2045
for(var $attr in str){
Mar 19, 2018
2046
if(typeof str[$attr] == "function"){
Mar 19, 2018
2047
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2048
return function(){
Mar 19, 2018
2049
var args = [],
2050
pos = 0
2051
if(arguments.length > 0){
2052
var args = [arguments[0].valueOf()],
2053
pos = 1
2054
for(var i = 1, len = arguments.length; i < len; i++){
2055
args[pos++] = arguments[i]
Sep 5, 2014
2056
}
2057
}
Mar 19, 2018
2058
return str[attr].apply(null, args)
Sep 5, 2014
2059
}
2060
})($attr)
2061
}
2062
}
str
Feb 10, 2018
2063
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2066
str
Feb 10, 2018
2067
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2069
_b_.str = str
2070
2071
// Function to parse the 2nd argument of format()
2072
$B.parse_format_spec = function(spec){
Mar 19, 2018
2073
if(spec == ""){this.empty = true}
2074
else{
Mar 19, 2018
2075
var pos = 0,
2076
aligns = "<>=^",
2077
digits = "0123456789",
2078
types = "bcdeEfFgGnosxX%",
2079
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2080
if(align_pos != -1){
2081
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2082
// If the second char is also an alignment specifier, the
2083
// first char is the fill value
2084
this.fill = spec.charAt(0)
2085
this.align = spec.charAt(1)
2086
pos = 2
2087
}else{
2088
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2089
this.align = aligns[align_pos]
2090
this.fill = " "
2091
pos++
2092
}
2093
}else{
2094
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2095
if(spec.charAt(1) && align_pos != -1){
2096
// The second character defines alignment : fill is the first one
Mar 19, 2018
2097
this.align = aligns[align_pos]
2098
this.fill = spec.charAt(0)
2099
pos = 2
2100
}
2101
}
2102
var car = spec.charAt(pos)
Mar 19, 2018
2103
if(car == "+" || car == "-" || car == " "){
2104
this.sign = car
2105
pos++
2106
car = spec.charAt(pos)
Mar 19, 2018
2108
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
2109
if(car == "0"){
Mar 19, 2018
2110
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2111
this.fill = "0"
2112
if(align_pos == -1){
2113
this.align = "="
2114
}
Mar 19, 2018
2115
pos++
2116
car = spec.charAt(pos)
2117
}
Mar 19, 2018
2118
while(car && digits.indexOf(car) > -1){
2119
if(this.width === undefined){this.width = car}
2120
else{this.width += car}
2121
pos++
2122
car = spec.charAt(pos)
Mar 19, 2018
2124
if(this.width !== undefined){this.width = parseInt(this.width)}
2125
if(this.width === undefined && car == "{"){
2126
// Width is determined by a parameter
2127
var end_param_pos = spec.substr(pos).search("}")
2128
this.width = spec.substring(pos, end_param_pos)
2129
console.log("width", "[" + this.width + "]")
2130
pos += end_param_pos + 1
2131
}
Mar 19, 2018
2132
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
2133
if(car == "."){
2134
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2135
throw _b_.ValueError.$factory(
2136
"Missing precision in format spec")
Mar 19, 2018
2138
this.precision = spec.charAt(pos + 1)
2139
pos += 2
2140
car = spec.charAt(pos)
2141
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2142
this.precision += car
Mar 19, 2018
2143
pos++
2144
car = spec.charAt(pos)
2145
}
2146
this.precision = parseInt(this.precision)
2147
}
Mar 19, 2018
2148
if(car && types.indexOf(car) > -1){
2149
this.type = car
2150
pos++
2151
car = spec.charAt(pos)
2152
}
2153
if(pos !== spec.length){
2154
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2158
this.toString = function(){
Mar 19, 2018
2159
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2160
(this.align || "") +
2161
(this.sign || "") +
2162
(this.alternate ? "#" : "") +
2163
(this.sign_aware ? "0" : "") +
2164
(this.width || "") +
2165
(this.comma ? "," : "") +
2166
(this.precision ? "." + this.precision : "") +
2167
(this.type || "")
2168
}
2169
}
2170
2171
$B.format_width = function(s, fmt){
Mar 19, 2018
2172
if(fmt.width && s.length < fmt.width){
2173
var fill = fmt.fill || " ",
2174
align = fmt.align || "<",
2175
missing = fmt.width - s.length
2176
switch(align){
Mar 19, 2018
2177
case "<":
2178
return s + fill.repeat(missing)
2179
case ">":
2180
return fill.repeat(missing) + s
2181
case "=":
2182
if("+-".indexOf(s.charAt(0)) > -1){
2183
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2184
}else{
Mar 19, 2018
2185
return fill.repeat(missing) + s
Mar 19, 2018
2187
case "^":
2188
var left = parseInt(missing / 2)
2189
return fill.repeat(left) + s + fill.repeat(missing - left)
2190
}
2191
}
2192
return s
2193
}
2194
2195
function fstring_expression(){
Mar 19, 2018
2196
this.type = "expression"
2197
this.expression = ""
2198
this.conversion = null
2199
this.fmt = null
2200
}
2201
2202
$B.parse_fstring = function(string){
2203
// Parse a f-string
2204
var elts = [],
2205
pos = 0,
Mar 19, 2018
2206
current = "",
2207
ctype = null,
2208
nb_braces = 0,
2209
car
2210
Mar 19, 2018
2211
while(pos < string.length){
2212
if(ctype === null){
2213
car = string.charAt(pos)
Mar 19, 2018
2214
if(car == "{"){
Mar 21, 2018
2215
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2216
ctype = "string"
2217
current = "{"
2218
pos += 2
2219
}else{
Mar 19, 2018
2220
ctype = "expression"
2221
nb_braces = 1
2222
pos++
2223
}
Mar 19, 2018
2224
}else if(car == "}"){
Mar 21, 2018
2225
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2226
ctype = "string"
2227
current = "}"
2228
pos += 2
2229
}else{
2230
throw Error(" f-string: single '}' is not allowed")
2231
}
2232
}else{
Mar 19, 2018
2233
ctype = "string"
2234
current = car
2235
pos++
Mar 19, 2018
2237
}else if(ctype == "string"){
2238
// end of string is the first single { or end of string
Mar 19, 2018
2239
var i = pos
2240
while(i < string.length){
2241
car = string.charAt(i)
Mar 19, 2018
2242
if(car == "{"){
Mar 21, 2018
2243
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2244
current += "{"
2245
i += 2
2246
}else{
2247
elts.push(current)
Mar 19, 2018
2248
ctype = "expression"
2249
pos = i + 1
2250
break
2251
}
Mar 19, 2018
2252
}else if(car == "}"){
2253
if(string.charAt(i + 1) == car){
2254
current += car
2255
i += 2
2256
}else{
2257
throw Error(" f-string: single '}' is not allowed")
2258
}
2259
}else{
2260
current += car
2261
i++
2262
}
2263
}
Mar 19, 2018
2264
pos = i + 1
2265
}else if(ctype == "debug"){
2266
// after the equal sign, whitespace are ignored and the only
2267
// valid characters are } and :
2268
while(string.charAt(i) == " "){i++}
2269
if(string.charAt(i) == "}"){
2270
// end of debug expression
2271
elts.push(current)
2272
ctype = null
2273
current = ""
2274
pos = i + 1
2275
}
2276
}else{
2277
// End of expression is the } matching the opening {
2278
// There may be nested braces
2279
var i = pos,
2280
nb_braces = 1,
2281
nb_paren = 0,
2282
current = new fstring_expression()
Mar 19, 2018
2283
while(i < string.length){
2284
car = string.charAt(i)
Mar 19, 2018
2285
if(car == "{" && nb_paren == 0){
2286
nb_braces++
2287
current.expression += car
2288
i++
Mar 19, 2018
2289
}else if(car == "}" && nb_paren == 0){
2290
nb_braces -= 1
Mar 19, 2018
2291
if(nb_braces == 0){
2292
// end of expression
2293
elts.push(current)
2294
ctype = null
Mar 19, 2018
2295
current = ""
2296
pos = i + 1
2299
current.expression += car
2300
i++
Mar 19, 2018
2301
}else if(car == "\\"){
2302
// backslash is not allowed in expressions
2303
throw Error("f-string expression part cannot include a" +
2304
" backslash")
Mar 19, 2018
2305
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2306
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2307
if(current.expression.length == 0){
2308
throw Error("f-string: empty expression not allowed")
2309
}
Mar 19, 2018
2310
if("ars".indexOf(string.charAt(i + 1)) == -1){
2311
throw Error("f-string: invalid conversion character:" +
2312
" expected 's', 'r', or 'a'")
2313
}else{
Mar 19, 2018
2314
current.conversion = string.charAt(i + 1)
2315
i += 2
2316
}
Mar 19, 2018
2317
}else if(car == "("){
2318
nb_paren++
2319
current.expression += car
2320
i++
Mar 19, 2018
2321
}else if(car == ")"){
2322
nb_paren--
2323
current.expression += car
2324
i++
Mar 19, 2018
2325
}else if(car == '"'){
2326
// triple string ?
Mar 19, 2018
2327
if(string.substr(i, 3) == '"""'){
2328
var end = string.indexOf('"""', i + 3)
2329
if(end == -1){
2330
throw Error("f-string: unterminated string")
2331
}else{
2332
var trs = string.substring(i, end + 3)
2333
trs = trs.replace("\n", "\\n\\")
2334
current.expression += trs
Mar 19, 2018
2335
i = end + 3
2336
}
2337
}else{
Mar 19, 2018
2338
var end = string.indexOf('"', i + 1)
2339
if(end == -1){
2340
throw Error("f-string: unterminated string")
2341
}else{
2342
current.expression += string.substring(i, end + 1)
2343
i = end + 1
2344
}
2345
}
Mar 19, 2018
2346
}else if(nb_paren == 0 && car == ":"){
2347
current.fmt = true
2348
current.expression += car
2349
i++
2350
}else if(car == "="){
2351
// might be a "debug expression", eg f"{x=}"
2352
var ce = current.expression
2353
if(ce.length == 0 ||
2354
"=!<>:".search(ce.charAt(ce.length - 1)) > -1){
2355
current.expression += car
2356
i++
2357
}else{
2358
// add debug string
2359
tail = car
2360
while(string.charAt(i + 1).match(/\s/)){
2361
tail += string.charAt(i + 1)
2362
i++
2363
}
2364
elts.push(current.expression + tail)
2365
// remove trailing whitespace from expression
2366
while(ce.match(/\s$/)){
2367
ce = ce.substr(0, ce.length - 1)
2368
}
2369
current.expression = ce
2370
ctype = "debug"
2371
i++
2372
}
2373
}else{
2374
current.expression += car
2375
i++
2376
}
2377
}
Mar 21, 2018
2378
if(nb_braces > 0){
2379
throw Error("f-string: expected '}'")
2380
}
2381
}
2382
}
Mar 19, 2018
2383
if(current.length > 0){elts.push(current)}
2384
return elts
2385
}
2386
Sep 5, 2014
2387
})(__BRYTHON__)