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