Skip to content
Permalink
Newer
Older
100644 1944 lines (1773 sloc) 63.6 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
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__
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'")
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("Sign not allowed in string format specifier")
134
}
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('string index out of range')
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(arg))
161
throw _b_.TypeError('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(val) // yes, floats are valid (they are cast to int)
546
} catch (err) {
547
throw _b_.TypeError('%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
636
}else{
637
getitem = _b_.getattr(args,'__getitem__', null)
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("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("format requires a mapping")
656
}
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("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("incomplete format")
697
}
698
throw _b_.ValueError("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("%" + 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("incomplete format")
743
}
744
pos = newpos + 1
745
} while (pos < length)
747
if(argpos!==null){
748
if(args.length>argpos){
749
throw _b_.TypeError('not enough arguments for format string')
750
}else if(args.length<argpos){
751
throw _b_.TypeError('not all arguments converted during string formatting')
752
}
753
}else if(nbph==0){
754
throw _b_.TypeError('not all arguments converted during string formatting')
755
}
Sep 5, 2014
758
759
$StringDict.__mro__ = [$ObjectDict]
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(
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("'str' object does not support item assignment")
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(
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("OPERATOR not implemented for class str")
815
}
816
817
$StringDict.title = unicode.title;
818
$StringDict.capitalize = unicode.capitalize;
819
$StringDict.casefold = unicode.casefold;
820
$StringDict.islower = unicode.islower;
821
$StringDict.isupper = unicode.isupper;
822
$StringDict.istitle = unicode.istitle;
823
$StringDict.isspace = unicode.isspace;
824
$StringDict.isalpha = unicode.isalpha;
825
$StringDict.isalnum = unicode.isalnum;
826
$StringDict.isdecimal = unicode.isdecimal;
827
$StringDict.isdigit = unicode.isdigit;
828
$StringDict.isnumeric = unicode.isnumeric;
829
$StringDict.isidentifier = unicode.isidentifier;
830
$StringDict.isprintable = unicode.isprintable;
831
$StringDict.lower = unicode.lower;
832
$StringDict.swapcase = unicode.swapcase;
833
$StringDict.upper = unicode.upper;
Sep 5, 2014
834
835
$StringDict.center = function(self,width,fillchar){
836
var $=$B.args("center",3,
837
{self:null, width:null, fillchar:null},
838
['self', 'width', 'fillchar'],
839
arguments,{fillchar:' '},null,null)
840
841
if($.width<=self.length) return self
843
var pad = parseInt(($.width-self.length)/2)
844
var res = $.fillchar.repeat(pad)
Sep 5, 2014
845
res += self + res
846
if(res.length<$.width){res += $.fillchar}
Sep 5, 2014
847
return res
848
}
849
850
$StringDict.count = function(){
851
var $ = $B.args('count', 4, {self:null, sub:null, start:null, stop:null},
852
['self', 'sub', 'start', 'stop'], arguments, {start:null, stop:null},
853
null, null)
854
if(!(typeof $.sub==="string")){throw _b_.TypeError(
855
"Can't convert '"+$B.get_class($.sub).__name__+"' object to str implicitly")}
856
var substr = $.self
857
if($.start!==null){
858
var _slice
859
if($.stop!==null){_slice = _b_.slice($.start, $.stop)}
860
else{_slice = _b_.slice($.start,$.self.length)}
861
substr = $StringDict.__getitem__.apply(null, [$.self].concat(_slice))
862
}else{
863
if($.self.length+$.sub.length==0){return 1} // ''.count('') = 1
864
}
865
if($.sub.length==0){
866
if($.start==$.self.length){return 1} // 'aaa'.count('',3) = 1
867
else if(substr.length==0){return 0} // 'aaa'.count('',4) = 0
868
return substr.length+1
869
}
870
var n=0, pos=0
871
while(pos<substr.length){
872
pos=substr.indexOf($.sub,pos)
873
if(pos>=0){ n++; pos+=$.sub.length} else break;
Sep 5, 2014
874
}
875
return n
876
}
877
878
$StringDict.encode = function(self, encoding) {
879
if (encoding === undefined) encoding='utf-8'
880
if(encoding=='rot13' || encoding=='rot_13'){
881
// Special case : returns a string
882
var res = ''
883
for(var i=0, _len = self.length; i<_len ; i++){
884
var char = self.charAt(i)
885
if(('a'<=char && char<='m') || ('A'<=char && char<='M')){
886
res += String.fromCharCode(String.charCodeAt(char)+13)
887
}else if(('m'<char && char<='z') || ('M'<char && char<='Z')){
888
res += String.fromCharCode(String.charCodeAt(char)-13)
889
}else{res += char}
890
}
891
return res
892
}
893
return _b_.bytes(self, encoding)
Sep 5, 2014
894
}
895
Sep 20, 2015
896
$StringDict.endswith = function(){
897
// Return True if the string ends with the specified suffix, otherwise
898
// return False. suffix can also be a tuple of suffixes to look for.
899
// With optional start, test beginning at that position. With optional
Sep 5, 2014
900
// end, stop comparing at that position.
Sep 20, 2015
901
var $=$B.args("endswith",4,
902
{self:null, suffix:null, start:null, end:null},
903
['self', 'suffix', 'start', 'end'],
Sep 20, 2015
904
arguments,{start:0, end:null},null,null)
905
906
normalize_start_end($)
907
908
var suffixes = $.suffix
Sep 5, 2014
909
if(!isinstance(suffixes,_b_.tuple)){suffixes=[suffixes]}
Sep 20, 2015
911
var s = $.self.substring($.start,$.end)
912
for(var i=0, _len_i = suffixes.length; i < _len_i;i++){
913
var suffix = suffixes[i]
Sep 20, 2015
914
if(!_b_.isinstance(suffix, str)){throw _b_.TypeError(
915
"endswith first arg must be str or a tuple of str, not int")}
Sep 5, 2014
916
if(suffix.length<=s.length &&
917
s.substr(s.length-suffix.length)==suffix) return true
918
}
919
return false
920
}
921
922
$StringDict.expandtabs = function(self, tabsize) {
923
var $ = $B.args('expandtabs', 2, {self:null, tabsize:null},
924
['self', 'tabsize'], arguments, {tabsize:8}, null, null)
925
var s=$B.$GetInt($.tabsize), col=0,pos=0,res=''
926
if(s==1){return self.replace(/\t/g,' ')}
927
while(pos<self.length){
928
var car = self.charAt(pos)
929
switch(car){
930
case '\t':
931
while(col%s > 0){res += ' ';col++}
932
break
933
case '\r':
934
case '\n':
935
res += car
936
col = 0
937
break
938
default:
939
res += car
940
col++
941
break
942
}
943
pos++
944
}
Sep 5, 2014
947
}
948
949
$StringDict.find = function(){
950
// Return the lowest index in the string where substring sub is found,
951
// such that sub is contained in the slice s[start:end]. Optional
952
// arguments start and end are interpreted as in slice notation.
Sep 5, 2014
953
// Return -1 if sub is not found.
954
var $=$B.args("$StringDict.find",4,
955
{self:null, sub:null, start:null, end:null},
957
arguments,{start:0,end:null},null,null)
958
check_str($.sub)
961
if(!isinstance($.start,_b_.int)||!isinstance($.end,_b_.int)){
Sep 5, 2014
962
throw _b_.TypeError(
963
"slice indices must be integers or None or have an __index__ method")}
964
var s = $.self.substring($.start,$.end)
965
966
if($.sub.length==0 && $.start==$.self.length){return $.self.length}
967
if(s.length+$.sub.length==0){return -1}
968
969
var last_search = s.length-$.sub.length
970
for(var i=0;i<=last_search;i++){
971
if(s.substr(i, $.sub.length)==$.sub){return $.start+i}
Sep 5, 2014
972
}
Sep 5, 2014
974
}
975
976
// Next function used by method .format()
977
978
function parse_format(fmt_string){
Sep 5, 2014
979
980
// Parse a "format string", as described in the Python documentation
981
// Return a format object. For the format string
982
// a.x[z]!r:...
983
// the object has attributes :
984
// - name : "a"
985
// - name_ext : [".x", "[z]"]
986
// - conv : r
987
// - spec : rest of string after :
Sep 5, 2014
988
989
var elts = fmt_string.split(':'), name, conv, spec, name_ext=[]
990
if(elts.length==1){
991
// No : in the string : it only contains a name
992
name = fmt_string
993
}else{
994
// name is before the first ":"
995
// spec (the format specification) is after
996
name = elts[0]
997
spec = elts.splice(1).join(':')
998
}
999
1000
var elts = name.split('!')
1001
if(elts.length>1){
1002
name=elts[0]
1003
conv=elts[1] // conversion flag
1004
if(conv.length!==1 || 'ras'.search(conv)==-1){
1005
throw _b_.ValueError('wrong conversion flag '+conv)
1006
}
1007
}
Sep 5, 2014
1008
1009
if(name!==undefined){
1010
// "name' may be a subscription or attribute
1011
// Put these "extensions" in the list "name_ext"
1012
function name_repl(match){
1013
name_ext.push(match)
1014
return ''
1015
}
1016
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
1017
name = name.replace(name_ext_re, name_repl)
1018
}
Sep 5, 2014
1019
1020
return {name: name, name_ext: name_ext,
1021
conv: conv, spec: spec||''}
1022
}
Sep 5, 2014
1023
1024
$StringDict.format = function(self) {
Sep 5, 2014
1025
1026
var $ = $B.args('format', 1, {self:null}, ['self'],
1027
arguments, {}, 'args', 'kw')
1028
1029
// Parse self to detect formatting instructions
1030
// Create a list "parts" made of sections of the string :
1031
// - elements of even rank are literal text
1032
// - elements of odd rank are "format objects", built from the
1033
// format strings in self (of the form {...})
1034
var pos=0,
1035
_len=self.length,
1036
car,
1037
text='',
1038
parts=[],
1040
1041
while(pos<_len){
1042
car = self.charAt(pos)
1043
if(car=='{' && self.charAt(pos+1)=='{'){
1044
// replace {{ by literal {
1045
text += '{'
1046
pos+=2
1047
}else if(car=='}' && self.charAt(pos+1)=='}'){
1048
// replace }} by literal }
1049
text += '}'
1050
pos+=2
1051
}else if(car=='{'){
1052
// Start of a format string
1054
// Store current literal text
1055
parts.push(text)
1056
1057
// Search the end of the format string, ie the } closing the
1058
// opening {. Since the string can contain other pairs {} for
1059
// nested formatting, an integer nb is incremented for each { and
1060
// decremented for each } ; the end of the format string is
1061
// reached when nb==0
1062
var end = pos+1, nb=1
1063
while(end<_len){
1064
if(self.charAt(end)=='{'){nb++;end++}
1065
else if(self.charAt(end)=='}'){
1066
nb--;end++
1067
if(nb==0){
1068
// End of format string
1069
var fmt_string = self.substring(pos+1, end-1)
1070
1071
// Create a format object, by function parse_format
1072
var fmt_obj = parse_format(fmt_string)
1073
1074
// If no name is explicitely provided, use the rank
1075
if(!fmt_obj.name){
1076
fmt_obj.name=rank+''
1077
rank++
1078
}
Sep 5, 2014
1079
1080
if(fmt_obj.spec!==undefined){
1081
// "spec" may contain "nested replacement fields"
1082
// In this case, evaluate them using the positional
1083
// or keyword arguments passed to format()
1084
function replace_nested(name, key){
1085
if(/\d+/.exec(key)){
1086
// If key is numeric, search in positional
1087
// arguments
1088
return _b_.tuple.$dict.__getitem__($.args,
1089
parseInt(key))
1090
}else{
1091
// Else try in keyword arguments
1092
return _b_.dict.$dict.__getitem__($.kw, key)
1093
}
1095
fmt_obj.spec = fmt_obj.spec.replace(/\{(.+?)\}/g,
1096
replace_nested)
1097
}
1099
// Store format object in list "parts"
1100
parts.push(fmt_obj)
1101
text = ''
1102
break
1103
}
1104
}else{end++}
Sep 5, 2014
1105
}
1106
if(nb>0){throw ValueError("wrong format "+self)}
1107
pos = end
1108
}else{text += car;pos++}
Sep 5, 2014
1109
}
1110
if(text){parts.push(text)}
1112
// Apply formatting to the values passed to format()
1113
var res = '', fmt
1114
for(var i=0;i<parts.length;i++){
1115
// Literal text is added unchanged
1116
if(typeof parts[i]=='string'){res += parts[i];continue}
1118
// Format objects
1119
fmt = parts[i]
1120
if(fmt.name.charAt(0).search(/\d/)>-1){
1121
// Numerical reference : use positional arguments
1122
var pos = parseInt(fmt.name),
1123
value = _b_.tuple.$dict.__getitem__($.args, pos)
1124
}else{
1125
// Use keyword arguments
1126
var value = _b_.dict.$dict.__getitem__($.kw, fmt.name)
1127
}
1128
// If name has extensions (attributes or subscriptions)
1129
for(var j=0;j<fmt.name_ext.length;j++){
1130
var ext = fmt.name_ext[j]
1131
if(ext.charAt(0)=='.'){
1132
// Attribute
1133
value = _b_.getattr(value, ext.substr(1))
1134
}else{
1135
// Subscription
1136
var key = ext.substr(1, ext.length-2)
1137
// An index made of digits is transformed into an integer
1138
if(key.charAt(0).search(/\d/)>-1){key = parseInt(key)}
1139
value = _b_.getattr(value, '__getitem__')(key)
1140
}
1141
}
1142
// If the conversion flag is set, first call a function to convert
1143
// the value
1144
if(fmt.conv=='a'){value = _b_.ascii(value)}
1145
else if(fmt.conv=='r'){value = _b_.repr(value)}
1146
else if(fmt.conv=='s'){value = _b_.str(value)}
1148
// Call attribute __format__ to perform the actual formatting
1149
if(value.__class__===$B.$factory){
1150
// For classes, don't use the class __format__ method
1151
res += value.$dict.__class__.__format__(value, fmt.spec)
1152
}else{
1153
res += _b_.getattr(value, '__format__')(fmt.spec)
1154
}
Sep 5, 2014
1155
}
Sep 5, 2014
1157
}
1158
1159
$StringDict.format_map = function(self) {
1160
throw NotImplementedError("function format_map not implemented yet");
1161
}
1162
1163
$StringDict.index = function(self){
1164
// Like find(), but raise ValueError when the substring is not found.
1165
var res = $StringDict.find.apply(null,arguments)
Sep 5, 2014
1166
if(res===-1) throw _b_.ValueError("substring not found")
1167
return res
1168
}
1169
1170
$StringDict.join = function(){
1171
var $=$B.args('join',2,{self:null,iterable:null},
1172
['self', 'iterable'], arguments, {}, null, null)
1174
var iterable=_b_.iter($.iterable)
1175
var res = [],
1176
count=0,
1177
ce = $B.current_exception
Sep 5, 2014
1178
while(1){
1179
try{
1180
var obj2 = _b_.next(iterable)
Sep 5, 2014
1181
if(!isinstance(obj2,str)){throw _b_.TypeError(
1182
"sequence item "+count+": expected str instance, "+$B.get_class(obj2).__name__+" found")}
1183
res.push(obj2)
Sep 5, 2014
1184
}catch(err){
1185
if(_b_.isinstance(err, _b_.StopIteration)){
1186
$B.current_exception = ce
1187
break
1188
}
Sep 5, 2014
1189
else{throw err}
1190
}
1191
}
1192
return res.join($.self)
Sep 5, 2014
1193
}
1194
1195
$StringDict.ljust = function(self) {
1196
var $=$B.args('ljust',3,{self:null,width:null,fillchar:null},
1197
['self','width','fillchar'],arguments,{fillchar:' '},null,null)
1198
1199
if ($.width <= self.length) return self
1200
return self + $.fillchar.repeat($.width - self.length)
Sep 5, 2014
1201
}
1202
1203
$StringDict.lstrip = function(self,x){
1204
var $=$B.args('lstrip',2,{self:null,chars:null},['self','chars'],
1205
arguments,{chars:_b_.None},null,null)
1206
if($.chars===_b_.None){return $.self.trimLeft()}
1207
for (var i = 0; i < $.self.length; i++) {
1208
if ($.chars.indexOf($.self.charAt(i)) === -1) {
1209
return $.self.substring(i);
1210
}
1211
}
1212
return '';
Sep 5, 2014
1213
}
1214
1215
// note, maketrans should be a static function.
1216
$StringDict.maketrans = function() {
1217
var $ = $B.args('maketrans', 3, {x:null,y:null,z:null},['x','y','z'],
1218
arguments, {y:null, z:null}, null, null)
1220
var _t=_b_.dict()
1221
// make 'default' translate table
1222
for(var i=0; i < 256; i++) _t.$numeric_dict[i]=i
1223
1224
if($.y===null && $.z===null){
1225
// If there is only one argument, it must be a dictionary mapping
1226
// Unicode ordinals (integers) or characters (strings of length 1) to
1227
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1228
// keys will then be converted to ordinals.
1229
if(!_b_.isinstance($.x, _b_.dict)){
1230
throw _b_.TypeError('maketrans only argument must be a dict')
1231
}
1232
var items = _b_.list(_b_.dict.$dict.items($.x))
1233
for(var i=0, len=items.length;i<len;i++){
1234
var k = items[i][0], v=items[i][1]
1235
if(!_b_.isinstance(k, _b_.int)){
1236
if(_b_.isinstance(k, _b_.str) && k.length==1){k = _b_.ord(k)}
1237
else{throw _b_.TypeError("dictionary key "+k+
1238
" is not int or 1-char string")}
1239
}
1240
if(v!==_b_.None && !_b_.isinstance(v, [_b_.int, _b_.str])){
1241
throw _b_.TypeError("dictionary value "+v+
1242
" is not None, integer or string")
1243
}
1244
_t.$numeric_dict[k] = v
1245
}
1246
return _t
1247
}else{
1248
// If there are two arguments, they must be strings of equal length,
1249
// and in the resulting dictionary, each character in x will be mapped
1250
// to the character at the same position in y
1251
if(!(_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1252
throw _b_.TypeError("maketrans arguments must be strings")
1253
}else if($.x.length!==$.y.length){
1254
throw _b_.TypeError("maketrans arguments must be strings or same length")
1255
}else{
1256
var toNone = {}
1257
if($.z!==null){
1258
// If there is a third argument, it must be a string, whose
1259
// characters will be mapped to None in the result
1260
if(!_b_.isinstance($.z, _b_.str)){
1261
throw _b_.TypeError('maketrans third argument must be a string')
1262
}
1263
for(var i=0,len=$.z.length;i<len;i++){
1264
toNone[_b_.ord($.z.charAt(i))] = true
1265
}
1267
for(var i=0,len=$.x.length;i<len;i++){
1268
_t.$numeric_dict[_b_.ord($.x.charAt(i))] = _b_.ord($.y.charAt(i))
1269
}
1270
for(var k in toNone){
1271
_t.$numeric_dict[k] = _b_.None
1272
}
1273
return _t
1274
}
1275
}
Sep 5, 2014
1276
}
1277
1278
$StringDict.partition = function() {
1279
var $=$B.args('partition',2,{self:null,sep:null},['self','sep'],
1280
arguments,{},null,null)
1281
if($.sep==''){throw _b_.ValueError('empty separator')}
1282
check_str($.sep)
1283
var i=$.self.indexOf($.sep)
1284
if (i== -1) return _b_.tuple([$.self, '', ''])
1285
return _b_.tuple([$.self.substring(0,i), $.sep,
1286
$.self.substring(i+$.sep.length)])
Sep 5, 2014
1287
}
1288
1289
function $re_escape(str)
1290
{
1291
var specials = "[.*+?|()$^"
1292
for(var i=0, _len_i = specials.length; i < _len_i;i++){
Sep 5, 2014
1293
var re = new RegExp('\\'+specials.charAt(i),'g')
1294
str = str.replace(re, "\\"+specials.charAt(i))
1295
}
1296
return str
1297
}
1298
1299
$StringDict.replace = function(self, old, _new, count) {
1300
// Replaces occurrences of 'old' by '_new'. Count references
1301
// the number of times to replace. In CPython, negative or undefined
1302
// values of count means replace all.
1303
var $ = $B.args('replace', 4, {self:null,old:null,$$new:null,count:null},
1304
['self','old','$$new','count'], arguments, {count:-1},null,null),
1305
count=$.count,self=$.self,old=$.old,_new=$.$$new
1306
// Validate type of old
1307
check_str(old)
1308
check_str(_new)
1309
// Validate instance type of 'count'
1310
if (!isinstance(count,[_b_.int,_b_.float])) {
1311
throw _b_.TypeError("'" + $B.get_class(count).__name__ +
1312
"' object cannot be interpreted as an integer");
1313
} else if (isinstance(count, _b_.float)) {
1314
throw _b_.TypeError("integer argument expected, got float");
1315
}
1316
if(count==0){return self}
1317
if(count.__class__==$B.LongInt.$dict){count=parseInt(count.value)}
1318
if(old==''){
1319
if(_new==''){return self}
1320
if(self==''){return _new}
1321
var elts=self.split('')
1322
if(count>-1 && elts.length>=count){
1323
var rest = elts.slice(count).join('')
1324
return _new+elts.slice(0, count).join(_new)+rest
1325
}else{return _new+elts.join(_new)+_new}
1326
}else{
1327
var elts = $StringDict.split(self,old,count)
Sep 5, 2014
1328
}
1330
var res = self, pos = -1
1331
if(old.length==0){
1332
var res = _new
1333
for(var i=0;i<elts.length;i++){
1334
res += elts[i]+_new
1335
}
1336
return res+rest
1337
}
1339
if (count < 0) count = res.length;
1340
while (count > 0) {
1341
pos = res.indexOf(old, pos);
1342
if (pos < 0)
1343
break;
1344
res = res.substr(0, pos) + _new + res.substr(pos + old.length);
1345
pos = pos + _new.length;
1346
count--;
1347
}
1348
return res;
Sep 5, 2014
1349
}
1350
1351
$StringDict.rfind = function(self){
1352
// Return the highest index in the string where substring sub is found,
1353
// such that sub is contained within s[start:end]. Optional arguments
Sep 5, 2014
1354
// start and end are interpreted as in slice notation. Return -1 on failure.
1356
{self:null, sub:null, start:null, end:null},
1357
['self', 'sub', 'start', 'end'],
1358
arguments,{start:0, end:null},null,null)
Sep 5, 2014
1359
1362
check_str($.sub)
1364
if($.sub.length==0){
1365
if($.start>$.self.length){return -1}
1366
else{return $.self.length}
1367
}
1368
var sublen = $.sub.length
1370
for(var i=$.end-sublen;i>=$.start;i--){
1371
if($.self.substr(i, sublen)==$.sub){return i}
1372
}
1373
return -1
Sep 5, 2014
1374
}
1375
1376
$StringDict.rindex = function(){
1377
// Like rfind() but raises ValueError when the substring sub is not found
1378
var res = $StringDict.rfind.apply(null,arguments)
Sep 5, 2014
1379
if(res==-1){throw _b_.ValueError("substring not found")}
1380
return res
1381
}
1382
1383
$StringDict.rjust = function(self) {
1385
{self:null, width:null, fillchar:null},
1386
['self', 'width', 'fillchar'],
1387
arguments,{fillchar:' '},null,null)
Sep 5, 2014
1388
1389
if ($.width <= self.length) return self
Sep 5, 2014
1390
1391
return $.fillchar.repeat($.width - self.length) + self
Sep 5, 2014
1392
}
1393
1394
$StringDict.rpartition = function(self,sep) {
1395
var $=$B.args('rpartition',2,{self:null,sep:null},['self','sep'],
1396
arguments,{},null,null)
1397
check_str($.sep)
1398
var self = reverse($.self),
1399
sep = reverse($.sep)
1400
var items = $StringDict.partition(self,sep).reverse()
1401
for(var i=0;i<items.length;i++){
1402
items[i]=items[i].split('').reverse().join('')
1403
}
1404
return items
Sep 5, 2014
1405
}
1406
1407
$StringDict.rsplit = function(self) {
1408
var $=$B.args("rsplit",3,{self:null,sep:null,maxsplit:null},
1409
['self','sep','maxsplit'],arguments,
1410
{sep:_b_.None, maxsplit:-1},null,null),
1412
1413
// Use split on the reverse of the string and of separator
1414
var rev_str = reverse($.self),
1415
rev_sep = sep === _b_.None ? sep : reverse($.sep),
1416
rev_res = $StringDict.split(rev_str, rev_sep, $.maxsplit)
1418
// Reverse the list, then each string inside the list
1419
rev_res.reverse()
1420
for(var i=0;i<rev_res.length;i++){
1421
rev_res[i] = reverse(rev_res[i])
Sep 5, 2014
1424
}
1425
1426
$StringDict.rstrip = function(self,x){
1427
var $=$B.args('rstrip',2,{self:null,chars:null},['self','chars'],
1428
arguments,{chars:_b_.None},null,null)
1429
if($.chars===_b_.None){return $.self.trimRight()}
1430
for (var j = $.self.length-1; j >= 0; j--) {
1431
if ($.chars.indexOf($.self.charAt(j)) === -1) {
1432
return $.self.substring(0,j+1);
1433
}
1434
}
1435
return '';
Sep 5, 2014
1436
}
1437
1438
$StringDict.split = function(){
1440
var $=$B.args("split",3,{self:null,sep:null,maxsplit:null},
1441
['self','sep','maxsplit'],arguments,
1442
{sep:_b_.None, maxsplit:-1},null,null)
1443
var sep=$.sep,maxsplit=$.maxsplit,self=$.self
1444
if(maxsplit.__class__===$B.LongInt.$dict){maxsplit=parseInt(maxsplit.value)}
1445
if(sep=='') throw _b_.ValueError('empty separator')
Sep 5, 2014
1447
var res = []
1448
while(pos<self.length&&self.charAt(pos).search(/\s/)>-1){pos++}
1449
if(pos===self.length-1){return [self]}
Sep 5, 2014
1450
var name = ''
1451
while(1){
1452
if(self.charAt(pos).search(/\s/)===-1){
1453
if(name===''){name=self.charAt(pos)}
1454
else{name+=self.charAt(pos)}
1455
}else{
1456
if(name!==''){
1457
res.push(name)
1458
if(maxsplit!==-1&&res.length===maxsplit+1){
1459
res.pop()
1460
res.push(name+self.substr(pos))
1461
return res
1462
}
1463
name=''
1464
}
1465
}
1466
pos++
1467
if(pos>self.length-1){
1468
if(name){res.push(name)}
1469
break
1470
}
1471
}
1472
return res
1473
}else{
1474
var res = [],s='',seplen=sep.length
1475
if(maxsplit==0){return [self]}
1476
while(pos<self.length){
1477
if(self.substr(pos,seplen)==sep){
1478
res.push(s)
1479
pos += seplen
1480
if(maxsplit>-1 && res.length>=maxsplit){
1481
res.push(self.substr(pos))
1482
return res
1483
}
1484
s= ''
1485
}else{
1486
s += self.charAt(pos)
1487
pos++
Sep 5, 2014
1488
}
1489
}
Sep 5, 2014
1492
}
1493
}
1494
1495
$StringDict.splitlines = function(self){
1496
var $=$B.args('splitlines',2,{self:null,keepends:null},
1497
['self','keepends'],arguments,{keepends:false},null,null)
1498
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
1499
throw _b_.TypeError('integer argument expected, got '+
1500
$B.get_class($.keepends).__name)
1501
}
1502
var keepends = _b_.int($.keepends)
1503
// Remove trailing line breaks
1504
if(keepends){
1505
var res = [],
1506
start=pos,
1507
pos=0,
1508
self=$.self
1509
while(pos<self.length){
1510
if(self.substr(pos,2)=='\r\n'){
1511
res.push(self.substring(start,pos+2))
1512
start = pos+2
1513
pos = start
1514
}else if(self.charAt(pos)=='\r' || self.charAt(pos)=='\n'){
1515
res.push(self.substring(start,pos+1))
1516
start = pos+1
1517
pos = start
1518
}else{pos++}
1519
}
1520
var rest = self.substr(start)
1521
if(rest){res.push(rest)}
1522
return res
1523
}else{
1524
var self = $.self.replace(/[\r\n]$/,'')
1525
return self.split(/\n|\r\n|\r/)
1526
}
1527
}
Sep 5, 2014
1528
1529
$StringDict.startswith = function(){
1530
// Return True if string starts with the prefix, otherwise return False.
1531
// prefix can also be a tuple of prefixes to look for. With optional
1532
// start, test string beginning at that position. With optional end,
Sep 5, 2014
1533
// stop comparing string at that position.
1534
var $=$B.args("startswith",4,
1535
{self:null, prefix:null, start:null, end:null},
1536
['self', 'prefix', 'start', 'end'],
1537
arguments,{start:0, end:null},null,null)
Sep 5, 2014
1538
1539
normalize_start_end($)
1540
1541
var prefixes = $.prefix
1542
if(!isinstance(prefixes,_b_.tuple)){prefixes=[prefixes]}
1544
var s = $.self.substring($.start,$.end)
1545
for(var i=0, _len_i = prefixes.length; i < _len_i;i++){
1546
prefix = prefixes[i]
1547
if(!_b_.isinstance(prefix, str)){throw _b_.TypeError(
1548
"endswith first arg must be str or a tuple of str, not int")}
1549
if(s.substr(0,prefix.length)==prefix) return true
Sep 5, 2014
1550
}
1551
return false
1552
Sep 5, 2014
1553
}
1554
1555
$StringDict.strip = function(){
1556
var $=$B.args('strip',2,{self:null,chars:null},['self','chars'],
1557
arguments,{chars:_b_.None},null,null)
1558
if($.chars===_b_.None){return $.self.trim()}
1559
for (var i = 0; i < $.self.length; i++) {
1560
if ($.chars.indexOf($.self.charAt(i)) === -1) {
1561
break;
1562
}
1563
}
1564
for (var j = $.self.length-1; j >= i; j--) {
1565
if ($.chars.indexOf($.self.charAt(j)) === -1) {
1566
break;
1567
}
1568
}
1569
return $.self.substring(i,j+1);
Sep 5, 2014
1570
}
1571
1572
$StringDict.translate = function(self,table) {
1573
var res = [], pos=0
Sep 5, 2014
1574
if (isinstance(table, _b_.dict)) {
1575
for (var i=0, _len_i = self.length; i < _len_i; i++) {
Sep 5, 2014
1576
var repl = _b_.dict.$dict.get(table,self.charCodeAt(i),-1)
1577
if(repl==-1){res[pos++]=self.charAt(i)}
1578
else if(repl!==None){res[pos++]=_b_.chr(repl)}
Sep 5, 2014
1579
}
1580
}
1581
return res.join('')
Sep 5, 2014
1582
}
1583
1584
$StringDict.zfill = function(self, width) {
1585
var $=$B.args('zfill',2,{self:null,width:null},
1586
['self','width'],arguments,{},null,null)
1587
if ($.width <= self.length) {return self}
1588
switch(self.charAt(0)){
1589
case '+':
1590
case '-':
1591
return self.charAt(0)+'0'.repeat($.width-self.length)+self.substr(1)
1592
default:
1593
return '0'.repeat(width - self.length)+self
1594
}
Sep 5, 2014
1595
}
1596
1597
function str(arg){
1599
if(arg===undefined) return '<undefined>'
1600
switch(typeof arg) {
1601
case 'string':
1602
return arg
1603
case 'number':
1604
if(isFinite(arg)){return arg.toString()}
1608
if(arg.__class__===$B.$factory){
1609
// arg is a class (the factory function)
1610
// In this case, str() doesn't use the attribute __str__ of the
1611
// class or its subclasses, but the attribute __str__ of the
1612
// class metaclass (usually "type") or its subclasses (usually
1613
// "object")
1614
// The metaclass is the attribute __class__ of the class dictionary
1615
var func = $B.$type.__getattribute__(arg.$dict.__class__, '__str__')
1616
if(func.__func__===_b_.object.$dict.__str__){return func(arg)}
1618
}
Sep 5, 2014
1619
var f = getattr(arg,'__str__')
1620
// XXX fix : if not better than object.__str__, try __repr__
Sep 5, 2014
1622
}
1623
catch(err){
1624
//console.log('err '+err)
Sep 5, 2014
1625
try{ // try __repr__
1626
var f = getattr(arg,'__repr__')
1627
//return getattr(f,'__call__')()
Sep 5, 2014
1628
}catch(err){
1629
if($B.debug>1){console.log(err)}
1630
console.log('Warning - no method __str__ or __repr__, default to toString', arg)
1631
return arg.toString()
Sep 5, 2014
1632
}
1633
}
1635
return getattr(f, '__call__')()
Sep 5, 2014
1636
}
1637
str.__class__ = $B.$factory
1638
str.$dict = $StringDict
1639
$StringDict.$factory = str
1640
$StringDict.__new__ = function(cls){
1641
if(cls===undefined){
1642
throw _b_.TypeError('str.__new__(): not enough arguments')
1643
}
1644
return {__class__:cls.$dict}
1645
}
1646
1647
$B.set_func_names($StringDict)
1648
Sep 5, 2014
1649
// dictionary and factory for subclasses of string
1650
var $StringSubclassDict = {
1651
__class__:$B.$type,
1652
__name__:'str'
1653
}
1654
1655
// the methods in subclass apply the methods in $StringDict to the
1656
// result of instance.valueOf(), which is a Javascript string
1657
for(var $attr in $StringDict){
1658
if(typeof $StringDict[$attr]=='function'){
1659
$StringSubclassDict[$attr]=(function(attr){
1660
return function(){
1661
var args = [], pos=0
Sep 5, 2014
1662
if(arguments.length>0){
1663
var args = [arguments[0].valueOf()], pos=1
1664
for(var i=1, _len_i = arguments.length; i < _len_i;i++){
1665
args[pos++]=arguments[i]
Sep 5, 2014
1666
}
1667
}
1668
return $StringDict[attr].apply(null,args)
1669
}
1670
})($attr)
1671
}
1672
}
1673
$StringSubclassDict.__mro__ = [$ObjectDict]
Sep 5, 2014
1674
1675
// factory for str subclasses
1676
$B.$StringSubclassFactory = {
1677
__class__:$B.$factory,
1678
$dict:$StringSubclassDict
1679
}
1680
1681
_b_.str = str
1682
1683
// Function to parse the 2nd argument of format()
1684
$B.parse_format_spec = function(spec){
1685
1686
if(spec==''){this.empty=true}
1687
else{
1688
var pos=0,
1689
aligns = '<>=^',
1690
digits = '0123456789',
1691
types = 'bcdeEfFgGnosxX%',
1692
align_pos = aligns.indexOf(spec.charAt(0))
1693
if(align_pos!=-1){
1694
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1))!=-1){
1695
// If the second char is also an alignment specifier, the
1696
// first char is the fill value
1697
this.fill = spec.charAt(0)
1698
this.align = spec.charAt(1)
1699
pos = 2
1700
}else{
1701
// The first character defines alignment : fill defaults to ' '
1702
this.align=aligns[align_pos];
1703
this.fill=' ';
1704
pos++
1705
}
1706
}else{
1707
align_pos = aligns.indexOf(spec.charAt(1))
1708
if(spec.charAt(1) && align_pos!=-1){
1709
// The second character defines alignment : fill is the first one
1710
this.align=aligns[align_pos]
1711
this.fill=spec.charAt(0)
1712
pos = 2
1713
}
1714
}
1715
var car = spec.charAt(pos)
1716
if(car=='+'||car=='-'||car==' '){
1717
this.sign=car;
1718
pos++;
1719
car=spec.charAt(pos);
1721
if(car=='#'){this.alternate=true;pos++;car=spec.charAt(pos)}
1722
if(car=='0'){
1723
// sign-aware : equivalent to fill=0 and align=='='
1724
this.fill='0'
1725
this.align = '='
1726
pos++;car=spec.charAt(pos)
1727
}
1728
while(car && digits.indexOf(car)>-1){
1729
if(this.width===undefined){this.width=car}
1730
else{this.width+=car}
1731
pos++;car=spec.charAt(pos)
1733
if(this.width!==undefined){this.width=parseInt(this.width)}
1734
if(car==','){this.comma=true;pos++;car=spec.charAt(pos)}
1735
if(car=='.'){
1736
if(digits.indexOf(spec.charAt(pos+1))==-1){
1737
throw _b_.ValueError("Missing precision in format spec")
1738
}
1739
this.precision = spec.charAt(pos+1)
1740
pos+=2;car=spec.charAt(pos)
1741
while(car && digits.indexOf(car)>-1){
1742
this.precision+=car;pos++;car=spec.charAt(pos)
1743
}
1744
this.precision = parseInt(this.precision)
1745
}
1746
if(car && types.indexOf(car)>-1){this.type=car;pos++;car=spec.charAt(pos)}
1747
if(pos!==spec.length){
Nov 11, 2015
1748
//console.log('error', spec, this, pos, spec.charAt(pos))
1749
throw _b_.ValueError("Invalid format specifier")
1750
}
1752
this.toString = function(){
1753
return (this.fill===undefined ? '' : _b_.str(this.fill))+
1754
(this.align||'')+
1755
(this.sign||'')+
1756
(this.alternate ? '#' : '')+
1757
(this.sign_aware ? '0' : '')+
1758
(this.width || '')+
1759
(this.comma ? ',' : '')+
1760
(this.precision ? '.'+this.precision : '')+
1761
(this.type || '')
1762
}
1763
}
1764
1765
$B.format_width = function(s, fmt){
1766
if(fmt.width && s.length<fmt.width){
1767
var fill=fmt.fill || ' ', align = fmt.align || '<',
1768
missing = fmt.width-s.length
1769
switch(align){
1770
case '<':
1771
return s+fill.repeat(missing)
1772
case '>':
1773
return fill.repeat(missing)+s
1774
case '=':
1775
if('+-'.indexOf(s.charAt(0))>-1){
1776
return s.charAt(0)+fill.repeat(missing)+s.substr(1)
1777
}else{
1778
return fill.repeat(missing)+s
1779
}
1780
case '^':
1781
var left = parseInt(missing/2)
1782
return fill.repeat(left)+s+fill.repeat(missing-left)
1783
}
1784
}
1785
return s
1786
}
1787
1788
function fstring_expression(){
1789
this.type = 'expression'
1790
this.expression = ''
1791
this.conversion = null
1792
this.fmt = null
1793
}
1794
1795
$B.parse_fstring = function(string){
1796
// Parse a f-string
1797
var elts = [],
1798
pos = 0,
1799
current = '',
1800
ctype = null,
1801
nb_braces = 0,
1802
car
1803
1804
while(pos<string.length){
1805
if(ctype===null){
1806
car = string.charAt(pos)
1807
if(car=='{'){
1808
if(string.charAt(pos+1)=='{'){
1809
ctype = 'string'
1810
current = '{'
1811
pos += 2
1812
}else{
1813
ctype = 'expression'
1814
nb_braces = 1
1815
pos++
1816
}
1817
}else if(car=='}'){
1818
if(string.charAt(pos+1)==car){
1819
ctype = 'string'
1820
current = '}'
1821
pos += 2
1822
}else{
1823
throw Error(" f-string: single '}' is not allowed")
1824
}
1825
}else{
1826
ctype = 'string'
1827
current = car
1828
pos++
1829
}
1830
}else if(ctype=='string'){
1831
// end of string is the first single { or end of string
1832
var i=pos
1833
while(i<string.length){
1834
car = string.charAt(i)
1835
if(car=='{'){
1836
if(string.charAt(i+1)=='{'){
1837
current += '{'
1838
i+=2
1839
}else{
1840
elts.push(current)
1841
ctype = 'expression'
1842
pos = i+1
1843
break
1844
}
1845
}else if(car=='}'){
1846
if(string.charAt(i+1)==car){
1847
current += car
1848
i += 2
1849
}else{
1850
throw Error(" f-string: single '}' is not allowed")
1851
}
1852
}else{
1853
current += car
1854
i++
1855
}
1856
}
1857
pos = i+1
1858
}else{
1859
// End of expression is the } matching the opening {
1860
// There may be nested braces
1861
var i = pos,
1862
nb_braces = 1,
1863
nb_paren = 0,
1864
current = new fstring_expression()
1865
while(i<string.length){
1866
car = string.charAt(i)
1867
if(car=='{' && nb_paren==0){
1868
nb_braces++
1869
current.expression += car
1870
i++
1871
}else if(car=='}' && nb_paren==0){
1872
nb_braces -= 1
1873
if(nb_braces==0){
1874
// end of expression
1875
elts.push(current)
1876
ctype = null
1877
current = ''
1878
pos = i+1
1879
break
1881
current.expression += car
1882
i++
1883
}else if(car=='\\'){
1884
// backslash is not allowed in expressions
1885
throw Error("f-string expression part cannot include a" +
1886
" backslash")
1887
}else if(nb_paren == 0 && car=='!' && current.fmt===null &&
1888
':}'.indexOf(string.charAt(i + 2))>-1){
1889
if(current.expression.length==0){
1890
throw Error("f-string: empty expression not allowed")
1891
}
1892
if('ars'.indexOf(string.charAt(i+1)) == -1){
1893
throw Error("f-string: invalid conversion character:" +
1894
" expected 's', 'r', or 'a'")
1895
}else{
1896
current.conversion = string.charAt(i+1)
1897
i += 2
1898
}
1899
}else if(car=='('){
1900
nb_paren++
1901
current.expression += car
1902
i++
1903
}else if(car==')'){
1904
nb_paren--
1905
current.expression += car
1906
i++
1907
}else if(car=='"'){
1908
// triple string ?
1909
if(string.substr(i, 3)=='"""'){
1910
var end = string.indexOf('"""', i+3)
1911
if(end==-1){throw Error("f-string: unterminated string")}
1912
else{
1913
var trs = string.substring(i, end+3)
1914
trs = trs.replace('\n', '\\n\\')
1915
current.expression += trs
1916
i = end+3
1917
}
1918
}else{
1919
var end = string.indexOf('"', i+1)
1920
if(end==-1){throw Error("f-string: unterminated string")}
1921
else{
1922
current.expression += string.substring(i, end+1)
1923
i = end+1
1924
}
1925
}
1926
}else if(nb_paren == 0 && car==':'){
1927
current.fmt = true
1928
current.expression += car
1929
i++
1930
}else{
1931
current.expression += car
1932
i++
1933
}
1934
}
1935
if(nb_braces>0){
1936
throw Error("f-string: expected '}'")
1937
}
1938
}
1939
}
1940
if(current.length>0){elts.push(current)}
1941
return elts
1942
}
1943
Sep 5, 2014
1944
})(__BRYTHON__)