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