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