Location.java 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright (c) 2004 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.mapping;
  4. /** A Location is an abstract cell/location/variable with a value of type T. */
  5. public abstract class Location<T>
  6. {
  7. /* DEBUGGING
  8. static int counter;
  9. public int id=++counter;
  10. */
  11. public Location ()
  12. {
  13. }
  14. public Symbol getKeySymbol ()
  15. {
  16. return null;
  17. }
  18. public Object getKeyProperty ()
  19. {
  20. return null;
  21. }
  22. public String toString()
  23. {
  24. StringBuffer sbuf = new StringBuffer();
  25. sbuf.append(getClass().getName());
  26. Symbol sym = getKeySymbol();
  27. sbuf.append('[');
  28. if (sym != null)
  29. {
  30. sbuf.append(sym);
  31. Object property = getKeyProperty();
  32. // For a ThreadLocation the property defaults to "this".
  33. // In that case we'd better not print the property ...
  34. if (property != null && property != this)
  35. {
  36. sbuf.append('/');
  37. sbuf.append(property);
  38. }
  39. }
  40. /* DEBUGGING:
  41. sbuf.append(" #:");
  42. sbuf.append(id);
  43. */
  44. sbuf.append("]");
  45. return sbuf.toString();
  46. }
  47. /** Magic value used to indicate there is no property binding. */
  48. public static final String UNBOUND = new String("(unbound)");
  49. public T get (T defaultValue)
  50. {
  51. return isBound() ? get() : defaultValue;
  52. }
  53. /** Get the current value of this location.
  54. * @exception UnboundLocationException the location does not have a value. */
  55. public abstract T get ();
  56. public abstract void set (T value);
  57. public void undefine ()
  58. {
  59. throw new UnsupportedOperationException ();
  60. }
  61. /** Set a value, but return cookie so old value can be restored.
  62. * This is intended for fluid-let where (in the case of multiple threads)
  63. * a simple save-restore isn't always the right thing. */
  64. public Object setWithSave (T newValue)
  65. {
  66. Object old = isBound() ? get() : UNBOUND;
  67. set(newValue);
  68. return old;
  69. }
  70. /** Restore an old value.
  71. * @param oldValue the return value from a prior setWithSave. */
  72. public void setRestore (Object oldValue)
  73. {
  74. if (oldValue == UNBOUND)
  75. undefine();
  76. else
  77. set((T) oldValue);
  78. }
  79. public abstract boolean isBound ();
  80. public boolean isConstant ()
  81. {
  82. return false;
  83. }
  84. public Location getBase ()
  85. {
  86. return this;
  87. }
  88. public final T getValue ()
  89. {
  90. return get(null);
  91. }
  92. public final T setValue (T newValue)
  93. {
  94. T value = get(null);
  95. set(newValue);
  96. return value;
  97. }
  98. /** True if directly entered in an Environment. (Only if NamedLocation.) */
  99. public boolean entered ()
  100. {
  101. return false;
  102. }
  103. public void print(java.io.PrintWriter ps)
  104. {
  105. ps.print ("#<location ");
  106. Symbol name = getKeySymbol();
  107. if (name != null)
  108. ps.print(name);
  109. if (isBound())
  110. {
  111. ps.print(" -> ");
  112. try
  113. {
  114. ps.print(get());
  115. }
  116. catch (Exception ex)
  117. {
  118. ps.print("<caught "+ex+">");
  119. }
  120. }
  121. else
  122. ps.print("(unbound)");
  123. ps.print ('>');
  124. }
  125. // The compiler emits calls to this method.
  126. public static Location make (Object init, String name)
  127. {
  128. ThreadLocation loc = new ThreadLocation(name);
  129. loc.setGlobal(init);
  130. return loc;
  131. }
  132. // The compiler emits calls to this method.
  133. public static IndirectableLocation make (String name)
  134. {
  135. Symbol sym = Namespace.EmptyNamespace.getSymbol(name.intern());
  136. PlainLocation loc = new PlainLocation(sym, null);
  137. loc.base = null;
  138. loc.value = UNBOUND;
  139. return loc;
  140. }
  141. public static IndirectableLocation make (Symbol name)
  142. {
  143. PlainLocation loc = new PlainLocation(name, null);
  144. loc.base = null;
  145. loc.value = UNBOUND;
  146. return loc;
  147. }
  148. /** Implement top-level 'define' for Scheme in interactive mode.
  149. * I.e. if there is no binding, create it;
  150. * if the existing binding is non-constant, set its value;
  151. * if it is constant, create a new binding initialized to the old value
  152. * (though we actually change the binding to non-constant).
  153. */
  154. public static Location define(Symbol name) {
  155. Environment env = Environment.getCurrent();
  156. int hash = name.hashCode();
  157. NamedLocation loc = env.getLocation(name, null, hash, true);
  158. if (loc.isConstant()) {
  159. Object value = loc.get(Location.UNBOUND);
  160. loc.value = value;
  161. loc.base = null;
  162. }
  163. return loc;
  164. }
  165. }