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