str.js 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168
  1. Sk.builtin.interned = {};
  2. /**
  3. * @constructor
  4. * @param {*} x
  5. * @extends Sk.builtin.object
  6. */
  7. Sk.builtin.str = function (x) {
  8. var ret;
  9. if (x === undefined) {
  10. x = "";
  11. }
  12. if (x instanceof Sk.builtin.str) {
  13. return x;
  14. }
  15. if (!(this instanceof Sk.builtin.str)) {
  16. return new Sk.builtin.str(x);
  17. }
  18. // convert to js string
  19. if (x === true) {
  20. ret = "True";
  21. } else if (x === false) {
  22. ret = "False";
  23. } else if ((x === null) || (x instanceof Sk.builtin.none)) {
  24. ret = "None";
  25. } else if (x instanceof Sk.builtin.bool) {
  26. if (x.v) {
  27. ret = "True";
  28. } else {
  29. ret = "False";
  30. }
  31. } else if (typeof x === "number") {
  32. ret = x.toString();
  33. if (ret === "Infinity") {
  34. ret = "inf";
  35. } else if (ret === "-Infinity") {
  36. ret = "-inf";
  37. }
  38. } else if (typeof x === "string") {
  39. ret = x;
  40. } else if (x.tp$str !== undefined) {
  41. ret = x.tp$str();
  42. if (!(ret instanceof Sk.builtin.str)) {
  43. throw new Sk.builtin.ValueError("__str__ didn't return a str");
  44. }
  45. return ret;
  46. } else {
  47. return Sk.misceval.objectRepr(x);
  48. }
  49. // interning required for strings in py
  50. if (Sk.builtin.interned["1" + ret]) {
  51. return Sk.builtin.interned["1" + ret];
  52. }
  53. this.__class__ = Sk.builtin.str;
  54. this.v = ret;
  55. this["v"] = this.v;
  56. Sk.builtin.interned["1" + ret] = this;
  57. return this;
  58. };
  59. goog.exportSymbol("Sk.builtin.str", Sk.builtin.str);
  60. Sk.abstr.setUpInheritance("str", Sk.builtin.str, Sk.builtin.seqtype);
  61. Sk.builtin.str.prototype.mp$subscript = function (index) {
  62. var ret;
  63. if (Sk.misceval.isIndex(index)) {
  64. index = Sk.misceval.asIndex(index);
  65. if (index < 0) {
  66. index = this.v.length + index;
  67. }
  68. if (index < 0 || index >= this.v.length) {
  69. throw new Sk.builtin.IndexError("string index out of range");
  70. }
  71. return new Sk.builtin.str(this.v.charAt(index));
  72. } else if (index instanceof Sk.builtin.slice) {
  73. ret = "";
  74. index.sssiter$(this, function (i, wrt) {
  75. if (i >= 0 && i < wrt.v.length) {
  76. ret += wrt.v.charAt(i);
  77. }
  78. });
  79. return new Sk.builtin.str(ret);
  80. } else {
  81. throw new Sk.builtin.TypeError("string indices must be integers, not " + Sk.abstr.typeName(index));
  82. }
  83. };
  84. Sk.builtin.str.prototype.sq$length = function () {
  85. return this.v.length;
  86. };
  87. Sk.builtin.str.prototype.sq$concat = function (other) {
  88. var otypename;
  89. if (!other || !Sk.builtin.checkString(other)) {
  90. otypename = Sk.abstr.typeName(other);
  91. throw new Sk.builtin.TypeError("cannot concatenate 'str' and '" + otypename + "' objects");
  92. }
  93. return new Sk.builtin.str(this.v + other.v);
  94. };
  95. Sk.builtin.str.prototype.nb$add = Sk.builtin.str.prototype.sq$concat;
  96. Sk.builtin.str.prototype.nb$inplace_add = Sk.builtin.str.prototype.sq$concat;
  97. Sk.builtin.str.prototype.sq$repeat = function (n) {
  98. var i;
  99. var ret;
  100. if (!Sk.misceval.isIndex(n)) {
  101. throw new Sk.builtin.TypeError("can't multiply sequence by non-int of type '" + Sk.abstr.typeName(n) + "'");
  102. }
  103. n = Sk.misceval.asIndex(n);
  104. ret = "";
  105. for (i = 0; i < n; ++i) {
  106. ret += this.v;
  107. }
  108. return new Sk.builtin.str(ret);
  109. };
  110. Sk.builtin.str.prototype.nb$multiply = Sk.builtin.str.prototype.sq$repeat;
  111. Sk.builtin.str.prototype.nb$inplace_multiply = Sk.builtin.str.prototype.sq$repeat;
  112. Sk.builtin.str.prototype.sq$item = function () {
  113. goog.asserts.fail();
  114. };
  115. Sk.builtin.str.prototype.sq$slice = function (i1, i2) {
  116. i1 = Sk.builtin.asnum$(i1);
  117. i2 = Sk.builtin.asnum$(i2);
  118. if (i1 < 0) {
  119. i1 = 0;
  120. }
  121. return new Sk.builtin.str(this.v.substr(i1, i2 - i1));
  122. };
  123. Sk.builtin.str.prototype.sq$contains = function (ob) {
  124. if (!(ob instanceof Sk.builtin.str)) {
  125. throw new Sk.builtin.TypeError("TypeError: 'In <string> requires string as left operand");
  126. }
  127. return this.v.indexOf(ob.v) != -1;
  128. };
  129. Sk.builtin.str.prototype.__iter__ = new Sk.builtin.func(function (self) {
  130. return new Sk.builtin.str_iter_(self);
  131. });
  132. Sk.builtin.str.prototype.tp$iter = function () {
  133. return new Sk.builtin.str_iter_(this);
  134. };
  135. Sk.builtin.str.prototype.tp$richcompare = function (other, op) {
  136. if (!(other instanceof Sk.builtin.str)) {
  137. return undefined;
  138. }
  139. switch (op) {
  140. case "Lt":
  141. return this.v < other.v;
  142. case "LtE":
  143. return this.v <= other.v;
  144. case "Eq":
  145. return this.v === other.v;
  146. case "NotEq":
  147. return this.v !== other.v;
  148. case "Gt":
  149. return this.v > other.v;
  150. case "GtE":
  151. return this.v >= other.v;
  152. default:
  153. goog.asserts.fail();
  154. }
  155. };
  156. Sk.builtin.str.prototype["$r"] = function () {
  157. // single is preferred
  158. var ashex;
  159. var c;
  160. var i;
  161. var ret;
  162. var len;
  163. var quote = "'";
  164. //jshint ignore:start
  165. if (this.v.indexOf("'") !== -1 && this.v.indexOf('"') === -1) {
  166. quote = '"';
  167. }
  168. //jshint ignore:end
  169. len = this.v.length;
  170. ret = quote;
  171. for (i = 0; i < len; ++i) {
  172. c = this.v.charAt(i);
  173. if (c === quote || c === "\\") {
  174. ret += "\\" + c;
  175. } else if (c === "\t") {
  176. ret += "\\t";
  177. } else if (c === "\n") {
  178. ret += "\\n";
  179. } else if (c === "\r") {
  180. ret += "\\r";
  181. } else if (c < " " || c >= 0x7f) {
  182. ashex = c.charCodeAt(0).toString(16);
  183. if (ashex.length < 2) {
  184. ashex = "0" + ashex;
  185. }
  186. ret += "\\x" + ashex;
  187. } else {
  188. ret += c;
  189. }
  190. }
  191. ret += quote;
  192. return new Sk.builtin.str(ret);
  193. };
  194. Sk.builtin.str.re_escape_ = function (s) {
  195. var c;
  196. var i;
  197. var ret = [];
  198. var re = /^[A-Za-z0-9]+$/;
  199. for (i = 0; i < s.length; ++i) {
  200. c = s.charAt(i);
  201. if (re.test(c)) {
  202. ret.push(c);
  203. } else {
  204. if (c === "\\000") {
  205. ret.push("\\000");
  206. } else {
  207. ret.push("\\" + c);
  208. }
  209. }
  210. }
  211. return ret.join("");
  212. };
  213. Sk.builtin.str.prototype["lower"] = new Sk.builtin.func(function (self) {
  214. Sk.builtin.pyCheckArgs("lower", arguments, 1, 1);
  215. return new Sk.builtin.str(self.v.toLowerCase());
  216. });
  217. Sk.builtin.str.prototype["upper"] = new Sk.builtin.func(function (self) {
  218. Sk.builtin.pyCheckArgs("upper", arguments, 1, 1);
  219. return new Sk.builtin.str(self.v.toUpperCase());
  220. });
  221. Sk.builtin.str.prototype["capitalize"] = new Sk.builtin.func(function (self) {
  222. var i;
  223. var cap;
  224. var orig;
  225. Sk.builtin.pyCheckArgs("capitalize", arguments, 1, 1);
  226. orig = self.v;
  227. if (orig.length === 0) {
  228. return new Sk.builtin.str("");
  229. }
  230. cap = orig.charAt(0).toUpperCase();
  231. for (i = 1; i < orig.length; i++) {
  232. cap += orig.charAt(i).toLowerCase();
  233. }
  234. return new Sk.builtin.str(cap);
  235. });
  236. Sk.builtin.str.prototype["join"] = new Sk.builtin.func(function (self, seq) {
  237. var it, i;
  238. var arrOfStrs;
  239. Sk.builtin.pyCheckArgs("join", arguments, 2, 2);
  240. Sk.builtin.pyCheckType("seq", "iterable", Sk.builtin.checkIterable(seq));
  241. arrOfStrs = [];
  242. for (it = seq.tp$iter(), i = it.tp$iternext(); i !== undefined; i = it.tp$iternext()) {
  243. if (i.constructor !== Sk.builtin.str) {
  244. throw new Sk.builtin.TypeError("TypeError: sequence item " + arrOfStrs.length + ": expected string, " + typeof i + " found");
  245. }
  246. arrOfStrs.push(i.v);
  247. }
  248. return new Sk.builtin.str(arrOfStrs.join(self.v));
  249. });
  250. Sk.builtin.str.prototype["split"] = new Sk.builtin.func(function (self, on, howmany) {
  251. var splits;
  252. var index;
  253. var match;
  254. var result;
  255. var s;
  256. var str;
  257. var regex;
  258. Sk.builtin.pyCheckArgs("split", arguments, 1, 3);
  259. if ((on === undefined) || (on instanceof Sk.builtin.none)) {
  260. on = null;
  261. }
  262. if ((on !== null) && !Sk.builtin.checkString(on)) {
  263. throw new Sk.builtin.TypeError("expected a string");
  264. }
  265. if ((on !== null) && on.v === "") {
  266. throw new Sk.builtin.ValueError("empty separator");
  267. }
  268. if ((howmany !== undefined) && !Sk.builtin.checkInt(howmany)) {
  269. throw new Sk.builtin.TypeError("an integer is required");
  270. }
  271. howmany = Sk.builtin.asnum$(howmany);
  272. regex = /[\s]+/g;
  273. str = self.v;
  274. if (on === null) {
  275. str = goog.string.trimLeft(str);
  276. } else {
  277. // Escape special characters in "on" so we can use a regexp
  278. s = on.v.replace(/([.*+?=|\\\/()\[\]\{\}^$])/g, "\\$1");
  279. regex = new RegExp(s, "g");
  280. }
  281. // This is almost identical to re.split,
  282. // except how the regexp is constructed
  283. result = [];
  284. index = 0;
  285. splits = 0;
  286. while ((match = regex.exec(str)) != null) {
  287. if (match.index === regex.lastIndex) {
  288. // empty match
  289. break;
  290. }
  291. result.push(new Sk.builtin.str(str.substring(index, match.index)));
  292. index = regex.lastIndex;
  293. splits += 1;
  294. if (howmany && (splits >= howmany)) {
  295. break;
  296. }
  297. }
  298. str = str.substring(index);
  299. if (on !== null || (str.length > 0)) {
  300. result.push(new Sk.builtin.str(str));
  301. }
  302. return new Sk.builtin.list(result);
  303. });
  304. Sk.builtin.str.prototype["strip"] = new Sk.builtin.func(function (self, chars) {
  305. var regex;
  306. var pattern;
  307. Sk.builtin.pyCheckArgs("strip", arguments, 1, 2);
  308. if ((chars !== undefined) && !Sk.builtin.checkString(chars)) {
  309. throw new Sk.builtin.TypeError("strip arg must be None or str");
  310. }
  311. if (chars === undefined) {
  312. pattern = /^\s+|\s+$/g;
  313. } else {
  314. regex = Sk.builtin.str.re_escape_(chars.v);
  315. pattern = new RegExp("^[" + regex + "]+|[" + regex + "]+$", "g");
  316. }
  317. return new Sk.builtin.str(self.v.replace(pattern, ""));
  318. });
  319. Sk.builtin.str.prototype["lstrip"] = new Sk.builtin.func(function (self, chars) {
  320. var regex;
  321. var pattern;
  322. Sk.builtin.pyCheckArgs("lstrip", arguments, 1, 2);
  323. if ((chars !== undefined) && !Sk.builtin.checkString(chars)) {
  324. throw new Sk.builtin.TypeError("lstrip arg must be None or str");
  325. }
  326. if (chars === undefined) {
  327. pattern = /^\s+/g;
  328. } else {
  329. regex = Sk.builtin.str.re_escape_(chars.v);
  330. pattern = new RegExp("^[" + regex + "]+", "g");
  331. }
  332. return new Sk.builtin.str(self.v.replace(pattern, ""));
  333. });
  334. Sk.builtin.str.prototype["rstrip"] = new Sk.builtin.func(function (self, chars) {
  335. var regex;
  336. var pattern;
  337. Sk.builtin.pyCheckArgs("rstrip", arguments, 1, 2);
  338. if ((chars !== undefined) && !Sk.builtin.checkString(chars)) {
  339. throw new Sk.builtin.TypeError("rstrip arg must be None or str");
  340. }
  341. if (chars === undefined) {
  342. pattern = /\s+$/g;
  343. } else {
  344. regex = Sk.builtin.str.re_escape_(chars.v);
  345. pattern = new RegExp("[" + regex + "]+$", "g");
  346. }
  347. return new Sk.builtin.str(self.v.replace(pattern, ""));
  348. });
  349. Sk.builtin.str.prototype["partition"] = new Sk.builtin.func(function (self, sep) {
  350. var pos;
  351. var sepStr;
  352. Sk.builtin.pyCheckArgs("partition", arguments, 2, 2);
  353. Sk.builtin.pyCheckType("sep", "string", Sk.builtin.checkString(sep));
  354. sepStr = new Sk.builtin.str(sep);
  355. pos = self.v.indexOf(sepStr.v);
  356. if (pos < 0) {
  357. return new Sk.builtin.tuple([self, Sk.builtin.str.$emptystr, Sk.builtin.str.$emptystr]);
  358. }
  359. return new Sk.builtin.tuple([
  360. new Sk.builtin.str(self.v.substring(0, pos)),
  361. sepStr,
  362. new Sk.builtin.str(self.v.substring(pos + sepStr.v.length))]);
  363. });
  364. Sk.builtin.str.prototype["rpartition"] = new Sk.builtin.func(function (self, sep) {
  365. var pos;
  366. var sepStr;
  367. Sk.builtin.pyCheckArgs("rpartition", arguments, 2, 2);
  368. Sk.builtin.pyCheckType("sep", "string", Sk.builtin.checkString(sep));
  369. sepStr = new Sk.builtin.str(sep);
  370. pos = self.v.lastIndexOf(sepStr.v);
  371. if (pos < 0) {
  372. return new Sk.builtin.tuple([Sk.builtin.str.$emptystr, Sk.builtin.str.$emptystr, self]);
  373. }
  374. return new Sk.builtin.tuple([
  375. new Sk.builtin.str(self.v.substring(0, pos)),
  376. sepStr,
  377. new Sk.builtin.str(self.v.substring(pos + sepStr.v.length))]);
  378. });
  379. Sk.builtin.str.prototype["count"] = new Sk.builtin.func(function (self, pat, start, end) {
  380. var normaltext;
  381. var ctl;
  382. var slice;
  383. var m;
  384. Sk.builtin.pyCheckArgs("count", arguments, 2, 4);
  385. if (!Sk.builtin.checkString(pat)) {
  386. throw new Sk.builtin.TypeError("expected a character buffer object");
  387. }
  388. if ((start !== undefined) && !Sk.builtin.checkInt(start)) {
  389. throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
  390. }
  391. if ((end !== undefined) && !Sk.builtin.checkInt(end)) {
  392. throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
  393. }
  394. if (start === undefined) {
  395. start = 0;
  396. } else {
  397. start = Sk.builtin.asnum$(start);
  398. start = start >= 0 ? start : self.v.length + start;
  399. }
  400. if (end === undefined) {
  401. end = self.v.length;
  402. } else {
  403. end = Sk.builtin.asnum$(end);
  404. end = end >= 0 ? end : self.v.length + end;
  405. }
  406. normaltext = pat.v.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
  407. m = new RegExp(normaltext, "g");
  408. slice = self.v.slice(start, end);
  409. ctl = slice.match(m);
  410. if (!ctl) {
  411. return new Sk.builtin.int_(0);
  412. } else {
  413. return new Sk.builtin.int_(ctl.length);
  414. }
  415. });
  416. Sk.builtin.str.prototype["ljust"] = new Sk.builtin.func(function (self, len, fillchar) {
  417. var newstr;
  418. Sk.builtin.pyCheckArgs("ljust", arguments, 2, 3);
  419. if (!Sk.builtin.checkInt(len)) {
  420. throw new Sk.builtin.TypeError("integer argument exepcted, got " + Sk.abstr.typeName(len));
  421. }
  422. if ((fillchar !== undefined) && (!Sk.builtin.checkString(fillchar) || fillchar.v.length !== 1)) {
  423. throw new Sk.builtin.TypeError("must be char, not " + Sk.abstr.typeName(fillchar));
  424. }
  425. if (fillchar === undefined) {
  426. fillchar = " ";
  427. } else {
  428. fillchar = fillchar.v;
  429. }
  430. len = Sk.builtin.asnum$(len);
  431. if (self.v.length >= len) {
  432. return self;
  433. } else {
  434. newstr = Array.prototype.join.call({length: Math.floor(len - self.v.length) + 1}, fillchar);
  435. return new Sk.builtin.str(self.v + newstr);
  436. }
  437. });
  438. Sk.builtin.str.prototype["rjust"] = new Sk.builtin.func(function (self, len, fillchar) {
  439. var newstr;
  440. Sk.builtin.pyCheckArgs("rjust", arguments, 2, 3);
  441. if (!Sk.builtin.checkInt(len)) {
  442. throw new Sk.builtin.TypeError("integer argument exepcted, got " + Sk.abstr.typeName(len));
  443. }
  444. if ((fillchar !== undefined) && (!Sk.builtin.checkString(fillchar) || fillchar.v.length !== 1)) {
  445. throw new Sk.builtin.TypeError("must be char, not " + Sk.abstr.typeName(fillchar));
  446. }
  447. if (fillchar === undefined) {
  448. fillchar = " ";
  449. } else {
  450. fillchar = fillchar.v;
  451. }
  452. len = Sk.builtin.asnum$(len);
  453. if (self.v.length >= len) {
  454. return self;
  455. } else {
  456. newstr = Array.prototype.join.call({length: Math.floor(len - self.v.length) + 1}, fillchar);
  457. return new Sk.builtin.str(newstr + self.v);
  458. }
  459. });
  460. Sk.builtin.str.prototype["center"] = new Sk.builtin.func(function (self, len, fillchar) {
  461. var newstr;
  462. var newstr1;
  463. Sk.builtin.pyCheckArgs("center", arguments, 2, 3);
  464. if (!Sk.builtin.checkInt(len)) {
  465. throw new Sk.builtin.TypeError("integer argument exepcted, got " + Sk.abstr.typeName(len));
  466. }
  467. if ((fillchar !== undefined) && (!Sk.builtin.checkString(fillchar) || fillchar.v.length !== 1)) {
  468. throw new Sk.builtin.TypeError("must be char, not " + Sk.abstr.typeName(fillchar));
  469. }
  470. if (fillchar === undefined) {
  471. fillchar = " ";
  472. } else {
  473. fillchar = fillchar.v;
  474. }
  475. len = Sk.builtin.asnum$(len);
  476. if (self.v.length >= len) {
  477. return self;
  478. } else {
  479. newstr1 = Array.prototype.join.call({length: Math.floor((len - self.v.length) / 2) + 1}, fillchar);
  480. newstr = newstr1 + self.v + newstr1;
  481. if (newstr.length < len) {
  482. newstr = newstr + fillchar;
  483. }
  484. return new Sk.builtin.str(newstr);
  485. }
  486. });
  487. Sk.builtin.str.prototype["find"] = new Sk.builtin.func(function (self, tgt, start, end) {
  488. var idx;
  489. Sk.builtin.pyCheckArgs("find", arguments, 2, 4);
  490. if (!Sk.builtin.checkString(tgt)) {
  491. throw new Sk.builtin.TypeError("expected a character buffer object");
  492. }
  493. if ((start !== undefined) && !Sk.builtin.checkInt(start)) {
  494. throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
  495. }
  496. if ((end !== undefined) && !Sk.builtin.checkInt(end)) {
  497. throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
  498. }
  499. if (start === undefined) {
  500. start = 0;
  501. } else {
  502. start = Sk.builtin.asnum$(start);
  503. start = start >= 0 ? start : self.v.length + start;
  504. }
  505. if (end === undefined) {
  506. end = self.v.length;
  507. } else {
  508. end = Sk.builtin.asnum$(end);
  509. end = end >= 0 ? end : self.v.length + end;
  510. }
  511. idx = self.v.indexOf(tgt.v, start);
  512. idx = ((idx >= start) && (idx < end)) ? idx : -1;
  513. return new Sk.builtin.int_(idx);
  514. });
  515. Sk.builtin.str.prototype["index"] = new Sk.builtin.func(function (self, tgt, start, end) {
  516. var idx;
  517. Sk.builtin.pyCheckArgs("index", arguments, 2, 4);
  518. idx = Sk.misceval.callsim(self["find"], self, tgt, start, end);
  519. if (Sk.builtin.asnum$(idx) === -1) {
  520. throw new Sk.builtin.ValueError("substring not found");
  521. }
  522. return idx;
  523. });
  524. Sk.builtin.str.prototype["rfind"] = new Sk.builtin.func(function (self, tgt, start, end) {
  525. var idx;
  526. Sk.builtin.pyCheckArgs("rfind", arguments, 2, 4);
  527. if (!Sk.builtin.checkString(tgt)) {
  528. throw new Sk.builtin.TypeError("expected a character buffer object");
  529. }
  530. if ((start !== undefined) && !Sk.builtin.checkInt(start)) {
  531. throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
  532. }
  533. if ((end !== undefined) && !Sk.builtin.checkInt(end)) {
  534. throw new Sk.builtin.TypeError("slice indices must be integers or None or have an __index__ method");
  535. }
  536. if (start === undefined) {
  537. start = 0;
  538. } else {
  539. start = Sk.builtin.asnum$(start);
  540. start = start >= 0 ? start : self.v.length + start;
  541. }
  542. if (end === undefined) {
  543. end = self.v.length;
  544. } else {
  545. end = Sk.builtin.asnum$(end);
  546. end = end >= 0 ? end : self.v.length + end;
  547. }
  548. idx = self.v.lastIndexOf(tgt.v, end);
  549. idx = (idx !== end) ? idx : self.v.lastIndexOf(tgt.v, end - 1);
  550. idx = ((idx >= start) && (idx < end)) ? idx : -1;
  551. return new Sk.builtin.int_(idx);
  552. });
  553. Sk.builtin.str.prototype["rindex"] = new Sk.builtin.func(function (self, tgt, start, end) {
  554. var idx;
  555. Sk.builtin.pyCheckArgs("rindex", arguments, 2, 4);
  556. idx = Sk.misceval.callsim(self["rfind"], self, tgt, start, end);
  557. if (Sk.builtin.asnum$(idx) === -1) {
  558. throw new Sk.builtin.ValueError("substring not found");
  559. }
  560. return idx;
  561. });
  562. Sk.builtin.str.prototype["startswith"] = new Sk.builtin.func(function (self, tgt) {
  563. Sk.builtin.pyCheckArgs("startswith", arguments, 2, 2);
  564. Sk.builtin.pyCheckType("tgt", "string", Sk.builtin.checkString(tgt));
  565. return new Sk.builtin.bool( self.v.indexOf(tgt.v) === 0);
  566. });
  567. // http://stackoverflow.com/questions/280634/endswith-in-javascript
  568. Sk.builtin.str.prototype["endswith"] = new Sk.builtin.func(function (self, tgt) {
  569. Sk.builtin.pyCheckArgs("endswith", arguments, 2, 2);
  570. Sk.builtin.pyCheckType("tgt", "string", Sk.builtin.checkString(tgt));
  571. return new Sk.builtin.bool( self.v.indexOf(tgt.v, self.v.length - tgt.v.length) !== -1);
  572. });
  573. Sk.builtin.str.prototype["replace"] = new Sk.builtin.func(function (self, oldS, newS, count) {
  574. var c;
  575. var patt;
  576. Sk.builtin.pyCheckArgs("replace", arguments, 3, 4);
  577. Sk.builtin.pyCheckType("oldS", "string", Sk.builtin.checkString(oldS));
  578. Sk.builtin.pyCheckType("newS", "string", Sk.builtin.checkString(newS));
  579. if ((count !== undefined) && !Sk.builtin.checkInt(count)) {
  580. throw new Sk.builtin.TypeError("integer argument expected, got " +
  581. Sk.abstr.typeName(count));
  582. }
  583. count = Sk.builtin.asnum$(count);
  584. patt = new RegExp(Sk.builtin.str.re_escape_(oldS.v), "g");
  585. if ((count === undefined) || (count < 0)) {
  586. return new Sk.builtin.str(self.v.replace(patt, newS.v));
  587. }
  588. c = 0;
  589. function replacer (match) {
  590. c++;
  591. if (c <= count) {
  592. return newS.v;
  593. }
  594. return match;
  595. }
  596. return new Sk.builtin.str(self.v.replace(patt, replacer));
  597. });
  598. Sk.builtin.str.prototype["zfill"] = new Sk.builtin.func(function (self, len) {
  599. var str = self.v;
  600. var ret;
  601. var zeroes;
  602. var offset;
  603. var pad = "";
  604. Sk.builtin.pyCheckArgs("zfill", arguments, 2, 2);
  605. if (! Sk.builtin.checkInt(len)) {
  606. throw new Sk.builtin.TypeError("integer argument exepected, got " + Sk.abstr.typeName(len));
  607. }
  608. // figure out how many zeroes are needed to make the proper length
  609. zeroes = len.v - str.length;
  610. // offset by 1 if there is a +/- at the beginning of the string
  611. offset = (str[0] === "+" || str[0] === "-") ? 1 : 0;
  612. for(var i = 0; i < zeroes; i++){
  613. pad += "0";
  614. }
  615. // combine the string and the zeroes
  616. ret = str.substr(0, offset) + pad + str.substr(offset);
  617. return new Sk.builtin.str(ret);
  618. });
  619. Sk.builtin.str.prototype["isdigit"] = new Sk.builtin.func(function (self) {
  620. Sk.builtin.pyCheckArgs("isdigit", arguments, 1, 1);
  621. return new Sk.builtin.bool( /^\d+$/.test(self.v));
  622. });
  623. Sk.builtin.str.prototype["isspace"] = new Sk.builtin.func(function (self) {
  624. Sk.builtin.pyCheckArgs("isspace", arguments, 1, 1);
  625. return new Sk.builtin.bool( /^\s+$/.test(self.v));
  626. });
  627. Sk.builtin.str.prototype["expandtabs"] = new Sk.builtin.func(function (self, tabsize) {
  628. // var input = self.v;
  629. // var expanded = "";
  630. // var split;
  631. // var spacestr = "";
  632. // var spacerem;
  633. var spaces;
  634. var expanded;
  635. Sk.builtin.pyCheckArgs("expandtabs", arguments, 1, 2);
  636. if ((tabsize !== undefined) && ! Sk.builtin.checkInt(tabsize)) {
  637. throw new Sk.builtin.TypeError("integer argument exepected, got " + Sk.abstr.typeName(tabsize));
  638. }
  639. if (tabsize === undefined) {
  640. tabsize = 8;
  641. } else {
  642. tabsize = Sk.builtin.asnum$(tabsize);
  643. }
  644. spaces = (new Array(tabsize + 1)).join(" ");
  645. expanded = self.v.replace(/([^\r\n\t]*)\t/g, function(a, b) {
  646. return b + spaces.slice(b.length % tabsize);
  647. });
  648. return new Sk.builtin.str(expanded);
  649. });
  650. Sk.builtin.str.prototype["swapcase"] = new Sk.builtin.func(function (self) {
  651. var ret;
  652. Sk.builtin.pyCheckArgs("swapcase", arguments, 1, 1);
  653. ret = self.v.replace(/[a-z]/gi, function(c) {
  654. var lc = c.toLowerCase();
  655. return lc === c ? c.toUpperCase() : lc;
  656. });
  657. return new Sk.builtin.str(ret);
  658. });
  659. Sk.builtin.str.prototype["splitlines"] = new Sk.builtin.func(function (self, keepends) {
  660. var data = self.v;
  661. var i = 0;
  662. var j = i;
  663. var selflen = self.v.length;
  664. var strs_w = [];
  665. var ch;
  666. var eol;
  667. var sol = 0;
  668. var slice;
  669. Sk.builtin.pyCheckArgs("splitlines", arguments, 1, 2);
  670. if ((keepends !== undefined) && ! Sk.builtin.checkBool(keepends)) {
  671. throw new Sk.builtin.TypeError("boolean argument expected, got " + Sk.abstr.typeName(keepends));
  672. }
  673. if (keepends === undefined) {
  674. keepends = false;
  675. } else {
  676. keepends = keepends.v;
  677. }
  678. for (i = 0; i < selflen; i ++) {
  679. ch = data.charAt(i);
  680. if (data.charAt(i + 1) === "\n" && ch === "\r") {
  681. eol = i + 2;
  682. slice = data.slice(sol, eol);
  683. if (! keepends) {
  684. slice = slice.replace(/(\r|\n)/g, "");
  685. }
  686. strs_w.push(new Sk.builtin.str(slice));
  687. sol = eol;
  688. } else if ((ch === "\n" && data.charAt(i - 1) !== "\r") || ch === "\r") {
  689. eol = i + 1;
  690. slice = data.slice(sol, eol);
  691. if (! keepends) {
  692. slice = slice.replace(/(\r|\n)/g, "");
  693. }
  694. strs_w.push(new Sk.builtin.str(slice));
  695. sol = eol;
  696. }
  697. }
  698. if (sol < selflen) {
  699. eol = selflen;
  700. slice = data.slice(sol, eol);
  701. if (! keepends) {
  702. slice = slice.replace(/(\r|\n)/g, "");
  703. }
  704. strs_w.push(new Sk.builtin.str(slice));
  705. }
  706. return new Sk.builtin.list(strs_w);
  707. });
  708. Sk.builtin.str.prototype["title"] = new Sk.builtin.func(function (self) {
  709. var ret;
  710. Sk.builtin.pyCheckArgs("title", arguments, 1, 1);
  711. ret = self.v.replace(/[a-z][a-z]*/gi, function(str) {
  712. return str[0].toUpperCase() + str.substr(1).toLowerCase();
  713. });
  714. return new Sk.builtin.str(ret);
  715. });
  716. Sk.builtin.str.prototype["isalpha"] = new Sk.builtin.func(function (self) {
  717. Sk.builtin.pyCheckArgs("isalpha", arguments, 1, 1);
  718. return new Sk.builtin.bool( self.v.length && goog.string.isAlpha(self.v));
  719. });
  720. Sk.builtin.str.prototype["isalnum"] = new Sk.builtin.func(function (self) {
  721. Sk.builtin.pyCheckArgs("isalnum", arguments, 1, 1);
  722. return new Sk.builtin.bool( self.v.length && goog.string.isAlphaNumeric(self.v));
  723. });
  724. // does not account for unicode numeric values
  725. Sk.builtin.str.prototype["isnumeric"] = new Sk.builtin.func(function (self) {
  726. Sk.builtin.pyCheckArgs("isnumeric", arguments, 1, 1);
  727. return new Sk.builtin.bool( self.v.length && goog.string.isNumeric(self.v));
  728. });
  729. Sk.builtin.str.prototype["islower"] = new Sk.builtin.func(function (self) {
  730. Sk.builtin.pyCheckArgs("islower", arguments, 1, 1);
  731. return new Sk.builtin.bool( self.v.length && /[a-z]/.test(self.v) && !/[A-Z]/.test(self.v));
  732. });
  733. Sk.builtin.str.prototype["isupper"] = new Sk.builtin.func(function (self) {
  734. Sk.builtin.pyCheckArgs("isupper", arguments, 1, 1);
  735. return new Sk.builtin.bool( self.v.length && !/[a-z]/.test(self.v) && /[A-Z]/.test(self.v));
  736. });
  737. Sk.builtin.str.prototype["istitle"] = new Sk.builtin.func(function (self) {
  738. // Comparing to str.title() seems the most intuitive thing, but it fails on "",
  739. // Other empty-ish strings with no change.
  740. var input = self.v;
  741. var cased = false;
  742. var previous_is_cased = false;
  743. var pos;
  744. var ch;
  745. Sk.builtin.pyCheckArgs("istitle", arguments, 1, 1);
  746. for (pos = 0; pos < input.length; pos ++) {
  747. ch = input.charAt(pos);
  748. if (! /[a-z]/.test(ch) && /[A-Z]/.test(ch)) {
  749. if (previous_is_cased) {
  750. return new Sk.builtin.bool( false);
  751. }
  752. previous_is_cased = true;
  753. cased = true;
  754. } else if (/[a-z]/.test(ch) && ! /[A-Z]/.test(ch)) {
  755. if (! previous_is_cased) {
  756. return new Sk.builtin.bool( false);
  757. }
  758. cased = true;
  759. } else {
  760. previous_is_cased = false;
  761. }
  762. }
  763. return new Sk.builtin.bool( cased);
  764. });
  765. Sk.builtin.str.prototype.nb$remainder = function (rhs) {
  766. // % format op. rhs can be a value, a tuple, or something with __getitem__ (dict)
  767. // From http://docs.python.org/library/stdtypes.html#string-formatting the
  768. // format looks like:
  769. // 1. The '%' character, which marks the start of the specifier.
  770. // 2. Mapping key (optional), consisting of a parenthesised sequence of characters (for example, (somename)).
  771. // 3. Conversion flags (optional), which affect the result of some conversion types.
  772. // 4. Minimum field width (optional). If specified as an '*' (asterisk), the actual width is read from the next
  773. // element of the tuple in values, and the object to convert comes after the minimum field width and optional
  774. // precision. 5. Precision (optional), given as a '.' (dot) followed by the precision. If specified as '*' (an
  775. // asterisk), the actual width is read from the next element of the tuple in values, and the value to convert comes
  776. // after the precision. 6. Length modifier (optional). 7. Conversion type. length modifier is ignored
  777. var ret;
  778. var replFunc;
  779. var index;
  780. var regex;
  781. if (rhs.constructor !== Sk.builtin.tuple && (rhs.mp$subscript === undefined || rhs.constructor === Sk.builtin.str)) {
  782. rhs = new Sk.builtin.tuple([rhs]);
  783. }
  784. // general approach is to use a regex that matches the format above, and
  785. // do an re.sub with a function as replacement to make the subs.
  786. // 1 2222222222222222 33333333 444444444 5555555555555 66666 777777777777777777
  787. regex = /%(\([a-zA-Z0-9]+\))?([#0 +\-]+)?(\*|[0-9]+)?(\.(\*|[0-9]+))?[hlL]?([diouxXeEfFgGcrs%])/g;
  788. index = 0;
  789. replFunc = function (substring, mappingKey, conversionFlags, fieldWidth, precision, precbody, conversionType) {
  790. var result;
  791. var convName;
  792. var convValue;
  793. var base;
  794. var r;
  795. var mk;
  796. var value;
  797. var handleWidth;
  798. var formatNumber;
  799. var alternateForm;
  800. var precedeWithSign;
  801. var blankBeforePositive;
  802. var leftAdjust;
  803. var zeroPad;
  804. var i;
  805. fieldWidth = Sk.builtin.asnum$(fieldWidth);
  806. precision = Sk.builtin.asnum$(precision);
  807. if (mappingKey === undefined || mappingKey === "") {
  808. i = index++;
  809. } // ff passes '' not undef for some reason
  810. if (precision === "") { // ff passes '' here aswell causing problems with G,g, etc.
  811. precision = undefined;
  812. }
  813. zeroPad = false;
  814. leftAdjust = false;
  815. blankBeforePositive = false;
  816. precedeWithSign = false;
  817. alternateForm = false;
  818. if (conversionFlags) {
  819. if (conversionFlags.indexOf("-") !== -1) {
  820. leftAdjust = true;
  821. } else if (conversionFlags.indexOf("0") !== -1) {
  822. zeroPad = true;
  823. }
  824. if (conversionFlags.indexOf("+") !== -1) {
  825. precedeWithSign = true;
  826. } else if (conversionFlags.indexOf(" ") !== -1) {
  827. blankBeforePositive = true;
  828. }
  829. alternateForm = conversionFlags.indexOf("#") !== -1;
  830. }
  831. if (precision) {
  832. precision = parseInt(precision.substr(1), 10);
  833. }
  834. formatNumber = function (n, base) {
  835. var precZeroPadded;
  836. var prefix;
  837. var didSign;
  838. var neg;
  839. var r;
  840. var j;
  841. base = Sk.builtin.asnum$(base);
  842. neg = false;
  843. didSign = false;
  844. if (typeof n === "number") {
  845. if (n < 0) {
  846. n = -n;
  847. neg = true;
  848. }
  849. r = n.toString(base);
  850. } else if (n instanceof Sk.builtin.float_) {
  851. r = n.str$(base, false);
  852. if (r.length > 2 && r.substr(-2) === ".0") {
  853. r = r.substr(0, r.length - 2);
  854. }
  855. neg = n.nb$isnegative();
  856. } else if (n instanceof Sk.builtin.int_) {
  857. r = n.str$(base, false);
  858. neg = n.nb$isnegative();
  859. } else if (n instanceof Sk.builtin.lng) {
  860. r = n.str$(base, false);
  861. neg = n.nb$isnegative(); // neg = n.size$ < 0; RNL long.js change
  862. }
  863. goog.asserts.assert(r !== undefined, "unhandled number format");
  864. precZeroPadded = false;
  865. if (precision) {
  866. //print("r.length",r.length,"precision",precision);
  867. for (j = r.length; j < precision; ++j) {
  868. r = "0" + r;
  869. precZeroPadded = true;
  870. }
  871. }
  872. prefix = "";
  873. if (neg) {
  874. prefix = "-";
  875. } else if (precedeWithSign) {
  876. prefix = "+" + prefix;
  877. } else if (blankBeforePositive) {
  878. prefix = " " + prefix;
  879. }
  880. if (alternateForm) {
  881. if (base === 16) {
  882. prefix += "0x";
  883. } else if (base === 8 && !precZeroPadded && r !== "0") {
  884. prefix += "0";
  885. }
  886. }
  887. return [prefix, r];
  888. };
  889. handleWidth = function (args) {
  890. var totLen;
  891. var prefix = args[0];
  892. var r = args[1];
  893. var j;
  894. if (fieldWidth) {
  895. fieldWidth = parseInt(fieldWidth, 10);
  896. totLen = r.length + prefix.length;
  897. if (zeroPad) {
  898. for (j = totLen; j < fieldWidth; ++j) {
  899. r = "0" + r;
  900. }
  901. } else if (leftAdjust) {
  902. for (j = totLen; j < fieldWidth; ++j) {
  903. r = r + " ";
  904. }
  905. } else {
  906. for (j = totLen; j < fieldWidth; ++j) {
  907. prefix = " " + prefix;
  908. }
  909. }
  910. }
  911. return prefix + r;
  912. };
  913. //print("Rhs:",rhs, "ctor", rhs.constructor);
  914. if (rhs.constructor === Sk.builtin.tuple) {
  915. value = rhs.v[i];
  916. } else if (rhs.mp$subscript !== undefined && mappingKey !== undefined) {
  917. mk = mappingKey.substring(1, mappingKey.length - 1);
  918. //print("mk",mk);
  919. value = rhs.mp$subscript(new Sk.builtin.str(mk));
  920. } else if (rhs.constructor === Sk.builtin.dict || rhs.constructor === Sk.builtin.list) {
  921. // new case where only one argument is provided
  922. value = rhs;
  923. } else {
  924. throw new Sk.builtin.AttributeError(rhs.tp$name + " instance has no attribute 'mp$subscript'");
  925. }
  926. base = 10;
  927. if (conversionType === "d" || conversionType === "i") {
  928. return handleWidth(formatNumber(value, 10));
  929. } else if (conversionType === "o") {
  930. return handleWidth(formatNumber(value, 8));
  931. } else if (conversionType === "x") {
  932. return handleWidth(formatNumber(value, 16));
  933. } else if (conversionType === "X") {
  934. return handleWidth(formatNumber(value, 16)).toUpperCase();
  935. } else if (conversionType === "f" || conversionType === "F" || conversionType === "e" || conversionType === "E" || conversionType === "g" || conversionType === "G") {
  936. convValue = Sk.builtin.asnum$(value);
  937. if (typeof convValue === "string") {
  938. convValue = Number(convValue);
  939. }
  940. if (convValue === Infinity) {
  941. return "inf";
  942. }
  943. if (convValue === -Infinity) {
  944. return "-inf";
  945. }
  946. if (isNaN(convValue)) {
  947. return "nan";
  948. }
  949. convName = ["toExponential", "toFixed", "toPrecision"]["efg".indexOf(conversionType.toLowerCase())];
  950. if (precision === undefined || precision === "") {
  951. if (conversionType === "e" || conversionType === "E") {
  952. precision = 6;
  953. } else if (conversionType === "f" || conversionType === "F") {
  954. precision = 7;
  955. }
  956. }
  957. result = (convValue)[convName](precision); // possible loose of negative zero sign
  958. // apply sign to negative zeros, floats only!
  959. if(Sk.builtin.checkFloat(value)) {
  960. if(convValue === 0 && 1/convValue === -Infinity) {
  961. result = "-" + result; // add sign for zero
  962. }
  963. }
  964. if ("EFG".indexOf(conversionType) !== -1) {
  965. result = result.toUpperCase();
  966. }
  967. return handleWidth(["", result]);
  968. } else if (conversionType === "c") {
  969. if (typeof value === "number") {
  970. return String.fromCharCode(value);
  971. } else if (value instanceof Sk.builtin.int_) {
  972. return String.fromCharCode(value.v);
  973. } else if (value instanceof Sk.builtin.float_) {
  974. return String.fromCharCode(value.v);
  975. } else if (value instanceof Sk.builtin.lng) {
  976. return String.fromCharCode(value.str$(10, false)[0]);
  977. } else if (value.constructor === Sk.builtin.str) {
  978. return value.v.substr(0, 1);
  979. } else {
  980. throw new Sk.builtin.TypeError("an integer is required");
  981. }
  982. } else if (conversionType === "r") {
  983. r = Sk.builtin.repr(value);
  984. if (precision) {
  985. return r.v.substr(0, precision);
  986. }
  987. return r.v;
  988. } else if (conversionType === "s") {
  989. r = new Sk.builtin.str(value);
  990. if (precision) {
  991. return r.v.substr(0, precision);
  992. }
  993. if(fieldWidth) {
  994. r.v = handleWidth([" ", r.v]);
  995. }
  996. return r.v;
  997. } else if (conversionType === "%") {
  998. return "%";
  999. }
  1000. };
  1001. ret = this.v.replace(regex, replFunc);
  1002. return new Sk.builtin.str(ret);
  1003. };
  1004. /**
  1005. * @constructor
  1006. * @param {Object} obj
  1007. */
  1008. Sk.builtin.str_iter_ = function (obj) {
  1009. if (!(this instanceof Sk.builtin.str_iter_)) {
  1010. return new Sk.builtin.str_iter_(obj);
  1011. }
  1012. this.$index = 0;
  1013. this.$obj = obj.v.slice();
  1014. this.sq$length = this.$obj.length;
  1015. this.tp$iter = this;
  1016. this.tp$iternext = function () {
  1017. if (this.$index >= this.sq$length) {
  1018. return undefined;
  1019. }
  1020. return new Sk.builtin.str(this.$obj.substr(this.$index++, 1));
  1021. };
  1022. this.$r = function () {
  1023. return new Sk.builtin.str("iterator");
  1024. };
  1025. return this;
  1026. };
  1027. Sk.abstr.setUpInheritance("iterator", Sk.builtin.str_iter_, Sk.builtin.object);
  1028. Sk.builtin.str_iter_.prototype.__class__ = Sk.builtin.str_iter_;
  1029. Sk.builtin.str_iter_.prototype.__iter__ = new Sk.builtin.func(function (self) {
  1030. Sk.builtin.pyCheckArgs("__iter__", arguments, 0, 0, true, false);
  1031. return self;
  1032. });
  1033. Sk.builtin.str_iter_.prototype["next"] = new Sk.builtin.func(function (self) {
  1034. var ret = self.tp$iternext();
  1035. if (ret === undefined) {
  1036. throw new Sk.builtin.StopIteration();
  1037. }
  1038. return ret;
  1039. });