Skip to content
Permalink
Newer
Older
100644 2090 lines (1919 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
$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 19, 2018
839
if(res.search('"') == -1 && res.search("'") == -1){
840
return "'" + res + "'"
841
}else if(self.search('"') == -1){
842
return '"' + res + '"'
843
}
844
var qesc = new RegExp("'", "g") // to escape single quote
845
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
846
return res
847
}
848
Mar 19, 2018
849
str.__setitem__ = function(self, attr, value){
850
throw _b_.TypeError.$factory(
851
"'str' object does not support item assignment")
Sep 5, 2014
852
}
str
Feb 10, 2018
854
str.__str__ = function(self){
Sep 5, 2014
856
}
Mar 19, 2018
857
str.toString = function(){return "string!"}
Sep 5, 2014
858
859
// generate comparison methods
860
var $comp_func = function(self,other){
Mar 19, 2018
861
if(typeof other !== "string"){throw _b_.TypeError.$factory(
862
"unorderable types: 'str' > " + $B.class_name(other) + "()")}
Sep 5, 2014
863
return self > other
864
}
Mar 19, 2018
865
$comp_func += "" // source code
866
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
867
for(var $op in $comps){
Mar 19, 2018
868
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
869
}
870
871
// add "reflected" methods
str
Feb 10, 2018
872
$B.make_rmethods(str)
Sep 5, 2014
873
874
// unsupported operations
Mar 19, 2018
875
var $notimplemented = function(self, other){
876
throw NotImplementedError.$factory(
877
"OPERATOR not implemented for class str")
Sep 5, 2014
878
}
879
880
// Copy static methods from unicode
881
var from_unicode = [
882
"title",
883
"capitalize",
884
"casefold",
885
"islower",
886
"isupper",
887
"istitle",
888
"isspace",
889
"isalpha",
890
"isalnum",
891
"isdecimal",
892
"isdigit",
893
"isnumeric",
894
"isidentifier",
895
"isprintable",
896
"lower",
897
"swapcase",
898
"upper"
899
]
900
// uses the object unicode, defined in unicode.min.js
Mar 19, 2018
901
from_unicode.forEach(function(name){
str
Feb 10, 2018
902
str[name] = unicode[name]
Mar 19, 2018
903
})
Sep 5, 2014
904
Mar 19, 2018
905
str.center = function(){
906
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
907
["self", "width", "fillchar"],
908
arguments, {fillchar:" "}, null, null),
909
self = $.self
Mar 19, 2018
911
if($.width <= self.length) {return self}
Mar 19, 2018
913
var pad = parseInt(($.width - self.length) / 2),
914
res = $.fillchar.repeat(pad)
Sep 5, 2014
915
res += self + res
Mar 19, 2018
916
if(res.length < $.width){res += $.fillchar}
Sep 5, 2014
917
return res
918
}
919
str
Feb 10, 2018
920
str.count = function(){
Mar 19, 2018
921
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
922
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
Mar 19, 2018
924
if(!(typeof $.sub == "string")){throw _b_.TypeError.$factory(
925
"Can't convert '" + $B.class_name($.sub) +
Mar 19, 2018
926
"' object to str implicitly")}
Mar 19, 2018
928
if($.start !== null){
Mar 19, 2018
930
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
931
else{_slice = _b_.slice.$factory($.start, $.self.length)}
str
Feb 10, 2018
932
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
Mar 19, 2018
934
if($.self.length + $.sub.length == 0){return 1}
Mar 19, 2018
936
if($.sub.length == 0){
937
if($.start == $.self.length){return 1}
938
else if(substr.length == 0){return 0}
939
return substr.length + 1
Mar 19, 2018
941
var n = 0,
942
pos = 0
943
while(pos < substr.length){
944
pos = substr.indexOf($.sub, pos)
945
if(pos >= 0){n++; pos += $.sub.length}
946
else{break}
Sep 5, 2014
947
}
948
return n
949
}
950
str
Feb 10, 2018
951
str.encode = function(self, encoding) {
Mar 23, 2018
952
if(encoding === undefined){encoding = "utf-8"}
Mar 19, 2018
953
if(encoding == "rot13" || encoding == "rot_13"){
954
// Special case : returns a string
Mar 19, 2018
955
var res = ""
956
for(var i = 0, len = self.length; i < len ; i++){
957
var char = self.charAt(i)
Mar 19, 2018
958
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
959
res += String.fromCharCode(String.charCodeAt(char) + 13)
960
}else if(("m" < char && char <= "z") ||
961
("M" < char && char <= "Z")){
962
res += String.fromCharCode(String.charCodeAt(char) - 13)
963
}else{res += char}
964
}
965
return res
966
}
967
return _b_.bytes.$factory(self, encoding)
Sep 5, 2014
968
}
969
str
Feb 10, 2018
970
str.endswith = function(){
971
// Return True if the string ends with the specified suffix, otherwise
972
// return False. suffix can also be a tuple of suffixes to look for.
973
// With optional start, test beginning at that position. With optional
Sep 5, 2014
974
// end, stop comparing at that position.
Mar 19, 2018
975
var $ = $B.args("endswith", 4,
976
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
977
["self", "suffix", "start", "end"],
978
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
979
980
normalize_start_end($)
981
982
var suffixes = $.suffix
Mar 19, 2018
983
if(! isinstance(suffixes,_b_.tuple)){suffixes = [suffixes]}
Mar 19, 2018
985
var s = $.self.substring($.start, $.end)
986
for(var i = 0, len = suffixes.length; i < len; i++){
987
var suffix = suffixes[i]
Mar 19, 2018
988
if(! _b_.isinstance(suffix, str)){throw _b_.TypeError.$factory(
Sep 20, 2015
989
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
990
if(suffix.length <= s.length &&
991
s.substr(s.length - suffix.length) == suffix){return true}
Sep 5, 2014
992
}
993
return false
994
}
995
str
Feb 10, 2018
996
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
997
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
998
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
999
var s = $B.$GetInt($.tabsize),
1000
col = 0,
1001
pos = 0,
1002
res = ""
1003
if(s == 1){return self.replace(/\t/g," ")}
1004
while(pos < self.length){
1005
var car = self.charAt(pos)
1006
switch(car){
Mar 19, 2018
1007
case "\t":
Mar 21, 2018
1008
while(col % s > 0){res += " "; col++}
Mar 19, 2018
1010
case "\r":
1011
case "\n":
1012
res += car
1013
col = 0
1014
break
1015
default:
1016
res += car
1017
col++
1018
break
1019
}
1020
pos++
1021
}
Sep 5, 2014
1024
}
1025
str
Feb 10, 2018
1026
str.find = function(){
1027
// Return the lowest index in the string where substring sub is found,
1028
// such that sub is contained in the slice s[start:end]. Optional
1029
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1030
// Return -1 if sub is not found.
Mar 19, 2018
1031
var $ = $B.args("str.find", 4,
Mar 19, 2018
1032
{self: null, sub: null, start: null, end: null},
1033
["self", "sub", "start", "end"],
1034
arguments, {start: 0, end: null}, null, null)
1035
check_str($.sub)
Mar 19, 2018
1038
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
1039
throw _b_.TypeError.$factory("slice indices must be " +
1040
"integers or None or have an __index__ method")}
1041
var s = $.self.substring($.start, $.end)
Mar 19, 2018
1043
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1044
if(s.length + $.sub.length == 0){return -1}
Mar 19, 2018
1046
var last_search = s.length - $.sub.length
1047
for(var i = 0; i <= last_search; i++){
1048
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
Sep 5, 2014
1049
}
Sep 5, 2014
1051
}
1052
1053
// Next function used by method .format()
1054
1055
$B.parse_format = function(fmt_string){
Sep 5, 2014
1056
1057
// Parse a "format string", as described in the Python documentation
1058
// Return a format object. For the format string
1059
// a.x[z]!r:...
1060
// the object has attributes :
1061
// - name : "a"
1062
// - name_ext : [".x", "[z]"]
1063
// - conv : r
1064
// - spec : rest of string after :
Sep 5, 2014
1065
Mar 19, 2018
1066
var elts = fmt_string.split(":"),
1067
name,
1068
conv,
1069
spec,
Mar 19, 2018
1070
name_ext = []
Mar 19, 2018
1071
if(elts.length == 1){
1072
// No : in the string : it only contains a name
1073
name = fmt_string
1074
}else{
1075
// name is before the first ":"
1076
// spec (the format specification) is after
1077
name = elts[0]
Mar 19, 2018
1078
spec = elts.splice(1).join(":")
Mar 19, 2018
1081
var elts = name.split("!")
1082
if(elts.length > 1){
1083
name = elts[0]
1084
conv = elts[1] // conversion flag
Sep 5, 2014
1086
Mar 19, 2018
1087
if(name !== undefined){
1088
// "name' may be a subscription or attribute
1089
// Put these "extensions" in the list "name_ext"
1090
function name_repl(match){
1091
name_ext.push(match)
Mar 19, 2018
1092
return ""
1093
}
1094
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1095
name = name.replace(name_ext_re, name_repl)
1096
}
Sep 5, 2014
1097
1098
return {name: name, name_ext: name_ext,
1099
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1101
1102
$B.split_format = function(self){
1103
// Parse self to detect formatting instructions
1104
// Create a list "parts" made of sections of the string :
1105
// - elements of even rank are literal text
1106
// - elements of odd rank are "format objects", built from the
1107
// format strings in self (of the form {...})
Mar 19, 2018
1108
var pos = 0,
1109
_len = self.length,
Mar 19, 2018
1111
text = "",
1112
parts = [],
1113
rank = 0
1114
while(pos < _len){
1115
car = self.charAt(pos)
Mar 21, 2018
1116
if(car == "{" && self.charAt(pos + 1) == "{"){
1117
// replace {{ by literal {
Mar 19, 2018
1118
text += "{"
1119
pos += 2
1120
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1121
// replace }} by literal }
Mar 19, 2018
1122
text += "}"
1123
pos += 2
1124
}else if(car == "{"){
1125
// Start of a format string
1127
// Store current literal text
1128
parts.push(text)
1129
1130
// Search the end of the format string, ie the } closing the
1131
// opening {. Since the string can contain other pairs {} for
1132
// nested formatting, an integer nb is incremented for each { and
1133
// decremented for each } ; the end of the format string is
Mar 19, 2018
1134
// reached when nb == 0
1135
var end = pos + 1,
1136
nb = 1
1137
while(end < _len){
1138
if(self.charAt(end) == "{"){nb++; end++}
1139
else if(self.charAt(end) == "}"){
1140
nb--; end++
1141
if(nb == 0){
1142
// End of format string
Mar 19, 2018
1143
var fmt_string = self.substring(pos + 1, end - 1)
1144
1145
// Create a format object, by function parse_format
1146
var fmt_obj = $B.parse_format(fmt_string)
1147
fmt_obj.raw_name = fmt_obj.name
1148
fmt_obj.raw_spec = fmt_obj.spec
1149
1150
// If no name is explicitely provided, use the rank
1151
if(!fmt_obj.name){
Mar 19, 2018
1152
fmt_obj.name = rank + ""
Sep 5, 2014
1155
Mar 19, 2018
1156
if(fmt_obj.spec !== undefined){
1157
// "spec" may contain "nested replacement fields"
1158
// Replace empty fields by the rank in positional
1159
// arguments
1160
function replace_nested(name, key){
1161
if(key == ""){
1162
// Use implicit rank
1163
return "{" + rank++ + "}"
1167
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1168
replace_nested)
1169
}
1171
// Store format object in list "parts"
1172
parts.push(fmt_obj)
Mar 19, 2018
1173
text = ""
1174
break
1175
}
1176
}else{end++}
Sep 5, 2014
1177
}
Mar 19, 2018
1178
if(nb > 0){throw ValueError.$factory("wrong format " + self)}
Mar 19, 2018
1180
}else{text += car; pos++}
Sep 5, 2014
1181
}
1182
if(text){parts.push(text)}
1183
return parts
1184
}
1185
1186
str.format = function(self) {
1187
var $ = $B.args("format", 1, {self: null}, ["self"],
1188
arguments, {}, "$args", "$kw")
1189
1190
var parts = $B.split_format($.self)
1191
1192
// Apply formatting to the values passed to format()
Mar 19, 2018
1193
var res = "",
1194
fmt
Mar 19, 2018
1196
for(var i = 0; i < parts.length; i++){
1197
// Literal text is added unchanged
Mar 19, 2018
1198
if(typeof parts[i] == "string"){res += parts[i]; continue}
1200
// Format objects
1201
fmt = parts[i]
1202
1203
if(fmt.spec !== undefined){
1204
// "spec" may contain "nested replacement fields"
1205
// In this case, evaluate them using the positional
1206
// or keyword arguments passed to format()
1207
function replace_nested(name, key){
1208
if(/\d+/.exec(key)){
1209
// If key is numeric, search in positional
1210
// arguments
1211
return _b_.tuple.__getitem__($.$args,
1212
parseInt(key))
1213
}else{
1214
// Else try in keyword arguments
1215
return _b_.dict.__getitem__($.$kw, key)
1216
}
1217
}
1218
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1219
replace_nested)
1220
}
Mar 21, 2018
1221
if(fmt.name.charAt(0).search(/\d/) > -1){
1222
// Numerical reference : use positional arguments
1223
var pos = parseInt(fmt.name),
Feb 11, 2018
1224
value = _b_.tuple.__getitem__($.$args, pos)
1225
}else{
1226
// Use keyword arguments
Feb 11, 2018
1227
var value = _b_.dict.__getitem__($.$kw, fmt.name)
1228
}
1229
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1230
for(var j = 0; j < fmt.name_ext.length; j++){
1231
var ext = fmt.name_ext[j]
Mar 19, 2018
1232
if(ext.charAt(0) == "."){
1233
// Attribute
1234
value = _b_.getattr(value, ext.substr(1))
1235
}else{
1236
// Subscription
Mar 19, 2018
1237
var key = ext.substr(1, ext.length - 2)
1238
// An index made of digits is transformed into an integer
Mar 19, 2018
1239
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1240
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1243
1244
// If the conversion flag is set, first call a function to convert
1245
// the value
Mar 19, 2018
1246
if(fmt.conv == "a"){value = _b_.ascii(value)}
1247
else if(fmt.conv == "r"){value = _b_.repr(value)}
1248
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1250
// Call attribute __format__ to perform the actual formatting
1251
if(value.$is_class || value.$factory){
1252
// For classes, don't use the class __format__ method
1253
res += value.__class__.__format__(value, fmt.spec)
Mar 19, 2018
1255
res += _b_.getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1257
}
Sep 5, 2014
1259
}
1260
str
Feb 10, 2018
1261
str.format_map = function(self) {
Mar 19, 2018
1262
throw NotImplementedError.$factory(
1263
"function format_map not implemented yet")
Sep 5, 2014
1264
}
1265
str
Feb 10, 2018
1266
str.index = function(self){
Sep 5, 2014
1267
// Like find(), but raise ValueError when the substring is not found.
str
Feb 10, 2018
1268
var res = str.find.apply(null,arguments)
Mar 19, 2018
1269
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1270
return res
1271
}
1272
str
Feb 10, 2018
1273
str.join = function(){
Mar 19, 2018
1274
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1275
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1277
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1278
res = [],
Sep 5, 2014
1280
while(1){
1281
try{
1282
var obj2 = _b_.next(iterable)
Mar 19, 2018
1283
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1284
"sequence item " + count + ": expected str instance, " +
1285
$B.class_name(obj2) + " found")}
1286
res.push(obj2)
Sep 5, 2014
1287
}catch(err){
1288
if(_b_.isinstance(err, _b_.StopIteration)){
1289
break
1290
}
Sep 5, 2014
1291
else{throw err}
1292
}
1293
}
1294
return res.join($.self)
Sep 5, 2014
1295
}
1296
str
Feb 10, 2018
1297
str.ljust = function(self) {
Mar 19, 2018
1298
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1299
["self", "width", "fillchar"],
1300
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1302
if($.width <= self.length){return self}
1303
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1304
}
1305
str
Feb 10, 2018
1306
str.lstrip = function(self,x){
Mar 19, 2018
1307
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1308
arguments, {chars:_b_.None}, null, null)
1309
if($.chars === _b_.None){return $.self.trimLeft()}
1310
for(var i = 0; i < $.self.length; i++){
1311
if($.chars.indexOf($.self.charAt(i)) === -1){
1312
return $.self.substring(i)
Mar 19, 2018
1315
return ""
Sep 5, 2014
1316
}
1317
1318
// note, maketrans should be a static function.
str
Feb 10, 2018
1319
str.maketrans = function() {
Mar 19, 2018
1320
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1321
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1323
var _t = _b_.dict.$factory()
Mar 19, 2018
1325
if($.y === null && $.z === null){
1326
// If there is only one argument, it must be a dictionary mapping
1327
// Unicode ordinals (integers) or characters (strings of length 1) to
1328
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1329
// keys will then be converted to ordinals.
Mar 19, 2018
1330
if(! _b_.isinstance($.x, _b_.dict)){
1331
throw _b_.TypeError.$factory(
1332
"maketrans only argument must be a dict")
Feb 11, 2018
1334
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1335
for(var i = 0, len = items.length; i < len; i++){
1336
var k = items[i][0],
1337
v = items[i][1]
1338
if(! _b_.isinstance(k, _b_.int)){
1339
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1340
k = _b_.ord(k)
1341
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1342
" is not int or 1-char string")}
1343
}
Mar 19, 2018
1344
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1345
throw _b_.TypeError.$factory("dictionary value " + v +
1346
" is not None, integer or string")
1347
}
1348
_b_.dict.$setitem(_t, k, v)
1349
}
1350
return _t
1351
}else{
1352
// If there are two arguments, they must be strings of equal length,
1353
// and in the resulting dictionary, each character in x will be mapped
1354
// to the character at the same position in y
Mar 19, 2018
1355
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1356
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1357
}else if($.x.length !== $.y.length){
1358
throw _b_.TypeError.$factory(
1359
"maketrans arguments must be strings or same length")
1360
}else{
1361
var toNone = {}
Mar 19, 2018
1362
if($.z !== null){
1363
// If there is a third argument, it must be a string, whose
1364
// characters will be mapped to None in the result
Mar 19, 2018
1365
if(! _b_.isinstance($.z, _b_.str)){
1366
throw _b_.TypeError.$factory(
1367
"maketrans third argument must be a string")
Mar 19, 2018
1369
for(var i = 0, len = $.z.length; i < len; i++){
1370
toNone[_b_.ord($.z.charAt(i))] = true
1371
}
Mar 19, 2018
1373
for(var i = 0, len = $.x.length; i < len; i++){
1374
var key = _b_.ord($.x.charAt(i)),
1375
value = $.y.charAt(i)
1376
_b_.dict.$setitem(_t, key, value)
1377
}
1378
for(var k in toNone){
1379
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1380
}
1381
return _t
1382
}
1383
}
Sep 5, 2014
1384
}
1385
str
Feb 10, 2018
1386
str.partition = function() {
Mar 19, 2018
1387
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1388
arguments, {}, null, null)
Mar 19, 2018
1389
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1390
check_str($.sep)
1391
var i = $.self.indexOf($.sep)
Mar 23, 2018
1392
if(i == -1){return _b_.tuple.$factory([$.self, "", ""])}
Mar 19, 2018
1393
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1394
$.self.substring(i + $.sep.length)])
1395
}
1396
1397
function $re_escape(str){
1398
var specials = "[.*+?|()$^"
1399
for(var i = 0, len = specials.length; i < len; i++){
1400
var re = new RegExp("\\"+specials.charAt(i), "g")
1401
str = str.replace(re, "\\"+specials.charAt(i))
1402
}
1403
return str
Sep 5, 2014
1404
}
1405
str
Feb 10, 2018
1406
str.replace = function(self, old, _new, count) {
1407
// Replaces occurrences of 'old' by '_new'. Count references
1408
// the number of times to replace. In CPython, negative or undefined
1409
// values of count means replace all.
Mar 19, 2018
1410
var $ = $B.args("replace", 4,
1411
{self: null, old: null, $$new: null, count: null},
1412
["self", "old", "$$new", "count"],
1413
arguments, {count: -1}, null, null),
1414
count = $.count,
1415
self = $.self,
1416
old = $.old,
1417
_new = $.$$new
1418
// Validate type of old
1419
check_str(old)
1420
check_str(_new)
1421
// Validate instance type of 'count'
Mar 23, 2018
1422
if(! isinstance(count,[_b_.int, _b_.float])){
1423
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
1424
"' object cannot be interpreted as an integer")
1425
}else if(isinstance(count, _b_.float)){
1426
throw _b_.TypeError.$factory("integer argument expected, got float")
1427
}
1428
if(count == 0){return self}
1429
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1430
if(old == ""){
1431
if(_new == ""){return self}
1432
if(self == ""){return _new}
1433
var elts = self.split("")
1434
if(count > -1 && elts.length >= count){
1435
var rest = elts.slice(count).join("")
1436
return _new + elts.slice(0, count).join(_new) + rest
1437
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1439
var elts = str.split(self, old, count)
Sep 5, 2014
1440
}
Mar 19, 2018
1442
var res = self,
1443
pos = -1
1444
if(old.length == 0){
Mar 19, 2018
1446
for(var i = 0; i < elts.length; i++){
1447
res += elts[i] + _new
Mar 19, 2018
1449
return res + rest
Mar 19, 2018
1452
if(count < 0){count = res.length}
1453
while(count > 0){
1454
pos = res.indexOf(old, pos)
1455
if(pos < 0){break}
1456
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1457
pos = pos + _new.length
1458
count--
Mar 19, 2018
1460
return res
Sep 5, 2014
1461
}
1462
str
Feb 10, 2018
1463
str.rfind = function(self){
1464
// Return the highest index in the string where substring sub is found,
1465
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1466
// start and end are interpreted as in slice notation. Return -1 on failure.
Mar 19, 2018
1467
var $ = $B.args("rfind", 4,
Mar 19, 2018
1468
{self: null, sub: null, start: null, end: null},
1469
["self", "sub", "start", "end"],
1470
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1471
1474
check_str($.sub)
Mar 19, 2018
1476
if($.sub.length == 0){
1477
if($.start > $.self.length){return -1}
1478
else{return $.self.length}
1479
}
1480
var sublen = $.sub.length
Mar 19, 2018
1482
for(var i = $.end - sublen; i >= $.start; i--){
1483
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1486
}
1487
str
Feb 10, 2018
1488
str.rindex = function(){
Sep 5, 2014
1489
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1490
var res = str.rfind.apply(null, arguments)
1491
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1492
return res
1493
}
1494
str
Feb 10, 2018
1495
str.rjust = function(self) {
Mar 19, 2018
1496
var $ = $B.args("rjust",3,
1497
{self: null, width: null, fillchar: null},
1498
["self", "width", "fillchar"],
1499
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1500
Mar 19, 2018
1501
if($.width <= self.length){return self}
Sep 5, 2014
1502
1503
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1504
}
1505
str
Feb 10, 2018
1506
str.rpartition = function(self,sep) {
Mar 19, 2018
1507
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1508
arguments, {}, null, null)
1509
check_str($.sep)
1510
var self = reverse($.self),
1511
sep = reverse($.sep)
Mar 19, 2018
1512
var items = str.partition(self, sep).reverse()
1513
for(var i = 0; i < items.length; i++){
1514
items[i] = items[i].split("").reverse().join("")
1515
}
1516
return items
Sep 5, 2014
1517
}
1518
str
Feb 10, 2018
1519
str.rsplit = function(self) {
Mar 19, 2018
1520
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1521
["self", "sep", "maxsplit"], arguments,
1522
{sep: _b_.None, maxsplit: -1}, null, null),
1523
sep = $.sep
1524
1525
// Use split on the reverse of the string and of separator
1526
var rev_str = reverse($.self),
1527
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1528
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1530
// Reverse the list, then each string inside the list
1531
rev_res.reverse()
Mar 19, 2018
1532
for(var i = 0; i < rev_res.length; i++){
1533
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1536
}
1537
Mar 19, 2018
1538
str.rstrip = function(self, x){
1539
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1540
arguments, {chars: _b_.None}, null, null)
1541
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1542
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1543
if($.chars.indexOf($.self.charAt(j)) == -1){
1544
return $.self.substring(0, j + 1)
Mar 19, 2018
1547
return ""
Sep 5, 2014
1548
}
1549
str
Feb 10, 2018
1550
str.split = function(){
Mar 19, 2018
1551
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1552
["self", "sep", "maxsplit"], arguments,
1553
{sep: _b_.None, maxsplit: -1}, null, null),
1554
sep = $.sep,
1555
maxsplit = $.maxsplit,
1556
self = $.self,
1557
pos = 0
1558
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1559
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1560
if(sep === _b_.None){
Sep 5, 2014
1561
var res = []
Mar 19, 2018
1562
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1563
if(pos === self.length - 1){return [self]}
1564
var name = ""
Sep 5, 2014
1565
while(1){
Mar 19, 2018
1566
if(self.charAt(pos).search(/\s/) == -1){
1567
if(name == ""){name = self.charAt(pos)}
1568
else{name += self.charAt(pos)}
Sep 5, 2014
1569
}else{
Mar 19, 2018
1570
if(name !== ""){
Sep 5, 2014
1571
res.push(name)
Mar 19, 2018
1572
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1573
res.pop()
Mar 19, 2018
1574
res.push(name + self.substr(pos))
Sep 5, 2014
1575
return res
1576
}
Mar 19, 2018
1577
name = ""
Sep 5, 2014
1578
}
1579
}
1580
pos++
Mar 19, 2018
1581
if(pos > self.length - 1){
Sep 5, 2014
1582
if(name){res.push(name)}
1583
break
1584
}
1585
}
1586
return res
1587
}else{
Mar 19, 2018
1588
var res = [],
1589
s = "",
1590
seplen = sep.length
1591
if(maxsplit == 0){return [self]}
1592
while(pos < self.length){
1593
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1596
if(maxsplit > -1 && res.length >= maxsplit){
1597
res.push(self.substr(pos))
1598
return res
1599
}
Mar 19, 2018
1600
s = ""
1601
}else{
1602
s += self.charAt(pos)
1603
pos++
Sep 5, 2014
1604
}
1605
}
Sep 5, 2014
1608
}
1609
}
1610
str
Feb 10, 2018
1611
str.splitlines = function(self){
Mar 19, 2018
1612
var $ = $B.args("splitlines", 2, {self: null, keepends: null},
Mar 19, 2018
1613
["self", "keepends"], arguments, {keepends: false}, null, null)
1614
if(! _b_.isinstance($.keepends, [_b_.bool, _b_.int])){
1615
throw _b_.TypeError.$factory("integer argument expected, got " +
1616
$B.get_class($.keepends).__name)
1617
}
1618
var keepends = _b_.int.$factory($.keepends)
1619
// Remove trailing line breaks
1620
if(keepends){
1621
var res = [],
Mar 19, 2018
1622
start = pos,
1623
pos = 0,
1624
self = $.self
1625
while(pos < self.length){
1626
if(self.substr(pos, 2) == "\r\n"){
1627
res.push(self.substring(start, pos + 2))
1628
start = pos + 2
1629
pos = start
Mar 19, 2018
1630
}else if(self.charAt(pos) == "\r" || self.charAt(pos) == "\n"){
1631
res.push(self.substring(start, pos + 1))
1632
start = pos + 1
1633
pos = start
1634
}else{pos++}
1635
}
1636
var rest = self.substr(start)
1637
if(rest){res.push(rest)}
1638
return res
1639
}else{
Mar 19, 2018
1640
var self = $.self.replace(/[\r\n]$/, "")
1641
return self.split(/\n|\r\n|\r/)
1642
}
1643
}
Sep 5, 2014
1644
str
Feb 10, 2018
1645
str.startswith = function(){
1646
// Return True if string starts with the prefix, otherwise return False.
1647
// prefix can also be a tuple of prefixes to look for. With optional
1648
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1649
// stop comparing string at that position.
Mar 19, 2018
1650
var $ = $B.args("startswith", 4,
1651
{self: null, prefix: null, start: null, end: null},
1652
["self", "prefix", "start", "end"],
1653
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1654
1655
normalize_start_end($)
1656
1657
var prefixes = $.prefix
Mar 19, 2018
1658
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1660
var s = $.self.substring($.start, $.end)
1661
for(var i = 0, len = prefixes.length; i < len; i++){
1662
var prefix = prefixes[i]
Mar 19, 2018
1663
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1664
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1665
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1666
}
1667
return false
1668
Sep 5, 2014
1669
}
1670
str
Feb 10, 2018
1671
str.strip = function(){
Mar 19, 2018
1672
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1673
arguments, {chars: _b_.None}, null, null)
1674
if($.chars === _b_.None){return $.self.trim()}
1675
for(var i = 0; i < $.self.length; i++){
1676
if($.chars.indexOf($.self.charAt(i)) == -1){
1677
break
Mar 19, 2018
1680
for(var j = $.self.length - 1; j >= i; j--){
1681
if($.chars.indexOf($.self.charAt(j)) == -1){
1682
break
Mar 19, 2018
1685
return $.self.substring(i, j + 1)
Sep 5, 2014
1686
}
1687
1688
str.translate = function(self, table){
Mar 19, 2018
1689
var res = [],
1690
getitem = $B.$getattr(table, "__getitem__")
1691
for(var i = 0, len = self.length; i < len; i++){
1692
try{
1693
var repl = getitem(self.charCodeAt(i))
1694
if(repl !== _b_.None){
1695
res.push(repl)
1696
}
1697
}catch(err){
1698
res.push(self.charAt(i))
1699
}
Sep 5, 2014
1700
}
Mar 19, 2018
1701
return res.join("")
Sep 5, 2014
1702
}
1703
Mar 19, 2018
1704
str.zfill = function(self, width){
Mar 19, 2018
1705
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
1706
["self", "width"], arguments, {}, null, null)
1707
if($.width <= self.length){return self}
Mar 19, 2018
1709
case "+":
1710
case "-":
1711
return self.charAt(0) +
1712
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
1714
return "0".repeat(width - self.length) + self
Sep 5, 2014
1716
}
1717
1718
str.$factory = function(arg, encoding, errors){
Mar 19, 2018
1719
if(arg === undefined){console.log("undef"); return "<undefined>"}
1720
switch(typeof arg) {
Mar 19, 2018
1721
case "string":
1722
return arg
1723
case "number":
1724
if(isFinite(arg)){return arg.toString()}
1727
if(arg.$is_class || arg.$factory){
1728
// arg is a class
1729
// In this case, str() doesn't use the attribute __str__ of the
1730
// class or its subclasses, but the attribute __str__ of the
1731
// class metaclass (usually "type") or its subclasses (usually
1732
// "object")
1733
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
1734
var func = $B.$getattr(arg.__class__, "__str__")
1736
}
1737
if(arg.__class__ && arg.__class__ === _b_.bytes &&
1738
encoding !== undefined){
1739
// str(bytes, encoding, errors) is equal to
1740
// bytes.decode(encoding, errors)
1741
return _b_.bytes.decode(arg, encoding || "utf-8",
1742
errors || "strict")
1743
}
1744
var f = $B.$getattr(arg, "__str__", null)
1745
if(f === null ||
1746
// if not better than object.__str__, try __repr__
1747
(arg.__class__ && arg.__class__ !== _b_.object &&
1748
f.$infos && f.$infos.__func__ === _b_.object.__str__)){
1749
var f = $B.$getattr(arg, "__repr__")
1750
}
Sep 5, 2014
1751
}
1752
catch(err){
1753
console.log("no __str__ for", arg)
Mar 19, 2018
1754
console.log("err ", err)
1755
if($B.debug > 1){console.log(err)}
1756
console.log("Warning - no method __str__ or __repr__, " +
1757
"default to toString", arg)
1758
return arg.toString()
Sep 5, 2014
1759
}
Sep 5, 2014
1761
}
str
Feb 10, 2018
1762
1763
str.__new__ = function(cls){
Mar 19, 2018
1764
if(cls === undefined){
1765
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
1766
}
Mar 19, 2018
1767
return {__class__: cls}
Sep 5, 2014
1768
}
1769
str
Feb 10, 2018
1770
$B.set_func_names(str, "builtins")
Sep 5, 2014
1772
// dictionary and factory for subclasses of string
str
Feb 10, 2018
1773
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
1774
__class__: _b_.type,
str
Feb 10, 2018
1775
__mro__: [object],
1776
$infos: {
1777
__module__: "builtins",
1778
__name__: "str"
1779
},
str
Feb 10, 2018
1780
$is_class: true
Sep 5, 2014
1781
}
1782
str
Feb 10, 2018
1783
// the methods in subclass apply the methods in str to the
Sep 5, 2014
1784
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
1785
for(var $attr in str){
Mar 19, 2018
1786
if(typeof str[$attr] == "function"){
Mar 19, 2018
1787
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
1788
return function(){
Mar 19, 2018
1789
var args = [],
1790
pos = 0
1791
if(arguments.length > 0){
1792
var args = [arguments[0].valueOf()],
1793
pos = 1
1794
for(var i = 1, len = arguments.length; i < len; i++){
1795
args[pos++] = arguments[i]
Sep 5, 2014
1796
}
1797
}
Mar 19, 2018
1798
return str[attr].apply(null, args)
Sep 5, 2014
1799
}
1800
})($attr)
1801
}
1802
}
str
Feb 10, 2018
1803
StringSubclass.__new__ = function(cls){
Sep 5, 2014
1806
str
Feb 10, 2018
1807
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
1809
_b_.str = str
1810
1811
// Function to parse the 2nd argument of format()
1812
$B.parse_format_spec = function(spec){
Mar 19, 2018
1813
if(spec == ""){this.empty = true}
1814
else{
Mar 19, 2018
1815
var pos = 0,
1816
aligns = "<>=^",
1817
digits = "0123456789",
1818
types = "bcdeEfFgGnosxX%",
1819
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
1820
if(align_pos != -1){
1821
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
1822
// If the second char is also an alignment specifier, the
1823
// first char is the fill value
1824
this.fill = spec.charAt(0)
1825
this.align = spec.charAt(1)
1826
pos = 2
1827
}else{
1828
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
1829
this.align = aligns[align_pos]
1830
this.fill = " "
1831
pos++
1832
}
1833
}else{
1834
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
1835
if(spec.charAt(1) && align_pos != -1){
1836
// The second character defines alignment : fill is the first one
Mar 19, 2018
1837
this.align = aligns[align_pos]
1838
this.fill = spec.charAt(0)
1839
pos = 2
1840
}
1841
}
1842
var car = spec.charAt(pos)
Mar 19, 2018
1843
if(car == "+" || car == "-" || car == " "){
1844
this.sign = car
1845
pos++
1846
car = spec.charAt(pos)
Mar 19, 2018
1848
if(car == "#"){this.alternate = true; pos++; car = spec.charAt(pos)}
1849
if(car == "0"){
Mar 19, 2018
1850
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
1851
this.fill = "0"
1852
this.align = "="
1853
pos++
1854
car = spec.charAt(pos)
1855
}
Mar 19, 2018
1856
while(car && digits.indexOf(car) > -1){
1857
if(this.width === undefined){this.width = car}
1858
else{this.width += car}
1859
pos++
1860
car = spec.charAt(pos)
Mar 19, 2018
1862
if(this.width !== undefined){this.width = parseInt(this.width)}
1863
if(this.width === undefined && car == "{"){
1864
// Width is determined by a parameter
1865
var end_param_pos = spec.substr(pos).search("}")
1866
this.width = spec.substring(pos, end_param_pos)
1867
console.log("width", "[" + this.width + "]")
1868
pos += end_param_pos + 1
1869
}
Mar 19, 2018
1870
if(car == ","){this.comma = true; pos++; car = spec.charAt(pos)}
1871
if(car == "."){
1872
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
1873
throw _b_.ValueError.$factory(
1874
"Missing precision in format spec")
Mar 19, 2018
1876
this.precision = spec.charAt(pos + 1)
1877
pos += 2
1878
car = spec.charAt(pos)
1879
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
1880
this.precision += car
Mar 19, 2018
1881
pos++
1882
car = spec.charAt(pos)
1883
}
1884
this.precision = parseInt(this.precision)
1885
}
Mar 19, 2018
1886
if(car && types.indexOf(car) > -1){
1887
this.type = car
1888
pos++
1889
car = spec.charAt(pos)
1890
}
1891
if(pos !== spec.length){
1892
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
1895
this.toString = function(){
Mar 19, 2018
1896
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
1897
(this.align || "") +
1898
(this.sign || "") +
1899
(this.alternate ? "#" : "") +
1900
(this.sign_aware ? "0" : "") +
1901
(this.width || "") +
1902
(this.comma ? "," : "") +
1903
(this.precision ? "." + this.precision : "") +
1904
(this.type || "")
1905
}
1906
}
1907
1908
$B.format_width = function(s, fmt){
Mar 19, 2018
1909
if(fmt.width && s.length < fmt.width){
1910
var fill = fmt.fill || " ",
1911
align = fmt.align || "<",
1912
missing = fmt.width - s.length
1913
switch(align){
Mar 19, 2018
1914
case "<":
1915
return s + fill.repeat(missing)
1916
case ">":
1917
return fill.repeat(missing) + s
1918
case "=":
1919
if("+-".indexOf(s.charAt(0)) > -1){
1920
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
1921
}else{
Mar 19, 2018
1922
return fill.repeat(missing) + s
Mar 19, 2018
1924
case "^":
1925
var left = parseInt(missing / 2)
1926
return fill.repeat(left) + s + fill.repeat(missing - left)
1927
}
1928
}
1929
return s
1930
}
1931
1932
function fstring_expression(){
Mar 19, 2018
1933
this.type = "expression"
1934
this.expression = ""
1935
this.conversion = null
1936
this.fmt = null
1937
}
1938
1939
$B.parse_fstring = function(string){
1940
// Parse a f-string
1941
var elts = [],
1942
pos = 0,
Mar 19, 2018
1943
current = "",
1944
ctype = null,
1945
nb_braces = 0,
1946
car
1947
Mar 19, 2018
1948
while(pos < string.length){
1949
if(ctype === null){
1950
car = string.charAt(pos)
Mar 19, 2018
1951
if(car == "{"){
Mar 21, 2018
1952
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
1953
ctype = "string"
1954
current = "{"
1955
pos += 2
1956
}else{
Mar 19, 2018
1957
ctype = "expression"
1958
nb_braces = 1
1959
pos++
1960
}
Mar 19, 2018
1961
}else if(car == "}"){
Mar 21, 2018
1962
if(string.charAt(pos + 1) == car){
Mar 19, 2018
1963
ctype = "string"
1964
current = "}"
1965
pos += 2
1966
}else{
1967
throw Error(" f-string: single '}' is not allowed")
1968
}
1969
}else{
Mar 19, 2018
1970
ctype = "string"
1971
current = car
1972
pos++
Mar 19, 2018
1974
}else if(ctype == "string"){
1975
// end of string is the first single { or end of string
Mar 19, 2018
1976
var i = pos
1977
while(i < string.length){
1978
car = string.charAt(i)
Mar 19, 2018
1979
if(car == "{"){
Mar 21, 2018
1980
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
1981
current += "{"
1982
i += 2
1983
}else{
1984
elts.push(current)
Mar 19, 2018
1985
ctype = "expression"
1986
pos = i + 1
1987
break
1988
}
Mar 19, 2018
1989
}else if(car == "}"){
1990
if(string.charAt(i + 1) == car){
1991
current += car
1992
i += 2
1993
}else{
1994
throw Error(" f-string: single '}' is not allowed")
1995
}
1996
}else{
1997
current += car
1998
i++
1999
}
2000
}
Mar 19, 2018
2001
pos = i + 1
2002
}else{
2003
// End of expression is the } matching the opening {
2004
// There may be nested braces
2005
var i = pos,
2006
nb_braces = 1,
2007
nb_paren = 0,
2008
current = new fstring_expression()
Mar 19, 2018
2009
while(i < string.length){
2010
car = string.charAt(i)
Mar 19, 2018
2011
if(car == "{" && nb_paren == 0){
2012
nb_braces++
2013
current.expression += car
2014
i++
Mar 19, 2018
2015
}else if(car == "}" && nb_paren == 0){
2016
nb_braces -= 1
Mar 19, 2018
2017
if(nb_braces == 0){
2018
// end of expression
2019
elts.push(current)
2020
ctype = null
Mar 19, 2018
2021
current = ""
2022
pos = i + 1
2025
current.expression += car
2026
i++
Mar 19, 2018
2027
}else if(car == "\\"){
2028
// backslash is not allowed in expressions
2029
throw Error("f-string expression part cannot include a" +
2030
" backslash")
Mar 19, 2018
2031
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
Mar 21, 2018
2032
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2033
if(current.expression.length == 0){
2034
throw Error("f-string: empty expression not allowed")
2035
}
Mar 19, 2018
2036
if("ars".indexOf(string.charAt(i + 1)) == -1){
2037
throw Error("f-string: invalid conversion character:" +
2038
" expected 's', 'r', or 'a'")
2039
}else{
Mar 19, 2018
2040
current.conversion = string.charAt(i + 1)
2041
i += 2
2042
}
Mar 19, 2018
2043
}else if(car == "("){
2044
nb_paren++
2045
current.expression += car
2046
i++
Mar 19, 2018
2047
}else if(car == ")"){
2048
nb_paren--
2049
current.expression += car
2050
i++
Mar 19, 2018
2051
}else if(car == '"'){
2052
// triple string ?
Mar 19, 2018
2053
if(string.substr(i, 3) == '"""'){
2054
var end = string.indexOf('"""', i + 3)
2055
if(end == -1){
2056
throw Error("f-string: unterminated string")
2057
}else{
2058
var trs = string.substring(i, end + 3)
2059
trs = trs.replace("\n", "\\n\\")
2060
current.expression += trs
Mar 19, 2018
2061
i = end + 3
2062
}
2063
}else{
Mar 19, 2018
2064
var end = string.indexOf('"', i + 1)
2065
if(end == -1){
2066
throw Error("f-string: unterminated string")
2067
}else{
2068
current.expression += string.substring(i, end + 1)
2069
i = end + 1
2070
}
2071
}
Mar 19, 2018
2072
}else if(nb_paren == 0 && car == ":"){
2073
current.fmt = true
2074
current.expression += car
2075
i++
2076
}else{
2077
current.expression += car
2078
i++
2079
}
2080
}
Mar 21, 2018
2081
if(nb_braces > 0){
2082
throw Error("f-string: expected '}'")
2083
}
2084
}
2085
}
Mar 19, 2018
2086
if(current.length > 0){elts.push(current)}
2087
return elts
2088
}
2089
Sep 5, 2014
2090
})(__BRYTHON__)