Skip to content
Permalink
75917912c3
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
2941 lines (2727 sloc) 88.8 KB
;(function($B){
var _b_ = $B.builtins
// build tables from data in unicode_data.js
var unicode_tables = $B.unicode_tables
$B.has_surrogate = function(s){
// Check if there are "surrogate pairs" characters in string s
for(var i = 0; i < s.length; i++){
code = s.charCodeAt(i)
if(code >= 0xD800 && code <= 0xDBFF){
return true
}
}
return false
}
$B.String = function(s){
var codepoints = [],
surrogates = [],
j = 0
for(var i = 0, len = s.length; i < len; i++){
var cp = s.codePointAt(i)
if(cp >= 0x10000){
surrogates.push(j)
i++
}
j++
}
if(surrogates.length == 0){
return s
}
var res = new String(s)
res.__class__ = str
res.surrogates = surrogates
return res
}
function pypos2jspos(s, pypos){
// convert Python position to JS position
if(s.surrogates === undefined){
return pypos
}
var nb = 0
while(s.surrogates[nb] < pypos){
nb++
}
return pypos + nb
}
function jspos2pypos(s, jspos){
// convert JS position to Python position
if(s.surrogates === undefined){
return jspos
}
var nb = 0
while(s.surrogates[nb] + nb < jspos){
nb++
}
return jspos - nb
}
var str = {
__class__: _b_.type,
__dir__: _b_.object.__dir__,
$infos: {
__module__: "builtins",
__name__: "str"
},
$is_class: true,
$native: true
}
function normalize_start_end($){
var len
if(typeof $.self == "string"){
len = $.self.length
}else{
len = str.__len__($.self)
}
if($.start === null || $.start === _b_.None){
$.start = 0
}else if($.start < 0){
$.start += len
$.start = Math.max(0, $.start)
}
if($.end === null || $.end === _b_.None){
$.end = len
}else if($.end < 0){
$.end += len
$.end = Math.max(0, $.end)
}
if(! _b_.isinstance($.start, _b_.int) || ! _b_.isinstance($.end, _b_.int)){
throw _b_.TypeError.$factory("slice indices must be integers " +
"or None or have an __index__ method")
}
if($.self.surrogates){
$.js_start = pypos2jspos($.self, $.start)
$.js_end = pypos2jspos($.self, $.end)
}
}
function reverse(s){
// Reverse a string
return s.split("").reverse().join("")
}
function check_str(obj, prefix){
if(obj instanceof String || typeof obj == "string"){
return
}
if(! _b_.isinstance(obj, str)){
throw _b_.TypeError.$factory((prefix || '') +
"must be str, not " + $B.class_name(obj))
}
}
function to_chars(s){
// Transform Javascript string s into a list of Python characters
// (2 JS chars if surrogate, 1 otherwise)
var chars = []
for(var i = 0, len = s.length; i < len; i++){
var code = s.charCodeAt(i)
if(code >= 0xD800 && code <= 0xDBFF){
chars.push(s.substr(i, 2))
i++
}else{
chars.push(s.charAt(i))
}
}
return chars
}
function to_codepoints(s){
// Transform Javascript string s into a list of codepoints
if(s.codepoints){
return s.codepoints
}
var cps = []
for(var i = 0, len = s.length; i < len; i++){
var code = s.charCodeAt(i)
if(code >= 0xD800 && code <= 0xDBFF){
var v = 0x10000
v += (code & 0x03FF) << 10
v += (s.charCodeAt(i + 1) & 0x03FF)
cps.push(v)
i++
}else{
cps.push(code)
}
}
return s.codepoints = cps
}
str.__add__ = function(self, other){
if(! _b_.isinstance(other, str)){
try{
return $B.$getattr(other, "__radd__")(self)
}catch(err){
throw _b_.TypeError.$factory("Can't convert " +
$B.class_name(other) + " to str implicitly")}
}
return $B.String(self + other)
}
str.__contains__ = function(self, item){
if(! _b_.isinstance(item, str)){
throw _b_.TypeError.$factory("'in <string>' requires " +
"string as left operand, not " + $B.class_name(item))
}
if(item.__class__ === str || _b_.isinstance(item, str)){
var nbcar = item.length
}else{
var nbcar = _b_.len(item)
}
if(nbcar == 0){
// a string contains the empty string
return true
}
var len = self.length
if(len == 0){
return nbcar == 0
}
for(var i = 0, len = self.length; i < len; i++){
if(self.substr(i, nbcar) == item){
return true
}
}
return false
}
str.__delitem__ = function(){
throw _b_.TypeError.$factory("'str' object doesn't support item deletion")
}
// __dir__must be assigned explicitely because attribute resolution for
// builtin classes doesn't use __mro__
str.__dir__ = _b_.object.__dir__
str.__eq__ = function(self, other){
if(_b_.isinstance(other, _b_.str)){
return other.valueOf() == self.valueOf()
}
return _b_.NotImplemented
}
function preformat(self, fmt){
if(fmt.empty){
return _b_.str.$factory(self)
}
if(fmt.type && fmt.type != "s"){
throw _b_.ValueError.$factory("Unknown format code '" + fmt.type +
"' for object of type 'str'")
}
return self
}
str.__format__ = function(self, format_spec) {
var fmt = new $B.parse_format_spec(format_spec)
if(fmt.sign !== undefined){
throw _b_.ValueError.$factory(
"Sign not allowed in string format specifier")
}
if(fmt.precision){
self = self.substr(0, fmt.precision)
}
// For strings, alignment default to left
fmt.align = fmt.align || "<"
return $B.format_width(preformat(self, fmt), fmt)
}
str.__getitem__ = function(self, arg){
var len = str.__len__(self)
if(_b_.isinstance(arg, _b_.int)){
var pos = arg
if(arg < 0){
pos += len
}
if(pos >= 0 && pos < len){
var jspos = pypos2jspos(self, pos)
if(self.codePointAt(jspos) >= 0x10000){
return $B.String(self.substr(jspos, 2))
}else{
return self[jspos]
}
}
throw _b_.IndexError.$factory("string index out of range")
}
if(_b_.isinstance(arg, _b_.slice)){
var s = _b_.slice.$conv_for_seq(arg, len),
start = pypos2jspos(self, s.start),
stop = pypos2jspos(self, s.stop),
step = s.step
var res = "",
i = null
if(step > 0){
if(stop <= start){
return ""
}
for(var i = start; i < stop; i += step){
res += self[i]
}
}else{
if(stop >= start){
return ''
}
for(var i = start; i > stop; i += step){
res += self[i]
}
}
return $B.String(res)
}
if(_b_.isinstance(arg, _b_.bool)){
return self.__getitem__(_b_.int.$factory(arg))
}
throw _b_.TypeError.$factory("string indices must be integers")
}
var prefix = 2,
suffix = 3,
mask = (2 ** 32 - 1),
str_hash_cache = {}
str.$nb_str_hash_cache = 0
function fnv(p){
if(p.length == 0){
return 0
}
var x = prefix
x = (x ^ (p[0] << 7)) & mask
for(var i = 0, len = p.length; i < len; i++){
x = ((1000003 * x) ^ p[i]) & mask
}
x = (x ^ p.length) & mask
x = (x ^ suffix) & mask
if(x == -1){
x = -2
}
return x
}
str.__hash__ = function(self) {
if(str_hash_cache[self] !== undefined){
return str_hash_cache[self]
}
str.$nb_str_hash_cache++
if(str.$nb_str_hash_cache > 100000){
// Avoid memory overflow
str.$nb_str_hash_cache = 0
str_hash_cache = {}
}
try{
return str_hash_cache[self] = fnv(to_codepoints(self))
}catch(err){
console.log('error hash, cps', self, to_codepoints(self))
throw err
}
}
str.__init__ = function(self, arg){
self.valueOf = function(){return arg}
self.toString = function(){return arg}
return _b_.None
}
var str_iterator = $B.make_iterator_class("str_iterator")
str.__iter__ = function(self){
return str_iterator.$factory(to_chars(self))
}
str.__len__ = function(self){
if(self.surrogates === undefined){
return self.length
}
if(self.len !== undefined){
return self.len
}
var len = self.len = self.valueOf().length - self.surrogates.length
return len
}
// Start of section for legacy formatting (with %)
var kwarg_key = new RegExp("([^\\)]*)\\)")
var NotANumber = function() {
this.name = "NotANumber"
}
var number_check = function(s){
if(! _b_.isinstance(s, [_b_.int, _b_.float])){
throw new NotANumber()
}
}
var get_char_array = function(size, char){
if(size <= 0){
return ""
}
return new Array(size + 1).join(char)
}
var format_padding = function(s, flags, minus_one){
var padding = flags.padding
if(! padding){ // undefined
return s
}
s = s.toString()
padding = parseInt(padding, 10)
if(minus_one){ // numeric formatting where sign goes in front of padding
padding -= 1
}
if(! flags.left){
return get_char_array(padding - s.length, flags.pad_char) + s
}else{
// left adjusted
return s + get_char_array(padding - s.length, flags.pad_char)
}
}
var format_int_precision = function(val, flags){
var precision = flags.precision
if(!precision){
return val.toString()
}
precision = parseInt(precision, 10)
var s
if(val.__class__ === $B.long_int){
s = $B.long_int.to_base(val, 10)
}else{
s = val.toString()
}
if(s[0] === "-"){
return "-" + get_char_array(precision - s.length + 1, "0") + s.slice(1)
}
return get_char_array(precision - s.length, "0") + s
}
var format_float_precision = function(val, upper, flags, modifier){
var precision = flags.precision
// val is a float
if(isFinite(val)){
return modifier(val, precision, flags, upper)
}
if(val === Infinity){
val = "inf"
}else if(val === -Infinity){
val = "-inf"
}else{
val = "nan"
}
if(upper){
return val.toUpperCase()
}
return val
}
var format_sign = function(val, flags){
if(flags.sign){
if(val >= 0){
return "+"
}
}else if (flags.space){
if(val >= 0){
return " "
}
}
return ""
}
var str_format = function(val, flags) {
// string format supports left and right padding
flags.pad_char = " " // even if 0 padding is defined, don't use it
return format_padding(str.$factory(val), flags)
}
var num_format = function(val, flags) {
number_check(val)
if(val.__class__ === $B.long_int){
val = $B.long_int.to_base(val, 10)
}else{
val = parseInt(val)
}
var s = format_int_precision(val, flags)
if(flags.pad_char === "0"){
if(val < 0){
s = s.substring(1)
return "-" + format_padding(s, flags, true)
}
var sign = format_sign(val, flags)
if(sign !== ""){
return sign + format_padding(s, flags, true)
}
}
return format_padding(format_sign(val, flags) + s, flags)
}
var repr_format = function(val, flags) {
flags.pad_char = " " // even if 0 padding is defined, don't use it
return format_padding(_b_.repr(val), flags)
}
var ascii_format = function(val, flags) {
flags.pad_char = " " // even if 0 padding is defined, don't use it
return format_padding(_b_.ascii(val), flags)
}
// converts val to float and sets precision if missing
var _float_helper = function(val, flags){
number_check(val)
if(! flags.precision){
if(! flags.decimal_point){
flags.precision = 6
}else{
flags.precision = 0
}
}else{
flags.precision = parseInt(flags.precision, 10)
validate_precision(flags.precision)
}
return parseFloat(val)
}
// used to capture and remove trailing zeroes
var trailing_zeros = /(.*?)(0+)([eE].*)/,
leading_zeros = /\.(0*)/,
trailing_dot = /\.$/
var validate_precision = function(precision) {
// force precision to limits of javascript
if(precision > 20){precision = 20}
}
// gG
var floating_point_format = function(val, upper, flags){
val = _float_helper(val, flags),
v = val.toString(),
v_len = v.length,
dot_idx = v.indexOf('.')
if(dot_idx < 0){dot_idx = v_len}
if(val < 1 && val > -1){
var zeros = leading_zeros.exec(v),
numzeros
if(zeros){
numzeros = zeros[1].length
}else{
numzeros = 0
}
if(numzeros >= 4){
val = format_sign(val, flags) + format_float_precision(val, upper,
flags, _floating_g_exp_helper)
if(!flags.alternate){
var trl = trailing_zeros.exec(val)
if(trl){
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
}
}else{
if(flags.precision <= 1){
val = val[0] + "." + val.substring(1)
}
}
return format_padding(val, flags)
}
flags.precision = (flags.precision || 0) + numzeros
return format_padding(format_sign(val, flags) +
format_float_precision(val, upper, flags,
function(val, precision) {
return val.toFixed(_b_.min(precision, v_len - dot_idx) +
numzeros)
}),
flags
)
}
if(dot_idx > flags.precision){
val = format_sign(val, flags) + format_float_precision(val, upper,
flags, _floating_g_exp_helper)
if(! flags.alternate){
var trl = trailing_zeros.exec(val)
if(trl){
val = trl[1].replace(trailing_dot, "") + trl[3] // remove trailing
}
}else{
if(flags.precision <= 1){
val = val[0] + "." + val.substring(1)
}
}
return format_padding(val, flags)
}
return format_padding(format_sign(val, flags) +
format_float_precision(val, upper, flags,
function(val, precision) {
if(!flags.decimal_point){
precision = _b_.min(v_len - 1, 6)
}else if (precision > v_len){
if(! flags.alternate){
precision = v_len
}
}
if(precision < dot_idx){
precision = dot_idx
}
return val.toFixed(precision - dot_idx)
}),
flags
)
}
var _floating_g_exp_helper = function(val, precision, flags, upper){
if(precision){--precision}
val = val.toExponential(precision)
// pad exponent to two digits
var e_idx = val.lastIndexOf("e")
if(e_idx > val.length - 4){
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
}
if(upper){return val.toUpperCase()}
return val
}
// fF
var floating_point_decimal_format = function(val, upper, flags) {
val = _float_helper(val, flags)
return format_padding(format_sign(val, flags) +
format_float_precision(val, upper, flags,
function(val, precision, flags) {
val = val.toFixed(precision)
if(precision === 0 && flags.alternate){
val += '.'
}
return val
}),
flags
)
}
var _floating_exp_helper = function(val, precision, flags, upper) {
val = val.toExponential(precision)
// pad exponent to two digits
var e_idx = val.lastIndexOf("e")
if(e_idx > val.length - 4){
val = val.substring(0, e_idx + 2) + "0" + val.substring(e_idx + 2)
}
if(upper){return val.toUpperCase()}
return val
}
// eE
var floating_point_exponential_format = function(val, upper, flags){
val = _float_helper(val, flags)
return format_padding(format_sign(val, flags) +
format_float_precision(val, upper, flags, _floating_exp_helper), flags)
}
var signed_hex_format = function(val, upper, flags){
var ret
number_check(val)
if(val.__class__ === $B.long_int){
ret = $B.long_int.to_base(val, 16)
}else{
ret = parseInt(val)
ret = ret.toString(16)
}
ret = format_int_precision(ret, flags)
if(upper){ret = ret.toUpperCase()}
if(flags.pad_char === "0"){
if(val < 0){
ret = ret.substring(1)
ret = "-" + format_padding(ret, flags, true)
}
var sign = format_sign(val, flags)
if(sign !== ""){
ret = sign + format_padding(ret, flags, true)
}
}
if(flags.alternate){
if(ret.charAt(0) === "-"){
if(upper){ret = "-0X" + ret.slice(1)}
else{ret = "-0x" + ret.slice(1)}
}else{
if(upper){ret = "0X" + ret}
else{ret = "0x" + ret}
}
}
return format_padding(format_sign(val, flags) + ret, flags)
}
var octal_format = function(val, flags) {
number_check(val)
var ret
if(val.__class__ === $B.long_int){
ret = $B.long_int.to_base(8)
}else{
ret = parseInt(val)
ret = ret.toString(8)
}
ret = format_int_precision(ret, flags)
if(flags.pad_char === "0"){
if(val < 0){
ret = ret.substring(1)
ret = "-" + format_padding(ret, flags, true)
}
var sign = format_sign(val, flags)
if(sign !== ""){
ret = sign + format_padding(ret, flags, true)
}
}
if(flags.alternate){
if(ret.charAt(0) === "-"){ret = "-0o" + ret.slice(1)}
else{ret = "0o" + ret}
}
return format_padding(ret, flags)
}
function series_of_bytes(val, flags){
if(val.__class__ && val.__class__.$buffer_protocol){
var it = _b_.iter(val),
ints = []
while(true){
try{
ints.push(_b_.next(it))
}catch(err){
if(err.__class__ === _b_.StopIteration){
var b = _b_.bytes.$factory(ints)
return format_padding(_b_.bytes.decode(b, "ascii"), flags)
}
throw err
}
}
}else{
try{
bytes_obj = $B.$getattr(val, "__bytes__")
return format_padding(_b_.bytes.decode(bytes_obj), flags)
}catch(err){
if(err.__class__ === _b_.AttributeError){
throw _b_.TypeError.$factory("%b does not accept '" +
$B.class_name(val) + "'")
}
throw err
}
}
}
var single_char_format = function(val, flags){
if(_b_.isinstance(val, str) && val.length == 1){
return val
}else if(_b_.isinstance(val, _b_.bytes) && val.source.length == 1){
val = val.source[0]
}else{
try{
val = _b_.int.$factory(val) // yes, floats are valid (they are cast to int)
}catch (err){
throw _b_.TypeError.$factory("%c requires int or char")
}
}
return format_padding(_b_.chr(val), flags)
}
var num_flag = function(c, flags){
if(c === "0" && ! flags.padding && ! flags.decimal_point && ! flags.left){
flags.pad_char = "0"
return
}
if(!flags.decimal_point){
flags.padding = (flags.padding || "") + c
}else{
flags.precision = (flags.precision || "") + c
}
}
var decimal_point_flag = function(val, flags) {
if(flags.decimal_point){
// can only have one decimal point
throw new UnsupportedChar()
}
flags.decimal_point = true
}
var neg_flag = function(val, flags){
flags.pad_char = " " // overrides '0' flag
flags.left = true
}
var space_flag = function(val, flags){
flags.space = true
}
var sign_flag = function(val, flags){
flags.sign = true
}
var alternate_flag = function(val, flags){
flags.alternate = true
}
var char_mapping = {
"b": series_of_bytes,
"s": str_format,
"d": num_format,
"i": num_format,
"u": num_format,
"o": octal_format,
"r": repr_format,
"a": ascii_format,
"g": function(val, flags){
return floating_point_format(val, false, flags)
},
"G": function(val, flags){return floating_point_format(val, true, flags)},
"f": function(val, flags){
return floating_point_decimal_format(val, false, flags)
},
"F": function(val, flags){
return floating_point_decimal_format(val, true, flags)
},
"e": function(val, flags){
return floating_point_exponential_format(val, false, flags)
},
"E": function(val, flags){
return floating_point_exponential_format(val, true, flags)
},
"x": function(val, flags){return signed_hex_format(val, false, flags)},
"X": function(val, flags){return signed_hex_format(val, true, flags)},
"c": single_char_format,
"0": function(val, flags){return num_flag("0", flags)},
"1": function(val, flags){return num_flag("1", flags)},
"2": function(val, flags){return num_flag("2", flags)},
"3": function(val, flags){return num_flag("3", flags)},
"4": function(val, flags){return num_flag("4", flags)},
"5": function(val, flags){return num_flag("5", flags)},
"6": function(val, flags){return num_flag("6", flags)},
"7": function(val, flags){return num_flag("7", flags)},
"8": function(val, flags){return num_flag("8", flags)},
"9": function(val, flags){return num_flag("9", flags)},
"-": neg_flag,
" ": space_flag,
"+": sign_flag,
".": decimal_point_flag,
"#": alternate_flag
}
// exception thrown when an unsupported char is encountered in legacy format
var UnsupportedChar = function(){
this.name = "UnsupportedChar"
}
str.__mod__ = function(self, args){
var length = self.length,
pos = 0 | 0,
argpos = null,
getitem
if(_b_.isinstance(args, _b_.tuple)){
argpos = 0 | 0
}else{
getitem = $B.$getattr(args, "__getitem__", _b_.None)
}
var ret = ''
var $get_kwarg_string = function(s) {
// returns [self, newpos]
++pos
var rslt = kwarg_key.exec(s.substring(newpos))
if(! rslt){
throw _b_.ValueError.$factory("incomplete format key")
}
var key = rslt[1]
newpos += rslt[0].length
try{
var self = getitem(key)
}catch(err){
if(err.__class__ === _b_.KeyError){
throw err
}
throw _b_.TypeError.$factory("format requires a mapping")
}
return get_string_value(s, self)
}
var $get_arg_string = function(s) {
// returns [self, newpos]
var self
// non-tuple args
if(argpos === null){
// args is the value
self = args
}else{
self = args[argpos++]
if(self === undefined){
throw _b_.TypeError.$factory(
"not enough arguments for format string")
}
}
return get_string_value(s, self)
}
var get_string_value = function(s, self) {
// todo: get flags, type
// todo: string value based on flags, type, value
var flags = {"pad_char": " "}
do{
var func = char_mapping[s[newpos]]
try{
if(func === undefined){
throw new UnsupportedChar()
}else{
var ret = func(self, flags)
if(ret !== undefined){
return ret
}
++newpos
}
}catch (err){
if(err.name == "UnsupportedChar"){
invalid_char = s[newpos]
if(invalid_char === undefined){
throw _b_.ValueError.$factory("incomplete format")
}
throw _b_.ValueError.$factory(
"unsupported format character '" + invalid_char +
"' (0x" + invalid_char.charCodeAt(0).toString(16) +
") at index " + newpos)
}else if(err.name === "NotANumber"){
var try_char = s[newpos],
cls = self.__class__
if(!cls){
if(typeof(self) === "string"){
cls = "str"
}else{
cls = typeof(self)
}
}else{
cls = cls.$infos.__name__
}
throw _b_.TypeError.$factory("%" + try_char +
" format: a number is required, not " + cls)
}else{
throw err
}
}
}while (true)
}
var nbph = 0 // number of placeholders
do{
var newpos = self.indexOf("%", pos)
if(newpos < 0){
ret += self.substring(pos)
break
}
ret += self.substring(pos, newpos)
++newpos
if(newpos < length){
if(self[newpos] === "%"){
ret += "%"
}else{
nbph++
if(self[newpos] === "("){
++newpos
ret += $get_kwarg_string(self)
}else{
ret += $get_arg_string(self)
}
}
}else{
// % at end of string
throw _b_.ValueError.$factory("incomplete format")
}
pos = newpos + 1
}while(pos < length)
if(argpos !== null){
if(args.length > argpos){
throw _b_.TypeError.$factory(
"not enough arguments for format string")
}else if(args.length < argpos){
throw _b_.TypeError.$factory(
"not all arguments converted during string formatting")
}
}else if(nbph == 0){
throw _b_.TypeError.$factory(
"not all arguments converted during string formatting")
}
return ret
}
str.__mro__ = [_b_.object]
str.__mul__ = function(){
var $ = $B.args("__mul__", 2, {self: null, other: null},
["self", "other"], arguments, {}, null, null)
if(! _b_.isinstance($.other, _b_.int)){
throw _b_.TypeError.$factory(
"Can't multiply sequence by non-int of type '" +
$B.class_name($.other) + "'")
}
return $.self.valueOf().repeat($.other < 0 ? 0 : $.other)
}
str.__ne__ = function(self, other){
return other.valueOf() !== self.valueOf()
}
function __newobj__(){
// __newobj__ is called with a generator as only argument
var $ = $B.args('__newobj__', 0, {}, [], arguments, {}, 'args', null),
args = $.args
var res = args[1]
res.__class__ = args[0]
return res
}
str.__reduce_ex__ = function(self){
return $B.fast_tuple([
__newobj__,
$B.fast_tuple([self.__class__ || _b_.str, self]),
_b_.None,
_b_.None])
}
str.__repr__ = function(self){
// special cases
var t = $B.special_string_repr, // in brython_builtins.js
repl = '',
chars = to_chars(self)
for(var i = 0; i < chars.length; i++){
var cp = _b_.ord(chars[i])
if(t[cp] !== undefined){
repl += t[cp]
}else if($B.is_unicode_cn(cp)){
var s = cp.toString(16)
while(s.length < 4){
s = '0' + s
}
repl += '\\u' + s
}else if(cp < 0x20 || (cp >= 0x7f && cp < 0xa0)){
cp = cp.toString(16)
if(cp.length < 2){
cp = '0' + cp
}
repl += '\\x' + cp
}else if(cp >= 0x300 && cp <= 0x36F){
repl += "\u200B" + chars[i] + ' '
}else if(cp.toString(16) == 'feff'){
repl += '\\ufeff'
}else{
repl += chars[i]
}
}
var res = repl
if(res.search('"') == -1 && res.search("'") == -1){
return "'" + res + "'"
}else if(self.search('"') == -1){
return '"' + res + '"'
}
var qesc = new RegExp("'", "g") // to escape single quote
res = "'" + res.replace(qesc, "\\'") + "'"
return res
}
str.__rmod__ = function(){
var $ = $B.args('__rmod__', 2, {self: null, other: null},
['self', 'other'], arguments, {}, null, null)
return str.__mod__($.other, $.self)
}
str.__rmul__ = function(self, other){
if(_b_.isinstance(other, _b_.int)){
other = _b_.int.numerator(other)
var res = ''
while(other > 0){
res += self
other--
}
return res
}
return _b_.NotImplemented
}
str.__setattr__ = function(self, attr, value){
if(typeof self === "string"){
if(str.hasOwnProperty(attr)){
throw _b_.AttributeError.$factory("'str' object attribute '" +
attr + "' is read-only")
}else{
throw _b_.AttributeError.$factory(
"'str' object has no attribute '" + attr + "'")
}
}
// str subclass : use __dict__
_b_.dict.$setitem(self.__dict__, attr, value)
return $N
}
str.__setitem__ = function(self, attr, value){
throw _b_.TypeError.$factory(
"'str' object does not support item assignment")
}
var combining = []
for(var cp = 0x300; cp <= 0x36F; cp++){
combining.push(String.fromCharCode(cp))
}
var combining_re = new RegExp("(" + combining.join("|") + ")", "g")
str.__str__ = function(self){
var repl = '',
chars = to_chars(self)
if(chars.length == self.length){
return self.replace(combining_re, "\u200B$1")
}
for(var i = 0; i < chars.length; i++){
var cp = _b_.ord(chars[i])
if(cp >= 0x300 && cp <= 0x36F){
repl += "\u200B" + chars[i]
}else{
repl += chars[i]
}
}
return repl
}
str.toString = function(){return "string!"}
// generate comparison methods
var $comp_func = function(self,other){
if(typeof other !== "string"){return _b_.NotImplemented}
return self > other
}
$comp_func += "" // source code
var $comps = {">": "gt", ">=": "ge", "<": "lt", "<=": "le"}
for(var $op in $comps){
eval("str.__" + $comps[$op] + '__ = ' + $comp_func.replace(/>/gm,$op))
}
// unsupported operations
var $notimplemented = function(self, other){
throw _b_.NotImplementedError.$factory(
"OPERATOR not implemented for class str")
}
str.capitalize = function(self){
var $ = $B.args("capitalize", 1, {self}, ["self"],
arguments, {}, null, null)
if(self.length == 0){
return ""
}
return self.charAt(0).toUpperCase() + self.substr(1)
}
str.casefold = function(self){
var $ = $B.args("casefold", 1, {self}, ["self"],
arguments, {}, null, null),
res = "",
char,
cf,
chars = to_chars($.self)
for(var i = 0, len = chars.length; i < len; i++){
char = chars[i]
cf = $B.unicode_casefold[char]
if(cf){
cf.forEach(function(cp){
res += String.fromCharCode(cp)
})
}else{
res += char.toLowerCase()
}
}
return res
}
str.center = function(){
var $ = $B.args("center", 3, {self: null, width: null, fillchar: null},
["self", "width", "fillchar"],
arguments, {fillchar:" "}, null, null),
self = $.self
if($.width <= self.length) {return self}
var pad = parseInt(($.width - self.length) / 2),
res = $.fillchar.repeat(pad)
res += self + res
if(res.length < $.width){
res += $.fillchar
}
return res
}
str.count = function(){
var $ = $B.args("count", 4, {self:null, sub:null, start:null, stop:null},
["self", "sub", "start", "stop"], arguments, {start:null, stop:null},
null, null)
if(!(typeof $.sub.valueOf() == "string")){
throw _b_.TypeError.$factory("Can't convert '" + $B.class_name($.sub) +
"' object to str implicitly")
}
var substr = $.self
if($.start !== null){
var _slice
if($.stop !== null){
_slice = _b_.slice.$factory($.start, $.stop)
}else{
_slice = _b_.slice.$factory($.start, $.self.length)
}
substr = str.__getitem__.apply(null, [$.self].concat(_slice))
}else{
if($.self.length + $.sub.length == 0){
return 1
}
}
if($.sub.length == 0){
if($.start == $.self.length){
return 1
}else if(substr.length == 0){
return 0
}
return substr.length + 1
}
var n = 0,
pos = 0
while(pos < substr.length){
pos = substr.indexOf($.sub, pos)
if(pos >= 0){
n++
pos += $.sub.length
}else{
break
}
}
return n
}
str.encode = function(){
var $ = $B.args("encode", 3, {self: null, encoding: null, errors: null},
["self", "encoding", "errors"], arguments,
{encoding: "utf-8", errors: "strict"}, null, null)
if($.encoding == "rot13" || $.encoding == "rot_13"){
// Special case : returns a string
var res = ""
for(var i = 0, len = $.self.length; i < len ; i++){
var char = $.self.charAt(i)
if(("a" <= char && char <= "m") || ("A" <= char && char <= "M")){
res += String.fromCharCode(String.charCodeAt(char) + 13)
}else if(("m" < char && char <= "z") ||
("M" < char && char <= "Z")){
res += String.fromCharCode(String.charCodeAt(char) - 13)
}else{res += char}
}
return res
}
return _b_.bytes.__new__(_b_.bytes, $.self, $.encoding, $.errors)
}
str.endswith = function(){
// Return True if the string ends with the specified suffix, otherwise
// return False. suffix can also be a tuple of suffixes to look for.
// With optional start, test beginning at that position. With optional
// end, stop comparing at that position.
var $ = $B.args("endswith", 4,
{self:null, suffix:null, start:null, end:null},
["self", "suffix", "start", "end"],
arguments, {start: 0, end: null}, null, null)
normalize_start_end($)
var suffixes = $.suffix
if(! _b_.isinstance(suffixes,_b_.tuple)){
suffixes = [suffixes]
}
var chars = to_chars($.self),
s = chars.slice($.start, $.end)
for(var i = 0, len = suffixes.length; i < len; i++){
var suffix = suffixes[i]
if(! _b_.isinstance(suffix, str)){
throw _b_.TypeError.$factory(
"endswith first arg must be str or a tuple of str, not int")
}
if(suffix.length <= s.length &&
s.slice(s.length - suffix.length).join('') == suffix){
return true
}
}
return false
}
str.expandtabs = function(self, tabsize) {
var $ = $B.args("expandtabs", 2, {self: null, tabsize: null},
["self", "tabsize"], arguments, {tabsize: 8}, null, null)
var s = $B.$GetInt($.tabsize),
col = 0,
pos = 0,
res = "",
chars = to_chars(self)
if(s == 1){
return self.replace(/\t/g," ")
}
while(pos < chars.length){
var car = chars[pos]
switch(car){
case "\t":
while(col % s > 0){
res += " ";
col++
}
break
case "\r":
case "\n":
res += car
col = 0
break
default:
res += car
col++
break
}
pos++
}
return res
}
str.find = function(){
// Return the lowest index in the string where substring sub is found,
// such that sub is contained in the slice s[start:end]. Optional
// arguments start and end are interpreted as in slice notation.
// Return -1 if sub is not found.
var $ = $B.args("str.find", 4,
{self: null, sub: null, start: null, end: null},
["self", "sub", "start", "end"],
arguments, {start: 0, end: null}, null, null)
check_str($.sub)
normalize_start_end($)
var len = str.__len__($.self),
sub_len = str.__len__($.sub)
if(sub_len == 0 && $.start == len){
return len
}
if(len + sub_len == 0){
return -1
}
// Use .indexOf(), not .search(), to avoid conversion to reg exp
var js_start = pypos2jspos($.self, $.start),
js_end = pypos2jspos($.self, $.end),
ix = $.self.substring(js_start, js_end).indexOf($.sub)
if(ix == -1){
return -1
}
return jspos2pypos($.self, js_start + ix)
}
// Next function used by method .format()
$B.parse_format = function(fmt_string){
// Parse a "format string", as described in the Python documentation
// Return a format object. For the format string
// a.x[z]!r:...
// the object has attributes :
// - name : "a"
// - name_ext : [".x", "[z]"]
// - conv : r
// - spec : rest of string after :
var elts = fmt_string.split(":"),
name,
conv,
spec,
name_ext = []
if(elts.length == 1){
// No : in the string : it only contains a name
name = fmt_string
}else{
// name is before the first ":"
// spec (the format specification) is after
name = elts[0]
spec = elts.splice(1).join(":")
}
var elts = name.split("!")
if(elts.length > 1){
name = elts[0]
conv = elts[1] // conversion flag
}
if(name !== undefined){
// "name' may be a subscription or attribute
// Put these "extensions" in the list "name_ext"
function name_repl(match){
name_ext.push(match)
return ""
}
var name_ext_re = /\.[_a-zA-Z][_a-zA-Z0-9]*|\[[_a-zA-Z][_a-zA-Z0-9]*\]|\[[0-9]+\]/g
name = name.replace(name_ext_re, name_repl)
}
return {name: name, name_ext: name_ext,
conv: conv, spec: spec || "", string: fmt_string}
}
$B.split_format = function(self){
// Parse self to detect formatting instructions
// Create a list "parts" made of sections of the string :
// - elements of even rank are literal text
// - elements of odd rank are "format objects", built from the
// format strings in self (of the form {...})
var pos = 0,
_len = self.length,
car,
text = "",
parts = [],
rank = 0
while(pos < _len){
car = self.charAt(pos)
if(car == "{" && self.charAt(pos + 1) == "{"){
// replace {{ by literal {
text += "{"
pos += 2
}else if(car == "}" && self.charAt(pos + 1) == "}"){
// replace }} by literal }
text += "}"
pos += 2
}else if(car == "{"){
// Start of a format string
// Store current literal text
parts.push(text)
// Search the end of the format string, ie the } closing the
// opening {. Since the string can contain other pairs {} for
// nested formatting, an integer nb is incremented for each { and
// decremented for each } ; the end of the format string is
// reached when nb == 0
var end = pos + 1,
nb = 1
while(end < _len){
if(self.charAt(end) == "{"){nb++; end++}
else if(self.charAt(end) == "}"){
nb--; end++
if(nb == 0){
// End of format string
var fmt_string = self.substring(pos + 1, end - 1)
// Create a format object, by function parse_format
var fmt_obj = $B.parse_format(fmt_string)
fmt_obj.raw_name = fmt_obj.name
fmt_obj.raw_spec = fmt_obj.spec
// If no name is explicitely provided, use the rank
if(!fmt_obj.name){
fmt_obj.name = rank + ""
rank++
}
if(fmt_obj.spec !== undefined){
// "spec" may contain "nested replacement fields"
// Replace empty fields by the rank in positional
// arguments
function replace_nested(name, key){
if(key == ""){
// Use implicit rank
return "{" + rank++ + "}"
}
return "{" + key + "}"
}
fmt_obj.spec = fmt_obj.spec.replace(/\{(.*?)\}/g,
replace_nested)
}
// Store format object in list "parts"
parts.push(fmt_obj)
text = ""
break
}
}else{end++}
}
if(nb > 0){
throw _b_.ValueError.$factory("wrong format " + self)
}
pos = end
}else{
text += car
pos++
}
}
if(text){
parts.push(text)
}
return parts
}
str.format = function(self) {
// Special management of keyword arguments if str.format is called by
// str.format_map(mapping) : the argument "mapping" might not be a
// dictionary
var last_arg = $B.last(arguments)
if(last_arg.$nat == "mapping"){
var mapping = last_arg.mapping,
getitem = $B.$getattr(mapping, "__getitem__")
// Get the rest of the arguments
var args = []
for(var i = 0, len = arguments.length - 1; i < len; i++){
args.push(arguments[i])
}
var $ = $B.args("format", 1, {self: null}, ["self"],
args, {}, "$args", null)
}else{
var $ = $B.args("format", 1, {self: null}, ["self"],
arguments, {}, "$args", "$kw"),
mapping = $.$kw, // dictionary
getitem = function(key){
return _b_.dict.$getitem(mapping, key)
}
}
var parts = $B.split_format($.self)
// Apply formatting to the values passed to format()
var res = "",
fmt
for(var i = 0; i < parts.length; i++){
// Literal text is added unchanged
if(typeof parts[i] == "string"){
res += parts[i];
continue
}
// Format objects
fmt = parts[i]
if(fmt.spec !== undefined){
// "spec" may contain "nested replacement fields"
// In this case, evaluate them using the positional
// or keyword arguments passed to format()
function replace_nested(name, key){
if(/\d+/.exec(key)){
// If key is numeric, search in positional
// arguments
return _b_.tuple.__getitem__($.$args,
parseInt(key))
}else{
// Else try in keyword arguments
return _b_.dict.__getitem__($.$kw, key)
}
}
fmt.spec = fmt.spec.replace(/\{(.*?)\}/g,
replace_nested)
}
if(fmt.name.charAt(0).search(/\d/) > -1){
// Numerical reference : use positional arguments
var pos = parseInt(fmt.name),
value = _b_.tuple.__getitem__($.$args, pos)
}else{
// Use keyword arguments
var value = getitem(fmt.name)
}
// If name has extensions (attributes or subscriptions)
for(var j = 0; j < fmt.name_ext.length; j++){
var ext = fmt.name_ext[j]
if(ext.charAt(0) == "."){
// Attribute
value = $B.$getattr(value, ext.substr(1))
}else{
// Subscription
var key = ext.substr(1, ext.length - 2)
// An index made of digits is transformed into an integer
if(key.charAt(0).search(/\d/) > -1){key = parseInt(key)}
value = $B.$getattr(value, "__getitem__")(key)
}
}
// If the conversion flag is set, first call a function to convert
// the value
if(fmt.conv == "a"){value = _b_.ascii(value)}
else if(fmt.conv == "r"){value = _b_.repr(value)}
else if(fmt.conv == "s"){value = _b_.str.$factory(value)}
// Call attribute __format__ to perform the actual formatting
if(value.$is_class || value.$factory){
// For classes, don't use the class __format__ method
res += value.__class__.__format__(value, fmt.spec)
}else{
res += $B.$getattr(value, "__format__")(fmt.spec)
}
}
return res
}
str.format_map = function(self, mapping){
var $ = $B.args("format_map", 2, {self: null, mapping: null},
['self', 'mapping'], arguments, {}, null, null)
return str.format(self, {$nat: 'mapping', mapping})
}
str.index = function(self){
// Like find(), but raise ValueError when the substring is not found.
var res = str.find.apply(null, arguments)
if(res === -1){
throw _b_.ValueError.$factory("substring not found")
}
return res
}
str.isascii = function(self){
/* Return true if the string is empty or all characters in the string are
ASCII, false otherwise. ASCII characters have code points in the range
U+0000-U+007F. */
for(var i = 0, len = self.length; i < len; i++){
if(self.charCodeAt(i) > 127){
return false
}
}
return true
}
str.isalnum = function(self){
/* Return true if all characters in the string are alphanumeric and there
is at least one character, false otherwise. A character c is alphanumeric
if one of the following returns True: c.isalpha(), c.isdecimal(),
c.isdigit(), or c.isnumeric(). */
var $ = $B.args("isalnum", 1, {self: null}, ["self"],
arguments, {}, null, null),
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(unicode_tables.Ll[cp] ||
unicode_tables.Lu[cp] ||
unicode_tables.Lm[cp] ||
unicode_tables.Lt[cp] ||
unicode_tables.Lo[cp] ||
unicode_tables.Nd[cp] ||
unicode_tables.digits[cp] ||
unicode_tables.numeric[cp]){
continue
}
return false
}
return true
}
str.isalpha = function(self){
/* Return true if all characters in the string are alphabetic and there is
at least one character, false otherwise. Alphabetic characters are those
characters defined in the Unicode character database as "Letter", i.e.,
those with general category property being one of "Lm", "Lt", "Lu", "Ll",
or "Lo". */
var $ = $B.args("isalpha", 1, {self: null}, ["self"],
arguments, {}, null, null),
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(unicode_tables.Ll[cp] ||
unicode_tables.Lu[cp] ||
unicode_tables.Lm[cp] ||
unicode_tables.Lt[cp] ||
unicode_tables.Lo[cp]){
continue
}
return false
}
return true
}
str.isdecimal = function(self){
/* Return true if all characters in the string are decimal characters and
there is at least one character, false otherwise. Decimal characters are
those that can be used to form numbers in base 10, e.g. U+0660,
ARABIC-INDIC DIGIT ZERO. Formally a decimal character is a character in
the Unicode General Category "Nd". */
var $ = $B.args("isdecimal", 1, {self: null}, ["self"],
arguments, {}, null, null),
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(! unicode_tables.Nd[cp]){
return false
}
}
return self.length > 0
}
str.isdigit = function(self){
/* Return true if all characters in the string are digits and there is at
least one character, false otherwise. */
var $ = $B.args("isdigit", 1, {self: null}, ["self"],
arguments, {}, null, null),
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(! unicode_tables.digits[cp]){
return false
}
}
return self.length > 0
}
str.isidentifier = function(self){
/* Return true if the string is a valid identifier according to the
language definition. */
var $ = $B.args("isidentifier", 1, {self: null}, ["self"],
arguments, {}, null, null)
if(self.length == 0){
return false
}
var chars = to_chars(self)
if(unicode_tables.XID_Start[_b_.ord(chars[0])] === undefined){
return false
}else{
for(var char of chars){
var cp = _b_.ord(char)
if(unicode_tables.XID_Continue[cp] === undefined){
return false
}
}
}
return true
}
str.islower = function(self){
/* Return true if all cased characters 4 in the string are lowercase and
there is at least one cased character, false otherwise. */
var $ = $B.args("islower", 1, {self: null}, ["self"],
arguments, {}, null, null),
has_cased = false,
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(unicode_tables.Ll[cp]){
has_cased = true
continue
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
return false
}
}
return has_cased
}
str.isnumeric = function(self){
/* Return true if all characters in the string are numeric characters, and
there is at least one character, false otherwise. Numeric characters
include digit characters, and all characters that have the Unicode numeric
value property, e.g. U+2155, VULGAR FRACTION ONE FIFTH. Formally, numeric
characters are those with the property value Numeric_Type=Digit,
Numeric_Type=Decimal or Numeric_Type=Numeric.*/
var $ = $B.args("isnumeric", 1, {self: null}, ["self"],
arguments, {}, null, null)
for(var char of to_chars(self)){
if(! unicode_tables.numeric[_b_.ord(char)]){
return false
}
}
return self.length > 0
}
var unprintable = {},
unprintable_gc = ['Cc', 'Cf', 'Co', 'Cs','Zl', 'Zp', 'Zs']
str.isprintable = function(self){
/* Return true if all characters in the string are printable or the string
is empty, false otherwise. Nonprintable characters are those characters
defined in the Unicode character database as "Other" or "Separator",
excepting the ASCII space (0x20) which is considered printable. */
// Set unprintable if not set yet
if(Object.keys(unprintable).length == 0){
for(var i = 0; i < unprintable_gc.length; i++){
var table = unicode_tables[unprintable_gc[i]]
for(var cp in table){
unprintable[cp] = true
}
}
unprintable[32] = true
}
var $ = $B.args("isprintable", 1, {self: null}, ["self"],
arguments, {}, null, null)
for(var char of to_chars(self)){
if(unprintable[_b_.ord(char)]){
return false
}
}
return true
}
str.isspace = function(self){
/* Return true if there are only whitespace characters in the string and
there is at least one character, false otherwise.
A character is whitespace if in the Unicode character database, either its
general category is Zs ("Separator, space"), or its bidirectional class is
one of WS, B, or S.*/
var $ = $B.args("isspace", 1, {self: null}, ["self"],
arguments, {}, null, null),
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(! unicode_tables.Zs[cp] &&
$B.unicode_bidi_whitespace.indexOf(cp) == -1){
return false
}
}
return self.length > 0
}
str.istitle = function(self){
/* Return true if the string is a titlecased string and there is at least
one character, for example uppercase characters may only follow uncased
characters and lowercase characters only cased ones. Return false
otherwise. */
var $ = $B.args("istitle", 1, {self: null}, ["self"],
arguments, {}, null, null)
return self.length > 0 && str.title(self) == self
}
str.isupper = function(self){
/* Return true if all cased characters 4 in the string are lowercase and
there is at least one cased character, false otherwise. */
var $ = $B.args("islower", 1, {self: null}, ["self"],
arguments, {}, null, null),
is_upper = false,
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(unicode_tables.Lu[cp]){
is_upper = true
continue
}else if(unicode_tables.Ll[cp] || unicode_tables.Lt[cp]){
return false
}
}
return is_upper
}
str.join = function(){
var $ = $B.args("join", 2, {self: null, iterable: null},
["self", "iterable"], arguments, {}, null, null)
var iterable = _b_.iter($.iterable),
res = [],
count = 0
while(1){
try{
var obj2 = _b_.next(iterable)
if(! _b_.isinstance(obj2, str)){
throw _b_.TypeError.$factory("sequence item " + count +
": expected str instance, " + $B.class_name(obj2) +
" found")
}
res.push(obj2)
}catch(err){
if(_b_.isinstance(err, _b_.StopIteration)){
break
}
else{throw err}
}
}
return res.join($.self)
}
str.ljust = function(self) {
var $ = $B.args("ljust", 3, {self: null, width: null, fillchar:null},
["self", "width", "fillchar"],
arguments, {fillchar: " "}, null, null),
len = str.__len__(self)
if($.width <= len){
return self
}
return self + $.fillchar.repeat($.width - len)
}
str.lower = function(self){
var $ = $B.args("lower", 1, {self: null}, ["self"],
arguments, {}, null, null)
return self.toLowerCase()
}
str.lstrip = function(self, x){
var $ = $B.args("lstrip", 2, {self: null, chars: null}, ["self", "chars"],
arguments, {chars:_b_.None}, null, null),
self = $.self,
chars = $.chars
if(chars === _b_.None){
return self.trimStart()
}
while(self.length > 0){
var flag = false
for(var char of chars){
if(self.startsWith(char)){
self = self.substr(char.length)
flag = true
break
}
}
if(! flag){
return $.self.surrogates ? $B.String(self) : self
}
}
return ''
}
// note, maketrans should be a static function.
str.maketrans = function() {
var $ = $B.args("maketrans", 3, {x: null, y: null, z: null},
["x", "y", "z"], arguments, {y: null, z: null}, null, null)
var _t = $B.empty_dict()
if($.y === null && $.z === null){
// If there is only one argument, it must be a dictionary mapping
// Unicode ordinals (integers) or characters (strings of length 1) to
// Unicode ordinals, strings (of arbitrary lengths) or None. Character
// keys will then be converted to ordinals.
if(! _b_.isinstance($.x, _b_.dict)){
throw _b_.TypeError.$factory(
"maketrans only argument must be a dict")
}
var items = _b_.list.$factory(_b_.dict.items($.x))
for(var i = 0, len = items.length; i < len; i++){
var k = items[i][0],
v = items[i][1]
if(! _b_.isinstance(k, _b_.int)){
if(_b_.isinstance(k, _b_.str) && k.length == 1){
k = _b_.ord(k)
}else{throw _b_.TypeError.$factory("dictionary key " + k +
" is not int or 1-char string")}
}
if(v !== _b_.None && ! _b_.isinstance(v, [_b_.int, _b_.str])){
throw _b_.TypeError.$factory("dictionary value " + v +
" is not None, integer or string")
}
_b_.dict.$setitem(_t, k, v)
}
return _t
}else{
// If there are two arguments, they must be strings of equal length,
// and in the resulting dictionary, each character in x will be mapped
// to the character at the same position in y
if(! (_b_.isinstance($.x, _b_.str) && _b_.isinstance($.y, _b_.str))){
throw _b_.TypeError.$factory("maketrans arguments must be strings")
}else if($.x.length !== $.y.length){
throw _b_.TypeError.$factory(
"maketrans arguments must be strings or same length")
}else{
var toNone = {}
if($.z !== null){
// If there is a third argument, it must be a string, whose
// characters will be mapped to None in the result
if(! _b_.isinstance($.z, _b_.str)){
throw _b_.TypeError.$factory(
"maketrans third argument must be a string")
}
for(var i = 0, len = $.z.length; i < len; i++){
toNone[_b_.ord($.z.charAt(i))] = true
}
}
for(var i = 0, len = $.x.length; i < len; i++){
var key = _b_.ord($.x.charAt(i)),
value = $.y.charCodeAt(i)
_b_.dict.$setitem(_t, key, value)
}
for(var k in toNone){
_b_.dict.$setitem(_t, parseInt(k), _b_.None)
}
return _t
}
}
}
str.maketrans.$type = "staticmethod"
str.partition = function() {
var $ = $B.args("partition", 2, {self: null, sep: null}, ["self", "sep"],
arguments, {}, null, null)
if($.sep == ""){
throw _b_.ValueError.$factory("empty separator")
}
check_str($.sep)
var chars = to_chars($.self),
i = $.self.indexOf($.sep)
if(i == -1){
return _b_.tuple.$factory([$.self, "", ""])
}
return _b_.tuple.$factory([chars.slice(0, i).join(''), $.sep,
chars.slice(i + $.sep.length).join('')])
}
str.removeprefix = function(){
var $ = $B.args("removeprefix", 2, {self: null, prefix: null},
["self", "prefix"], arguments, {}, null, null)
if(!_b_.isinstance($.prefix, str)){
throw _b_.ValueError.$factory("prefix should be str, not " +
`'${$B.class_name($.prefix)}'`)
}
if(str.startswith($.self, $.prefix)){
return $.self.substr($.prefix.length)
}
return $.self.substr(0)
}
str.removesuffix = function(){
var $ = $B.args("removesuffix", 2, {self: null, prefix: null},
["self", "suffix"], arguments, {}, null, null)
if(!_b_.isinstance($.suffix, str)){
throw _b_.ValueError.$factory("suffix should be str, not " +
`'${$B.class_name($.prefix)}'`)
}
if($.suffix.length > 0 && str.endswith($.self, $.suffix)){
return $.self.substr(0, $.self.length - $.suffix.length)
}
return $.self.substr(0)
}
function $re_escape(str){
var specials = "[.*+?|()$^"
for(var i = 0, len = specials.length; i < len; i++){
var re = new RegExp("\\"+specials.charAt(i), "g")
str = str.replace(re, "\\"+specials.charAt(i))
}
return str
}
str.replace = function(self, old, _new, count) {
// Replaces occurrences of 'old' by '_new'. Count references
// the number of times to replace. In CPython, negative or undefined
// values of count means replace all.
var $ = $B.args("replace", 4,
{self: null, old: null, new: null, count: null},
["self", "old", "new", "count"],
arguments, {count: -1}, null, null),
count = $.count,
self = $.self,
old = $.old,
_new = $.new
// Validate type of old
check_str(old, "replace() argument 1 ")
check_str(_new, "replace() argument 2 ")
// Validate instance type of 'count'
if(! _b_.isinstance(count,[_b_.int, _b_.float])){
throw _b_.TypeError.$factory("'" + $B.class_name(count) +
"' object cannot be interpreted as an integer")
}else if(_b_.isinstance(count, _b_.float)){
throw _b_.TypeError.$factory("integer argument expected, got float")
}
if(count == 0){
return self
}
if(count.__class__ == $B.long_int){
count = parseInt(count.value)
}
if(old == ""){
if(_new == ""){
return self
}
if(self == ""){
return _new
}
var elts = self.split("")
if(count > -1 && elts.length >= count){
var rest = elts.slice(count).join("")
return _new + elts.slice(0, count).join(_new) + rest
}else{
return _new + elts.join(_new) + _new
}
}else{
var elts = str.split(self, old, count)
}
var res = self,
pos = -1
if(old.length == 0){
var res = _new
for(var i = 0; i < elts.length; i++){
res += elts[i] + _new
}
return res + rest
}
if(count < 0){
count = res.length
}
while(count > 0){
pos = res.indexOf(old, pos)
if(pos < 0){
break
}
res = res.substr(0, pos) + _new + res.substr(pos + old.length)
pos = pos + _new.length
count--
}
return res
}
str.rfind = function(self, substr){
// Return the highest index in the string where substring sub is found,
// such that sub is contained within s[start:end]. Optional arguments
// start and end are interpreted as in slice notation. Return -1 on failure.
var $ = $B.args("rfind", 4,
{self: null, sub: null, start: null, end: null},
["self", "sub", "start", "end"],
arguments, {start: 0, end: null}, null, null)
normalize_start_end($)
check_str($.sub)
var len = str.__len__($.self),
sub_len = str.__len__($.sub)
if(sub_len == 0){
if($.js_start > len){
return -1
}else{
return str.__len__($.self)
}
}
// Use .indexOf(), not .search(), to avoid conversion to reg exp
var js_start = pypos2jspos($.self, $.start),
js_end = pypos2jspos($.self, $.end),
ix = $.self.substring(js_start, js_end).lastIndexOf($.sub)
if(ix == -1){
return -1
}
return jspos2pypos($.self, js_start + ix) - $.start
}
str.rindex = function(){
// Like rfind() but raises ValueError when the substring sub is not found
var res = str.rfind.apply(null, arguments)
if(res == -1){
throw _b_.ValueError.$factory("substring not found")
}
return res
}
str.rjust = function(self) {
var $ = $B.args("rjust",3,
{self: null, width: null, fillchar: null},
["self", "width", "fillchar"],
arguments, {fillchar: " "}, null, null)
var len = str.__len__(self)
if($.width <= len){
return self
}
return $B.String($.fillchar.repeat($.width - len) + self)
}
str.rpartition = function(self,sep) {
var $ = $B.args("rpartition", 2, {self: null, sep: null}, ["self", "sep"],
arguments, {}, null, null)
check_str($.sep)
var self = reverse($.self),
sep = reverse($.sep)
var items = str.partition(self, sep).reverse()
for(var i = 0; i < items.length; i++){
items[i] = items[i].split("").reverse().join("")
}
return items
}
str.rsplit = function(self) {
var $ = $B.args("rsplit", 3, {self: null, sep: null, maxsplit: null},
["self", "sep", "maxsplit"], arguments,
{sep: _b_.None, maxsplit: -1}, null, null),
sep = $.sep
// Use split on the reverse of the string and of separator
var rev_str = reverse($.self),
rev_sep = sep === _b_.None ? sep : reverse($.sep),
rev_res = str.split(rev_str, rev_sep, $.maxsplit)
// Reverse the list, then each string inside the list
rev_res.reverse()
for(var i = 0; i < rev_res.length; i++){
rev_res[i] = reverse(rev_res[i])
}
return rev_res
}
str.rstrip = function(self, x){
var $ = $B.args("rstrip", 2, {self: null, chars: null}, ["self", "chars"],
arguments, {chars: _b_.None}, null, null),
self = $.self,
chars = $.chars
if(chars === _b_.None){
return self.trimEnd()
}
while(self.length > 0){
var flag = false
for(var char of chars){
if(self.endsWith(char)){
self = self.substr(0, self.length - char.length)
flag = true
break
}
}
if(! flag){
return $.self.surrogates ? $B.String(self) : self
}
}
return ''
}
str.split = function(){
var $ = $B.args("split", 3, {self: null, sep: null, maxsplit: null},
["self", "sep", "maxsplit"], arguments,
{sep: _b_.None, maxsplit: -1}, null, null),
sep = $.sep,
maxsplit = $.maxsplit,
self = $.self,
pos = 0
if(maxsplit.__class__ === $B.long_int){
maxsplit = parseInt(maxsplit.value)
}
if(sep == ""){
throw _b_.ValueError.$factory("empty separator")
}
if(sep === _b_.None){
var res = []
while(pos < self.length && self.charAt(pos).search(/\s/) > -1){
pos++
}
if(pos === self.length - 1){
return [self]
}
var name = ""
while(1){
if(self.charAt(pos).search(/\s/) == -1){
if(name == ""){
name = self.charAt(pos)
}else{
name += self.charAt(pos)
}
}else{
if(name !== ""){
res.push(name)
if(maxsplit !== -1 && res.length == maxsplit + 1){
res.pop()
res.push(name + self.substr(pos))
return res
}
name = ""
}
}
pos++
if(pos > self.length - 1){
if(name){
res.push(name)
}
break
}
}
return res.map($B.String)
}else{
var res = [],
s = "",
seplen = sep.length
if(maxsplit == 0){
return [self]
}
while(pos < self.length){
if(self.substr(pos, seplen) == sep){
res.push(s)
pos += seplen
if(maxsplit > -1 && res.length >= maxsplit){
res.push(self.substr(pos))
return res.map($B.String)
}
s = ""
}else{
s += self.charAt(pos)
pos++
}
}
res.push(s)
return res.map($B.String)
}
}
str.splitlines = function(self) {
var $ = $B.args('splitlines', 2, {self: null, keepends: null},
['self','keepends'], arguments, {keepends: false},
null, null)
if(!_b_.isinstance($.keepends,[_b_.bool, _b_.int])){
throw _b_.TypeError('integer argument expected, got '+
$B.get_class($.keepends).__name)
}
var keepends = _b_.int.$factory($.keepends),
res = [],
self = $.self,
start = 0,
pos = 0
if(!self.length){
return res
}
while(pos < self.length){
if(self.substr(pos, 2) == '\r\n'){
res.push(self.slice(start, keepends ? pos + 2 : pos))
start = pos = pos+2
}else if(self[pos] == '\r' || self[pos] == '\n'){
res.push(self.slice(start, keepends ? pos+1 : pos))
start = pos = pos+1
}else{
pos++
}
}
if(start < self.length){
res.push(self.slice(start))
}
return res.map($B.String)
}
str.startswith = function(){
// Return True if string starts with the prefix, otherwise return False.
// prefix can also be a tuple of prefixes to look for. With optional
// start, test string beginning at that position. With optional end,
// stop comparing string at that position.
var $ = $B.args("startswith", 4,
{self: null, prefix: null, start: null, end: null},
["self", "prefix", "start", "end"],
arguments, {start: 0, end: null}, null, null)
normalize_start_end($)
var prefixes = $.prefix
if(! _b_.isinstance(prefixes, _b_.tuple)){
prefixes = [prefixes]
}
var s = $.self.substring($.start, $.end)
for(var prefix of prefixes){
if(! _b_.isinstance(prefix, str)){
throw _b_.TypeError.$factory("endswith first arg must be str " +
"or a tuple of str, not int")
}
if(s.substr(0, prefix.length) == prefix){
return true
}
}
return false
}
str.strip = function(){
var $ = $B.args("strip", 2, {self: null, chars: null}, ["self", "chars"],
arguments, {chars: _b_.None}, null, null)
if($.chars === _b_.None){
return $.self.trim()
}
return str.rstrip(str.lstrip($.self, $.chars), $.chars)
}
str.swapcase = function(self){
var $ = $B.args("swapcase", 1, {self}, ["self"],
arguments, {}, null, null),
res = "",
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(unicode_tables.Ll[cp]){
res += char.toUpperCase()
}else if(unicode_tables.Lu[cp]){
res += char.toLowerCase()
}else{
res += char
}
}
return res
}
str.title = function(self){
var $ = $B.args("title", 1, {self}, ["self"],
arguments, {}, null, null),
state,
cp,
res = ""
for(var char of to_chars(self)){
cp = _b_.ord(char)
if(unicode_tables.Ll[cp]){
if(! state){
res += char.toUpperCase()
state = "word"
}else{
res += char
}
}else if(unicode_tables.Lu[cp] || unicode_tables.Lt[cp]){
res += state ? char.toLowerCase() : char
state = "word"
}else{
state = null
res += char
}
}
return res
}
str.translate = function(self, table){
var res = [],
getitem = $B.$getattr(table, "__getitem__"),
cp
for(var char of to_chars(self)){
cp = _b_.ord(char)
try{
var repl = getitem(cp)
if(repl !== _b_.None){
if(typeof repl == "string"){
res.push(repl)
}else if(typeof repl == "number"){
res.push(String.fromCharCode(repl))
}
}
}catch(err){
res.push(char)
}
}
return res.join("")
}
str.upper = function(self){
var $ = $B.args("upper", 1, {self: null}, ["self"],
arguments, {}, null, null)
return self.toUpperCase()
}
str.zfill = function(self, width){
var $ = $B.args("zfill", 2, {self: null, width: null},
["self", "width"], arguments, {}, null, null),
len = str.__len__(self)
if($.width <= len){
return self
}
switch(self.charAt(0)){
case "+":
case "-":
return self.charAt(0) +
"0".repeat($.width - len) + self.substr(1)
default:
return "0".repeat($.width - len) + self
}
}
str.$factory = function(arg, encoding, errors){
if(arguments.length == 0){
return ""
}
if(arg === undefined){
return $B.UndefinedClass.__str__()
}else if(arg === null){
return '<Javascript null>'
}
if(encoding !== undefined){
// Arguments may be passed as keywords (cf. issue #1060)
var $ = $B.args("str", 3, {arg: null, encoding: null, errors: null},
["arg", "encoding", "errors"], arguments,
{encoding: "utf-8", errors: "strict"}, null, null),
encoding = $.encoding,
errors = $.errors
}
if(typeof arg == "string" || arg instanceof String ||
typeof arg == "number"){
if(isFinite(arg)){
return arg.toString()
}
}
try{
if(arg.$is_class || arg.$factory){
// arg is a class
// In this case, str() doesn't use the attribute __str__ of the
// class or its subclasses, but the attribute __str__ of the
// class metaclass (usually "type") or its subclasses (usually
// "object")
// The metaclass is the attribute __class__ of the class dictionary
var func = $B.$getattr(arg.__class__, "__str__")
return func(arg)
}
if(arg.__class__ && arg.__class__ === _b_.bytes &&
encoding !== undefined){
// str(bytes, encoding, errors) is equal to
// bytes.decode(encoding, errors)
return _b_.bytes.decode(arg, $.encoding, $.errors)
}
// Implicit invocation of __str__ uses method __str__ on the class,
// even if arg has an attribute __str__
var klass = arg.__class__ || $B.get_class(arg)
if(klass === undefined){
return $B.JSObj.__str__($B.JSObj.$factory(arg))
}
var method = $B.$getattr(klass , "__str__", null)
if(method === null ||
// if not better than object.__str__, try __repr__
(arg.__class__ && arg.__class__ !== _b_.object &&
method === _b_.object.__str__)){
var method = $B.$getattr(klass, "__repr__")
}
}
catch(err){
console.log("no __str__ for", arg)
console.log("err ", err)
if($B.debug > 1){console.log(err)}
console.log("Warning - no method __str__ or __repr__, " +
"default to toString", arg)
throw err
}
return $B.$call(method)(arg)
}
str.__new__ = function(cls){
if(cls === undefined){
throw _b_.TypeError.$factory("str.__new__(): not enough arguments")
}
return {__class__: cls}
}
$B.set_func_names(str, "builtins")
// dictionary and factory for subclasses of string
var StringSubclass = $B.StringSubclass = {
__class__: _b_.type,
__mro__: [_b_.object],
$infos: {
__module__: "builtins",
__name__: "str"
},
$is_class: true
}
// the methods in subclass apply the methods in str to the
// result of instance.valueOf(), which is a Javascript string
for(var $attr in str){
if(typeof str[$attr] == "function"){
StringSubclass[$attr] = (function(attr){
return function(){
var args = [],
pos = 0
if(arguments.length > 0){
var args = [arguments[0].valueOf()],
pos = 1
for(var i = 1, len = arguments.length; i < len; i++){
args[pos++] = arguments[i]
}
}
return str[attr].apply(null, args)
}
})($attr)
}
}
StringSubclass.__new__ = function(cls){
return {__class__: cls}
}
$B.set_func_names(StringSubclass, "builtins")
_b_.str = str
// Function to parse the 2nd argument of format()
$B.parse_format_spec = function(spec){
if(spec == ""){
this.empty = true
}else{
var pos = 0,
aligns = "<>=^",
digits = "0123456789",
types = "bcdeEfFgGnosxX%",
align_pos = aligns.indexOf(spec.charAt(0))
if(align_pos != -1){
if(spec.charAt(1) && aligns.indexOf(spec.charAt(1)) != -1){
// If the second char is also an alignment specifier, the
// first char is the fill value
this.fill = spec.charAt(0)
this.align = spec.charAt(1)
pos = 2
}else{
// The first character defines alignment : fill defaults to ' '
this.align = aligns[align_pos]
this.fill = " "
pos++
}
}else{
align_pos = aligns.indexOf(spec.charAt(1))
if(spec.charAt(1) && align_pos != -1){
// The second character defines alignment : fill is the first one
this.align = aligns[align_pos]
this.fill = spec.charAt(0)
pos = 2
}
}
var car = spec.charAt(pos)
if(car == "+" || car == "-" || car == " "){
this.sign = car
pos++
car = spec.charAt(pos)
}
if(car == "#"){
this.alternate = true; pos++; car = spec.charAt(pos)
}
if(car == "0"){
// sign-aware : equivalent to fill = 0 and align == "="
this.fill = "0"
if(align_pos == -1){
this.align = "="
}
pos++
car = spec.charAt(pos)
}
while(car && digits.indexOf(car) > -1){
if(this.width === undefined){
this.width = car
}else{
this.width += car
}
pos++
car = spec.charAt(pos)
}
if(this.width !== undefined){
this.width = parseInt(this.width)
}
if(this.width === undefined && car == "{"){
// Width is determined by a parameter
var end_param_pos = spec.substr(pos).search("}")
this.width = spec.substring(pos, end_param_pos)
console.log("width", "[" + this.width + "]")
pos += end_param_pos + 1
}
if(car == ","){
this.comma = true
pos++
car = spec.charAt(pos)
}
if(car == "."){
if(digits.indexOf(spec.charAt(pos + 1)) == -1){
throw _b_.ValueError.$factory(
"Missing precision in format spec")
}
this.precision = spec.charAt(pos + 1)
pos += 2
car = spec.charAt(pos)
while(car && digits.indexOf(car) > -1){
this.precision += car
pos++
car = spec.charAt(pos)
}
this.precision = parseInt(this.precision)
}
if(car && types.indexOf(car) > -1){
this.type = car
pos++
car = spec.charAt(pos)
}
if(pos !== spec.length){
throw _b_.ValueError.$factory("Invalid format specifier: " + spec)
}
}
this.toString = function(){
return (this.fill === undefined ? "" : _b_.str.$factory(this.fill)) +
(this.align || "") +
(this.sign || "") +
(this.alternate ? "#" : "") +
(this.sign_aware ? "0" : "") +
(this.width || "") +
(this.comma ? "," : "") +
(this.precision ? "." + this.precision : "") +
(this.type || "")
}
}
$B.format_width = function(s, fmt){
if(fmt.width && s.length < fmt.width){
var fill = fmt.fill || " ",
align = fmt.align || "<",
missing = fmt.width - s.length
switch(align){
case "<":
return s + fill.repeat(missing)
case ">":
return fill.repeat(missing) + s
case "=":
if("+-".indexOf(s.charAt(0)) > -1){
return s.charAt(0) + fill.repeat(missing) + s.substr(1)
}else{
return fill.repeat(missing) + s
}
case "^":
var left = parseInt(missing / 2)
return fill.repeat(left) + s + fill.repeat(missing - left)
}
}
return s
}
function fstring_expression(start){
this.type = "expression"
this.start = start
this.expression = ""
this.conversion = null
this.fmt = null
}
function fstring_error(msg, pos){
error = Error(msg)
error.position = pos
throw error
}
$B.parse_fstring = function(string){
// Parse a f-string
var elts = [],
pos = 0,
current = "",
ctype = null,
nb_braces = 0,
expr_start,
car
while(pos < string.length){
if(ctype === null){
car = string.charAt(pos)
if(car == "{"){
if(string.charAt(pos + 1) == "{"){
ctype = "string"
current = "{"
pos += 2
}else{
ctype = "expression"
expr_start = pos + 1
nb_braces = 1
pos++
}
}else if(car == "}"){
if(string.charAt(pos + 1) == car){
ctype = "string"
current = "}"
pos += 2
}else{
fstring_error(" f-string: single '}' is not allowed",
pos)
}
}else{
ctype = "string"
current = car
pos++
}
}else if(ctype == "string"){
// end of string is the first single { or end of string
var i = pos
while(i < string.length){
car = string.charAt(i)
if(car == "{"){
if(string.charAt(i + 1) == "{"){
current += "{"
i += 2
}else{
elts.push(current)
ctype = "expression"
expr_start = i + 1
pos = i + 1
break
}
}else if(car == "}"){
if(string.charAt(i + 1) == car){
current += car
i += 2
}else{
fstring_error(" f-string: single '}' is not allowed",
pos)
}
}else{
current += car
i++
}
}
pos = i + 1
}else if(ctype == "debug"){
// after the equal sign, whitespace are ignored and the only
// valid characters are } and :
while(string.charAt(i) == " "){i++}
if(string.charAt(i) == "}"){
// end of debug expression
elts.push(current)
ctype = null
current = ""
pos = i + 1
}
}else{
// End of expression is the } matching the opening {
// There may be nested braces
var i = pos,
nb_braces = 1,
nb_paren = 0,
current = new fstring_expression(expr_start)
while(i < string.length){
car = string.charAt(i)
if(car == "{" && nb_paren == 0){
nb_braces++
current.expression += car
i++
}else if(car == "}" && nb_paren == 0){
nb_braces -= 1
if(nb_braces == 0){
// end of expression
if(current.expression == ""){
fstring_error("f-string: empty expression not allowed",
pos)
}
elts.push(current)
ctype = null
current = ""
pos = i + 1
break
}
current.expression += car
i++
}else if(car == "\\"){
// backslash is not allowed in expressions
throw Error("f-string expression part cannot include a" +
" backslash")
}else if(nb_paren == 0 && car == "!" && current.fmt === null &&
":}".indexOf(string.charAt(i + 2)) > -1){
if(current.expression.length == 0){
throw Error("f-string: empty expression not allowed")
}
if("ars".indexOf(string.charAt(i + 1)) == -1){
throw Error("f-string: invalid conversion character:" +
" expected 's', 'r', or 'a'")
}else{
current.conversion = string.charAt(i + 1)
i += 2
}
}else if(car == "(" || car == '['){
nb_paren++
current.expression += car
i++
}else if(car == ")" || car == ']'){
nb_paren--
current.expression += car
i++
}else if(car == '"'){
// triple string ?
if(string.substr(i, 3) == '"""'){
var end = string.indexOf('"""', i + 3)
if(end == -1){
fstring_error("f-string: unterminated string", pos)
}else{
var trs = string.substring(i, end + 3)
trs = trs.replace("\n", "\\n\\")
current.expression += trs
i = end + 3
}
}else{
var end = string.indexOf('"', i + 1)
if(end == -1){
fstring_error("f-string: unterminated string", pos)
}else{
current.expression += string.substring(i, end + 1)
i = end + 1
}
}
}else if(nb_paren == 0 && car == ":"){
// start format
current.fmt = true
var cb = 0,
fmt_complete = false
for(var j = i + 1; j < string.length; j++){
if(string[j] == '{'){
if(string[j + 1] == '{'){
j += 2
}else{
cb++
}
}else if(string[j] == '}'){
if(string[j + 1] == '}'){
j += 2
}else if(cb == 0){
fmt_complete = true
var fmt = string.substring(i + 1, j)
current.format = $B.parse_fstring(fmt)
i = j
break
}else{
cb--
}
}
}
if(! fmt_complete){
fstring_error('invalid format', pos)
}
}else if(car == "="){
// might be a "debug expression", eg f"{x=}"
var ce = current.expression,
last_char = ce.charAt(ce.length - 1),
last_char_re = ('()'.indexOf(last_char) > -1 ? "\\" : "") + last_char
if(ce.length == 0 ||
nb_paren > 0 ||
string.charAt(i + 1) == "=" ||
"=!<>:".search(last_char_re) > -1){
// not a debug expression
current.expression += car
i += 1
}else{
// add debug string
tail = car
while(string.charAt(i + 1).match(/\s/)){
tail += string.charAt(i + 1)
i++
}
// push simple string
elts.push(current.expression + tail)
// remove trailing whitespace from expression
while(ce.match(/\s$/)){
ce = ce.substr(0, ce.length - 1)
}
current.expression = ce
ctype = "debug"
i++
}
}else{
current.expression += car
i++
}
}
if(nb_braces > 0){
fstring_error("f-string: expected '}'", pos)
}
}
}
if(current.length > 0){
elts.push(current)
}
for(var elt of elts){
if(typeof elt == "object"){
if(elt.fmt_pos !== undefined &&
elt.expression.charAt(elt.fmt_pos) != ':'){
console.log('mauvais format', string, elts)
throw Error()
}
}
}
return elts
}
var _chr = $B.codepoint2jsstring = function(i){
if(i >= 0x10000 && i <= 0x10FFFF){
var code = (i - 0x10000)
return String.fromCodePoint(0xD800 | (code >> 10)) +
String.fromCodePoint(0xDC00 | (code & 0x3FF))
}else{
return String.fromCodePoint(i)
}
}
var _ord = $B.jsstring2codepoint = function(c){
if(c.length == 1){
return c.charCodeAt(0)
}
var code = 0x10000
code += (c.charCodeAt(0) & 0x03FF) << 10
code += (c.charCodeAt(1) & 0x03FF)
return code
}
})(__BRYTHON__)