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