Source code: com/memoire/foo/FooList.java
1 /**
2 * @modification $Date: 2002/12/16 18:56:26 $
3 * @statut unstable
4 * @file FooList.java
5 * @version 0.08
6 * @author Guillaume Desnoix
7 * @email guillaume@desnoix.com
8 * @license GNU General Public License 2 (GPL2)
9 * @copyright 1999-2001 Guillaume Desnoix
10 */
11
12 package com.memoire.foo;
13 import com.memoire.foo.*;
14
15 import java.lang.reflect.*;
16 import java.util.*;
17
18 public class FooList
19 implements FooEval
20 {
21 private static FooCategory pkg_=null;
22
23 public static final FooCategory init()
24 {
25 if(pkg_==null)
26 {
27 pkg_=FooCategory.create(FooList.class);
28 pkg_.alias("&list");
29
30 pkg_.setMessage("#" ,FooList.class,"length");
31 pkg_.setMessage("+" ,FooList.class,"append");
32 pkg_.setMessage("[]" ,FooList.class,"extractII");
33 pkg_.setMessage("[[" ,FooList.class,"extractIX");
34 pkg_.setMessage("]]" ,FooList.class,"extractXI");
35 pkg_.setMessage("][" ,FooList.class,"extractXX");
36 //pkg_.setMessage("]" ,FooList.class,"brkMsg2");
37 pkg_.setMessage("=" ,FooList.class,"setValue");
38 pkg_.setMessage(":" ,FooList.class,"local",false);
39 pkg_.setMessage("each",FooList.class,"each",false);
40 //pkg_.setMessage("==" ,FooList.class,"equals");
41 }
42
43 return pkg_;
44 }
45
46 private Vector vector_;
47 String origin_;
48 int lineno_;
49
50 public FooList()
51 {
52 vector_=new Vector(0);
53 }
54
55 /*
56 public FooList(Object[] _array)
57 {
58 vector_=new Vector(_array.length,1);
59 for(int i=0;i<_array.length;i++)
60 add(_array[i]);
61 }
62 */
63
64 // not public
65 void add(Object _o)
66 {
67 if(_o!=FooVoid.VOID)
68 {
69 if(_o==null) _o=FooNull.NULL;
70 vector_.addElement(_o);
71 }
72 }
73
74 public Object at(int _i)
75 {
76 Object r=null;
77 if((_i>=0)&&(_i<vector_.size()))
78 r=vector_.elementAt(_i);
79 if(r==FooNull.NULL) r=null;
80 return r;
81 }
82
83 public int length()
84 {
85 return vector_.size();
86 }
87
88 public boolean empty()
89 {
90 return (vector_.size()==0);
91 }
92
93 public boolean contains(Object _o)
94 {
95 return vector_.contains(_o);
96 }
97
98 public int hashCode()
99 {
100 return toString().hashCode();
101 }
102
103 public boolean equals(Object _o)
104 {
105 if(_o==this) return true;
106 if(_o==null) return false;
107
108 //System.err.println("LIST-EQUALS:"+this+"=="+_o);
109 boolean r=(_o instanceof FooList);
110
111 if(r)
112 {
113 FooList o=(FooList)_o;
114 int l=length();
115
116 r=(l==o.length());
117
118 if(r)
119 {
120 for(int i=0;i<l;i++)
121 {
122 Object a=at(i);
123 Object b=o.at(i);
124 /*
125 FooList call=new FooList();
126 call.add(a);
127 call.add(FooSymbol.create("=="));
128 call.add(b);
129 r=FooLib.booleanValue(call.eval());
130 System.err.println("CALL="+call);
131 */
132 r=FooObject.eqMsg(a,b).booleanValue();
133 if(!r) break;
134 }
135 }
136 }
137
138 return r;
139 }
140
141 public Object[] array()
142 {
143 // return vector_.toArray();
144
145 int l=length();
146 Object[] r=new Object[l];
147
148 for(int i=0;i<l;i++) r[i]=at(i);
149 return r;
150 }
151
152 public Object convert(Class _c)
153 {
154 int l=length();
155 Object r=Array.newInstance(_c,l);
156
157 for(int i=0;i<l;i++)
158 Array.set(r,i,at(i));
159
160 return r;
161 }
162
163 public Object eval()
164 {
165 if(empty()) return this;
166
167 Object r=null;
168
169 Object old_call3 =FooSymbol.get_local("[call-3]");
170 Object old_call2 =FooSymbol.get_local("[call-2]");
171 Object old_call1 =FooSymbol.get_local("[call-1]");
172 Object old_caller=FooSymbol.get_local("[caller]");
173 Object old_agent =FooSymbol.get_local("[agent]" );
174
175 FooSymbol.create_local("[call-3]",old_call2);
176 FooSymbol.create_local("[call-2]",old_call1);
177 FooSymbol.create_local("[call-1]",this);
178
179 Object c=FooNull.NULL;
180 Object a=null;
181
182 if( (old_call1 instanceof FooList)
183 &&!((FooList)old_call1).empty())
184 c=((FooList)old_call1).at(0);
185
186 if( (c!=null)
187 &&(FooCategory.create(c.getClass()).getMessage("[send]")!=null))
188 a=c;
189
190 FooSymbol.create_local("[caller]",c);
191 if(a!=null) FooSymbol.create_local("[agent]",a);
192
193 r=eval1();
194
195 FooSymbol.forget_local("[call-3]",old_call3);
196 FooSymbol.forget_local("[call-2]",old_call2);
197 FooSymbol.forget_local("[call-1]",old_call1);
198 FooSymbol.forget_local("[caller]",old_caller);
199 if(a!=null) FooSymbol.forget_local("[agent]" ,old_agent);
200
201 return r;
202 }
203
204 private Object eval1()
205 {
206 if(empty())
207 throw new RuntimeException
208 ("empty list:"+FooLib.toString(this));
209
210 Object o=FooLib.eval(at(0));
211
212 if(o==null) o=FooNull.NULL;
213 /*
214 if(o==null)
215 throw new RuntimeException
216 ("object is null:"+FooLib.toString(at(0)));
217 */
218
219 if(length()==1)
220 throw new RuntimeException
221 ("no message to eval:"+FooLib.toString(this));
222
223 Object z=at(1);
224 if(z instanceof FooComma)
225 z=((FooComma)z).eval();
226
227 String s=z.toString();
228 Object r=null;
229 Object e=this;
230
231 Object a=FooSymbol.get_local("[agent]" );
232 Object c=FooSymbol.get_local("[caller]");
233
234 /*
235 System.err.println("$$$ call2="+FooLib.toSource(FooSymbol.get_local("[call-2]")));
236 System.err.println("$$$ call1="+FooLib.toSource(FooSymbol.get_local("[call-1]")));
237 System.err.println("$$$ this ="+FooLib.toSource(this));
238 System.err.println("$$$ a ="+FooLib.toSource(a));
239 System.err.println("$$$ c ="+FooLib.toSource(c));
240 System.err.println("$$$ o ="+FooLib.toSource(o));
241 */
242
243 Object old_meta_send=FooSymbol.get_local("[meta-send]");
244 Object old_meta_recv=FooSymbol.get_local("[meta-recv]");
245
246 if( !Boolean.TRUE.equals(old_meta_send)
247 &&!Boolean.TRUE.equals(old_meta_recv)
248 &&(a!=null)
249 &&(a!=o))
250 {
251 FooList l=new FooList();
252 l.add(a);
253 l.add(FooSymbol.create("[send]"));
254 l.add(this);
255 FooSymbol.create_local("[meta-send]",Boolean.TRUE);
256 e=l.eval();
257 FooSymbol.forget_local("[meta-send]",old_meta_send);
258 }
259
260 if( !Boolean.TRUE.equals(old_meta_send)
261 &&(c!=o)
262 &&(FooCategory.create(o.getClass()).getMessage("[receive]")!=null)
263 &&!"[receive]".equals(s))
264 {
265 FooList l=new FooList();
266 l.add(o);
267 l.add(FooSymbol.create("[receive]"));
268 l.add(this);
269 FooSymbol.create_local("[meta-recv]",Boolean.TRUE);
270 e=l.eval();
271 FooSymbol.forget_local("[meta-recv]",old_meta_recv);
272 }
273
274 /*
275 System.err.println("T="+this);
276 System.err.println("E="+e);
277 System.err.println("=="+equals(e));
278 */
279
280 if(equals(e)) r=eval0(o,s);
281 else r=FooLib.eval(e);
282
283 return r;
284 }
285
286 private Object eval0(Object _o,String _s)
287 {
288 Object r=null;
289 Object o=_o;
290 String s=_s;
291 int l=length();
292
293 Object[] p=new Object[l-2];
294 for(int i=2;i<l;i++)
295 p[i-2]=at(i);
296
297 Method m=null;
298 Class c=o.getClass();
299
300 boolean isClass =false;
301 boolean evalArgs=true;
302
303 //System.err.println("Object : "+o);
304 //System.err.println("Message: "+s);
305 //System.err.println("Params#: "+p.length);
306
307 Class d=c;
308 while(d!=null)
309 {
310 FooCategory fd=FooCategory.create(d);
311 //System.err.println(" - "+d+" "+fd);
312 if(fd!=null)
313 {
314 FooMessage msg=fd.getMessage(s);
315 if(msg!=null)
316 {
317 Object obj=msg.getObject();
318 if(obj instanceof Method)
319 {
320 m=(Method)obj;
321 evalArgs=msg.shouldEvalArgs();
322 break;
323 }
324 if(obj instanceof Field)
325 {
326 if(msg.shouldEvalArgs())
327 for(int i=0;i<p.length;i++)
328 p[i]=FooLib.eval(p[i]);
329 return FooLib.invokeField(o,(Field)obj,p);
330 }
331 if(obj instanceof Object[])
332 {
333 if(msg.shouldEvalArgs())
334 for(int i=0;i<p.length;i++)
335 p[i]=FooLib.eval(p[i]);
336 return FooLib.invokeBlock(o,(Object[])obj,p,msg.getArgNames());
337 }
338 if(obj instanceof String)
339 {
340 d=c;
341 s=(String)obj;
342 if(msg.shouldEvalArgs())
343 for(int i=0;i<p.length;i++)
344 p[i]=FooLib.eval(p[i]);
345 continue;
346 }
347 }
348 }
349 d=FooLib.getSuperclass(d);
350 }
351
352 if((m==null)&&(o instanceof Class))
353 {
354 Constructor n=FooLib.getConstructor((Class)o,s,p.length);
355 if(n!=null)
356 {
357 if(evalArgs)
358 for(int i=0;i<p.length;i++)
359 p[i]=FooLib.eval(p[i]);
360 return FooLib.invokeConstructor(n,p);
361 }
362 }
363
364 if(m==null)
365 {
366 m=FooLib.getMethod(c,s,p.length);
367 if((m==null)&&(o instanceof Class))
368 {
369 m=FooLib.getMethod((Class)o,s,p.length);
370 isClass=(m!=null);
371 }
372 }
373
374 if(m==null)
375 {
376 Field f=FooLib.getField(c,s);
377 if((f==null)&&(o instanceof Class))
378 f=FooLib.getField((Class)o,s);
379
380 // System.out.println("Field: "+f);
381 if(f!=null)
382 {
383 if(evalArgs)
384 for(int i=0;i<p.length;i++)
385 p[i]=FooLib.eval(p[i]);
386 return FooLib.invokeField(o,f,p);
387 }
388 }
389
390 if(m==null)
391 throw new RuntimeException
392 ("message "+s+" can not be found for "+
393 FooLib.getClassName(o.getClass()));
394
395 if(evalArgs)
396 for(int i=0;i<p.length;i++)
397 p[i]=FooLib.eval(p[i]);
398
399 //System.out.println(""+m);
400
401 if(!isClass)
402 {
403 boolean isStatic = ((m.getModifiers() & Modifier.STATIC) != 0);
404 if(isStatic)
405 {
406 Object[] q=new Object[p.length+1];
407 for(int i=0;i<p.length;i++) q[i+1]=p[i];
408 q[0]=o;
409 o=null;
410 p=q;
411 }
412 }
413
414 r=FooLib.invokeMethod(o,m,p);
415 //System.out.println("--> "+r);
416 return r;
417 }
418
419 public String toString()
420 {
421 StringBuffer r=new StringBuffer();
422 r.append('(');
423 for(int i=0;i<length();i++)
424 {
425 if(i>0) r.append(' ');
426 Object o=at(i);
427 if(o==null) r.append(o);
428 else if(o.getClass().isArray()) r.append(FooLib.stringValue(o));
429 else r.append(o);
430 }
431 r.append(')');
432 return r.toString();
433 }
434
435 public String toSource()
436 {
437 StringBuffer r=new StringBuffer();
438 r.append('(');
439 for(int i=0;i<length();i++)
440 {
441 if(i>0) r.append(' ');
442 r.append(FooLib.toSource(at(i)));
443 }
444 r.append(')');
445 return r.toString();
446 }
447
448 public Object car()
449 {
450 return at(0);
451 }
452
453 public FooList cdr()
454 {
455 FooList r=new FooList();
456 for(int i=1;i<length();i++) r.add(at(i));
457 return r;
458 }
459
460 public FooList append(Object[] _n)
461 {
462 FooList r=new FooList();
463 for(int i=0;i<length() ;i++) r.add(at(i));
464 for(int i=0;i<_n.length;i++) r.add(_n[i]);
465 return r;
466 }
467
468 /*
469 public FooList map(Object _msg)
470 {
471 FooList r=new FooList();
472 for(int i=0;i<length();i++)
473 {
474 Object o=at(i);
475 FooList call=new FooList().append(new Object[] { o,_msg });
476 r.add(call.eval());
477 }
478 return r;
479 }
480 */
481
482 public FooList map(Object[] _o)
483 {
484 FooList r=new FooList();
485 for(int i=0;i<length();i++)
486 {
487 Object o=at(i);
488 FooList call=new FooList();
489 call=call.append(new Object[] { new FooQuote(o) });
490 call=call.append(_o);
491 r.add(call.eval());
492 }
493 return r;
494 }
495
496 public FooList filter(Object[] _o)
497 {
498 FooList r=new FooList();
499 for(int i=0;i<length();i++)
500 {
501 Object o=at(i);
502 FooList call=new FooList();
503 call=call.append(new Object[] { o });
504 call=call.append(_o);
505 Object b=call.eval();
506 if(FooLib.booleanValue(b)) r.add(o);
507 }
508 return r;
509 }
510
511 public FooList each(Object[] _o)
512 {
513 FooLib.checkClassArgument(FooSymbol.class,_o[0],1);
514
515 FooList r =new FooList();
516 String name=((FooSymbol)_o[0]).getName();
517
518 for(int i=0;i<length();i++)
519 {
520 Object old=FooSymbol.get_local(name);
521 FooSymbol.create_local(name,at(i));
522 r.add(FooLib.evalBlock(_o,1));
523 FooSymbol.forget_local(name,old);
524 }
525
526 return r;
527 }
528
529 public FooList slice(int _begin, int _end)
530 {
531 FooList r=new FooList();
532 for(int i=Math.max(0,_begin);
533 i<Math.min(length(),_end);i++)
534 r.add(at(i));
535 return r;
536 }
537
538 public Object extractII(Object[] _o)
539 {
540 Object r=null;
541
542 switch(_o.length)
543 {
544 case 1:
545 FooLib.checkClassArgument(Number.class,_o[0],1);
546 r=at(((Number)_o[0]).intValue());
547 break;
548 case 2:
549 FooLib.checkClassArgument(Number.class,_o[0],1);
550 FooLib.checkClassArgument(Number.class,_o[1],2);
551 r=slice(((Number)_o[0]).intValue()+0,
552 ((Number)_o[1]).intValue()+1);
553 break;
554 default:
555 FooLib.checkNumberArgument(1,_o.length);
556 break;
557 }
558
559 return r;
560 }
561
562 public Object extractIX(Object[] _o)
563 {
564 Object r=null;
565
566 switch(_o.length)
567 {
568 case 2:
569 FooLib.checkClassArgument(Number.class,_o[0],1);
570 FooLib.checkClassArgument(Number.class,_o[1],2);
571 r=slice(((Number)_o[0]).intValue()+0,
572 ((Number)_o[1]).intValue()+0);
573 break;
574 default:
575 FooLib.checkNumberArgument(2,_o.length);
576 break;
577 }
578
579 return r;
580 }
581
582 public Object extractXI(Object[] _o)
583 {
584 Object r=null;
585
586 switch(_o.length)
587 {
588 case 2:
589 FooLib.checkClassArgument(Number.class,_o[0],1);
590 FooLib.checkClassArgument(Number.class,_o[1],2);
591 r=slice(((Number)_o[0]).intValue()+1,
592 ((Number)_o[1]).intValue()+1);
593 break;
594 default:
595 FooLib.checkNumberArgument(2,_o.length);
596 break;
597 }
598
599 return r;
600 }
601
602 public Object extractXX(Object[] _o)
603 {
604 Object r=null;
605
606 switch(_o.length)
607 {
608 case 2:
609 FooLib.checkClassArgument(Number.class,_o[0],1);
610 FooLib.checkClassArgument(Number.class,_o[1],2);
611 r=slice(((Number)_o[0]).intValue()+1,
612 ((Number)_o[1]).intValue()+0);
613 break;
614 default:
615 FooLib.checkNumberArgument(2,_o.length);
616 break;
617 }
618
619 return r;
620 }
621
622 /*
623 public Object brkMsg(Object[] _o)
624 {
625 Object r=null;
626
627 switch(_o.length)
628 {
629 case 0:
630 case 1:
631 FooLib.checkNumberArgument(2,_o.length);
632 break;
633 case 2:
634 FooLib.checkClassArgument(Number.class,_o[0],1);
635 FooLib.checkValueArgument("]",_o[1],2);
636 r=at(((Number)_o[0]).intValue());
637 break;
638 case 3:
639 FooLib.checkClassArgument(Number.class,_o[0],1);
640 FooLib.checkClassArgument(Number.class,_o[1],2);
641 FooLib.checkBracket(_o[2],3);
642 r=slice(((Number)_o[0]).intValue(),
643 ((Number)_o[1]).intValue()+
644 ("]".equals(_o[2]) ? 1 : 0));
645 break;
646 default:
647 FooLib.checkNumberArgument(4,_o.length);
648 break;
649 }
650
651 return r;
652 }
653 */
654
655 /*
656 public Object brkMsg2(Object[] _o)
657 {
658 Object r=null;
659
660 switch(_o.length)
661 {
662 case 3:
663 FooLib.checkClassArgument(Number.class,_o[0],1);
664 FooLib.checkClassArgument(Number.class,_o[1],2);
665 FooLib.checkBracket(_o[2],3);
666 r=slice(((Number)_o[0]).intValue()+1,
667 ((Number)_o[1]).intValue()+
668 ("]".equals(_o[2]) ? 1 : 0));
669 break;
670 default:
671 FooLib.checkNumberArgument(4,_o.length);
672 break;
673 }
674
675 return r;
676 }
677 */
678
679 public void setValue(FooList _list)
680 {
681 int l=_list.length();
682 Object[] r=new Object[l];
683 for(int i=0;i<l;i++)
684 r[i]=FooLib.eval(_list.at(i));
685
686 int n=length();
687 for(int i=0;i<n;i++)
688 {
689 Object s=at(i);
690 if(s==null) continue;
691 if(!(s instanceof FooSymbol))
692 throw new RuntimeException
693 ("not a symbol:"+FooLib.toString(s));
694 ((FooSymbol)s).setValue
695 ((i<r.length) ? r[i] : null);
696 }
697 }
698
699 public Object local(Object[] _body)
700 {
701 Object r=null;
702 Object[] names=array();
703 int l=names.length;
704 Object[] old_vars=new Object[l];
705
706 for(int i=0;i<l;i++)
707 {
708 Object s=names[i];
709 if(!(s instanceof FooSymbol))
710 throw new RuntimeException
711 ("not a symbol:"+FooLib.toString(s));
712 String n=s.toString();
713 old_vars[i]=FooSymbol.get_local(n);
714 FooSymbol.create_local(n,null);
715 }
716
717 r=FooLib.evalBlock(_body,0);
718
719 for(int i=0;i<l;i++)
720 {
721 Object s=names[i];
722 String n=s.toString();
723 FooSymbol.forget_local(n,old_vars[i]);
724 }
725
726 return r;
727 }
728
729 // BROKEN???
730 public FooList order()
731 {
732 Hashtable t=new Hashtable();
733 int l=length();
734 int i;
735
736 for(i=0;i<l;i++)
737 {
738 Object o=at(i);
739 Integer j=(Integer)t.get(o);
740 if(j==null) j=new Integer(1);
741 else j=new Integer(j.intValue()+1);
742 t.put(o,j);
743 }
744
745 l=t.size();
746 int[] n=new int[l];
747 Object[] v=new Object[l];
748 Enumeration e=t.keys();
749 i=0;
750 while(e.hasMoreElements())
751 {
752 Object o=e.nextElement();
753 v[i]=o;
754 n[i]=((Integer)t.get(o)).intValue();
755 i++;
756 }
757
758 for(i=1;i<l;i++)
759 {
760 if(n[i-1]<n[i])
761 {
762 int m=n[i-1]; n[i-1]=n[i]; n[i]=m;
763 Object w=v[i-1]; v[i-1]=v[i]; v[i]=w;
764 i--;
765 if(i>=0) i--;
766 }
767 }
768
769 return new FooList().append(v);
770 }
771 }