/library/pyjslib.py

http://pyjamas.googlecode.com/ · Python · 699 lines · 593 code · 77 blank · 29 comment · 29 complexity · e222c3da1675663a2d6d425a291eadb5 MD5 · raw file

  1. # Copyright 2006 James Tauber and contributors
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. # iteration from Bob Ippolito's Iteration in JavaScript
  15. # pyjs_extend from Kevin Lindsey's Inteheritance Tutorial (http://www.kevlindev.com/tutorials/javascript/inheritance/)
  16. from __pyjamas__ import JS
  17. JS("""
  18. StopIteration = function () {};
  19. StopIteration.prototype = new Error();
  20. StopIteration.name = 'StopIteration';
  21. StopIteration.message = 'StopIteration';
  22. KeyError = function () {};
  23. KeyError.prototype = new Error();
  24. KeyError.name = 'KeyError';
  25. KeyError.message = 'KeyError';
  26. function pyjslib_String_find(sub, start, end) {
  27. var pos=this.indexOf(sub, start);
  28. if (pyjslib_isUndefined(end)) return pos;
  29. if (pos + sub.length>end) return -1;
  30. return pos;
  31. }
  32. function pyjslib_String_join(data) {
  33. var text="";
  34. if (pyjslib_isArray(data)) {
  35. return data.join(this);
  36. }
  37. else if (pyjslib_isIteratable(data)) {
  38. var iter=data.__iter__();
  39. try {
  40. text+=iter.next();
  41. while (true) {
  42. var item=iter.next();
  43. text+=this + item;
  44. }
  45. }
  46. catch (e) {
  47. if (e != StopIteration) throw e;
  48. }
  49. }
  50. return text;
  51. }
  52. function pyjslib_String_replace(old, replace, count) {
  53. var do_max=false;
  54. var start=0;
  55. var new_str="";
  56. var pos=0;
  57. if (!pyjslib_isString(old)) return this.__replace(old, replace);
  58. if (!pyjslib_isUndefined(count)) do_max=true;
  59. while (start<this.length) {
  60. if (do_max && !count--) break;
  61. pos=this.indexOf(old, start);
  62. if (pos<0) break;
  63. new_str+=this.substring(start, pos) + replace;
  64. start=pos+old.length;
  65. }
  66. if (start<this.length) new_str+=this.substring(start);
  67. return new_str;
  68. }
  69. function pyjslib_String_split(sep, maxsplit) {
  70. var items=new pyjslib_List();
  71. var do_max=false;
  72. var subject=this;
  73. var start=0;
  74. var pos=0;
  75. if (pyjslib_isUndefined(sep) || pyjslib_isNull(sep)) {
  76. sep=" ";
  77. subject=subject.strip();
  78. subject=subject.replace(/\s+/g, sep);
  79. }
  80. else if (!pyjslib_isUndefined(maxsplit)) do_max=true;
  81. while (start<subject.length) {
  82. if (do_max && !maxsplit--) break;
  83. pos=subject.indexOf(sep, start);
  84. if (pos<0) break;
  85. items.append(subject.substring(start, pos));
  86. start=pos+sep.length;
  87. }
  88. if (start<subject.length) items.append(subject.substring(start));
  89. return items;
  90. }
  91. function pyjslib_String_strip(chars) {
  92. return this.lstrip(chars).rstrip(chars);
  93. }
  94. function pyjslib_String_lstrip(chars) {
  95. if (pyjslib_isUndefined(chars)) return this.replace(/^\s+/, "");
  96. return this.replace(new RegExp("^[" + chars + "]+"), "");
  97. }
  98. function pyjslib_String_rstrip(chars) {
  99. if (pyjslib_isUndefined(chars)) return this.replace(/\s+$/, "");
  100. return this.replace(new RegExp("[" + chars + "]+$"), "");
  101. }
  102. function pyjslib_String_startswith(prefix, start) {
  103. if (pyjslib_isUndefined(start)) start = 0;
  104. if (this.substring(start, prefix.length) == prefix) return true;
  105. return false;
  106. }
  107. String.prototype.__getitem__ = String.prototype.charAt;
  108. String.prototype.upper = String.prototype.toUpperCase;
  109. String.prototype.lower = String.prototype.toLowerCase;
  110. String.prototype.find=pyjslib_String_find;
  111. String.prototype.join=pyjslib_String_join;
  112. String.prototype.__replace=String.prototype.replace;
  113. String.prototype.replace=pyjslib_String_replace;
  114. String.prototype.split=pyjslib_String_split;
  115. String.prototype.strip=pyjslib_String_strip;
  116. String.prototype.lstrip=pyjslib_String_lstrip;
  117. String.prototype.rstrip=pyjslib_String_rstrip;
  118. String.prototype.startswith=pyjslib_String_startswith;
  119. var str = String;
  120. var pyjslib_abs = Math.abs;
  121. function pyjs_extend(klass, base) {
  122. function klass_object_inherit() {}
  123. klass_object_inherit.prototype = base.prototype;
  124. klass_object = new klass_object_inherit();
  125. for (var i in base.prototype.__class__) {
  126. v = base.prototype.__class__[i];
  127. if (typeof v == "function" && (v.class_method || v.static_method || v.unbound_method))
  128. {
  129. klass_object[i] = v;
  130. }
  131. }
  132. function klass_inherit() {}
  133. klass_inherit.prototype = klass_object;
  134. klass.prototype = new klass_inherit();
  135. klass_object.constructor = klass;
  136. klass.prototype.__class__ = klass_object;
  137. for (var i in base.prototype) {
  138. v = base.prototype[i];
  139. if (typeof v == "function" && v.instance_method)
  140. {
  141. klass.prototype[i] = v;
  142. }
  143. }
  144. }
  145. function pyjs_kwargs_function_call(func, args)
  146. {
  147. return func.apply(null, func.parse_kwargs.apply(null, args));
  148. }
  149. function pyjs_kwargs_method_call(obj, method_name, args)
  150. {
  151. var method = obj[method_name];
  152. return method.apply(obj, method.parse_kwargs.apply(null, args));
  153. }
  154. """)
  155. class Object:
  156. pass
  157. class Class:
  158. def __init__(self, name):
  159. self.name = name
  160. def __str___(self):
  161. return self.name
  162. def cmp(a,b):
  163. if hasattr(a, "__cmp__"):
  164. return a.__cmp__(b)
  165. elif hasattr(a, "__cmp__"):
  166. return -b.__cmp__(a)
  167. if a > b:
  168. return 1
  169. elif b > a:
  170. return -1
  171. else:
  172. return 0
  173. class List:
  174. def __init__(self, data=None):
  175. JS("""
  176. this.l = [];
  177. if (pyjslib_isArray(data)) {
  178. for (var i=0; i < data.length; i++) {
  179. this.l[i]=data[i];
  180. }
  181. }
  182. else if (pyjslib_isIteratable(data)) {
  183. var iter=data.__iter__();
  184. var i=0;
  185. try {
  186. while (true) {
  187. var item=iter.next();
  188. this.l[i++]=item;
  189. }
  190. }
  191. catch (e) {
  192. if (e != StopIteration) throw e;
  193. }
  194. }
  195. """)
  196. def append(self, item):
  197. JS(""" this.l[this.l.length] = item;""")
  198. def remove(self, value):
  199. JS("""
  200. var index=this.index(value);
  201. if (index<0) return false;
  202. this.l.splice(index, 1);
  203. return true;
  204. """)
  205. def index(self, value, start=0):
  206. JS("""
  207. var length=this.l.length;
  208. for (var i=start; i<length; i++) {
  209. if (this.l[i]==value) {
  210. return i;
  211. }
  212. }
  213. return -1;
  214. """)
  215. def insert(self, index, value):
  216. JS(""" var a = this.l; this.l=a.slice(0, index).concat(value, a.slice(index));""")
  217. def pop(self, index = -1):
  218. JS("""
  219. if (index<0) index = this.l.length + index;
  220. var a = this.l[index];
  221. this.l.splice(index, 1);
  222. return a;
  223. """)
  224. def slice(self, lower, upper):
  225. JS("""
  226. if (upper==null) return pyjslib_List(this.l.slice(lower));
  227. return pyjslib_List(this.l.slice(lower, upper));
  228. """)
  229. def __getitem__(self, index):
  230. JS("""
  231. if (index<0) index = this.l.length + index;
  232. return this.l[index];
  233. """)
  234. def __setitem__(self, index, value):
  235. JS(""" this.l[index]=value;""")
  236. def __delitem__(self, index):
  237. JS(""" this.l.splice(index, 1);""")
  238. def __len__(self):
  239. JS(""" return this.l.length;""")
  240. def __contains__(self, value):
  241. return self.index(value) >= 0
  242. def __iter__(self):
  243. JS("""
  244. var i = 0;
  245. var l = this.l;
  246. return {
  247. 'next': function() {
  248. if (i >= l.length) {
  249. throw StopIteration;
  250. }
  251. return l[i++];
  252. },
  253. '__iter__': function() {
  254. return this;
  255. }
  256. };
  257. """)
  258. def sort(self, compareFunc=None, keyFunc=None, reverse=False):
  259. if not compareFunc:
  260. global cmp
  261. compareFunc = cmp
  262. if keyFunc and reverse:
  263. def thisSort1(a,b):
  264. return -compareFunc(keyFunc(a), keyFunc(b))
  265. self.l.sort(thisSort1)
  266. elif keyFunc:
  267. def thisSort2(a,b):
  268. return compareFunc(keyFunc(a), keyFunc(b))
  269. self.l.sort(thisSort2)
  270. elif reverse:
  271. def thisSort3(a,b):
  272. return -compareFunc(a, b)
  273. self.l.sort(thisSort3)
  274. else:
  275. self.l.sort(compareFunc)
  276. def getArray(self):
  277. """
  278. Access the javascript Array that is used internally by this list
  279. """
  280. return self.l
  281. list = List
  282. class Tuple(List):
  283. def __init__(self, data):
  284. List.__init__(self, data)
  285. tuple = Tuple
  286. class Dict:
  287. def __init__(self, data=None):
  288. JS("""
  289. this.d = {};
  290. if (pyjslib_isArray(data)) {
  291. for (var i in data) {
  292. var item=data[i];
  293. this.d[item[0]]=item[1];
  294. }
  295. }
  296. else if (pyjslib_isIteratable(data)) {
  297. var iter=data.__iter__();
  298. try {
  299. while (true) {
  300. var item=iter.next();
  301. this.d[item.__getitem__(0)]=item.__getitem__(1);
  302. }
  303. }
  304. catch (e) {
  305. if (e != StopIteration) throw e;
  306. }
  307. }
  308. else if (pyjslib_isObject(data)) {
  309. for (var key in data) {
  310. this.d[key]=data[key];
  311. }
  312. }
  313. """)
  314. def __setitem__(self, key, value):
  315. JS(""" this.d[key]=value;""")
  316. def __getitem__(self, key):
  317. JS("""
  318. var value=this.d[key];
  319. // if (pyjslib_isUndefined(value)) throw KeyError;
  320. return value;
  321. """)
  322. def __len__(self):
  323. JS("""
  324. var size=0;
  325. for (var i in this.d) size++;
  326. return size;
  327. """)
  328. def has_key(self, key):
  329. JS("""
  330. if (pyjslib_isUndefined(this.d[key])) return false;
  331. return true;
  332. """)
  333. def __delitem__(self, key):
  334. JS(""" delete this.d[key];""")
  335. def __contains__(self, key):
  336. JS(""" return (pyjslib_isUndefined(this.d[key])) ? false : true;""")
  337. def keys(self):
  338. JS("""
  339. var keys=new pyjslib_List();
  340. for (var key in this.d) keys.append(key);
  341. return keys;
  342. """)
  343. def values(self):
  344. JS("""
  345. var keys=new pyjslib_List();
  346. for (var key in this.d) keys.append(this.d[key]);
  347. return keys;
  348. """)
  349. def __iter__(self):
  350. JS("""
  351. return this.keys().__iter__();
  352. """)
  353. def iterkeys(self):
  354. JS("""
  355. return this.keys().__iter__();
  356. """)
  357. def itervalues(self):
  358. JS("""
  359. return this.values().__iter__();
  360. """)
  361. def iteritems(self):
  362. JS("""
  363. var d = this.d;
  364. var iter=this.keys().__iter__();
  365. return {
  366. '__iter__': function() {
  367. return this;
  368. },
  369. 'next': function() {
  370. var key;
  371. while (key=iter.next()) {
  372. var item=new pyjslib_List();
  373. item.append(key);
  374. item.append(d[key]);
  375. return item;
  376. }
  377. }
  378. };
  379. """)
  380. def setdefault(self, key, default_value):
  381. if not self.has_key(key):
  382. self[key] = default_value
  383. def get(self, key, default_value=None):
  384. value = self[key]
  385. JS("if(pyjslib_isUndefined(value)) { value = default_value; }")
  386. return value;
  387. def update(self, d):
  388. for k,v in d.iteritems():
  389. self[k] = v
  390. def getObject(self):
  391. """
  392. Return the javascript Object which this class uses to store dictionary keys and values
  393. """
  394. return self.d
  395. dict = Dict
  396. # taken from mochikit: range( [start,] stop[, step] )
  397. def range():
  398. JS("""
  399. var start = 0;
  400. var stop = 0;
  401. var step = 1;
  402. if (arguments.length == 2) {
  403. start = arguments[0];
  404. stop = arguments[1];
  405. }
  406. else if (arguments.length == 3) {
  407. start = arguments[0];
  408. stop = arguments[1];
  409. step = arguments[2];
  410. }
  411. else if (arguments.length>0) stop = arguments[0];
  412. return {
  413. 'next': function() {
  414. if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) throw StopIteration;
  415. var rval = start;
  416. start += step;
  417. return rval;
  418. },
  419. '__iter__': function() {
  420. return this;
  421. }
  422. }
  423. """)
  424. def slice(object, lower, upper):
  425. JS("""
  426. if (pyjslib_isString(object)) {
  427. if (pyjslib_isNull(upper)) upper=object.length;
  428. return object.substring(lower, upper);
  429. }
  430. if (pyjslib_isObject(object) && object.slice) return object.slice(lower, upper);
  431. return null;
  432. """)
  433. def str(text):
  434. JS("""
  435. return String(text);
  436. """)
  437. def int(text, radix=0):
  438. JS("""
  439. return parseInt(text, radix);
  440. """)
  441. def len(object):
  442. JS("""
  443. if (object==null) return 0;
  444. if (pyjslib_isObject(object) && object.__len__) return object.__len__();
  445. return object.length;
  446. """)
  447. def getattr(obj, method):
  448. JS("""
  449. if (!pyjslib_isObject(obj)) return null;
  450. if (!pyjslib_isFunction(obj[method])) return obj[method];
  451. return function() {
  452. obj[method].call(obj);
  453. }
  454. """)
  455. def hasattr(obj, method):
  456. JS("""
  457. if (!pyjslib_isObject(obj)) return false;
  458. if (pyjslib_isUndefined(obj[method])) return false;
  459. return true;
  460. """)
  461. def dir(obj):
  462. JS("""
  463. var properties=new pyjslib_List();
  464. for (property in obj) properties.append(property);
  465. return properties;
  466. """)
  467. def filter(obj, method, sequence=None):
  468. # object context is LOST when a method is passed, hence object must be passed separately
  469. # to emulate python behaviour, should generate this code inline rather than as a function call
  470. items = []
  471. if sequence == None:
  472. sequence = method
  473. method = obj
  474. for item in sequence:
  475. if method(item):
  476. items.append(item)
  477. else:
  478. for item in sequence:
  479. if method.call(obj, item):
  480. items.append(item)
  481. return items
  482. def map(obj, method, sequence=None):
  483. items = []
  484. if sequence == None:
  485. sequence = method
  486. method = obj
  487. for item in sequence:
  488. items.append(method(item))
  489. else:
  490. for item in sequence:
  491. items.append(method.call(obj, item))
  492. return items
  493. next_hash_id = 0
  494. def hash(obj):
  495. JS("""
  496. if (obj == null) return null;
  497. if (obj.$H) return obj.$H;
  498. if (obj.__hash__) return obj.__hash__();
  499. if (obj.constructor == String || obj.constructor == Number || obj.constructor == Date) return obj;
  500. obj.$H = ++pyjslib_next_hash_id;
  501. return obj.$H;
  502. """)
  503. # type functions from Douglas Crockford's Remedial Javascript: http://www.crockford.com/javascript/remedial.html
  504. def isObject(a):
  505. JS("""
  506. return (a && typeof a == 'object') || pyjslib_isFunction(a);
  507. """)
  508. def isFunction(a):
  509. JS("""
  510. return typeof a == 'function';
  511. """)
  512. def isString(a):
  513. JS("""
  514. return typeof a == 'string';
  515. """)
  516. def isNull(a):
  517. JS("""
  518. return typeof a == 'object' && !a;
  519. """)
  520. def isArray(a):
  521. JS("""
  522. return pyjslib_isObject(a) && a.constructor == Array;
  523. """)
  524. def isUndefined(a):
  525. JS("""
  526. return typeof a == 'undefined';
  527. """)
  528. def isIteratable(a):
  529. JS("""
  530. return pyjslib_isObject(a) && a.__iter__;
  531. """)
  532. def isNumber(a):
  533. JS("""
  534. return typeof a == 'number' && isFinite(a);
  535. """)
  536. def toJSObjects(x):
  537. """
  538. Convert the pyjs pythonic List and Dict objects into javascript Object and Array
  539. objects, recursively.
  540. """
  541. result = x
  542. if isObject(x) and x.__class__:
  543. if x.__class__ == 'pyjslib_Dict':
  544. return toJSObjects(x.d)
  545. elif x.__class__ == 'pyjslib_List':
  546. return toJSObjects(x.l)
  547. if isObject(x):
  548. JS("""
  549. result = {};
  550. for(var k in x) {
  551. var v = x[k];
  552. var tv = pyjslib_toJSObjects(v)
  553. result[k] = tv;
  554. }
  555. """)
  556. if isArray(x):
  557. JS("""
  558. result = [];
  559. for(var k=0; k < x.length; k++) {
  560. var v = x[k];
  561. var tv = pyjslib_toJSObjects(v);
  562. result.push(tv);
  563. }
  564. """)
  565. return result
  566. def printFunc(objs):
  567. JS("""
  568. var s = "";
  569. for(var i=0; i < objs.length; i++) {
  570. if(s != "") s += " ";
  571. s += objs[i];
  572. }
  573. console.debug(s)
  574. """)