source: trunk/abcl/src/org/armedbear/lisp/Cons.java

Last change on this file was 15435, checked in by Mark Evenson, 3 years ago

Initial implementation of accessing recursive entries in local jars

SYS:CLEAR-ZIP-CACHE will clear the cache

  • * *

Fix accessing remote jar contents

  • * *

Speculatively fix merging remote jar pathnames

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