source: trunk/abcl/src/org/armedbear/lisp/StandardObject.java @ 12254

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

Remove 'throws ConditionThrowable?' method annotations:

it's an unchecked exception now, so no need to declare it thrown.

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