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