Skip to content
Permalink
Newer
Older
100644 2099 lines (1927 sloc) 66.6 KB
Sep 5, 2014
1
;(function($B){
2
3
var bltns = $B.InjectBuiltins()
4
eval(bltns)
Sep 5, 2014
5
Mar 23, 2018
6
if(!String.prototype.trim){
Mar 19, 2018
7
// Polyfill for older browsers
8
// The code does not use a regex to make it a bit faster.
9
// Implementation taken from a comment by Timo on the blog:
10
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
11
String.prototype.trim = function () {
12
var c
13
for(var i = 0; i < this.length; i++){
14
c = this.charCodeAt(i)
15
if([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
16
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
17
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
18
continue
19
}else{break}
20
}
21
for(var j = this.length - 1; j >= i; j--){
22
c = this.charCodeAt(j)
Mar 23, 2018
23
if([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
Mar 19, 2018
24
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
25
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
26
continue
27
}else{break}
28
}
29
return this.substring(i, j + 1);
30
}
Mar 23, 2018
32
if(!String.prototype.trimLeft) {
33
// Convenience method for browsers which do not have a native trimLeft
34
// (which is a nonstandard extension in Firefox and Chrome)
Mar 19, 2018
35
String.prototype.trimLeft = function () {
36
var c
37
for(var i = 0; i < this.length; i++){
38
c = this.charCodeAt(i)
Mar 23, 2018
39
if([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
Mar 19, 2018
40
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
41
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
42
continue
43
}else{break}
44
}
45
return this.substring(i)
Mar 23, 2018
48
if(!String.prototype.trimRight) {
Mar 19, 2018
49
String.prototype.trimRight = function () {
50
// Convenience method for browsers which do not have a native trimRight
51
// (which is a nonstandard extension in Firefox and Chrome)
52
var c
53
for(var j = this.length - 1; j >= 0; j--){
54
c = this.charCodeAt(j)
55
if([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
56
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
57
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
58
continue
59
}else{break}
60
}
61
return this.substring(0, j + 1)
Sep 5, 2014
66
str
Feb 10, 2018
67
var str = {
Mar 19, 2018
68
__class__: _b_.type,
69
__dir__: object.__dir__,
70
$infos: {
71
__module__: "builtins",
72
__name__: "str"
73
},
str
Feb 10, 2018
74
$is_class: true,
Mar 19, 2018
75
$native: true
Sep 5, 2014
76
}
77
Mar 19, 2018
79
if($.start === null || $.start === _b_.None){$.start = 0}
80
else if($.start < 0){
81
$.start += $.self.length
82
$.start = Math.max(0, $.start)
83
}
84
if($.end === null || $.end === _b_.None){$.end = $.self.length}
85
else if($.end < 0){
86
$.end += $.self.length
87
$.end = Math.max(0, $.end)
88
}
Mar 19, 2018
90
if(! isinstance($.start, _b_.int) || ! isinstance($.end, _b_.int)){
91
throw _b_.TypeError.$factory("slice indices must be integers " +
92
"or None or have an __index__ method")
93
}
97
function reverse(s){
98
// Reverse a string
Mar 19, 2018
99
return s.split("").reverse().join("")
100
}
101
102
function check_str(obj){
Mar 19, 2018
103
if(! _b_.isinstance(obj, str)){
Mar 21, 2018
104
throw _b_.TypeError.$factory("can't convert '" +
105
$B.class_name(obj) + "' object to str implicitly")
Mar 19, 2018
106
}
str
Feb 10, 2018
109
str.__add__ = function(self,other){
Mar 19, 2018
110
if(!(typeof other === "string")){
111
try{return getattr(other, "__radd__")(self)}
112
catch(err){
113
throw _b_.TypeError.$factory("Can't convert " +
114
$B.class_name(other) + " to str implicitly")}
Sep 5, 2014
115
}
Mar 19, 2018
116
return self + other
Sep 5, 2014
117
}
118
Mar 19, 2018
119
str.__contains__ = function(self, item){
120
if(!(typeof item == "string")){
121
throw _b_.TypeError.$factory("'in <string>' requires " +
122
"string as left operand, not " + item.__class__)
123
}
Sep 5, 2014
124
var nbcar = item.length
Mar 19, 2018
125
if(nbcar == 0) {return true} // a string contains the empty string
126
if(self.length == 0){return nbcar == 0}
127
for(var i = 0, len = self.length; i < len; i++){
128
if(self.substr(i, nbcar) == item){return true}
Sep 5, 2014
129
}
130
return false
131
}
132
str
Feb 10, 2018
133
str.__delitem__ = function(){
134
throw _b_.TypeError.$factory("'str' object doesn't support item deletion")
Sep 5, 2014
135
}
136
Mar 19, 2018
137
// __dir__must be assigned explicitely because attribute resolution for
138
// builtin classes doesn't use __mro__
str
Feb 10, 2018
139
str.__dir__ = object.__dir__
str
Feb 10, 2018
141
str.__eq__ = function(self,other){
Mar 19, 2018
142
if(other === undefined){ // compare object "self" to class "str"
143
return self === str
Sep 5, 2014
144
}
Mar 23, 2018
145
if(_b_.isinstance(other, _b_.str)){
146
return other.valueOf() == self.valueOf()
147
}
148
return _b_.NotImplemented
Sep 5, 2014
149
}
150
151
function preformat(self, fmt){
str
Feb 10, 2018
152
if(fmt.empty){return _b_.str.$factory(self)}
Mar 19, 2018
153
if(fmt.type && fmt.type != "s"){
154
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
155
"' for object of type 'str'")
157
return self
158
}
159
str
Feb 10, 2018
160
str.__format__ = function(self, format_spec) {
161
var fmt = new $B.parse_format_spec(format_spec)
Mar 19, 2018
162
if(fmt.sign !== undefined){
163
throw _b_.ValueError.$factory(
164
"Sign not allowed in string format specifier")
166
// For strings, alignment default to left
Mar 19, 2018
167
fmt.align = fmt.align || "<"
168
return $B.format_width(preformat(self, fmt), fmt)
Sep 5, 2014
169
}
170
str
Feb 10, 2018
171
str.__getitem__ = function(self,arg){
Mar 19, 2018
172
if(isinstance(arg, _b_.int)){
Sep 5, 2014
173
var pos = arg
Mar 19, 2018
174
if(arg < 0) {pos += self.length}
175
if(pos >= 0 && pos < self.length){return self.charAt(pos)}
176
throw _b_.IndexError.$factory("string index out of range")
177
}
178
if(isinstance(arg, slice)) {
179
var s = _b_.slice.$conv_for_seq(arg, self.length),
180
start = s.start,
181
stop = s.stop,
182
step = s.step
183
var res = "",
Mar 19, 2018
184
i = null
Mar 19, 2018
185
if(step > 0){
186
if(stop <= start){return ""}
187
for(var i = start; i < stop; i += step){res += self.charAt(i)}
Mar 23, 2018
188
}else{
Mar 19, 2018
189
if(stop >= start){return ''}
190
for(var i = start; i > stop; i += step){res += self.charAt(i)}
Sep 5, 2014
192
return res
193
}
194
if(isinstance(arg, _b_.bool)){return self.__getitem__(_b_.int.$factory(arg))}
Mar 19, 2018
195
throw _b_.TypeError.$factory("string indices must be integers")
Sep 5, 2014
196
}
197
198
var prefix = 2,
199
suffix = 3,
200
mask = (2 ** 32 - 1)
201
function fnv(p){
202
if(p.length == 0){
203
return 0
204
}
Sep 5, 2014
205
206
var x = prefix
207
x = (x ^ (p.charCodeAt(0) << 7)) & mask
208
for(var i = 0, len = p.length; i < len; i++){
209
x = ((1000003 * x) ^ p.charCodeAt(i)) & mask
210
}
211
x = (x ^ p.length) & mask
212
x = (x ^ suffix) & mask
Sep 5, 2014
213
214
if(x == -1){
215
x = -2
216
}
217
return x
218
}
220
str.__hash__ = function(self) {
221
return fnv(self)
Sep 5, 2014
222
}
223
Mar 19, 2018
224
str.__init__ = function(self, arg){
Sep 5, 2014
225
self.valueOf = function(){return arg}
226
self.toString = function(){return arg}
Sep 5, 2014
228
}
229
Mar 19, 2018
230
var $str_iterator = $B.$iterator_class("str_iterator")
str
Feb 10, 2018
231
str.__iter__ = function(self){
Mar 19, 2018
232
var items = self.split("") // list of all characters in string
233
return $B.$iterator(items, $str_iterator)
Sep 5, 2014
234
}
235
str
Feb 10, 2018
236
str.__len__ = function(self){return self.length}
Sep 5, 2014
237
238
// Start of section for legacy formatting (with %)
239
Mar 19, 2018
240
var kwarg_key = new RegExp("([^\\)]*)\\)")
241
242
var NotANumber = function() {
Mar 19, 2018
243
this.name = "NotANumber"
244
}
245
Mar 19, 2018
246
var number_check = function(s){
247
if(! isinstance(s, [_b_.int, _b_.float])){
248
throw new NotANumber()
249
}
250
}
251
Mar 19, 2018
252
var get_char_array = function(size, char){
Mar 23, 2018
253
if(size <= 0){return ""}
254
return new Array(size + 1).join(char)
255
}
256
Mar 19, 2018
257
var format_padding = function(s, flags, minus_one){
258
var padding = flags.padding
Mar 23, 2018
259
if(! padding){ // undefined
260
return s
261
}
262
s = s.toString()
263
padding = parseInt(padding, 10)
Mar 23, 2018
264
if(minus_one){ // numeric formatting where sign goes in front of padding
265
padding -= 1
266
}
Mar 19, 2018
267
if(! flags.left){
268
return get_char_array(padding - s.length, flags.pad_char) + s
Mar 19, 2018
269
}else{
270
// left adjusted
271
return s + get_char_array(padding - s.length, flags.pad_char)
272
}
273
}
274
Mar 19, 2018
275
var format_int_precision = function(val, flags){
276
var precision = flags.precision
Mar 19, 2018
277
if(!precision){
278
return val.toString()
279
}
280
precision = parseInt(precision, 10)
Mar 19, 2018
282
if(val.__class__ === $B.long_int){
283
s = $B.long_int.to_base(val, 10)
284
}else{
285
s = val.toString()
Mar 19, 2018
287
if(s[0] === "-"){
288
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
Mar 19, 2018
290
return get_char_array(precision - s.length, "0") + s
291
}
292
Mar 19, 2018
293
var format_float_precision = function(val, upper, flags, modifier){
294
var precision = flags.precision
295
// val is a float
Mar 19, 2018
296
if(isFinite(val)){
297
return modifier(val, precision, flags, upper)
Mar 19, 2018
299
if(val === Infinity){
300
val = "inf"
301
}else if(val === -Infinity){
302
val = "-inf"
303
}else{
304
val = "nan"
Mar 19, 2018
306
if(upper){
307
return val.toUpperCase()
308
}
309
return val
311
}
312
Mar 19, 2018
313
var format_sign = function(val, flags){
314
if(flags.sign){
315
if(val >= 0){
316
return "+"
Sep 5, 2014
317
}
Mar 19, 2018
318
}else if (flags.space){
319
if(val >= 0){
320
return " "
321
}
322
}
323
return ""
324
}
Sep 5, 2014
325
326
var str_format = function(val, flags) {
327
// string format supports left and right padding
328
flags.pad_char = " " // even if 0 padding is defined, don't use it
str
Feb 10, 2018
329
return format_padding(str.$factory(val), flags)
Sep 5, 2014
331
332
var num_format = function(val, flags) {
333
number_check(val)
Mar 19, 2018
334
if(val.__class__ === $B.long_int){
335
val = $B.long_int.to_base(val, 10)
336
}else{
337
val = parseInt(val)
340
var s = format_int_precision(val, flags)
Mar 19, 2018
341
if(flags.pad_char === "0"){
342
if(val < 0){
343
s = s.substring(1)
Mar 19, 2018
344
return "-" + format_padding(s, flags, true)
345
}
346
var sign = format_sign(val, flags)
Mar 19, 2018
347
if(sign !== ""){
348
return sign + format_padding(s, flags, true)
349
}
350
}
352
return format_padding(format_sign(val, flags) + s, flags)
353
}
Sep 5, 2014
354
355
var repr_format = function(val, flags) {
356
flags.pad_char = " " // even if 0 padding is defined, don't use it
357
return format_padding(repr(val), flags)
358
}
Sep 5, 2014
359
360
var ascii_format = function(val, flags) {
361
flags.pad_char = " " // even if 0 padding is defined, don't use it
362
return format_padding(ascii(val), flags)
363
}
Sep 5, 2014
364
365
// converts val to float and sets precision if missing
Mar 19, 2018
366
var _float_helper = function(val, flags){
367
number_check(val)
Mar 19, 2018
368
if(! flags.precision){
369
if(! flags.decimal_point){
370
flags.precision = 6
Mar 19, 2018
371
}else{
372
flags.precision = 0
373
}
Mar 19, 2018
374
}else{
375
flags.precision = parseInt(flags.precision, 10)
376
validate_precision(flags.precision)
377
}
378
return parseFloat(val)
379
}
Sep 5, 2014
380
381
// used to capture and remove trailing zeroes
Mar 19, 2018
382
var trailing_zeros = /(.*?)(0+)([eE].*)/,
383
leading_zeros = /\.(0*)/,
384
trailing_dot = /\.$/
Sep 5, 2014
385
386
var validate_precision = function(precision) {
387
// force precision to limits of javascript
Mar 19, 2018
388
if(precision > 20){precision = 20}
389
}
390
391
// gG
Mar 19, 2018
392
var floating_point_format = function(val, upper, flags){
393
val = _float_helper(val, flags),
394
v = val.toString(),
395
v_len = v.length,
396
dot_idx = v.indexOf('.')
397
if(dot_idx < 0){dot_idx = v_len}
398
if(val < 1 && val > -1){
399
var zeros = leading_zeros.exec(v),
400
numzeros
401
if(zeros){
402
numzeros = zeros[1].length
Mar 19, 2018
403
}else{
404
numzeros = 0
405
}
Mar 19, 2018
406
if(numzeros >= 4){
407
val = format_sign(val, flags) + format_float_precision(val, upper,
408
flags, _floating_g_exp_helper)
409
if(!flags.alternate){
410
var trl = trailing_zeros.exec(val)
Mar 19, 2018
411
if(trl){
412
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
414
}else{
415
if(flags.precision <= 1){
416
val = val[0] + "." + val.substring(1)
418
}
419
return format_padding(val, flags)
420
}
421
flags.precision = (flags.precision || 0) + numzeros
Mar 19, 2018
422
return format_padding(format_sign(val, flags) +
423
format_float_precision(val, upper, flags,
424
function(val, precision) {
425
return val.toFixed(min(precision, v_len - dot_idx) +
426
numzeros)
427
}),
428
flags
429
)
430
}
431
432
if(dot_idx > flags.precision){
433
val = format_sign(val, flags) + format_float_precision(val, upper,
434
flags, _floating_g_exp_helper)
435
if(! flags.alternate){
436
var trl = trailing_zeros.exec(val)
Mar 19, 2018
437
if(trl){
438
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
440
}else{
441
if(flags.precision <= 1){
442
val = val[0] + "." + val.substring(1)
443
}
444
}
445
return format_padding(val, flags)
446
}
Mar 19, 2018
447
return format_padding(format_sign(val, flags) +
448
format_float_precision(val, upper, flags,
449
function(val, precision) {
450
if(!flags.decimal_point){
451
precision = min(v_len - 1, 6)
452
}else if (precision > v_len){
453
if(! flags.alternate){
454
precision = v_len
455
}
Sep 5, 2014
456
}
Mar 19, 2018
457
if(precision < dot_idx){
458
precision = dot_idx
459
}
460
return val.toFixed(precision - dot_idx)
461
}),
462
flags
463
)
Sep 5, 2014
465
Mar 19, 2018
466
var _floating_g_exp_helper = function(val, precision, flags, upper){
467
if(precision){--precision}
468
val = val.toExponential(precision)
469
// pad exponent to two digits
Mar 19, 2018
470
var e_idx = val.lastIndexOf("e")
471
if(e_idx > val.length - 4){
472
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
474
if(upper){return val.toUpperCase()}
475
return val
476
}
477
478
// fF
479
var floating_point_decimal_format = function(val, upper, flags) {
480
val = _float_helper(val, flags)
Mar 19, 2018
481
return format_padding(format_sign(val, flags) +
482
format_float_precision(val, upper, flags,
483
function(val, precision, flags) {
484
val = val.toFixed(precision)
485
if(precision === 0 && flags.alternate){
486
val += '.'
487
}
488
return val
489
}),
490
flags
491
)
492
}
493
494
var _floating_exp_helper = function(val, precision, flags, upper) {
495
val = val.toExponential(precision)
496
// pad exponent to two digits
Mar 19, 2018
497
var e_idx = val.lastIndexOf("e")
Mar 23, 2018
498
if(e_idx > val.length - 4){
Mar 19, 2018
499
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
501
if(upper){return val.toUpperCase()}
502
return val
503
}
504
505
// eE
Mar 19, 2018
506
var floating_point_exponential_format = function(val, upper, flags){
507
val = _float_helper(val, flags)
Mar 19, 2018
509
return format_padding(format_sign(val, flags) +
510
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
511
}
512
Mar 19, 2018
513
var signed_hex_format = function(val, upper, flags){
515
number_check(val)
Mar 23, 2018
517
if(val.__class__ === $B.long_int){
Mar 19, 2018
518
ret = $B.long_int.to_base(val, 16)
519
}else{
520
ret = parseInt(val)
521
ret = ret.toString(16)
522
}
523
ret = format_int_precision(ret, flags)
Mar 19, 2018
524
if(upper){ret = ret.toUpperCase()}
Mar 23, 2018
525
if(flags.pad_char === "0"){
Mar 19, 2018
526
if(val < 0){
527
ret = ret.substring(1)
Mar 19, 2018
528
ret = "-" + format_padding(ret, flags, true)
529
}
530
var sign = format_sign(val, flags)
Mar 19, 2018
531
if(sign !== ""){
532
ret = sign + format_padding(ret, flags, true)
Sep 5, 2014
533
}
Mar 19, 2018
536
if(flags.alternate){
537
if(ret.charAt(0) === "-"){
538
if(upper){ret = "-0X" + ret.slice(1)}
539
else{ret = "-0x" + ret.slice(1)}
540
}else{
541
if(upper){ret = "0X" + ret}
542
else{ret = "0x" + ret}
543
}
544
}
545
return format_padding(format_sign(val, flags) + ret, flags)
546
}
Sep 5, 2014
547
548
var octal_format = function(val, flags) {
549
number_check(val)
Mar 19, 2018
552
if(val.__class__ === $B.long_int){
553
ret = $B.long_int.to_base(8)
554
}else{
555
ret = parseInt(val)
556
ret = ret.toString(8)
559
ret = format_int_precision(ret, flags)
Mar 19, 2018
561
if(flags.pad_char === "0"){
562
if(val < 0){
563
ret = ret.substring(1)
Mar 19, 2018
564
ret = "-" + format_padding(ret, flags, true)
565
}
566
var sign = format_sign(val, flags)
Mar 19, 2018
567
if(sign !== ""){
568
ret = sign + format_padding(ret, flags, true)
569
}
Sep 5, 2014
570
}
Mar 19, 2018
572
if(flags.alternate){
573
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
574
else{ret = "0o" + ret}
Sep 5, 2014
575
}
576
return format_padding(ret, flags)
577
}
578
Mar 19, 2018
579
var single_char_format = function(val, flags){
580
if(isinstance(val, str) && val.length == 1) return val
581
try{
582
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
Mar 19, 2018
583
}catch (err){
584
throw _b_.TypeError.$factory("%c requires int or char")
585
}
586
return format_padding(chr(val), flags)
587
}
588
Mar 19, 2018
589
var num_flag = function(c, flags){
590
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
591
flags.pad_char = "0"
592
return
593
}
Mar 19, 2018
594
if(!flags.decimal_point){
595
flags.padding = (flags.padding || "") + c
Mar 19, 2018
596
}else{
597
flags.precision = (flags.precision || "") + c
598
}
599
}
600
601
var decimal_point_flag = function(val, flags) {
Mar 23, 2018
602
if(flags.decimal_point){
603
// can only have one decimal point
604
throw new UnsupportedChar()
605
}
606
flags.decimal_point = true
607
}
608
Mar 19, 2018
609
var neg_flag = function(val, flags){
610
flags.pad_char = " " // overrides '0' flag
611
flags.left = true
612
}
613
Mar 19, 2018
614
var space_flag = function(val, flags){
615
flags.space = true
616
}
617
Mar 19, 2018
618
var sign_flag = function(val, flags){
619
flags.sign = true
620
}
621
Mar 19, 2018
622
var alternate_flag = function(val, flags){
623
flags.alternate = true
624
}
625
626
var char_mapping = {
Mar 19, 2018
627
"s": str_format,
628
"d": num_format,
629
"i": num_format,
630
"u": num_format,
631
"o": octal_format,
632
"r": repr_format,
633
"a": ascii_format,
634
"g": function(val, flags){
635
return floating_point_format(val, false, flags)
636
},
637
"G": function(val, flags){return floating_point_format(val, true, flags)},
638
"f": function(val, flags){
639
return floating_point_decimal_format(val, false, flags)
640
},
641
"F": function(val, flags){
642
return floating_point_decimal_format(val, true, flags)
643
},
644
"e": function(val, flags){
645
return floating_point_exponential_format(val, false, flags)
646
},
647
"E": function(val, flags){
648
return floating_point_exponential_format(val, true, flags)
649
},
650
"x": function(val, flags){return signed_hex_format(val, false, flags)},
651
"X": function(val, flags){return signed_hex_format(val, true, flags)},
652
"c": single_char_format,
653
"0": function(val, flags){return num_flag("0", flags)},
654
"1": function(val, flags){return num_flag("1", flags)},
655
"2": function(val, flags){return num_flag("2", flags)},
656
"3": function(val, flags){return num_flag("3", flags)},
657
"4": function(val, flags){return num_flag("4", flags)},
658
"5": function(val, flags){return num_flag("5", flags)},
659
"6": function(val, flags){return num_flag("6", flags)},
660
"7": function(val, flags){return num_flag("7", flags)},
661
"8": function(val, flags){return num_flag("8", flags)},
662
"9": function(val, flags){return num_flag("9", flags)},
663
"-": neg_flag,
664
" ": space_flag,
665
"+": sign_flag,
666
".": decimal_point_flag,
667
"#": alternate_flag
668
}
669
670
// exception thrown when an unsupported char is encountered in legacy format
Mar 19, 2018
671
var UnsupportedChar = function(){
672
this.name = "UnsupportedChar"
673
}
674
str
Feb 10, 2018
675
str.__mod__ = function(self, args) {
677
var length = self.length,
Mar 19, 2018
678
pos = 0 | 0,
679
argpos = null,
680
getitem
Mar 19, 2018
681
if(_b_.isinstance(args, _b_.tuple)){
682
argpos = 0 | 0
Mar 19, 2018
684
getitem = _b_.getattr(args, "__getitem__", _b_.None)
685
}
686
var ret = ''
687
var $get_kwarg_string = function(s) {
688
// returns [self, newpos]
689
++pos
690
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
691
if(! rslt){
692
throw _b_.ValueError.$factory("incomplete format key")
693
}
694
var key = rslt[1]
695
newpos += rslt[0].length
Mar 23, 2018
696
try{
697
var self = getitem(key)
Mar 19, 2018
698
}catch(err){
699
if(err.name === "KeyError"){
700
throw err
701
}
702
throw _b_.TypeError.$factory("format requires a mapping")
704
return get_string_value(s, self)
705
}
706
707
var $get_arg_string = function(s) {
708
// returns [self, newpos]
709
var self
711
// non-tuple args
Mar 19, 2018
712
if(argpos === null){
713
// args is the value
Mar 19, 2018
715
}else{
716
self = args[argpos++]
Mar 19, 2018
717
if(self === undefined){
718
throw _b_.TypeError.$factory(
719
"not enough arguments for format string")
Sep 5, 2014
720
}
721
}
722
return get_string_value(s, self)
724
var get_string_value = function(s, self) {
725
// todo: get flags, type
726
// todo: string value based on flags, type, value
Mar 19, 2018
727
var flags = {"pad_char": " "}
728
do{
729
var func = char_mapping[s[newpos]]
Mar 23, 2018
730
try{
Mar 19, 2018
731
if(func === undefined){
732
throw new UnsupportedChar()
Mar 19, 2018
733
}else{
734
var ret = func(self, flags)
Mar 19, 2018
735
if(ret !== undefined){
736
return ret
737
}
738
++newpos
739
}
Mar 19, 2018
740
}catch (err){
741
if(err.name == "UnsupportedChar"){
742
invalid_char = s[newpos]
Mar 19, 2018
743
if(invalid_char === undefined){
744
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
746
throw _b_.ValueError.$factory(
747
"unsupported format character '" + invalid_char +
748
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
749
") at index " + newpos)
750
}else if(err.name === "NotANumber"){
751
var try_char = s[newpos],
752
cls = self.__class__
753
if(!cls){
754
if(typeof(self) === "string"){
755
cls = "str"
756
}else{
757
cls = typeof(self)
Mar 19, 2018
759
}else{
Mar 19, 2018
762
throw _b_.TypeError.$factory("%" + try_char +
763
" format: a number is required, not " + cls)
764
}else{
765
throw err
766
}
Sep 5, 2014
767
}
Mar 19, 2018
768
}while (true)
Sep 5, 2014
769
}
770
var nbph = 0 // number of placeholders
Mar 19, 2018
771
do{
772
var newpos = self.indexOf("%", pos)
773
if(newpos < 0){
774
ret += self.substring(pos)
775
break
776
}
777
ret += self.substring(pos, newpos)
778
++newpos
Mar 19, 2018
779
if(newpos < length){
780
if(self[newpos] === "%"){
781
ret += "%"
782
}else{
Mar 19, 2018
784
if(self[newpos] === "("){
785
++newpos
786
ret += $get_kwarg_string(self)
Mar 23, 2018
787
}else{
788
ret += $get_arg_string(self)
789
}
790
}
Mar 19, 2018
791
}else{
792
// % at end of string
793
throw _b_.ValueError.$factory("incomplete format")
794
}
795
pos = newpos + 1
Mar 19, 2018
796
}while(pos < length)
797
798
if(argpos !== null){
799
if(args.length > argpos){
800
throw _b_.TypeError.$factory(
801
"not enough arguments for format string")
802
}else if(args.length < argpos){
803
throw _b_.TypeError.$factory(
804
"not all arguments converted during string formatting")
Mar 19, 2018
806
}else if(nbph == 0){
807
throw _b_.TypeError.$factory(
808
"not all arguments converted during string formatting")
Sep 5, 2014
812
str
Feb 10, 2018
813
str.__mro__ = [object]
Sep 5, 2014
814
str
Feb 10, 2018
815
str.__mul__ = function(){
Mar 19, 2018
816
var $ = $B.args("__mul__", 2, {self: null, other: null},
817
["self", "other"], arguments, {}, null, null)
818
if(! isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
819
"Can't multiply sequence by non-int of type '" +
Mar 19, 2018
821
var $res = ""
822
for(var i = 0; i< $.other; i++){$res += $.self.valueOf()}
Sep 5, 2014
823
return $res
824
}
825
Mar 19, 2018
826
str.__ne__ = function(self,other){return other !== self.valueOf()}
Sep 5, 2014
827
str
Feb 10, 2018
828
str.__repr__ = function(self){
830
// escape the escape char
831
res = self.replace(/\\/g, "\\\\")
832
// special cases
833
res = res.replace(new RegExp("\u0007", "g"), "\\x07").
834
replace(new RegExp("\b", "g"), "\\x08").
835
replace(new RegExp("\f", "g"), "\\x0c").
836
replace(new RegExp("\n", "g"), "\\n").
837
replace(new RegExp("\r", "g"), "\\r").
838
replace(new RegExp("\t", "g"), "\\t")
Mar 27, 2019
839
840
res = res.replace(combining_re, "\u200B$1")
Mar 19, 2018
841
if(res.search('"') == -1 && res.search("'") == -1){
842
return "'" + res + "'"
843
}else if(self.search('"') == -1){
844
return '"' + res + '"'
845
}
846
var qesc = new RegExp("'", "g") // to escape single quote
847
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
848
return res
849
}
850
Mar 19, 2018
851
str.__setitem__ = function(self, attr, value){
852
throw _b_.TypeError.$factory(
853
"'str' object does not support item assignment")
Sep 5, 2014
854
}
Mar 27, 2019
855
var combining = []
856
for(var cp = 0x300; cp <= 0x36F; cp++){
857
combining.push(String.fromCharCode(cp))
858
}
859
var combining_re = new RegExp("(" + combining.join("|") + ")")
str
Feb 10, 2018
861
str.__str__ = function(self){
Mar 27, 2019
862
return self.replace(combining_re, "\u200B$1")
Sep 5, 2014
863
}
Mar 19, 2018
864
str.toString = function(){return "string!"}
Sep 5, 2014
865
866
// generate comparison methods
867
var $comp_func = function(self,other){
868
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
869
return self > other
870
}
Mar 19, 2018
871
$comp_func += "" // source code
872
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
873
for(var $op in $comps){
Mar 19, 2018
874
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
875
}
876
877
// add "reflected" methods
str
Feb 10, 2018
878
$B.make_rmethods(str)
Sep 5, 2014
879
880
// unsupported operations
Mar 19, 2018
881
var $notimplemented = function(self, other){
882
throw NotImplementedError.$factory(
883
"OPERATOR not implemented for class str")
Sep 5, 2014
884
}
885
886
// Copy static methods from unicode
887
var from_unicode = [
888
"title",
889
"capitalize",
890
"casefold",
891
"islower",
892
"isupper",
893
"istitle",
894
"isspace",
895
"isalpha",
896
"isalnum",
897
"isdecimal",
898
"isdigit",
899
"isnumeric",
900
"isidentifier",
901
"isprintable",
902
"lower",
903
"swapcase",
904
"upper"
905
]
906
// uses the object unicode, defined in unicode.min.js
Mar 19, 2018
907
from_unicode.forEach(function(name){
str
Feb 10, 2018
908
str[name] = unicode[name]
Mar 19, 2018
909
})
Sep 5, 2014
910
Mar 19, 2018
911
str.center = function(){
912
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
913
["self", "width", "fillchar"],
914
arguments, {fillchar:" "}, null, null),
915
self = $.self
Mar 19, 2018
917
if($.width <= self.length) {return self}
Mar 19, 2018
919
var pad = parseInt(($.width - self.length) / 2),
920
res = $.fillchar.repeat(pad)
Sep 5, 2014
921
res += self + res
Mar 19, 2018
922
if(res.length < $.width){res += $.fillchar}
Sep 5, 2014
923
return res
924
}
925
str
Feb 10, 2018
926
str.count = function(){
Mar 19, 2018
927
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
928
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
Mar 19, 2018
930
if(!(typeof $.sub == "string")){throw _b_.TypeError.$factory(
931
"Can't convert '" + $B.class_name($.sub) +
Mar 19, 2018
932
"' object to str implicitly")}
Mar 19, 2018
934
if($.start !== null){
Mar 19, 2018
936
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
937
else{_slice = _b_.slice.$factory($.start, $.self.length)}
str
Feb 10, 2018
938
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
Mar 19, 2018
940
if($.self.length + $.sub.length == 0){return 1}
Mar 19, 2018
942
if($.sub.length == 0){
943
if($.start == $.self.length){return 1}
944
else if(substr.length == 0){return 0}
945
return substr.length + 1
Mar 19, 2018
947
var n = 0,
948
pos = 0
949
while(pos < substr.length){
950
pos = substr.indexOf($.sub, pos)
951
if(pos >= 0){n++; pos += $.sub.length}
952
else{break}
Sep 5, 2014
953
}
954
return n
955
}
956
Mar 31, 2019
957
str.encode = function (self, encoding, errors = "") {
Mar 23, 2018
958
if(encoding === undefined){encoding = "utf-8"}
Mar 19, 2018
959
if(encoding == "rot13" || encoding == "rot_13"){
960
// Special case : returns a string
Mar 19, 2018
961
var res = ""
962
for(var i = 0, len = self.length; i < len ; i++){
963
var char = self.charAt(i)
Mar 19, 2018
964
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
965
res += String.fromCharCode(String.charCodeAt(char) + 13)
966
}else if(("m" < char && char <= "z") ||
967
("M" < char && char <= "Z")){
968
res += String.fromCharCode(String.charCodeAt(char) - 13)
969
}else{res += char}
970
}
971
return res
972
}
Mar 31, 2019
973
return _b_.bytes.$factory(self, encoding, errors)
Sep 5, 2014
974
}
975
str
Feb 10, 2018
976
str.endswith = function(){
977
// Return True if the string ends with the specified suffix, otherwise
978
// return False. suffix can also be a tuple of suffixes to look for.
979
// With optional start, test beginning at that position. With optional
Sep 5, 2014
980
// end, stop comparing at that position.
Mar 19, 2018
981
var $ = $B.args("endswith", 4,
982
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
983
["self", "suffix", "start", "end"],
984
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
985
986
normalize_start_end($)
987
988
var suffixes = $.suffix
Mar 19, 2018
989
if(! isinstance(suffixes,_b_.tuple)){suffixes = [suffixes]}
Mar 19, 2018
991
var s = $.self.substring($.start, $.end)
992
for(var i = 0, len = suffixes.length; i < len; i++){
993
var suffix = suffixes[i]
Mar 19, 2018
994
if(! _b_.isinstance(suffix, str)){throw _b_.TypeError.$factory(
Sep 20, 2015
995
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
996
if(suffix.length <= s.length &&
997
s.substr(s.length - suffix.length) == suffix){return true}
Sep 5, 2014
998
}
999
return false
1000
}
1001
str
Feb 10, 2018
1002
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
1003
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1004
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1005
var s = $B.$GetInt($.tabsize),
1006
col = 0,
1007
pos = 0,
1008
res = ""
1009
if(s == 1){return self.replace(/\t/g," ")}
1010
while(pos < self.length){
1011
var car = self.charAt(pos)
1012
switch(car){
Mar 19, 2018
1013
case "\t":
Mar 21, 2018
1014
while(col % s > 0){res += " "; col++}
Mar 19, 2018
1016
case "\r":
1017
case "\n":
1018
res += car
1019
col = 0
1020
break
1021
default:
1022
res += car
1023
col++
1024
break
1025
}
1026
pos++
1027
}
Sep 5, 2014
1030
}
1031
str
Feb 10, 2018
1032
str.find = function(){
1033
// Return the lowest index in the string where substring sub is found,
1034
// such that sub is contained in the slice s[start:end]. Optional
1035
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1036
// Return -1 if sub is not found.
Mar 19, 2018
1037
var $ = $B.args("str.find", 4,
Mar 19, 2018
1038
{self: null, sub: null, start: null, end: null},
1039
["self", "sub", "start", "end"],
1040
arguments, {start: 0, end: null}, null, null)
1041
check_str($.sub)
Mar 19, 2018
1044
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
1045
throw _b_.TypeError.$factory("slice indices must be " +
1046
"integers or None or have an __index__ method")}
1047
var s = $.self.substring($.start, $.end)
Mar 19, 2018
1049
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1050
if(s.length + $.sub.length == 0){return -1}
Mar 19, 2018
1052
var last_search = s.length - $.sub.length
1053
for(var i = 0; i <= last_search; i++){
1054
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
Sep 5, 2014
1055
}
Sep 5, 2014
1057
}
1058
1059
// Next function used by method .format()
1060
1061
$B.parse_format = function(fmt_string){
Sep 5, 2014
1062
1063
// Parse a "format string", as described in the Python documentation
1064
// Return a format object. For the format string
1065
// a.x[z]!r:...
1066
// the object has attributes :
1067
// - name : "a"
1068
// - name_ext : [".x", "[z]"]
1069
// - conv : r
1070
// - spec : rest of string after :
Sep 5, 2014
1071
Mar 19, 2018
1072
var elts = fmt_string.split(":"),
1073
name,
1074
conv,
1075
spec,
Mar 19, 2018
1076
name_ext = []
Mar 19, 2018
1077
if(elts.length == 1){
1078
// No : in the string : it only contains a name
1079
name = fmt_string
1080
}else{
1081
// name is before the first ":"
1082
// spec (the format specification) is after
1083
name = elts[0]
Mar 19, 2018
1084
spec = elts.splice(1).join(":")
Mar 19, 2018
1087
var elts = name.split("!")
1088
if(elts.length > 1){
1089
name = elts[0]
1090
conv = elts[1] // conversion flag
Sep 5, 2014
1092
Mar 19, 2018
1093
if(name !== undefined){
1094
// "name' may be a subscription or attribute
1095
// Put these "extensions" in the list "name_ext"
1096
function name_repl(match){
1097
name_ext.push(match)
Mar 19, 2018
1098
return ""
1099
}
1100
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1101
name = name.replace(name_ext_re, name_repl)
1102
}
Sep 5, 2014
1103
1104
return {name: name, name_ext: name_ext,
1105
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1107
1108
$B.split_format = function(self){
1109
// Parse self to detect formatting instructions
1110
// Create a list "parts" made of sections of the string :
1111
// - elements of even rank are literal text
1112
// - elements of odd rank are "format objects", built from the
1113
// format strings in self (of the form {...})
Mar 19, 2018
1114
var pos = 0,
1115
_len = self.length,
Mar 19, 2018
1117
text = "",
1118
parts = [],
1119
rank = 0
1120
while(pos < _len){
1121
car = self.charAt(pos)
Mar 21, 2018
1122
if(car == "{" && self.charAt(pos + 1) == "{"){
1123
// replace {{ by literal {
Mar 19, 2018
1124
text += "{"
1125
pos += 2
1126
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1127
// replace }} by literal }
Mar 19, 2018
1128
text += "}"
1129
pos += 2
1130
}else if(car == "{"){
1131
// Start of a format string
1133
// Store current literal text
1134
parts.push(text)
1135
1136
// Search the end of the format string, ie the } closing the
1137
// opening {. Since the string can contain other pairs {} for
1138
// nested formatting, an integer nb is incremented for each { and
1139
// decremented for each } ; the end of the format string is
Mar 19, 2018
1140
// reached when nb == 0
1141
var end = pos + 1,
1142
nb = 1
1143
while(end < _len){
1144
if(self.charAt(end) == "{"){nb++; end++}
1145
else if(self.charAt(end) == "}"){
1146
nb--; end++
1147
if(nb == 0){
1148
// End of format string
Mar 19, 2018
1149
var fmt_string = self.substring(pos + 1, end - 1)
1150
1151
// Create a format object, by function parse_format
1152
var fmt_obj = $B.parse_format(fmt_string)
1153
fmt_obj.raw_name = fmt_obj.name
1154
fmt_obj.raw_spec = fmt_obj.spec
1155
1156
// If no name is explicitely provided, use the rank
1157
if(!fmt_obj.name){
Mar 19, 2018
1158
fmt_obj.name = rank + ""
Sep 5, 2014
1161
Mar 19, 2018
1162
if(fmt_obj.spec !== undefined){
1163
// "spec" may contain "nested replacement fields"
1164
// Replace empty fields by the rank in positional
1165
// arguments
1166
function replace_nested(name, key){
1167
if(key == ""){
1168
// Use implicit rank
1169
return "{" + rank++ + "}"
1173
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1174
replace_nested)
1175
}
1177
// Store format object in list "parts"
1178
parts.push(fmt_obj)
Mar 19, 2018
1179
text = ""
1180
break
1181
}
1182
}else{end++}
Sep 5, 2014
1183
}
Mar 19, 2018
1184
if(nb > 0){throw ValueError.$factory("wrong format " + self)}
Mar 19, 2018
1186
}else{text += car; pos++}
Sep 5, 2014
1187
}
1188
if(text){parts.push(text)}
1189
return parts
1190
}
1191
1192
str.format = function(self) {
1193
var $ = $B.args("format", 1, {self: null}, ["self"],
1194
arguments, {}, "$args", "$kw")
1195
1196
var parts = $B.split_format($.self)
1197
1198
// Apply formatting to the values passed to format()
Mar 19, 2018
1199
var res = "",
1200
fmt
Mar 19, 2018
1202
for(var i = 0; i < parts.length; i++){
1203
// Literal text is added unchanged
Mar 19, 2018
1204
if(typeof parts[i] == "string"){res += parts[i]; continue}
1206
// Format objects
1207
fmt = parts[i]
1208
1209
if(fmt.spec !== undefined){
1210
// "spec" may contain "nested replacement fields"
1211
// In this case, evaluate them using the positional
1212
// or keyword arguments passed to format()
1213
function replace_nested(name, key){
1214
if(/\d+/.exec(key)){
1215
// If key is numeric, search in positional
1216
// arguments
1217
return _b_.tuple.__getitem__($.$args,
1218
parseInt(key))
1219
}else{
1220
// Else try in keyword arguments
1221
return _b_.dict.__getitem__($.$kw, key)
1222
}
1223
}
1224
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1225
replace_nested)
1226
}
Mar 21, 2018
1227
if(fmt.name.charAt(0).search(/\d/) > -1){
1228
// Numerical reference : use positional arguments
1229
var pos = parseInt(fmt.name),
Feb 11, 2018
1230
value = _b_.tuple.__getitem__($.$args, pos)
1231
}else{
1232
// Use keyword arguments
Feb 11, 2018
1233
var value = _b_.dict.__getitem__($.$kw, fmt.name)
1234
}
1235
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1236
for(var j = 0; j < fmt.name_ext.length; j++){
1237
var ext = fmt.name_ext[j]
Mar 19, 2018
1238
if(ext.charAt(0) == "."){
1239
// Attribute
1240
value = _b_.getattr(value, ext.substr(1))
1241
}else{
1242
// Subscription
Mar 19, 2018
1243
var key = ext.substr(1, ext.length - 2)
1244
// An index made of digits is transformed into an integer
Mar 19, 2018
1245
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1246
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1249
1250
// If the conversion flag is set, first call a function to convert
1251
// the value
Mar 19, 2018
1252
if(fmt.conv == "a"){value = _b_.ascii(value)}
1253
else if(fmt.conv == "r"){value = _b_.repr(value)}
1254
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1256
// Call attribute __format__ to perform the actual formatting
1257
if(value.$is_class || value.$factory){
1258
// For classes, don't use the class __format__ method
1259
res += value.__class__.__format__(value, fmt.spec)
Mar 19, 2018
1261
res += _b_.getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1263
}
Sep 5, 2014
1265
}
1266
str
Feb 10, 2018
1267
str.format_map = function(self) {
Mar 19, 2018
1268
throw NotImplementedError.$factory(
1269
"function format_map not implemented yet")
Sep 5, 2014
1270
}
1271
str
Feb 10, 2018
1272
str.index = function(self){
Sep 5, 2014
1273
// Like find(), but raise ValueError when the substring is not found.
str
Feb 10, 2018
1274
var res = str.find.apply(null,arguments)
Mar 19, 2018
1275
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1276
return res
1277
}
1278
str
Feb 10, 2018
1279
str.join = function(){
Mar 19, 2018
1280
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1281
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1283
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1284
res = [],
Sep 5, 2014
1286
while(1){
1287
try{
1288
var obj2 = _b_.next(iterable)
Mar 19, 2018
1289
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1290
"sequence item " + count + ": expected str instance, " +
1291
$B.class_name(obj2) + " found")}
1292
res.push(obj2)
Sep 5, 2014
1293
}catch(err){
1294
if(_b_.isinstance(err, _b_.StopIteration)){
1295
break
1296
}
Sep 5, 2014
1297
else{throw err}
1298
}
1299
}
1300
return res.join($.self)
Sep 5, 2014
1301
}
1302
str
Feb 10, 2018
1303
str.ljust = function(self) {
Mar 19, 2018
1304
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1305
["self", "width", "fillchar"],
1306
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1308
if($.width <= self.length){return self}
1309
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1310
}
1311
str
Feb 10, 2018
1312
str.lstrip = function(self,x){
Mar 19, 2018
1313
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1314
arguments, {chars:_b_.None}, null, null)
1315
if($.chars === _b_.None){return $.self.trimLeft()}
1316
for(var i = 0; i < $.self.length; i++){
1317
if($.chars.indexOf($.self.charAt(i)) === -1){
1318
return $.self.substring(i)
Mar 19, 2018
1321
return ""
Sep 5, 2014
1322
}
1323
1324
// note, maketrans should be a static function.
str
Feb 10, 2018
1325
str.maketrans = function() {
Mar 19, 2018
1326
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1327
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1329
var _t = _b_.dict.$factory()
Mar 19, 2018
1331
if($.y === null && $.z === null){
1332
// If there is only one argument, it must be a dictionary mapping
1333
// Unicode ordinals (integers) or characters (strings of length 1) to
1334
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1335
// keys will then be converted to ordinals.
Mar 19, 2018
1336
if(! _b_.isinstance($.x, _b_.dict)){
1337
throw _b_.TypeError.$factory(
1338
"maketrans only argument must be a dict")
Feb 11, 2018
1340
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1341
for(var i = 0, len = items.length; i < len; i++){
1342
var k = items[i][0],
1343
v = items[i][1]
1344
if(! _b_.isinstance(k, _b_.int)){
1345
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1346
k = _b_.ord(k)
1347
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1348
" is not int or 1-char string")}
1349
}
Mar 19, 2018
1350
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1351
throw _b_.TypeError.$factory("dictionary value " + v +
1352
" is not None, integer or string")
1353
}
1354
_b_.dict.$setitem(_t, k, v)
1355
}
1356
return _t
1357
}else{
1358
// If there are two arguments, they must be strings of equal length,
1359
// and in the resulting dictionary, each character in x will be mapped
1360
// to the character at the same position in y
Mar 19, 2018
1361
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1362
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1363
}else if($.x.length !== $.y.length){
1364
throw _b_.TypeError.$factory(
1365
"maketrans arguments must be strings or same length")
1366
}else{
1367
var toNone = {}
Mar 19, 2018
1368
if($.z !== null){
1369
// If there is a third argument, it must be a string, whose
1370
// characters will be mapped to None in the result
Mar 19, 2018
1371
if(! _b_.isinstance($.z, _b_.str)){
1372
throw _b_.TypeError.$factory(
1373
"maketrans third argument must be a string")
Mar 19, 2018
1375
for(var i = 0, len = $.z.length; i < len; i++){
1376
toNone[_b_.ord($.z.charAt(i))] = true
1377
}
Mar 19, 2018
1379
for(var i = 0, len = $.x.length; i < len; i++){
1380
var key = _b_.ord($.x.charAt(i)),
1381
value = $.y.charAt(i)
1382
_b_.dict.$setitem(_t, key, value)
1383
}
1384
for(var k in toNone){
1385
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1386
}
1387
return _t
1388
}
1389
}
Sep 5, 2014
1390
}
1391
str
Feb 10, 2018
1392
str.partition = function() {
Mar 19, 2018
1393
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1394
arguments, {}, null, null)
Mar 19, 2018
1395
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1396
check_str($.sep)
1397
var i = $.self.indexOf($.sep)
Mar 23, 2018
1398
if(i == -1){return _b_.tuple.$factory([$.self, "", ""])}
Mar 19, 2018
1399
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1400
$.self.substring(i + $.sep.length)])
1401
}
1402
1403
function $re_escape(str){
1404
var specials = "[.*+?|()$^"
1405
for(var i = 0, len = specials.length; i < len; i++){
1406
var re = new RegExp("\\"+specials.charAt(i), "g")
1407
str = str.replace(re, "\\"+specials.charAt(i))
1408
}
1409
return str
Sep 5, 2014
1410
}
1411
str
Feb 10, 2018
1412
str.replace = function(self, old, _new, count) {
1413
// Replaces occurrences of 'old' by '_new'. Count references
1414
// the number of times to replace. In CPython, negative or undefined
1415
// values of count means replace all.
Mar 19, 2018
1416
var $ = $B.args("replace", 4,
1417
{self: null, old: null, $$new: null, count: null},
1418
["self", "old", "$$new", "count"],
1419
arguments, {count: -1}, null, null),
1420
count = $.count,
1421
self = $.self,
1422
old = $.old,
1423
_new = $.$$new
1424
// Validate type of old
1425
check_str(old)
1426
check_str(_new)
1427
// Validate instance type of 'count'
Mar 23, 2018
1428
if(! isinstance(count,[_b_.int, _b_.float])){
1429
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1430
"' object cannot be interpreted as an integer")
1431
}else if(isinstance(count, _b_.float)){
1432
throw _b_.TypeError.$factory("integer argument expected, got float")
1433
}
1434
if(count == 0){return self}
1435
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1436
if(old == ""){
1437
if(_new == ""){return self}
1438
if(self == ""){return _new}
1439
var elts = self.split("")
1440
if(count > -1 && elts.length >= count){
1441
var rest = elts.slice(count).join("")
1442
return _new + elts.slice(0, count).join(_new) + rest
1443
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1445
var elts = str.split(self, old, count)
Sep 5, 2014
1446
}
Mar 19, 2018
1448
var res = self,
1449
pos = -1
1450
if(old.length == 0){
Mar 19, 2018
1452
for(var i = 0; i < elts.length; i++){
1453
res += elts[i] + _new
Mar 19, 2018
1455
return res + rest
Mar 19, 2018
1458
if(count < 0){count = res.length}
1459
while(count > 0){
1460
pos = res.indexOf(old, pos)
1461
if(pos < 0){break}
1462
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1463
pos = pos + _new.length
1464
count--
Mar 19, 2018
1466
return res
Sep 5, 2014
1467
}
1468
str
Feb 10, 2018
1469
str.rfind = function(self){
1470
// Return the highest index in the string where substring sub is found,
1471
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1472
// start and end are interpreted as in slice notation. Return -1 on failure.
Mar 19, 2018
1473
var $ = $B.args("rfind", 4,
Mar 19, 2018
1474
{self: null, sub: null, start: null, end: null},
1475
["self", "sub", "start", "end"],
1476
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1477
1480
check_str($.sub)
Mar 19, 2018
1482
if($.sub.length == 0){
1483
if($.start > $.self.length){return -1}
1484
else{return $.self.length}
1485
}
1486
var sublen = $.sub.length
Mar 19, 2018
1488
for(var i = $.end - sublen; i >= $.start; i--){
1489
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1492
}
1493
str
Feb 10, 2018
1494
str.rindex = function(){
Sep 5, 2014
1495
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1496
var res = str.rfind.apply(null, arguments)
1497
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1498
return res
1499
}
1500
str
Feb 10, 2018
1501
str.rjust = function(self) {
Mar 19, 2018
1502
var $ = $B.args("rjust",3,
1503
{self: null, width: null, fillchar: null},
1504
["self", "width", "fillchar"],
1505
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1506
Mar 19, 2018
1507
if($.width <= self.length){return self}
Sep 5, 2014
1508
1509
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1510
}
1511
str
Feb 10, 2018
1512
str.rpartition = function(self,sep) {
Mar 19, 2018
1513
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1514
arguments, {}, null, null)
1515
check_str($.sep)
1516
var self = reverse($.self),
1517
sep = reverse($.sep)
Mar 19, 2018
1518
var items = str.partition(self, sep).reverse()
1519
for(var i = 0; i < items.length; i++){
1520
items[i] = items[i].split("").reverse().join("")
1521
}
1522
return items
Sep 5, 2014
1523
}
1524
str
Feb 10, 2018
1525
str.rsplit = function(self) {
Mar 19, 2018
1526
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1527
["self", "sep", "maxsplit"], arguments,
1528
{sep: _b_.None, maxsplit: -1}, null, null),
1529
sep = $.sep
1530
1531
// Use split on the reverse of the string and of separator
1532
var rev_str = reverse($.self),
1533
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1534
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1536
// Reverse the list, then each string inside the list
1537
rev_res.reverse()
Mar 19, 2018
1538
for(var i = 0; i < rev_res.length; i++){
1539
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1542
}
1543
Mar 19, 2018
1544
str.rstrip = function(self, x){
1545
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1546
arguments, {chars: _b_.None}, null, null)
1547
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1548
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1549
if($.chars.indexOf($.self.charAt(j)) == -1){
1550
return $.self.substring(0, j + 1)
Mar 19, 2018
1553
return ""
Sep 5, 2014
1554
}
1555
str
Feb 10, 2018
1556
str.split = function(){
Mar 19, 2018
1557
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1558
["self", "sep", "maxsplit"], arguments,
1559
{sep: _b_.None, maxsplit: -1}, null, null),
1560
sep = $.sep,
1561
maxsplit = $.maxsplit,
1562
self = $.self,
1563
pos = 0
1564
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1565
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1566
if(sep === _b_.None){
Sep 5, 2014
1567
var res = []
Mar 19, 2018
1568
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1569
if(pos === self.length - 1){return [self]}
1570
var name = ""
Sep 5, 2014
1571
while(1){
Mar 19, 2018
1572
if(self.charAt(pos).search(/\s/) == -1){
1573
if(name == ""){name = self.charAt(pos)}
1574
else{name += self.charAt(pos)}
Sep 5, 2014
1575
}else{
Mar 19, 2018
1576
if(name !== ""){
Sep 5, 2014
1577
res.push(name)
Mar 19, 2018
1578
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1579
res.pop()
Mar 19, 2018
1580
res.push(name + self.substr(pos))
Sep 5, 2014
1581
return res
1582
}
Mar 19, 2018
1583
name = ""
Sep 5, 2014
1584
}
1585
}
1586
pos++
Mar 19, 2018
1587
if(pos > self.length - 1){
Sep 5, 2014
1588
if(name){res.push(name)}
1589
break
1590
}
1591
}
1592
return res
1593
}else{
Mar 19, 2018
1594
var res = [],
1595
s = "",
1596
seplen = sep.length
1597
if(maxsplit == 0){return [self]}
1598
while(pos < self.length){
1599
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1602
if(maxsplit > -1 && res.length >= maxsplit){
1603
res.push(self.substr(pos))
1604
return res
1605
}
Mar 19, 2018
1606
s = ""
1607
}else{
1608
s += self.charAt(pos)
1609
pos++
Sep 5, 2014
1610
}
1611
}
Sep 5, 2014
1614
}
1615
}
1616
str
Feb 10, 2018
1617
str.splitlines = function(self){
Mar 19, 2018
1618
var $ = $B.args("splitlines", 2, {self: null, keepends: null},
Mar 19, 2018
1619
["self", "keepends"], arguments, {keepends: false}, null, null)
1620
if(! _b_.isinstance($.keepends, [_b_.bool, _b_.int])){
1621
throw _b_.TypeError.$factory("integer argument expected, got " +
1622
$B.get_class($.keepends).__name)
1623
}
1624
var keepends = _b_.int.$factory($.keepends)
1625
// Remove trailing line breaks
1626
if(keepends){
1627
var res = [],
Mar 19, 2018
1628
start = pos,
1629
pos = 0,
1630
self = $.self
1631
while(pos < self.length){
1632
if(self.substr(pos, 2) == "\r\n"){
1633
res.push(self.substring(start, pos + 2))
1634
start = pos + 2
1635
pos = start
Mar 19, 2018
1636
}else if(self.charAt(pos) == "\r" || self.charAt(pos) == "\n"){
1637
res.push(self.substring(start, pos + 1))
1638
start = pos + 1
1639
pos = start
1640
}else{pos++}
1641
}
1642
var rest = self.substr(start)
1643
if(rest){res.push(rest)}
1644
return res
1645
}else{
Mar 19, 2018
1646
var self = $.self.replace(/[\r\n]$/, "")
1647
return self.split(/\n|\r\n|\r/)
1648
}
1649
}
Sep 5, 2014
1650
str
Feb 10, 2018
1651
str.startswith = function(){
1652
// Return True if string starts with the prefix, otherwise return False.
1653
// prefix can also be a tuple of prefixes to look for. With optional
1654
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1655
// stop comparing string at that position.
Mar 19, 2018
1656
var $ = $B.args("startswith", 4,
1657
{self: null, prefix: null, start: null, end: null},
1658
["self", "prefix", "start", "end"],
1659
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1660
1661
normalize_start_end($)
1662
1663
var prefixes = $.prefix
Mar 19, 2018
1664
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1666
var s = $.self.substring($.start, $.end)
1667
for(var i = 0, len = prefixes.length; i < len; i++){
1668
var prefix = prefixes[i]
Mar 19, 2018
1669
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1670
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1671
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1672
}
1673
return false
1674
Sep 5, 2014
1675
}
1676
str
Feb 10, 2018
1677
str.strip = function(){
Mar 19, 2018
1678
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1679
arguments, {chars: _b_.None}, null, null)
1680
if($.chars === _b_.None){return $.self.trim()}
1681
for(var i = 0; i < $.self.length; i++){
1682
if($.chars.indexOf($.self.charAt(i)) == -1){
1683
break
Mar 19, 2018
1686
for(var j = $.self.length - 1; j >= i; j--){
1687
if($.chars.indexOf($.self.charAt(j)) == -1){
1688
break
Mar 19, 2018
1691
return $.self.substring(i, j + 1)
Sep 5, 2014
1692
}
1693
1694
str.translate = function(self, table){
Mar 19, 2018
1695
var res = [],
1696
getitem = $B.$getattr(table, "__getitem__")
1697
for(var i = 0, len = self.length; i < len; i++){
1698
try{
1699
var repl = getitem(self.charCodeAt(i))
1700
if(repl !== _b_.None){
1701
res.push(repl)
1702
}
1703
}catch(err){
1704
res.push(self.charAt(i))
1705
}
Sep 5, 2014
1706
}
Mar 19, 2018
1707
return res.join("")
Sep 5, 2014
1708
}
1709
Mar 19, 2018
1710
str.zfill = function(self, width){
Mar 19, 2018
1711
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
1712
["self", "width"], arguments, {}, null, null)
1713
if($.width <= self.length){return self}
Mar 19, 2018
1715
case "+":
1716
case "-":
1717
return self.charAt(0) +
1718
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
1720
return "0".repeat(width - self.length) + self
Sep 5, 2014
1722
}
1723
1724
str.$factory = function(arg, encoding, errors){
Mar 19, 2018
1725
if(arg === undefined){console.log("undef"); return "<undefined>"}
1726
switch(typeof arg) {
Mar 19, 2018
1727
case "string":
Mar 27, 2019
1728
return str.__str__(arg)
Mar 19, 2018
1729
case "number":
1730
if(isFinite(arg)){return arg.toString()}
1733
if(arg.$is_class || arg.$factory){
1734
// arg is a class
1735
// In this case, str() doesn't use the attribute __str__ of the
1736
// class or its subclasses, but the attribute __str__ of the
1737
// class metaclass (usually "type") or its subclasses (usually
1738
// "object")
1739
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
1740
var func = $B.$getattr(arg.__class__, "__str__")
1742
}
1743
if(arg.__class__ && arg.__class__ === _b_.bytes &&
1744
encoding !== undefined){
1745
// str(bytes, encoding, errors) is equal to
1746
// bytes.decode(encoding, errors)
1747
// Arguments may be passed as keywords (cf. issue #1060)
1748
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
1749
["arg", "encoding", "errors"], arguments,
1750
{encoding: "utf-8", errors: "strict"}, null, null)
1751
return _b_.bytes.decode(arg, $.encoding, $.errors)
1753
var f = $B.$getattr(arg, "__str__", null)
1754
if(f === null ||
1755
// if not better than object.__str__, try __repr__
1756
(arg.__class__ && arg.__class__ !== _b_.object &&
1757
f.$infos && f.$infos.__func__ === _b_.object.__str__)){
1758
var f = $B.$getattr(arg, "__repr__")
1759
}
Sep 5, 2014
1760
}
1761
catch(err){
1762
console.log("no __str__ for", arg)
Mar 19, 2018
1763
console.log("err ", err)
1764
if($B.debug > 1){console.log(err)}
1765
console.log("Warning - no method __str__ or __repr__, " +
1766
"default to toString", arg)
1767
return arg.toString()
Sep 5, 2014
1768
}
Sep 5, 2014
1770
}
str
Feb 10, 2018
1771
1772
str.__new__ = function(cls){
Mar 19, 2018
1773
if(cls === undefined){
1774
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
1775
}
Mar 19, 2018
1776
return {__class__: cls}
Sep 5, 2014
1777
}
1778
str
Feb 10, 2018
1779
$B.set_func_names(str, "builtins")
Sep 5, 2014
1781
// dictionary and factory for subclasses of string
str
Feb 10, 2018
1782
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
1783
__class__: _b_.type,
str
Feb 10, 2018
1784
__mro__: [object],
1785
$infos: {
1786
__module__: "builtins",
1787
__name__: "str"
1788
},
str
Feb 10, 2018
1789
$is_class: true
Sep 5, 2014
1790
}
1791
str
Feb 10, 2018
1792
// the methods in subclass apply the methods in str to the
Sep 5, 2014
1793
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
1794
for(var $attr in str){
Mar 19, 2018
1795
if(typeof str[$attr] == "function"){
Mar 19, 2018
1796
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
1797
return function(){
Mar 19, 2018
1798
var args = [],
1799
pos = 0
1800
if(arguments.length > 0){
1801
var args = [arguments[0].valueOf()],
1802
pos = 1
1803
for(var i = 1, len = arguments.length; i < len; i++){
1804
args[pos++] = arguments[i]
Sep 5, 2014
1805
}
1806
}
Mar 19, 2018
1807
return str[attr].apply(null, args)
Sep 5, 2014
1808
}
1809
})($attr)
1810
}
1811
}
str
Feb 10, 2018
1812
StringSubclass.__new__ = function(cls){
Sep 5, 2014
1815
str
Feb 10, 2018
1816
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
1818
_b_.str = str
1819
1820
// Function to parse the 2nd argument of format()
1821
$B.parse_format_spec = function(spec){
Mar 19, 2018
1822
if(spec == ""){this.empty = true}
1823
else{
Mar 19, 2018
1824
var pos = 0,
1825
aligns = "<>=^",
1826
digits = "0123456789",
1827
types = "bcdeEfFgGnosxX%",
1828
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
1829
if(align_pos != -1){
1830
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
1831
// If the second char is also an alignment specifier, the
1832
// first char is the fill value
1833
this.fill = spec.charAt(0)
1834
this.align = spec.charAt(1)
1835
pos = 2
1836
}else{
1837
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
1838
this.align = aligns[align_pos]
1839
this.fill = " "
1840
pos++
1841
}
1842
}else{
1843
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
1844
if(spec.charAt(1) && align_pos != -1){
1845
// The second character defines alignment : fill is the first one
Mar 19, 2018
1846
this.align = aligns[align_pos]
1847
this.fill = spec.charAt(0)
1848
pos = 2
1849
}
1850
}
1851
var car = spec.charAt(pos)
Mar 19, 2018
1852
if(car == "+" || car == "-" || car == " "){
1853
this.sign = car
1854
pos++
1855
car = spec.charAt(pos)
Mar 19, 2018
1857
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
1858
if(car == "0"){
Mar 19, 2018
1859
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
1860
this.fill = "0"
1861
this.align = "="
1862
pos++
1863
car = spec.charAt(pos)
1864
}
Mar 19, 2018
1865
while(car && digits.indexOf(car) > -1){
1866
if(this.width === undefined){this.width = car}
1867
else{this.width += car}
1868
pos++
1869
car = spec.charAt(pos)
Mar 19, 2018
1871
if(this.width !== undefined){this.width = parseInt(this.width)}
1872
if(this.width === undefined && car == "{"){
1873
// Width is determined by a parameter
1874
var end_param_pos = spec.substr(pos).search("}")
1875
this.width = spec.substring(pos, end_param_pos)
1876
console.log("width", "[" + this.width + "]")
1877
pos += end_param_pos + 1
1878
}
Mar 19, 2018
1879
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
1880
if(car == "."){
1881
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
1882
throw _b_.ValueError.$factory(
1883
"Missing precision in format spec")
Mar 19, 2018
1885
this.precision = spec.charAt(pos + 1)
1886
pos += 2
1887
car = spec.charAt(pos)
1888
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
1889
this.precision += car
Mar 19, 2018
1890
pos++
1891
car = spec.charAt(pos)
1892
}
1893
this.precision = parseInt(this.precision)
1894
}
Mar 19, 2018
1895
if(car && types.indexOf(car) > -1){
1896
this.type = car
1897
pos++
1898
car = spec.charAt(pos)
1899
}
1900
if(pos !== spec.length){
1901
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
1904
this.toString = function(){
Mar 19, 2018
1905
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
1906
(this.align || "") +
1907
(this.sign || "") +
1908
(this.alternate ? "#" : "") +
1909
(this.sign_aware ? "0" : "") +
1910
(this.width || "") +
1911
(this.comma ? "," : "") +
1912
(this.precision ? "." + this.precision : "") +
1913
(this.type || "")
1914
}
1915
}
1916
1917
$B.format_width = function(s, fmt){
Mar 19, 2018
1918
if(fmt.width && s.length < fmt.width){
1919
var fill = fmt.fill || " ",
1920
align = fmt.align || "<",
1921
missing = fmt.width - s.length
1922
switch(align){
Mar 19, 2018
1923
case "<":
1924
return s + fill.repeat(missing)
1925
case ">":
1926
return fill.repeat(missing) + s
1927
case "=":
1928
if("+-".indexOf(s.charAt(0)) > -1){
1929
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
1930
}else{
Mar 19, 2018
1931
return fill.repeat(missing) + s
Mar 19, 2018
1933
case "^":
1934
var left = parseInt(missing / 2)
1935
return fill.repeat(left) + s + fill.repeat(missing - left)
1936
}
1937
}
1938
return s
1939
}
1940
1941
function fstring_expression(){
Mar 19, 2018
1942
this.type = "expression"
1943
this.expression = ""
1944
this.conversion = null
1945
this.fmt = null
1946
}
1947
1948
$B.parse_fstring = function(string){
1949
// Parse a f-string
1950
var elts = [],
1951
pos = 0,
Mar 19, 2018
1952
current = "",
1953
ctype = null,
1954
nb_braces = 0,
1955
car
1956
Mar 19, 2018
1957
while(pos < string.length){
1958
if(ctype === null){
1959
car = string.charAt(pos)
Mar 19, 2018
1960
if(car == "{"){
Mar 21, 2018
1961
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
1962
ctype = "string"
1963
current = "{"
1964
pos += 2
1965
}else{
Mar 19, 2018
1966
ctype = "expression"
1967
nb_braces = 1
1968
pos++
1969
}
Mar 19, 2018
1970
}else if(car == "}"){
Mar 21, 2018
1971
if(string.charAt(pos + 1) == car){
Mar 19, 2018
1972
ctype = "string"
1973
current = "}"
1974
pos += 2
1975
}else{
1976
throw Error(" f-string: single '}' is not allowed")
1977
}
1978
}else{
Mar 19, 2018
1979
ctype = "string"
1980
current = car
1981
pos++
Mar 19, 2018
1983
}else if(ctype == "string"){
1984
// end of string is the first single { or end of string
Mar 19, 2018
1985
var i = pos
1986
while(i < string.length){
1987
car = string.charAt(i)
Mar 19, 2018
1988
if(car == "{"){
Mar 21, 2018
1989
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
1990
current += "{"
1991
i += 2
1992
}else{
1993
elts.push(current)
Mar 19, 2018
1994
ctype = "expression"
1995
pos = i + 1
1996
break
1997
}
Mar 19, 2018
1998
}else if(car == "}"){
1999
if(string.charAt(i + 1) == car){
2000
current += car
2001
i += 2
2002
}else{
2003
throw Error(" f-string: single '}' is not allowed")
2004
}
2005
}else{
2006
current += car
2007
i++
2008
}
2009
}
Mar 19, 2018
2010
pos = i + 1
2011
}else{
2012
// End of expression is the } matching the opening {
2013
// There may be nested braces
2014
var i = pos,
2015
nb_braces = 1,
2016
nb_paren = 0,
2017
current = new fstring_expression()
Mar 19, 2018
2018
while(i < string.length){
2019
car = string.charAt(i)
Mar 19, 2018
2020
if(car == "{" && nb_paren == 0){
2021
nb_braces++
2022
current.expression += car
2023
i++
Mar 19, 2018
2024
}else if(car == "}" && nb_paren == 0){
2025
nb_braces -= 1
Mar 19, 2018
2026
if(nb_braces == 0){
2027
// end of expression
2028
elts.push(current)
2029
ctype = null
Mar 19, 2018
2030
current = ""
2031
pos = i + 1
2034
current.expression += car
2035
i++
Mar 19, 2018
2036
}else if(car == "\\"){
2037
// backslash is not allowed in expressions
2038
throw Error("f-string expression part cannot include a" +
2039
" backslash")
Mar 19, 2018
2040
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2041
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2042
if(current.expression.length == 0){
2043
throw Error("f-string: empty expression not allowed")
2044
}
Mar 19, 2018
2045
if("ars".indexOf(string.charAt(i + 1)) == -1){
2046
throw Error("f-string: invalid conversion character:" +
2047
" expected 's', 'r', or 'a'")
2048
}else{
Mar 19, 2018
2049
current.conversion = string.charAt(i + 1)
2050
i += 2
2051
}
Mar 19, 2018
2052
}else if(car == "("){
2053
nb_paren++
2054
current.expression += car
2055
i++
Mar 19, 2018
2056
}else if(car == ")"){
2057
nb_paren--
2058
current.expression += car
2059
i++
Mar 19, 2018
2060
}else if(car == '"'){
2061
// triple string ?
Mar 19, 2018
2062
if(string.substr(i, 3) == '"""'){
2063
var end = string.indexOf('"""', i + 3)
2064
if(end == -1){
2065
throw Error("f-string: unterminated string")
2066
}else{
2067
var trs = string.substring(i, end + 3)
2068
trs = trs.replace("\n", "\\n\\")
2069
current.expression += trs
Mar 19, 2018
2070
i = end + 3
2071
}
2072
}else{
Mar 19, 2018
2073
var end = string.indexOf('"', i + 1)
2074
if(end == -1){
2075
throw Error("f-string: unterminated string")
2076
}else{
2077
current.expression += string.substring(i, end + 1)
2078
i = end + 1
2079
}
2080
}
Mar 19, 2018
2081
}else if(nb_paren == 0 && car == ":"){
2082
current.fmt = true
2083
current.expression += car
2084
i++
2085
}else{
2086
current.expression += car
2087
i++
2088
}
2089
}
Mar 21, 2018
2090
if(nb_braces > 0){
2091
throw Error("f-string: expected '}'")
2092
}
2093
}
2094
}
Mar 19, 2018
2095
if(current.length > 0){elts.push(current)}
2096
return elts
2097
}
2098
Sep 5, 2014
2099
})(__BRYTHON__)