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

Last change on this file was 11754, checked in by vvoutilainen, 16 years ago

Convert using ClassCastException? to checking instanceof.
Performance tests show this approach to be faster.
Patch by Douglas R. Miles. I modified the patch to
remove tabs, so indentation may be slightly off in places.
That's something that we need to handle separately, abcl
doesn't have a clear indentation policy.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.5 KB
Line 
1/*
2 * Cons.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: Cons.java 11754 2009-04-12 10:53:39Z vvoutilainen $
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) throws ConditionThrowable
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) throws ConditionThrowable
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) throws ConditionThrowable
159  {
160    cdr = obj;
161    return this;
162  }
163
164  @Override
165  public final LispObject cadr() throws ConditionThrowable
166  {
167    return cdr.car();
168  }
169
170  @Override
171  public final LispObject cddr() throws ConditionThrowable
172  {
173    return cdr.cdr();
174  }
175
176  @Override
177  public final LispObject caddr() throws ConditionThrowable
178  {
179    return cdr.cadr();
180  }
181
182  @Override
183  public LispObject nthcdr(int n) throws ConditionThrowable
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() //throws ConditionThrowable
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) throws ConditionThrowable
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) throws ConditionThrowable
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() throws ConditionThrowable
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) throws ConditionThrowable
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) throws ConditionThrowable
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) throws ConditionThrowable
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() throws ConditionThrowable
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() throws ConditionThrowable
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() throws ConditionThrowable
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() throws ConditionThrowable
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) throws ConditionThrowable
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    throws ConditionThrowable
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    throws ConditionThrowable
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    throws ConditionThrowable
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    throws ConditionThrowable
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    throws ConditionThrowable
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    throws ConditionThrowable
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    throws ConditionThrowable
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) throws ConditionThrowable
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() throws ConditionThrowable
604  {
605    return type_error(this, list(Symbol.OR, Symbol.FUNCTION,
606                                       Symbol.SYMBOL));
607  }
608
609  @Override
610  public String writeToString() throws ConditionThrowable
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.