Skip to content
Permalink
Newer
Older
100644 2919 lines (2706 sloc) 87.9 KB
Sep 5, 2014
1
;(function($B){
2
3
var _b_ = $B.builtins
Sep 5, 2014
4
5
// build tables from data in unicode_data.js
6
var unicode_tables = $B.unicode_tables
Sep 5, 2014
7
8
9
$B.has_surrogate = function(s){
10
// Check if there are "surrogate pairs" characters in string s
11
for(var i = 0; i < s.length; i++){
12
code = s.charCodeAt(i)
13
if(code >= 0xD800 && code <= 0xDBFF){
14
return true
15
}
16
}
17
return false
18
}
19
20
$B.String = function(s){
21
var codepoints = [],
22
surrogates = [],
23
j = 0
24
for(var i = 0, len = s.length; i < len; i++){
25
var cp = s.codePointAt(i)
26
if(cp >= 0x10000){
27
surrogates.push(j)
32
if(surrogates.length == 0){
33
return s
35
var res = new String(s)
36
res.__class__ = str
37
res.surrogates = surrogates
38
return res
39
}
40
41
function pypos2jspos(s, pypos){
42
// convert Python position to JS position
43
if(s.surrogates === undefined){
44
return pypos
45
}
46
var nb = 0
47
while(s.surrogates[nb] < pypos){
48
nb++
49
}
50
return pypos + nb
53
function jspos2pypos(s, jspos){
54
// convert JS position to Python position
55
if(s.surrogates === undefined){
56
return jspos
57
}
58
var nb = 0
59
while(s.surrogates[nb] + nb < jspos){
60
nb++
61
}
62
return jspos - nb
63
}
64
str
Feb 10, 2018
65
var str = {
Mar 19, 2018
66
__class__: _b_.type,
67
__dir__: _b_.object.__dir__,
68
$infos: {
69
__module__: "builtins",
70
__name__: "str"
71
},
str
Feb 10, 2018
72
$is_class: true,
Mar 19, 2018
73
$native: true
Sep 5, 2014
74
}
75
78
if(typeof $.self == "string"){
79
len = $.self.length
80
}else{
81
len = str.__len__($.self)
82
}
83
if($.start === null || $.start === _b_.None){
84
$.start = 0
85
}else if($.start < 0){
86
$.start += len
Mar 19, 2018
87
$.start = Math.max(0, $.start)
88
}
89
if($.end === null || $.end === _b_.None){
90
$.end = len
91
}else if($.end < 0){
92
$.end += len
Mar 19, 2018
93
$.end = Math.max(0, $.end)
94
}
96
if(! _b_.isinstance($.start, _b_.int) || ! _b_.isinstance($.end, _b_.int)){
Mar 19, 2018
97
throw _b_.TypeError.$factory("slice indices must be integers " +
98
"or None or have an __index__ method")
99
}
100
if($.self.surrogates){
101
$.js_start = pypos2jspos($.self, $.start)
102
$.js_end = pypos2jspos($.self, $.end)
103
}
106
function reverse(s){
107
// Reverse a string
Mar 19, 2018
108
return s.split("").reverse().join("")
109
}
110
111
function check_str(obj, prefix){
112
if(obj instanceof String || typeof obj == "string"){
113
return
114
}
Mar 19, 2018
115
if(! _b_.isinstance(obj, str)){
116
throw _b_.TypeError.$factory((prefix || '') +
117
"must be str, not " + $B.class_name(obj))
Mar 19, 2018
118
}
121
function to_chars(s){
122
// Transform Javascript string s into a list of Python characters
123
// (2 JS chars if surrogate, 1 otherwise)
124
var chars = []
125
for(var i = 0, len = s.length; i < len; i++){
126
var code = s.charCodeAt(i)
127
if(code >= 0xD800 && code <= 0xDBFF){
128
chars.push(s.substr(i, 2))
129
i++
130
}else{
131
chars.push(s.charAt(i))
132
}
133
}
134
return chars
135
}
136
137
function to_codepoints(s){
138
// Transform Javascript string s into a list of codepoints
139
if(s.codepoints){
140
return s.codepoints
141
}
142
var cps = []
143
for(var i = 0, len = s.length; i < len; i++){
144
var code = s.charCodeAt(i)
145
if(code >= 0xD800 && code <= 0xDBFF){
146
var v = 0x10000
147
v += (code & 0x03FF) << 10
148
v += (s.charCodeAt(i + 1) & 0x03FF)
149
cps.push(v)
150
i++
151
}else{
152
cps.push(code)
153
}
154
}
155
return s.codepoints = cps
156
}
157
158
str.__add__ = function(self, other){
159
if(! _b_.isinstance(other, str)){
160
try{
161
return $B.$getattr(other, "__radd__")(self)
162
}catch(err){
Mar 19, 2018
163
throw _b_.TypeError.$factory("Can't convert " +
164
$B.class_name(other) + " to str implicitly")}
Sep 5, 2014
165
}
166
return $B.String(self + other)
Sep 5, 2014
167
}
168
Mar 19, 2018
169
str.__contains__ = function(self, item){
170
if(! _b_.isinstance(item, str)){
Mar 19, 2018
171
throw _b_.TypeError.$factory("'in <string>' requires " +
172
"string as left operand, not " + item.__class__)
173
}
174
if(item.__class__ === str || _b_.isinstance(item, str)){
175
var nbcar = item.length
176
}else{
177
var nbcar = _b_.len(item)
178
}
179
if(nbcar == 0){
180
// a string contains the empty string
181
return true
182
}
183
var len = self.length
184
if(len == 0){
Mar 19, 2018
187
for(var i = 0, len = self.length; i < len; i++){
188
if(self.substr(i, nbcar) == item){
189
return true
190
}
Sep 5, 2014
191
}
192
return false
193
}
194
str
Feb 10, 2018
195
str.__delitem__ = function(){
196
throw _b_.TypeError.$factory("'str' object doesn't support item deletion")
Sep 5, 2014
197
}
198
Mar 19, 2018
199
// __dir__must be assigned explicitely because attribute resolution for
200
// builtin classes doesn't use __mro__
201
str.__dir__ = _b_.object.__dir__
203
str.__eq__ = function(self, other){
Mar 23, 2018
204
if(_b_.isinstance(other, _b_.str)){
205
return other.valueOf() == self.valueOf()
206
}
207
return _b_.NotImplemented
Sep 5, 2014
208
}
209
210
function preformat(self, fmt){
211
if(fmt.empty){
212
return _b_.str.$factory(self)
213
}
Mar 19, 2018
214
if(fmt.type && fmt.type != "s"){
215
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
216
"' for object of type 'str'")
218
return self
219
}
220
str
Feb 10, 2018
221
str.__format__ = function(self, format_spec) {
222
var fmt = new $B.parse_format_spec(format_spec)
Mar 19, 2018
223
if(fmt.sign !== undefined){
224
throw _b_.ValueError.$factory(
225
"Sign not allowed in string format specifier")
227
if(fmt.precision){
228
self = self.substr(0, fmt.precision)
229
}
230
// For strings, alignment default to left
Mar 19, 2018
231
fmt.align = fmt.align || "<"
232
return $B.format_width(preformat(self, fmt), fmt)
Sep 5, 2014
233
}
234
235
str.__getitem__ = function(self, arg){
236
var len = str.__len__(self)
237
if(_b_.isinstance(arg, _b_.int)){
Sep 5, 2014
238
var pos = arg
240
pos += len
242
if(pos >= 0 && pos < len){
243
var jspos = pypos2jspos(self, pos)
244
if(self.codePointAt(jspos) >= 0x10000){
245
return $B.String(self.substr(jspos, 2))
246
}else{
Mar 19, 2018
250
throw _b_.IndexError.$factory("string index out of range")
251
}
252
if(_b_.isinstance(arg, _b_.slice)){
253
var s = _b_.slice.$conv_for_seq(arg, len),
254
start = pypos2jspos(self, s.start),
255
stop = pypos2jspos(self, s.stop),
Mar 19, 2018
256
step = s.step
257
var res = "",
Mar 19, 2018
258
i = null
Mar 19, 2018
259
if(step > 0){
260
if(stop <= start){
261
return ""
262
}
263
for(var i = start; i < stop; i += step){
264
res += self[i]
Mar 23, 2018
266
}else{
267
if(stop >= start){
268
return ''
269
}
270
for(var i = start; i > stop; i += step){
271
res += self[i]
274
return $B.String(res)
Sep 5, 2014
275
}
276
if(_b_.isinstance(arg, _b_.bool)){
277
return self.__getitem__(_b_.int.$factory(arg))
278
}
Mar 19, 2018
279
throw _b_.TypeError.$factory("string indices must be integers")
Sep 5, 2014
280
}
281
282
var prefix = 2,
283
suffix = 3,
Jun 12, 2020
284
mask = (2 ** 32 - 1),
285
str_hash_cache = {}
286
287
str.$nb_str_hash_cache = 0
Jun 12, 2020
288
289
function fnv(p){
290
if(p.length == 0){
291
return 0
292
}
Sep 5, 2014
293
294
var x = prefix
295
x = (x ^ (p[0] << 7)) & mask
296
for(var i = 0, len = p.length; i < len; i++){
297
x = ((1000003 * x) ^ p[i]) & mask
298
}
299
x = (x ^ p.length) & mask
300
x = (x ^ suffix) & mask
Sep 5, 2014
301
302
if(x == -1){
303
x = -2
304
}
305
return x
306
}
308
str.__hash__ = function(self) {
Jun 12, 2020
309
if(str_hash_cache[self] !== undefined){
310
return str_hash_cache[self]
311
}
312
str.$nb_str_hash_cache++
313
if(str.$nb_str_hash_cache > 100000){
314
// Avoid memory overflow
315
str.$nb_str_hash_cache = 0
316
str_hash_cache = {}
317
}
318
try{
319
return str_hash_cache[self] = fnv(to_codepoints(self))
320
}catch(err){
321
console.log('error hash, cps', self, to_codepoints(self))
322
throw err
323
}
Sep 5, 2014
324
}
325
Mar 19, 2018
326
str.__init__ = function(self, arg){
Sep 5, 2014
327
self.valueOf = function(){return arg}
328
self.toString = function(){return arg}
Sep 5, 2014
330
}
331
332
var str_iterator = $B.make_iterator_class("str_iterator")
str
Feb 10, 2018
333
str.__iter__ = function(self){
334
return str_iterator.$factory(to_chars(self))
Sep 5, 2014
335
}
336
337
str.__len__ = function(self){
338
if(self.surrogates === undefined){
339
return self.length
341
if(self.len !== undefined){
342
return self.len
343
}
344
var len = self.len = self.valueOf().length - self.surrogates.length
345
return len
Sep 5, 2014
347
348
// Start of section for legacy formatting (with %)
349
Mar 19, 2018
350
var kwarg_key = new RegExp("([^\\)]*)\\)")
351
352
var NotANumber = function() {
Mar 19, 2018
353
this.name = "NotANumber"
354
}
355
Mar 19, 2018
356
var number_check = function(s){
357
if(! _b_.isinstance(s, [_b_.int, _b_.float])){
358
throw new NotANumber()
359
}
360
}
361
Mar 19, 2018
362
var get_char_array = function(size, char){
363
if(size <= 0){
364
return ""
365
}
366
return new Array(size + 1).join(char)
367
}
368
Mar 19, 2018
369
var format_padding = function(s, flags, minus_one){
370
var padding = flags.padding
Mar 23, 2018
371
if(! padding){ // undefined
372
return s
373
}
374
s = s.toString()
375
padding = parseInt(padding, 10)
Mar 23, 2018
376
if(minus_one){ // numeric formatting where sign goes in front of padding
377
padding -= 1
378
}
Mar 19, 2018
379
if(! flags.left){
380
return get_char_array(padding - s.length, flags.pad_char) + s
Mar 19, 2018
381
}else{
382
// left adjusted
383
return s + get_char_array(padding - s.length, flags.pad_char)
384
}
385
}
386
Mar 19, 2018
387
var format_int_precision = function(val, flags){
388
var precision = flags.precision
Mar 19, 2018
389
if(!precision){
390
return val.toString()
391
}
392
precision = parseInt(precision, 10)
Mar 19, 2018
394
if(val.__class__ === $B.long_int){
395
s = $B.long_int.to_base(val, 10)
396
}else{
397
s = val.toString()
Mar 19, 2018
399
if(s[0] === "-"){
400
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
Mar 19, 2018
402
return get_char_array(precision - s.length, "0") + s
403
}
404
Mar 19, 2018
405
var format_float_precision = function(val, upper, flags, modifier){
406
var precision = flags.precision
407
// val is a float
Mar 19, 2018
408
if(isFinite(val)){
409
return modifier(val, precision, flags, upper)
Mar 19, 2018
411
if(val === Infinity){
412
val = "inf"
413
}else if(val === -Infinity){
414
val = "-inf"
415
}else{
416
val = "nan"
Mar 19, 2018
418
if(upper){
419
return val.toUpperCase()
420
}
421
return val
423
}
424
Mar 19, 2018
425
var format_sign = function(val, flags){
426
if(flags.sign){
427
if(val >= 0){
428
return "+"
Sep 5, 2014
429
}
Mar 19, 2018
430
}else if (flags.space){
431
if(val >= 0){
432
return " "
433
}
434
}
435
return ""
436
}
Sep 5, 2014
437
438
var str_format = function(val, flags) {
439
// string format supports left and right padding
440
flags.pad_char = " " // even if 0 padding is defined, don't use it
str
Feb 10, 2018
441
return format_padding(str.$factory(val), flags)
Sep 5, 2014
443
444
var num_format = function(val, flags) {
445
number_check(val)
Mar 19, 2018
446
if(val.__class__ === $B.long_int){
447
val = $B.long_int.to_base(val, 10)
448
}else{
449
val = parseInt(val)
452
var s = format_int_precision(val, flags)
Mar 19, 2018
453
if(flags.pad_char === "0"){
454
if(val < 0){
455
s = s.substring(1)
Mar 19, 2018
456
return "-" + format_padding(s, flags, true)
457
}
458
var sign = format_sign(val, flags)
Mar 19, 2018
459
if(sign !== ""){
460
return sign + format_padding(s, flags, true)
461
}
462
}
464
return format_padding(format_sign(val, flags) + s, flags)
465
}
Sep 5, 2014
466
467
var repr_format = function(val, flags) {
468
flags.pad_char = " " // even if 0 padding is defined, don't use it
469
return format_padding(_b_.repr(val), flags)
Sep 5, 2014
471
472
var ascii_format = function(val, flags) {
473
flags.pad_char = " " // even if 0 padding is defined, don't use it
474
return format_padding(_b_.ascii(val), flags)
Sep 5, 2014
476
477
// converts val to float and sets precision if missing
Mar 19, 2018
478
var _float_helper = function(val, flags){
479
number_check(val)
Mar 19, 2018
480
if(! flags.precision){
481
if(! flags.decimal_point){
482
flags.precision = 6
Mar 19, 2018
483
}else{
484
flags.precision = 0
485
}
Mar 19, 2018
486
}else{
487
flags.precision = parseInt(flags.precision, 10)
488
validate_precision(flags.precision)
489
}
490
return parseFloat(val)
491
}
Sep 5, 2014
492
493
// used to capture and remove trailing zeroes
Mar 19, 2018
494
var trailing_zeros = /(.*?)(0+)([eE].*)/,
495
leading_zeros = /\.(0*)/,
496
trailing_dot = /\.$/
Sep 5, 2014
497
498
var validate_precision = function(precision) {
499
// force precision to limits of javascript
Mar 19, 2018
500
if(precision > 20){precision = 20}
501
}
502
503
// gG
Mar 19, 2018
504
var floating_point_format = function(val, upper, flags){
505
val = _float_helper(val, flags),
506
v = val.toString(),
507
v_len = v.length,
508
dot_idx = v.indexOf('.')
509
if(dot_idx < 0){dot_idx = v_len}
510
if(val < 1 && val > -1){
511
var zeros = leading_zeros.exec(v),
512
numzeros
513
if(zeros){
514
numzeros = zeros[1].length
Mar 19, 2018
515
}else{
516
numzeros = 0
517
}
Mar 19, 2018
518
if(numzeros >= 4){
519
val = format_sign(val, flags) + format_float_precision(val, upper,
520
flags, _floating_g_exp_helper)
521
if(!flags.alternate){
522
var trl = trailing_zeros.exec(val)
Mar 19, 2018
523
if(trl){
524
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
526
}else{
527
if(flags.precision <= 1){
528
val = val[0] + "." + val.substring(1)
530
}
531
return format_padding(val, flags)
532
}
533
flags.precision = (flags.precision || 0) + numzeros
Mar 19, 2018
534
return format_padding(format_sign(val, flags) +
535
format_float_precision(val, upper, flags,
536
function(val, precision) {
537
return val.toFixed(_b_.min(precision, v_len - dot_idx) +
Mar 19, 2018
538
numzeros)
539
}),
540
flags
541
)
542
}
543
544
if(dot_idx > flags.precision){
545
val = format_sign(val, flags) + format_float_precision(val, upper,
546
flags, _floating_g_exp_helper)
547
if(! flags.alternate){
548
var trl = trailing_zeros.exec(val)
Mar 19, 2018
549
if(trl){
550
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
Mar 19, 2018
552
}else{
553
if(flags.precision <= 1){
554
val = val[0] + "." + val.substring(1)
555
}
556
}
557
return format_padding(val, flags)
558
}
Mar 19, 2018
559
return format_padding(format_sign(val, flags) +
560
format_float_precision(val, upper, flags,
561
function(val, precision) {
562
if(!flags.decimal_point){
563
precision = _b_.min(v_len - 1, 6)
Mar 19, 2018
564
}else if (precision > v_len){
565
if(! flags.alternate){
566
precision = v_len
567
}
Sep 5, 2014
568
}
Mar 19, 2018
569
if(precision < dot_idx){
570
precision = dot_idx
571
}
572
return val.toFixed(precision - dot_idx)
573
}),
574
flags
575
)
Sep 5, 2014
577
Mar 19, 2018
578
var _floating_g_exp_helper = function(val, precision, flags, upper){
579
if(precision){--precision}
580
val = val.toExponential(precision)
581
// pad exponent to two digits
Mar 19, 2018
582
var e_idx = val.lastIndexOf("e")
583
if(e_idx > val.length - 4){
584
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
586
if(upper){return val.toUpperCase()}
587
return val
588
}
589
590
// fF
591
var floating_point_decimal_format = function(val, upper, flags) {
592
val = _float_helper(val, flags)
Mar 19, 2018
593
return format_padding(format_sign(val, flags) +
594
format_float_precision(val, upper, flags,
595
function(val, precision, flags) {
596
val = val.toFixed(precision)
597
if(precision === 0 && flags.alternate){
598
val += '.'
599
}
600
return val
601
}),
602
flags
603
)
604
}
605
606
var _floating_exp_helper = function(val, precision, flags, upper) {
607
val = val.toExponential(precision)
608
// pad exponent to two digits
Mar 19, 2018
609
var e_idx = val.lastIndexOf("e")
Mar 23, 2018
610
if(e_idx > val.length - 4){
Mar 19, 2018
611
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
Mar 19, 2018
613
if(upper){return val.toUpperCase()}
614
return val
615
}
616
617
// eE
Mar 19, 2018
618
var floating_point_exponential_format = function(val, upper, flags){
619
val = _float_helper(val, flags)
Mar 19, 2018
621
return format_padding(format_sign(val, flags) +
622
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
623
}
624
Mar 19, 2018
625
var signed_hex_format = function(val, upper, flags){
627
number_check(val)
Mar 23, 2018
629
if(val.__class__ === $B.long_int){
Mar 19, 2018
630
ret = $B.long_int.to_base(val, 16)
631
}else{
632
ret = parseInt(val)
633
ret = ret.toString(16)
634
}
635
ret = format_int_precision(ret, flags)
Mar 19, 2018
636
if(upper){ret = ret.toUpperCase()}
Mar 23, 2018
637
if(flags.pad_char === "0"){
Mar 19, 2018
638
if(val < 0){
639
ret = ret.substring(1)
Mar 19, 2018
640
ret = "-" + format_padding(ret, flags, true)
641
}
642
var sign = format_sign(val, flags)
Mar 19, 2018
643
if(sign !== ""){
644
ret = sign + format_padding(ret, flags, true)
Sep 5, 2014
645
}
Mar 19, 2018
648
if(flags.alternate){
649
if(ret.charAt(0) === "-"){
650
if(upper){ret = "-0X" + ret.slice(1)}
651
else{ret = "-0x" + ret.slice(1)}
652
}else{
653
if(upper){ret = "0X" + ret}
654
else{ret = "0x" + ret}
655
}
656
}
657
return format_padding(format_sign(val, flags) + ret, flags)
658
}
Sep 5, 2014
659
660
var octal_format = function(val, flags) {
661
number_check(val)
Mar 19, 2018
664
if(val.__class__ === $B.long_int){
665
ret = $B.long_int.to_base(8)
666
}else{
667
ret = parseInt(val)
668
ret = ret.toString(8)
671
ret = format_int_precision(ret, flags)
Mar 19, 2018
673
if(flags.pad_char === "0"){
674
if(val < 0){
675
ret = ret.substring(1)
Mar 19, 2018
676
ret = "-" + format_padding(ret, flags, true)
677
}
678
var sign = format_sign(val, flags)
Mar 19, 2018
679
if(sign !== ""){
680
ret = sign + format_padding(ret, flags, true)
681
}
Sep 5, 2014
682
}
Mar 19, 2018
684
if(flags.alternate){
685
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
686
else{ret = "0o" + ret}
Sep 5, 2014
687
}
688
return format_padding(ret, flags)
689
}
690
691
function series_of_bytes(val, flags){
692
if(val.__class__ && val.__class__.$buffer_protocol){
693
var it = _b_.iter(val),
694
ints = []
695
while(true){
696
try{
697
ints.push(_b_.next(it))
698
}catch(err){
699
if(err.__class__ === _b_.StopIteration){
700
var b = _b_.bytes.$factory(ints)
701
return format_padding(_b_.bytes.decode(b, "ascii"), flags)
702
}
703
throw err
704
}
705
}
706
}else{
707
try{
708
bytes_obj = $B.$getattr(val, "__bytes__")
709
return format_padding(_b_.bytes.decode(bytes_obj), flags)
710
}catch(err){
711
if(err.__class__ === _b_.AttributeError){
712
throw _b_.TypeError.$factory("%b does not accept '" +
713
$B.class_name(val) + "'")
714
}
715
throw err
716
}
717
}
718
}
719
Mar 19, 2018
720
var single_char_format = function(val, flags){
721
if(_b_.isinstance(val, str) && val.length == 1){
723
}else if(_b_.isinstance(val, _b_.bytes) && val.source.length == 1){
724
val = val.source[0]
725
}else{
726
try{
727
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
728
}catch (err){
729
throw _b_.TypeError.$factory("%c requires int or char")
730
}
732
return format_padding(_b_.chr(val), flags)
733
}
734
Mar 19, 2018
735
var num_flag = function(c, flags){
736
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
737
flags.pad_char = "0"
738
return
739
}
Mar 19, 2018
740
if(!flags.decimal_point){
741
flags.padding = (flags.padding || "") + c
Mar 19, 2018
742
}else{
743
flags.precision = (flags.precision || "") + c
744
}
745
}
746
747
var decimal_point_flag = function(val, flags) {
Mar 23, 2018
748
if(flags.decimal_point){
749
// can only have one decimal point
750
throw new UnsupportedChar()
751
}
752
flags.decimal_point = true
753
}
754
Mar 19, 2018
755
var neg_flag = function(val, flags){
756
flags.pad_char = " " // overrides '0' flag
757
flags.left = true
758
}
759
Mar 19, 2018
760
var space_flag = function(val, flags){
761
flags.space = true
762
}
763
Mar 19, 2018
764
var sign_flag = function(val, flags){
765
flags.sign = true
766
}
767
Mar 19, 2018
768
var alternate_flag = function(val, flags){
769
flags.alternate = true
770
}
771
772
var char_mapping = {
Mar 19, 2018
774
"s": str_format,
775
"d": num_format,
776
"i": num_format,
777
"u": num_format,
778
"o": octal_format,
779
"r": repr_format,
780
"a": ascii_format,
781
"g": function(val, flags){
782
return floating_point_format(val, false, flags)
783
},
784
"G": function(val, flags){return floating_point_format(val, true, flags)},
785
"f": function(val, flags){
786
return floating_point_decimal_format(val, false, flags)
787
},
788
"F": function(val, flags){
789
return floating_point_decimal_format(val, true, flags)
790
},
791
"e": function(val, flags){
792
return floating_point_exponential_format(val, false, flags)
793
},
794
"E": function(val, flags){
795
return floating_point_exponential_format(val, true, flags)
796
},
797
"x": function(val, flags){return signed_hex_format(val, false, flags)},
798
"X": function(val, flags){return signed_hex_format(val, true, flags)},
799
"c": single_char_format,
800
"0": function(val, flags){return num_flag("0", flags)},
801
"1": function(val, flags){return num_flag("1", flags)},
802
"2": function(val, flags){return num_flag("2", flags)},
803
"3": function(val, flags){return num_flag("3", flags)},
804
"4": function(val, flags){return num_flag("4", flags)},
805
"5": function(val, flags){return num_flag("5", flags)},
806
"6": function(val, flags){return num_flag("6", flags)},
807
"7": function(val, flags){return num_flag("7", flags)},
808
"8": function(val, flags){return num_flag("8", flags)},
809
"9": function(val, flags){return num_flag("9", flags)},
810
"-": neg_flag,
811
" ": space_flag,
812
"+": sign_flag,
813
".": decimal_point_flag,
814
"#": alternate_flag
815
}
816
817
// exception thrown when an unsupported char is encountered in legacy format
Mar 19, 2018
818
var UnsupportedChar = function(){
819
this.name = "UnsupportedChar"
820
}
821
822
str.__mod__ = function(self, args){
823
var length = self.length,
Mar 19, 2018
824
pos = 0 | 0,
825
argpos = null,
826
getitem
Mar 19, 2018
827
if(_b_.isinstance(args, _b_.tuple)){
828
argpos = 0 | 0
830
getitem = $B.$getattr(args, "__getitem__", _b_.None)
831
}
832
var ret = ''
833
var $get_kwarg_string = function(s) {
834
// returns [self, newpos]
835
++pos
836
var rslt = kwarg_key.exec(s.substring(newpos))
Mar 19, 2018
837
if(! rslt){
838
throw _b_.ValueError.$factory("incomplete format key")
839
}
840
var key = rslt[1]
841
newpos += rslt[0].length
Mar 23, 2018
842
try{
843
var self = getitem(key)
Mar 19, 2018
844
}catch(err){
845
if(err.__class__ === _b_.KeyError){
846
throw err
847
}
848
throw _b_.TypeError.$factory("format requires a mapping")
850
return get_string_value(s, self)
851
}
852
853
var $get_arg_string = function(s) {
854
// returns [self, newpos]
855
var self
857
// non-tuple args
Mar 19, 2018
858
if(argpos === null){
859
// args is the value
Mar 19, 2018
861
}else{
862
self = args[argpos++]
Mar 19, 2018
863
if(self === undefined){
864
throw _b_.TypeError.$factory(
865
"not enough arguments for format string")
Sep 5, 2014
866
}
867
}
868
return get_string_value(s, self)
870
var get_string_value = function(s, self) {
871
// todo: get flags, type
872
// todo: string value based on flags, type, value
Mar 19, 2018
873
var flags = {"pad_char": " "}
874
do{
875
var func = char_mapping[s[newpos]]
Mar 23, 2018
876
try{
Mar 19, 2018
877
if(func === undefined){
878
throw new UnsupportedChar()
Mar 19, 2018
879
}else{
880
var ret = func(self, flags)
Mar 19, 2018
881
if(ret !== undefined){
882
return ret
883
}
884
++newpos
885
}
Mar 19, 2018
886
}catch (err){
887
if(err.name == "UnsupportedChar"){
888
invalid_char = s[newpos]
Mar 19, 2018
889
if(invalid_char === undefined){
890
throw _b_.ValueError.$factory("incomplete format")
Mar 19, 2018
892
throw _b_.ValueError.$factory(
893
"unsupported format character '" + invalid_char +
894
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
895
") at index " + newpos)
896
}else if(err.name === "NotANumber"){
897
var try_char = s[newpos],
898
cls = self.__class__
899
if(!cls){
900
if(typeof(self) === "string"){
901
cls = "str"
902
}else{
903
cls = typeof(self)
Mar 19, 2018
905
}else{
Mar 19, 2018
908
throw _b_.TypeError.$factory("%" + try_char +
909
" format: a number is required, not " + cls)
910
}else{
911
throw err
912
}
Sep 5, 2014
913
}
Mar 19, 2018
914
}while (true)
Sep 5, 2014
915
}
916
var nbph = 0 // number of placeholders
Mar 19, 2018
917
do{
918
var newpos = self.indexOf("%", pos)
919
if(newpos < 0){
920
ret += self.substring(pos)
921
break
922
}
923
ret += self.substring(pos, newpos)
924
++newpos
Mar 19, 2018
925
if(newpos < length){
926
if(self[newpos] === "%"){
927
ret += "%"
928
}else{
Mar 19, 2018
930
if(self[newpos] === "("){
931
++newpos
932
ret += $get_kwarg_string(self)
Mar 23, 2018
933
}else{
934
ret += $get_arg_string(self)
935
}
936
}
Mar 19, 2018
937
}else{
938
// % at end of string
939
throw _b_.ValueError.$factory("incomplete format")
940
}
941
pos = newpos + 1
Mar 19, 2018
942
}while(pos < length)
943
944
if(argpos !== null){
945
if(args.length > argpos){
946
throw _b_.TypeError.$factory(
947
"not enough arguments for format string")
948
}else if(args.length < argpos){
949
throw _b_.TypeError.$factory(
950
"not all arguments converted during string formatting")
Mar 19, 2018
952
}else if(nbph == 0){
953
throw _b_.TypeError.$factory(
954
"not all arguments converted during string formatting")
Sep 5, 2014
958
Sep 5, 2014
960
str
Feb 10, 2018
961
str.__mul__ = function(){
Mar 19, 2018
962
var $ = $B.args("__mul__", 2, {self: null, other: null},
963
["self", "other"], arguments, {}, null, null)
964
if(! _b_.isinstance($.other, _b_.int)){throw _b_.TypeError.$factory(
Mar 19, 2018
965
"Can't multiply sequence by non-int of type '" +
967
return $.self.valueOf().repeat($.other)
Sep 5, 2014
968
}
969
970
str.__ne__ = function(self, other){
971
return other.valueOf() !== self.valueOf()
Sep 5, 2014
973
974
function __newobj__(){
975
// __newobj__ is called with a generator as only argument
976
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
977
args = $.args
978
var res = args[1]
979
res.__class__ = args[0]
980
return res
981
}
982
983
str.__reduce_ex__ = function(self){
984
return $B.fast_tuple([
985
__newobj__,
986
$B.fast_tuple([self.__class__ || _b_.str, self]),
987
_b_.None,
988
_b_.None])
989
}
990
str
Feb 10, 2018
991
str.__repr__ = function(self){
993
var t = {
994
8: "\\x08",
995
9: "\\t",
996
10: "\\n",
997
11: "\\x0b",
998
12: "\\x0c",
999
13: "\\r",
1000
92: "\\\\"
1001
}
1002
var repl = '',
1003
chars = to_chars(self)
1004
for(var i = 0; i < chars.length; i++){
1005
var cp = _b_.ord(chars[i])
1006
if(t[cp] !== undefined){
1007
repl += t[cp]
1008
}else if($B.is_unicode_cn(cp)){
1009
var s = cp.toString(16)
1010
while(s.length < 4){
1011
s = '0' + s
1012
}
1013
repl += '\\u' + s
1014
}else if(cp < 0x20 || (cp >= 0x7f && cp < 0xa0)){
1015
cp = cp.toString(16)
1016
if(cp.length < 2){
1017
cp = '0' + cp
1018
}
1019
repl += '\\x' + cp
1020
}else if(cp >= 0x300 && cp <= 0x36F){
1021
repl += "\u200B" + chars[i]
Mar 19, 2018
1027
if(res.search('"') == -1 && res.search("'") == -1){
1028
return "'" + res + "'"
1029
}else if(self.search('"') == -1){
1030
return '"' + res + '"'
1031
}
1032
var qesc = new RegExp("'", "g") // to escape single quote
1033
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
1034
return res
1035
}
1036
1037
str.__rmul__ = function(self, other){
1038
if(_b_.isinstance(other, _b_.int)){
1039
other = _b_.int.numerator(other)
1040
var res = ''
1041
while(other > 0){
1042
res += self
1043
other--
1044
}
1045
return res
1046
}
1047
return _b_.NotImplemented
1048
}
1049
1050
str.__setattr__ = function(self, attr, value){
1051
if(typeof self === "string"){
1052
if(str.hasOwnProperty(attr)){
1053
throw _b_.AttributeError.$factory("'str' object attribute '" +
1054
attr + "' is read-only")
1055
}else{
1056
throw _b_.AttributeError.$factory(
1057
"'str' object has no attribute '" + attr + "'")
1058
}
1059
}
1060
// str subclass : use __dict__
1061
_b_.dict.$setitem(self.__dict__, attr, value)
1062
return $N
1063
}
1064
Mar 19, 2018
1065
str.__setitem__ = function(self, attr, value){
1066
throw _b_.TypeError.$factory(
1067
"'str' object does not support item assignment")
Sep 5, 2014
1068
}
Mar 27, 2019
1070
var combining = []
1071
for(var cp = 0x300; cp <= 0x36F; cp++){
1072
combining.push(String.fromCharCode(cp))
1073
}
1074
var combining_re = new RegExp("(" + combining.join("|") + ")", "g")
str
Feb 10, 2018
1076
str.__str__ = function(self){
1077
var repl = '',
1078
chars = to_chars(self)
1079
if(chars.length == self.length){
1080
return self.replace(combining_re, "\u200B$1")
1081
}
1082
for(var i = 0; i < chars.length; i++){
1083
var cp = _b_.ord(chars[i])
1084
if(cp >= 0x300 && cp <= 0x36F){
1085
repl += "\u200B" + chars[i]
1086
}else{
1087
repl += chars[i]
1088
}
1089
}
1090
return repl
Sep 5, 2014
1091
}
Mar 19, 2018
1093
str.toString = function(){return "string!"}
Sep 5, 2014
1094
1095
// generate comparison methods
1096
var $comp_func = function(self,other){
1097
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
1098
return self > other
1099
}
Mar 19, 2018
1100
$comp_func += "" // source code
1101
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
1102
for(var $op in $comps){
Mar 19, 2018
1103
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
1104
}
1105
1106
// unsupported operations
Mar 19, 2018
1107
var $notimplemented = function(self, other){
1108
throw _b_.NotImplementedError.$factory(
Mar 19, 2018
1109
"OPERATOR not implemented for class str")
Sep 5, 2014
1110
}
1111
1112
str.capitalize = function(self){
1113
var $ = $B.args("capitalize", 1, {self}, ["self"],
1114
arguments, {}, null, null)
1115
if(self.length == 0){
1116
return ""
1117
}
1118
return self.charAt(0).toUpperCase() + self.substr(1)
1119
}
1120
1121
str.casefold = function(self){
1122
var $ = $B.args("casefold", 1, {self}, ["self"],
1123
arguments, {}, null, null),
1124
res = "",
1125
char,
1126
cf,
1127
chars = to_chars($.self)
1128
1129
for(var i = 0, len = chars.length; i < len; i++){
1130
char = chars[i]
1131
cf = $B.unicode_casefold[char]
1132
if(cf){
1133
cf.forEach(function(cp){
1134
res += String.fromCharCode(cp)
1135
})
1136
}else{
1138
}
1139
}
1140
return res
1141
}
Sep 5, 2014
1142
Mar 19, 2018
1143
str.center = function(){
1144
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
1145
["self", "width", "fillchar"],
1146
arguments, {fillchar:" "}, null, null),
1147
self = $.self
Mar 19, 2018
1149
if($.width <= self.length) {return self}
Mar 19, 2018
1151
var pad = parseInt(($.width - self.length) / 2),
1152
res = $.fillchar.repeat(pad)
Sep 5, 2014
1153
res += self + res
1154
if(res.length < $.width){
1155
res += $.fillchar
1156
}
Sep 5, 2014
1157
return res
1158
}
1159
str
Feb 10, 2018
1160
str.count = function(){
Mar 19, 2018
1161
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
1162
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
1164
if(!(typeof $.sub.valueOf() == "string")){
1165
throw _b_.TypeError.$factory("Can't convert '" + $B.class_name($.sub) +
1166
"' object to str implicitly")
1167
}
Mar 19, 2018
1169
if($.start !== null){
1171
if($.stop !== null){
1172
_slice = _b_.slice.$factory($.start, $.stop)
1173
}else{
1174
_slice = _b_.slice.$factory($.start, $.self.length)
1175
}
str
Feb 10, 2018
1176
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
1178
if($.self.length + $.sub.length == 0){
1179
return 1
1180
}
Mar 19, 2018
1182
if($.sub.length == 0){
1183
if($.start == $.self.length){
1184
return 1
1185
}else if(substr.length == 0){
1186
return 0
1187
}
Mar 19, 2018
1188
return substr.length + 1
Mar 19, 2018
1190
var n = 0,
1191
pos = 0
1192
while(pos < substr.length){
1193
pos = substr.indexOf($.sub, pos)
1194
if(pos >= 0){
1195
n++
1196
pos += $.sub.length
1197
}else{
1198
break
1199
}
Sep 5, 2014
1200
}
1201
return n
1202
}
1203
1204
str.encode = function(){
1205
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
1206
["self", "encoding", "errors"], arguments,
1207
{encoding: "utf-8", errors: "strict"}, null, null)
1208
if($.encoding == "rot13" || $.encoding == "rot_13"){
1209
// Special case : returns a string
Mar 19, 2018
1210
var res = ""
1211
for(var i = 0, len = $.self.length; i < len ; i++){
1212
var char = $.self.charAt(i)
Mar 19, 2018
1213
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
1214
res += String.fromCharCode(String.charCodeAt(char) + 13)
1215
}else if(("m" < char && char <= "z") ||
1216
("M" < char && char <= "Z")){
1217
res += String.fromCharCode(String.charCodeAt(char) - 13)
1218
}else{res += char}
1219
}
1220
return res
1221
}
1222
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
Sep 5, 2014
1223
}
1224
str
Feb 10, 2018
1225
str.endswith = function(){
1226
// Return True if the string ends with the specified suffix, otherwise
1227
// return False. suffix can also be a tuple of suffixes to look for.
1228
// With optional start, test beginning at that position. With optional
Sep 5, 2014
1229
// end, stop comparing at that position.
Mar 19, 2018
1230
var $ = $B.args("endswith", 4,
1231
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
1232
["self", "suffix", "start", "end"],
1233
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
1234
1235
normalize_start_end($)
1236
1237
var suffixes = $.suffix
1238
if(! _b_.isinstance(suffixes,_b_.tuple)){
1239
suffixes = [suffixes]
1240
}
1242
var chars = to_chars($.self),
1243
s = chars.slice($.start, $.end)
Mar 19, 2018
1244
for(var i = 0, len = suffixes.length; i < len; i++){
1245
var suffix = suffixes[i]
1246
if(! _b_.isinstance(suffix, str)){
1247
throw _b_.TypeError.$factory(
1248
"endswith first arg must be str or a tuple of str, not int")
1249
}
Mar 19, 2018
1250
if(suffix.length <= s.length &&
1251
s.slice(s.length - suffix.length).join('') == suffix){
1252
return true
1253
}
Sep 5, 2014
1254
}
1255
return false
1256
}
1257
str
Feb 10, 2018
1258
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
1259
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1260
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1261
var s = $B.$GetInt($.tabsize),
1262
col = 0,
1263
pos = 0,
1264
res = "",
1265
chars = to_chars(self)
1266
if(s == 1){
1267
return self.replace(/\t/g," ")
1268
}
1269
while(pos < chars.length){
1270
var car = chars[pos]
Mar 19, 2018
1272
case "\t":
1273
while(col % s > 0){
1274
res += " ";
1275
col++
1276
}
Mar 19, 2018
1278
case "\r":
1279
case "\n":
1280
res += car
1281
col = 0
1282
break
1283
default:
1284
res += car
1285
col++
1286
break
1287
}
1288
pos++
1289
}
1290
return res
Sep 5, 2014
1291
}
1292
str
Feb 10, 2018
1293
str.find = function(){
1294
// Return the lowest index in the string where substring sub is found,
1295
// such that sub is contained in the slice s[start:end]. Optional
1296
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1297
// Return -1 if sub is not found.
Mar 19, 2018
1298
var $ = $B.args("str.find", 4,
1299
{self: null, sub: null, start: null, end: null},
1300
["self", "sub", "start", "end"],
1301
arguments, {start: 0, end: null}, null, null)
1302
check_str($.sub)
1305
var len = str.__len__($.self),
1306
sub_len = str.__len__($.sub)
1308
if(sub_len == 0 && $.start == len){
1311
if(len + sub_len == 0){
1314
// Use .indexOf(), not .search(), to avoid conversion to reg exp
1315
var js_start = pypos2jspos($.self, $.start),
1316
js_end = pypos2jspos($.self, $.end),
1317
ix = $.self.substring(js_start, js_end).indexOf($.sub)
1318
if(ix == -1){
1319
return -1
Sep 5, 2014
1320
}
1321
return jspos2pypos($.self, js_start + ix)
Sep 5, 2014
1322
}
1323
1324
// Next function used by method .format()
1325
1326
$B.parse_format = function(fmt_string){
Sep 5, 2014
1327
1328
// Parse a "format string", as described in the Python documentation
1329
// Return a format object. For the format string
1330
// a.x[z]!r:...
1331
// the object has attributes :
1332
// - name : "a"
1333
// - name_ext : [".x", "[z]"]
1334
// - conv : r
1335
// - spec : rest of string after :
Sep 5, 2014
1336
Mar 19, 2018
1337
var elts = fmt_string.split(":"),
1338
name,
1339
conv,
1340
spec,
Mar 19, 2018
1341
name_ext = []
Mar 19, 2018
1342
if(elts.length == 1){
1343
// No : in the string : it only contains a name
1344
name = fmt_string
1345
}else{
1346
// name is before the first ":"
1347
// spec (the format specification) is after
1348
name = elts[0]
Mar 19, 2018
1349
spec = elts.splice(1).join(":")
Mar 19, 2018
1352
var elts = name.split("!")
1353
if(elts.length > 1){
1354
name = elts[0]
1355
conv = elts[1] // conversion flag
Sep 5, 2014
1357
Mar 19, 2018
1358
if(name !== undefined){
1359
// "name' may be a subscription or attribute
1360
// Put these "extensions" in the list "name_ext"
1361
function name_repl(match){
1362
name_ext.push(match)
Mar 19, 2018
1363
return ""
1364
}
1365
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1366
name = name.replace(name_ext_re, name_repl)
1367
}
Sep 5, 2014
1368
1369
return {name: name, name_ext: name_ext,
1370
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1372
1373
$B.split_format = function(self){
1374
// Parse self to detect formatting instructions
1375
// Create a list "parts" made of sections of the string :
1376
// - elements of even rank are literal text
1377
// - elements of odd rank are "format objects", built from the
1378
// format strings in self (of the form {...})
Mar 19, 2018
1379
var pos = 0,
1380
_len = self.length,
Mar 19, 2018
1382
text = "",
1383
parts = [],
1384
rank = 0
1385
while(pos < _len){
1386
car = self.charAt(pos)
Mar 21, 2018
1387
if(car == "{" && self.charAt(pos + 1) == "{"){
1388
// replace {{ by literal {
Mar 19, 2018
1389
text += "{"
1390
pos += 2
1391
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1392
// replace }} by literal }
Mar 19, 2018
1393
text += "}"
1394
pos += 2
1395
}else if(car == "{"){
1396
// Start of a format string
1398
// Store current literal text
1399
parts.push(text)
1400
1401
// Search the end of the format string, ie the } closing the
1402
// opening {. Since the string can contain other pairs {} for
1403
// nested formatting, an integer nb is incremented for each { and
1404
// decremented for each } ; the end of the format string is
Mar 19, 2018
1405
// reached when nb == 0
1406
var end = pos + 1,
1407
nb = 1
1408
while(end < _len){
1409
if(self.charAt(end) == "{"){nb++; end++}
1410
else if(self.charAt(end) == "}"){
1411
nb--; end++
1412
if(nb == 0){
1413
// End of format string
Mar 19, 2018
1414
var fmt_string = self.substring(pos + 1, end - 1)
1415
1416
// Create a format object, by function parse_format
1417
var fmt_obj = $B.parse_format(fmt_string)
1418
fmt_obj.raw_name = fmt_obj.name
1419
fmt_obj.raw_spec = fmt_obj.spec
1420
1421
// If no name is explicitely provided, use the rank
1422
if(!fmt_obj.name){
Mar 19, 2018
1423
fmt_obj.name = rank + ""
Sep 5, 2014
1426
Mar 19, 2018
1427
if(fmt_obj.spec !== undefined){
1428
// "spec" may contain "nested replacement fields"
1429
// Replace empty fields by the rank in positional
1430
// arguments
1431
function replace_nested(name, key){
1432
if(key == ""){
1433
// Use implicit rank
1434
return "{" + rank++ + "}"
1438
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1439
replace_nested)
1440
}
1442
// Store format object in list "parts"
1443
parts.push(fmt_obj)
Mar 19, 2018
1444
text = ""
1445
break
1446
}
1447
}else{end++}
Sep 5, 2014
1448
}
1449
if(nb > 0){
1450
throw _b_.ValueError.$factory("wrong format " + self)
1451
}
1453
}else{
1454
text += car
1455
pos++
1456
}
1457
}
1458
if(text){
1459
parts.push(text)
Sep 5, 2014
1460
}
1461
return parts
1462
}
1463
1464
str.format = function(self) {
1465
// Special management of keyword arguments if str.format is called by
1466
// str.format_map(mapping) : the argument "mapping" might not be a
1467
// dictionary
1468
var last_arg = $B.last(arguments)
1469
if(last_arg.$nat == "mapping"){
1470
var mapping = last_arg.mapping,
1471
getitem = $B.$getattr(mapping, "__getitem__")
1472
// Get the rest of the arguments
1473
var args = []
1474
for(var i = 0, len = arguments.length - 1; i < len; i++){
1475
args.push(arguments[i])
1476
}
1477
var $ = $B.args("format", 1, {self: null}, ["self"],
1478
args, {}, "$args", null)
1479
}else{
1480
var $ = $B.args("format", 1, {self: null}, ["self"],
1481
arguments, {}, "$args", "$kw"),
1482
mapping = $.$kw, // dictionary
1483
getitem = function(key){
1484
return _b_.dict.$getitem(mapping, key)
1485
}
1486
}
1487
var parts = $B.split_format($.self)
1488
1489
// Apply formatting to the values passed to format()
Mar 19, 2018
1490
var res = "",
1491
fmt
Mar 19, 2018
1493
for(var i = 0; i < parts.length; i++){
1494
// Literal text is added unchanged
1495
if(typeof parts[i] == "string"){
1496
res += parts[i];
1497
continue
1498
}
1500
// Format objects
1501
fmt = parts[i]
1502
1503
if(fmt.spec !== undefined){
1504
// "spec" may contain "nested replacement fields"
1505
// In this case, evaluate them using the positional
1506
// or keyword arguments passed to format()
1507
function replace_nested(name, key){
1508
if(/\d+/.exec(key)){
1509
// If key is numeric, search in positional
1510
// arguments
1511
return _b_.tuple.__getitem__($.$args,
1512
parseInt(key))
1513
}else{
1514
// Else try in keyword arguments
1515
return _b_.dict.__getitem__($.$kw, key)
1516
}
1517
}
1518
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1519
replace_nested)
1520
}
Mar 21, 2018
1521
if(fmt.name.charAt(0).search(/\d/) > -1){
1522
// Numerical reference : use positional arguments
1523
var pos = parseInt(fmt.name),
Feb 11, 2018
1524
value = _b_.tuple.__getitem__($.$args, pos)
1525
}else{
1526
// Use keyword arguments
1527
var value = getitem(fmt.name)
1528
}
1529
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1530
for(var j = 0; j < fmt.name_ext.length; j++){
1531
var ext = fmt.name_ext[j]
Mar 19, 2018
1532
if(ext.charAt(0) == "."){
1534
value = $B.$getattr(value, ext.substr(1))
1535
}else{
1536
// Subscription
Mar 19, 2018
1537
var key = ext.substr(1, ext.length - 2)
1538
// An index made of digits is transformed into an integer
Mar 19, 2018
1539
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1540
value = $B.$getattr(value, "__getitem__")(key)
Feb 12, 2018
1543
1544
// If the conversion flag is set, first call a function to convert
1545
// the value
Mar 19, 2018
1546
if(fmt.conv == "a"){value = _b_.ascii(value)}
1547
else if(fmt.conv == "r"){value = _b_.repr(value)}
1548
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1550
// Call attribute __format__ to perform the actual formatting
1551
if(value.$is_class || value.$factory){
1552
// For classes, don't use the class __format__ method
1553
res += value.__class__.__format__(value, fmt.spec)
1555
res += $B.$getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1557
}
Sep 5, 2014
1559
}
1560
1561
str.format_map = function(self, mapping){
1562
var $ = $B.args("format_map", 2, {self: null, mapping: null},
1563
['self', 'mapping'], arguments, {}, null, null)
1564
return str.format(self, {$nat: 'mapping', mapping})
Sep 5, 2014
1565
}
1566
str
Feb 10, 2018
1567
str.index = function(self){
Sep 5, 2014
1568
// Like find(), but raise ValueError when the substring is not found.
1569
var res = str.find.apply(null, arguments)
1570
if(res === -1){
1571
throw _b_.ValueError.$factory("substring not found")
1572
}
Sep 5, 2014
1573
return res
1574
}
1575
1576
str.isascii = function(self){
1577
/* Return true if the string is empty or all characters in the string are
1578
ASCII, false otherwise. ASCII characters have code points in the range
1579
U+0000-U+007F. */
1580
for(var i = 0, len = self.length; i < len; i++){
1581
if(self.charCodeAt(i) > 127){
1582
return false
1583
}
1584
}
1585
return true
1586
}
1587
1588
str.isalnum = function(self){
1589
/* Return true if all characters in the string are alphanumeric and there
1590
is at least one character, false otherwise. A character c is alphanumeric
1591
if one of the following returns True: c.isalpha(), c.isdecimal(),
1592
c.isdigit(), or c.isnumeric(). */
1593
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1594
arguments, {}, null, null),
1595
cp
1596
for(var char of to_chars(self)){
1597
cp = _b_.ord(char)
1598
if(unicode_tables.Ll[cp] ||
1599
unicode_tables.Lu[cp] ||
1600
unicode_tables.Lm[cp] ||
1601
unicode_tables.Lt[cp] ||
1602
unicode_tables.Lo[cp] ||
1603
unicode_tables.Nd[cp] ||
1604
unicode_tables.digits[cp] ||
1605
unicode_tables.numeric[cp]){
1606
continue
1607
}
1608
return false
1609
}
1610
return true
1611
}
1612
1613
str.isalpha = function(self){
1614
/* Return true if all characters in the string are alphabetic and there is
1615
at least one character, false otherwise. Alphabetic characters are those
1616
characters defined in the Unicode character database as "Letter", i.e.,
1617
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1618
or "Lo". */
1619
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1620
arguments, {}, null, null),
1621
cp
1622
for(var char of to_chars(self)){
1623
cp = _b_.ord(char)
1624
if(unicode_tables.Ll[cp] ||
1625
unicode_tables.Lu[cp] ||
1626
unicode_tables.Lm[cp] ||
1627
unicode_tables.Lt[cp] ||
1628
unicode_tables.Lo[cp]){
1629
continue
1630
}
1631
return false
1632
}
1633
return true
1634
}
1635
1636
str.isdecimal = function(self){
1637
/* Return true if all characters in the string are decimal characters and
1638
there is at least one character, false otherwise. Decimal characters are
1639
those that can be used to form numbers in base 10, e.g. U+0660,
1640
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1641
the Unicode General Category "Nd". */
1642
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1643
arguments, {}, null, null),
1644
cp
1645
for(var char of to_chars(self)){
1646
cp = _b_.ord(char)
1647
if(! unicode_tables.Nd[cp]){
1648
return false
1649
}
1650
}
1651
return self.length > 0
1652
}
1653
1654
str.isdigit = function(self){
1655
/* Return true if all characters in the string are digits and there is at
1656
least one character, false otherwise. */
1657
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1658
arguments, {}, null, null),
1659
cp
1660
for(var char of to_chars(self)){
1661
cp = _b_.ord(char)
1662
if(! unicode_tables.digits[cp]){
1663
return false
1664
}
1665
}
1666
return self.length > 0
1667
}
1668
1669
str.isidentifier = function(self){
1670
/* Return true if the string is a valid identifier according to the
1671
language definition. */
1672
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1674
if(self.length == 0){
1675
return false
1676
}
1677
var chars = to_chars(self)
1678
if(unicode_tables.XID_Start[_b_.ord(chars[0])] === undefined){
1681
for(var char of chars){
1682
var cp = _b_.ord(char)
1683
if(unicode_tables.XID_Continue[cp] === undefined){
1684
return false
1685
}
1686
}
1687
}
1688
return true
1689
}
1690
1691
str.islower = function(self){
1692
/* Return true if all cased characters 4 in the string are lowercase and
1693
there is at least one cased character, false otherwise. */
1694
var $ = $B.args("islower", 1, {self: null}, ["self"],
1695
arguments, {}, null, null),
1696
has_cased = false,
1699
for(var char of to_chars(self)){
1700
cp = _b_.ord(char)
1701
if(unicode_tables.Ll[cp]){
1702
has_cased = true
1703
continue
1704
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
1705
return false
1706
}
1707
}
1708
return has_cased
1709
}
1710
1711
str.isnumeric = function(self){
1712
/* Return true if all characters in the string are numeric characters, and
1713
there is at least one character, false otherwise. Numeric characters
1714
include digit characters, and all characters that have the Unicode numeric
1715
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1716
characters are those with the property value Numeric_Type=Digit,
1717
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1718
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1719
arguments, {}, null, null)
1720
for(var char of to_chars(self)){
1721
if(! unicode_tables.numeric[_b_.ord(char)]){
1722
return false
1723
}
1724
}
1725
return self.length > 0
1726
}
1727
1728
var unprintable = {},
1729
unprintable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1730
1731
str.isprintable = function(self){
1732
/* Return true if all characters in the string are printable or the string
1733
is empty, false otherwise. Nonprintable characters are those characters
1734
defined in the Unicode character database as "Other" or "Separator",
1735
excepting the ASCII space (0x20) which is considered printable. */
1736
1737
// Set unprintable if not set yet
1738
if(Object.keys(unprintable).length == 0){
1739
for(var i = 0; i < unprintable_gc.length; i++){
1740
var table = unicode_tables[unprintable_gc[i]]
1742
unprintable[cp] = true
1745
unprintable[32] = true
1746
}
1747
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1748
arguments, {}, null, null)
1749
for(var char of to_chars(self)){
1750
if(unprintable[_b_.ord(char)]){
1751
return false
1752
}
1753
}
1754
return true
1755
}
1756
1757
str.isspace = function(self){
1758
/* Return true if there are only whitespace characters in the string and
1759
there is at least one character, false otherwise.
1760
1761
A character is whitespace if in the Unicode character database, either its
1762
general category is Zs ("Separator, space"), or its bidirectional class is
1763
one of WS, B, or S.*/
1764
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1765
arguments, {}, null, null),
1766
cp
1767
for(var char of to_chars(self)){
1768
cp = _b_.ord(char)
1769
if(! unicode_tables.Zs[cp] &&
1770
$B.unicode_bidi_whitespace.indexOf(cp) == -1){
1771
return false
1772
}
1773
}
1774
return self.length > 0
1775
}
1776
1777
str.istitle = function(self){
1778
/* Return true if the string is a titlecased string and there is at least
1779
one character, for example uppercase characters may only follow uncased
1780
characters and lowercase characters only cased ones. Return false
1781
otherwise. */
1782
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1783
arguments, {}, null, null)
1784
return self.length > 0 && str.title(self) == self
1785
}
1786
1787
str.isupper = function(self){
1788
/* Return true if all cased characters 4 in the string are lowercase and
1789
there is at least one cased character, false otherwise. */
1790
var $ = $B.args("islower", 1, {self: null}, ["self"],
1791
arguments, {}, null, null),
1795
for(var char of to_chars(self)){
1796
cp = _b_.ord(char)
1797
if(unicode_tables.Lu[cp]){
1798
is_upper = true
1799
continue
1800
}else if(unicode_tables.Ll[cp] || unicode_tables.Lt[cp]){
str
Feb 10, 2018
1808
str.join = function(){
Mar 19, 2018
1809
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1810
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1812
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1813
res = [],
Sep 5, 2014
1815
while(1){
1816
try{
1817
var obj2 = _b_.next(iterable)
1818
if(! _b_.isinstance(obj2, str)){
1819
throw _b_.TypeError.$factory("sequence item " + count +
1820
": expected str instance, " + $B.class_name(obj2) +
1821
" found")
1822
}
1823
res.push(obj2)
Sep 5, 2014
1824
}catch(err){
1825
if(_b_.isinstance(err, _b_.StopIteration)){
1826
break
1827
}
Sep 5, 2014
1828
else{throw err}
1829
}
1830
}
1831
return res.join($.self)
Sep 5, 2014
1832
}
1833
str
Feb 10, 2018
1834
str.ljust = function(self) {
Mar 19, 2018
1835
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1836
["self", "width", "fillchar"],
1837
arguments, {fillchar: " "}, null, null),
1838
len = str.__len__(self)
1840
if($.width <= len){
1841
return self
1842
}
1843
return self + $.fillchar.repeat($.width - len)
Sep 5, 2014
1844
}
1845
1846
str.lower = function(self){
1847
var $ = $B.args("lower", 1, {self: null}, ["self"],
1848
arguments, {}, null, null)
1849
return self.toLowerCase()
1850
}
1851
1852
str.lstrip = function(self, x){
Mar 19, 2018
1853
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1854
arguments, {chars:_b_.None}, null, null),
1855
self = $.self,
1856
chars = $.chars
1857
if(chars === _b_.None){
1858
return self.trimStart()
1860
while(self.length > 0){
1861
var flag = false
1862
for(var char of chars){
1863
if(self.startsWith(char)){
1864
self = self.substr(char.length)
1865
flag = true
1866
break
1867
}
1868
}
1869
if(! flag){
1870
return $.self.surrogates ? $B.String(self) : self
Sep 5, 2014
1874
}
1875
1876
// note, maketrans should be a static function.
str
Feb 10, 2018
1877
str.maketrans = function() {
Mar 19, 2018
1878
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1879
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1883
if($.y === null && $.z === null){
1884
// If there is only one argument, it must be a dictionary mapping
1885
// Unicode ordinals (integers) or characters (strings of length 1) to
1886
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1887
// keys will then be converted to ordinals.
Mar 19, 2018
1888
if(! _b_.isinstance($.x, _b_.dict)){
1889
throw _b_.TypeError.$factory(
1890
"maketrans only argument must be a dict")
Feb 11, 2018
1892
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1893
for(var i = 0, len = items.length; i < len; i++){
1894
var k = items[i][0],
1895
v = items[i][1]
1896
if(! _b_.isinstance(k, _b_.int)){
1897
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1898
k = _b_.ord(k)
1899
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1900
" is not int or 1-char string")}
1901
}
Mar 19, 2018
1902
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1903
throw _b_.TypeError.$factory("dictionary value " + v +
1904
" is not None, integer or string")
1905
}
1906
_b_.dict.$setitem(_t, k, v)
1907
}
1908
return _t
1909
}else{
1910
// If there are two arguments, they must be strings of equal length,
1911
// and in the resulting dictionary, each character in x will be mapped
1912
// to the character at the same position in y
Mar 19, 2018
1913
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1914
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1915
}else if($.x.length !== $.y.length){
1916
throw _b_.TypeError.$factory(
1917
"maketrans arguments must be strings or same length")
1918
}else{
1919
var toNone = {}
Mar 19, 2018
1920
if($.z !== null){
1921
// If there is a third argument, it must be a string, whose
1922
// characters will be mapped to None in the result
Mar 19, 2018
1923
if(! _b_.isinstance($.z, _b_.str)){
1924
throw _b_.TypeError.$factory(
1925
"maketrans third argument must be a string")
Mar 19, 2018
1927
for(var i = 0, len = $.z.length; i < len; i++){
1928
toNone[_b_.ord($.z.charAt(i))] = true
1929
}
Mar 19, 2018
1931
for(var i = 0, len = $.x.length; i < len; i++){
1932
var key = _b_.ord($.x.charAt(i)),
1934
_b_.dict.$setitem(_t, key, value)
1935
}
1936
for(var k in toNone){
1937
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1938
}
1939
return _t
1940
}
1941
}
Sep 5, 2014
1942
}
1943
1944
str.maketrans.$type = "staticmethod"
1945
str
Feb 10, 2018
1946
str.partition = function() {
Mar 19, 2018
1947
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1948
arguments, {}, null, null)
1949
if($.sep == ""){
1950
throw _b_.ValueError.$factory("empty separator")
1951
}
Mar 19, 2018
1952
check_str($.sep)
1953
var chars = to_chars($.self),
1954
i = $.self.indexOf($.sep)
1955
if(i == -1){
1956
return _b_.tuple.$factory([$.self, "", ""])
1957
}
1958
return _b_.tuple.$factory([chars.slice(0, i).join(''), $.sep,
1959
chars.slice(i + $.sep.length).join('')])
Mar 19, 2018
1960
}
1961
1962
str.removeprefix = function(){
1963
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1964
["self", "prefix"], arguments, {}, null, null)
1965
if(!_b_.isinstance($.prefix, str)){
1966
throw _b_.ValueError.$factory("prefix should be str, not " +
1967
`'${$B.class_name($.prefix)}'`)
1968
}
1969
if(str.startswith($.self, $.prefix)){
1970
return $.self.substr($.prefix.length)
1971
}
1972
return $.self.substr(0)
1973
}
1974
1975
str.removesuffix = function(){
1976
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1977
["self", "suffix"], arguments, {}, null, null)
1978
if(!_b_.isinstance($.suffix, str)){
1979
throw _b_.ValueError.$factory("suffix should be str, not " +
1980
`'${$B.class_name($.prefix)}'`)
1981
}
1982
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1983
return $.self.substr(0, $.self.length - $.suffix.length)
1984
}
1985
return $.self.substr(0)
1986
}
1987
Mar 19, 2018
1988
function $re_escape(str){
1989
var specials = "[.*+?|()$^"
1990
for(var i = 0, len = specials.length; i < len; i++){
1991
var re = new RegExp("\\"+specials.charAt(i), "g")
1992
str = str.replace(re, "\\"+specials.charAt(i))
1993
}
1994
return str
Sep 5, 2014
1995
}
1996
str
Feb 10, 2018
1997
str.replace = function(self, old, _new, count) {
1998
// Replaces occurrences of 'old' by '_new'. Count references
1999
// the number of times to replace. In CPython, negative or undefined
2000
// values of count means replace all.
Mar 19, 2018
2001
var $ = $B.args("replace", 4,
2002
{self: null, old: null, $$new: null, count: null},
2003
["self", "old", "$$new", "count"],
2004
arguments, {count: -1}, null, null),
2005
count = $.count,
2006
self = $.self,
2007
old = $.old,
2008
_new = $.$$new
2009
// Validate type of old
2010
check_str(old, "replace() argument 1 ")
2011
check_str(_new, "replace() argument 2 ")
2012
// Validate instance type of 'count'
2013
if(! _b_.isinstance(count,[_b_.int, _b_.float])){
2014
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
2015
"' object cannot be interpreted as an integer")
2016
}else if(_b_.isinstance(count, _b_.float)){
Mar 19, 2018
2017
throw _b_.TypeError.$factory("integer argument expected, got float")
2018
}
2019
if(count == 0){
2020
return self
2021
}
2022
if(count.__class__ == $B.long_int){
2023
count = parseInt(count.value)
2024
}
Mar 19, 2018
2025
if(old == ""){
2026
if(_new == ""){
2027
return self
2028
}
2029
if(self == ""){
2030
return _new
2031
}
Mar 19, 2018
2032
var elts = self.split("")
2033
if(count > -1 && elts.length >= count){
2034
var rest = elts.slice(count).join("")
2035
return _new + elts.slice(0, count).join(_new) + rest
2036
}else{
2037
return _new + elts.join(_new) + _new
2038
}
Mar 19, 2018
2040
var elts = str.split(self, old, count)
Sep 5, 2014
2041
}
Mar 19, 2018
2043
var res = self,
2044
pos = -1
2045
if(old.length == 0){
Mar 19, 2018
2047
for(var i = 0; i < elts.length; i++){
2048
res += elts[i] + _new
Mar 19, 2018
2050
return res + rest
2053
if(count < 0){
2054
count = res.length
2055
}
Mar 19, 2018
2056
while(count > 0){
2057
pos = res.indexOf(old, pos)
2058
if(pos < 0){
2059
break
2060
}
Mar 19, 2018
2061
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
2062
pos = pos + _new.length
2063
count--
Mar 19, 2018
2065
return res
Sep 5, 2014
2066
}
2067
2068
str.rfind = function(self, substr){
2069
// Return the highest index in the string where substring sub is found,
2070
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
2071
// start and end are interpreted as in slice notation. Return -1 on failure.
Mar 19, 2018
2072
var $ = $B.args("rfind", 4,
Mar 19, 2018
2073
{self: null, sub: null, start: null, end: null},
2074
["self", "sub", "start", "end"],
2075
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
2076
2078
check_str($.sub)
2080
var len = str.__len__($.self),
2081
sub_len = str.__len__($.sub)
2082
2083
if(sub_len == 0){
2084
if($.js_start > len){
2085
return -1
2086
}else{
2087
return str.__len__($.self)
2088
}
2091
// Use .indexOf(), not .search(), to avoid conversion to reg exp
2092
var js_start = pypos2jspos($.self, $.start),
2093
js_end = pypos2jspos($.self, $.end),
2094
ix = $.self.substring(js_start, js_end).lastIndexOf($.sub)
2095
if(ix == -1){
2096
return -1
2098
return jspos2pypos($.self, js_start + ix) - $.start
Sep 5, 2014
2099
}
2100
str
Feb 10, 2018
2101
str.rindex = function(){
Sep 5, 2014
2102
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
2103
var res = str.rfind.apply(null, arguments)
2104
if(res == -1){
2105
throw _b_.ValueError.$factory("substring not found")
2106
}
Sep 5, 2014
2107
return res
2108
}
2109
str
Feb 10, 2018
2110
str.rjust = function(self) {
Mar 19, 2018
2111
var $ = $B.args("rjust",3,
2112
{self: null, width: null, fillchar: null},
2113
["self", "width", "fillchar"],
2114
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
2115
2116
var len = str.__len__(self)
2117
if($.width <= len){
2120
return $B.String($.fillchar.repeat($.width - len) + self)
Sep 5, 2014
2121
}
2122
str
Feb 10, 2018
2123
str.rpartition = function(self,sep) {
Mar 19, 2018
2124
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
2125
arguments, {}, null, null)
2126
check_str($.sep)
2127
var self = reverse($.self),
2128
sep = reverse($.sep)
Mar 19, 2018
2129
var items = str.partition(self, sep).reverse()
2130
for(var i = 0; i < items.length; i++){
2131
items[i] = items[i].split("").reverse().join("")
2132
}
2133
return items
Sep 5, 2014
2134
}
2135
str
Feb 10, 2018
2136
str.rsplit = function(self) {
Mar 19, 2018
2137
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
2138
["self", "sep", "maxsplit"], arguments,
2139
{sep: _b_.None, maxsplit: -1}, null, null),
2140
sep = $.sep
2141
2142
// Use split on the reverse of the string and of separator
2143
var rev_str = reverse($.self),
2144
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
2145
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
2147
// Reverse the list, then each string inside the list
2148
rev_res.reverse()
Mar 19, 2018
2149
for(var i = 0; i < rev_res.length; i++){
2150
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
2153
}
2154
Mar 19, 2018
2155
str.rstrip = function(self, x){
2156
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
2157
arguments, {chars: _b_.None}, null, null),
2158
self = $.self,
2159
chars = $.chars
2160
if(chars === _b_.None){
2161
return self.trimEnd()
2163
while(self.length > 0){
2164
var flag = false
2165
for(var char of chars){
2166
if(self.endsWith(char)){
2167
self = self.substr(0, self.length - char.length)
2168
flag = true
2169
break
2170
}
2171
}
2172
if(! flag){
2173
return $.self.surrogates ? $B.String(self) : self
Sep 5, 2014
2177
}
2178
str
Feb 10, 2018
2179
str.split = function(){
Mar 19, 2018
2180
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
2181
["self", "sep", "maxsplit"], arguments,
2182
{sep: _b_.None, maxsplit: -1}, null, null),
2183
sep = $.sep,
2184
maxsplit = $.maxsplit,
2185
self = $.self,
2186
pos = 0
2187
if(maxsplit.__class__ === $B.long_int){
2188
maxsplit = parseInt(maxsplit.value)
2189
}
2190
if(sep == ""){
2191
throw _b_.ValueError.$factory("empty separator")
2192
}
Mar 19, 2018
2194
if(sep === _b_.None){
Sep 5, 2014
2195
var res = []
2196
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){
2197
pos++
2198
}
2199
if(pos === self.length - 1){
2200
return [self]
2201
}
Mar 19, 2018
2202
var name = ""
Sep 5, 2014
2203
while(1){
Mar 19, 2018
2204
if(self.charAt(pos).search(/\s/) == -1){
2205
if(name == ""){
2206
name = self.charAt(pos)
2207
}else{
2208
name += self.charAt(pos)
2209
}
Sep 5, 2014
2210
}else{
Mar 19, 2018
2211
if(name !== ""){
Sep 5, 2014
2212
res.push(name)
Mar 19, 2018
2213
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
2214
res.pop()
Mar 19, 2018
2215
res.push(name + self.substr(pos))
Sep 5, 2014
2216
return res
2217
}
Mar 19, 2018
2218
name = ""
Sep 5, 2014
2219
}
2220
}
2221
pos++
Mar 19, 2018
2222
if(pos > self.length - 1){
2223
if(name){
2224
res.push(name)
2225
}
Sep 5, 2014
2226
break
2227
}
2228
}
2229
return res.map($B.String)
Sep 5, 2014
2230
}else{
Mar 19, 2018
2231
var res = [],
2232
s = "",
2233
seplen = sep.length
2234
if(maxsplit == 0){
2235
return [self]
2236
}
Mar 19, 2018
2237
while(pos < self.length){
2238
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
2241
if(maxsplit > -1 && res.length >= maxsplit){
2243
return res.map($B.String)
Mar 19, 2018
2245
s = ""
2246
}else{
2247
s += self.charAt(pos)
2248
pos++
Sep 5, 2014
2249
}
2250
}
2252
return res.map($B.String)
Sep 5, 2014
2253
}
2254
}
2255
2256
str.splitlines = function(self) {
2257
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
2258
['self','keepends'], arguments, {keepends: false},
2259
null, null)
2260
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
2261
throw _b_.TypeError('integer argument expected, got '+
2262
$B.get_class($.keepends).__name)
2263
}
2264
var keepends = _b_.int.$factory($.keepends),
2265
res = [],
2266
self = $.self,
2267
start = 0,
2268
pos = 0
2269
if(!self.length){
2270
return res
2271
}
2273
if(self.substr(pos, 2) == '\r\n'){
2274
res.push(self.slice(start, keepends ? pos + 2 : pos))
2275
start = pos = pos+2
2276
}else if(self[pos] == '\r' || self[pos] == '\n'){
2277
res.push(self.slice(start, keepends ? pos+1 : pos))
2278
start = pos = pos+1
2279
}else{
2280
pos++
2281
}
2282
}
2283
if(start < self.length){
2284
res.push(self.slice(start))
2285
}
2286
return res.map($B.String)
2287
}
Sep 5, 2014
2288
str
Feb 10, 2018
2289
str.startswith = function(){
2290
// Return True if string starts with the prefix, otherwise return False.
2291
// prefix can also be a tuple of prefixes to look for. With optional
2292
// start, test string beginning at that position. With optional end,
Sep 5, 2014
2293
// stop comparing string at that position.
Mar 19, 2018
2294
var $ = $B.args("startswith", 4,
2295
{self: null, prefix: null, start: null, end: null},
2296
["self", "prefix", "start", "end"],
2297
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
2298
2299
normalize_start_end($)
2300
2301
var prefixes = $.prefix
2302
if(! _b_.isinstance(prefixes, _b_.tuple)){
2303
prefixes = [prefixes]
2304
}
2305
var s = $.self.substring($.js_start, $.js_end)
2306
for(var prefix of prefixes){
2307
if(! _b_.isinstance(prefix, str)){
2308
throw _b_.TypeError.$factory("endswith first arg must be str " +
2309
"or a tuple of str, not int")
2310
}
2311
if(s.substr(0, prefix.length) == prefix){
2312
return true
2313
}
Sep 5, 2014
2314
}
2315
return false
2316
}
2317
str
Feb 10, 2018
2318
str.strip = function(){
Mar 19, 2018
2319
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
2320
arguments, {chars: _b_.None}, null, null)
2321
if($.chars === _b_.None){
2322
return $.self.trim()
2323
}
2324
return str.rstrip(str.lstrip($.self, $.chars), $.chars)
Sep 5, 2014
2325
}
2326
2327
str.swapcase = function(self){
2328
var $ = $B.args("swapcase", 1, {self}, ["self"],
2329
arguments, {}, null, null),
2330
res = "",
2331
cp
2332
2333
for(var char of to_chars(self)){
2334
cp = _b_.ord(char)
2335
if(unicode_tables.Ll[cp]){
2336
res += char.toUpperCase()
2337
}else if(unicode_tables.Lu[cp]){
2338
res += char.toLowerCase()
2341
}
2342
}
2343
return res
2344
}
2345
2346
str.title = function(self){
2347
var $ = $B.args("title", 1, {self}, ["self"],
2348
arguments, {}, null, null),
2349
state,
2352
for(var char of to_chars(self)){
2353
cp = _b_.ord(char)
2354
if(unicode_tables.Ll[cp]){
2361
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
2362
res += state ? char.toLowerCase() : char
2363
state = "word"
2364
}else{
2365
state = null
2367
}
2368
}
2369
return res
2370
}
2371
2372
str.translate = function(self, table){
Mar 19, 2018
2373
var res = [],
2374
getitem = $B.$getattr(table, "__getitem__"),
2375
cp
2376
for(var char of to_chars(self)){
2377
cp = _b_.ord(char)
2380
if(repl !== _b_.None){
2381
if(typeof repl == "string"){
2382
res.push(repl)
2383
}else if(typeof repl == "number"){
2384
res.push(String.fromCharCode(repl))
2385
}
2386
}
2387
}catch(err){
Sep 5, 2014
2390
}
Mar 19, 2018
2391
return res.join("")
Sep 5, 2014
2392
}
2393
2394
str.upper = function(self){
2395
var $ = $B.args("upper", 1, {self: null}, ["self"],
2396
arguments, {}, null, null)
2397
return self.toUpperCase()
2398
}
2399
Mar 19, 2018
2400
str.zfill = function(self, width){
Mar 19, 2018
2401
var $ = $B.args("zfill", 2, {self: null, width: null},
2402
["self", "width"], arguments, {}, null, null),
2403
len = str.__len__(self)
2404
if($.width <= len){
2405
return self
2406
}
Mar 19, 2018
2408
case "+":
2409
case "-":
2410
return self.charAt(0) +
2411
"0".repeat($.width - len) + self.substr(1)
2413
return "0".repeat($.width - len) + self
Sep 5, 2014
2415
}
2416
2417
str.$factory = function(arg, encoding, errors){
2418
if(arguments.length == 0){
2419
return ""
2420
}
2422
return $B.UndefinedClass.__str__()
2423
}else if(arg === null){
2424
return '<Javascript null>'
2426
if(encoding !== undefined){
2427
// Arguments may be passed as keywords (cf. issue #1060)
2428
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2429
["arg", "encoding", "errors"], arguments,
2430
{encoding: "utf-8", errors: "strict"}, null, null),
2431
encoding = $.encoding,
2432
errors = $.errors
2433
}
2434
if(typeof arg == "string" || arg instanceof String ||
2435
typeof arg == "number"){
2436
if(isFinite(arg)){
2437
return arg.toString()
2438
}
2441
if(arg.$is_class || arg.$factory){
2442
// arg is a class
2443
// In this case, str() doesn't use the attribute __str__ of the
2444
// class or its subclasses, but the attribute __str__ of the
2445
// class metaclass (usually "type") or its subclasses (usually
2446
// "object")
2447
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
2448
var func = $B.$getattr(arg.__class__, "__str__")
2450
}
2452
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2453
encoding !== undefined){
2454
// str(bytes, encoding, errors) is equal to
2455
// bytes.decode(encoding, errors)
2456
return _b_.bytes.decode(arg, $.encoding, $.errors)
2458
// Implicit invocation of __str__ uses method __str__ on the class,
2459
// even if arg has an attribute __str__
2460
var klass = arg.__class__ || $B.get_class(arg)
2462
return $B.JSObj.__str__($B.JSObj.$factory(arg))
2464
var method = $B.$getattr(klass , "__str__", null)
2465
if(method === null ||
2466
// if not better than object.__str__, try __repr__
2467
(arg.__class__ && arg.__class__ !== _b_.object &&
2468
method.$infos && method.$infos.__func__ === _b_.object.__str__)){
2469
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2471
}
2472
catch(err){
2473
console.log("no __str__ for", arg)
Mar 19, 2018
2474
console.log("err ", err)
2475
if($B.debug > 1){console.log(err)}
2476
console.log("Warning - no method __str__ or __repr__, " +
2477
"default to toString", arg)
May 20, 2019
2478
throw err
Sep 5, 2014
2479
}
2480
return $B.$call(method)(arg)
Sep 5, 2014
2481
}
str
Feb 10, 2018
2482
2483
str.__new__ = function(cls){
Mar 19, 2018
2484
if(cls === undefined){
2485
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2486
}
Mar 19, 2018
2487
return {__class__: cls}
Sep 5, 2014
2488
}
2489
str
Feb 10, 2018
2490
$B.set_func_names(str, "builtins")
Sep 5, 2014
2492
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2493
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2494
__class__: _b_.type,
2495
__mro__: [_b_.object],
2496
$infos: {
2497
__module__: "builtins",
2498
__name__: "str"
2499
},
str
Feb 10, 2018
2500
$is_class: true
Sep 5, 2014
2501
}
2502
str
Feb 10, 2018
2503
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2504
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2505
for(var $attr in str){
Mar 19, 2018
2506
if(typeof str[$attr] == "function"){
Mar 19, 2018
2507
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2508
return function(){
Mar 19, 2018
2509
var args = [],
2510
pos = 0
2511
if(arguments.length > 0){
2512
var args = [arguments[0].valueOf()],
2513
pos = 1
2514
for(var i = 1, len = arguments.length; i < len; i++){
2515
args[pos++] = arguments[i]
Sep 5, 2014
2516
}
2517
}
Mar 19, 2018
2518
return str[attr].apply(null, args)
Sep 5, 2014
2519
}
2520
})($attr)
2521
}
2522
}
2523
str
Feb 10, 2018
2524
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2527
str
Feb 10, 2018
2528
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2530
_b_.str = str
2531
2532
// Function to parse the 2nd argument of format()
2533
$B.parse_format_spec = function(spec){
2534
if(spec == ""){
2535
this.empty = true
2536
}else{
Mar 19, 2018
2537
var pos = 0,
2538
aligns = "<>=^",
2539
digits = "0123456789",
2540
types = "bcdeEfFgGnosxX%",
2541
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2542
if(align_pos != -1){
2543
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2544
// If the second char is also an alignment specifier, the
2545
// first char is the fill value
2546
this.fill = spec.charAt(0)
2547
this.align = spec.charAt(1)
2548
pos = 2
2549
}else{
2550
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2551
this.align = aligns[align_pos]
2552
this.fill = " "
2553
pos++
2554
}
2555
}else{
2556
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2557
if(spec.charAt(1) && align_pos != -1){
2558
// The second character defines alignment : fill is the first one
Mar 19, 2018
2559
this.align = aligns[align_pos]
2560
this.fill = spec.charAt(0)
2561
pos = 2
2562
}
2563
}
2564
var car = spec.charAt(pos)
Mar 19, 2018
2565
if(car == "+" || car == "-" || car == " "){
2566
this.sign = car
2567
pos++
2568
car = spec.charAt(pos)
2570
if(car == "#"){
2571
this.alternate = true; pos++; car = spec.charAt(pos)
2572
}
Mar 19, 2018
2573
if(car == "0"){
Mar 19, 2018
2574
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2575
this.fill = "0"
2576
if(align_pos == -1){
2577
this.align = "="
2578
}
Mar 19, 2018
2579
pos++
2580
car = spec.charAt(pos)
2581
}
Mar 19, 2018
2582
while(car && digits.indexOf(car) > -1){
2583
if(this.width === undefined){
2584
this.width = car
2585
}else{
2586
this.width += car
2587
}
Mar 19, 2018
2588
pos++
2589
car = spec.charAt(pos)
2591
if(this.width !== undefined){
2592
this.width = parseInt(this.width)
2593
}
2594
if(this.width === undefined && car == "{"){
2595
// Width is determined by a parameter
2596
var end_param_pos = spec.substr(pos).search("}")
2597
this.width = spec.substring(pos, end_param_pos)
2598
console.log("width", "[" + this.width + "]")
2599
pos += end_param_pos + 1
2600
}
2601
if(car == ","){
2602
this.comma = true
2603
pos++
2604
car = spec.charAt(pos)
2605
}
Mar 19, 2018
2606
if(car == "."){
2607
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2608
throw _b_.ValueError.$factory(
2609
"Missing precision in format spec")
Mar 19, 2018
2611
this.precision = spec.charAt(pos + 1)
2612
pos += 2
2613
car = spec.charAt(pos)
2614
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2615
this.precision += car
Mar 19, 2018
2616
pos++
2617
car = spec.charAt(pos)
2618
}
2619
this.precision = parseInt(this.precision)
2620
}
Mar 19, 2018
2621
if(car && types.indexOf(car) > -1){
2622
this.type = car
2623
pos++
2624
car = spec.charAt(pos)
2625
}
2626
if(pos !== spec.length){
2627
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2631
this.toString = function(){
Mar 19, 2018
2632
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2633
(this.align || "") +
2634
(this.sign || "") +
2635
(this.alternate ? "#" : "") +
2636
(this.sign_aware ? "0" : "") +
2637
(this.width || "") +
2638
(this.comma ? "," : "") +
2639
(this.precision ? "." + this.precision : "") +
2640
(this.type || "")
2641
}
2642
}
2643
2644
$B.format_width = function(s, fmt){
Mar 19, 2018
2645
if(fmt.width && s.length < fmt.width){
2646
var fill = fmt.fill || " ",
2647
align = fmt.align || "<",
2648
missing = fmt.width - s.length
2649
switch(align){
Mar 19, 2018
2650
case "<":
2651
return s + fill.repeat(missing)
2652
case ">":
2653
return fill.repeat(missing) + s
2654
case "=":
2655
if("+-".indexOf(s.charAt(0)) > -1){
2656
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2657
}else{
Mar 19, 2018
2658
return fill.repeat(missing) + s
Mar 19, 2018
2660
case "^":
2661
var left = parseInt(missing / 2)
2662
return fill.repeat(left) + s + fill.repeat(missing - left)
2663
}
2664
}
2665
return s
2666
}
2667
2668
function fstring_expression(){
Mar 19, 2018
2669
this.type = "expression"
2670
this.expression = ""
2671
this.conversion = null
2672
this.fmt = null
2673
}
2674
2675
function fstring_error(msg, pos){
2676
error = Error(msg)
2677
error.position = pos
2678
throw error
2679
}
2680
2681
$B.parse_fstring = function(string){
2682
// Parse a f-string
2683
var elts = [],
2684
pos = 0,
Mar 19, 2018
2685
current = "",
2686
ctype = null,
2687
nb_braces = 0,
2688
expr_start,
2689
car
2690
Mar 19, 2018
2691
while(pos < string.length){
2692
if(ctype === null){
2693
car = string.charAt(pos)
Mar 19, 2018
2694
if(car == "{"){
Mar 21, 2018
2695
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2696
ctype = "string"
2697
current = "{"
2698
pos += 2
2699
}else{
Mar 19, 2018
2700
ctype = "expression"
2701
expr_start = pos + 1
2702
nb_braces = 1
2703
pos++
2704
}
Mar 19, 2018
2705
}else if(car == "}"){
Mar 21, 2018
2706
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2707
ctype = "string"
2708
current = "}"
2709
pos += 2
2710
}else{
2711
fstring_error(" f-string: single '}' is not allowed",
2712
pos)
2713
}
2714
}else{
Mar 19, 2018
2715
ctype = "string"
2716
current = car
2717
pos++
Mar 19, 2018
2719
}else if(ctype == "string"){
2720
// end of string is the first single { or end of string
Mar 19, 2018
2721
var i = pos
2722
while(i < string.length){
2723
car = string.charAt(i)
Mar 19, 2018
2724
if(car == "{"){
Mar 21, 2018
2725
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2726
current += "{"
2727
i += 2
2728
}else{
2729
elts.push(current)
Mar 19, 2018
2730
ctype = "expression"
2731
expr_start = i + 1
Mar 19, 2018
2732
pos = i + 1
2733
break
2734
}
Mar 19, 2018
2735
}else if(car == "}"){
2736
if(string.charAt(i + 1) == car){
2737
current += car
2738
i += 2
2739
}else{
2740
fstring_error(" f-string: single '}' is not allowed",
2741
pos)
2742
}
2743
}else{
2744
current += car
2745
i++
2746
}
2747
}
Mar 19, 2018
2748
pos = i + 1
2749
}else if(ctype == "debug"){
2750
// after the equal sign, whitespace are ignored and the only
2751
// valid characters are } and :
2752
while(string.charAt(i) == " "){i++}
2753
if(string.charAt(i) == "}"){
2754
// end of debug expression
2755
console.log('end of debug', current)
2756
elts.push(current)
2757
ctype = null
2758
current = ""
2759
pos = i + 1
2760
}
2761
}else{
2762
// End of expression is the } matching the opening {
2763
// There may be nested braces
2764
var i = pos,
2765
nb_braces = 1,
2766
nb_paren = 0,
2767
current = new fstring_expression()
Mar 19, 2018
2768
while(i < string.length){
2769
car = string.charAt(i)
Mar 19, 2018
2770
if(car == "{" && nb_paren == 0){
2771
nb_braces++
2772
current.expression += car
2773
i++
Mar 19, 2018
2774
}else if(car == "}" && nb_paren == 0){
2775
nb_braces -= 1
Mar 19, 2018
2776
if(nb_braces == 0){
2777
// end of expression
2778
if(current.fmt){
2779
current.format_string = string.substring(fmt_start, i)
2780
current.format = $B.parse_fstring(current.format_string.substr(1))
2782
if(current.expression == ""){
2783
fstring_error("f-string: empty expression not allowed",
2784
pos)
2785
}
2786
elts.push(current)
2787
ctype = null
Mar 19, 2018
2788
current = ""
2789
pos = i + 1
2792
current.expression += car
2793
i++
Mar 19, 2018
2794
}else if(car == "\\"){
2795
// backslash is not allowed in expressions
2796
throw Error("f-string expression part cannot include a" +
2797
" backslash")
Mar 19, 2018
2798
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
2799
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2800
if(current.expression.length == 0){
2801
throw Error("f-string: empty expression not allowed")
2802
}
Mar 19, 2018
2803
if("ars".indexOf(string.charAt(i + 1)) == -1){
2804
throw Error("f-string: invalid conversion character:" +
2805
" expected 's', 'r', or 'a'")
2806
}else{
Mar 19, 2018
2807
current.conversion = string.charAt(i + 1)
2808
i += 2
2809
}
Mar 19, 2018
2810
}else if(car == "("){
2811
nb_paren++
2812
current.expression += car
2813
i++
Mar 19, 2018
2814
}else if(car == ")"){
2815
nb_paren--
2816
current.expression += car
2817
i++
Mar 19, 2018
2818
}else if(car == '"'){
2819
// triple string ?
Mar 19, 2018
2820
if(string.substr(i, 3) == '"""'){
2821
var end = string.indexOf('"""', i + 3)
2822
if(end == -1){
2823
fstring_error("f-string: unterminated string", pos)
Mar 19, 2018
2824
}else{
2825
var trs = string.substring(i, end + 3)
2826
trs = trs.replace("\n", "\\n\\")
2827
current.expression += trs
Mar 19, 2018
2828
i = end + 3
2829
}
2830
}else{
Mar 19, 2018
2831
var end = string.indexOf('"', i + 1)
2832
if(end == -1){
2833
fstring_error("f-string: unterminated string", pos)
Mar 19, 2018
2834
}else{
2835
current.expression += string.substring(i, end + 1)
2836
i = end + 1
2837
}
2838
}
Mar 19, 2018
2839
}else if(nb_paren == 0 && car == ":"){
2840
current.fmt = true
2841
var fmt_start = i
2842
current.expression += car
2843
i++
2844
}else if(car == "="){
2845
// might be a "debug expression", eg f"{x=}"
2846
var ce = current.expression,
2847
last_char = ce.charAt(ce.length - 1),
2848
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
2852
string.charAt(i + 1) == "=" ||
2853
"=!<>:".search(last_char_re) > -1){
2854
// not a debug expression
2857
}else{
2858
// add debug string
2859
tail = car
2860
while(string.charAt(i + 1).match(/\s/)){
2861
tail += string.charAt(i + 1)
2862
i++
2863
}
2864
// push simple string
2865
elts.push(current.expression + tail)
2866
// remove trailing whitespace from expression
2867
while(ce.match(/\s$/)){
2868
ce = ce.substr(0, ce.length - 1)
2869
}
2870
current.expression = ce
2871
ctype = "debug"
2872
i++
2873
}
2874
}else{
2875
current.expression += car
2876
i++
2877
}
2878
}
Mar 21, 2018
2879
if(nb_braces > 0){
2880
fstring_error("f-string: expected '}'", pos)
2881
}
2882
}
2883
}
2884
if(current.length > 0){
2885
elts.push(current)
2886
}
2887
for(var elt of elts){
2888
if(typeof elt == "object"){
2889
if(elt.fmt_pos !== undefined &&
2890
elt.expression.charAt(elt.fmt_pos) != ':'){
2891
console.log('mauvais format', string, elts)
2892
throw Error()
2893
}
2894
}
2895
}
2896
return elts
2897
}
2898
2899
var _chr = $B.codepoint2jsstring = function(i){
2900
if(i >= 0x10000 && i <= 0x10FFFF){
2901
var code = (i - 0x10000)
2902
return String.fromCodePoint(0xD800 | (code >> 10)) +
2903
String.fromCodePoint(0xDC00 | (code & 0x3FF))
2904
}else{
2905
return String.fromCodePoint(i)
2906
}
2907
}
2909
var _ord = $B.jsstring2codepoint = function(c){
2910
if(c.length == 1){
2911
return c.charCodeAt(0)
2912
}
2913
var code = 0x10000
2914
code += (c.charCodeAt(0) & 0x03FF) << 10
2915
code += (c.charCodeAt(1) & 0x03FF)
2916
return code
2917
}
2918
Sep 5, 2014
2919
})(__BRYTHON__)