PageRenderTime 45ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/py_list.js

https://bitbucket.org/Grahack/brython-git
JavaScript | 395 lines | 342 code | 44 blank | 9 comment | 104 complexity | 7e3bae87e59d271ea3b10169680f1caa MD5 | raw file
  1. list = function(){
  2. function $list(){
  3. // used for list displays
  4. // different from list : $list(1) is valid (matches [1])
  5. // but list(1) is invalid (integer 1 is not iterable)
  6. var args = new Array()
  7. for(var i=0;i<arguments.length;i++){args.push(arguments[i])}
  8. return new $ListClass(args)
  9. }
  10. function list(){
  11. if(arguments.length===0){return []}
  12. else if(arguments.length>1){
  13. throw TypeError("list() takes at most 1 argument ("+arguments.length+" given)")
  14. }
  15. var res = []
  16. list.__init__(res,arguments[0])
  17. return res
  18. }
  19. list.__add__ = function(self,other){
  20. var res = self.valueOf().concat(other.valueOf())
  21. if(isinstance(self,tuple)){res = tuple.apply(self,res)}
  22. return res
  23. }
  24. list.__class__ = $type
  25. list.__contains__ = function(self,item){
  26. for(var i=0;i<self.length;i++){
  27. try{if(self[i].__eq__(item)){return true}
  28. }catch(err){void(0)}
  29. }
  30. return false
  31. }
  32. list.__delitem__ = function(self,arg){
  33. if(isinstance(arg,int)){
  34. var pos = arg
  35. if(arg<0){pos=self.length+pos}
  36. if(pos>=0 && pos<self.length){
  37. self.splice(pos,1)
  38. return
  39. }
  40. else{throw IndexError('list index out of range')}
  41. } else if(isinstance(arg,slice)) {
  42. var start = arg.start || 0
  43. var stop = arg.stop || self.length
  44. var step = arg.step || 1
  45. if(start<0){start=self.length+start}
  46. if(stop<0){stop=self.length+stop}
  47. var res = [],i=null
  48. if(step>0){
  49. if(stop>start){
  50. for(i=start;i<stop;i+=step){
  51. if(self[i]!==undefined){res.push(i)}
  52. }
  53. }
  54. } else {
  55. if(stop<start){
  56. for(i=start;i>stop;i+=step.value){
  57. if(self[i]!==undefined){res.push(i)}
  58. }
  59. res.reverse() // must be in ascending order
  60. }
  61. }
  62. // delete items from left to right
  63. for(var i=res.length-1;i>=0;i--){
  64. self.splice(res[i],1)
  65. }
  66. return
  67. } else {
  68. throw TypeError('list indices must be integer, not '+str(arg.__class__))
  69. }
  70. }
  71. list.__eq__ = function(self,other){
  72. if(other===undefined){ // compare object "self" to class "list"
  73. return self===list
  74. }
  75. if(isinstance(other,self.__class__)){
  76. if(other.length==self.length){
  77. for(var i=0;i<self.length;i++){
  78. if(!self[i].__eq__(other[i])){return False}
  79. }
  80. return True
  81. }
  82. }
  83. return False
  84. }
  85. list.__getattr__ = function(attr){
  86. switch(attr){
  87. case '__class__':
  88. var res = function(){return list}
  89. res.__str__ = list.__str__
  90. return res
  91. case '__name__':
  92. var res = function(){
  93. throw AttributeError(" 'list' object has no attribute '__name__'")
  94. }
  95. res.__str__ = function(){return 'list'}
  96. return res
  97. default:
  98. return list[attr]
  99. }
  100. }
  101. list.__getitem__ = function(self,arg){
  102. if(isinstance(arg,int)){
  103. var items=self.valueOf()
  104. var pos = arg
  105. if(arg<0){pos=items.length+pos}
  106. if(pos>=0 && pos<items.length){return items[pos]}
  107. else{
  108. throw IndexError('list index out of range')
  109. }
  110. } else if(isinstance(arg,slice)) {
  111. var step = arg.step===None ? 1 : arg.step
  112. if(step>0){
  113. var start = arg.start===None ? 0 : arg.start
  114. var stop = arg.stop===None ? self.__len__() : arg.stop
  115. }else{
  116. var start = arg.start===None ? self.__len__()-1 : arg.start
  117. var stop = arg.stop===None ? 0 : arg.stop
  118. }
  119. if(start<0){start=int(self.length+start)}
  120. if(stop<0){stop=self.length+stop}
  121. var res = [],i=null,items=self.valueOf()
  122. if(step>0){
  123. if(stop<=start){return res}
  124. else {
  125. for(i=start;i<stop;i+=step){
  126. if(items[i]!==undefined){res.push(items[i])}
  127. }
  128. return res
  129. }
  130. } else {
  131. if(stop>=start){return res}
  132. else {
  133. for(i=start;i>=stop;i+=step){
  134. if(items[i]!==undefined){res.push(items[i])}
  135. }
  136. return res
  137. }
  138. }
  139. } else if(isinstance(arg,bool)){
  140. return self.__getitem__(int(arg))
  141. } else {
  142. throw TypeError('list indices must be integer, not '+str(arg.__class__))
  143. }
  144. }
  145. list.__hash__ = function(self){throw TypeError("unhashable type: 'list'")}
  146. list.__in__ = function(self,item){return item.__contains__(self)}
  147. list.__init__ = function(self){
  148. while(self.__len__()>0){self.pop()}
  149. if(arguments.length===1){return}
  150. var arg = arguments[1]
  151. for(var i=0;i<arg.__len__();i++){self.push(arg.__item__(i))}
  152. }
  153. list.__item__ = function(self,i){return self[i]}
  154. list.__len__ = function(self){return self.length}
  155. list.__mul__ = function(self,other){
  156. if(isinstance(other,int)){return other.__mul__(self)}
  157. else{throw TypeError("can't multiply sequence by non-int of type '"+other.__name+"'")}
  158. }
  159. list.__name__ = 'list'
  160. list.__ne__ = function(self,other){return !self.__eq__(other)}
  161. list.__next__ = function(self){
  162. if(self.iter===null){self.iter=0}
  163. if(self.iter<self.valueOf().length){
  164. self.iter++
  165. return self.valueOf()[self.iter-1]
  166. } else {
  167. self.iter = null
  168. throw StopIteration('')
  169. }
  170. }
  171. list.__not_in__ = function(self,item){return !item.__contains__(self)}
  172. list.__setitem__ = function(self,arg,value){
  173. if(isinstance(arg,int)){
  174. var pos = arg
  175. if(arg<0){pos=self.length+pos}
  176. if(pos>=0 && pos<self.length){self[pos]=value}
  177. else{throw IndexError('list index out of range')}
  178. } else if(isinstance(arg,slice)){
  179. var start = arg.start===None ? 0 : arg.start
  180. var stop = arg.stop===None ? self.__len__() : arg.stop
  181. var step = arg.step===None ? 1 : arg.step
  182. if(start<0){start=self.length+start}
  183. if(stop<0){stop=self.length+stop}
  184. self.splice(start,stop-start)
  185. // copy items in a temporary JS array
  186. // otherwise, a[:0]=a fails
  187. if(hasattr(value,'__item__')){
  188. var $temp = list(value)
  189. for(var i=$temp.length-1;i>=0;i--){
  190. self.splice(start,0,$temp[i])
  191. }
  192. }else{
  193. throw TypeError("can only assign an iterable")
  194. }
  195. }else {
  196. throw TypeError('list indices must be integer, not '+str(arg.__class__))
  197. }
  198. }
  199. list.__str__ = function(self){
  200. if(self===undefined){return "<class 'list'>"}
  201. var res = "[",items=self.valueOf()
  202. for(var i=0;i<self.length;i++){
  203. var x = self[i]
  204. if(isinstance(x,str)){res += "'"+x+"'"}
  205. else if(x['__str__']!==undefined){res += x.__str__()}
  206. else{res += x.toString()}
  207. if(i<self.length-1){res += ','}
  208. }
  209. return res+']'
  210. }
  211. list.append = function(self,other){self.push(other)}
  212. list.count = function(self,elt){
  213. var res = 0
  214. for(var i=0;i<self.length;i++){
  215. if(self[i].__eq__(elt)){res++}
  216. }
  217. return res
  218. }
  219. list.extend = function(self,other){
  220. if(arguments.length!=2){throw TypeError(
  221. "extend() takes exactly one argument ("+arguments.length+" given)")}
  222. try{
  223. for(var i=0;i<other.__len__();i++){self.push(other.__item__(i))}
  224. }catch(err){
  225. throw TypeError("object is not iterable")
  226. }
  227. }
  228. list.index = function(self,elt){
  229. for(var i=0;i<self.length;i++){
  230. if(self[i].__eq__(elt)){return i}
  231. }
  232. throw ValueError(str(elt)+" is not in list")
  233. }
  234. list.insert = function(self,i,item){self.splice(i,0,item)}
  235. list.remove = function(self,elt){
  236. for(var i=0;i<self.length;i++){
  237. if(self[i].__eq__(elt)){
  238. self.splice(i,1)
  239. return
  240. }
  241. }
  242. throw ValueError(str(elt)+" is not in list")
  243. }
  244. list.pop = function(self,pos){
  245. if(pos===undefined){ // can't use self.pop() : too much recursion !
  246. var res = self[self.length-1]
  247. self.splice(self.length-1,1)
  248. return res
  249. }else if(arguments.length==2){
  250. if(isinstance(pos,int)){
  251. var res = self[pos]
  252. self.splice(pos,1)
  253. return res
  254. }else{
  255. throw TypeError(pos.__class__+" object cannot be interpreted as an integer")
  256. }
  257. }else{
  258. throw TypeError("pop() takes at most 1 argument ("+(arguments.length-1)+' given)')
  259. }
  260. }
  261. list.reverse = function(self){
  262. for(var i=0;i<parseInt(self.length/2);i++){
  263. var buf = self[i]
  264. self[i] = self[self.length-i-1]
  265. self[self.length-i-1] = buf
  266. }
  267. }
  268. // QuickSort implementation found at http://en.literateprograms.org/Quicksort_(JavaScript)
  269. function $partition(arg,array,begin,end,pivot)
  270. {
  271. var piv=array[pivot];
  272. array.swap(pivot, end-1);
  273. var store=begin;
  274. for(var ix=begin;ix<end-1;++ix) {
  275. if(arg(array[ix]).__le__(arg(piv))) {
  276. array.swap(store, ix);
  277. ++store;
  278. }
  279. }
  280. array.swap(end-1, store);
  281. return store;
  282. }
  283. Array.prototype.swap=function(a, b)
  284. {
  285. var tmp=this[a];
  286. this[a]=this[b];
  287. this[b]=tmp;
  288. }
  289. function $qsort(arg,array, begin, end)
  290. {
  291. if(end-1>begin) {
  292. var pivot=begin+Math.floor(Math.random()*(end-begin));
  293. pivot=$partition(arg,array, begin, end, pivot);
  294. $qsort(arg,array, begin, pivot);
  295. $qsort(arg,array, pivot+1, end);
  296. }
  297. }
  298. list.sort = function(self){
  299. var func=function(x){return x}
  300. var reverse = false
  301. for(var i=1;i<arguments.length;i++){
  302. var arg = arguments[i]
  303. if(isinstance(arg,$Kw)){
  304. if(arg.name==='key'){func=arg.value}
  305. else if(arg.name==='reverse'){reverse=arg.value}
  306. }
  307. }
  308. if(self.length==0){return}
  309. $qsort(func,self,0,self.length)
  310. if(reverse){list.reverse(self)}
  311. }
  312. list.toString = list.__str__
  313. function $ListClass(items){
  314. var x = null,i = null;
  315. this.iter = null
  316. this.__class__ = list
  317. this.items = items // JavaScript array
  318. }
  319. // add Brython attributes to Javascript Array
  320. // set other Array.prototype attributes
  321. for(var attr in list){
  322. if(typeof list[attr]==='function'){list[attr].__str__=function(){return "<list method "+attr+">"}}
  323. var func = (function(attr){
  324. return function(){
  325. var args = [this]
  326. for(var i=0;i<arguments.length;i++){args.push(arguments[i])}
  327. return list[attr].apply(this,args)
  328. }
  329. })(attr)
  330. func.__str__ = (function(attr){
  331. return function(){return "<method-wrapper '"+attr+"' of list object>"}
  332. })(attr)
  333. Array.prototype[attr] = func
  334. }
  335. Array.prototype.__class__ = list
  336. Array.prototype.__getattr__ = function(attr){
  337. if(attr==='__class__'){return this.__class__} // may be list or tuple
  338. if(list[attr]===undefined){
  339. throw AttributeError("'"+this.__class__.__name__+"' object has no attribute '"+attr+"'")
  340. }
  341. var obj = this
  342. var res = function(){
  343. var args = [obj]
  344. for(var i=0;i<arguments.length;i++){args.push(arguments[i])}
  345. return list[attr].apply(obj,args)
  346. }
  347. res.__str__ = function(){return "<built-in method "+attr+" of "+this.__class__.__name__+" object>"}
  348. return res
  349. }
  350. return list
  351. }()