source: branches/0.19.x/abcl/src/org/armedbear/lisp/Cons.java

Last change on this file was 12516, checked in by astalla, 15 years ago

Support for user-extensible sequences, adapted from SBCL.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.2 KB
Line 
1/*
2 * Cons.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: Cons.java 12516 2010-03-03 21:05:41Z astalla $
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20 *
21 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38public final class Cons extends LispObject
39{
40  public LispObject car;
41  public LispObject cdr;
42
43  public Cons(LispObject car, LispObject cdr)
44  {
45    this.car = car;
46    this.cdr = cdr;
47    ++count;
48  }
49
50  public Cons(LispObject car)
51  {
52    this.car = car;
53    this.cdr = NIL;
54    ++count;
55  }
56
57  public Cons(String name, LispObject value)
58  {
59    this.car = new SimpleString(name);
60    this.cdr = value != null ? value : NULL_VALUE;
61    ++count;
62  }
63
64  @Override
65  public LispObject typeOf()
66  {
67    return Symbol.CONS;
68  }
69
70  @Override
71  public LispObject classOf()
72  {
73    return BuiltInClass.CONS;
74  }
75
76  @Override
77  public LispObject typep(LispObject typeSpecifier)
78  {
79    if (typeSpecifier instanceof Symbol)
80      {
81        if (typeSpecifier == Symbol.LIST)
82          return T;
83        if (typeSpecifier == Symbol.CONS)
84          return T;
85        if (typeSpecifier == Symbol.SEQUENCE)
86          return T;
87        if (typeSpecifier == T)
88          return T;
89      }
90    else if (typeSpecifier instanceof LispClass)
91      {
92        if (typeSpecifier == BuiltInClass.LIST)
93          return T;
94        if (typeSpecifier == BuiltInClass.CONS)
95          return T;
96        if (typeSpecifier == BuiltInClass.SEQUENCE)
97          return T;
98        if (typeSpecifier == BuiltInClass.CLASS_T)
99          return T;
100      }
101    return NIL;
102  }
103
104  @Override
105  public final boolean constantp()
106  {
107    if (car == Symbol.QUOTE)
108      {
109        if (cdr instanceof Cons)
110          if (((Cons)cdr).cdr == NIL)
111            return true;
112      }
113    return false;
114  }
115
116  @Override
117  public boolean atom()
118  {
119    return false;
120  }
121
122  @Override
123  public LispObject RPLACA(LispObject obj)
124  {
125    car = obj;
126    return this;
127  }
128
129  @Override
130  public LispObject RPLACD(LispObject obj)
131  {
132    cdr = obj;
133    return this;
134  }
135
136  @Override
137  public final LispObject cadr()
138  {
139    return cdr.car();
140  }
141
142  @Override
143  public final LispObject cddr()
144  {
145    return cdr.cdr();
146  }
147
148  @Override
149  public final LispObject caddr()
150  {
151    return cdr.cadr();
152  }
153
154  @Override
155  public LispObject nthcdr(int n)
156  {
157    if (n < 0)
158      return type_error(Fixnum.getInstance(n),
159                             list(Symbol.INTEGER, Fixnum.ZERO));
160    LispObject result = this;
161    for (int i = n; i-- > 0;)
162      {
163        result = result.cdr();
164        if (result == NIL)
165          break;
166      }
167    return result;
168  }
169
170  @Override
171  public final int sxhash()
172  {
173    return computeHash(this, 4);
174  }
175
176  private static final int computeHash(LispObject obj, int depth)
177  {
178    if (obj instanceof Cons)
179      {
180        if (depth > 0)
181          {
182            int n1 = computeHash(((Cons)obj).car, depth - 1);
183            int n2 = computeHash(((Cons)obj).cdr, depth - 1);
184            return n1 ^ n2;
185          }
186        else
187          {
188            // This number comes from SBCL, but since we're not really
189            // using SBCL's SXHASH algorithm, it's probably not optimal.
190            // But who knows?
191            return 261835505;
192          }
193      }
194    else
195      return obj.sxhash();
196  }
197
198  @Override
199  public final int psxhash()
200  {
201    return computeEqualpHash(this, 4);
202  }
203
204  private static final int computeEqualpHash(LispObject obj, int depth)
205  {
206    if (obj instanceof Cons)
207      {
208        if (depth > 0)
209          {
210            int n1 = computeEqualpHash(((Cons)obj).car, depth - 1);
211            int n2 = computeEqualpHash(((Cons)obj).cdr, depth - 1);
212            return n1 ^ n2;
213          }
214        else
215          return 261835505; // See above.
216      }
217    else
218      return obj.psxhash();
219  }
220
221  @Override
222  public final boolean equal(LispObject obj)
223  {
224    if (this == obj)
225      return true;
226    if (obj instanceof Cons)
227      {
228        if (car.equal(((Cons)obj).car) && cdr.equal(((Cons)obj).cdr))
229          return true;
230      }
231    return false;
232  }
233
234  @Override
235  public final boolean equalp(LispObject obj)
236  {
237    if (this == obj)
238      return true;
239    if (obj instanceof Cons)
240      {
241        if (car.equalp(((Cons)obj).car) && cdr.equalp(((Cons)obj).cdr))
242          return true;
243      }
244    return false;
245  }
246
247  @Override
248  public final int length()
249  {
250    int length = 1;
251    LispObject obj = cdr;
252        while (obj != NIL)
253          {
254            ++length;
255            if (obj instanceof Cons) {
256                obj = ((Cons)obj).cdr;
257            } else  type_error(obj, Symbol.LIST);
258          }     
259    return length;
260  }
261
262  @Override
263  public LispObject NTH(int index)
264  {
265    if (index < 0)
266      type_error(Fixnum.getInstance(index), Symbol.UNSIGNED_BYTE);
267    int i = 0;
268    LispObject obj = this;
269    while (true)
270      {
271        if (i == index)
272          return obj.car();
273        obj = obj.cdr();
274        if (obj == NIL)
275          return NIL;
276        ++i;
277      }
278  }
279
280  @Override
281  public LispObject NTH(LispObject arg)
282  {
283    int index;
284    if (arg instanceof Fixnum)
285      {
286        index = ((Fixnum)arg).value;
287      }
288    else
289        {
290        if (arg instanceof Bignum)
291          {
292            // FIXME (when machines have enough memory for it to matter)
293            if (arg.minusp())
294              return type_error(arg, Symbol.UNSIGNED_BYTE);
295            return NIL;
296          }
297        return type_error(arg, Symbol.UNSIGNED_BYTE);
298      }
299    if (index < 0)
300      type_error(arg, Symbol.UNSIGNED_BYTE);
301    int i = 0;
302    LispObject obj = this;
303    while (true)
304      {
305        if (i == index)
306          return obj.car();
307        obj = obj.cdr();
308        if (obj == NIL)
309          return NIL;
310        ++i;
311      }
312  }
313
314  @Override
315  public LispObject elt(int index)
316  {
317    if (index < 0)
318      type_error(Fixnum.getInstance(index), Symbol.UNSIGNED_BYTE);
319    int i = 0;
320    Cons cons = this;
321    while (true)
322      {
323        if (i == index)
324          return cons.car;
325        LispObject conscdr = cons.cdr;
326        if (conscdr instanceof Cons)
327          {
328            cons = (Cons) conscdr;
329          }
330        else
331          {
332            if (conscdr == NIL)
333              {
334                // Index too large.
335                type_error(Fixnum.getInstance(index),
336                                list(Symbol.INTEGER, Fixnum.ZERO,
337                                      Fixnum.getInstance(length() - 1)));
338              }
339            else
340              {
341                // Dotted list.
342                type_error(conscdr, Symbol.LIST);
343              }
344            // Not reached.
345            return NIL;
346          }
347        ++i;
348      }
349  }
350
351  @Override
352  public LispObject reverse()
353  {
354    Cons cons = this;
355    LispObject result = new Cons(cons.car);
356    while (cons.cdr instanceof Cons)
357      {
358        cons = (Cons) cons.cdr;
359        result = new Cons(cons.car, result);
360      }
361    if (cons.cdr != NIL)
362      return type_error(cons.cdr, Symbol.LIST);
363    return result;
364  }
365
366  @Override
367  public final LispObject nreverse()
368  {
369    if (cdr instanceof Cons)
370      {
371        Cons cons = (Cons) cdr;
372        if (cons.cdr instanceof Cons)
373          {
374            Cons cons1 = cons;
375            LispObject list = NIL;
376            do
377              {
378                Cons temp = (Cons) cons.cdr;
379                cons.cdr = list;
380                list = cons;
381                cons = temp;
382              }
383            while (cons.cdr instanceof Cons);
384            if (cons.cdr != NIL)
385              return type_error(cons.cdr, Symbol.LIST);
386            cdr = list;
387            cons1.cdr = cons;
388          }
389        else if (cons.cdr != NIL)
390          return type_error(cons.cdr, Symbol.LIST);
391        LispObject temp = car;
392        car = cons.car;
393        cons.car = temp;
394      }
395    else if (cdr != NIL)
396      return type_error(cdr, Symbol.LIST);
397    return this;
398  }
399
400  @Override
401  public final boolean listp()
402  {
403    return true;
404  }
405
406  @Override
407  public final boolean endp()
408  {
409    return false;
410  }
411
412  @Override
413  public final LispObject[] copyToArray()
414  {
415    final int length = length();
416    LispObject[] array = new LispObject[length];
417    LispObject rest = this;
418    for (int i = 0; i < length; i++)
419      {
420        array[i] = rest.car();
421        rest = rest.cdr();
422      }
423    return array;
424  }
425
426  @Override
427  public LispObject execute()
428  {
429    if (car == Symbol.LAMBDA)
430      {
431        Closure closure = new Closure(this, new Environment());
432        return closure.execute();
433      }
434    return signalExecutionError();
435  }
436
437  @Override
438  public LispObject execute(LispObject arg)
439  {
440    if (car == Symbol.LAMBDA)
441      {
442        Closure closure = new Closure(this, new Environment());
443        return closure.execute(arg);
444      }
445    return signalExecutionError();
446  }
447
448  @Override
449  public LispObject execute(LispObject first, LispObject second)
450
451  {
452    if (car == Symbol.LAMBDA)
453      {
454        Closure closure = new Closure(this, new Environment());
455        return closure.execute(first, second);
456      }
457    return signalExecutionError();
458  }
459
460  @Override
461  public LispObject execute(LispObject first, LispObject second,
462                            LispObject third)
463
464  {
465    if (car == Symbol.LAMBDA)
466      {
467        Closure closure = new Closure(this, new Environment());
468        return closure.execute(first, second, third);
469      }
470    return signalExecutionError();
471  }
472
473  @Override
474  public LispObject execute(LispObject first, LispObject second,
475                            LispObject third, LispObject fourth)
476
477  {
478    if (car == Symbol.LAMBDA)
479      {
480        Closure closure = new Closure(this, new Environment());
481        return closure.execute(first, second, third, fourth);
482      }
483    return signalExecutionError();
484  }
485
486  @Override
487  public LispObject execute(LispObject first, LispObject second,
488                            LispObject third, LispObject fourth,
489                            LispObject fifth)
490
491  {
492    if (car == Symbol.LAMBDA)
493      {
494        Closure closure = new Closure(this, new Environment());
495        return closure.execute(first, second, third, fourth, fifth);
496      }
497    return signalExecutionError();
498  }
499
500  @Override
501  public LispObject execute(LispObject first, LispObject second,
502                            LispObject third, LispObject fourth,
503                            LispObject fifth, LispObject sixth)
504
505  {
506    if (car == Symbol.LAMBDA)
507      {
508        Closure closure = new Closure(this, new Environment());
509        return closure.execute(first, second, third, fourth, fifth, sixth);
510      }
511    return signalExecutionError();
512  }
513
514  @Override
515  public LispObject execute(LispObject first, LispObject second,
516                            LispObject third, LispObject fourth,
517                            LispObject fifth, LispObject sixth,
518                            LispObject seventh)
519
520  {
521    if (car == Symbol.LAMBDA)
522      {
523        Closure closure = new Closure(this, new Environment());
524        return closure.execute(first, second, third, fourth, fifth, sixth,
525                               seventh);
526      }
527    return signalExecutionError();
528  }
529
530  @Override
531  public LispObject execute(LispObject first, LispObject second,
532                            LispObject third, LispObject fourth,
533                            LispObject fifth, LispObject sixth,
534                            LispObject seventh, LispObject eighth)
535
536  {
537    if (car == Symbol.LAMBDA)
538      {
539        Closure closure = new Closure(this, new Environment());
540        return closure.execute(first, second, third, fourth, fifth, sixth,
541                               seventh, eighth);
542      }
543    return signalExecutionError();
544  }
545
546  @Override
547  public LispObject execute(LispObject[] args)
548  {
549    if (car == Symbol.LAMBDA)
550      {
551        Closure closure = new Closure(this, new Environment());
552        return closure.execute(args);
553      }
554    return signalExecutionError();
555  }
556
557  private final LispObject signalExecutionError()
558  {
559    return type_error(this, list(Symbol.OR, Symbol.FUNCTION,
560                                       Symbol.SYMBOL));
561  }
562
563  @Override
564  public String writeToString()
565  {
566    final LispThread thread = LispThread.currentThread();
567    final LispObject printLength = Symbol.PRINT_LENGTH.symbolValue(thread);
568    final int maxLength;
569    if (printLength instanceof Fixnum)
570      maxLength = ((Fixnum)printLength).value;
571    else
572      maxLength = Integer.MAX_VALUE;
573    final LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
574    final int maxLevel;
575    if (printLevel instanceof Fixnum)
576      maxLevel = ((Fixnum)printLevel).value;
577    else
578      maxLevel = Integer.MAX_VALUE;
579    StringBuilder sb = new StringBuilder();
580    if (car == Symbol.QUOTE)
581      {
582        if (cdr instanceof Cons)
583          {
584            // Not a dotted list.
585            if (cdr.cdr() == NIL)
586              {
587                sb.append('\'');
588                sb.append(cdr.car().writeToString());
589                return sb.toString();
590              }
591          }
592      }
593    if (car == Symbol.FUNCTION)
594      {
595        if (cdr instanceof Cons)
596          {
597            // Not a dotted list.
598            if (cdr.cdr() == NIL)
599              {
600                sb.append("#'");
601                sb.append(cdr.car().writeToString());
602                return sb.toString();
603              }
604          }
605      }
606    LispObject currentPrintLevel =
607      _CURRENT_PRINT_LEVEL_.symbolValue(thread);
608    int currentLevel = Fixnum.getValue(currentPrintLevel);
609    if (currentLevel < maxLevel)
610      {
611        final SpecialBindingsMark mark = thread.markSpecialBindings();
612        thread.bindSpecial(_CURRENT_PRINT_LEVEL_, currentPrintLevel.incr());
613        try
614          {
615            int count = 0;
616            boolean truncated = false;
617            sb.append('(');
618            if (count < maxLength)
619              {
620                LispObject p = this;
621                sb.append(p.car().writeToString());
622                ++count;
623                while ((p = p.cdr()) instanceof Cons)
624                  {
625                    sb.append(' ');
626                    if (count < maxLength)
627                      {
628                        sb.append(p.car().writeToString());
629                        ++count;
630                      }
631                    else
632                      {
633                        truncated = true;
634                        break;
635                      }
636                  }
637                if (!truncated && p != NIL)
638                  {
639                    sb.append(" . ");
640                    sb.append(p.writeToString());
641                  }
642              }
643            else
644              truncated = true;
645            if (truncated)
646              sb.append("...");
647            sb.append(')');
648          }
649        finally
650          {
651            thread.resetSpecialBindings(mark);
652          }
653      }
654    else
655      sb.append('#');
656    return sb.toString();
657  }
658
659  // Statistics for TIME.
660  private static long count;
661
662  /*package*/ static long getCount()
663  {
664    return count;
665  }
666
667  /*package*/ static void setCount(long n)
668  {
669    count = n;
670  }
671}
Note: See TracBrowser for help on using the repository browser.