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