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

Last change on this file since 12288 was 12288, checked in by vvoutilainen, 15 years ago

Don't extend Lisp in LispObject, static import Lisp wherever
necessary. Patch by Douglas R. Miles.

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