source: branches/1.0.x/abcl/src/org/armedbear/lisp/StandardObject.java

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

Convert docstrings and primitives to standard conventions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.4 KB
Line 
1/*
2 * StandardObject.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StandardObject.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 StandardObject extends LispObject
39{
40  protected Layout layout;
41  protected LispObject[] slots;
42
43  protected StandardObject()
44  {
45    layout = new Layout(StandardClass.STANDARD_OBJECT, NIL, NIL);
46  }
47
48
49  protected StandardObject(Layout layout)
50  {
51    this(layout, layout.getLength());
52  }
53
54  protected StandardObject(Layout layout, int length)
55  {
56    this.layout = layout;
57    slots = new LispObject[length];
58    for (int i = slots.length; i-- > 0;)
59      slots[i] = UNBOUND_VALUE;
60  }
61
62
63  protected StandardObject(LispClass cls, int length)
64  {
65    layout = cls == null ? null : cls.getClassLayout();
66    slots = new LispObject[length];
67    for (int i = slots.length; i-- > 0;)
68      slots[i] = UNBOUND_VALUE;
69  }
70
71  protected StandardObject(LispClass cls)
72  {
73    layout = cls == null ? null : cls.getClassLayout();
74    slots = new LispObject[layout == null ? 0 : layout.getLength()];
75    for (int i = slots.length; i-- > 0;)
76      slots[i] = UNBOUND_VALUE;
77  }
78
79  @Override
80  public LispObject getParts()
81  {
82    LispObject parts = NIL;
83    if (layout != null)
84      {
85        if (layout.isInvalid())
86          {
87            // Update instance.
88            layout = updateLayout();
89          }
90      }
91    parts = parts.push(new Cons("LAYOUT", layout));
92    if (layout != null)
93      {
94        LispObject[] slotNames = layout.getSlotNames();
95        if (slotNames != null)
96          {
97            for (int i = 0; i < slotNames.length; i++)
98              {
99                parts = parts.push(new Cons(slotNames[i], slots[i]));
100              }
101          }
102      }
103    return parts.nreverse();
104  }
105
106  public final LispObject getLispClass()
107  {
108    return layout.getLispClass();
109  }
110
111  private LispObject helperGetClassName()
112  {
113    final LispObject c1 = layout.getLispClass();
114    if (c1 instanceof LispClass)
115        return ((LispClass)c1).getName();
116    else
117        return LispThread.currentThread().execute(Symbol.CLASS_NAME, c1);
118  }
119
120  private LispObject helperGetCPL()
121  {
122    final LispObject c1 = layout.getLispClass();
123    if (c1 instanceof LispClass)
124        return ((LispClass)c1).getCPL();
125    else
126        return LispThread.currentThread().execute(Symbol.CLASS_PRECEDENCE_LIST, c1);
127  }
128
129  @Override
130  public LispObject typeOf()
131  {
132    // "For objects of metaclass STRUCTURE-CLASS or STANDARD-CLASS, and for
133    // conditions, TYPE-OF returns the proper name of the class returned by
134    // CLASS-OF if it has a proper name, and otherwise returns the class
135    // itself."
136    final LispObject c1 = layout.getLispClass();
137    LispObject name;
138    if (c1 instanceof LispClass)
139        name = ((LispClass)c1).getName();
140    else
141        name = LispThread.currentThread().execute(Symbol.CLASS_NAME, c1);
142
143    // The proper name of a class is "a symbol that names the class whose
144    // name is that symbol".
145    if (name != NIL && name != UNBOUND_VALUE)
146      {
147        // TYPE-OF.9
148        final LispObject c2 = LispClass.findClass(name, false);
149        if (c2 == c1)
150          return name;
151      }
152    return c1;
153  }
154
155  @Override
156  public LispObject classOf()
157  {
158    return layout.getLispClass();
159  }
160
161  @Override
162  public LispObject typep(LispObject type)
163  {
164    if (type == Symbol.STANDARD_OBJECT)
165      return T;
166    if (type == StandardClass.STANDARD_OBJECT)
167      return T;
168    LispObject cls = layout != null ? layout.getLispClass() : null;
169    if (cls != null)
170      {
171        if (type == cls)
172          return T;
173        if (type == helperGetClassName())
174          return T;
175        LispObject cpl = helperGetCPL();
176        while (cpl != NIL)
177          {
178            if (type == cpl.car())
179              return T;
180
181            LispObject otherName;
182            LispObject otherClass = cpl.car();
183            if (otherClass instanceof LispClass) {
184              if (type == ((LispClass)otherClass).getName())
185                return T;
186            }
187            else
188            if (type == LispThread
189                .currentThread().execute(Symbol.CLASS_NAME, otherClass))
190                return T;
191
192            cpl = cpl.cdr();
193          }
194      }
195    return super.typep(type);
196  }
197
198  @Override
199  public String printObject()
200  {
201    final LispThread thread = LispThread.currentThread();
202    int maxLevel = Integer.MAX_VALUE;
203    LispObject printLevel = Symbol.PRINT_LEVEL.symbolValue(thread);
204    if (printLevel instanceof Fixnum)
205      maxLevel = ((Fixnum)printLevel).value;
206    LispObject currentPrintLevel =
207      _CURRENT_PRINT_LEVEL_.symbolValue(thread);
208    int currentLevel = Fixnum.getValue(currentPrintLevel);
209    if (currentLevel >= maxLevel)
210      return "#";
211    return unreadableString(typeOf().printObject());
212  }
213
214  Layout updateLayout()
215  {
216    Debug.assertTrue(layout.isInvalid());
217    Layout oldLayout = layout;
218    LispObject cls = oldLayout.getLispClass();
219    Layout newLayout;
220
221    if (cls instanceof LispClass)
222        newLayout = ((LispClass)cls).getClassLayout();
223    else
224        newLayout = (Layout)Symbol.CLASS_LAYOUT.execute(cls);
225
226    Debug.assertTrue(!newLayout.isInvalid());
227    StandardObject newInstance = new StandardObject(newLayout);
228    Debug.assertTrue(newInstance.layout == newLayout);
229    LispObject added = NIL;
230    LispObject discarded = NIL;
231    LispObject plist = NIL;
232    // Old local slots.
233    LispObject[] oldSlotNames = oldLayout.getSlotNames();
234    for (int i = 0; i < oldSlotNames.length; i++)
235      {
236        LispObject slotName = oldSlotNames[i];
237        int j = newLayout.getSlotIndex(slotName);
238        if (j >= 0)
239          newInstance.slots[j] = slots[i];
240        else
241          {
242            discarded = discarded.push(slotName);
243            if (slots[i] != UNBOUND_VALUE)
244              {
245                plist = plist.push(slotName);
246                plist = plist.push(slots[i]);
247              }
248          }
249      }
250    // Old shared slots.
251    LispObject rest = oldLayout.getSharedSlots(); // A list.
252    if (rest != null)
253      {
254        while (rest != NIL)
255          {
256            LispObject location = rest.car();
257            LispObject slotName = location.car();
258            int i = newLayout.getSlotIndex(slotName);
259            if (i >= 0)
260              newInstance.slots[i] = location.cdr();
261            rest = rest.cdr();
262          }
263      }
264    // Go through all the new local slots to compute the added slots.
265    LispObject[] newSlotNames = newLayout.getSlotNames();
266    for (int i = 0; i < newSlotNames.length; i++)
267      {
268        LispObject slotName = newSlotNames[i];
269        int j = oldLayout.getSlotIndex(slotName);
270        if (j >= 0)
271          continue;
272        LispObject location = oldLayout.getSharedSlotLocation(slotName);
273        if (location != null)
274          continue;
275        // Not found.
276        added = added.push(slotName);
277      }
278    // Swap slots.
279    LispObject[] tempSlots = slots;
280    slots = newInstance.slots;
281    newInstance.slots = tempSlots;
282    // Swap layouts.
283    Layout tempLayout = layout;
284    layout = newInstance.layout;
285    newInstance.layout = tempLayout;
286    Debug.assertTrue(!layout.isInvalid());
287    // Call UPDATE-INSTANCE-FOR-REDEFINED-CLASS.
288    Symbol.UPDATE_INSTANCE_FOR_REDEFINED_CLASS.execute(this, added,
289                                                       discarded, plist);
290    return newLayout;
291  }
292
293  // Only handles instance slots (not shared slots).
294  public LispObject getInstanceSlotValue(LispObject slotName)
295
296  {
297    Debug.assertTrue(layout != null);
298    if (layout.isInvalid())
299      {
300        // Update instance.
301        layout = updateLayout();
302      }
303    Debug.assertTrue(layout != null);
304    int index = layout.getSlotIndex(slotName);
305    //### FIXME: should call SLOT-MISSING (clhs)
306    if (index < 0)
307      return error(new LispError("Missing slot " + slotName.princToString()));
308    return slots[index];
309  }
310
311  // Only handles instance slots (not shared slots).
312  public void setInstanceSlotValue(LispObject slotName, LispObject newValue)
313
314  {
315    Debug.assertTrue(layout != null);
316    if (layout.isInvalid())
317      {
318        // Update instance.
319        layout = updateLayout();
320      }
321    Debug.assertTrue(layout != null);
322    int index = layout.getSlotIndex(slotName);
323    // FIXME: should call SLOT-MISSING (clhs)
324    if (index < 0)
325      error(new LispError("Missing slot " + slotName.princToString()));
326    slots[index] = newValue;
327  }
328 
329  final public static StandardObject checkStandardObject(LispObject first)
330  {
331    if (first instanceof StandardObject)
332      return (StandardObject) first;
333    return (StandardObject) type_error(first, Symbol.STANDARD_OBJECT);
334  }
335       
336  private static final Primitive SWAP_SLOTS
337    = new pf_swap_slots(); 
338  @DocString(name="swap-slots",
339             args="instance-1 instance-2",
340             returns="nil")
341  private static final class pf_swap_slots extends Primitive
342  {
343    pf_swap_slots()
344    {
345      super("swap-slots", PACKAGE_SYS, true, "instance-1 instance-2");
346    }
347    @Override
348    public LispObject execute(LispObject first, LispObject second)
349    {
350      final StandardObject obj1 = checkStandardObject(first);
351      final StandardObject obj2 = checkStandardObject(second);
352      LispObject[] temp = obj1.slots;
353      obj1.slots = obj2.slots;
354      obj2.slots = temp;
355      return NIL;
356    }
357  };
358
359  private static final Primitive STD_INSTANCE_LAYOUT
360    = new pf_std_instance_layout();
361  @DocString(name="std-instance-layout")
362  private static final class pf_std_instance_layout extends Primitive
363  {
364    pf_std_instance_layout() 
365    {
366      super("std-instance-layout", PACKAGE_SYS, true);
367    }
368    @Override
369    public LispObject execute(LispObject arg)
370    {
371      final StandardObject instance = checkStandardObject(arg);
372      Layout layout = instance.layout;
373      if (layout.isInvalid())
374        {
375          // Update instance.
376          layout = instance.updateLayout();
377        }
378      return layout;
379    }
380  };
381
382  private static final Primitive _SET_STD_INSTANCE_LAYOUT
383    = new pf__set_std_instance_layout();
384  @DocString(name="%set-std-instance-layout")
385  private static final class pf__set_std_instance_layout extends Primitive
386  {
387    pf__set_std_instance_layout()
388    {
389      super("%set-std-instance-layout", PACKAGE_SYS, true);
390    }
391    @Override
392    public LispObject execute(LispObject first, LispObject second)
393    {
394      checkStandardObject(first).layout = checkLayout(second);         
395      return second;
396    }
397  };
398
399  private static final Primitive STD_INSTANCE_CLASS
400    = new pf_std_instance_class(); 
401  @DocString(name="std-instance-class")
402  private static final class pf_std_instance_class extends Primitive
403  {
404    pf_std_instance_class()
405    {
406      super("std-instance-class", PACKAGE_SYS, true);
407    }
408    @Override
409    public LispObject execute(LispObject arg)
410    {
411      return checkStandardObject(arg).layout.getLispClass();
412    }
413  };
414
415  private static final Primitive STANDARD_INSTANCE_ACCESS
416    = new pf_standard_instance_access();
417  @DocString(name="standard-instance-access",
418             args="instance location",
419             returns="value")
420  private static final class pf_standard_instance_access extends Primitive
421  {
422    pf_standard_instance_access()
423    {
424      super("standard-instance-access", PACKAGE_SYS, true,
425            "instance location");
426    }
427    @Override
428    public LispObject execute(LispObject first, LispObject second)
429    {
430      final StandardObject instance = checkStandardObject(first);
431      final int index;
432      if (second instanceof Fixnum)
433        {
434          index = ((Fixnum)second).value;
435        }
436      else
437        {
438          return type_error(second,
439                            list(Symbol.INTEGER, Fixnum.ZERO,
440                                 Fixnum.getInstance(instance.slots.length)));
441        }
442      LispObject value;
443      try
444        {
445          value = instance.slots[index];
446        }
447      catch (ArrayIndexOutOfBoundsException e)
448        {
449          return type_error(second,
450                            list(Symbol.INTEGER, Fixnum.ZERO,
451                                 Fixnum.getInstance(instance.slots.length)));
452        }
453      if (value == UNBOUND_VALUE)
454        {
455          LispObject slotName = instance.layout.getSlotNames()[index];
456          value = Symbol.SLOT_UNBOUND.execute(instance.getLispClass(),
457                                              instance, slotName);
458          LispThread.currentThread()._values = null;
459        }
460      return value;
461    }
462  };
463
464  private static final Primitive _SET_STANDARD_INSTANCE_ACCESS
465    = new pf__set_standard_instance_access();
466  @DocString(name="%set-standard-instance-access",
467             args="instance location new-value",
468             returns="new-value")
469  private static final class pf__set_standard_instance_access extends Primitive
470  {
471    pf__set_standard_instance_access()
472    {
473      super("%set-standard-instance-access", PACKAGE_SYS, true);
474    }
475    @Override
476    public LispObject execute(LispObject first, LispObject second,
477                              LispObject third)
478    {
479      checkStandardObject(first).slots[Fixnum.getValue(second)] = third; // FIXME
480      return third;
481    }
482  };
483
484  private static final Primitive STD_SLOT_BOUNDP
485    = new pf_std_slot_boundp();
486  @DocString(name="std-slot-boundp")
487  private static final class pf_std_slot_boundp extends Primitive
488  {
489    pf_std_slot_boundp()
490    {
491      super(Symbol.STD_SLOT_BOUNDP, "instance slot-name");
492    }
493    @Override
494    public LispObject execute(LispObject first, LispObject second)
495    {
496      final StandardObject instance = checkStandardObject(first);
497      Layout layout = instance.layout;
498      if (layout.isInvalid())
499        {
500          // Update instance.
501          layout = instance.updateLayout();
502        }
503      final LispObject index = layout.slotTable.get(second);
504      if (index != null)
505        {
506          // Found instance slot.
507          return instance.slots[((Fixnum)index).value] != UNBOUND_VALUE ? T : NIL;
508        }
509      // Check for shared slot.
510      final LispObject location = layout.getSharedSlotLocation(second);
511      if (location != null)
512        return location.cdr() != UNBOUND_VALUE ? T : NIL;
513      // Not found.
514      final LispThread thread = LispThread.currentThread();
515      LispObject value =
516        thread.execute(Symbol.SLOT_MISSING, instance.getLispClass(),
517                       instance, second, Symbol.SLOT_BOUNDP);
518      // "If SLOT-MISSING is invoked and returns a value, a boolean
519      // equivalent to its primary value is returned by SLOT-BOUNDP."
520      thread._values = null;
521      return value != NIL ? T : NIL;
522    }
523  };
524
525  @Override
526  public LispObject SLOT_VALUE(LispObject slotName)
527  {
528    if (layout.isInvalid())
529      {
530        // Update instance.
531        layout = updateLayout();
532      }
533    LispObject value;
534    final LispObject index = layout.slotTable.get(slotName);
535    if (index != null)
536      {
537        // Found instance slot.
538        value = slots[((Fixnum)index).value];
539      }
540    else
541      {
542        // Check for shared slot.
543        LispObject location = layout.getSharedSlotLocation(slotName);
544        if (location == null)
545          return Symbol.SLOT_MISSING.execute(getLispClass(), this, slotName,
546                                             Symbol.SLOT_VALUE);
547        value = location.cdr();
548      }
549    if (value == UNBOUND_VALUE)
550      {
551        value = Symbol.SLOT_UNBOUND.execute(getLispClass(), this, slotName);
552        LispThread.currentThread()._values = null;
553      }
554    return value;
555  }
556
557  private static final Primitive STD_SLOT_VALUE
558    = new pf_std_slot_value();
559  @DocString(name="std-slot-value")
560  private static final class pf_std_slot_value extends Primitive
561  {
562    pf_std_slot_value()
563    {
564      super(Symbol.STD_SLOT_VALUE, "instance slot-name");
565    }
566    @Override
567    public LispObject execute(LispObject first, LispObject second)
568    {
569      return first.SLOT_VALUE(second);
570    }
571  };
572
573  @Override
574  public void setSlotValue(LispObject slotName, LispObject newValue)
575  {
576    if (layout.isInvalid())
577      {
578        // Update instance.
579        layout = updateLayout();
580      }
581    final LispObject index = layout.slotTable.get(slotName);
582    if (index != null)
583      {
584        // Found instance slot.
585        slots[((Fixnum)index).value] = newValue;
586        return;
587      }
588    // Check for shared slot.
589    LispObject location = layout.getSharedSlotLocation(slotName);
590    if (location != null)
591      {
592        location.setCdr(newValue);
593        return;
594      }
595    LispObject[] args = new LispObject[5];
596    args[0] = getLispClass();
597    args[1] = this;
598    args[2] = slotName;
599    args[3] = Symbol.SETF;
600    args[4] = newValue;
601    Symbol.SLOT_MISSING.execute(args);
602  }
603
604  private static final Primitive SET_STD_SLOT_VALUE
605    = new pf_set_std_slot_value();
606  @DocString(name="set-std-slot-value")
607  private static final class pf_set_std_slot_value extends Primitive
608  {
609    pf_set_std_slot_value()
610    {
611      super(Symbol.SET_STD_SLOT_VALUE, "instance slot-name new-value");
612    }
613    @Override
614    public LispObject execute(LispObject first, LispObject second,
615                              LispObject third)
616    {
617      first.setSlotValue(second, third);
618      return third;
619    }
620  };
621}
Note: See TracBrowser for help on using the repository browser.