source: branches/1.1.x/src/org/armedbear/lisp/StructureObject.java

Last change on this file was 13541, checked in by Mark Evenson, 13 years ago

Convert docstrings and primitives to standard conventions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.6 KB
Line 
1/*
2 * StructureObject.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StructureObject.java 13541 2011-08-27 23:23:24Z 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 class StructureObject extends LispObject
39{
40  private final StructureClass structureClass;
41  final LispObject[] slots;
42
43  public StructureObject(Symbol symbol)
44
45  {
46      structureClass = (StructureClass) LispClass.findClass(symbol/*, true*/); // Might return null.
47    if (structureClass == null) {
48        System.err.println("No mitens sitten: " + BuiltInClass.SYSTEM_STREAM.toString());
49        System.err.println("joopa joo:" + Symbol.SYSTEM_STREAM.name);
50        System.err.println("Oh noes, structure object got a null class:" + symbol.toString() + ", symbol name:" + symbol.name );
51    }
52    slots = new LispObject[0];
53  }
54
55  public StructureObject(Symbol symbol, LispObject[] slots)
56
57  {
58    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
59    this.slots = slots;
60  }
61
62  public StructureObject(Symbol symbol, LispObject obj0)
63
64  {
65    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
66    LispObject[] slots = new LispObject[1];
67    slots[0] = obj0;
68    this.slots = slots;
69  }
70
71  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1)
72
73  {
74    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
75    LispObject[] slots = new LispObject[2];
76    slots[0] = obj0;
77    slots[1] = obj1;
78    this.slots = slots;
79  }
80
81  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
82                         LispObject obj2)
83
84  {
85    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
86    LispObject[] slots = new LispObject[3];
87    slots[0] = obj0;
88    slots[1] = obj1;
89    slots[2] = obj2;
90    this.slots = slots;
91  }
92
93  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
94                         LispObject obj2, LispObject obj3)
95
96  {
97    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
98    LispObject[] slots = new LispObject[4];
99    slots[0] = obj0;
100    slots[1] = obj1;
101    slots[2] = obj2;
102    slots[3] = obj3;
103    this.slots = slots;
104  }
105
106  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
107                         LispObject obj2, LispObject obj3, LispObject obj4)
108
109  {
110    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
111    LispObject[] slots = new LispObject[5];
112    slots[0] = obj0;
113    slots[1] = obj1;
114    slots[2] = obj2;
115    slots[3] = obj3;
116    slots[4] = obj4;
117    this.slots = slots;
118  }
119
120  public StructureObject(Symbol symbol, LispObject obj0, LispObject obj1,
121                         LispObject obj2, LispObject obj3, LispObject obj4,
122                         LispObject obj5)
123
124  {
125    structureClass = (StructureClass) LispClass.findClass(symbol); // Might return null.
126    LispObject[] slots = new LispObject[6];
127    slots[0] = obj0;
128    slots[1] = obj1;
129    slots[2] = obj2;
130    slots[3] = obj3;
131    slots[4] = obj4;
132    slots[5] = obj5;
133    this.slots = slots;
134  }
135
136  public StructureObject(StructureObject obj)
137  {
138    this.structureClass = obj.structureClass;
139    slots = new LispObject[obj.slots.length];
140    for (int i = slots.length; i-- > 0;)
141      slots[i] = obj.slots[i];
142  }
143
144  @Override
145  public LispObject typeOf()
146  {
147    return structureClass.getName();
148  }
149
150  @Override
151  public LispObject classOf()
152  {
153    return structureClass;
154  }
155
156    protected int getSlotIndex(LispObject slotName) {
157  LispObject effectiveSlots = structureClass.getSlotDefinitions();
158  LispObject[] effectiveSlotsArray = effectiveSlots.copyToArray();
159  for (int i = 0; i < slots.length; i++) {
160      SimpleVector slotDefinition = (SimpleVector) effectiveSlotsArray[i];
161      LispObject candidateSlotName = slotDefinition.AREF(1);
162      if(slotName == candidateSlotName) {
163    return i;
164      }
165  }
166  return -1;
167    }
168
169  @Override
170  public LispObject SLOT_VALUE(LispObject slotName)
171  {
172    LispObject value;
173    final int index = getSlotIndex(slotName);
174    if (index >= 0) {
175        value = slots[index];
176    } else {
177  value = UNBOUND_VALUE;
178        value = Symbol.SLOT_UNBOUND.execute(structureClass, this, slotName);
179        LispThread.currentThread()._values = null;
180    }
181    return value;
182  }
183
184  public void setSlotValue(LispObject slotName, LispObject newValue) {
185      final int index = getSlotIndex(slotName);
186      if (index >= 0) {
187    slots[index] = newValue;
188      } else {
189    LispObject[] args = new LispObject[5];
190    args[0] = structureClass;
191    args[1] = this;
192    args[2] = slotName;
193    args[3] = Symbol.SETF;
194    args[4] = newValue;
195    Symbol.SLOT_MISSING.execute(args);
196      }
197  }
198
199  @Override
200  public LispObject getParts()
201  {
202    LispObject result = NIL;
203    result = result.push(new Cons("class", structureClass));
204    LispObject effectiveSlots = structureClass.getSlotDefinitions();
205    LispObject[] effectiveSlotsArray = effectiveSlots.copyToArray();
206    Debug.assertTrue(effectiveSlotsArray.length == slots.length);
207    for (int i = 0; i < slots.length; i++)
208      {
209        SimpleVector slotDefinition = (SimpleVector) effectiveSlotsArray[i];
210        LispObject slotName = slotDefinition.AREF(1);
211        result = result.push(new Cons(slotName, slots[i]));
212      }
213    return result.nreverse();
214  }
215
216  @Override
217  public LispObject typep(LispObject type)
218  {
219    if (type instanceof StructureClass)
220      return memq(type, structureClass.getCPL()) ? T : NIL;
221    if (type == structureClass.getName())
222      return T;
223    if (type == Symbol.STRUCTURE_OBJECT)
224      return T;
225    if (type == BuiltInClass.STRUCTURE_OBJECT)
226      return T;
227    if (type instanceof Symbol)
228      {
229        LispClass c = LispClass.findClass((Symbol)type);
230        if (c != null)
231          return memq(c, structureClass.getCPL()) ? T : NIL;
232      }
233    return super.typep(type);
234  }
235
236  @Override
237  public boolean equalp(LispObject obj)
238  {
239    if (this == obj)
240      return true;
241    if (obj instanceof StructureObject)
242      {
243        StructureObject o = (StructureObject) obj;
244        if (structureClass != o.structureClass)
245          return false;
246        for (int i = 0; i < slots.length; i++)
247          {
248            if (!slots[i].equalp(o.slots[i]))
249              return false;
250          }
251        return true;
252      }
253    return false;
254  }
255
256  @Override
257  public LispObject getSlotValue_0()
258  {
259    try
260      {
261        return slots[0];
262      }
263    catch (ArrayIndexOutOfBoundsException e)
264      {
265        return badIndex(0);
266      }
267  }
268
269  @Override
270  public LispObject getSlotValue_1()
271  {
272    try
273      {
274        return slots[1];
275      }
276    catch (ArrayIndexOutOfBoundsException e)
277      {
278        return badIndex(1);
279      }
280  }
281
282  @Override
283  public LispObject getSlotValue_2()
284  {
285    try
286      {
287        return slots[2];
288      }
289    catch (ArrayIndexOutOfBoundsException e)
290      {
291        return badIndex(2);
292      }
293  }
294
295  @Override
296  public LispObject getSlotValue_3()
297  {
298    try
299      {
300        return slots[3];
301      }
302    catch (ArrayIndexOutOfBoundsException e)
303      {
304        return badIndex(3);
305      }
306  }
307
308  @Override
309  public LispObject getSlotValue(int index)
310  {
311    try
312      {
313        return slots[index];
314      }
315    catch (ArrayIndexOutOfBoundsException e)
316      {
317        return badIndex(index);
318      }
319  }
320
321  @Override
322  public int getFixnumSlotValue(int index)
323  {
324    try
325      {
326        return Fixnum.getValue(slots[index]);
327      }
328    catch (ArrayIndexOutOfBoundsException e)
329      {
330        badIndex(index);
331        // Not reached.
332        return 0;
333      }
334  }
335
336  @Override
337  public boolean getSlotValueAsBoolean(int index)
338  {
339    try
340      {
341        return slots[index] != NIL ? true : false;
342      }
343    catch (ArrayIndexOutOfBoundsException e)
344      {
345        badIndex(index);
346        // Not reached.
347        return false;
348      }
349  }
350
351  @Override
352  public void setSlotValue_0(LispObject value)
353
354  {
355    try
356      {
357        slots[0] = value;
358      }
359    catch (ArrayIndexOutOfBoundsException e)
360      {
361        badIndex(0);
362      }
363  }
364
365  @Override
366  public void setSlotValue_1(LispObject value)
367
368  {
369    try
370      {
371        slots[1] = value;
372      }
373    catch (ArrayIndexOutOfBoundsException e)
374      {
375        badIndex(1);
376      }
377  }
378
379  @Override
380  public void setSlotValue_2(LispObject value)
381
382  {
383    try
384      {
385        slots[2] = value;
386      }
387    catch (ArrayIndexOutOfBoundsException e)
388      {
389        badIndex(2);
390      }
391  }
392
393  @Override
394  public void setSlotValue_3(LispObject value)
395
396  {
397    try
398      {
399        slots[3] = value;
400      }
401    catch (ArrayIndexOutOfBoundsException e)
402      {
403        badIndex(3);
404      }
405  }
406
407  @Override
408  public void setSlotValue(int index, LispObject value)
409
410  {
411    try
412      {
413        slots[index] = value;
414      }
415    catch (ArrayIndexOutOfBoundsException e)
416      {
417        badIndex(index);
418      }
419  }
420
421  private LispObject badIndex(int n)
422  {
423    StringBuilder sb = new StringBuilder("Invalid slot index ");
424    sb.append(Fixnum.getInstance(n).princToString());
425    sb.append(" for ");
426    sb.append(princToString());
427    return error(new LispError(sb.toString()));
428  }
429
430  @Override
431  public final int psxhash()
432  {
433    return psxhash(4);
434  }
435
436  @Override
437  public final int psxhash(int depth)
438  {
439    int result = mix(structureClass.sxhash(), 7814971);
440    if (depth > 0)
441      {
442        int limit = slots.length;
443        if (limit > 4)
444          limit = 4;
445        for (int i = 0; i < limit; i++)
446          result = mix(slots[i].psxhash(depth - 1), result);
447      }
448    return result & 0x7fffffff;
449  }
450
451  @Override
452  public String printObject()
453  {
454    try
455      {
456        final LispThread thread = LispThread.currentThread();
457        // FIXME
458        if (typep(Symbol.RESTART) != NIL)
459          {
460            Symbol PRINT_RESTART = PACKAGE_SYS.intern("PRINT-RESTART");
461            LispObject fun = PRINT_RESTART.getSymbolFunction();
462            StringOutputStream stream = new StringOutputStream();
463            thread.execute(fun, this, stream);
464            return stream.getString().getStringValue();
465          }
466        if (_PRINT_STRUCTURE_.symbolValue(thread) == NIL)
467          return unreadableString(structureClass.getName().printObject());
468        int maxLevel = Integer.MAX_VALUE;
469        LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
470        if (printLevel instanceof Fixnum)
471          maxLevel = ((Fixnum)printLevel).value;
472        LispObject currentPrintLevel =
473          _CURRENT_PRINT_LEVEL_.symbolValue(thread);
474        int currentLevel = Fixnum.getValue(currentPrintLevel);
475        if (currentLevel >= maxLevel && slots.length > 0)
476          return "#";
477        StringBuilder sb = new StringBuilder("#S(");
478        sb.append(structureClass.getName().printObject());
479        if (currentLevel < maxLevel)
480          {
481            LispObject effectiveSlots = structureClass.getSlotDefinitions();
482            LispObject[] effectiveSlotsArray = effectiveSlots.copyToArray();
483            Debug.assertTrue(effectiveSlotsArray.length == slots.length);
484            final LispObject printLength = Symbol.PRINT_LENGTH.symbolValue(thread);
485            final int limit;
486            if (printLength instanceof Fixnum)
487              limit = Math.min(slots.length, ((Fixnum)printLength).value);
488            else
489              limit = slots.length;
490            final boolean printCircle =
491              (Symbol.PRINT_CIRCLE.symbolValue(thread) != NIL);
492            for (int i = 0; i < limit; i++)
493              {
494                sb.append(' ');
495                SimpleVector slotDefinition = (SimpleVector) effectiveSlotsArray[i];
496                // FIXME AREF(1)
497                LispObject slotName = slotDefinition.AREF(1);
498                Debug.assertTrue(slotName instanceof Symbol);
499                sb.append(':');
500                sb.append(((Symbol)slotName).name.getStringValue());
501                sb.append(' ');
502                if (printCircle)
503                  {
504                    StringOutputStream stream = new StringOutputStream();
505                    thread.execute(Symbol.OUTPUT_OBJECT.getSymbolFunction(),
506                                   slots[i], stream);
507                    sb.append(stream.getString().getStringValue());
508                  }
509                else
510                  sb.append(slots[i].printObject());
511              }
512            if (limit < slots.length)
513              sb.append(" ...");
514          }
515        sb.append(')');
516        return sb.toString();
517      }
518    catch (StackOverflowError e)
519      {
520        error(new StorageCondition("Stack overflow."));
521        return null; // Not reached.
522      }
523  }
524
525  private static final Primitive STRUCTURE_OBJECT_P
526    = new pf_structure_object_p();
527  @DocString(name="structure-object-p",
528             args="object",
529             returns="generalized-boolean")
530  private static final class pf_structure_object_p extends Primitive
531  {
532    pf_structure_object_p()
533    {
534      super("structure-object-p", PACKAGE_SYS, true, "object");
535    }
536    @Override
537    public LispObject execute(LispObject arg)
538    {
539      return arg instanceof StructureObject ? T : NIL;
540    }
541  };
542
543  private static final Primitive STRUCTURE_LENGTH
544    = new pf_structure_length();
545  @DocString(name="structure-length",
546             args="instance",
547             returns="length")
548  private static final class pf_structure_length extends Primitive
549  {
550    pf_structure_length()
551    {
552      super("structure-length", PACKAGE_SYS, true, "instance");
553    }
554    @Override
555    public LispObject execute(LispObject arg)
556    {
557      if (arg instanceof StructureObject)
558        return Fixnum.getInstance(((StructureObject)arg).slots.length);
559      return type_error(arg, Symbol.STRUCTURE_OBJECT);
560    }
561  };
562
563  private static final Primitive STRUCTURE_REF
564    = new pf_structure_ref();
565  @DocString(name="structure-ref",
566             args="instance index",
567             returns="value")
568  private static final class pf_structure_ref extends Primitive
569  {
570    pf_structure_ref()
571    {
572      super("structure-ref", PACKAGE_SYS, true);
573    }
574    @Override
575    public LispObject execute(LispObject first, LispObject second)
576    {
577      if (first instanceof StructureObject)
578        try
579          {
580            return ((StructureObject)first).slots[Fixnum.getValue(second)];
581          }
582        catch (ArrayIndexOutOfBoundsException e)
583          {
584            // Shouldn't happen.
585            return error(new LispError("Internal error."));
586          }     
587      return type_error(first, Symbol.STRUCTURE_OBJECT);
588    }
589  };
590
591  private static final Primitive STRUCTURE_SET
592    = new pf_structure_set();
593  @DocString(name="structure-set",
594             args="instance index new-value",
595             returns="new-value")
596  private static final class pf_structure_set extends Primitive
597  {
598    pf_structure_set()
599    {
600      super("structure-set", PACKAGE_SYS, true);
601    }
602    @Override
603    public LispObject execute(LispObject first, LispObject second,
604                              LispObject third)
605    {
606      if (first instanceof StructureObject)
607        try
608          {
609            ((StructureObject)first).slots[Fixnum.getValue(second)] = third;
610            return third;
611          }
612        catch (ArrayIndexOutOfBoundsException e)
613          {
614            // Shouldn't happen.
615            return error(new LispError("Internal error."));
616          }     
617      return type_error(first, Symbol.STRUCTURE_OBJECT);
618    }     
619  };
620
621  private static final Primitive MAKE_STRUCTURE
622    = new pf_make_structure();
623  @DocString(name="make-structure")
624  private static final class pf_make_structure extends Primitive
625  {
626    pf_make_structure() 
627    { 
628      super("make-structure", PACKAGE_SYS, true);
629    }
630    @Override
631    public LispObject execute(LispObject first, LispObject second)
632    {
633      return new StructureObject(checkSymbol(first), second);
634    }
635    @Override
636    public LispObject execute(LispObject first, LispObject second,
637                              LispObject third)
638     
639    {
640      return new StructureObject(checkSymbol(first), second, third);
641    }
642    @Override
643    public LispObject execute(LispObject first, LispObject second,
644                              LispObject third, LispObject fourth)
645     
646    {
647      return new StructureObject(checkSymbol(first), second, third, fourth);
648    }
649    @Override
650    public LispObject execute(LispObject first, LispObject second,
651                              LispObject third, LispObject fourth,
652                              LispObject fifth)
653    {
654      return new StructureObject(checkSymbol(first), second, third, fourth,
655                                 fifth);
656    }
657    @Override
658    public LispObject execute(LispObject first, LispObject second,
659                              LispObject third, LispObject fourth,
660                              LispObject fifth, LispObject sixth)
661    {
662      return new StructureObject(checkSymbol(first), second, third, fourth,
663                                 fifth, sixth);
664    }
665    @Override
666    public LispObject execute(LispObject first, LispObject second,
667                              LispObject third, LispObject fourth,
668                              LispObject fifth, LispObject sixth,
669                              LispObject seventh)
670    {
671      return new StructureObject(checkSymbol(first), second, third, fourth,
672                                 fifth, sixth, seventh);
673    }
674  };
675
676  private static final Primitive _MAKE_STRUCTURE
677    = new pf__make_structure();
678  @DocString(name="%make-structure",
679             args="name slot-values",
680             returns="object")
681  private static final class pf__make_structure extends Primitive
682  {
683    pf__make_structure()
684    {
685      super("%make-structure", PACKAGE_SYS, true);
686    }
687    @Override
688    public LispObject execute(LispObject first, LispObject second)
689    {
690      return new StructureObject(checkSymbol(first), second.copyToArray());
691    }
692  };
693
694  private static final Primitive COPY_STRUCTURE
695    = new pf_copy_structure();
696  @DocString(name="copy-structure",
697             args="structure",
698             returns="copy")
699  private static final class pf_copy_structure extends Primitive
700  {
701    pf_copy_structure()
702    {
703      super(Symbol.COPY_STRUCTURE, "structure");
704    }
705    @Override
706    public LispObject execute(LispObject arg)
707    {
708      if (arg instanceof StructureObject)
709        return new StructureObject((StructureObject)arg);
710      return type_error(arg, Symbol.STRUCTURE_OBJECT);
711    }
712  };
713}
Note: See TracBrowser for help on using the repository browser.