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