Skip to content
Permalink
Newer
Older
100644 2033 lines (1865 sloc) 64.7 KB
Sep 5, 2014
1
;(function($B){
2
3
eval($B.InjectBuiltins())
Sep 5, 2014
4
5
if (!String.prototype.trim) {
Mar 19, 2018
6
// Polyfill for older browsers
7
// The code does not use a regex to make it a bit faster.
8
// Implementation taken from a comment by Timo on the blog:
9
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
10
String.prototype.trim = function () {
11
var c
12
for(var i = 0; i < this.length; i++){
13
c = this.charCodeAt(i)
14
if([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
15
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
16
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
17
continue
18
}else{break}
19
}
20
for(var j = this.length - 1; j >= i; j--){
21
c = this.charCodeAt(j)
22
if ([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
23
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
24
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
25
continue
26
}else{break}
27
}
28
return this.substring(i, j + 1);
29
}
30
}
31
if (!String.prototype.trimLeft) {
32
// Convenience method for browsers which do not have a native trimLeft
33
// (which is a nonstandard extension in Firefox and Chrome)
Mar 19, 2018
34
String.prototype.trimLeft = function () {
35
var c
36
for(var i = 0; i < this.length; i++){
37
c = this.charCodeAt(i)
38
if ([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
39
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
40
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
41
continue
42
}else{break}
43
}
44
return this.substring(i)
45
}
46
}
47
if (!String.prototype.trimRight) {
Mar 19, 2018
48
String.prototype.trimRight = function () {
49
// Convenience method for browsers which do not have a native trimRight
50
// (which is a nonstandard extension in Firefox and Chrome)
51
var c
52
for(var j = this.length - 1; j >= 0; j--){
53
c = this.charCodeAt(j)
54
if([32, 10, 13, 9, 12, 11, 160, 5760, 6158, 8192, 8193, 8194,
55
8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232,
56
8233, 8239, 8287, 12288, 65279].indexOf(c) > -1){
57
continue
58
}else{break}
59
}
60
return this.substring(0, j + 1)
Sep 5, 2014
65
str
Feb 10, 2018
66
var str = {
Mar 19, 2018
67
__class__: _b_.type,
68
__dir__: object.__dir__,
69
__name__: "str",
str
Feb 10, 2018
70
$is_class: true,
Mar 19, 2018
71
$native: true
Sep 5, 2014
72
}
73
Mar 19, 2018
75
if($.start === null || $.start === _b_.None){$.start = 0}
76
else if($.start < 0){
77
$.start += $.self.length
78
$.start = Math.max(0, $.start)
79
}
80
if($.end === null || $.end === _b_.None){$.end = $.self.length}
81
else if($.end < 0){
82
$.end += $.self.length
83
$.end = Math.max(0, $.end)
84
}
Mar 19, 2018
86
if(! isinstance($.start, _b_.int) || ! isinstance($.end, _b_.int)){
87
throw _b_.TypeError.$factory("slice indices must be integers " +
88
"or None or have an __index__ method")
89
}
93
function reverse(s){
94
// Reverse a string
Mar 19, 2018
95
return s.split("").reverse().join("")
96
}
97
98
function check_str(obj){
Mar 19, 2018
99
if(! _b_.isinstance(obj, str)){
Mar 21, 2018
100
throw _b_.TypeError.$factory("can't convert '" +
101
$B.get_class(obj).__name__ + "' object to str implicitely")
Mar 19, 2018
102
}
str
Feb 10, 2018
105
str.__add__ = function(self,other){
Mar 19, 2018
106
if(!(typeof other === "string")){
107
try{return getattr(other, "__radd__")(self)}
108
catch(err){
109
throw _b_.TypeError.$factory("Can't convert " +
110
$B.get_class(other).__name__ + " to str implicitely")}
Sep 5, 2014
111
}
Mar 19, 2018
112
return self + other
Sep 5, 2014
113
}
114
Mar 19, 2018
115
str.__contains__ = function(self, item){
116
if(!(typeof item == "string")){
117
throw _b_.TypeError.$factory("'in <string>' requires " +
118
"string as left operand, not " + item.__class__)
119
}
Sep 5, 2014
120
var nbcar = item.length
Mar 19, 2018
121
if(nbcar == 0) {return true} // a string contains the empty string
122
if(self.length == 0){return nbcar == 0}
123
for(var i = 0, len = self.length; i < len; i++){
124
if(self.substr(i, nbcar) == item){return true}
Sep 5, 2014
125
}
126
return false
127
}
128
str
Feb 10, 2018
129
str.__delitem__ = function(){
130
throw _b_.TypeError.$factory("'str' object doesn't support item deletion")
Sep 5, 2014
131
}
132
Mar 19, 2018
133
// __dir__must be assigned explicitely because attribute resolution for
134
// builtin classes doesn't use __mro__
str
Feb 10, 2018
135
str.__dir__ = object.__dir__
str
Feb 10, 2018
137
str.__eq__ = function(self,other){
Mar 19, 2018
138
if(other === undefined){ // compare object "self" to class "str"
139
return self === str
Sep 5, 2014
140
}
141
if (_b_.isinstance(other, _b_.str)) {
142
return other.valueOf() == self.valueOf()
143
}
Mar 19, 2018
144
return other === self.valueOf()
Sep 5, 2014
145
}
146
147
function preformat(self, fmt){
str
Feb 10, 2018
148
if(fmt.empty){return _b_.str.$factory(self)}
Mar 19, 2018
149
if(fmt.type && fmt.type != "s"){
150
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
151
"' for object of type 'str'")
153
return self
154
}
155
str
Feb 10, 2018
156
str.__format__ = function(self, format_spec) {
157
var fmt = new $B.parse_format_spec(format_spec)
Mar 19, 2018
158
if(fmt.sign !== undefined){
159
throw _b_.ValueError.$factory(
160
"Sign not allowed in string format specifier")
162
// For strings, alignment default to left
Mar 19, 2018
163
fmt.align = fmt.align || "<"
164
return $B.format_width(preformat(self, fmt), fmt)
Sep 5, 2014
165
}
166
str
Feb 10, 2018
167
str.__getitem__ = function(self,arg){
Mar 19, 2018
168
if(isinstance(arg, _b_.int)){
Sep 5, 2014
169
var pos = arg
Mar 19, 2018
170
if(arg < 0) {pos += self.length}
171
if(pos >= 0 && pos < self.length){return self.charAt(pos)}
172
throw _b_.IndexError.$factory("string index out of range")
173
}
174
if(isinstance(arg, slice)) {
175
var s = _b_.slice.$conv_for_seq(arg, self.length),
176
start = s.start,
177
stop = s.stop,
178
step = s.step
179
var res = "",
Mar 19, 2018
180
i = null
Mar 19, 2018
181
if(step > 0){
182
if(stop <= start){return ""}
183
for(var i = start; i < stop; i += step){res += self.charAt(i)}
Sep 5, 2014
184
} else {
Mar 19, 2018
185
if(stop >= start){return ''}
186
for(var i = start; i > stop; i += step){res += self.charAt(i)}
Sep 5, 2014
188
return res
189
}
Mar 19, 2018
190
if(isinstance(arg, bool)){return self.__getitem__(_b_.int.$factory(arg))}
191
throw _b_.TypeError.$factory("string indices must be integers")
Sep 5, 2014
192
}
193
str
Feb 10, 2018
194
str.__hash__ = function(self) {
195
if (self === undefined) {
str
Feb 10, 2018
196
return str.__hashvalue__ || $B.$py_next_hash-- // for hash of string type (not instance of string)
Sep 5, 2014
199
//http://stackoverflow.com/questions/2909106/python-whats-a-correct-and-good-way-to-implement-hash
200
// this implementation for strings maybe good enough for us..
201
Mar 19, 2018
202
var hash = 1
203
for(var i = 0, len = self.length; i < len; i++){
Mar 19, 2018
204
hash = (101 * hash + self.charCodeAt(i)) & 0xFFFFFFFF
Sep 5, 2014
205
}
206
207
return hash
208
}
209
Mar 19, 2018
210
str.__init__ = function(self, arg){
Sep 5, 2014
211
self.valueOf = function(){return arg}
212
self.toString = function(){return arg}
Sep 5, 2014
214
}
215
Mar 19, 2018
216
var $str_iterator = $B.$iterator_class("str_iterator")
str
Feb 10, 2018
217
str.__iter__ = function(self){
Mar 19, 2018
218
var items = self.split("") // list of all characters in string
219
return $B.$iterator(items, $str_iterator)
Sep 5, 2014
220
}
221
str
Feb 10, 2018
222
str.__len__ = function(self){return self.length}
Sep 5, 2014
223
224
// Start of section for legacy formatting (with %)
225
Mar 19, 2018
226
var kwarg_key = new RegExp("([^\\)]*)\\)")
227
228
var NotANumber = function() {
Mar 19, 2018
229
this.name = "NotANumber"
230
}
231
Mar 19, 2018
232
var number_check = function(s){
233
if(! isinstance(s, [_b_.int, _b_.float])){
234
throw new NotANumber()
235
}
236
}
237
Mar 19, 2018
238
var get_char_array = function(size, char){
239
if (size <= 0){return ""}
240
return new Array(size + 1).join(char)
241
}
242
Mar 19, 2018
243
var format_padding = function(s, flags, minus_one){
244
var padding = flags.padding
Mar 19, 2018
245
if (! padding) { // undefined
246
return s
247
}
248
s = s.toString()
249
padding = parseInt(padding, 10)
250
if (minus_one) { // numeric formatting where sign goes in front of padding
251
padding -= 1
252
}
Mar 19, 2018
253
if(! flags.left){
254
return get_char_array(padding - s.length, flags.pad_char) + s
Mar 19, 2018
255
}else{
256
// left adjusted
257
return s + get_char_array(padding - s.length, flags.pad_char)
258
}
259
}
260
Mar 19, 2018
261
var format_int_precision = function(val, flags){
262
var precision = flags.precision
Mar 19, 2018
263
if(!precision){
264
return val.toString()
265
}
266
precision = parseInt(precision, 10)
Mar 19, 2018
268
if(val.__class__ === $B.long_int){
269
s = $B.long_int.to_base(val, 10)
270
}else{
271
s = val.toString()
Mar 19, 2018
273
if(s[0] === "-"){
274
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
Mar 19, 2018
276
return get_char_array(precision - s.length, "0") + s
277
}
278
Mar 19, 2018
279
var format_float_precision = function(val, upper, flags, modifier){
280
var precision = flags.precision
281
// val is a float
Mar 19, 2018
282
if(isFinite(val)){
283
return modifier(val, precision, flags, upper)
Mar 19, 2018
285
if(val === Infinity){
286
val = "inf"
287
}else if(val === -Infinity){
288
val = "-inf"
289
}else{
290
val = "nan"
Mar 19, 2018
292
if(upper){
293
return val.toUpperCase()
294
}
295
return val
297
}
298
Mar 19, 2018
299
var format_sign = function(val, flags){
300
if(flags.sign){
301
if(val >= 0){
302
return "+"
Sep 5, 2014
303
}
Mar 19, 2018
304
}else if (flags.space){
305
if(val >= 0){
306
return " "
307
}
308
}
309
return ""
310
}
Sep 5, 2014
311
312
var str_format = function(val, flags) {
313
// string format supports left and right padding
314
flags.pad_char = " " // even if 0 padding is defined, don't use it
str
Feb 10, 2018
315
return format_padding(str.$factory(val), flags)
Sep 5, 2014
317
318
var num_format = function(val, flags) {
319
number_check(val)
Mar 19, 2018
320
if(val.__class__ === $B.long_int){
321
val = $B.long_int.to_base(val, 10)
322
}else{
323
val = parseInt(val)
326
var s = format_int_precision(val, flags)
Mar 19, 2018
327
if(flags.pad_char === "0"){
328
if(val < 0){
329
s = s.substring(1)
Mar 19, 2018
330
return "-" + format_padding(s, flags, true)
331
}
332
var sign = format_sign(val, flags)
Mar 19, 2018
333
if(sign !== ""){
334
return sign + format_padding(s, flags, true)
335
}
336
}
338
return format_padding(format_sign(val, flags) + s, flags)
339
}
Sep 5, 2014
340
341
var repr_format = function(val, flags) {
342
flags.pad_char = " " // even if 0 padding is defined, don't use it
343
return format_padding(repr(val), flags)
344
}
Sep 5, 2014
345
346
var ascii_format = function(val, flags) {
347
flags.pad_char = " " // even if 0 padding is defined, don't use it
348
return format_padding(ascii(val), flags)
349
}
Sep 5, 2014
350
351
// converts val to float and sets precision if missing
Mar 19, 2018
352
var _float_helper = function(val, flags){
353
number_check(val)
Mar 19, 2018
354
if(! flags.precision){
355
if(! flags.decimal_point){
356
flags.precision = 6
Mar 19, 2018
357
}else{
358
flags.precision = 0
359
}
Mar 19, 2018
360
}else{
361
flags.precision = parseInt(flags.precision, 10)
362
validate_precision(flags.precision)
363
}
364
return parseFloat(val)
365
}
Sep 5, 2014
366
367
// used to capture and remove trailing zeroes
Mar 19, 2018
368
var trailing_zeros = /(.*?)(0+)([eE].*)/,
369
leading_zeros = /\.(0*)/,
370
trailing_dot = /\.$/
Sep 5, 2014
371
372
var validate_precision = function(precision) {
373
// force precision to limits of javascript
Mar 19, 2018
374
if(precision > 20){precision = 20}
375
}
376
377
// gG
Mar 19, 2018
378
var floating_point_format = function(val, upper, flags){
379
val = _float_helper(val, flags),
380
v = val.toString(),
381
v_len = v.length,
382
dot_idx = v.indexOf('.')
383
if(dot_idx < 0){dot_idx = v_len}
384
if(val < 1 && val > -1){
385
var zeros = leading_zeros.exec(v),
386
numzeros
387
if(zeros){
388
numzeros = zeros[1].length
Mar 19, 2018
389
}else{
390
numzeros = 0
391
}
Mar 19, 2018
392
if(numzeros >= 4){
393
val = format_sign(val, flags) + format_float_precision(val, upper,
394
flags, _floating_g_exp_helper)
395
if(!flags.alternate){
396
var trl = trailing_zeros.exec(val)
Mar 19, 2018
397
if(trl){
398
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
400
}else{
401
if(flags.precision <= 1){
402
val = val[0] + "." + val.substring(1)
404
}
405
return format_padding(val, flags)
406
}
407
flags.precision = (flags.precision || 0) + numzeros
Mar 19, 2018
408
return format_padding(format_sign(val, flags) +
409
format_float_precision(val, upper, flags,
410
function(val, precision) {
411
return val.toFixed(min(precision, v_len - dot_idx) +
412
numzeros)
413
}),
414
flags
415
)
416
}
417
418
if(dot_idx > flags.precision){
419
val = format_sign(val, flags) + format_float_precision(val, upper,
420
flags, _floating_g_exp_helper)
421
if(! flags.alternate){
422
var trl = trailing_zeros.exec(val)
Mar 19, 2018
423
if(trl){
424
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
426
}else{
427
if(flags.precision <= 1){
428
val = val[0] + "." + val.substring(1)
429
}
430
}
431
return format_padding(val, flags)
432
}
Mar 19, 2018
433
return format_padding(format_sign(val, flags) +
434
format_float_precision(val, upper, flags,
435
function(val, precision) {
436
if(!flags.decimal_point){
437
precision = min(v_len - 1, 6)
438
}else if (precision > v_len){
439
if(! flags.alternate){
440
precision = v_len
441
}
Sep 5, 2014
442
}
Mar 19, 2018
443
if(precision < dot_idx){
444
precision = dot_idx
445
}
446
return val.toFixed(precision - dot_idx)
447
}),
448
flags
449
)
Sep 5, 2014
451
Mar 19, 2018
452
var _floating_g_exp_helper = function(val, precision, flags, upper){
453
if(precision){--precision}
454
val = val.toExponential(precision)
455
// pad exponent to two digits
Mar 19, 2018
456
var e_idx = val.lastIndexOf("e")
457
if(e_idx > val.length - 4){
458
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
460
if(upper){return val.toUpperCase()}
461
return val
462
}
463
464
// fF
465
var floating_point_decimal_format = function(val, upper, flags) {
466
val = _float_helper(val, flags)
Mar 19, 2018
467
return format_padding(format_sign(val, flags) +
468
format_float_precision(val, upper, flags,
469
function(val, precision, flags) {
470
val = val.toFixed(precision)
471
if(precision === 0 && flags.alternate){
472
val += '.'
473
}
474
return val
475
}),
476
flags
477
)
478
}
479
480
var _floating_exp_helper = function(val, precision, flags, upper) {
481
val = val.toExponential(precision)
482
// pad exponent to two digits
Mar 19, 2018
483
var e_idx = val.lastIndexOf("e")
484
if (e_idx > val.length - 4) {
Mar 19, 2018
485
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
487
if(upper){return val.toUpperCase()}
488
return val
489
}
490
491
// eE
Mar 19, 2018
492
var floating_point_exponential_format = function(val, upper, flags){
493
val = _float_helper(val, flags)
Mar 19, 2018
495
return format_padding(format_sign(val, flags) +
496
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
497
}
498
Mar 19, 2018
499
var signed_hex_format = function(val, upper, flags){
501
number_check(val)
Mar 19, 2018
503
if (val.__class__ === $B.long_int){
504
ret = $B.long_int.to_base(val, 16)
505
}else{
506
ret = parseInt(val)
507
ret = ret.toString(16)
508
}
509
ret = format_int_precision(ret, flags)
Mar 19, 2018
510
if(upper){ret = ret.toUpperCase()}
511
if (flags.pad_char === "0") {
512
if(val < 0){
513
ret = ret.substring(1)
Mar 19, 2018
514
ret = "-" + format_padding(ret, flags, true)
515
}
516
var sign = format_sign(val, flags)
Mar 19, 2018
517
if(sign !== ""){
518
ret = sign + format_padding(ret, flags, true)
Sep 5, 2014
519
}
Mar 19, 2018
522
if(flags.alternate){
523
if(ret.charAt(0) === "-"){
524
if(upper){ret = "-0X" + ret.slice(1)}
525
else{ret = "-0x" + ret.slice(1)}
526
}else{
527
if(upper){ret = "0X" + ret}
528
else{ret = "0x" + ret}
529
}
530
}
531
return format_padding(format_sign(val, flags) + ret, flags)
532
}
Sep 5, 2014
533
534
var octal_format = function(val, flags) {
535
number_check(val)
Mar 19, 2018
538
if(val.__class__ === $B.long_int){
539
ret = $B.long_int.to_base(8)
540
}else{
541
ret = parseInt(val)
542
ret = ret.toString(8)
545
ret = format_int_precision(ret, flags)
Mar 19, 2018
547
if(flags.pad_char === "0"){
548
if(val < 0){
549
ret = ret.substring(1)
Mar 19, 2018
550
ret = "-" + format_padding(ret, flags, true)
551
}
552
var sign = format_sign(val, flags)
Mar 19, 2018
553
if(sign !== ""){
554
ret = sign + format_padding(ret, flags, true)
555
}
Sep 5, 2014
556
}
Mar 19, 2018
558
if(flags.alternate){
559
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
560
else{ret = "0o" + ret}
Sep 5, 2014
561
}
562
return format_padding(ret, flags)
563
}
564
Mar 19, 2018
565
var single_char_format = function(val, flags){
566
if(isinstance(val, str) && val.length == 1) return val
567
try{
568
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
Mar 19, 2018
569
}catch (err){
570
throw _b_.TypeError.$factory("%c requires int or char")
571
}
572
return format_padding(chr(val), flags)
573
}
574
Mar 19, 2018
575
var num_flag = function(c, flags){
576
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
577
flags.pad_char = "0"
578
return
579
}
Mar 19, 2018
580
if(!flags.decimal_point){
581
flags.padding = (flags.padding || "") + c
Mar 19, 2018
582
}else{
583
flags.precision = (flags.precision || "") + c
584
}
585
}
586
587
var decimal_point_flag = function(val, flags) {
588
if (flags.decimal_point) {
589
// can only have one decimal point
590
throw new UnsupportedChar()
591
}
592
flags.decimal_point = true
593
}
594
Mar 19, 2018
595
var neg_flag = function(val, flags){
596
flags.pad_char = " " // overrides '0' flag
597
flags.left = true
598
}
599
Mar 19, 2018
600
var space_flag = function(val, flags){
601
flags.space = true
602
}
603
Mar 19, 2018
604
var sign_flag = function(val, flags){
605
flags.sign = true
606
}
607
Mar 19, 2018
608
var alternate_flag = function(val, flags){
609
flags.alternate = true
610
}
611
612
var char_mapping = {
Mar 19, 2018
613
"s": str_format,
614
"d": num_format,
615
"i": num_format,
616
"u": num_format,
617
"o": octal_format,
618
"r": repr_format,
619
"a": ascii_format,
620
"g": function(val, flags){
621
return floating_point_format(val, false, flags)
622
},
623
"G": function(val, flags){return floating_point_format(val, true, flags)},
624
"f": function(val, flags){
625
return floating_point_decimal_format(val, false, flags)
626
},
627
"F": function(val, flags){
628
return floating_point_decimal_format(val, true, flags)
629
},
630
"e": function(val, flags){
631
return floating_point_exponential_format(val, false, flags)
632
},
633
"E": function(val, flags){
634
return floating_point_exponential_format(val, true, flags)
635
},
636
"x": function(val, flags){return signed_hex_format(val, false, flags)},
637
"X": function(val, flags){return signed_hex_format(val, true, flags)},
638
"c": single_char_format,
639
"0": function(val, flags){return num_flag("0", flags)},
640
"1": function(val, flags){return num_flag("1", flags)},
641
"2": function(val, flags){return num_flag("2", flags)},
642
"3": function(val, flags){return num_flag("3", flags)},
643
"4": function(val, flags){return num_flag("4", flags)},
644
"5": function(val, flags){return num_flag("5", flags)},
645
"6": function(val, flags){return num_flag("6", flags)},
646
"7": function(val, flags){return num_flag("7", flags)},
647
"8": function(val, flags){return num_flag("8", flags)},
648
"9": function(val, flags){return num_flag("9", flags)},
649
"-": neg_flag,
650
" ": space_flag,
651
"+": sign_flag,
652
".": decimal_point_flag,
653
"#": alternate_flag
654
}
655
656
// exception thrown when an unsupported char is encountered in legacy format
Mar 19, 2018
657
var UnsupportedChar = function(){
658
this.name = "UnsupportedChar"
659
}
660
str
Feb 10, 2018
661
str.__mod__ = function(self, args) {
663
var length = self.length,
Mar 19, 2018
664
pos = 0 | 0,
665
argpos = null,
666
getitem
Mar 19, 2018
667
if(_b_.isinstance(args, _b_.tuple)){
668
argpos = 0 | 0
Mar 19, 2018
670
getitem = _b_.getattr(args, "__getitem__", _b_.None)
671
}
672
var ret = ''
673
var $get_kwarg_string = function(s) {
674
// returns [self, newpos]
675
++pos
676
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
677
if(! rslt){
678
throw _b_.ValueError.$factory("incomplete format key")
679
}
680
var key = rslt[1]
681
newpos += rslt[0].length
682
try {
683
var self = getitem(key)
Mar 19, 2018
684
}catch(err){
685
if(err.name === "KeyError"){
686
throw err
687
}
688
throw _b_.TypeError.$factory("format requires a mapping")
690
return get_string_value(s, self)
691
}
692
693
var $get_arg_string = function(s) {
694
// returns [self, newpos]
695
var self
697
// non-tuple args
Mar 19, 2018
698
if(argpos === null){
699
// args is the value
Mar 19, 2018
701
}else{
702
self = args[argpos++]
Mar 19, 2018
703
if(self === undefined){
704
throw _b_.TypeError.$factory(
705
"not enough arguments for format string")
Sep 5, 2014
706
}
707
}
708
return get_string_value(s, self)
710
var get_string_value = function(s, self) {
711
// todo: get flags, type
712
// todo: string value based on flags, type, value
Mar 19, 2018
713
var flags = {"pad_char": " "}
714
do{
715
var func = char_mapping[s[newpos]]
716
try {
Mar 19, 2018
717
if(func === undefined){
718
throw new UnsupportedChar()
Mar 19, 2018
719
}else{
720
var ret = func(self, flags)
Mar 19, 2018
721
if(ret !== undefined){
722
return ret
723
}
724
++newpos
725
}
Mar 19, 2018
726
}catch (err){
727
if(err.name == "UnsupportedChar"){
728
invalid_char = s[newpos]
Mar 19, 2018
729
if(invalid_char === undefined){
730
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
732
throw _b_.ValueError.$factory(
733
"unsupported format character '" + invalid_char +
734
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
735
") at index " + newpos)
736
}else if(err.name === "NotANumber"){
737
var try_char = s[newpos],
738
cls = self.__class__
739
if(!cls){
740
if(typeof(self) === "string"){
741
cls = "str"
742
}else{
743
cls = typeof(self)
Mar 19, 2018
745
}else{
746
cls = cls.__name__
747
}
Mar 19, 2018
748
throw _b_.TypeError.$factory("%" + try_char +
749
" format: a number is required, not " + cls)
750
}else{
751
throw err
752
}
Sep 5, 2014
753
}
Mar 19, 2018
754
}while (true)
Sep 5, 2014
755
}
756
var nbph = 0 // number of placeholders
Mar 19, 2018
757
do{
758
var newpos = self.indexOf("%", pos)
759
if(newpos < 0){
760
ret += self.substring(pos)
761
break
762
}
763
ret += self.substring(pos, newpos)
764
++newpos
Mar 19, 2018
765
if(newpos < length){
766
if(self[newpos] === "%"){
767
ret += "%"
768
}else{
Mar 19, 2018
770
if(self[newpos] === "("){
771
++newpos
772
ret += $get_kwarg_string(self)
773
} else {
774
ret += $get_arg_string(self)
775
}
776
}
Mar 19, 2018
777
}else{
778
// % at end of string
779
throw _b_.ValueError.$factory("incomplete format")
780
}
781
pos = newpos + 1
Mar 19, 2018
782
}while(pos < length)
783
784
if(argpos !== null){
785
if(args.length > argpos){
786
throw _b_.TypeError.$factory(
787
"not enough arguments for format string")
788
}else if(args.length < argpos){
789
throw _b_.TypeError.$factory(
790
"not all arguments converted during string formatting")
Mar 19, 2018
792
}else if(nbph == 0){
793
throw _b_.TypeError.$factory(
794
"not all arguments converted during string formatting")
Sep 5, 2014
798
str
Feb 10, 2018
799
str.__mro__ = [object]
Sep 5, 2014
800
str
Feb 10, 2018
801
str.__mul__ = function(){
Mar 19, 2018
802
var $ = $B.args("__mul__", 2, {self: null, other: null},
803
["self", "other"], arguments, {}, null, null)
804
if(! isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
805
"Can't multiply sequence by non-int of type '" +
806
$B.get_class($.other).__name__ + "'")}
807
var $res = ""
808
for(var i = 0; i< $.other; i++){$res += $.self.valueOf()}
Sep 5, 2014
809
return $res
810
}
811
Mar 19, 2018
812
str.__ne__ = function(self,other){return other !== self.valueOf()}
Sep 5, 2014
813
str
Feb 10, 2018
814
str.__repr__ = function(self){
Mar 19, 2018
815
var res = self.replace(/\n/g,"\\\\n")
816
// escape the escape char
Mar 19, 2018
817
res = res.replace(/\\/g, "\\\\")
818
if(res.search('"') == -1 && res.search("'") == -1){
819
return "'" + res + "'"
820
}else if(self.search('"') == -1){
821
return '"' + res + '"'
822
}
823
var qesc = new RegExp("'", "g") // to escape single quote
824
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
825
return res
826
}
827
Mar 19, 2018
828
str.__setitem__ = function(self, attr, value){
829
throw _b_.TypeError.$factory(
830
"'str' object does not support item assignment")
Sep 5, 2014
831
}
str
Feb 10, 2018
832
str.__str__ = function(self){
Mar 19, 2018
833
if(self === undefined){return "<class 'str'>"}
Sep 5, 2014
834
return self.toString()
835
}
Mar 19, 2018
836
str.toString = function(){return "string!"}
Sep 5, 2014
837
838
// generate comparison methods
839
var $comp_func = function(self,other){
Mar 19, 2018
840
if(typeof other !== "string"){throw _b_.TypeError.$factory(
841
"unorderable types: 'str' > " + $B.get_class(other).__name__ + "()")}
Sep 5, 2014
842
return self > other
843
}
Mar 19, 2018
844
$comp_func += "" // source code
845
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
846
for(var $op in $comps){
Mar 19, 2018
847
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
848
}
849
850
// add "reflected" methods
str
Feb 10, 2018
851
$B.make_rmethods(str)
Sep 5, 2014
852
853
// unsupported operations
Mar 19, 2018
854
var $notimplemented = function(self, other){
855
throw NotImplementedError.$factory(
856
"OPERATOR not implemented for class str")
Sep 5, 2014
857
}
858
859
// Copy static methods from unicode
860
var from_unicode = [
861
"title",
862
"capitalize",
863
"casefold",
864
"islower",
865
"isupper",
866
"istitle",
867
"isspace",
868
"isalpha",
869
"isalnum",
870
"isdecimal",
871
"isdigit",
872
"isnumeric",
873
"isidentifier",
874
"isprintable",
875
"lower",
876
"swapcase",
877
"upper"
878
]
Mar 19, 2018
879
880
from_unicode.forEach(function(name){
str
Feb 10, 2018
881
str[name] = unicode[name]
Mar 19, 2018
882
})
Sep 5, 2014
883
Mar 19, 2018
884
str.center = function(){
885
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
886
["self", "width", "fillchar"],
887
arguments, {fillchar:" "}, null, null),
888
self = $.self
Mar 19, 2018
890
if($.width <= self.length) {return self}
Mar 19, 2018
892
var pad = parseInt(($.width - self.length) / 2),
893
res = $.fillchar.repeat(pad)
Sep 5, 2014
894
res += self + res
Mar 19, 2018
895
if(res.length < $.width){res += $.fillchar}
Sep 5, 2014
896
return res
897
}
898
str
Feb 10, 2018
899
str.count = function(){
Mar 19, 2018
900
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
901
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
Mar 19, 2018
903
if(!(typeof $.sub == "string")){throw _b_.TypeError.$factory(
904
"Can't convert '" + $B.get_class($.sub).__name__ +
905
"' object to str implicitly")}
Mar 19, 2018
907
if($.start !== null){
Mar 19, 2018
909
if($.stop !== null){_slice = _b_.slice.$factory($.start, $.stop)}
910
else{_slice = _b_.slice.$factory($.start, $.self.length)}
str
Feb 10, 2018
911
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
Mar 19, 2018
913
if($.self.length + $.sub.length == 0){return 1}
Mar 19, 2018
915
if($.sub.length == 0){
916
if($.start == $.self.length){return 1}
917
else if(substr.length == 0){return 0}
918
return substr.length + 1
Mar 19, 2018
920
var n = 0,
921
pos = 0
922
while(pos < substr.length){
923
pos = substr.indexOf($.sub, pos)
924
if(pos >= 0){n++; pos += $.sub.length}
925
else{break}
Sep 5, 2014
926
}
927
return n
928
}
929
str
Feb 10, 2018
930
str.encode = function(self, encoding) {
Mar 19, 2018
931
if (encoding === undefined){encoding = "utf-8"}
932
if(encoding == "rot13" || encoding == "rot_13"){
933
// Special case : returns a string
Mar 19, 2018
934
var res = ""
935
for(var i = 0, len = self.length; i < len ; i++){
936
var char = self.charAt(i)
Mar 19, 2018
937
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
938
res += String.fromCharCode(String.charCodeAt(char) + 13)
939
}else if(("m" < char && char <= "z") ||
940
("M" < char && char <= "Z")){
941
res += String.fromCharCode(String.charCodeAt(char) - 13)
942
}else{res += char}
943
}
944
return res
945
}
946
return _b_.bytes.$factory(self, encoding)
Sep 5, 2014
947
}
948
str
Feb 10, 2018
949
str.endswith = function(){
950
// Return True if the string ends with the specified suffix, otherwise
951
// return False. suffix can also be a tuple of suffixes to look for.
952
// With optional start, test beginning at that position. With optional
Sep 5, 2014
953
// end, stop comparing at that position.
Mar 19, 2018
954
var $ = $B.args("endswith", 4,
955
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
956
["self", "suffix", "start", "end"],
957
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
958
959
normalize_start_end($)
960
961
var suffixes = $.suffix
Mar 19, 2018
962
if(! isinstance(suffixes,_b_.tuple)){suffixes = [suffixes]}
Mar 19, 2018
964
var s = $.self.substring($.start, $.end)
965
for(var i = 0, len = suffixes.length; i < len; i++){
966
var suffix = suffixes[i]
Mar 19, 2018
967
if(! _b_.isinstance(suffix, str)){throw _b_.TypeError.$factory(
Sep 20, 2015
968
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
969
if(suffix.length <= s.length &&
970
s.substr(s.length - suffix.length) == suffix){return true}
Sep 5, 2014
971
}
972
return false
973
}
974
str
Feb 10, 2018
975
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
976
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
977
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
978
var s = $B.$GetInt($.tabsize),
979
col = 0,
980
pos = 0,
981
res = ""
982
if(s == 1){return self.replace(/\t/g," ")}
983
while(pos < self.length){
984
var car = self.charAt(pos)
985
switch(car){
Mar 19, 2018
986
case "\t":
Mar 21, 2018
987
while(col % s > 0){res += " "; col++}
Mar 19, 2018
989
case "\r":
990
case "\n":
991
res += car
992
col = 0
993
break
994
default:
995
res += car
996
col++
997
break
998
}
999
pos++
1000
}
Sep 5, 2014
1003
}
1004
str
Feb 10, 2018
1005
str.find = function(){
1006
// Return the lowest index in the string where substring sub is found,
1007
// such that sub is contained in the slice s[start:end]. Optional
1008
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1009
// Return -1 if sub is not found.
Mar 19, 2018
1010
var $ = $B.args("str.find", 4,
Mar 19, 2018
1011
{self: null, sub: null, start: null, end: null},
1012
["self", "sub", "start", "end"],
1013
arguments, {start: 0, end: null}, null, null)
1014
check_str($.sub)
Mar 19, 2018
1017
if(!isinstance($.start, _b_.int)||!isinstance($.end, _b_.int)){
1018
throw _b_.TypeError.$factory("slice indices must be " +
1019
"integers or None or have an __index__ method")}
1020
var s = $.self.substring($.start, $.end)
Mar 19, 2018
1022
if($.sub.length == 0 && $.start == $.self.length){return $.self.length}
1023
if(s.length + $.sub.length == 0){return -1}
Mar 19, 2018
1025
var last_search = s.length - $.sub.length
1026
for(var i = 0; i <= last_search; i++){
1027
if(s.substr(i, $.sub.length) == $.sub){return $.start + i}
Sep 5, 2014
1028
}
Sep 5, 2014
1030
}
1031
1032
// Next function used by method .format()
1033
1034
function parse_format(fmt_string){
Sep 5, 2014
1035
1036
// Parse a "format string", as described in the Python documentation
1037
// Return a format object. For the format string
1038
// a.x[z]!r:...
1039
// the object has attributes :
1040
// - name : "a"
1041
// - name_ext : [".x", "[z]"]
1042
// - conv : r
1043
// - spec : rest of string after :
Sep 5, 2014
1044
Mar 19, 2018
1045
var elts = fmt_string.split(":"),
1046
name,
1047
conv,
1048
spec,
Mar 19, 2018
1049
name_ext = []
Mar 19, 2018
1050
if(elts.length == 1){
1051
// No : in the string : it only contains a name
1052
name = fmt_string
1053
}else{
1054
// name is before the first ":"
1055
// spec (the format specification) is after
1056
name = elts[0]
Mar 19, 2018
1057
spec = elts.splice(1).join(":")
Mar 19, 2018
1060
var elts = name.split("!")
1061
if(elts.length > 1){
1062
name = elts[0]
1063
conv = elts[1] // conversion flag
1064
if(conv.length !== 1 || "ras".search(conv) == -1){
1065
throw _b_.ValueError.$factory("wrong conversion flag " + conv)
Sep 5, 2014
1068
Mar 19, 2018
1069
if(name !== undefined){
1070
// "name' may be a subscription or attribute
1071
// Put these "extensions" in the list "name_ext"
1072
function name_repl(match){
1073
name_ext.push(match)
Mar 19, 2018
1074
return ""
1075
}
1076
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1077
name = name.replace(name_ext_re, name_repl)
1078
}
Sep 5, 2014
1079
1080
return {name: name, name_ext: name_ext,
Mar 19, 2018
1081
conv: conv, spec: spec || ""}
Sep 5, 2014
1083
str
Feb 10, 2018
1084
str.format = function(self) {
Mar 19, 2018
1085
var $ = $B.args("format", 1, {self: null}, ["self"],
1086
arguments, {}, "$args", "$kw")
1087
1088
// Parse self to detect formatting instructions
1089
// Create a list "parts" made of sections of the string :
1090
// - elements of even rank are literal text
1091
// - elements of odd rank are "format objects", built from the
1092
// format strings in self (of the form {...})
Mar 19, 2018
1093
var pos = 0,
1094
_len = self.length,
Mar 19, 2018
1096
text = "",
1097
parts = [],
1098
rank = 0
1099
while(pos < _len){
1100
car = self.charAt(pos)
Mar 21, 2018
1101
if(car == "{" && self.charAt(pos + 1) == "{"){
1102
// replace {{ by literal {
Mar 19, 2018
1103
text += "{"
1104
pos += 2
1105
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1106
// replace }} by literal }
Mar 19, 2018
1107
text += "}"
1108
pos += 2
1109
}else if(car == "{"){
1110
// Start of a format string
1112
// Store current literal text
1113
parts.push(text)
1114
1115
// Search the end of the format string, ie the } closing the
1116
// opening {. Since the string can contain other pairs {} for
1117
// nested formatting, an integer nb is incremented for each { and
1118
// decremented for each } ; the end of the format string is
Mar 19, 2018
1119
// reached when nb == 0
1120
var end = pos + 1,
1121
nb = 1
1122
while(end < _len){
1123
if(self.charAt(end) == "{"){nb++; end++}
1124
else if(self.charAt(end) == "}"){
1125
nb--; end++
1126
if(nb == 0){
1127
// End of format string
Mar 19, 2018
1128
var fmt_string = self.substring(pos + 1, end - 1)
1129
1130
// Create a format object, by function parse_format
1131
var fmt_obj = parse_format(fmt_string)
1132
1133
// If no name is explicitely provided, use the rank
1134
if(!fmt_obj.name){
Mar 19, 2018
1135
fmt_obj.name = rank + ""
Sep 5, 2014
1138
Mar 19, 2018
1139
if(fmt_obj.spec !== undefined){
1140
// "spec" may contain "nested replacement fields"
1141
// In this case, evaluate them using the positional
1142
// or keyword arguments passed to format()
1143
function replace_nested(name, key){
1144
if(/\d+/.exec(key)){
1145
// If key is numeric, search in positional
1146
// arguments
Feb 11, 2018
1147
return _b_.tuple.__getitem__($.$args,
1148
parseInt(key))
1149
}else{
1150
// Else try in keyword arguments
Feb 11, 2018
1151
return _b_.dict.__getitem__($.$kw, key)
1154
fmt_obj.spec = fmt_obj.spec.replace(/\{(.+?)\}/g,
1155
replace_nested)
1156
}
1158
// Store format object in list "parts"
1159
parts.push(fmt_obj)
Mar 19, 2018
1160
text = ""
1161
break
1162
}
1163
}else{end++}
Sep 5, 2014
1164
}
Mar 19, 2018
1165
if(nb > 0){throw ValueError.$factory("wrong format " + self)}
Mar 19, 2018
1167
}else{text += car; pos++}
Sep 5, 2014
1168
}
1169
if(text){parts.push(text)}
1170
// Apply formatting to the values passed to format()
Mar 19, 2018
1171
var res = "",
1172
fmt
1173
for(var i = 0; i < parts.length; i++){
1174
// Literal text is added unchanged
Mar 19, 2018
1175
if(typeof parts[i] == "string"){res += parts[i]; continue}
1177
// Format objects
1178
fmt = parts[i]
Mar 21, 2018
1179
if(fmt.name.charAt(0).search(/\d/) > -1){
1180
// Numerical reference : use positional arguments
1181
var pos = parseInt(fmt.name),
Feb 11, 2018
1182
value = _b_.tuple.__getitem__($.$args, pos)
1183
}else{
1184
// Use keyword arguments
Feb 11, 2018
1185
var value = _b_.dict.__getitem__($.$kw, fmt.name)
1186
}
1187
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1188
for(var j = 0; j < fmt.name_ext.length; j++){
1189
var ext = fmt.name_ext[j]
Mar 19, 2018
1190
if(ext.charAt(0) == "."){
1191
// Attribute
1192
value = _b_.getattr(value, ext.substr(1))
1193
}else{
1194
// Subscription
Mar 19, 2018
1195
var key = ext.substr(1, ext.length - 2)
1196
// An index made of digits is transformed into an integer
Mar 19, 2018
1197
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1198
value = _b_.getattr(value, "__getitem__")(key)
Feb 12, 2018
1201
1202
// If the conversion flag is set, first call a function to convert
1203
// the value
Mar 19, 2018
1204
if(fmt.conv == "a"){value = _b_.ascii(value)}
1205
else if(fmt.conv == "r"){value = _b_.repr(value)}
1206
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1208
// Call attribute __format__ to perform the actual formatting
1209
if(value.$is_class || value.$factory){
1210
// For classes, don't use the class __format__ method
1211
res += value.__class__.__format__(value, fmt.spec)
Mar 19, 2018
1213
res += _b_.getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1215
}
Sep 5, 2014
1217
}
1218
str
Feb 10, 2018
1219
str.format_map = function(self) {
Mar 19, 2018
1220
throw NotImplementedError.$factory(
1221
"function format_map not implemented yet")
Sep 5, 2014
1222
}
1223
str
Feb 10, 2018
1224
str.index = function(self){
Sep 5, 2014
1225
// Like find(), but raise ValueError when the substring is not found.
str
Feb 10, 2018
1226
var res = str.find.apply(null,arguments)
Mar 19, 2018
1227
if(res === -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1228
return res
1229
}
1230
str
Feb 10, 2018
1231
str.join = function(){
Mar 19, 2018
1232
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1233
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1235
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1236
res = [],
1237
count = 0,
Sep 5, 2014
1239
while(1){
1240
try{
1241
var obj2 = _b_.next(iterable)
Mar 19, 2018
1242
if(! isinstance(obj2, str)){throw _b_.TypeError.$factory(
1243
"sequence item " + count + ": expected str instance, " +
1244
$B.get_class(obj2).__name__ + " found")}
1245
res.push(obj2)
Sep 5, 2014
1246
}catch(err){
1247
if(_b_.isinstance(err, _b_.StopIteration)){
1248
$B.current_exception = ce
1249
break
1250
}
Sep 5, 2014
1251
else{throw err}
1252
}
1253
}
1254
return res.join($.self)
Sep 5, 2014
1255
}
1256
str
Feb 10, 2018
1257
str.ljust = function(self) {
Mar 19, 2018
1258
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1259
["self", "width", "fillchar"],
1260
arguments, {fillchar: " "}, null, null)
Mar 19, 2018
1262
if($.width <= self.length){return self}
1263
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1264
}
1265
str
Feb 10, 2018
1266
str.lstrip = function(self,x){
Mar 19, 2018
1267
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1268
arguments, {chars:_b_.None}, null, null)
1269
if($.chars === _b_.None){return $.self.trimLeft()}
1270
for(var i = 0; i < $.self.length; i++){
1271
if($.chars.indexOf($.self.charAt(i)) === -1){
1272
return $.self.substring(i)
Mar 19, 2018
1275
return ""
Sep 5, 2014
1276
}
1277
1278
// note, maketrans should be a static function.
str
Feb 10, 2018
1279
str.maketrans = function() {
Mar 19, 2018
1280
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1281
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1283
var _t = _b_.dict.$factory()
1284
// make 'default' translate table
Mar 19, 2018
1285
for(var i =0; i < 256; i++){_t.$numeric_dict[i] = i}
Mar 19, 2018
1287
if($.y === null && $.z === null){
1288
// If there is only one argument, it must be a dictionary mapping
1289
// Unicode ordinals (integers) or characters (strings of length 1) to
1290
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1291
// keys will then be converted to ordinals.
Mar 19, 2018
1292
if(! _b_.isinstance($.x, _b_.dict)){
1293
throw _b_.TypeError.$factory(
1294
"maketrans only argument must be a dict")
Feb 11, 2018
1296
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1297
for(var i = 0, len = items.length; i < len; i++){
1298
var k = items[i][0],
1299
v = items[i][1]
1300
if(! _b_.isinstance(k, _b_.int)){
1301
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1302
k = _b_.ord(k)
1303
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1304
" is not int or 1-char string")}
1305
}
Mar 19, 2018
1306
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1307
throw _b_.TypeError.$factory("dictionary value " + v +
1308
" is not None, integer or string")
1309
}
Mar 19, 2018
1310
_t.$numeric_dict[k] = v
1311
}
1312
return _t
1313
}else{
1314
// If there are two arguments, they must be strings of equal length,
1315
// and in the resulting dictionary, each character in x will be mapped
1316
// to the character at the same position in y
Mar 19, 2018
1317
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1318
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1319
}else if($.x.length !== $.y.length){
1320
throw _b_.TypeError.$factory(
1321
"maketrans arguments must be strings or same length")
1322
}else{
1323
var toNone = {}
Mar 19, 2018
1324
if($.z !== null){
1325
// If there is a third argument, it must be a string, whose
1326
// characters will be mapped to None in the result
Mar 19, 2018
1327
if(! _b_.isinstance($.z, _b_.str)){
1328
throw _b_.TypeError.$factory(
1329
"maketrans third argument must be a string")
Mar 19, 2018
1331
for(var i = 0, len = $.z.length; i < len; i++){
1332
toNone[_b_.ord($.z.charAt(i))] = true
1333
}
Mar 19, 2018
1335
for(var i = 0, len = $.x.length; i < len; i++){
1336
_t.$numeric_dict[_b_.ord($.x.charAt(i))] =
1337
_b_.ord($.y.charAt(i))
1338
}
1339
for(var k in toNone){
1340
_t.$numeric_dict[k] = _b_.None
1341
}
1342
return _t
1343
}
1344
}
Sep 5, 2014
1345
}
1346
str
Feb 10, 2018
1347
str.partition = function() {
Mar 19, 2018
1348
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1349
arguments, {}, null, null)
Mar 19, 2018
1350
if($.sep == ""){throw _b_.ValueError.$factory("empty separator")}
Mar 19, 2018
1351
check_str($.sep)
1352
var i = $.self.indexOf($.sep)
1353
if (i == -1){return _b_.tuple.$factory([$.self, "", ""])}
1354
return _b_.tuple.$factory([$.self.substring(0, i), $.sep,
1355
$.self.substring(i + $.sep.length)])
1356
}
1357
1358
function $re_escape(str){
1359
var specials = "[.*+?|()$^"
1360
for(var i = 0, len = specials.length; i < len; i++){
1361
var re = new RegExp("\\"+specials.charAt(i), "g")
1362
str = str.replace(re, "\\"+specials.charAt(i))
1363
}
1364
return str
Sep 5, 2014
1365
}
1366
str
Feb 10, 2018
1367
str.replace = function(self, old, _new, count) {
1368
// Replaces occurrences of 'old' by '_new'. Count references
1369
// the number of times to replace. In CPython, negative or undefined
1370
// values of count means replace all.
Mar 19, 2018
1371
var $ = $B.args("replace", 4,
1372
{self: null, old: null, $$new: null, count: null},
1373
["self", "old", "$$new", "count"],
1374
arguments, {count: -1}, null, null),
1375
count = $.count,
1376
self = $.self,
1377
old = $.old,
1378
_new = $.$$new
1379
// Validate type of old
1380
check_str(old)
1381
check_str(_new)
1382
// Validate instance type of 'count'
Mar 19, 2018
1383
if (! isinstance(count,[_b_.int, _b_.float])) {
1384
throw _b_.TypeError.$factory("'" + $B.get_class(count).__name__ +
Mar 19, 2018
1385
"' object cannot be interpreted as an integer")
1386
}else if(isinstance(count, _b_.float)){
1387
throw _b_.TypeError.$factory("integer argument expected, got float")
1388
}
1389
if(count == 0){return self}
1390
if(count.__class__ == $B.long_int){count = parseInt(count.value)}
1391
if(old == ""){
1392
if(_new == ""){return self}
1393
if(self == ""){return _new}
1394
var elts = self.split("")
1395
if(count > -1 && elts.length >= count){
1396
var rest = elts.slice(count).join("")
1397
return _new + elts.slice(0, count).join(_new) + rest
1398
}else{return _new + elts.join(_new) + _new}
Mar 19, 2018
1400
var elts = str.split(self, old, count)
Sep 5, 2014
1401
}
Mar 19, 2018
1403
var res = self,
1404
pos = -1
1405
if(old.length == 0){
Mar 19, 2018
1407
for(var i = 0; i < elts.length; i++){
1408
res += elts[i] + _new
Mar 19, 2018
1410
return res + rest
Mar 19, 2018
1413
if(count < 0){count = res.length}
1414
while(count > 0){
1415
pos = res.indexOf(old, pos)
1416
if(pos < 0){break}
1417
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
1418
pos = pos + _new.length
1419
count--
Mar 19, 2018
1421
return res
Sep 5, 2014
1422
}
1423
str
Feb 10, 2018
1424
str.rfind = function(self){
1425
// Return the highest index in the string where substring sub is found,
1426
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1427
// start and end are interpreted as in slice notation. Return -1 on failure.
Mar 19, 2018
1428
var $ = $B.args("rfind", 4,
Mar 19, 2018
1429
{self: null, sub: null, start: null, end: null},
1430
["self", "sub", "start", "end"],
1431
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1432
1435
check_str($.sub)
Mar 19, 2018
1437
if($.sub.length == 0){
1438
if($.start > $.self.length){return -1}
1439
else{return $.self.length}
1440
}
1441
var sublen = $.sub.length
Mar 19, 2018
1443
for(var i = $.end - sublen; i >= $.start; i--){
1444
if($.self.substr(i, sublen) == $.sub){return i}
Sep 5, 2014
1447
}
1448
str
Feb 10, 2018
1449
str.rindex = function(){
Sep 5, 2014
1450
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
1451
var res = str.rfind.apply(null, arguments)
1452
if(res == -1){throw _b_.ValueError.$factory("substring not found")}
Sep 5, 2014
1453
return res
1454
}
1455
str
Feb 10, 2018
1456
str.rjust = function(self) {
Mar 19, 2018
1457
var $ = $B.args("rjust",3,
1458
{self: null, width: null, fillchar: null},
1459
["self", "width", "fillchar"],
1460
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
1461
Mar 19, 2018
1462
if($.width <= self.length){return self}
Sep 5, 2014
1463
1464
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1465
}
1466
str
Feb 10, 2018
1467
str.rpartition = function(self,sep) {
Mar 19, 2018
1468
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
1469
arguments, {}, null, null)
1470
check_str($.sep)
1471
var self = reverse($.self),
1472
sep = reverse($.sep)
Mar 19, 2018
1473
var items = str.partition(self, sep).reverse()
1474
for(var i = 0; i < items.length; i++){
1475
items[i] = items[i].split("").reverse().join("")
1476
}
1477
return items
Sep 5, 2014
1478
}
1479
str
Feb 10, 2018
1480
str.rsplit = function(self) {
Mar 19, 2018
1481
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
1482
["self", "sep", "maxsplit"], arguments,
1483
{sep: _b_.None, maxsplit: -1}, null, null),
1484
sep = $.sep
1485
1486
// Use split on the reverse of the string and of separator
1487
var rev_str = reverse($.self),
1488
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
1489
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
1491
// Reverse the list, then each string inside the list
1492
rev_res.reverse()
Mar 19, 2018
1493
for(var i = 0; i < rev_res.length; i++){
1494
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1497
}
1498
Mar 19, 2018
1499
str.rstrip = function(self, x){
1500
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
Mar 19, 2018
1501
arguments, {chars: _b_.None}, null, null)
1502
if($.chars === _b_.None){return $.self.trimRight()}
Mar 21, 2018
1503
for(var j = $.self.length - 1; j >= 0; j--){
Mar 19, 2018
1504
if($.chars.indexOf($.self.charAt(j)) == -1){
1505
return $.self.substring(0, j + 1)
Mar 19, 2018
1508
return ""
Sep 5, 2014
1509
}
1510
str
Feb 10, 2018
1511
str.split = function(){
Mar 19, 2018
1512
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
1513
["self", "sep", "maxsplit"], arguments,
1514
{sep: _b_.None, maxsplit: -1}, null, null),
1515
sep = $.sep,
1516
maxsplit = $.maxsplit,
1517
self = $.self,
1518
pos = 0
1519
if(maxsplit.__class__ === $B.long_int){maxsplit = parseInt(maxsplit.value)}
1520
if(sep == ""){throw _b_.ValueError.$factory("empty separator")}
1521
if(sep === _b_.None){
Sep 5, 2014
1522
var res = []
Mar 19, 2018
1523
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){pos++}
1524
if(pos === self.length - 1){return [self]}
1525
var name = ""
Sep 5, 2014
1526
while(1){
Mar 19, 2018
1527
if(self.charAt(pos).search(/\s/) == -1){
1528
if(name == ""){name = self.charAt(pos)}
1529
else{name += self.charAt(pos)}
Sep 5, 2014
1530
}else{
Mar 19, 2018
1531
if(name !== ""){
Sep 5, 2014
1532
res.push(name)
Mar 19, 2018
1533
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
1534
res.pop()
Mar 19, 2018
1535
res.push(name + self.substr(pos))
Sep 5, 2014
1536
return res
1537
}
Mar 19, 2018
1538
name = ""
Sep 5, 2014
1539
}
1540
}
1541
pos++
Mar 19, 2018
1542
if(pos > self.length - 1){
Sep 5, 2014
1543
if(name){res.push(name)}
1544
break
1545
}
1546
}
1547
return res
1548
}else{
Mar 19, 2018
1549
var res = [],
1550
s = "",
1551
seplen = sep.length
1552
if(maxsplit == 0){return [self]}
1553
while(pos < self.length){
1554
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
1557
if(maxsplit > -1 && res.length >= maxsplit){
1558
res.push(self.substr(pos))
1559
return res
1560
}
Mar 19, 2018
1561
s = ""
1562
}else{
1563
s += self.charAt(pos)
1564
pos++
Sep 5, 2014
1565
}
1566
}
Sep 5, 2014
1569
}
1570
}
1571
str
Feb 10, 2018
1572
str.splitlines = function(self){
Mar 19, 2018
1573
var $ = $B.args("splitlines", 2, {self: null, keepends: null},
Mar 19, 2018
1574
["self", "keepends"], arguments, {keepends: false}, null, null)
1575
if(! _b_.isinstance($.keepends, [_b_.bool, _b_.int])){
1576
throw _b_.TypeError.$factory("integer argument expected, got " +
1577
$B.get_class($.keepends).__name)
1578
}
1579
var keepends = _b_.int.$factory($.keepends)
1580
// Remove trailing line breaks
1581
if(keepends){
1582
var res = [],
Mar 19, 2018
1583
start = pos,
1584
pos = 0,
1585
self = $.self
1586
while(pos < self.length){
1587
if(self.substr(pos, 2) == "\r\n"){
1588
res.push(self.substring(start, pos + 2))
1589
start = pos + 2
1590
pos = start
Mar 19, 2018
1591
}else if(self.charAt(pos) == "\r" || self.charAt(pos) == "\n"){
1592
res.push(self.substring(start, pos + 1))
1593
start = pos + 1
1594
pos = start
1595
}else{pos++}
1596
}
1597
var rest = self.substr(start)
1598
if(rest){res.push(rest)}
1599
return res
1600
}else{
Mar 19, 2018
1601
var self = $.self.replace(/[\r\n]$/, "")
1602
return self.split(/\n|\r\n|\r/)
1603
}
1604
}
Sep 5, 2014
1605
str
Feb 10, 2018
1606
str.startswith = function(){
1607
// Return True if string starts with the prefix, otherwise return False.
1608
// prefix can also be a tuple of prefixes to look for. With optional
1609
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1610
// stop comparing string at that position.
Mar 19, 2018
1611
var $ = $B.args("startswith", 4,
1612
{self: null, prefix: null, start: null, end: null},
1613
["self", "prefix", "start", "end"],
1614
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
1615
1616
normalize_start_end($)
1617
1618
var prefixes = $.prefix
Mar 19, 2018
1619
if(! isinstance(prefixes, _b_.tuple)){prefixes = [prefixes]}
Mar 19, 2018
1621
var s = $.self.substring($.start, $.end)
1622
for(var i = 0, len = prefixes.length; i < len; i++){
1623
prefix = prefixes[i]
Mar 19, 2018
1624
if(! _b_.isinstance(prefix, str)){throw _b_.TypeError.$factory(
1625
"endswith first arg must be str or a tuple of str, not int")}
Mar 19, 2018
1626
if(s.substr(0, prefix.length) == prefix){return true}
Sep 5, 2014
1627
}
1628
return false
1629
Sep 5, 2014
1630
}
1631
str
Feb 10, 2018
1632
str.strip = function(){
Mar 19, 2018
1633
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
1634
arguments, {chars: _b_.None}, null, null)
1635
if($.chars === _b_.None){return $.self.trim()}
1636
for(var i = 0; i < $.self.length; i++){
1637
if($.chars.indexOf($.self.charAt(i)) == -1){
1638
break
Mar 19, 2018
1641
for(var j = $.self.length - 1; j >= i; j--){
1642
if($.chars.indexOf($.self.charAt(j)) == -1){
1643
break
Mar 19, 2018
1646
return $.self.substring(i, j + 1)
Sep 5, 2014
1647
}
1648
Mar 19, 2018
1649
str.translate = function(self,table){
1650
var res = [],
1651
pos = 0
1652
if(isinstance(table, _b_.dict)){
1653
for(var i = 0, len = self.length; i < len; i++){
1654
var repl = _b_.dict.get(table,self.charCodeAt(i), -1)
1655
if(repl == -1){res[pos++] = self.charAt(i)}
1656
else if(repl !== None){res[pos++] = _b_.chr(repl)}
Sep 5, 2014
1657
}
1658
}
Mar 19, 2018
1659
return res.join("")
Sep 5, 2014
1660
}
1661
Mar 19, 2018
1662
str.zfill = function(self, width){
Mar 19, 2018
1663
var $ = $B.args("zfill", 2, {self: null, width: null},
Mar 19, 2018
1664
["self", "width"], arguments, {}, null, null)
1665
if($.width <= self.length){return self}
Mar 19, 2018
1667
case "+":
1668
case "-":
1669
return self.charAt(0) +
1670
"0".repeat($.width - self.length) + self.substr(1)
Mar 19, 2018
1672
return "0".repeat(width - self.length) + self
Sep 5, 2014
1674
}
1675
str
Feb 10, 2018
1676
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
}
Mar 19, 2018
1696
var f = 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("pas de __str__ pour", 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__)