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