sku-pg
Version:
Skulpt is a Javascript implementation of Python 2.x. Python that runs in your browser!
1,169 lines (1,039 loc) • 38.9 kB
JavaScript
Sk.builtin.interned = {};
/**
* @constructor
* @param {*} x
* @extends Sk.builtin.object
*/
Sk.builtin.str = function (x) {
var ret;
if (x === undefined) {
x = "";
}
if (x instanceof Sk.builtin.str) {
return x;
}
if (!(this instanceof Sk.builtin.str)) {
return new Sk.builtin.str(x);
}
// convert to js string
if (x === true) {
ret = "True";
} else if (x === false) {
ret = "False";
} else if ((x === null) || (x instanceof Sk.builtin.none)) {
ret = "None";
} else if (x instanceof Sk.builtin.bool) {
if (x.v) {
ret = "True";
} else {
ret = "False";
}
} else if (typeof x === "number") {
ret = x.toString();
if (ret === "Infinity") {
ret = "inf";
} else if (ret === "-Infinity") {
ret = "-inf";
}
} else if (typeof x === "string") {
ret = x;
} else if (x.tp$str !== undefined) {
ret = x.tp$str();
if (!(ret instanceof Sk.builtin.str)) {
throw new Sk.builtin.ValueError("__str__ didn't return a str");
}
return ret;
} else {
return Sk.misceval.objectRepr(x);
}
// interning required for strings in py
if (Sk.builtin.interned["1" + ret]) {
return Sk.builtin.interned["1" + ret];
}
this.__class__ = Sk.builtin.str;
this.v = ret;
this["v"] = this.v;
Sk.builtin.interned["1" + ret] = this;
return this;
};
goog.exportSymbol("Sk.builtin.str", Sk.builtin.str);
Sk.abstr.setUpInheritance("str", Sk.builtin.str, Sk.builtin.seqtype);
Sk.builtin.str.prototype.mp$subscript = function (index) {
var ret;
if (Sk.misceval.isIndex(index)) {
index = Sk.misceval.asIndex(index);
if (index < 0) {
index = this.v.length + index;
}
if (index < 0 || index >= this.v.length) {
throw new Sk.builtin.IndexError("string index out of range");
}
return new Sk.builtin.str(this.v.charAt(index));
} else if (index instanceof Sk.builtin.slice) {
ret = "";
index.sssiter$(this, function (i, wrt) {
if (i >= 0 && i < wrt.v.length) {
ret += wrt.v.charAt(i);
}
});
return new Sk.builtin.str(ret);
} else {
throw new Sk.builtin.TypeError("string indices must be integers, not " + Sk.abstr.typeName(index));
}
};
Sk.builtin.str.prototype.sq$length = function () {
return this.v.length;
};
Sk.builtin.str.prototype.sq$concat = function (other) {
var otypename;
if (!other || !Sk.builtin.checkString(other)) {
otypename = Sk.abstr.typeName(other);
throw new Sk.builtin.TypeError("cannot concatenate 'str' and '" + otypename + "' objects");
}
return new Sk.builtin.str(this.v + other.v);
};
Sk.builtin.str.prototype.nb$add = Sk.builtin.str.prototype.sq$concat;
Sk.builtin.str.prototype.nb$inplace_add = Sk.builtin.str.prototype.sq$concat;
Sk.builtin.str.prototype.sq$repeat = function (n) {
var i;
var ret;
if (!Sk.misceval.isIndex(n)) {
throw new Sk.builtin.TypeError("can't multiply sequence by non-int of type '" + Sk.abstr.typeName(n) + "'");
}
n = Sk.misceval.asIndex(n);
ret = "";
for (i = 0; i < n; ++i) {
ret += this.v;
}
return new Sk.builtin.str(ret);
};
Sk.builtin.str.prototype.nb$multiply = Sk.builtin.str.prototype.sq$repeat;
Sk.builtin.str.prototype.nb$inplace_multiply = Sk.builtin.str.prototype.sq$repeat;
Sk.builtin.str.prototype.sq$item = function () {
goog.asserts.fail();
};
Sk.builtin.str.prototype.sq$slice = function (i1, i2) {
i1 = Sk.builtin.asnum$(i1);
i2 = Sk.builtin.asnum$(i2);
if (i1 < 0) {
i1 = 0;
}
return new Sk.builtin.str(this.v.substr(i1, i2 - i1));
};
Sk.builtin.str.prototype.sq$contains = function (ob) {
if (!(ob instanceof Sk.builtin.str)) {
throw new Sk.builtin.TypeError("TypeError: 'In <string> requires string as left operand");
}
return this.v.indexOf(ob.v) != -1;
};
Sk.builtin.str.prototype.__iter__ = new Sk.builtin.func(function (self) {
return new Sk.builtin.str_iter_(self);
});
Sk.builtin.str.prototype.tp$iter = function () {
return new Sk.builtin.str_iter_(this);
};
Sk.builtin.str.prototype.tp$richcompare = function (other, op) {
if (!(other instanceof Sk.builtin.str)) {
return undefined;
}
switch (op) {
case "Lt":
return this.v < other.v;
case "LtE":
return this.v <= other.v;
case "Eq":
return this.v === other.v;
case "NotEq":
return this.v !== other.v;
case "Gt":
return this.v > other.v;
case "GtE":
return this.v >= other.v;
default:
goog.asserts.fail();
}
};
Sk.builtin.str.prototype["$r"] = function () {
// single is preferred
var ashex;
var c;
var i;
var ret;
var len;
var quote = "'";
//jshint ignore:start
if (this.v.indexOf("'") !== -1 && this.v.indexOf('"') === -1) {
quote = '"';
}
//jshint ignore:end
len = this.v.length;
ret = quote;
for (i = 0; i < len; ++i) {
c = this.v.charAt(i);
if (c === quote || c === "\\") {
ret += "\\" + c;
} else if (c === "\t") {
ret += "\\t";
} else if (c === "\n") {
ret += "\\n";
} else if (c === "\r") {
ret += "\\r";
} else if (c < " " || c >= 0x7f) {
ashex = c.charCodeAt(0).toString(16);
if (ashex.length < 2) {
ashex = "0" + ashex;
}
ret += "\\x" + ashex;
} else {
ret += c;
}
}
ret += quote;
return new Sk.builtin.str(ret);
};
Sk.builtin.str.re_escape_ = function (s) {
var c;
var i;
var ret = [];
var re = /^[A-Za-z0-9]+$/;
for (i = 0; i < s.length; ++i) {
c = s.charAt(i);
if (re.test(c)) {
ret.push(c);
} else {
if (c === "\\000") {
ret.push("\\000");
} else {
ret.push("\\" + c);
}
}
}
return ret.join("");
};
Sk.builtin.str.prototype["lower"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("lower", arguments, 1, 1);
return new Sk.builtin.str(self.v.toLowerCase());
});
Sk.builtin.str.prototype["upper"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("upper", arguments, 1, 1);
return new Sk.builtin.str(self.v.toUpperCase());
});
Sk.builtin.str.prototype["capitalize"] = new Sk.builtin.func(function (self) {
var i;
var cap;
var orig;
Sk.builtin.pyCheckArgs("capitalize", arguments, 1, 1);
orig = self.v;
if (orig.length === 0) {
return new Sk.builtin.str("");
}
cap = orig.charAt(0).toUpperCase();
for (i = 1; i < orig.length; i++) {
cap += orig.charAt(i).toLowerCase();
}
return new Sk.builtin.str(cap);
});
Sk.builtin.str.prototype["join"] = new Sk.builtin.func(function (self, seq) {
var it, i;
var arrOfStrs;
Sk.builtin.pyCheckArgs("join", arguments, 2, 2);
Sk.builtin.pyCheckType("seq", "iterable", Sk.builtin.checkIterable(seq));
arrOfStrs = [];
for (it = seq.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
if (i.constructor !== Sk.builtin.str) {
throw new Sk.builtin.TypeError("TypeError: sequence item " + arrOfStrs.length + ": expected string, " + typeof i + " found");
}
arrOfStrs.push(i.v);
}
return new Sk.builtin.str(arrOfStrs.join(self.v));
});
Sk.builtin.str.prototype["split"] = new Sk.builtin.func(function (self, on, howmany) {
var splits;
var index;
var match;
var result;
var s;
var str;
var regex;
Sk.builtin.pyCheckArgs("split", arguments, 1, 3);
if ((on === undefined) || (on instanceof Sk.builtin.none)) {
on = null;
}
if ((on !== null) && !Sk.builtin.checkString(on)) {
throw new Sk.builtin.TypeError("expected a string");
}
if ((on !== null) && on.v === "") {
throw new Sk.builtin.ValueError("empty separator");
}
if ((howmany !== undefined) && !Sk.builtin.checkInt(howmany)) {
throw new Sk.builtin.TypeError("an integer is required");
}
howmany = Sk.builtin.asnum$(howmany);
regex = /[\s]+/g;
str = self.v;
if (on === null) {
str = goog.string.trimLeft(str);
} else {
// Escape special characters in "on" so we can use a regexp
s = on.v.replace(/([.*+?=|\\\/()\[\]\{\}^$])/g, "\\$1");
regex = new RegExp(s, "g");
}
// This is almost identical to re.split,
// except how the regexp is constructed
result = [];
index = 0;
splits = 0;
while ((match = regex.exec(str)) != null) {
if (match.index === regex.lastIndex) {
// empty match
break;
}
result.push(new Sk.builtin.str(str.substring(index, match.index)));
index = regex.lastIndex;
splits += 1;
if (howmany && (splits >= howmany)) {
break;
}
}
str = str.substring(index);
if (on !== null || (str.length > 0)) {
result.push(new Sk.builtin.str(str));
}
return new Sk.builtin.list(result);
});
Sk.builtin.str.prototype["strip"] = new Sk.builtin.func(function (self, chars) {
var regex;
var pattern;
Sk.builtin.pyCheckArgs("strip", arguments, 1, 2);
if ((chars !== undefined) && !Sk.builtin.checkString(chars)) {
throw new Sk.builtin.TypeError("strip arg must be None or str");
}
if (chars === undefined) {
pattern = /^\s+|\s+$/g;
} else {
regex = Sk.builtin.str.re_escape_(chars.v);
pattern = new RegExp("^[" + regex + "]+|[" + regex + "]+$", "g");
}
return new Sk.builtin.str(self.v.replace(pattern, ""));
});
Sk.builtin.str.prototype["lstrip"] = new Sk.builtin.func(function (self, chars) {
var regex;
var pattern;
Sk.builtin.pyCheckArgs("lstrip", arguments, 1, 2);
if ((chars !== undefined) && !Sk.builtin.checkString(chars)) {
throw new Sk.builtin.TypeError("lstrip arg must be None or str");
}
if (chars === undefined) {
pattern = /^\s+/g;
} else {
regex = Sk.builtin.str.re_escape_(chars.v);
pattern = new RegExp("^[" + regex + "]+", "g");
}
return new Sk.builtin.str(self.v.replace(pattern, ""));
});
Sk.builtin.str.prototype["rstrip"] = new Sk.builtin.func(function (self, chars) {
var regex;
var pattern;
Sk.builtin.pyCheckArgs("rstrip", arguments, 1, 2);
if ((chars !== undefined) && !Sk.builtin.checkString(chars)) {
throw new Sk.builtin.TypeError("rstrip arg must be None or str");
}
if (chars === undefined) {
pattern = /\s+$/g;
} else {
regex = Sk.builtin.str.re_escape_(chars.v);
pattern = new RegExp("[" + regex + "]+$", "g");
}
return new Sk.builtin.str(self.v.replace(pattern, ""));
});
Sk.builtin.str.prototype["partition"] = new Sk.builtin.func(function (self, sep) {
var pos;
var sepStr;
Sk.builtin.pyCheckArgs("partition", arguments, 2, 2);
Sk.builtin.pyCheckType("sep", "string", Sk.builtin.checkString(sep));
sepStr = new Sk.builtin.str(sep);
pos = self.v.indexOf(sepStr.v);
if (pos < 0) {
return new Sk.builtin.tuple([self, Sk.builtin.str.$emptystr, Sk.builtin.str.$emptystr]);
}
return new Sk.builtin.tuple([
new Sk.builtin.str(self.v.substring(0, pos)),
sepStr,
new Sk.builtin.str(self.v.substring(pos + sepStr.v.length))]);
});
Sk.builtin.str.prototype["rpartition"] = new Sk.builtin.func(function (self, sep) {
var pos;
var sepStr;
Sk.builtin.pyCheckArgs("rpartition", arguments, 2, 2);
Sk.builtin.pyCheckType("sep", "string", Sk.builtin.checkString(sep));
sepStr = new Sk.builtin.str(sep);
pos = self.v.lastIndexOf(sepStr.v);
if (pos < 0) {
return new Sk.builtin.tuple([Sk.builtin.str.$emptystr, Sk.builtin.str.$emptystr, self]);
}
return new Sk.builtin.tuple([
new Sk.builtin.str(self.v.substring(0, pos)),
sepStr,
new Sk.builtin.str(self.v.substring(pos + sepStr.v.length))]);
});
Sk.builtin.str.prototype["count"] = new Sk.builtin.func(function (self, pat, start, end) {
var normaltext;
var ctl;
var slice;
var m;
Sk.builtin.pyCheckArgs("count", arguments, 2, 4);
if (!Sk.builtin.checkString(pat)) {
throw new Sk.builtin.TypeError("expected a character buffer object");
}
if ((start !== undefined) && !Sk.builtin.checkInt(start)) {
throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
}
if ((end !== undefined) && !Sk.builtin.checkInt(end)) {
throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
}
if (start === undefined) {
start = 0;
} else {
start = Sk.builtin.asnum$(start);
start = start >= 0 ? start : self.v.length + start;
}
if (end === undefined) {
end = self.v.length;
} else {
end = Sk.builtin.asnum$(end);
end = end >= 0 ? end : self.v.length + end;
}
normaltext = pat.v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
m = new RegExp(normaltext, "g");
slice = self.v.slice(start, end);
ctl = slice.match(m);
if (!ctl) {
return new Sk.builtin.int_(0);
} else {
return new Sk.builtin.int_(ctl.length);
}
});
Sk.builtin.str.prototype["ljust"] = new Sk.builtin.func(function (self, len, fillchar) {
var newstr;
Sk.builtin.pyCheckArgs("ljust", arguments, 2, 3);
if (!Sk.builtin.checkInt(len)) {
throw new Sk.builtin.TypeError("integer argument exepcted, got " + Sk.abstr.typeName(len));
}
if ((fillchar !== undefined) && (!Sk.builtin.checkString(fillchar) || fillchar.v.length !== 1)) {
throw new Sk.builtin.TypeError("must be char, not " + Sk.abstr.typeName(fillchar));
}
if (fillchar === undefined) {
fillchar = " ";
} else {
fillchar = fillchar.v;
}
len = Sk.builtin.asnum$(len);
if (self.v.length >= len) {
return self;
} else {
newstr = Array.prototype.join.call({length: Math.floor(len - self.v.length) + 1}, fillchar);
return new Sk.builtin.str(self.v + newstr);
}
});
Sk.builtin.str.prototype["rjust"] = new Sk.builtin.func(function (self, len, fillchar) {
var newstr;
Sk.builtin.pyCheckArgs("rjust", arguments, 2, 3);
if (!Sk.builtin.checkInt(len)) {
throw new Sk.builtin.TypeError("integer argument exepcted, got " + Sk.abstr.typeName(len));
}
if ((fillchar !== undefined) && (!Sk.builtin.checkString(fillchar) || fillchar.v.length !== 1)) {
throw new Sk.builtin.TypeError("must be char, not " + Sk.abstr.typeName(fillchar));
}
if (fillchar === undefined) {
fillchar = " ";
} else {
fillchar = fillchar.v;
}
len = Sk.builtin.asnum$(len);
if (self.v.length >= len) {
return self;
} else {
newstr = Array.prototype.join.call({length: Math.floor(len - self.v.length) + 1}, fillchar);
return new Sk.builtin.str(newstr + self.v);
}
});
Sk.builtin.str.prototype["center"] = new Sk.builtin.func(function (self, len, fillchar) {
var newstr;
var newstr1;
Sk.builtin.pyCheckArgs("center", arguments, 2, 3);
if (!Sk.builtin.checkInt(len)) {
throw new Sk.builtin.TypeError("integer argument exepcted, got " + Sk.abstr.typeName(len));
}
if ((fillchar !== undefined) && (!Sk.builtin.checkString(fillchar) || fillchar.v.length !== 1)) {
throw new Sk.builtin.TypeError("must be char, not " + Sk.abstr.typeName(fillchar));
}
if (fillchar === undefined) {
fillchar = " ";
} else {
fillchar = fillchar.v;
}
len = Sk.builtin.asnum$(len);
if (self.v.length >= len) {
return self;
} else {
newstr1 = Array.prototype.join.call({length: Math.floor((len - self.v.length) / 2) + 1}, fillchar);
newstr = newstr1 + self.v + newstr1;
if (newstr.length < len) {
newstr = newstr + fillchar;
}
return new Sk.builtin.str(newstr);
}
});
Sk.builtin.str.prototype["find"] = new Sk.builtin.func(function (self, tgt, start, end) {
var idx;
Sk.builtin.pyCheckArgs("find", arguments, 2, 4);
if (!Sk.builtin.checkString(tgt)) {
throw new Sk.builtin.TypeError("expected a character buffer object");
}
if ((start !== undefined) && !Sk.builtin.checkInt(start)) {
throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
}
if ((end !== undefined) && !Sk.builtin.checkInt(end)) {
throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
}
if (start === undefined) {
start = 0;
} else {
start = Sk.builtin.asnum$(start);
start = start >= 0 ? start : self.v.length + start;
}
if (end === undefined) {
end = self.v.length;
} else {
end = Sk.builtin.asnum$(end);
end = end >= 0 ? end : self.v.length + end;
}
idx = self.v.indexOf(tgt.v, start);
idx = ((idx >= start) && (idx < end)) ? idx : -1;
return new Sk.builtin.int_(idx);
});
Sk.builtin.str.prototype["index"] = new Sk.builtin.func(function (self, tgt, start, end) {
var idx;
Sk.builtin.pyCheckArgs("index", arguments, 2, 4);
idx = Sk.misceval.callsim(self["find"], self, tgt, start, end);
if (Sk.builtin.asnum$(idx) === -1) {
throw new Sk.builtin.ValueError("substring not found");
}
return idx;
});
Sk.builtin.str.prototype["rfind"] = new Sk.builtin.func(function (self, tgt, start, end) {
var idx;
Sk.builtin.pyCheckArgs("rfind", arguments, 2, 4);
if (!Sk.builtin.checkString(tgt)) {
throw new Sk.builtin.TypeError("expected a character buffer object");
}
if ((start !== undefined) && !Sk.builtin.checkInt(start)) {
throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
}
if ((end !== undefined) && !Sk.builtin.checkInt(end)) {
throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
}
if (start === undefined) {
start = 0;
} else {
start = Sk.builtin.asnum$(start);
start = start >= 0 ? start : self.v.length + start;
}
if (end === undefined) {
end = self.v.length;
} else {
end = Sk.builtin.asnum$(end);
end = end >= 0 ? end : self.v.length + end;
}
idx = self.v.lastIndexOf(tgt.v, end);
idx = (idx !== end) ? idx : self.v.lastIndexOf(tgt.v, end - 1);
idx = ((idx >= start) && (idx < end)) ? idx : -1;
return new Sk.builtin.int_(idx);
});
Sk.builtin.str.prototype["rindex"] = new Sk.builtin.func(function (self, tgt, start, end) {
var idx;
Sk.builtin.pyCheckArgs("rindex", arguments, 2, 4);
idx = Sk.misceval.callsim(self["rfind"], self, tgt, start, end);
if (Sk.builtin.asnum$(idx) === -1) {
throw new Sk.builtin.ValueError("substring not found");
}
return idx;
});
Sk.builtin.str.prototype["startswith"] = new Sk.builtin.func(function (self, tgt) {
Sk.builtin.pyCheckArgs("startswith", arguments, 2, 2);
Sk.builtin.pyCheckType("tgt", "string", Sk.builtin.checkString(tgt));
return new Sk.builtin.bool( self.v.indexOf(tgt.v) === 0);
});
// http://stackoverflow.com/questions/280634/endswith-in-javascript
Sk.builtin.str.prototype["endswith"] = new Sk.builtin.func(function (self, tgt) {
Sk.builtin.pyCheckArgs("endswith", arguments, 2, 2);
Sk.builtin.pyCheckType("tgt", "string", Sk.builtin.checkString(tgt));
return new Sk.builtin.bool( self.v.indexOf(tgt.v, self.v.length - tgt.v.length) !== -1);
});
Sk.builtin.str.prototype["replace"] = new Sk.builtin.func(function (self, oldS, newS, count) {
var c;
var patt;
Sk.builtin.pyCheckArgs("replace", arguments, 3, 4);
Sk.builtin.pyCheckType("oldS", "string", Sk.builtin.checkString(oldS));
Sk.builtin.pyCheckType("newS", "string", Sk.builtin.checkString(newS));
if ((count !== undefined) && !Sk.builtin.checkInt(count)) {
throw new Sk.builtin.TypeError("integer argument expected, got " +
Sk.abstr.typeName(count));
}
count = Sk.builtin.asnum$(count);
patt = new RegExp(Sk.builtin.str.re_escape_(oldS.v), "g");
if ((count === undefined) || (count < 0)) {
return new Sk.builtin.str(self.v.replace(patt, newS.v));
}
c = 0;
function replacer (match) {
c++;
if (c <= count) {
return newS.v;
}
return match;
}
return new Sk.builtin.str(self.v.replace(patt, replacer));
});
Sk.builtin.str.prototype["zfill"] = new Sk.builtin.func(function (self, len) {
var str = self.v;
var ret;
var zeroes;
var offset;
var pad = "";
Sk.builtin.pyCheckArgs("zfill", arguments, 2, 2);
if (! Sk.builtin.checkInt(len)) {
throw new Sk.builtin.TypeError("integer argument exepected, got " + Sk.abstr.typeName(len));
}
// figure out how many zeroes are needed to make the proper length
zeroes = len.v - str.length;
// offset by 1 if there is a +/- at the beginning of the string
offset = (str[0] === "+" || str[0] === "-") ? 1 : 0;
for(var i = 0; i < zeroes; i++){
pad += "0";
}
// combine the string and the zeroes
ret = str.substr(0, offset) + pad + str.substr(offset);
return new Sk.builtin.str(ret);
});
Sk.builtin.str.prototype["isdigit"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("isdigit", arguments, 1, 1);
return new Sk.builtin.bool( /^\d+$/.test(self.v));
});
Sk.builtin.str.prototype["isspace"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("isspace", arguments, 1, 1);
return new Sk.builtin.bool( /^\s+$/.test(self.v));
});
Sk.builtin.str.prototype["expandtabs"] = new Sk.builtin.func(function (self, tabsize) {
// var input = self.v;
// var expanded = "";
// var split;
// var spacestr = "";
// var spacerem;
var spaces;
var expanded;
Sk.builtin.pyCheckArgs("expandtabs", arguments, 1, 2);
if ((tabsize !== undefined) && ! Sk.builtin.checkInt(tabsize)) {
throw new Sk.builtin.TypeError("integer argument exepected, got " + Sk.abstr.typeName(tabsize));
}
if (tabsize === undefined) {
tabsize = 8;
} else {
tabsize = Sk.builtin.asnum$(tabsize);
}
spaces = (new Array(tabsize + 1)).join(" ");
expanded = self.v.replace(/([^\r\n\t]*)\t/g, function(a, b) {
return b + spaces.slice(b.length % tabsize);
});
return new Sk.builtin.str(expanded);
});
Sk.builtin.str.prototype["swapcase"] = new Sk.builtin.func(function (self) {
var ret;
Sk.builtin.pyCheckArgs("swapcase", arguments, 1, 1);
ret = self.v.replace(/[a-z]/gi, function(c) {
var lc = c.toLowerCase();
return lc === c ? c.toUpperCase() : lc;
});
return new Sk.builtin.str(ret);
});
Sk.builtin.str.prototype["splitlines"] = new Sk.builtin.func(function (self, keepends) {
var data = self.v;
var i = 0;
var j = i;
var selflen = self.v.length;
var strs_w = [];
var ch;
var eol;
var sol = 0;
var slice;
Sk.builtin.pyCheckArgs("splitlines", arguments, 1, 2);
if ((keepends !== undefined) && ! Sk.builtin.checkBool(keepends)) {
throw new Sk.builtin.TypeError("boolean argument expected, got " + Sk.abstr.typeName(keepends));
}
if (keepends === undefined) {
keepends = false;
} else {
keepends = keepends.v;
}
for (i = 0; i < selflen; i ++) {
ch = data.charAt(i);
if (data.charAt(i + 1) === "\n" && ch === "\r") {
eol = i + 2;
slice = data.slice(sol, eol);
if (! keepends) {
slice = slice.replace(/(\r|\n)/g, "");
}
strs_w.push(new Sk.builtin.str(slice));
sol = eol;
} else if ((ch === "\n" && data.charAt(i - 1) !== "\r") || ch === "\r") {
eol = i + 1;
slice = data.slice(sol, eol);
if (! keepends) {
slice = slice.replace(/(\r|\n)/g, "");
}
strs_w.push(new Sk.builtin.str(slice));
sol = eol;
}
}
if (sol < selflen) {
eol = selflen;
slice = data.slice(sol, eol);
if (! keepends) {
slice = slice.replace(/(\r|\n)/g, "");
}
strs_w.push(new Sk.builtin.str(slice));
}
return new Sk.builtin.list(strs_w);
});
Sk.builtin.str.prototype["title"] = new Sk.builtin.func(function (self) {
var ret;
Sk.builtin.pyCheckArgs("title", arguments, 1, 1);
ret = self.v.replace(/[a-z][a-z]*/gi, function(str) {
return str[0].toUpperCase() + str.substr(1).toLowerCase();
});
return new Sk.builtin.str(ret);
});
Sk.builtin.str.prototype["isalpha"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("isalpha", arguments, 1, 1);
return new Sk.builtin.bool( self.v.length && goog.string.isAlpha(self.v));
});
Sk.builtin.str.prototype["isalnum"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("isalnum", arguments, 1, 1);
return new Sk.builtin.bool( self.v.length && goog.string.isAlphaNumeric(self.v));
});
// does not account for unicode numeric values
Sk.builtin.str.prototype["isnumeric"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("isnumeric", arguments, 1, 1);
return new Sk.builtin.bool( self.v.length && goog.string.isNumeric(self.v));
});
Sk.builtin.str.prototype["islower"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("islower", arguments, 1, 1);
return new Sk.builtin.bool( self.v.length && /[a-z]/.test(self.v) && !/[A-Z]/.test(self.v));
});
Sk.builtin.str.prototype["isupper"] = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("isupper", arguments, 1, 1);
return new Sk.builtin.bool( self.v.length && !/[a-z]/.test(self.v) && /[A-Z]/.test(self.v));
});
Sk.builtin.str.prototype["istitle"] = new Sk.builtin.func(function (self) {
// Comparing to str.title() seems the most intuitive thing, but it fails on "",
// Other empty-ish strings with no change.
var input = self.v;
var cased = false;
var previous_is_cased = false;
var pos;
var ch;
Sk.builtin.pyCheckArgs("istitle", arguments, 1, 1);
for (pos = 0; pos < input.length; pos ++) {
ch = input.charAt(pos);
if (! /[a-z]/.test(ch) && /[A-Z]/.test(ch)) {
if (previous_is_cased) {
return new Sk.builtin.bool( false);
}
previous_is_cased = true;
cased = true;
} else if (/[a-z]/.test(ch) && ! /[A-Z]/.test(ch)) {
if (! previous_is_cased) {
return new Sk.builtin.bool( false);
}
cased = true;
} else {
previous_is_cased = false;
}
}
return new Sk.builtin.bool( cased);
});
Sk.builtin.str.prototype.nb$remainder = function (rhs) {
// % format op. rhs can be a value, a tuple, or something with __getitem__ (dict)
// From http://docs.python.org/library/stdtypes.html#string-formatting the
// format looks like:
// 1. The '%' character, which marks the start of the specifier.
// 2. Mapping key (optional), consisting of a parenthesised sequence of characters (for example, (somename)).
// 3. Conversion flags (optional), which affect the result of some conversion types.
// 4. Minimum field width (optional). If specified as an '*' (asterisk), the actual width is read from the next
// element of the tuple in values, and the object to convert comes after the minimum field width and optional
// precision. 5. Precision (optional), given as a '.' (dot) followed by the precision. If specified as '*' (an
// asterisk), the actual width is read from the next element of the tuple in values, and the value to convert comes
// after the precision. 6. Length modifier (optional). 7. Conversion type. length modifier is ignored
var ret;
var replFunc;
var index;
var regex;
if (rhs.constructor !== Sk.builtin.tuple && (rhs.mp$subscript === undefined || rhs.constructor === Sk.builtin.str)) {
rhs = new Sk.builtin.tuple([rhs]);
}
// general approach is to use a regex that matches the format above, and
// do an re.sub with a function as replacement to make the subs.
// 1 2222222222222222 33333333 444444444 5555555555555 66666 777777777777777777
regex = /%(\([a-zA-Z0-9]+\))?([#0 +\-]+)?(\*|[0-9]+)?(\.(\*|[0-9]+))?[hlL]?([diouxXeEfFgGcrs%])/g;
index = 0;
replFunc = function (substring, mappingKey, conversionFlags, fieldWidth, precision, precbody, conversionType) {
var result;
var convName;
var convValue;
var base;
var r;
var mk;
var value;
var handleWidth;
var formatNumber;
var alternateForm;
var precedeWithSign;
var blankBeforePositive;
var leftAdjust;
var zeroPad;
var i;
fieldWidth = Sk.builtin.asnum$(fieldWidth);
precision = Sk.builtin.asnum$(precision);
if (mappingKey === undefined || mappingKey === "") {
i = index++;
} // ff passes '' not undef for some reason
if (precision === "") { // ff passes '' here aswell causing problems with G,g, etc.
precision = undefined;
}
zeroPad = false;
leftAdjust = false;
blankBeforePositive = false;
precedeWithSign = false;
alternateForm = false;
if (conversionFlags) {
if (conversionFlags.indexOf("-") !== -1) {
leftAdjust = true;
} else if (conversionFlags.indexOf("0") !== -1) {
zeroPad = true;
}
if (conversionFlags.indexOf("+") !== -1) {
precedeWithSign = true;
} else if (conversionFlags.indexOf(" ") !== -1) {
blankBeforePositive = true;
}
alternateForm = conversionFlags.indexOf("#") !== -1;
}
if (precision) {
precision = parseInt(precision.substr(1), 10);
}
formatNumber = function (n, base) {
var precZeroPadded;
var prefix;
var didSign;
var neg;
var r;
var j;
base = Sk.builtin.asnum$(base);
neg = false;
didSign = false;
if (typeof n === "number") {
if (n < 0) {
n = -n;
neg = true;
}
r = n.toString(base);
} else if (n instanceof Sk.builtin.float_) {
r = n.str$(base, false);
if (r.length > 2 && r.substr(-2) === ".0") {
r = r.substr(0, r.length - 2);
}
neg = n.nb$isnegative();
} else if (n instanceof Sk.builtin.int_) {
r = n.str$(base, false);
neg = n.nb$isnegative();
} else if (n instanceof Sk.builtin.lng) {
r = n.str$(base, false);
neg = n.nb$isnegative(); // neg = n.size$ < 0; RNL long.js change
}
goog.asserts.assert(r !== undefined, "unhandled number format");
precZeroPadded = false;
if (precision) {
//print("r.length",r.length,"precision",precision);
for (j = r.length; j < precision; ++j) {
r = "0" + r;
precZeroPadded = true;
}
}
prefix = "";
if (neg) {
prefix = "-";
} else if (precedeWithSign) {
prefix = "+" + prefix;
} else if (blankBeforePositive) {
prefix = " " + prefix;
}
if (alternateForm) {
if (base === 16) {
prefix += "0x";
} else if (base === 8 && !precZeroPadded && r !== "0") {
prefix += "0";
}
}
return [prefix, r];
};
handleWidth = function (args) {
var totLen;
var prefix = args[0];
var r = args[1];
var j;
if (fieldWidth) {
fieldWidth = parseInt(fieldWidth, 10);
totLen = r.length + prefix.length;
if (zeroPad) {
for (j = totLen; j < fieldWidth; ++j) {
r = "0" + r;
}
} else if (leftAdjust) {
for (j = totLen; j < fieldWidth; ++j) {
r = r + " ";
}
} else {
for (j = totLen; j < fieldWidth; ++j) {
prefix = " " + prefix;
}
}
}
return prefix + r;
};
//print("Rhs:",rhs, "ctor", rhs.constructor);
if (rhs.constructor === Sk.builtin.tuple) {
value = rhs.v[i];
} else if (rhs.mp$subscript !== undefined && mappingKey !== undefined) {
mk = mappingKey.substring(1, mappingKey.length - 1);
//print("mk",mk);
value = rhs.mp$subscript(new Sk.builtin.str(mk));
} else if (rhs.constructor === Sk.builtin.dict || rhs.constructor === Sk.builtin.list) {
// new case where only one argument is provided
value = rhs;
} else {
throw new Sk.builtin.AttributeError(rhs.tp$name + " instance has no attribute 'mp$subscript'");
}
base = 10;
if (conversionType === "d" || conversionType === "i") {
return handleWidth(formatNumber(value, 10));
} else if (conversionType === "o") {
return handleWidth(formatNumber(value, 8));
} else if (conversionType === "x") {
return handleWidth(formatNumber(value, 16));
} else if (conversionType === "X") {
return handleWidth(formatNumber(value, 16)).toUpperCase();
} else if (conversionType === "f" || conversionType === "F" || conversionType === "e" || conversionType === "E" || conversionType === "g" || conversionType === "G") {
convValue = Sk.builtin.asnum$(value);
if (typeof convValue === "string") {
convValue = Number(convValue);
}
if (convValue === Infinity) {
return "inf";
}
if (convValue === -Infinity) {
return "-inf";
}
if (isNaN(convValue)) {
return "nan";
}
convName = ["toExponential", "toFixed", "toPrecision"]["efg".indexOf(conversionType.toLowerCase())];
if (precision === undefined || precision === "") {
if (conversionType === "e" || conversionType === "E") {
precision = 6;
} else if (conversionType === "f" || conversionType === "F") {
precision = 7;
}
}
result = (convValue)[convName](precision); // possible loose of negative zero sign
// apply sign to negative zeros, floats only!
if(Sk.builtin.checkFloat(value)) {
if(convValue === 0 && 1/convValue === -Infinity) {
result = "-" + result; // add sign for zero
}
}
if ("EFG".indexOf(conversionType) !== -1) {
result = result.toUpperCase();
}
return handleWidth(["", result]);
} else if (conversionType === "c") {
if (typeof value === "number") {
return String.fromCharCode(value);
} else if (value instanceof Sk.builtin.int_) {
return String.fromCharCode(value.v);
} else if (value instanceof Sk.builtin.float_) {
return String.fromCharCode(value.v);
} else if (value instanceof Sk.builtin.lng) {
return String.fromCharCode(value.str$(10, false)[0]);
} else if (value.constructor === Sk.builtin.str) {
return value.v.substr(0, 1);
} else {
throw new Sk.builtin.TypeError("an integer is required");
}
} else if (conversionType === "r") {
r = Sk.builtin.repr(value);
if (precision) {
return r.v.substr(0, precision);
}
return r.v;
} else if (conversionType === "s") {
r = new Sk.builtin.str(value);
if (precision) {
return r.v.substr(0, precision);
}
if(fieldWidth) {
r.v = handleWidth([" ", r.v]);
}
return r.v;
} else if (conversionType === "%") {
return "%";
}
};
ret = this.v.replace(regex, replFunc);
return new Sk.builtin.str(ret);
};
/**
* @constructor
* @param {Object} obj
*/
Sk.builtin.str_iter_ = function (obj) {
if (!(this instanceof Sk.builtin.str_iter_)) {
return new Sk.builtin.str_iter_(obj);
}
this.$index = 0;
this.$obj = obj.v.slice();
this.sq$length = this.$obj.length;
this.tp$iter = this;
this.tp$iternext = function () {
if (this.$index >= this.sq$length) {
return undefined;
}
return new Sk.builtin.str(this.$obj.substr(this.$index++, 1));
};
this.$r = function () {
return new Sk.builtin.str("iterator");
};
return this;
};
Sk.abstr.setUpInheritance("iterator", Sk.builtin.str_iter_, Sk.builtin.object);
Sk.builtin.str_iter_.prototype.__class__ = Sk.builtin.str_iter_;
Sk.builtin.str_iter_.prototype.__iter__ = new Sk.builtin.func(function (self) {
Sk.builtin.pyCheckArgs("__iter__", arguments, 0, 0, true, false);
return self;
});
Sk.builtin.str_iter_.prototype["next"] = new Sk.builtin.func(function (self) {
var ret = self.tp$iternext();
if (ret === undefined) {
throw new Sk.builtin.StopIteration();
}
return ret;
});