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

Last change on this file was 12254, checked in by ehuelsmann, 16 years ago

Remove 'throws ConditionThrowable?' method annotations:

it's an unchecked exception now, so no need to declare it thrown.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 16.7 KB
Line 
1/*
2 * Cons.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: Cons.java 12254 2009-11-06 20:07:54Z ehuelsmann $
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
36public final class Cons extends LispObject
37{
38  public LispObject car;
39  public LispObject cdr;
40
41  public Cons(LispObject car, LispObject cdr)
42  {
43    this.car = car;
44    this.cdr = cdr;
45    ++count;
46  }
47
48  public Cons(LispObject car)
49  {
50    this.car = car;
51    this.cdr = NIL;
52    ++count;
53  }
54
55  public Cons(String name, LispObject value)
56  {
57    this.car = new SimpleString(name);
58    this.cdr = value != null ? value : NULL_VALUE;
59    ++count;
60  }
61
62  @Override
63  public LispObject typeOf()
64  {
65    return Symbol.CONS;
66  }
67
68  @Override
69  public LispObject classOf()
70  {
71    return BuiltInClass.CONS;
72  }
73
74  @Override
75  public LispObject typep(LispObject typeSpecifier)
76  {
77    if (typeSpecifier instanceof Symbol)
78      {
79        if (typeSpecifier == Symbol.LIST)
80          return T;
81        if (typeSpecifier == Symbol.CONS)
82          return T;
83        if (typeSpecifier == Symbol.SEQUENCE)
84          return T;
85        if (typeSpecifier == T)
86          return T;
87      }
88    else if (typeSpecifier instanceof BuiltInClass)
89      {
90        if (typeSpecifier == BuiltInClass.LIST)
91          return T;
92        if (typeSpecifier == BuiltInClass.CONS)
93          return T;
94        if (typeSpecifier == BuiltInClass.SEQUENCE)
95          return T;
96        if (typeSpecifier == BuiltInClass.CLASS_T)
97          return T;
98      }
99    return NIL;
100  }
101
102  @Override
103  public final boolean constantp()
104  {
105    if (car == Symbol.QUOTE)
106      {
107        if (cdr instanceof Cons)
108          if (((Cons)cdr).cdr == NIL)
109            return true;
110      }
111    return false;
112  }
113
114  @Override
115  public LispObject ATOM()
116  {
117    return NIL;
118  }
119
120  @Override
121  public boolean atom()
122  {
123    return false;
124  }
125
126  @Override
127  public final LispObject car()
128  {
129    return car;
130  }
131
132  @Override
133  public final LispObject cdr()
134  {
135    return cdr;
136  }
137
138  @Override
139  public final void setCar(LispObject obj)
140  {
141    car = obj;
142  }
143
144  @Override
145  public LispObject RPLACA(LispObject obj)
146  {
147    car = obj;
148    return this;
149  }
150
151  @Override
152  public final void setCdr(LispObject obj)
153  {
154    cdr = obj;
155  }
156
157  @Override
158  public LispObject RPLACD(LispObject obj)
159  {
160    cdr = obj;
161    return this;
162  }
163
164  @Override
165  public final LispObject cadr()
166  {
167    return cdr.car();
168  }
169
170  @Override
171  public final LispObject cddr()
172  {
173    return cdr.cdr();
174  }
175
176  @Override
177  public final LispObject caddr()
178  {
179    return cdr.cadr();
180  }
181
182  @Override
183  public LispObject nthcdr(int n)
184  {
185    if (n < 0)
186      return type_error(Fixnum.getInstance(n),
187                             list(Symbol.INTEGER, Fixnum.ZERO));
188    LispObject result = this;
189    for (int i = n; i-- > 0;)
190      {
191        result = result.cdr();
192        if (result == NIL)
193          break;
194      }
195    return result;
196  }
197
198  @Override
199  public final LispObject push(LispObject obj)
200  {
201    return new Cons(obj, this);
202  }
203
204  @Override
205  public final int sxhash()
206  {
207    return computeHash(this, 4);
208  }
209
210  private static final int computeHash(LispObject obj, int depth)
211  {
212    if (obj instanceof Cons)
213      {
214        if (depth > 0)
215          {
216            int n1 = computeHash(((Cons)obj).car, depth - 1);
217            int n2 = computeHash(((Cons)obj).cdr, depth - 1);
218            return n1 ^ n2;
219          }
220        else
221          {
222            // This number comes from SBCL, but since we're not really
223            // using SBCL's SXHASH algorithm, it's probably not optimal.
224            // But who knows?
225            return 261835505;
226          }
227      }
228    else
229      return obj.sxhash();
230  }
231
232  @Override
233  public final int psxhash()
234  {
235    return computeEqualpHash(this, 4);
236  }
237
238  private static final int computeEqualpHash(LispObject obj, int depth)
239  {
240    if (obj instanceof Cons)
241      {
242        if (depth > 0)
243          {
244            int n1 = computeEqualpHash(((Cons)obj).car, depth - 1);
245            int n2 = computeEqualpHash(((Cons)obj).cdr, depth - 1);
246            return n1 ^ n2;
247          }
248        else
249          return 261835505; // See above.
250      }
251    else
252      return obj.psxhash();
253  }
254
255  @Override
256  public final boolean equal(LispObject obj)
257  {
258    if (this == obj)
259      return true;
260    if (obj instanceof Cons)
261      {
262        if (car.equal(((Cons)obj).car) && cdr.equal(((Cons)obj).cdr))
263          return true;
264      }
265    return false;
266  }
267
268  @Override
269  public final boolean equalp(LispObject obj)
270  {
271    if (this == obj)
272      return true;
273    if (obj instanceof Cons)
274      {
275        if (car.equalp(((Cons)obj).car) && cdr.equalp(((Cons)obj).cdr))
276          return true;
277      }
278    return false;
279  }
280
281  @Override
282  public final int length()
283  {
284    int length = 1;
285    LispObject obj = cdr;
286        while (obj != NIL)
287          {
288            ++length;
289            if (obj instanceof Cons) {
290                obj = ((Cons)obj).cdr;
291            } else  type_error(obj, Symbol.LIST);
292          }     
293    return length;
294  }
295
296  @Override
297  public LispObject NTH(int index)
298  {
299    if (index < 0)
300      type_error(Fixnum.getInstance(index), 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 NTH(LispObject arg)
316  {
317    int index;
318    if (arg instanceof Fixnum)
319      {
320        index = ((Fixnum)arg).value;
321      }
322    else
323        {
324        if (arg instanceof Bignum)
325          {
326            // FIXME (when machines have enough memory for it to matter)
327            if (arg.minusp())
328              return type_error(arg, Symbol.UNSIGNED_BYTE);
329            return NIL;
330          }
331        return type_error(arg, Symbol.UNSIGNED_BYTE);
332      }
333    if (index < 0)
334      type_error(arg, Symbol.UNSIGNED_BYTE);
335    int i = 0;
336    LispObject obj = this;
337    while (true)
338      {
339        if (i == index)
340          return obj.car();
341        obj = obj.cdr();
342        if (obj == NIL)
343          return NIL;
344        ++i;
345      }
346  }
347
348  @Override
349  public LispObject elt(int index)
350  {
351    if (index < 0)
352      type_error(Fixnum.getInstance(index), Symbol.UNSIGNED_BYTE);
353    int i = 0;
354    Cons cons = this;
355    while (true)
356      {
357        if (i == index)
358          return cons.car;
359        LispObject conscdr = cons.cdr;
360        if (conscdr instanceof Cons)
361          {
362            cons = (Cons) conscdr;
363          }
364        else
365          {
366            if (conscdr == NIL)
367              {
368                // Index too large.
369                type_error(Fixnum.getInstance(index),
370                                list(Symbol.INTEGER, Fixnum.ZERO,
371                                      Fixnum.getInstance(length() - 1)));
372              }
373            else
374              {
375                // Dotted list.
376                type_error(conscdr, Symbol.LIST);
377              }
378            // Not reached.
379            return NIL;
380          }
381        ++i;
382      }
383  }
384
385  @Override
386  public LispObject reverse()
387  {
388    Cons cons = this;
389    LispObject result = new Cons(cons.car);
390    while (cons.cdr instanceof Cons)
391      {
392        cons = (Cons) cons.cdr;
393        result = new Cons(cons.car, result);
394      }
395    if (cons.cdr != NIL)
396      return type_error(cons.cdr, Symbol.LIST);
397    return result;
398  }
399
400  @Override
401  public final LispObject nreverse()
402  {
403    if (cdr instanceof Cons)
404      {
405        Cons cons = (Cons) cdr;
406        if (cons.cdr instanceof Cons)
407          {
408            Cons cons1 = cons;
409            LispObject list = NIL;
410            do
411              {
412                Cons temp = (Cons) cons.cdr;
413                cons.cdr = list;
414                list = cons;
415                cons = temp;
416              }
417            while (cons.cdr instanceof Cons);
418            if (cons.cdr != NIL)
419              return type_error(cons.cdr, Symbol.LIST);
420            cdr = list;
421            cons1.cdr = cons;
422          }
423        else if (cons.cdr != NIL)
424          return type_error(cons.cdr, Symbol.LIST);
425        LispObject temp = car;
426        car = cons.car;
427        cons.car = temp;
428      }
429    else if (cdr != NIL)
430      return type_error(cdr, Symbol.LIST);
431    return this;
432  }
433
434  @Override
435  public final boolean listp()
436  {
437    return true;
438  }
439
440  @Override
441  public final LispObject LISTP()
442  {
443    return T;
444  }
445
446  @Override
447  public final boolean endp()
448  {
449    return false;
450  }
451
452  @Override
453  public final LispObject ENDP()
454  {
455    return NIL;
456  }
457
458  @Override
459  public final LispObject[] copyToArray()
460  {
461    final int length = length();
462    LispObject[] array = new LispObject[length];
463    LispObject rest = this;
464    for (int i = 0; i < length; i++)
465      {
466        array[i] = rest.car();
467        rest = rest.cdr();
468      }
469    return array;
470  }
471
472  @Override
473  public LispObject execute()
474  {
475    if (car == Symbol.LAMBDA)
476      {
477        Closure closure = new Closure(this, new Environment());
478        return closure.execute();
479      }
480    return signalExecutionError();
481  }
482
483  @Override
484  public LispObject execute(LispObject arg)
485  {
486    if (car == Symbol.LAMBDA)
487      {
488        Closure closure = new Closure(this, new Environment());
489        return closure.execute(arg);
490      }
491    return signalExecutionError();
492  }
493
494  @Override
495  public LispObject execute(LispObject first, LispObject second)
496
497  {
498    if (car == Symbol.LAMBDA)
499      {
500        Closure closure = new Closure(this, new Environment());
501        return closure.execute(first, second);
502      }
503    return signalExecutionError();
504  }
505
506  @Override
507  public LispObject execute(LispObject first, LispObject second,
508                            LispObject third)
509
510  {
511    if (car == Symbol.LAMBDA)
512      {
513        Closure closure = new Closure(this, new Environment());
514        return closure.execute(first, second, third);
515      }
516    return signalExecutionError();
517  }
518
519  @Override
520  public LispObject execute(LispObject first, LispObject second,
521                            LispObject third, LispObject fourth)
522
523  {
524    if (car == Symbol.LAMBDA)
525      {
526        Closure closure = new Closure(this, new Environment());
527        return closure.execute(first, second, third, fourth);
528      }
529    return signalExecutionError();
530  }
531
532  @Override
533  public LispObject execute(LispObject first, LispObject second,
534                            LispObject third, LispObject fourth,
535                            LispObject fifth)
536
537  {
538    if (car == Symbol.LAMBDA)
539      {
540        Closure closure = new Closure(this, new Environment());
541        return closure.execute(first, second, third, fourth, fifth);
542      }
543    return signalExecutionError();
544  }
545
546  @Override
547  public LispObject execute(LispObject first, LispObject second,
548                            LispObject third, LispObject fourth,
549                            LispObject fifth, LispObject sixth)
550
551  {
552    if (car == Symbol.LAMBDA)
553      {
554        Closure closure = new Closure(this, new Environment());
555        return closure.execute(first, second, third, fourth, fifth, sixth);
556      }
557    return signalExecutionError();
558  }
559
560  @Override
561  public LispObject execute(LispObject first, LispObject second,
562                            LispObject third, LispObject fourth,
563                            LispObject fifth, LispObject sixth,
564                            LispObject seventh)
565
566  {
567    if (car == Symbol.LAMBDA)
568      {
569        Closure closure = new Closure(this, new Environment());
570        return closure.execute(first, second, third, fourth, fifth, sixth,
571                               seventh);
572      }
573    return signalExecutionError();
574  }
575
576  @Override
577  public LispObject execute(LispObject first, LispObject second,
578                            LispObject third, LispObject fourth,
579                            LispObject fifth, LispObject sixth,
580                            LispObject seventh, LispObject eighth)
581
582  {
583    if (car == Symbol.LAMBDA)
584      {
585        Closure closure = new Closure(this, new Environment());
586        return closure.execute(first, second, third, fourth, fifth, sixth,
587                               seventh, eighth);
588      }
589    return signalExecutionError();
590  }
591
592  @Override
593  public LispObject execute(LispObject[] args)
594  {
595    if (car == Symbol.LAMBDA)
596      {
597        Closure closure = new Closure(this, new Environment());
598        return closure.execute(args);
599      }
600    return signalExecutionError();
601  }
602
603  private final LispObject signalExecutionError()
604  {
605    return type_error(this, list(Symbol.OR, Symbol.FUNCTION,
606                                       Symbol.SYMBOL));
607  }
608
609  @Override
610  public String writeToString()
611  {
612    final LispThread thread = LispThread.currentThread();
613    final LispObject printLength = Symbol.PRINT_LENGTH.symbolValue(thread);
614    final int maxLength;
615    if (printLength instanceof Fixnum)
616      maxLength = ((Fixnum)printLength).value;
617    else
618      maxLength = Integer.MAX_VALUE;
619    final LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
620    final int maxLevel;
621    if (printLevel instanceof Fixnum)
622      maxLevel = ((Fixnum)printLevel).value;
623    else
624      maxLevel = Integer.MAX_VALUE;
625    FastStringBuffer sb = new FastStringBuffer();
626    if (car == Symbol.QUOTE)
627      {
628        if (cdr instanceof Cons)
629          {
630            // Not a dotted list.
631            if (cdr.cdr() == NIL)
632              {
633                sb.append('\'');
634                sb.append(cdr.car().writeToString());
635                return sb.toString();
636              }
637          }
638      }
639    if (car == Symbol.FUNCTION)
640      {
641        if (cdr instanceof Cons)
642          {
643            // Not a dotted list.
644            if (cdr.cdr() == NIL)
645              {
646                sb.append("#'");
647                sb.append(cdr.car().writeToString());
648                return sb.toString();
649              }
650          }
651      }
652    LispObject currentPrintLevel =
653      _CURRENT_PRINT_LEVEL_.symbolValue(thread);
654    int currentLevel = Fixnum.getValue(currentPrintLevel);
655    if (currentLevel < maxLevel)
656      {
657        SpecialBinding lastSpecialBinding = thread.lastSpecialBinding;
658        thread.bindSpecial(_CURRENT_PRINT_LEVEL_, currentPrintLevel.incr());
659        try
660          {
661            int count = 0;
662            boolean truncated = false;
663            sb.append('(');
664            if (count < maxLength)
665              {
666                LispObject p = this;
667                sb.append(p.car().writeToString());
668                ++count;
669                while ((p = p.cdr()) instanceof Cons)
670                  {
671                    sb.append(' ');
672                    if (count < maxLength)
673                      {
674                        sb.append(p.car().writeToString());
675                        ++count;
676                      }
677                    else
678                      {
679                        truncated = true;
680                        break;
681                      }
682                  }
683                if (!truncated && p != NIL)
684                  {
685                    sb.append(" . ");
686                    sb.append(p.writeToString());
687                  }
688              }
689            else
690              truncated = true;
691            if (truncated)
692              sb.append("...");
693            sb.append(')');
694          }
695        finally
696          {
697            thread.lastSpecialBinding = lastSpecialBinding;
698          }
699      }
700    else
701      sb.append('#');
702    return sb.toString();
703  }
704
705  // Statistics for TIME.
706  private static long count;
707
708  /*package*/ static long getCount()
709  {
710    return count;
711  }
712
713  /*package*/ static void setCount(long n)
714  {
715    count = n;
716  }
717}
Note: See TracBrowser for help on using the repository browser.