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