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

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

Serialization support for some Lisp types.
For symbols and packages, only the "identity" is serialized, i.e. package name + symbol name.
For packages, it is expected that a package of the same name exists "at the other side".
For symbols, the deserialized symbol is interned in its home package.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 15.1 KB
Line 
1/*
2 * Cons.java
3 *
4 * Copyright (C) 2002-2005 Peter Graves
5 * $Id: Cons.java 12713 2010-05-20 17:58:13Z 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 implements java.io.Serializable
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  public Cons(Cons original) 
65  {
66    Cons rest = original;
67    LispObject result = NIL;
68    while (rest.car() != NIL) {
69      result = result.push(rest.car());
70      if (rest.cdr() == NIL) {
71        break;
72      }
73      rest = (Cons) rest.cdr();
74    }
75    result = result.nreverse();
76    this.car = result.car();
77    this.cdr = result.cdr();
78    ++count;
79  }
80
81  @Override
82  public LispObject typeOf()
83  {
84    return Symbol.CONS;
85  }
86
87  @Override
88  public LispObject classOf()
89  {
90    return BuiltInClass.CONS;
91  }
92
93  @Override
94  public LispObject typep(LispObject typeSpecifier)
95  {
96    if (typeSpecifier instanceof Symbol)
97      {
98        if (typeSpecifier == Symbol.LIST)
99          return T;
100        if (typeSpecifier == Symbol.CONS)
101          return T;
102        if (typeSpecifier == Symbol.SEQUENCE)
103          return T;
104        if (typeSpecifier == T)
105          return T;
106      }
107    else if (typeSpecifier instanceof LispClass)
108      {
109        if (typeSpecifier == BuiltInClass.LIST)
110          return T;
111        if (typeSpecifier == BuiltInClass.CONS)
112          return T;
113        if (typeSpecifier == BuiltInClass.SEQUENCE)
114          return T;
115        if (typeSpecifier == BuiltInClass.CLASS_T)
116          return T;
117      }
118    return NIL;
119  }
120
121  @Override
122  public final boolean constantp()
123  {
124    if (car == Symbol.QUOTE)
125      {
126        if (cdr instanceof Cons)
127          if (((Cons)cdr).cdr == NIL)
128            return true;
129      }
130    return false;
131  }
132
133  @Override
134  public boolean atom()
135  {
136    return false;
137  }
138
139  @Override
140  public LispObject RPLACA(LispObject obj)
141  {
142    car = obj;
143    return this;
144  }
145
146  @Override
147  public LispObject RPLACD(LispObject obj)
148  {
149    cdr = obj;
150    return this;
151  }
152
153  @Override
154  public final int sxhash()
155  {
156    return computeHash(this, 4);
157  }
158
159  private static final int computeHash(LispObject obj, int depth)
160  {
161    if (obj instanceof Cons)
162      {
163        if (depth > 0)
164          {
165            int n1 = computeHash(((Cons)obj).car, depth - 1);
166            int n2 = computeHash(((Cons)obj).cdr, depth - 1);
167            return n1 ^ n2;
168          }
169        else
170          {
171            // This number comes from SBCL, but since we're not really
172            // using SBCL's SXHASH algorithm, it's probably not optimal.
173            // But who knows?
174            return 261835505;
175          }
176      }
177    else
178      return obj.sxhash();
179  }
180
181  @Override
182  public final int psxhash()
183  {
184    return computeEqualpHash(this, 4);
185  }
186
187  private static final int computeEqualpHash(LispObject obj, int depth)
188  {
189    if (obj instanceof Cons)
190      {
191        if (depth > 0)
192          {
193            int n1 = computeEqualpHash(((Cons)obj).car, depth - 1);
194            int n2 = computeEqualpHash(((Cons)obj).cdr, depth - 1);
195            return n1 ^ n2;
196          }
197        else
198          return 261835505; // See above.
199      }
200    else
201      return obj.psxhash();
202  }
203
204  @Override
205  public final boolean equal(LispObject obj)
206  {
207    if (this == obj)
208      return true;
209    if (obj instanceof Cons)
210      {
211        if (car.equal(((Cons)obj).car) && cdr.equal(((Cons)obj).cdr))
212          return true;
213      }
214    return false;
215  }
216
217  @Override
218  public final boolean equalp(LispObject obj)
219  {
220    if (this == obj)
221      return true;
222    if (obj instanceof Cons)
223      {
224        if (car.equalp(((Cons)obj).car) && cdr.equalp(((Cons)obj).cdr))
225          return true;
226      }
227    return false;
228  }
229
230  @Override
231  public final int length()
232  {
233    int length = 1;
234    LispObject obj = cdr;
235        while (obj != NIL)
236          {
237            ++length;
238            if (obj instanceof Cons) {
239                obj = ((Cons)obj).cdr;
240            } else  type_error(obj, Symbol.LIST);
241          }     
242    return length;
243  }
244
245  @Override
246  public LispObject NTH(int index)
247  {
248    if (index < 0)
249      type_error(Fixnum.getInstance(index), Symbol.UNSIGNED_BYTE);
250    int i = 0;
251    LispObject obj = this;
252    while (true)
253      {
254        if (i == index)
255          return obj.car();
256        obj = obj.cdr();
257        if (obj == NIL)
258          return NIL;
259        ++i;
260      }
261  }
262
263  @Override
264  public LispObject elt(int index)
265  {
266    if (index < 0)
267      type_error(Fixnum.getInstance(index), Symbol.UNSIGNED_BYTE);
268    int i = 0;
269    Cons cons = this;
270    while (true)
271      {
272        if (i == index)
273          return cons.car;
274        LispObject conscdr = cons.cdr;
275        if (conscdr instanceof Cons)
276          {
277            cons = (Cons) conscdr;
278          }
279        else
280          {
281            if (conscdr == NIL)
282              {
283                // Index too large.
284                type_error(Fixnum.getInstance(index),
285                                list(Symbol.INTEGER, Fixnum.ZERO,
286                                      Fixnum.getInstance(length() - 1)));
287              }
288            else
289              {
290                // Dotted list.
291                type_error(conscdr, Symbol.LIST);
292              }
293            // Not reached.
294            return NIL;
295          }
296        ++i;
297      }
298  }
299
300  @Override
301  public LispObject reverse()
302  {
303    Cons cons = this;
304    LispObject result = new Cons(cons.car);
305    while (cons.cdr instanceof Cons)
306      {
307        cons = (Cons) cons.cdr;
308        result = new Cons(cons.car, result);
309      }
310    if (cons.cdr != NIL)
311      return type_error(cons.cdr, Symbol.LIST);
312    return result;
313  }
314
315  @Override
316  public final LispObject nreverse()
317  {
318    if (cdr instanceof Cons)
319      {
320        Cons cons = (Cons) cdr;
321        if (cons.cdr instanceof Cons)
322          {
323            Cons cons1 = cons;
324            LispObject list = NIL;
325            do
326              {
327                Cons temp = (Cons) cons.cdr;
328                cons.cdr = list;
329                list = cons;
330                cons = temp;
331              }
332            while (cons.cdr instanceof Cons);
333            if (cons.cdr != NIL)
334              return type_error(cons.cdr, Symbol.LIST);
335            cdr = list;
336            cons1.cdr = cons;
337          }
338        else if (cons.cdr != NIL)
339          return type_error(cons.cdr, Symbol.LIST);
340        LispObject temp = car;
341        car = cons.car;
342        cons.car = temp;
343      }
344    else if (cdr != NIL)
345      return type_error(cdr, Symbol.LIST);
346    return this;
347  }
348
349  @Override
350  public final LispObject[] copyToArray()
351  {
352    final int length = length();
353    LispObject[] array = new LispObject[length];
354    LispObject rest = this;
355    for (int i = 0; i < length; i++)
356      {
357        array[i] = rest.car();
358        rest = rest.cdr();
359      }
360    return array;
361  }
362
363  @Override
364  public LispObject execute()
365  {
366    if (car == Symbol.LAMBDA)
367      {
368        Closure closure = new Closure(this, new Environment());
369        return closure.execute();
370      }
371    return signalExecutionError();
372  }
373
374  @Override
375  public LispObject execute(LispObject arg)
376  {
377    if (car == Symbol.LAMBDA)
378      {
379        Closure closure = new Closure(this, new Environment());
380        return closure.execute(arg);
381      }
382    return signalExecutionError();
383  }
384
385  @Override
386  public LispObject execute(LispObject first, LispObject second)
387
388  {
389    if (car == Symbol.LAMBDA)
390      {
391        Closure closure = new Closure(this, new Environment());
392        return closure.execute(first, second);
393      }
394    return signalExecutionError();
395  }
396
397  @Override
398  public LispObject execute(LispObject first, LispObject second,
399                            LispObject third)
400
401  {
402    if (car == Symbol.LAMBDA)
403      {
404        Closure closure = new Closure(this, new Environment());
405        return closure.execute(first, second, third);
406      }
407    return signalExecutionError();
408  }
409
410  @Override
411  public LispObject execute(LispObject first, LispObject second,
412                            LispObject third, LispObject fourth)
413
414  {
415    if (car == Symbol.LAMBDA)
416      {
417        Closure closure = new Closure(this, new Environment());
418        return closure.execute(first, second, third, fourth);
419      }
420    return signalExecutionError();
421  }
422
423  @Override
424  public LispObject execute(LispObject first, LispObject second,
425                            LispObject third, LispObject fourth,
426                            LispObject fifth)
427
428  {
429    if (car == Symbol.LAMBDA)
430      {
431        Closure closure = new Closure(this, new Environment());
432        return closure.execute(first, second, third, fourth, fifth);
433      }
434    return signalExecutionError();
435  }
436
437  @Override
438  public LispObject execute(LispObject first, LispObject second,
439                            LispObject third, LispObject fourth,
440                            LispObject fifth, LispObject sixth)
441
442  {
443    if (car == Symbol.LAMBDA)
444      {
445        Closure closure = new Closure(this, new Environment());
446        return closure.execute(first, second, third, fourth, fifth, sixth);
447      }
448    return signalExecutionError();
449  }
450
451  @Override
452  public LispObject execute(LispObject first, LispObject second,
453                            LispObject third, LispObject fourth,
454                            LispObject fifth, LispObject sixth,
455                            LispObject seventh)
456
457  {
458    if (car == Symbol.LAMBDA)
459      {
460        Closure closure = new Closure(this, new Environment());
461        return closure.execute(first, second, third, fourth, fifth, sixth,
462                               seventh);
463      }
464    return signalExecutionError();
465  }
466
467  @Override
468  public LispObject execute(LispObject first, LispObject second,
469                            LispObject third, LispObject fourth,
470                            LispObject fifth, LispObject sixth,
471                            LispObject seventh, LispObject eighth)
472
473  {
474    if (car == Symbol.LAMBDA)
475      {
476        Closure closure = new Closure(this, new Environment());
477        return closure.execute(first, second, third, fourth, fifth, sixth,
478                               seventh, eighth);
479      }
480    return signalExecutionError();
481  }
482
483  @Override
484  public LispObject execute(LispObject[] args)
485  {
486    if (car == Symbol.LAMBDA)
487      {
488        Closure closure = new Closure(this, new Environment());
489        return closure.execute(args);
490      }
491    return signalExecutionError();
492  }
493
494  private final LispObject signalExecutionError()
495  {
496    return type_error(this, list(Symbol.OR, Symbol.FUNCTION,
497                                       Symbol.SYMBOL));
498  }
499
500  @Override
501  public String writeToString()
502  {
503    final LispThread thread = LispThread.currentThread();
504    final LispObject printLength = Symbol.PRINT_LENGTH.symbolValue(thread);
505    final int maxLength;
506    if (printLength instanceof Fixnum)
507      maxLength = ((Fixnum)printLength).value;
508    else
509      maxLength = Integer.MAX_VALUE;
510    final LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
511    final int maxLevel;
512    if (printLevel instanceof Fixnum)
513      maxLevel = ((Fixnum)printLevel).value;
514    else
515      maxLevel = Integer.MAX_VALUE;
516    StringBuilder sb = new StringBuilder();
517    if (car == Symbol.QUOTE)
518      {
519        if (cdr instanceof Cons)
520          {
521            // Not a dotted list.
522            if (cdr.cdr() == NIL)
523              {
524                sb.append('\'');
525                sb.append(cdr.car().writeToString());
526                return sb.toString();
527              }
528          }
529      }
530    if (car == Symbol.FUNCTION)
531      {
532        if (cdr instanceof Cons)
533          {
534            // Not a dotted list.
535            if (cdr.cdr() == NIL)
536              {
537                sb.append("#'");
538                sb.append(cdr.car().writeToString());
539                return sb.toString();
540              }
541          }
542      }
543    LispObject currentPrintLevel =
544      _CURRENT_PRINT_LEVEL_.symbolValue(thread);
545    int currentLevel = Fixnum.getValue(currentPrintLevel);
546    if (currentLevel < maxLevel)
547      {
548        final SpecialBindingsMark mark = thread.markSpecialBindings();
549        thread.bindSpecial(_CURRENT_PRINT_LEVEL_, currentPrintLevel.incr());
550        try
551          {
552            int count = 0;
553            boolean truncated = false;
554            sb.append('(');
555            if (count < maxLength)
556              {
557                LispObject p = this;
558                sb.append(p.car().writeToString());
559                ++count;
560                while ((p = p.cdr()) instanceof Cons)
561                  {
562                    sb.append(' ');
563                    if (count < maxLength)
564                      {
565                        sb.append(p.car().writeToString());
566                        ++count;
567                      }
568                    else
569                      {
570                        truncated = true;
571                        break;
572                      }
573                  }
574                if (!truncated && p != NIL)
575                  {
576                    sb.append(" . ");
577                    sb.append(p.writeToString());
578                  }
579              }
580            else
581              truncated = true;
582            if (truncated)
583              sb.append("...");
584            sb.append(')');
585          }
586        finally
587          {
588            thread.resetSpecialBindings(mark);
589          }
590      }
591    else
592      sb.append('#');
593    return sb.toString();
594  }
595
596  // Statistics for TIME.
597  private static long count;
598
599  /*package*/ static long getCount()
600  {
601    return count;
602  }
603
604  /*package*/ static void setCount(long n)
605  {
606    count = n;
607  }
608}
Note: See TracBrowser for help on using the repository browser.