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

Last change on this file was 12513, checked in by ehuelsmann, 15 years ago

Remove 'private' keyword to eliminate the Java requirement

for the compiler to generate synthetic accessors: functions that
don't appear in the source but do appear in the class file.

Patch by: Douglas Miles <dmiles _at_ users.sf.net>

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