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