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

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

Re #38: Merge the METACLASS branch to trunk.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 17.5 KB
Line 
1/*
2 * StandardObject.java
3 *
4 * Copyright (C) 2003-2006 Peter Graves
5 * $Id: StandardObject.java 12576 2010-03-28 20:13:14Z 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    if (typep(Symbol.CONDITION) != NIL)
212      {
213        StringOutputStream stream = new StringOutputStream();
214        Symbol.PRINT_OBJECT.execute(this, stream);
215        return stream.getString().getStringValue();
216      }
217    return unreadableString(typeOf().writeToString());
218  }
219
220  Layout updateLayout()
221  {
222    Debug.assertTrue(layout.isInvalid());
223    Layout oldLayout = layout;
224    LispObject cls = oldLayout.getLispClass();
225    Layout newLayout;
226
227    if (cls instanceof LispClass)
228        newLayout = ((LispClass)cls).getClassLayout();
229    else
230        newLayout = (Layout)Symbol.CLASS_LAYOUT.execute(cls);
231
232    Debug.assertTrue(!newLayout.isInvalid());
233    StandardObject newInstance = new StandardObject(newLayout);
234    Debug.assertTrue(newInstance.layout == newLayout);
235    LispObject added = NIL;
236    LispObject discarded = NIL;
237    LispObject plist = NIL;
238    // Old local slots.
239    LispObject[] oldSlotNames = oldLayout.getSlotNames();
240    for (int i = 0; i < oldSlotNames.length; i++)
241      {
242        LispObject slotName = oldSlotNames[i];
243        int j = newLayout.getSlotIndex(slotName);
244        if (j >= 0)
245          newInstance.slots[j] = slots[i];
246        else
247          {
248            discarded = discarded.push(slotName);
249            if (slots[i] != UNBOUND_VALUE)
250              {
251                plist = plist.push(slotName);
252                plist = plist.push(slots[i]);
253              }
254          }
255      }
256    // Old shared slots.
257    LispObject rest = oldLayout.getSharedSlots(); // A list.
258    if (rest != null)
259      {
260        while (rest != NIL)
261          {
262            LispObject location = rest.car();
263            LispObject slotName = location.car();
264            int i = newLayout.getSlotIndex(slotName);
265            if (i >= 0)
266              newInstance.slots[i] = location.cdr();
267            rest = rest.cdr();
268          }
269      }
270    // Go through all the new local slots to compute the added slots.
271    LispObject[] newSlotNames = newLayout.getSlotNames();
272    for (int i = 0; i < newSlotNames.length; i++)
273      {
274        LispObject slotName = newSlotNames[i];
275        int j = oldLayout.getSlotIndex(slotName);
276        if (j >= 0)
277          continue;
278        LispObject location = oldLayout.getSharedSlotLocation(slotName);
279        if (location != null)
280          continue;
281        // Not found.
282        added = added.push(slotName);
283      }
284    // Swap slots.
285    LispObject[] tempSlots = slots;
286    slots = newInstance.slots;
287    newInstance.slots = tempSlots;
288    // Swap layouts.
289    Layout tempLayout = layout;
290    layout = newInstance.layout;
291    newInstance.layout = tempLayout;
292    Debug.assertTrue(!layout.isInvalid());
293    // Call UPDATE-INSTANCE-FOR-REDEFINED-CLASS.
294    Symbol.UPDATE_INSTANCE_FOR_REDEFINED_CLASS.execute(this, added,
295                                                       discarded, plist);
296    return newLayout;
297  }
298
299  // Only handles instance slots (not shared slots).
300  public LispObject getInstanceSlotValue(LispObject slotName)
301
302  {
303    Debug.assertTrue(layout != null);
304    if (layout.isInvalid())
305      {
306        // Update instance.
307        layout = updateLayout();
308      }
309    Debug.assertTrue(layout != null);
310    int index = layout.getSlotIndex(slotName);
311    //### FIXME: should call SLOT-MISSING (clhs)
312    if (index < 0)
313      return error(new LispError("Missing slot " + slotName.writeToString()));
314    return slots[index];
315  }
316
317  // Only handles instance slots (not shared slots).
318  public void setInstanceSlotValue(LispObject slotName, LispObject newValue)
319
320  {
321    Debug.assertTrue(layout != null);
322    if (layout.isInvalid())
323      {
324        // Update instance.
325        layout = updateLayout();
326      }
327    Debug.assertTrue(layout != null);
328    int index = layout.getSlotIndex(slotName);
329    //### FIXME: should call SLOT-MISSING (clhs)
330    if (index < 0)
331      error(new LispError("Missing slot " + slotName.writeToString()));
332    slots[index] = newValue;
333  }
334
335        final public static StandardObject checkStandardObject(LispObject first)
336        {
337                if (first instanceof StandardObject)
338                        return (StandardObject) first;
339                return (StandardObject) type_error(first, Symbol.STANDARD_OBJECT);
340        }
341       
342  // ### swap-slots instance-1 instance-2 => nil
343  private static final Primitive SWAP_SLOTS =
344    new Primitive("swap-slots", PACKAGE_SYS, true, "instance-1 instance-2")
345    {
346      @Override
347      public LispObject execute(LispObject first, LispObject second)
348
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  // ### std-instance-layout
360  private static final Primitive STD_INSTANCE_LAYOUT =
361    new Primitive("std-instance-layout", PACKAGE_SYS, true)
362    {
363      @Override
364      public LispObject execute(LispObject arg)
365      {
366        final StandardObject instance = checkStandardObject(arg);
367        Layout layout = instance.layout;
368        if (layout.isInvalid())
369          {
370            // Update instance.
371            layout = instance.updateLayout();
372          }
373        return layout;
374      }
375    };
376
377  // ### %set-std-instance-layout
378  private static final Primitive _SET_STD_INSTANCE_LAYOUT =
379    new Primitive("%set-std-instance-layout", PACKAGE_SYS, true)
380    {
381      @Override
382      public LispObject execute(LispObject first, LispObject second)
383
384      {
385          checkStandardObject(first).layout = checkLayout(second);         
386          return second;
387      }
388    };
389
390  // ### std-instance-class
391  private static final Primitive STD_INSTANCE_CLASS =
392    new Primitive("std-instance-class", PACKAGE_SYS, true)
393    {
394      @Override
395      public LispObject execute(LispObject arg)
396      {
397          return checkStandardObject(arg).layout.getLispClass();
398      }
399    };
400
401  // ### standard-instance-access instance location => value
402  private static final Primitive STANDARD_INSTANCE_ACCESS =
403    new Primitive("standard-instance-access", PACKAGE_SYS, true,
404                  "instance location")
405    {
406      @Override
407      public LispObject execute(LispObject first, LispObject second)
408
409      {
410        final StandardObject instance = checkStandardObject(first);
411        final int index;
412        if (second instanceof Fixnum)
413          {
414            index = ((Fixnum)second).value;
415          }
416        else
417          {
418            return type_error(second,
419                                   list(Symbol.INTEGER, Fixnum.ZERO,
420                                         Fixnum.getInstance(instance.slots.length)));
421          }
422        LispObject value;
423        try
424          {
425            value = instance.slots[index];
426          }
427        catch (ArrayIndexOutOfBoundsException e)
428          {
429            return type_error(second,
430                                   list(Symbol.INTEGER, Fixnum.ZERO,
431                                         Fixnum.getInstance(instance.slots.length)));
432          }
433        if (value == UNBOUND_VALUE)
434          {
435            LispObject slotName = instance.layout.getSlotNames()[index];
436            value = Symbol.SLOT_UNBOUND.execute(instance.getLispClass(),
437                                                instance, slotName);
438            LispThread.currentThread()._values = null;
439          }
440        return value;
441      }
442    };
443
444  // ### %set-standard-instance-access instance location new-value => new-value
445  private static final Primitive _SET_STANDARD_INSTANCE_ACCESS =
446    new Primitive("%set-standard-instance-access", PACKAGE_SYS, true)
447    {
448      @Override
449      public LispObject execute(LispObject first, LispObject second,
450                                LispObject third)
451
452      {
453          checkStandardObject(first).slots[Fixnum.getValue(second)] = third; // FIXME
454          return third;
455      }
456    };
457
458  // ### std-slot-boundp
459  private static final Primitive STD_SLOT_BOUNDP =
460    new Primitive(Symbol.STD_SLOT_BOUNDP, "instance slot-name")
461    {
462      @Override
463      public LispObject execute(LispObject first, LispObject second)
464
465      {
466        final StandardObject instance = checkStandardObject(first);
467        Layout layout = instance.layout;
468        if (layout.isInvalid())
469          {
470            // Update instance.
471            layout = instance.updateLayout();
472          }
473        final LispObject index = layout.slotTable.get(second);
474        if (index != null)
475          {
476            // Found instance slot.
477            return instance.slots[((Fixnum)index).value] != UNBOUND_VALUE ? T : NIL;
478          }
479        // Check for shared slot.
480        final LispObject location = layout.getSharedSlotLocation(second);
481        if (location != null)
482          return location.cdr() != UNBOUND_VALUE ? T : NIL;
483        // Not found.
484        final LispThread thread = LispThread.currentThread();
485        LispObject value =
486          thread.execute(Symbol.SLOT_MISSING, instance.getLispClass(),
487                         instance, second, Symbol.SLOT_BOUNDP);
488        // "If SLOT-MISSING is invoked and returns a value, a boolean
489        // equivalent to its primary value is returned by SLOT-BOUNDP."
490        thread._values = null;
491        return value != NIL ? T : NIL;
492      }
493    };
494
495  @Override
496  public LispObject SLOT_VALUE(LispObject slotName)
497  {
498    if (layout.isInvalid())
499      {
500        // Update instance.
501        layout = updateLayout();
502      }
503    LispObject value;
504    final LispObject index = layout.slotTable.get(slotName);
505    if (index != null)
506      {
507        // Found instance slot.
508        value = slots[((Fixnum)index).value];
509      }
510    else
511      {
512        // Check for shared slot.
513        LispObject location = layout.getSharedSlotLocation(slotName);
514        if (location == null)
515          return Symbol.SLOT_MISSING.execute(getLispClass(), this, slotName,
516                                             Symbol.SLOT_VALUE);
517        value = location.cdr();
518      }
519    if (value == UNBOUND_VALUE)
520      {
521        value = Symbol.SLOT_UNBOUND.execute(getLispClass(), this, slotName);
522        LispThread.currentThread()._values = null;
523      }
524    return value;
525  }
526
527  // ### std-slot-value
528  private static final Primitive STD_SLOT_VALUE =
529    new Primitive(Symbol.STD_SLOT_VALUE, "instance slot-name")
530    {
531      @Override
532      public LispObject execute(LispObject first, LispObject second)
533
534      {
535        return first.SLOT_VALUE(second);
536      }
537    };
538
539  @Override
540  public void setSlotValue(LispObject slotName, LispObject newValue)
541
542  {
543    if (layout.isInvalid())
544      {
545        // Update instance.
546        layout = updateLayout();
547      }
548    final LispObject index = layout.slotTable.get(slotName);
549    if (index != null)
550      {
551        // Found instance slot.
552        slots[((Fixnum)index).value] = newValue;
553        return;
554      }
555    // Check for shared slot.
556    LispObject location = layout.getSharedSlotLocation(slotName);
557    if (location != null)
558      {
559        location.setCdr(newValue);
560        return;
561      }
562    LispObject[] args = new LispObject[5];
563    args[0] = getLispClass();
564    args[1] = this;
565    args[2] = slotName;
566    args[3] = Symbol.SETF;
567    args[4] = newValue;
568    Symbol.SLOT_MISSING.execute(args);
569  }
570
571  // ### set-std-slot-value
572  private static final Primitive SET_STD_SLOT_VALUE =
573    new Primitive(Symbol.SET_STD_SLOT_VALUE, "instance slot-name new-value")
574    {
575      @Override
576      public LispObject execute(LispObject first, LispObject second,
577                                LispObject third)
578
579      {
580        first.setSlotValue(second, third);
581        return third;
582      }
583    };
584}
Note: See TracBrowser for help on using the repository browser.