Permalink
Jan 14, 2015
Jan 14, 2015
Sep 24, 2017
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
Aug 31, 2017
Jan 14, 2015
Aug 31, 2017
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Jan 14, 2015
Aug 31, 2017
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
Jan 14, 2015
Feb 9, 2016
Aug 31, 2017
Aug 31, 2017
Dec 3, 2015
Dec 3, 2015
Dec 3, 2015
Jan 6, 2016
Jan 6, 2016
Aug 31, 2017
Jan 6, 2016
Jan 6, 2016
Jan 6, 2016
Jan 6, 2016
Jan 1, 2015
Jan 1, 2015
Aug 31, 2017
Aug 31, 2017
Oct 12, 2016
Jul 10, 2017
Jun 29, 2017
Jun 29, 2017
Jun 29, 2017
Jun 29, 2017
Jul 10, 2017
Jul 10, 2017
Jul 14, 2017
Jun 29, 2017
Newer
100644
1938 lines (1768 sloc)
63.5 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
}
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__
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'")
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)
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
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 ''
165
if (self === undefined) {
166
return $StringDict.__hashvalue__ || $B.$py_next_hash-- // for hash of string type (not instance of string)
167
}
168
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;
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}
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
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)) {
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 "+"
275
} else if (flags.space) {
276
if (val >= 0) {
277
return " "
278
}
279
}
280
return ""
281
}
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
}
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
}
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
}
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
}
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
}
338
// used to capture and remove trailing zeroes
339
var trailing_zeros = /(.*?)(0+)([eE].*)/
340
var leading_zeros = /\.(0*)/
341
var trailing_dot = /\.$/
343
var validate_precision = function(precision) {
344
// force precision to limits of javascript
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
380
return format_padding(format_sign(val, flags) + format_float_precision(val, upper, flags,
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
408
}
409
if (precision < dot_idx) {
410
precision = dot_idx
411
}
412
return val.toFixed(precision - dot_idx)
413
}), flags)
414
}
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) {
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) {
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) {
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)
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
}
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
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
}
532
if (flags.alternate) {
533
if (ret.charAt(0) === '-') {
534
ret = "-0o" + ret.slice(1)
535
} else {
536
ret = "0o" + ret
537
}
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
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
630
var length = self.length,
631
pos = 0 |0,
632
argpos = null,
633
getitem
634
if (_b_.isinstance(args, _b_.tuple)) {
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 {
651
} catch(err) {
652
if (err.name === "KeyError") {
653
throw err
654
}
655
throw _b_.TypeError("format requires a mapping")
656
}
669
self = args[argpos++]
670
if(self===undefined){
671
throw _b_.TypeError("not enough arguments for format string")
677
// todo: get flags, type
678
// todo: string value based on flags, type, value
679
var flags = {'pad_char': ' '}
680
do {
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
}
699
"' (0x" + invalid_char.charCodeAt(0).toString(16) + ") at index " + newpos)
700
} else if (err.name === "NotANumber") {
701
var try_char = s[newpos]
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
}
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
}
762
var $=$B.args('__mul__',2,{self:null,other:null},['self','other'],
763
arguments,{},null,null)
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+"'"
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;
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
850
$StringDict.count = function(){
851
var $ = $B.args('count', 4, {self:null, sub:null, start:null, stop:null},
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)
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
}
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
904
arguments,{start:0, end:null},null,null)
905
906
normalize_start_end($)
907
908
var suffixes = $.suffix
914
if(!_b_.isinstance(suffix, str)){throw _b_.TypeError(
915
"endswith first arg must be str or a tuple of str, not int")}
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
}
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.
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}
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 :
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
}
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
}
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 {...})
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
}
1082
// In this case, evaluate them using the positional
1083
// or keyword arguments passed to format()
1085
if(/\d+/.exec(key)){
1086
// If key is numeric, search in positional
1087
// arguments
1089
parseInt(key))
1090
}else{
1091
// Else try in keyword arguments
1092
return _b_.dict.$dict.__getitem__($.kw, key)
1093
}
1099
// Store format object in list "parts"
1100
parts.push(fmt_obj)
1101
text = ''
1102
break
1103
}
1104
}else{end++}
1106
if(nb>0){throw ValueError("wrong format "+self)}
1107
pos = end
1108
}else{text += car;pos++}
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
res += _b_.getattr(value, '__format__')(fmt.spec)
1152
}
1153
1154
$StringDict.format_map = function(self) {
1155
throw NotImplementedError("function format_map not implemented yet");
1156
}
1157
1158
$StringDict.index = function(self){
1159
// Like find(), but raise ValueError when the substring is not found.
1161
if(res===-1) throw _b_.ValueError("substring not found")
1162
return res
1163
}
1164
1165
$StringDict.join = function(){
1166
var $=$B.args('join',2,{self:null,iterable:null},
1167
['self', 'iterable'], arguments, {}, null, null)
1174
if(!isinstance(obj2,str)){throw _b_.TypeError(
1175
"sequence item "+count+": expected str instance, "+$B.get_class(obj2).__name__+" found")}
1185
$StringDict.ljust = function(self) {
1186
var $=$B.args('ljust',3,{self:null,width:null,fillchar:null},
1187
['self','width','fillchar'],arguments,{fillchar:' '},null,null)
1188
1189
if ($.width <= self.length) return self
1190
return self + $.fillchar.repeat($.width - self.length)
1194
var $=$B.args('lstrip',2,{self:null,chars:null},['self','chars'],
1195
arguments,{chars:_b_.None},null,null)
1196
if($.chars===_b_.None){return $.self.trimLeft()}
1197
for (var i = 0; i < $.self.length; i++) {
1198
if ($.chars.indexOf($.self.charAt(i)) === -1) {
1199
return $.self.substring(i);
1200
}
1201
}
1202
return '';
1206
$StringDict.maketrans = function() {
1207
var $ = $B.args('maketrans', 3, {x:null,y:null,z:null},['x','y','z'],
1208
arguments, {y:null, z:null}, null, null)
1210
var _t=_b_.dict()
1211
// make 'default' translate table
1212
for(var i=0; i < 256; i++) _t.$numeric_dict[i]=i
1213
1214
if($.y===null && $.z===null){
1215
// If there is only one argument, it must be a dictionary mapping
1216
// Unicode ordinals (integers) or characters (strings of length 1) to
1217
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
1218
// keys will then be converted to ordinals.
1219
if(!_b_.isinstance($.x, _b_.dict)){
1220
throw _b_.TypeError('maketrans only argument must be a dict')
1221
}
1222
var items = _b_.list(_b_.dict.$dict.items($.x))
1223
for(var i=0, len=items.length;i<len;i++){
1224
var k = items[i][0], v=items[i][1]
1225
if(!_b_.isinstance(k, _b_.int)){
1226
if(_b_.isinstance(k, _b_.str) && k.length==1){k = _b_.ord(k)}
1227
else{throw _b_.TypeError("dictionary key "+k+
1228
" is not int or 1-char string")}
1229
}
1230
if(v!==_b_.None && !_b_.isinstance(v, [_b_.int, _b_.str])){
1231
throw _b_.TypeError("dictionary value "+v+
1232
" is not None, integer or string")
1233
}
1234
_t.$numeric_dict[k] = v
1235
}
1236
return _t
1237
}else{
1239
// and in the resulting dictionary, each character in x will be mapped
1240
// to the character at the same position in y
1241
if(!(_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
1242
throw _b_.TypeError("maketrans arguments must be strings")
1243
}else if($.x.length!==$.y.length){
1244
throw _b_.TypeError("maketrans arguments must be strings or same length")
1245
}else{
1246
var toNone = {}
1247
if($.z!==null){
1249
// characters will be mapped to None in the result
1250
if(!_b_.isinstance($.z, _b_.str)){
1251
throw _b_.TypeError('maketrans third argument must be a string')
1252
}
1253
for(var i=0,len=$.z.length;i<len;i++){
1254
toNone[_b_.ord($.z.charAt(i))] = true
1255
}
1257
for(var i=0,len=$.x.length;i<len;i++){
1258
_t.$numeric_dict[_b_.ord($.x.charAt(i))] = _b_.ord($.y.charAt(i))
1259
}
1260
for(var k in toNone){
1261
_t.$numeric_dict[k] = _b_.None
1262
}
1263
return _t
1264
}
1265
}
1268
$StringDict.partition = function() {
1269
var $=$B.args('partition',2,{self:null,sep:null},['self','sep'],
1270
arguments,{},null,null)
1271
if($.sep==''){throw _b_.ValueError('empty separator')}
1272
check_str($.sep)
1273
var i=$.self.indexOf($.sep)
1274
if (i== -1) return _b_.tuple([$.self, '', ''])
1283
var re = new RegExp('\\'+specials.charAt(i),'g')
1284
str = str.replace(re, "\\"+specials.charAt(i))
1285
}
1286
return str
1287
}
1288
1289
$StringDict.replace = function(self, old, _new, count) {
1290
// Replaces occurrences of 'old' by '_new'. Count references
1293
var $ = $B.args('replace', 4, {self:null,old:null,$$new:null,count:null},
1294
['self','old','$$new','count'], arguments, {count:-1},null,null),
1295
count=$.count,self=$.self,old=$.old,_new=$.$$new
1299
// Validate instance type of 'count'
1300
if (!isinstance(count,[_b_.int,_b_.float])) {
1302
"' object cannot be interpreted as an integer");
1303
} else if (isinstance(count, _b_.float)) {
1304
throw _b_.TypeError("integer argument expected, got float");
1305
}
1306
if(count==0){return self}
1307
if(count.__class__==$B.LongInt.$dict){count=parseInt(count.value)}
1308
if(old==''){
1309
if(_new==''){return self}
1310
if(self==''){return _new}
1311
var elts=self.split('')
1312
if(count>-1 && elts.length>=count){
1313
var rest = elts.slice(count).join('')
1314
return _new+elts.slice(0, count).join(_new)+rest
1315
}else{return _new+elts.join(_new)+_new}
1316
}else{
1317
var elts = $StringDict.split(self,old,count)
1320
var res = self, pos = -1
1321
if(old.length==0){
1322
var res = _new
1323
for(var i=0;i<elts.length;i++){
1324
res += elts[i]+_new
1325
}
1326
return res+rest
1327
}
1329
if (count < 0) count = res.length;
1330
while (count > 0) {
1331
pos = res.indexOf(old, pos);
1332
if (pos < 0)
1333
break;
1334
res = res.substr(0, pos) + _new + res.substr(pos + old.length);
1335
pos = pos + _new.length;
1336
count--;
1337
}
1338
return res;
1342
// Return the highest index in the string where substring sub is found,
1343
// such that sub is contained within s[start:end]. Optional arguments
1354
if($.sub.length==0){
1355
if($.start>$.self.length){return -1}
1356
else{return $.self.length}
1357
}
1358
var sublen = $.sub.length
1360
for(var i=$.end-sublen;i>=$.start;i--){
1361
if($.self.substr(i, sublen)==$.sub){return i}
1362
}
1363
return -1
1364
}
1365
1366
$StringDict.rindex = function(){
1367
// Like rfind() but raises ValueError when the substring sub is not found
1369
if(res==-1){throw _b_.ValueError("substring not found")}
1370
return res
1371
}
1372
1373
$StringDict.rjust = function(self) {
1375
{self:null, width:null, fillchar:null},
1376
['self', 'width', 'fillchar'],
1377
arguments,{fillchar:' '},null,null)
1385
var $=$B.args('rpartition',2,{self:null,sep:null},['self','sep'],
1386
arguments,{},null,null)
1387
check_str($.sep)
1389
sep = reverse($.sep)
1390
var items = $StringDict.partition(self,sep).reverse()
1391
for(var i=0;i<items.length;i++){
1392
items[i]=items[i].split('').reverse().join('')
1393
}
1394
return items
1398
var $=$B.args("rsplit",3,{self:null,sep:null,maxsplit:null},
1399
['self','sep','maxsplit'],arguments,
1400
{sep:_b_.None, maxsplit:-1},null,null),
1404
var rev_str = reverse($.self),
1405
rev_sep = sep === _b_.None ? sep : reverse($.sep),
1408
// Reverse the list, then each string inside the list
1409
rev_res.reverse()
1410
for(var i=0;i<rev_res.length;i++){
1417
var $=$B.args('rstrip',2,{self:null,chars:null},['self','chars'],
1418
arguments,{chars:_b_.None},null,null)
1419
if($.chars===_b_.None){return $.self.trimRight()}
1420
for (var j = $.self.length-1; j >= 0; j--) {
1421
if ($.chars.indexOf($.self.charAt(j)) === -1) {
1422
return $.self.substring(0,j+1);
1423
}
1424
}
1425
return '';
1430
var $=$B.args("split",3,{self:null,sep:null,maxsplit:null},
1431
['self','sep','maxsplit'],arguments,
1432
{sep:_b_.None, maxsplit:-1},null,null)
1433
var sep=$.sep,maxsplit=$.maxsplit,self=$.self
1434
if(maxsplit.__class__===$B.LongInt.$dict){maxsplit=parseInt(maxsplit.value)}
1440
var name = ''
1441
while(1){
1442
if(self.charAt(pos).search(/\s/)===-1){
1443
if(name===''){name=self.charAt(pos)}
1444
else{name+=self.charAt(pos)}
1445
}else{
1446
if(name!==''){
1447
res.push(name)
1448
if(maxsplit!==-1&&res.length===maxsplit+1){
1449
res.pop()
1450
res.push(name+self.substr(pos))
1451
return res
1452
}
1453
name=''
1454
}
1455
}
1456
pos++
1457
if(pos>self.length-1){
1458
if(name){res.push(name)}
1459
break
1460
}
1461
}
1462
return res
1463
}else{
1465
if(maxsplit==0){return [self]}
1466
while(pos<self.length){
1467
if(self.substr(pos,seplen)==sep){
1468
res.push(s)
1469
pos += seplen
1470
if(maxsplit>-1 && res.length>=maxsplit){
1471
res.push(self.substr(pos))
1472
return res
1473
}
1474
s= ''
1475
}else{
1476
s += self.charAt(pos)
1477
pos++
1485
$StringDict.splitlines = function(self){
1486
var $=$B.args('splitlines',2,{self:null,keepends:null},
1487
['self','keepends'],arguments,{keepends:false},null,null)
1488
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
1489
throw _b_.TypeError('integer argument expected, got '+
1490
$B.get_class($.keepends).__name)
1491
}
1492
var keepends = _b_.int($.keepends)
1493
// Remove trailing line breaks
1494
if(keepends){
1499
while(pos<self.length){
1500
if(self.substr(pos,2)=='\r\n'){
1501
res.push(self.substring(start,pos+2))
1502
start = pos+2
1503
pos = start
1504
}else if(self.charAt(pos)=='\r' || self.charAt(pos)=='\n'){
1505
res.push(self.substring(start,pos+1))
1506
start = pos+1
1507
pos = start
1508
}else{pos++}
1509
}
1510
var rest = self.substr(start)
1511
if(rest){res.push(rest)}
1512
return res
1513
}else{
1514
var self = $.self.replace(/[\r\n]$/,'')
1515
return self.split(/\n|\r\n|\r/)
1516
}
1517
}
1520
// Return True if string starts with the prefix, otherwise return False.
1521
// prefix can also be a tuple of prefixes to look for. With optional
1522
// start, test string beginning at that position. With optional end,
1529
normalize_start_end($)
1530
1531
var prefixes = $.prefix
1532
if(!isinstance(prefixes,_b_.tuple)){prefixes=[prefixes]}
1534
var s = $.self.substring($.start,$.end)
1535
for(var i=0, _len_i = prefixes.length; i < _len_i;i++){
1536
prefix = prefixes[i]
1537
if(!_b_.isinstance(prefix, str)){throw _b_.TypeError(
1538
"endswith first arg must be str or a tuple of str, not int")}
1539
if(s.substr(0,prefix.length)==prefix) return true
1545
$StringDict.strip = function(){
1546
var $=$B.args('strip',2,{self:null,chars:null},['self','chars'],
1547
arguments,{chars:_b_.None},null,null)
1548
if($.chars===_b_.None){return $.self.trim()}
1549
for (var i = 0; i < $.self.length; i++) {
1550
if ($.chars.indexOf($.self.charAt(i)) === -1) {
1551
break;
1552
}
1553
}
1554
for (var j = $.self.length-1; j >= i; j--) {
1555
if ($.chars.indexOf($.self.charAt(j)) === -1) {
1556
break;
1557
}
1558
}
1559
return $.self.substring(i,j+1);
1575
var $=$B.args('zfill',2,{self:null,width:null},
1576
['self','width'],arguments,{},null,null)
1577
if ($.width <= self.length) {return self}
1578
switch(self.charAt(0)){
1579
case '+':
1580
case '-':
1581
return self.charAt(0)+'0'.repeat($.width-self.length)+self.substr(1)
1582
default:
1583
return '0'.repeat(width - self.length)+self
1584
}
1600
// class or its subclasses, but the attribute __str__ of the
1601
// class metaclass (usually "type") or its subclasses (usually
1602
// "object")
1603
// The metaclass is the attribute __class__ of the class dictionary
1604
var func = $B.$type.__getattribute__(arg.$dict.__class__,'__str__')
1607
}else if(arg.__class__===$B.$type){ // experimental
1608
var func = $B.$type.__getattribute__(arg.__class__,'__str__')
1609
if(func.__func__===_b_.object.$dict.__str__){
1610
return func(arg)
1611
}
1612
return func()
1615
var f = getattr(arg,'__str__')
1616
// XXX fix : if not better than object.__str__, try __repr__
1625
if($B.debug>1){console.log(err)}
1626
console.log('Warning - no method __str__ or __repr__, default to toString', arg)
1631
}
1632
str.__class__ = $B.$factory
1633
str.$dict = $StringDict
1634
$StringDict.$factory = str
1635
$StringDict.__new__ = function(cls){
1636
if(cls===undefined){
1637
throw _b_.TypeError('str.__new__(): not enough arguments')
1638
}
1639
return {__class__:cls.$dict}
1640
}
1641
1644
// dictionary and factory for subclasses of string
1645
var $StringSubclassDict = {
1646
__class__:$B.$type,
1647
__name__:'str'
1648
}
1649
1650
// the methods in subclass apply the methods in $StringDict to the
1651
// result of instance.valueOf(), which is a Javascript string
1652
for(var $attr in $StringDict){
1653
if(typeof $StringDict[$attr]=='function'){
1654
$StringSubclassDict[$attr]=(function(attr){
1655
return function(){
1661
}
1662
}
1663
return $StringDict[attr].apply(null,args)
1664
}
1665
})($attr)
1666
}
1667
}
1669
1670
// factory for str subclasses
1671
$B.$StringSubclassFactory = {
1672
__class__:$B.$factory,
1673
$dict:$StringSubclassDict
1674
}
1675
1676
_b_.str = str
1677
1678
// Function to parse the 2nd argument of format()
1679
$B.parse_format_spec = function(spec){
1689
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1))!=-1){
1690
// If the second char is also an alignment specifier, the
1691
// first char is the fill value
1692
this.fill = spec.charAt(0)
1693
this.align = spec.charAt(1)
1694
pos = 2
1695
}else{
1696
// The first character defines alignment : fill defaults to ' '
1697
this.align=aligns[align_pos];
1698
this.fill=' ';
1699
pos++
1700
}
1701
}else{
1702
align_pos = aligns.indexOf(spec.charAt(1))
1703
if(spec.charAt(1) && align_pos!=-1){
1704
// The second character defines alignment : fill is the first one
1705
this.align=aligns[align_pos]
1706
this.fill=spec.charAt(0)
1707
pos = 2
1708
}
1709
}
1710
var car = spec.charAt(pos)
1711
if(car=='+'||car=='-'||car==' '){
1712
this.sign=car;
1713
pos++;
1714
car=spec.charAt(pos);
1717
if(car=='0'){
1718
// sign-aware : equivalent to fill=0 and align=='='
1719
this.fill='0'
1720
this.align = '='
1721
pos++;car=spec.charAt(pos)
1722
}
1724
if(this.width===undefined){this.width=car}
1725
else{this.width+=car}
1726
pos++;car=spec.charAt(pos)
1728
if(this.width!==undefined){this.width=parseInt(this.width)}
1729
if(car==','){this.comma=true;pos++;car=spec.charAt(pos)}
1730
if(car=='.'){
1731
if(digits.indexOf(spec.charAt(pos+1))==-1){
1732
throw _b_.ValueError("Missing precision in format spec")
1733
}
1734
this.precision = spec.charAt(pos+1)
1735
pos+=2;car=spec.charAt(pos)
1736
while(car && digits.indexOf(car)>-1){
1737
this.precision+=car;pos++;car=spec.charAt(pos)
1738
}
1739
this.precision = parseInt(this.precision)
1740
}
1741
if(car && types.indexOf(car)>-1){this.type=car;pos++;car=spec.charAt(pos)}
1742
if(pos!==spec.length){
1747
this.toString = function(){
1748
return (this.fill===undefined ? '' : _b_.str(this.fill))+
1749
(this.align||'')+
1750
(this.sign||'')+
1751
(this.alternate ? '#' : '')+
1752
(this.sign_aware ? '0' : '')+
1753
(this.width || '')+
1754
(this.comma ? ',' : '')+
1755
(this.precision ? '.'+this.precision : '')+
1756
(this.type || '')
1757
}
1758
}
1759
1760
$B.format_width = function(s, fmt){
1761
if(fmt.width && s.length<fmt.width){
1762
var fill=fmt.fill || ' ', align = fmt.align || '<',
1763
missing = fmt.width-s.length
1764
switch(align){
1765
case '<':
1766
return s+fill.repeat(missing)
1767
case '>':
1768
return fill.repeat(missing)+s
1769
case '=':
1770
if('+-'.indexOf(s.charAt(0))>-1){
1771
return s.charAt(0)+fill.repeat(missing)+s.substr(1)
1783
function fstring_expression(){
1784
this.type = 'expression'
1785
this.expression = ''
1786
this.conversion = null
1787
this.fmt = null
1788
}
1789
1790
$B.parse_fstring = function(string){
1791
// Parse a f-string
1792
var elts = [],
1793
pos = 0,
1794
current = '',
1795
ctype = null,
1796
nb_braces = 0,
1797
car
1798
1799
while(pos<string.length){
1800
if(ctype===null){
1801
car = string.charAt(pos)
1802
if(car=='{'){
1803
if(string.charAt(pos+1)=='{'){
1804
ctype = 'string'
1805
current = '{'
1806
pos += 2
1807
}else{
1808
ctype = 'expression'
1809
nb_braces = 1
1810
pos++
1811
}
1812
}else if(car=='}'){
1813
if(string.charAt(pos+1)==car){
1814
ctype = 'string'
1815
current = '}'
1817
}else{
1818
throw Error(" f-string: single '}' is not allowed")
1819
}
1820
}else{
1821
ctype = 'string'
1822
current = car
1824
}
1825
}else if(ctype=='string'){
1826
// end of string is the first single { or end of string
1828
while(i<string.length){
1829
car = string.charAt(i)
1830
if(car=='{'){
1831
if(string.charAt(i+1)=='{'){
1832
current += '{'
1833
i+=2
1834
}else{
1835
elts.push(current)
1836
ctype = 'expression'
1837
pos = i+1
1838
break
1839
}
1840
}else if(car=='}'){
1841
if(string.charAt(i+1)==car){
1842
current += car
1843
i += 2
1844
}else{
1845
throw Error(" f-string: single '}' is not allowed")
1846
}
1847
}else{
1848
current += car
1849
i++
1850
}
1851
}
1852
pos = i+1
1853
}else{
1854
// End of expression is the } matching the opening {
1855
// There may be nested braces
1856
var i = pos,
1857
nb_braces = 1,
1878
}else if(car=='\\'){
1879
// backslash is not allowed in expressions
1880
throw Error("f-string expression part cannot include a" +
1881
" backslash")
1883
if(current.expression.length==0){
1884
throw Error("f-string: empty expression not allowed")
1885
}
1886
if('ars'.indexOf(string.charAt(i+1)) == -1){
1887
throw Error("f-string: invalid conversion character:" +
1888
" expected 's', 'r', or 'a'")
1889
}else{
1890
current.conversion = string.charAt(i+1)
1891
i += 2
1892
}
1893
}else if(car=='('){
1894
nb_paren++
1895
current.expression += car
1896
i++
1897
}else if(car==')'){
1898
nb_paren--
1899
current.expression += car
1900
i++
1901
}else if(car=='"'){
1902
// triple string ?
1903
if(string.substr(i, 3)=='"""'){
1904
var end = string.indexOf('"""', i+3)
1905
if(end==-1){throw Error("f-string: unterminated string")}
1906
else{
1907
var trs = string.substring(i, end+3)
1908
trs = trs.replace('\n', '\\n\\')
1909
current.expression += trs
1910
i = end+3
1911
}
1912
}else{
1913
var end = string.indexOf('"', i+1)
1914
if(end==-1){throw Error("f-string: unterminated string")}
1915
else{
1916
current.expression += string.substring(i, end+1)
1917
i = end+1
1918
}
1919
}
1920
}else if(nb_paren == 0 && car==':'){
1926
i++
1927
}
1928
}
1929
if(nb_braces>0){
1930
throw Error("f-string: expected '}'")
1931
}
1932
}
1933
}
1934
if(current.length>0){elts.push(current)}
1935
return elts
1936
}
1937