Skip to content
Permalink
Newer
Older
100644 2935 lines (2722 sloc) 88.6 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 " + $B.class_name(item))
Mar 19, 2018
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)){
965
throw _b_.TypeError.$factory(
Mar 19, 2018
966
"Can't multiply sequence by non-int of type '" +
967
$B.class_name($.other) + "'")
968
}
969
return $.self.valueOf().repeat($.other < 0 ? 0 : $.other)
Sep 5, 2014
970
}
971
972
str.__ne__ = function(self, other){
973
return other.valueOf() !== self.valueOf()
Sep 5, 2014
975
976
function __newobj__(){
977
// __newobj__ is called with a generator as only argument
978
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
979
args = $.args
980
var res = args[1]
981
res.__class__ = args[0]
982
return res
983
}
984
985
str.__reduce_ex__ = function(self){
986
return $B.fast_tuple([
987
__newobj__,
988
$B.fast_tuple([self.__class__ || _b_.str, self]),
989
_b_.None,
990
_b_.None])
991
}
992
str
Feb 10, 2018
993
str.__repr__ = function(self){
995
var t = $B.special_string_repr, // in brython_builtins.js
996
repl = '',
997
chars = to_chars(self)
998
for(var i = 0; i < chars.length; i++){
999
var cp = _b_.ord(chars[i])
1000
if(t[cp] !== undefined){
1001
repl += t[cp]
1002
}else if($B.is_unicode_cn(cp)){
1003
var s = cp.toString(16)
1004
while(s.length < 4){
1005
s = '0' + s
1006
}
1007
repl += '\\u' + s
1008
}else if(cp < 0x20 || (cp >= 0x7f && cp < 0xa0)){
1009
cp = cp.toString(16)
1010
if(cp.length < 2){
1011
cp = '0' + cp
1012
}
1013
repl += '\\x' + cp
1014
}else if(cp >= 0x300 && cp <= 0x36F){
1015
repl += "\u200B" + chars[i] + ' '
1016
}else if(cp.toString(16) == 'feff'){
1017
repl += '\\ufeff'
Mar 19, 2018
1023
if(res.search('"') == -1 && res.search("'") == -1){
1024
return "'" + res + "'"
1025
}else if(self.search('"') == -1){
1026
return '"' + res + '"'
1027
}
1028
var qesc = new RegExp("'", "g") // to escape single quote
1029
res = "'" + res.replace(qesc, "\\'") + "'"
Sep 5, 2014
1030
return res
1031
}
1032
1033
str.__rmul__ = function(self, other){
1034
if(_b_.isinstance(other, _b_.int)){
1035
other = _b_.int.numerator(other)
1036
var res = ''
1037
while(other > 0){
1038
res += self
1039
other--
1040
}
1041
return res
1042
}
1043
return _b_.NotImplemented
1044
}
1045
1046
str.__setattr__ = function(self, attr, value){
1047
if(typeof self === "string"){
1048
if(str.hasOwnProperty(attr)){
1049
throw _b_.AttributeError.$factory("'str' object attribute '" +
1050
attr + "' is read-only")
1051
}else{
1052
throw _b_.AttributeError.$factory(
1053
"'str' object has no attribute '" + attr + "'")
1054
}
1055
}
1056
// str subclass : use __dict__
1057
_b_.dict.$setitem(self.__dict__, attr, value)
1058
return $N
1059
}
1060
Mar 19, 2018
1061
str.__setitem__ = function(self, attr, value){
1062
throw _b_.TypeError.$factory(
1063
"'str' object does not support item assignment")
Sep 5, 2014
1064
}
Mar 27, 2019
1066
var combining = []
1067
for(var cp = 0x300; cp <= 0x36F; cp++){
1068
combining.push(String.fromCharCode(cp))
1069
}
1070
var combining_re = new RegExp("(" + combining.join("|") + ")", "g")
str
Feb 10, 2018
1072
str.__str__ = function(self){
1073
var repl = '',
1074
chars = to_chars(self)
1075
if(chars.length == self.length){
1076
return self.replace(combining_re, "\u200B$1")
1077
}
1078
for(var i = 0; i < chars.length; i++){
1079
var cp = _b_.ord(chars[i])
1080
if(cp >= 0x300 && cp <= 0x36F){
1081
repl += "\u200B" + chars[i]
1082
}else{
1083
repl += chars[i]
1084
}
1085
}
1086
return repl
Sep 5, 2014
1087
}
Mar 19, 2018
1089
str.toString = function(){return "string!"}
Sep 5, 2014
1090
1091
// generate comparison methods
1092
var $comp_func = function(self,other){
1093
if(typeof other !== "string"){return _b_.NotImplemented}
Sep 5, 2014
1094
return self > other
1095
}
Mar 19, 2018
1096
$comp_func += "" // source code
1097
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
Sep 5, 2014
1098
for(var $op in $comps){
Mar 19, 2018
1099
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
Sep 5, 2014
1100
}
1101
1102
// unsupported operations
Mar 19, 2018
1103
var $notimplemented = function(self, other){
1104
throw _b_.NotImplementedError.$factory(
Mar 19, 2018
1105
"OPERATOR not implemented for class str")
Sep 5, 2014
1106
}
1107
1108
str.capitalize = function(self){
1109
var $ = $B.args("capitalize", 1, {self}, ["self"],
1110
arguments, {}, null, null)
1111
if(self.length == 0){
1112
return ""
1113
}
1114
return self.charAt(0).toUpperCase() + self.substr(1)
1115
}
1116
1117
str.casefold = function(self){
1118
var $ = $B.args("casefold", 1, {self}, ["self"],
1119
arguments, {}, null, null),
1120
res = "",
1121
char,
1122
cf,
1123
chars = to_chars($.self)
1124
1125
for(var i = 0, len = chars.length; i < len; i++){
1126
char = chars[i]
1127
cf = $B.unicode_casefold[char]
1128
if(cf){
1129
cf.forEach(function(cp){
1130
res += String.fromCharCode(cp)
1131
})
1132
}else{
1134
}
1135
}
1136
return res
1137
}
Sep 5, 2014
1138
Mar 19, 2018
1139
str.center = function(){
1140
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
1141
["self", "width", "fillchar"],
1142
arguments, {fillchar:" "}, null, null),
1143
self = $.self
Mar 19, 2018
1145
if($.width <= self.length) {return self}
Mar 19, 2018
1147
var pad = parseInt(($.width - self.length) / 2),
1148
res = $.fillchar.repeat(pad)
Sep 5, 2014
1149
res += self + res
1150
if(res.length < $.width){
1151
res += $.fillchar
1152
}
Sep 5, 2014
1153
return res
1154
}
1155
str
Feb 10, 2018
1156
str.count = function(){
Mar 19, 2018
1157
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
1158
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
1160
if(!(typeof $.sub.valueOf() == "string")){
1161
throw _b_.TypeError.$factory("Can't convert '" + $B.class_name($.sub) +
1162
"' object to str implicitly")
1163
}
Mar 19, 2018
1165
if($.start !== null){
1167
if($.stop !== null){
1168
_slice = _b_.slice.$factory($.start, $.stop)
1169
}else{
1170
_slice = _b_.slice.$factory($.start, $.self.length)
1171
}
str
Feb 10, 2018
1172
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
1174
if($.self.length + $.sub.length == 0){
1175
return 1
1176
}
Mar 19, 2018
1178
if($.sub.length == 0){
1179
if($.start == $.self.length){
1180
return 1
1181
}else if(substr.length == 0){
1182
return 0
1183
}
Mar 19, 2018
1184
return substr.length + 1
Mar 19, 2018
1186
var n = 0,
1187
pos = 0
1188
while(pos < substr.length){
1189
pos = substr.indexOf($.sub, pos)
1190
if(pos >= 0){
1191
n++
1192
pos += $.sub.length
1193
}else{
1194
break
1195
}
Sep 5, 2014
1196
}
1197
return n
1198
}
1199
1200
str.encode = function(){
1201
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
1202
["self", "encoding", "errors"], arguments,
1203
{encoding: "utf-8", errors: "strict"}, null, null)
1204
if($.encoding == "rot13" || $.encoding == "rot_13"){
1205
// Special case : returns a string
Mar 19, 2018
1206
var res = ""
1207
for(var i = 0, len = $.self.length; i < len ; i++){
1208
var char = $.self.charAt(i)
Mar 19, 2018
1209
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
1210
res += String.fromCharCode(String.charCodeAt(char) + 13)
1211
}else if(("m" < char && char <= "z") ||
1212
("M" < char && char <= "Z")){
1213
res += String.fromCharCode(String.charCodeAt(char) - 13)
1214
}else{res += char}
1215
}
1216
return res
1217
}
1218
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
Sep 5, 2014
1219
}
1220
str
Feb 10, 2018
1221
str.endswith = function(){
1222
// Return True if the string ends with the specified suffix, otherwise
1223
// return False. suffix can also be a tuple of suffixes to look for.
1224
// With optional start, test beginning at that position. With optional
Sep 5, 2014
1225
// end, stop comparing at that position.
Mar 19, 2018
1226
var $ = $B.args("endswith", 4,
1227
{self:null, suffix:null, start:null, end:null},
Mar 19, 2018
1228
["self", "suffix", "start", "end"],
1229
arguments, {start: 0, end: null}, null, null)
Sep 20, 2015
1230
1231
normalize_start_end($)
1232
1233
var suffixes = $.suffix
1234
if(! _b_.isinstance(suffixes,_b_.tuple)){
1235
suffixes = [suffixes]
1236
}
1238
var chars = to_chars($.self),
1239
s = chars.slice($.start, $.end)
Mar 19, 2018
1240
for(var i = 0, len = suffixes.length; i < len; i++){
1241
var suffix = suffixes[i]
1242
if(! _b_.isinstance(suffix, str)){
1243
throw _b_.TypeError.$factory(
1244
"endswith first arg must be str or a tuple of str, not int")
1245
}
Mar 19, 2018
1246
if(suffix.length <= s.length &&
1247
s.slice(s.length - suffix.length).join('') == suffix){
1248
return true
1249
}
Sep 5, 2014
1250
}
1251
return false
1252
}
1253
str
Feb 10, 2018
1254
str.expandtabs = function(self, tabsize) {
Mar 19, 2018
1255
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
1256
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
1257
var s = $B.$GetInt($.tabsize),
1258
col = 0,
1259
pos = 0,
1260
res = "",
1261
chars = to_chars(self)
1262
if(s == 1){
1263
return self.replace(/\t/g," ")
1264
}
1265
while(pos < chars.length){
1266
var car = chars[pos]
Mar 19, 2018
1268
case "\t":
1269
while(col % s > 0){
1270
res += " ";
1271
col++
1272
}
Mar 19, 2018
1274
case "\r":
1275
case "\n":
1276
res += car
1277
col = 0
1278
break
1279
default:
1280
res += car
1281
col++
1282
break
1283
}
1284
pos++
1285
}
1286
return res
Sep 5, 2014
1287
}
1288
str
Feb 10, 2018
1289
str.find = function(){
1290
// Return the lowest index in the string where substring sub is found,
1291
// such that sub is contained in the slice s[start:end]. Optional
1292
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
1293
// Return -1 if sub is not found.
Mar 19, 2018
1294
var $ = $B.args("str.find", 4,
1295
{self: null, sub: null, start: null, end: null},
1296
["self", "sub", "start", "end"],
1297
arguments, {start: 0, end: null}, null, null)
1298
check_str($.sub)
1301
var len = str.__len__($.self),
1302
sub_len = str.__len__($.sub)
1304
if(sub_len == 0 && $.start == len){
1307
if(len + sub_len == 0){
1310
// Use .indexOf(), not .search(), to avoid conversion to reg exp
1311
var js_start = pypos2jspos($.self, $.start),
1312
js_end = pypos2jspos($.self, $.end),
1313
ix = $.self.substring(js_start, js_end).indexOf($.sub)
1314
if(ix == -1){
1315
return -1
Sep 5, 2014
1316
}
1317
return jspos2pypos($.self, js_start + ix)
Sep 5, 2014
1318
}
1319
1320
// Next function used by method .format()
1321
1322
$B.parse_format = function(fmt_string){
Sep 5, 2014
1323
1324
// Parse a "format string", as described in the Python documentation
1325
// Return a format object. For the format string
1326
// a.x[z]!r:...
1327
// the object has attributes :
1328
// - name : "a"
1329
// - name_ext : [".x", "[z]"]
1330
// - conv : r
1331
// - spec : rest of string after :
Sep 5, 2014
1332
Mar 19, 2018
1333
var elts = fmt_string.split(":"),
1334
name,
1335
conv,
1336
spec,
Mar 19, 2018
1337
name_ext = []
Mar 19, 2018
1338
if(elts.length == 1){
1339
// No : in the string : it only contains a name
1340
name = fmt_string
1341
}else{
1342
// name is before the first ":"
1343
// spec (the format specification) is after
1344
name = elts[0]
Mar 19, 2018
1345
spec = elts.splice(1).join(":")
Mar 19, 2018
1348
var elts = name.split("!")
1349
if(elts.length > 1){
1350
name = elts[0]
1351
conv = elts[1] // conversion flag
Sep 5, 2014
1353
Mar 19, 2018
1354
if(name !== undefined){
1355
// "name' may be a subscription or attribute
1356
// Put these "extensions" in the list "name_ext"
1357
function name_repl(match){
1358
name_ext.push(match)
Mar 19, 2018
1359
return ""
1360
}
1361
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1362
name = name.replace(name_ext_re, name_repl)
1363
}
Sep 5, 2014
1364
1365
return {name: name, name_ext: name_ext,
1366
conv: conv, spec: spec || "", string: fmt_string}
Sep 5, 2014
1368
1369
$B.split_format = function(self){
1370
// Parse self to detect formatting instructions
1371
// Create a list "parts" made of sections of the string :
1372
// - elements of even rank are literal text
1373
// - elements of odd rank are "format objects", built from the
1374
// format strings in self (of the form {...})
Mar 19, 2018
1375
var pos = 0,
1376
_len = self.length,
Mar 19, 2018
1378
text = "",
1379
parts = [],
1380
rank = 0
1381
while(pos < _len){
1382
car = self.charAt(pos)
Mar 21, 2018
1383
if(car == "{" && self.charAt(pos + 1) == "{"){
1384
// replace {{ by literal {
Mar 19, 2018
1385
text += "{"
1386
pos += 2
1387
}else if(car == "}" && self.charAt(pos + 1) == "}"){
1388
// replace }} by literal }
Mar 19, 2018
1389
text += "}"
1390
pos += 2
1391
}else if(car == "{"){
1392
// Start of a format string
1394
// Store current literal text
1395
parts.push(text)
1396
1397
// Search the end of the format string, ie the } closing the
1398
// opening {. Since the string can contain other pairs {} for
1399
// nested formatting, an integer nb is incremented for each { and
1400
// decremented for each } ; the end of the format string is
Mar 19, 2018
1401
// reached when nb == 0
1402
var end = pos + 1,
1403
nb = 1
1404
while(end < _len){
1405
if(self.charAt(end) == "{"){nb++; end++}
1406
else if(self.charAt(end) == "}"){
1407
nb--; end++
1408
if(nb == 0){
1409
// End of format string
Mar 19, 2018
1410
var fmt_string = self.substring(pos + 1, end - 1)
1411
1412
// Create a format object, by function parse_format
1413
var fmt_obj = $B.parse_format(fmt_string)
1414
fmt_obj.raw_name = fmt_obj.name
1415
fmt_obj.raw_spec = fmt_obj.spec
1416
1417
// If no name is explicitely provided, use the rank
1418
if(!fmt_obj.name){
Mar 19, 2018
1419
fmt_obj.name = rank + ""
Sep 5, 2014
1422
Mar 19, 2018
1423
if(fmt_obj.spec !== undefined){
1424
// "spec" may contain "nested replacement fields"
1425
// Replace empty fields by the rank in positional
1426
// arguments
1427
function replace_nested(name, key){
1428
if(key == ""){
1429
// Use implicit rank
1430
return "{" + rank++ + "}"
1434
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
1435
replace_nested)
1436
}
1438
// Store format object in list "parts"
1439
parts.push(fmt_obj)
Mar 19, 2018
1440
text = ""
1441
break
1442
}
1443
}else{end++}
Sep 5, 2014
1444
}
1445
if(nb > 0){
1446
throw _b_.ValueError.$factory("wrong format " + self)
1447
}
1449
}else{
1450
text += car
1451
pos++
1452
}
1453
}
1454
if(text){
1455
parts.push(text)
Sep 5, 2014
1456
}
1457
return parts
1458
}
1459
1460
str.format = function(self) {
1461
// Special management of keyword arguments if str.format is called by
1462
// str.format_map(mapping) : the argument "mapping" might not be a
1463
// dictionary
1464
var last_arg = $B.last(arguments)
1465
if(last_arg.$nat == "mapping"){
1466
var mapping = last_arg.mapping,
1467
getitem = $B.$getattr(mapping, "__getitem__")
1468
// Get the rest of the arguments
1469
var args = []
1470
for(var i = 0, len = arguments.length - 1; i < len; i++){
1471
args.push(arguments[i])
1472
}
1473
var $ = $B.args("format", 1, {self: null}, ["self"],
1474
args, {}, "$args", null)
1475
}else{
1476
var $ = $B.args("format", 1, {self: null}, ["self"],
1477
arguments, {}, "$args", "$kw"),
1478
mapping = $.$kw, // dictionary
1479
getitem = function(key){
1480
return _b_.dict.$getitem(mapping, key)
1481
}
1482
}
1483
var parts = $B.split_format($.self)
1484
1485
// Apply formatting to the values passed to format()
Mar 19, 2018
1486
var res = "",
1487
fmt
Mar 19, 2018
1489
for(var i = 0; i < parts.length; i++){
1490
// Literal text is added unchanged
1491
if(typeof parts[i] == "string"){
1492
res += parts[i];
1493
continue
1494
}
1496
// Format objects
1497
fmt = parts[i]
1498
1499
if(fmt.spec !== undefined){
1500
// "spec" may contain "nested replacement fields"
1501
// In this case, evaluate them using the positional
1502
// or keyword arguments passed to format()
1503
function replace_nested(name, key){
1504
if(/\d+/.exec(key)){
1505
// If key is numeric, search in positional
1506
// arguments
1507
return _b_.tuple.__getitem__($.$args,
1508
parseInt(key))
1509
}else{
1510
// Else try in keyword arguments
1511
return _b_.dict.__getitem__($.$kw, key)
1512
}
1513
}
1514
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
1515
replace_nested)
1516
}
Mar 21, 2018
1517
if(fmt.name.charAt(0).search(/\d/) > -1){
1518
// Numerical reference : use positional arguments
1519
var pos = parseInt(fmt.name),
Feb 11, 2018
1520
value = _b_.tuple.__getitem__($.$args, pos)
1521
}else{
1522
// Use keyword arguments
1523
var value = getitem(fmt.name)
1524
}
1525
// If name has extensions (attributes or subscriptions)
Mar 19, 2018
1526
for(var j = 0; j < fmt.name_ext.length; j++){
1527
var ext = fmt.name_ext[j]
Mar 19, 2018
1528
if(ext.charAt(0) == "."){
1530
value = $B.$getattr(value, ext.substr(1))
1531
}else{
1532
// Subscription
Mar 19, 2018
1533
var key = ext.substr(1, ext.length - 2)
1534
// An index made of digits is transformed into an integer
Mar 19, 2018
1535
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
1536
value = $B.$getattr(value, "__getitem__")(key)
Feb 12, 2018
1539
1540
// If the conversion flag is set, first call a function to convert
1541
// the value
Mar 19, 2018
1542
if(fmt.conv == "a"){value = _b_.ascii(value)}
1543
else if(fmt.conv == "r"){value = _b_.repr(value)}
1544
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
1546
// Call attribute __format__ to perform the actual formatting
1547
if(value.$is_class || value.$factory){
1548
// For classes, don't use the class __format__ method
1549
res += value.__class__.__format__(value, fmt.spec)
1551
res += $B.$getattr(value, "__format__")(fmt.spec)
Sep 5, 2014
1553
}
Sep 5, 2014
1555
}
1556
1557
str.format_map = function(self, mapping){
1558
var $ = $B.args("format_map", 2, {self: null, mapping: null},
1559
['self', 'mapping'], arguments, {}, null, null)
1560
return str.format(self, {$nat: 'mapping', mapping})
Sep 5, 2014
1561
}
1562
str
Feb 10, 2018
1563
str.index = function(self){
Sep 5, 2014
1564
// Like find(), but raise ValueError when the substring is not found.
1565
var res = str.find.apply(null, arguments)
1566
if(res === -1){
1567
throw _b_.ValueError.$factory("substring not found")
1568
}
Sep 5, 2014
1569
return res
1570
}
1571
1572
str.isascii = function(self){
1573
/* Return true if the string is empty or all characters in the string are
1574
ASCII, false otherwise. ASCII characters have code points in the range
1575
U+0000-U+007F. */
1576
for(var i = 0, len = self.length; i < len; i++){
1577
if(self.charCodeAt(i) > 127){
1578
return false
1579
}
1580
}
1581
return true
1582
}
1583
1584
str.isalnum = function(self){
1585
/* Return true if all characters in the string are alphanumeric and there
1586
is at least one character, false otherwise. A character c is alphanumeric
1587
if one of the following returns True: c.isalpha(), c.isdecimal(),
1588
c.isdigit(), or c.isnumeric(). */
1589
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
1590
arguments, {}, null, null),
1591
cp
1592
for(var char of to_chars(self)){
1593
cp = _b_.ord(char)
1594
if(unicode_tables.Ll[cp] ||
1595
unicode_tables.Lu[cp] ||
1596
unicode_tables.Lm[cp] ||
1597
unicode_tables.Lt[cp] ||
1598
unicode_tables.Lo[cp] ||
1599
unicode_tables.Nd[cp] ||
1600
unicode_tables.digits[cp] ||
1601
unicode_tables.numeric[cp]){
1602
continue
1603
}
1604
return false
1605
}
1606
return true
1607
}
1608
1609
str.isalpha = function(self){
1610
/* Return true if all characters in the string are alphabetic and there is
1611
at least one character, false otherwise. Alphabetic characters are those
1612
characters defined in the Unicode character database as "Letter", i.e.,
1613
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
1614
or "Lo". */
1615
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
1616
arguments, {}, null, null),
1617
cp
1618
for(var char of to_chars(self)){
1619
cp = _b_.ord(char)
1620
if(unicode_tables.Ll[cp] ||
1621
unicode_tables.Lu[cp] ||
1622
unicode_tables.Lm[cp] ||
1623
unicode_tables.Lt[cp] ||
1624
unicode_tables.Lo[cp]){
1625
continue
1626
}
1627
return false
1628
}
1629
return true
1630
}
1631
1632
str.isdecimal = function(self){
1633
/* Return true if all characters in the string are decimal characters and
1634
there is at least one character, false otherwise. Decimal characters are
1635
those that can be used to form numbers in base 10, e.g. U+0660,
1636
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
1637
the Unicode General Category "Nd". */
1638
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
1639
arguments, {}, null, null),
1640
cp
1641
for(var char of to_chars(self)){
1642
cp = _b_.ord(char)
1643
if(! unicode_tables.Nd[cp]){
1644
return false
1645
}
1646
}
1647
return self.length > 0
1648
}
1649
1650
str.isdigit = function(self){
1651
/* Return true if all characters in the string are digits and there is at
1652
least one character, false otherwise. */
1653
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
1654
arguments, {}, null, null),
1655
cp
1656
for(var char of to_chars(self)){
1657
cp = _b_.ord(char)
1658
if(! unicode_tables.digits[cp]){
1659
return false
1660
}
1661
}
1662
return self.length > 0
1663
}
1664
1665
str.isidentifier = function(self){
1666
/* Return true if the string is a valid identifier according to the
1667
language definition. */
1668
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
1670
if(self.length == 0){
1671
return false
1672
}
1673
var chars = to_chars(self)
1674
if(unicode_tables.XID_Start[_b_.ord(chars[0])] === undefined){
1677
for(var char of chars){
1678
var cp = _b_.ord(char)
1679
if(unicode_tables.XID_Continue[cp] === undefined){
1680
return false
1681
}
1682
}
1683
}
1684
return true
1685
}
1686
1687
str.islower = function(self){
1688
/* Return true if all cased characters 4 in the string are lowercase and
1689
there is at least one cased character, false otherwise. */
1690
var $ = $B.args("islower", 1, {self: null}, ["self"],
1691
arguments, {}, null, null),
1692
has_cased = false,
1695
for(var char of to_chars(self)){
1696
cp = _b_.ord(char)
1697
if(unicode_tables.Ll[cp]){
1698
has_cased = true
1699
continue
1700
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
1701
return false
1702
}
1703
}
1704
return has_cased
1705
}
1706
1707
str.isnumeric = function(self){
1708
/* Return true if all characters in the string are numeric characters, and
1709
there is at least one character, false otherwise. Numeric characters
1710
include digit characters, and all characters that have the Unicode numeric
1711
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
1712
characters are those with the property value Numeric_Type=Digit,
1713
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
1714
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
1715
arguments, {}, null, null)
1716
for(var char of to_chars(self)){
1717
if(! unicode_tables.numeric[_b_.ord(char)]){
1718
return false
1719
}
1720
}
1721
return self.length > 0
1722
}
1723
1724
var unprintable = {},
1725
unprintable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
1726
1727
str.isprintable = function(self){
1728
/* Return true if all characters in the string are printable or the string
1729
is empty, false otherwise. Nonprintable characters are those characters
1730
defined in the Unicode character database as "Other" or "Separator",
1731
excepting the ASCII space (0x20) which is considered printable. */
1732
1733
// Set unprintable if not set yet
1734
if(Object.keys(unprintable).length == 0){
1735
for(var i = 0; i < unprintable_gc.length; i++){
1736
var table = unicode_tables[unprintable_gc[i]]
1738
unprintable[cp] = true
1741
unprintable[32] = true
1742
}
1743
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
1744
arguments, {}, null, null)
1745
for(var char of to_chars(self)){
1746
if(unprintable[_b_.ord(char)]){
1747
return false
1748
}
1749
}
1750
return true
1751
}
1752
1753
str.isspace = function(self){
1754
/* Return true if there are only whitespace characters in the string and
1755
there is at least one character, false otherwise.
1756
1757
A character is whitespace if in the Unicode character database, either its
1758
general category is Zs ("Separator, space"), or its bidirectional class is
1759
one of WS, B, or S.*/
1760
var $ = $B.args("isspace", 1, {self: null}, ["self"],
1761
arguments, {}, null, null),
1762
cp
1763
for(var char of to_chars(self)){
1764
cp = _b_.ord(char)
1765
if(! unicode_tables.Zs[cp] &&
1766
$B.unicode_bidi_whitespace.indexOf(cp) == -1){
1767
return false
1768
}
1769
}
1770
return self.length > 0
1771
}
1772
1773
str.istitle = function(self){
1774
/* Return true if the string is a titlecased string and there is at least
1775
one character, for example uppercase characters may only follow uncased
1776
characters and lowercase characters only cased ones. Return false
1777
otherwise. */
1778
var $ = $B.args("istitle", 1, {self: null}, ["self"],
1779
arguments, {}, null, null)
1780
return self.length > 0 && str.title(self) == self
1781
}
1782
1783
str.isupper = function(self){
1784
/* Return true if all cased characters 4 in the string are lowercase and
1785
there is at least one cased character, false otherwise. */
1786
var $ = $B.args("islower", 1, {self: null}, ["self"],
1787
arguments, {}, null, null),
1791
for(var char of to_chars(self)){
1792
cp = _b_.ord(char)
1793
if(unicode_tables.Lu[cp]){
1794
is_upper = true
1795
continue
1796
}else if(unicode_tables.Ll[cp] || unicode_tables.Lt[cp]){
str
Feb 10, 2018
1804
str.join = function(){
Mar 19, 2018
1805
var $ = $B.args("join", 2, {self: null, iterable: null},
Mar 19, 2018
1806
["self", "iterable"], arguments, {}, null, null)
Mar 19, 2018
1808
var iterable = _b_.iter($.iterable),
Mar 19, 2018
1809
res = [],
Sep 5, 2014
1811
while(1){
1812
try{
1813
var obj2 = _b_.next(iterable)
1814
if(! _b_.isinstance(obj2, str)){
1815
throw _b_.TypeError.$factory("sequence item " + count +
1816
": expected str instance, " + $B.class_name(obj2) +
1817
" found")
1818
}
1819
res.push(obj2)
Sep 5, 2014
1820
}catch(err){
1821
if(_b_.isinstance(err, _b_.StopIteration)){
1822
break
1823
}
Sep 5, 2014
1824
else{throw err}
1825
}
1826
}
1827
return res.join($.self)
Sep 5, 2014
1828
}
1829
str
Feb 10, 2018
1830
str.ljust = function(self) {
Mar 19, 2018
1831
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
1832
["self", "width", "fillchar"],
1833
arguments, {fillchar: " "}, null, null),
1834
len = str.__len__(self)
1836
if($.width <= len){
1837
return self
1838
}
1839
return self + $.fillchar.repeat($.width - len)
Sep 5, 2014
1840
}
1841
1842
str.lower = function(self){
1843
var $ = $B.args("lower", 1, {self: null}, ["self"],
1844
arguments, {}, null, null)
1845
return self.toLowerCase()
1846
}
1847
1848
str.lstrip = function(self, x){
Mar 19, 2018
1849
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
1850
arguments, {chars:_b_.None}, null, null),
1851
self = $.self,
1852
chars = $.chars
1853
if(chars === _b_.None){
1854
return self.trimStart()
1856
while(self.length > 0){
1857
var flag = false
1858
for(var char of chars){
1859
if(self.startsWith(char)){
1860
self = self.substr(char.length)
1861
flag = true
1862
break
1863
}
1864
}
1865
if(! flag){
1866
return $.self.surrogates ? $B.String(self) : self
Sep 5, 2014
1870
}
1871
1872
// note, maketrans should be a static function.
str
Feb 10, 2018
1873
str.maketrans = function() {
Mar 19, 2018
1874
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
1875
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
Mar 19, 2018
1879
if($.y === null && $.z === null){
1880
// If there is only one argument, it must be a dictionary mapping
1881
// Unicode ordinals (integers) or characters (strings of length 1) to
1882
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1883
// keys will then be converted to ordinals.
Mar 19, 2018
1884
if(! _b_.isinstance($.x, _b_.dict)){
1885
throw _b_.TypeError.$factory(
1886
"maketrans only argument must be a dict")
Feb 11, 2018
1888
var items = _b_.list.$factory(_b_.dict.items($.x))
Mar 19, 2018
1889
for(var i = 0, len = items.length; i < len; i++){
1890
var k = items[i][0],
1891
v = items[i][1]
1892
if(! _b_.isinstance(k, _b_.int)){
1893
if(_b_.isinstance(k, _b_.str) && k.length == 1){
1894
k = _b_.ord(k)
1895
}else{throw _b_.TypeError.$factory("dictionary key " + k +
1896
" is not int or 1-char string")}
1897
}
Mar 19, 2018
1898
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
1899
throw _b_.TypeError.$factory("dictionary value " + v +
1900
" is not None, integer or string")
1901
}
1902
_b_.dict.$setitem(_t, k, v)
1903
}
1904
return _t
1905
}else{
1906
// If there are two arguments, they must be strings of equal length,
1907
// and in the resulting dictionary, each character in x will be mapped
1908
// to the character at the same position in y
Mar 19, 2018
1909
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1910
throw _b_.TypeError.$factory("maketrans arguments must be strings")
Mar 19, 2018
1911
}else if($.x.length !== $.y.length){
1912
throw _b_.TypeError.$factory(
1913
"maketrans arguments must be strings or same length")
1914
}else{
1915
var toNone = {}
Mar 19, 2018
1916
if($.z !== null){
1917
// If there is a third argument, it must be a string, whose
1918
// characters will be mapped to None in the result
Mar 19, 2018
1919
if(! _b_.isinstance($.z, _b_.str)){
1920
throw _b_.TypeError.$factory(
1921
"maketrans third argument must be a string")
Mar 19, 2018
1923
for(var i = 0, len = $.z.length; i < len; i++){
1924
toNone[_b_.ord($.z.charAt(i))] = true
1925
}
Mar 19, 2018
1927
for(var i = 0, len = $.x.length; i < len; i++){
1928
var key = _b_.ord($.x.charAt(i)),
1930
_b_.dict.$setitem(_t, key, value)
1931
}
1932
for(var k in toNone){
1933
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
1934
}
1935
return _t
1936
}
1937
}
Sep 5, 2014
1938
}
1939
1940
str.maketrans.$type = "staticmethod"
1941
str
Feb 10, 2018
1942
str.partition = function() {
Mar 19, 2018
1943
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
1944
arguments, {}, null, null)
1945
if($.sep == ""){
1946
throw _b_.ValueError.$factory("empty separator")
1947
}
Mar 19, 2018
1948
check_str($.sep)
1949
var chars = to_chars($.self),
1950
i = $.self.indexOf($.sep)
1951
if(i == -1){
1952
return _b_.tuple.$factory([$.self, "", ""])
1953
}
1954
return _b_.tuple.$factory([chars.slice(0, i).join(''), $.sep,
1955
chars.slice(i + $.sep.length).join('')])
Mar 19, 2018
1956
}
1957
1958
str.removeprefix = function(){
1959
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
1960
["self", "prefix"], arguments, {}, null, null)
1961
if(!_b_.isinstance($.prefix, str)){
1962
throw _b_.ValueError.$factory("prefix should be str, not " +
1963
`'${$B.class_name($.prefix)}'`)
1964
}
1965
if(str.startswith($.self, $.prefix)){
1966
return $.self.substr($.prefix.length)
1967
}
1968
return $.self.substr(0)
1969
}
1970
1971
str.removesuffix = function(){
1972
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
1973
["self", "suffix"], arguments, {}, null, null)
1974
if(!_b_.isinstance($.suffix, str)){
1975
throw _b_.ValueError.$factory("suffix should be str, not " +
1976
`'${$B.class_name($.prefix)}'`)
1977
}
1978
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
1979
return $.self.substr(0, $.self.length - $.suffix.length)
1980
}
1981
return $.self.substr(0)
1982
}
1983
Mar 19, 2018
1984
function $re_escape(str){
1985
var specials = "[.*+?|()$^"
1986
for(var i = 0, len = specials.length; i < len; i++){
1987
var re = new RegExp("\\"+specials.charAt(i), "g")
1988
str = str.replace(re, "\\"+specials.charAt(i))
1989
}
1990
return str
Sep 5, 2014
1991
}
1992
str
Feb 10, 2018
1993
str.replace = function(self, old, _new, count) {
1994
// Replaces occurrences of 'old' by '_new'. Count references
1995
// the number of times to replace. In CPython, negative or undefined
1996
// values of count means replace all.
Mar 19, 2018
1997
var $ = $B.args("replace", 4,
1998
{self: null, old: null, new: null, count: null},
1999
["self", "old", "new", "count"],
Mar 19, 2018
2000
arguments, {count: -1}, null, null),
2001
count = $.count,
2002
self = $.self,
2003
old = $.old,
2004
_new = $.new
2005
// Validate type of old
2006
check_str(old, "replace() argument 1 ")
2007
check_str(_new, "replace() argument 2 ")
2008
// Validate instance type of 'count'
2009
if(! _b_.isinstance(count,[_b_.int, _b_.float])){
2010
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
Mar 19, 2018
2011
"' object cannot be interpreted as an integer")
2012
}else if(_b_.isinstance(count, _b_.float)){
Mar 19, 2018
2013
throw _b_.TypeError.$factory("integer argument expected, got float")
2014
}
2015
if(count == 0){
2016
return self
2017
}
2018
if(count.__class__ == $B.long_int){
2019
count = parseInt(count.value)
2020
}
Mar 19, 2018
2021
if(old == ""){
2022
if(_new == ""){
2023
return self
2024
}
2025
if(self == ""){
2026
return _new
2027
}
Mar 19, 2018
2028
var elts = self.split("")
2029
if(count > -1 && elts.length >= count){
2030
var rest = elts.slice(count).join("")
2031
return _new + elts.slice(0, count).join(_new) + rest
2032
}else{
2033
return _new + elts.join(_new) + _new
2034
}
Mar 19, 2018
2036
var elts = str.split(self, old, count)
Sep 5, 2014
2037
}
Mar 19, 2018
2039
var res = self,
2040
pos = -1
2041
if(old.length == 0){
Mar 19, 2018
2043
for(var i = 0; i < elts.length; i++){
2044
res += elts[i] + _new
Mar 19, 2018
2046
return res + rest
2049
if(count < 0){
2050
count = res.length
2051
}
Mar 19, 2018
2052
while(count > 0){
2053
pos = res.indexOf(old, pos)
2054
if(pos < 0){
2055
break
2056
}
Mar 19, 2018
2057
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
2058
pos = pos + _new.length
2059
count--
Mar 19, 2018
2061
return res
Sep 5, 2014
2062
}
2063
2064
str.rfind = function(self, substr){
2065
// Return the highest index in the string where substring sub is found,
2066
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
2067
// start and end are interpreted as in slice notation. Return -1 on failure.
Mar 19, 2018
2068
var $ = $B.args("rfind", 4,
Mar 19, 2018
2069
{self: null, sub: null, start: null, end: null},
2070
["self", "sub", "start", "end"],
2071
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
2072
2074
check_str($.sub)
2076
var len = str.__len__($.self),
2077
sub_len = str.__len__($.sub)
2078
2079
if(sub_len == 0){
2080
if($.js_start > len){
2081
return -1
2082
}else{
2083
return str.__len__($.self)
2084
}
2087
// Use .indexOf(), not .search(), to avoid conversion to reg exp
2088
var js_start = pypos2jspos($.self, $.start),
2089
js_end = pypos2jspos($.self, $.end),
2090
ix = $.self.substring(js_start, js_end).lastIndexOf($.sub)
2091
if(ix == -1){
2092
return -1
2094
return jspos2pypos($.self, js_start + ix) - $.start
Sep 5, 2014
2095
}
2096
str
Feb 10, 2018
2097
str.rindex = function(){
Sep 5, 2014
2098
// Like rfind() but raises ValueError when the substring sub is not found
Mar 19, 2018
2099
var res = str.rfind.apply(null, arguments)
2100
if(res == -1){
2101
throw _b_.ValueError.$factory("substring not found")
2102
}
Sep 5, 2014
2103
return res
2104
}
2105
str
Feb 10, 2018
2106
str.rjust = function(self) {
Mar 19, 2018
2107
var $ = $B.args("rjust",3,
2108
{self: null, width: null, fillchar: null},
2109
["self", "width", "fillchar"],
2110
arguments, {fillchar: " "}, null, null)
Sep 5, 2014
2111
2112
var len = str.__len__(self)
2113
if($.width <= len){
2116
return $B.String($.fillchar.repeat($.width - len) + self)
Sep 5, 2014
2117
}
2118
str
Feb 10, 2018
2119
str.rpartition = function(self,sep) {
Mar 19, 2018
2120
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
2121
arguments, {}, null, null)
2122
check_str($.sep)
2123
var self = reverse($.self),
2124
sep = reverse($.sep)
Mar 19, 2018
2125
var items = str.partition(self, sep).reverse()
2126
for(var i = 0; i < items.length; i++){
2127
items[i] = items[i].split("").reverse().join("")
2128
}
2129
return items
Sep 5, 2014
2130
}
2131
str
Feb 10, 2018
2132
str.rsplit = function(self) {
Mar 19, 2018
2133
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
2134
["self", "sep", "maxsplit"], arguments,
2135
{sep: _b_.None, maxsplit: -1}, null, null),
2136
sep = $.sep
2137
2138
// Use split on the reverse of the string and of separator
2139
var rev_str = reverse($.self),
2140
rev_sep = sep === _b_.None ? sep : reverse($.sep),
str
Feb 10, 2018
2141
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
2143
// Reverse the list, then each string inside the list
2144
rev_res.reverse()
Mar 19, 2018
2145
for(var i = 0; i < rev_res.length; i++){
2146
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
2149
}
2150
Mar 19, 2018
2151
str.rstrip = function(self, x){
2152
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
2153
arguments, {chars: _b_.None}, null, null),
2154
self = $.self,
2155
chars = $.chars
2156
if(chars === _b_.None){
2157
return self.trimEnd()
2159
while(self.length > 0){
2160
var flag = false
2161
for(var char of chars){
2162
if(self.endsWith(char)){
2163
self = self.substr(0, self.length - char.length)
2164
flag = true
2165
break
2166
}
2167
}
2168
if(! flag){
2169
return $.self.surrogates ? $B.String(self) : self
Sep 5, 2014
2173
}
2174
str
Feb 10, 2018
2175
str.split = function(){
Mar 19, 2018
2176
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
2177
["self", "sep", "maxsplit"], arguments,
2178
{sep: _b_.None, maxsplit: -1}, null, null),
2179
sep = $.sep,
2180
maxsplit = $.maxsplit,
2181
self = $.self,
2182
pos = 0
2183
if(maxsplit.__class__ === $B.long_int){
2184
maxsplit = parseInt(maxsplit.value)
2185
}
2186
if(sep == ""){
2187
throw _b_.ValueError.$factory("empty separator")
2188
}
Mar 19, 2018
2190
if(sep === _b_.None){
Sep 5, 2014
2191
var res = []
2192
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){
2193
pos++
2194
}
2195
if(pos === self.length - 1){
2196
return [self]
2197
}
Mar 19, 2018
2198
var name = ""
Sep 5, 2014
2199
while(1){
Mar 19, 2018
2200
if(self.charAt(pos).search(/\s/) == -1){
2201
if(name == ""){
2202
name = self.charAt(pos)
2203
}else{
2204
name += self.charAt(pos)
2205
}
Sep 5, 2014
2206
}else{
Mar 19, 2018
2207
if(name !== ""){
Sep 5, 2014
2208
res.push(name)
Mar 19, 2018
2209
if(maxsplit !== -1 && res.length == maxsplit + 1){
Sep 5, 2014
2210
res.pop()
Mar 19, 2018
2211
res.push(name + self.substr(pos))
Sep 5, 2014
2212
return res
2213
}
Mar 19, 2018
2214
name = ""
Sep 5, 2014
2215
}
2216
}
2217
pos++
Mar 19, 2018
2218
if(pos > self.length - 1){
2219
if(name){
2220
res.push(name)
2221
}
Sep 5, 2014
2222
break
2223
}
2224
}
2225
return res.map($B.String)
Sep 5, 2014
2226
}else{
Mar 19, 2018
2227
var res = [],
2228
s = "",
2229
seplen = sep.length
2230
if(maxsplit == 0){
2231
return [self]
2232
}
Mar 19, 2018
2233
while(pos < self.length){
2234
if(self.substr(pos, seplen) == sep){
Mar 19, 2018
2237
if(maxsplit > -1 && res.length >= maxsplit){
2239
return res.map($B.String)
Mar 19, 2018
2241
s = ""
2242
}else{
2243
s += self.charAt(pos)
2244
pos++
Sep 5, 2014
2245
}
2246
}
2248
return res.map($B.String)
Sep 5, 2014
2249
}
2250
}
2251
2252
str.splitlines = function(self) {
2253
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
2254
['self','keepends'], arguments, {keepends: false},
2255
null, null)
2256
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
2257
throw _b_.TypeError('integer argument expected, got '+
2258
$B.get_class($.keepends).__name)
2259
}
2260
var keepends = _b_.int.$factory($.keepends),
2261
res = [],
2262
self = $.self,
2263
start = 0,
2264
pos = 0
2265
if(!self.length){
2266
return res
2267
}
2269
if(self.substr(pos, 2) == '\r\n'){
2270
res.push(self.slice(start, keepends ? pos + 2 : pos))
2271
start = pos = pos+2
2272
}else if(self[pos] == '\r' || self[pos] == '\n'){
2273
res.push(self.slice(start, keepends ? pos+1 : pos))
2274
start = pos = pos+1
2275
}else{
2276
pos++
2277
}
2278
}
2279
if(start < self.length){
2280
res.push(self.slice(start))
2281
}
2282
return res.map($B.String)
2283
}
Sep 5, 2014
2284
str
Feb 10, 2018
2285
str.startswith = function(){
2286
// Return True if string starts with the prefix, otherwise return False.
2287
// prefix can also be a tuple of prefixes to look for. With optional
2288
// start, test string beginning at that position. With optional end,
Sep 5, 2014
2289
// stop comparing string at that position.
Mar 19, 2018
2290
var $ = $B.args("startswith", 4,
2291
{self: null, prefix: null, start: null, end: null},
2292
["self", "prefix", "start", "end"],
2293
arguments, {start: 0, end: null}, null, null)
Sep 5, 2014
2294
2295
normalize_start_end($)
2296
2297
var prefixes = $.prefix
2298
if(! _b_.isinstance(prefixes, _b_.tuple)){
2299
prefixes = [prefixes]
2300
}
2301
var s = $.self.substring($.js_start, $.js_end)
2302
for(var prefix of prefixes){
2303
if(! _b_.isinstance(prefix, str)){
2304
throw _b_.TypeError.$factory("endswith first arg must be str " +
2305
"or a tuple of str, not int")
2306
}
2307
if(s.substr(0, prefix.length) == prefix){
2308
return true
2309
}
Sep 5, 2014
2310
}
2311
return false
2312
}
2313
str
Feb 10, 2018
2314
str.strip = function(){
Mar 19, 2018
2315
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
2316
arguments, {chars: _b_.None}, null, null)
2317
if($.chars === _b_.None){
2318
return $.self.trim()
2319
}
2320
return str.rstrip(str.lstrip($.self, $.chars), $.chars)
Sep 5, 2014
2321
}
2322
2323
str.swapcase = function(self){
2324
var $ = $B.args("swapcase", 1, {self}, ["self"],
2325
arguments, {}, null, null),
2326
res = "",
2327
cp
2328
2329
for(var char of to_chars(self)){
2330
cp = _b_.ord(char)
2331
if(unicode_tables.Ll[cp]){
2332
res += char.toUpperCase()
2333
}else if(unicode_tables.Lu[cp]){
2334
res += char.toLowerCase()
2337
}
2338
}
2339
return res
2340
}
2341
2342
str.title = function(self){
2343
var $ = $B.args("title", 1, {self}, ["self"],
2344
arguments, {}, null, null),
2345
state,
2348
for(var char of to_chars(self)){
2349
cp = _b_.ord(char)
2350
if(unicode_tables.Ll[cp]){
2357
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
2358
res += state ? char.toLowerCase() : char
2359
state = "word"
2360
}else{
2361
state = null
2363
}
2364
}
2365
return res
2366
}
2367
2368
str.translate = function(self, table){
Mar 19, 2018
2369
var res = [],
2370
getitem = $B.$getattr(table, "__getitem__"),
2371
cp
2372
for(var char of to_chars(self)){
2373
cp = _b_.ord(char)
2376
if(repl !== _b_.None){
2377
if(typeof repl == "string"){
2378
res.push(repl)
2379
}else if(typeof repl == "number"){
2380
res.push(String.fromCharCode(repl))
2381
}
2382
}
2383
}catch(err){
Sep 5, 2014
2386
}
Mar 19, 2018
2387
return res.join("")
Sep 5, 2014
2388
}
2389
2390
str.upper = function(self){
2391
var $ = $B.args("upper", 1, {self: null}, ["self"],
2392
arguments, {}, null, null)
2393
return self.toUpperCase()
2394
}
2395
Mar 19, 2018
2396
str.zfill = function(self, width){
Mar 19, 2018
2397
var $ = $B.args("zfill", 2, {self: null, width: null},
2398
["self", "width"], arguments, {}, null, null),
2399
len = str.__len__(self)
2400
if($.width <= len){
2401
return self
2402
}
Mar 19, 2018
2404
case "+":
2405
case "-":
2406
return self.charAt(0) +
2407
"0".repeat($.width - len) + self.substr(1)
2409
return "0".repeat($.width - len) + self
Sep 5, 2014
2411
}
2412
2413
str.$factory = function(arg, encoding, errors){
2414
if(arguments.length == 0){
2415
return ""
2416
}
2418
return $B.UndefinedClass.__str__()
2419
}else if(arg === null){
2420
return '<Javascript null>'
2422
if(encoding !== undefined){
2423
// Arguments may be passed as keywords (cf. issue #1060)
2424
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
2425
["arg", "encoding", "errors"], arguments,
2426
{encoding: "utf-8", errors: "strict"}, null, null),
2427
encoding = $.encoding,
2428
errors = $.errors
2429
}
2430
if(typeof arg == "string" || arg instanceof String ||
2431
typeof arg == "number"){
2432
if(isFinite(arg)){
2433
return arg.toString()
2434
}
2437
if(arg.$is_class || arg.$factory){
2438
// arg is a class
2439
// In this case, str() doesn't use the attribute __str__ of the
2440
// class or its subclasses, but the attribute __str__ of the
2441
// class metaclass (usually "type") or its subclasses (usually
2442
// "object")
2443
// The metaclass is the attribute __class__ of the class dictionary
Mar 19, 2018
2444
var func = $B.$getattr(arg.__class__, "__str__")
2446
}
2448
if(arg.__class__ && arg.__class__ === _b_.bytes &&
2449
encoding !== undefined){
2450
// str(bytes, encoding, errors) is equal to
2451
// bytes.decode(encoding, errors)
2452
return _b_.bytes.decode(arg, $.encoding, $.errors)
2454
// Implicit invocation of __str__ uses method __str__ on the class,
2455
// even if arg has an attribute __str__
2456
var klass = arg.__class__ || $B.get_class(arg)
2458
return $B.JSObj.__str__($B.JSObj.$factory(arg))
2460
var method = $B.$getattr(klass , "__str__", null)
2461
if(method === null ||
2462
// if not better than object.__str__, try __repr__
2463
(arg.__class__ && arg.__class__ !== _b_.object &&
2464
method === _b_.object.__str__)){
2465
var method = $B.$getattr(klass, "__repr__")
Sep 5, 2014
2467
}
2468
catch(err){
2469
console.log("no __str__ for", arg)
Mar 19, 2018
2470
console.log("err ", err)
2471
if($B.debug > 1){console.log(err)}
2472
console.log("Warning - no method __str__ or __repr__, " +
2473
"default to toString", arg)
May 20, 2019
2474
throw err
Sep 5, 2014
2475
}
2476
return $B.$call(method)(arg)
Sep 5, 2014
2477
}
str
Feb 10, 2018
2478
2479
str.__new__ = function(cls){
Mar 19, 2018
2480
if(cls === undefined){
2481
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
Sep 5, 2014
2482
}
Mar 19, 2018
2483
return {__class__: cls}
Sep 5, 2014
2484
}
2485
str
Feb 10, 2018
2486
$B.set_func_names(str, "builtins")
Sep 5, 2014
2488
// dictionary and factory for subclasses of string
str
Feb 10, 2018
2489
var StringSubclass = $B.StringSubclass = {
Mar 19, 2018
2490
__class__: _b_.type,
2491
__mro__: [_b_.object],
2492
$infos: {
2493
__module__: "builtins",
2494
__name__: "str"
2495
},
str
Feb 10, 2018
2496
$is_class: true
Sep 5, 2014
2497
}
2498
str
Feb 10, 2018
2499
// the methods in subclass apply the methods in str to the
Sep 5, 2014
2500
// result of instance.valueOf(), which is a Javascript string
str
Feb 10, 2018
2501
for(var $attr in str){
Mar 19, 2018
2502
if(typeof str[$attr] == "function"){
Mar 19, 2018
2503
StringSubclass[$attr] = (function(attr){
Sep 5, 2014
2504
return function(){
Mar 19, 2018
2505
var args = [],
2506
pos = 0
2507
if(arguments.length > 0){
2508
var args = [arguments[0].valueOf()],
2509
pos = 1
2510
for(var i = 1, len = arguments.length; i < len; i++){
2511
args[pos++] = arguments[i]
Sep 5, 2014
2512
}
2513
}
Mar 19, 2018
2514
return str[attr].apply(null, args)
Sep 5, 2014
2515
}
2516
})($attr)
2517
}
2518
}
2519
str
Feb 10, 2018
2520
StringSubclass.__new__ = function(cls){
Sep 5, 2014
2523
str
Feb 10, 2018
2524
$B.set_func_names(StringSubclass, "builtins")
Sep 5, 2014
2526
_b_.str = str
2527
2528
// Function to parse the 2nd argument of format()
2529
$B.parse_format_spec = function(spec){
2530
if(spec == ""){
2531
this.empty = true
2532
}else{
Mar 19, 2018
2533
var pos = 0,
2534
aligns = "<>=^",
2535
digits = "0123456789",
2536
types = "bcdeEfFgGnosxX%",
2537
align_pos = aligns.indexOf(spec.charAt(0))
Mar 19, 2018
2538
if(align_pos != -1){
2539
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
2540
// If the second char is also an alignment specifier, the
2541
// first char is the fill value
2542
this.fill = spec.charAt(0)
2543
this.align = spec.charAt(1)
2544
pos = 2
2545
}else{
2546
// The first character defines alignment : fill defaults to ' '
Mar 19, 2018
2547
this.align = aligns[align_pos]
2548
this.fill = " "
2549
pos++
2550
}
2551
}else{
2552
align_pos = aligns.indexOf(spec.charAt(1))
Mar 19, 2018
2553
if(spec.charAt(1) && align_pos != -1){
2554
// The second character defines alignment : fill is the first one
Mar 19, 2018
2555
this.align = aligns[align_pos]
2556
this.fill = spec.charAt(0)
2557
pos = 2
2558
}
2559
}
2560
var car = spec.charAt(pos)
Mar 19, 2018
2561
if(car == "+" || car == "-" || car == " "){
2562
this.sign = car
2563
pos++
2564
car = spec.charAt(pos)
2566
if(car == "#"){
2567
this.alternate = true; pos++; car = spec.charAt(pos)
2568
}
Mar 19, 2018
2569
if(car == "0"){
Mar 19, 2018
2570
// sign-aware : equivalent to fill = 0 and align == "="
Mar 19, 2018
2571
this.fill = "0"
2572
if(align_pos == -1){
2573
this.align = "="
2574
}
Mar 19, 2018
2575
pos++
2576
car = spec.charAt(pos)
2577
}
Mar 19, 2018
2578
while(car && digits.indexOf(car) > -1){
2579
if(this.width === undefined){
2580
this.width = car
2581
}else{
2582
this.width += car
2583
}
Mar 19, 2018
2584
pos++
2585
car = spec.charAt(pos)
2587
if(this.width !== undefined){
2588
this.width = parseInt(this.width)
2589
}
2590
if(this.width === undefined && car == "{"){
2591
// Width is determined by a parameter
2592
var end_param_pos = spec.substr(pos).search("}")
2593
this.width = spec.substring(pos, end_param_pos)
2594
console.log("width", "[" + this.width + "]")
2595
pos += end_param_pos + 1
2596
}
2597
if(car == ","){
2598
this.comma = true
2599
pos++
2600
car = spec.charAt(pos)
2601
}
Mar 19, 2018
2602
if(car == "."){
2603
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
2604
throw _b_.ValueError.$factory(
2605
"Missing precision in format spec")
Mar 19, 2018
2607
this.precision = spec.charAt(pos + 1)
2608
pos += 2
2609
car = spec.charAt(pos)
2610
while(car && digits.indexOf(car) > -1){
Mar 21, 2018
2611
this.precision += car
Mar 19, 2018
2612
pos++
2613
car = spec.charAt(pos)
2614
}
2615
this.precision = parseInt(this.precision)
2616
}
Mar 19, 2018
2617
if(car && types.indexOf(car) > -1){
2618
this.type = car
2619
pos++
2620
car = spec.charAt(pos)
2621
}
2622
if(pos !== spec.length){
2623
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
2627
this.toString = function(){
Mar 19, 2018
2628
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
2629
(this.align || "") +
2630
(this.sign || "") +
2631
(this.alternate ? "#" : "") +
2632
(this.sign_aware ? "0" : "") +
2633
(this.width || "") +
2634
(this.comma ? "," : "") +
2635
(this.precision ? "." + this.precision : "") +
2636
(this.type || "")
2637
}
2638
}
2639
2640
$B.format_width = function(s, fmt){
Mar 19, 2018
2641
if(fmt.width && s.length < fmt.width){
2642
var fill = fmt.fill || " ",
2643
align = fmt.align || "<",
2644
missing = fmt.width - s.length
2645
switch(align){
Mar 19, 2018
2646
case "<":
2647
return s + fill.repeat(missing)
2648
case ">":
2649
return fill.repeat(missing) + s
2650
case "=":
2651
if("+-".indexOf(s.charAt(0)) > -1){
2652
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
2653
}else{
Mar 19, 2018
2654
return fill.repeat(missing) + s
Mar 19, 2018
2656
case "^":
2657
var left = parseInt(missing / 2)
2658
return fill.repeat(left) + s + fill.repeat(missing - left)
2659
}
2660
}
2661
return s
2662
}
2663
2664
function fstring_expression(start){
Mar 19, 2018
2665
this.type = "expression"
Mar 19, 2018
2667
this.expression = ""
2668
this.conversion = null
2669
this.fmt = null
2670
}
2671
2672
function fstring_error(msg, pos){
2673
error = Error(msg)
2674
error.position = pos
2675
throw error
2676
}
2677
2678
$B.parse_fstring = function(string){
2679
// Parse a f-string
2680
var elts = [],
2681
pos = 0,
Mar 19, 2018
2682
current = "",
2683
ctype = null,
2684
nb_braces = 0,
2685
expr_start,
2686
car
2687
Mar 19, 2018
2688
while(pos < string.length){
2689
if(ctype === null){
2690
car = string.charAt(pos)
Mar 19, 2018
2691
if(car == "{"){
Mar 21, 2018
2692
if(string.charAt(pos + 1) == "{"){
Mar 19, 2018
2693
ctype = "string"
2694
current = "{"
2695
pos += 2
2696
}else{
Mar 19, 2018
2697
ctype = "expression"
2698
expr_start = pos + 1
2699
nb_braces = 1
2700
pos++
2701
}
Mar 19, 2018
2702
}else if(car == "}"){
Mar 21, 2018
2703
if(string.charAt(pos + 1) == car){
Mar 19, 2018
2704
ctype = "string"
2705
current = "}"
2706
pos += 2
2707
}else{
2708
fstring_error(" f-string: single '}' is not allowed",
2709
pos)
2710
}
2711
}else{
Mar 19, 2018
2712
ctype = "string"
2713
current = car
2714
pos++
Mar 19, 2018
2716
}else if(ctype == "string"){
2717
// end of string is the first single { or end of string
Mar 19, 2018
2718
var i = pos
2719
while(i < string.length){
2720
car = string.charAt(i)
Mar 19, 2018
2721
if(car == "{"){
Mar 21, 2018
2722
if(string.charAt(i + 1) == "{"){
Mar 19, 2018
2723
current += "{"
2724
i += 2
2725
}else{
2726
elts.push(current)
Mar 19, 2018
2727
ctype = "expression"
2728
expr_start = i + 1
Mar 19, 2018
2729
pos = i + 1
2730
break
2731
}
Mar 19, 2018
2732
}else if(car == "}"){
2733
if(string.charAt(i + 1) == car){
2734
current += car
2735
i += 2
2736
}else{
2737
fstring_error(" f-string: single '}' is not allowed",
2738
pos)
2739
}
2740
}else{
2741
current += car
2742
i++
2743
}
2744
}
Mar 19, 2018
2745
pos = i + 1
2746
}else if(ctype == "debug"){
2747
// after the equal sign, whitespace are ignored and the only
2748
// valid characters are } and :
2749
while(string.charAt(i) == " "){i++}
2750
if(string.charAt(i) == "}"){
2751
// end of debug expression
2752
elts.push(current)
2753
ctype = null
2754
current = ""
2755
pos = i + 1
2756
}
2757
}else{
2758
// End of expression is the } matching the opening {
2759
// There may be nested braces
2760
var i = pos,
2761
nb_braces = 1,
2762
nb_paren = 0,
2763
current = new fstring_expression(expr_start)
Mar 19, 2018
2764
while(i < string.length){
2765
car = string.charAt(i)
Mar 19, 2018
2766
if(car == "{" && nb_paren == 0){
2767
nb_braces++
2768
current.expression += car
2769
i++
Mar 19, 2018
2770
}else if(car == "}" && nb_paren == 0){
2771
nb_braces -= 1
Mar 19, 2018
2772
if(nb_braces == 0){
2773
// end of expression
2774
if(current.expression == ""){
2775
fstring_error("f-string: empty expression not allowed",
2776
pos)
2777
}
2778
elts.push(current)
2779
ctype = null
Mar 19, 2018
2780
current = ""
2781
pos = i + 1
2784
current.expression += car
2785
i++
Mar 19, 2018
2786
}else if(car == "\\"){
2787
// backslash is not allowed in expressions
2788
throw Error("f-string expression part cannot include a" +
2789
" backslash")
Mar 19, 2018
2790
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
2791
":}".indexOf(string.charAt(i + 2)) > -1){
Mar 19, 2018
2792
if(current.expression.length == 0){
2793
throw Error("f-string: empty expression not allowed")
2794
}
Mar 19, 2018
2795
if("ars".indexOf(string.charAt(i + 1)) == -1){
2796
throw Error("f-string: invalid conversion character:" +
2797
" expected 's', 'r', or 'a'")
2798
}else{
Mar 19, 2018
2799
current.conversion = string.charAt(i + 1)
2800
i += 2
2801
}
2802
}else if(car == "(" || car == '['){
2803
nb_paren++
2804
current.expression += car
2805
i++
2806
}else if(car == ")" || car == ']'){
2807
nb_paren--
2808
current.expression += car
2809
i++
Mar 19, 2018
2810
}else if(car == '"'){
2811
// triple string ?
Mar 19, 2018
2812
if(string.substr(i, 3) == '"""'){
2813
var end = string.indexOf('"""', i + 3)
2814
if(end == -1){
2815
fstring_error("f-string: unterminated string", pos)
Mar 19, 2018
2816
}else{
2817
var trs = string.substring(i, end + 3)
2818
trs = trs.replace("\n", "\\n\\")
2819
current.expression += trs
Mar 19, 2018
2820
i = end + 3
2821
}
2822
}else{
Mar 19, 2018
2823
var end = string.indexOf('"', i + 1)
2824
if(end == -1){
2825
fstring_error("f-string: unterminated string", pos)
Mar 19, 2018
2826
}else{
2827
current.expression += string.substring(i, end + 1)
2828
i = end + 1
2829
}
2830
}
Mar 19, 2018
2831
}else if(nb_paren == 0 && car == ":"){
2832
// start format
2833
current.fmt = true
2834
var cb = 0,
2835
fmt_complete = false
2836
for(var j = i + 1; j < string.length; j++){
2837
if(string[j] == '{'){
2838
if(string[j + 1] == '{'){
2839
j += 2
2840
}else{
2841
cb++
2842
}
2843
}else if(string[j] == '}'){
2844
if(string[j + 1] == '}'){
2845
j += 2
2846
}else if(cb == 0){
2847
fmt_complete = true
2848
var fmt = string.substring(i + 1, j)
2849
current.format = $B.parse_fstring(fmt)
2850
i = j
2851
break
2852
}else{
2853
cb--
2854
}
2855
}
2856
}
2857
if(! fmt_complete){
2858
fstring_error('invalid format', pos)
2859
}
2860
}else if(car == "="){
2861
// might be a "debug expression", eg f"{x=}"
2862
var ce = current.expression,
2863
last_char = ce.charAt(ce.length - 1),
2864
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
2868
string.charAt(i + 1) == "=" ||
2869
"=!<>:".search(last_char_re) > -1){
2870
// not a debug expression
2873
}else{
2874
// add debug string
2875
tail = car
2876
while(string.charAt(i + 1).match(/\s/)){
2877
tail += string.charAt(i + 1)
2878
i++
2879
}
2880
// push simple string
2881
elts.push(current.expression + tail)
2882
// remove trailing whitespace from expression
2883
while(ce.match(/\s$/)){
2884
ce = ce.substr(0, ce.length - 1)
2885
}
2886
current.expression = ce
2887
ctype = "debug"
2888
i++
2889
}
2890
}else{
2891
current.expression += car
2892
i++
2893
}
2894
}
Mar 21, 2018
2895
if(nb_braces > 0){
2896
fstring_error("f-string: expected '}'", pos)
2897
}
2898
}
2899
}
2900
if(current.length > 0){
2901
elts.push(current)
2902
}
2903
for(var elt of elts){
2904
if(typeof elt == "object"){
2905
if(elt.fmt_pos !== undefined &&
2906
elt.expression.charAt(elt.fmt_pos) != ':'){
2907
console.log('mauvais format', string, elts)
2908
throw Error()
2909
}
2910
}
2911
}
2912
return elts
2913
}
2914
2915
var _chr = $B.codepoint2jsstring = function(i){
2916
if(i >= 0x10000 && i <= 0x10FFFF){
2917
var code = (i - 0x10000)
2918
return String.fromCodePoint(0xD800 | (code >> 10)) +
2919
String.fromCodePoint(0xDC00 | (code & 0x3FF))
2920
}else{
2921
return String.fromCodePoint(i)
2922
}
2923
}
2925
var _ord = $B.jsstring2codepoint = function(c){
2926
if(c.length == 1){
2927
return c.charCodeAt(0)
2928
}
2929
var code = 0x10000
2930
code += (c.charCodeAt(0) & 0x03FF) << 10
2931
code += (c.charCodeAt(1) & 0x03FF)
2932
return code
2933
}
2934
Sep 5, 2014
2935
})(__BRYTHON__)