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

Last change on this file was 13400, checked in by ehuelsmann, 14 years ago

Fix #154 on 0.26.x branch: backport r13399.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.3 KB
Line 
1/*
2 * StandardObject.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StandardObject.java 13400 2011-07-13 19:11:11Z ehuelsmann $
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 writeToString()
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().writeToString());
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.writeToString()));
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.writeToString()));
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  // ### swap-slots instance-1 instance-2 => nil
337  private static final Primitive SWAP_SLOTS =
338    new Primitive("swap-slots", PACKAGE_SYS, true, "instance-1 instance-2")
339    {
340      @Override
341      public LispObject execute(LispObject first, LispObject second)
342
343      {
344        final StandardObject obj1 = checkStandardObject(first);
345        final StandardObject obj2 = checkStandardObject(second);
346        LispObject[] temp = obj1.slots;
347        obj1.slots = obj2.slots;
348        obj2.slots = temp;
349        return NIL;
350      }
351    };
352
353  // ### std-instance-layout
354  private static final Primitive STD_INSTANCE_LAYOUT =
355    new Primitive("std-instance-layout", PACKAGE_SYS, true)
356    {
357      @Override
358      public LispObject execute(LispObject arg)
359      {
360        final StandardObject instance = checkStandardObject(arg);
361        Layout layout = instance.layout;
362        if (layout.isInvalid())
363          {
364            // Update instance.
365            layout = instance.updateLayout();
366          }
367        return layout;
368      }
369    };
370
371  // ### %set-std-instance-layout
372  private static final Primitive _SET_STD_INSTANCE_LAYOUT =
373    new Primitive("%set-std-instance-layout", PACKAGE_SYS, true)
374    {
375      @Override
376      public LispObject execute(LispObject first, LispObject second)
377
378      {
379          checkStandardObject(first).layout = checkLayout(second);         
380          return second;
381      }
382    };
383
384  // ### std-instance-class
385  private static final Primitive STD_INSTANCE_CLASS =
386    new Primitive("std-instance-class", PACKAGE_SYS, true)
387    {
388      @Override
389      public LispObject execute(LispObject arg)
390      {
391          return checkStandardObject(arg).layout.getLispClass();
392      }
393    };
394
395  // ### standard-instance-access instance location => value
396  private static final Primitive STANDARD_INSTANCE_ACCESS =
397    new Primitive("standard-instance-access", PACKAGE_SYS, true,
398                  "instance location")
399    {
400      @Override
401      public LispObject execute(LispObject first, LispObject second)
402
403      {
404        final StandardObject instance = checkStandardObject(first);
405        final int index;
406        if (second instanceof Fixnum)
407          {
408            index = ((Fixnum)second).value;
409          }
410        else
411          {
412            return type_error(second,
413                                   list(Symbol.INTEGER, Fixnum.ZERO,
414                                         Fixnum.getInstance(instance.slots.length)));
415          }
416        LispObject value;
417        try
418          {
419            value = instance.slots[index];
420          }
421        catch (ArrayIndexOutOfBoundsException e)
422          {
423            return type_error(second,
424                                   list(Symbol.INTEGER, Fixnum.ZERO,
425                                         Fixnum.getInstance(instance.slots.length)));
426          }
427        if (value == UNBOUND_VALUE)
428          {
429            LispObject slotName = instance.layout.getSlotNames()[index];
430            value = Symbol.SLOT_UNBOUND.execute(instance.getLispClass(),
431                                                instance, slotName);
432            LispThread.currentThread()._values = null;
433          }
434        return value;
435      }
436    };
437
438  // ### %set-standard-instance-access instance location new-value => new-value
439  private static final Primitive _SET_STANDARD_INSTANCE_ACCESS =
440    new Primitive("%set-standard-instance-access", PACKAGE_SYS, true)
441    {
442      @Override
443      public LispObject execute(LispObject first, LispObject second,
444                                LispObject third)
445
446      {
447          checkStandardObject(first).slots[Fixnum.getValue(second)] = third; // FIXME
448          return third;
449      }
450    };
451
452  // ### std-slot-boundp
453  private static final Primitive STD_SLOT_BOUNDP =
454    new Primitive(Symbol.STD_SLOT_BOUNDP, "instance slot-name")
455    {
456      @Override
457      public LispObject execute(LispObject first, LispObject second)
458
459      {
460        final StandardObject instance = checkStandardObject(first);
461        Layout layout = instance.layout;
462        if (layout.isInvalid())
463          {
464            // Update instance.
465            layout = instance.updateLayout();
466          }
467        final LispObject index = layout.slotTable.get(second);
468        if (index != null)
469          {
470            // Found instance slot.
471            return instance.slots[((Fixnum)index).value] != UNBOUND_VALUE ? T : NIL;
472          }
473        // Check for shared slot.
474        final LispObject location = layout.getSharedSlotLocation(second);
475        if (location != null)
476          return location.cdr() != UNBOUND_VALUE ? T : NIL;
477        // Not found.
478        final LispThread thread = LispThread.currentThread();
479        LispObject value =
480          thread.execute(Symbol.SLOT_MISSING, instance.getLispClass(),
481                         instance, second, Symbol.SLOT_BOUNDP);
482        // "If SLOT-MISSING is invoked and returns a value, a boolean
483        // equivalent to its primary value is returned by SLOT-BOUNDP."
484        thread._values = null;
485        return value != NIL ? T : NIL;
486      }
487    };
488
489  @Override
490  public LispObject SLOT_VALUE(LispObject slotName)
491  {
492    if (layout.isInvalid())
493      {
494        // Update instance.
495        layout = updateLayout();
496      }
497    LispObject value;
498    final LispObject index = layout.slotTable.get(slotName);
499    if (index != null)
500      {
501        // Found instance slot.
502        value = slots[((Fixnum)index).value];
503      }
504    else
505      {
506        // Check for shared slot.
507        LispObject location = layout.getSharedSlotLocation(slotName);
508        if (location == null)
509          return Symbol.SLOT_MISSING.execute(getLispClass(), this, slotName,
510                                             Symbol.SLOT_VALUE);
511        value = location.cdr();
512      }
513    if (value == UNBOUND_VALUE)
514      {
515        value = Symbol.SLOT_UNBOUND.execute(getLispClass(), this, slotName);
516        LispThread.currentThread()._values = null;
517      }
518    return value;
519  }
520
521  // ### std-slot-value
522  private static final Primitive STD_SLOT_VALUE =
523    new Primitive(Symbol.STD_SLOT_VALUE, "instance slot-name")
524    {
525      @Override
526      public LispObject execute(LispObject first, LispObject second)
527
528      {
529        return first.SLOT_VALUE(second);
530      }
531    };
532
533  @Override
534  public void setSlotValue(LispObject slotName, LispObject newValue)
535
536  {
537    if (layout.isInvalid())
538      {
539        // Update instance.
540        layout = updateLayout();
541      }
542    final LispObject index = layout.slotTable.get(slotName);
543    if (index != null)
544      {
545        // Found instance slot.
546        slots[((Fixnum)index).value] = newValue;
547        return;
548      }
549    // Check for shared slot.
550    LispObject location = layout.getSharedSlotLocation(slotName);
551    if (location != null)
552      {
553        location.setCdr(newValue);
554        return;
555      }
556    LispObject[] args = new LispObject[5];
557    args[0] = getLispClass();
558    args[1] = this;
559    args[2] = slotName;
560    args[3] = Symbol.SETF;
561    args[4] = newValue;
562    Symbol.SLOT_MISSING.execute(args);
563  }
564
565  // ### set-std-slot-value
566  private static final Primitive SET_STD_SLOT_VALUE =
567    new Primitive(Symbol.SET_STD_SLOT_VALUE, "instance slot-name new-value")
568    {
569      @Override
570      public LispObject execute(LispObject first, LispObject second,
571                                LispObject third)
572
573      {
574        first.setSlotValue(second, third);
575        return third;
576      }
577    };
578}
Note: See TracBrowser for help on using the repository browser.