KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > runtime > DynamicScope


1 package org.jruby.runtime;
2
3 import org.jruby.parser.BlockStaticScope;
4 import org.jruby.parser.StaticScope;
5 import org.jruby.runtime.builtin.IRubyObject;
6
7 /**
8  * Represents the the dynamic portion of scoping information. The variableValues are the
9  * values of assigned local or block variables. The staticScope identifies which sort of
10  * scope this is (block or local).
11  *
12  * Properties of Dynamic Scopes:
13  * 1. static and dynamic scopes have the same number of names to values
14  * 2. size of variables (and thus names) is determined during parsing. So those structured do
15  * not need to change
16  *
17  * FIXME: When creating dynamic scopes we sometimes accidentally pass in extra parents. This
18  * is harmless (other than wasting memory), but we should not do that. We can fix this in two
19  * ways:
20  * 1. Fix all callers
21  * 2. Check parent that is passed in and make if new instance is local, then its parent is not local
22  */

23 public class DynamicScope {
24     // Our values holder (name of variables are kept in staticScope)
25
private IRubyObject[] variableValues;
26     
27     // Static scoping information for this scope
28
private StaticScope staticScope;
29     
30     // Captured dyanmic scopes
31
private DynamicScope parent;
32     
33     // A place to store that special hiding space that bindings need to implement things like:
34
// eval("a = 1", binding); eval("p a"). All binding instances must get access to this
35
// hidden shared scope. We store it here. This will be null if no binding has yet
36
// been called.
37
private DynamicScope bindingScope;
38
39     public DynamicScope(StaticScope staticScope, DynamicScope parent) {
40         this.staticScope = staticScope;
41         this.parent = parent;
42         
43         int size = staticScope.getNumberOfVariables();
44         if (size > 0) variableValues = new IRubyObject[size];
45     }
46     
47     public DynamicScope cloneScope() {
48         return new DynamicScope(staticScope, parent);
49     }
50     
51     /**
52      * Get all variable names captured (visible) by this scope (sans $~ and $_).
53      *
54      * @return a list of variable names
55      */

56     public String JavaDoc[] getAllNamesInScope() {
57         return staticScope.getAllNamesInScope();
58     }
59
60     public IRubyObject[] getValues() {
61         return variableValues;
62     }
63     
64     /**
65      * Get value from current scope or one of its captured scopes.
66      *
67      * FIXME: block variables are not getting primed to nil so we need to null check those
68      * until we prime them properly. Also add assert back in.
69      *
70      * @param offset zero-indexed value that represents where variable lives
71      * @param depth how many captured scopes down this variable should be set
72      * @return the value here
73      */

74     public IRubyObject getValue(int offset, int depth) {
75         if (depth > 0) {
76             return parent.getValue(offset, depth - 1);
77         }
78         assert variableValues != null : "No variables in getValue for Off: " + offset + ", Dep: " + depth;
79         assert offset < variableValues.length : "Index to big for getValue Off: " + offset + ", Dep: " + depth + ", O: " + this;
80         // &foo are not getting set from somewhere...I want the following assert to be true though
81
//assert variableValues[offset] != null : "Getting unassigned: " + staticScope.getVariables()[offset];
82
return variableValues[offset];
83     }
84
85     /**
86      * Set value in current dynamic scope or one of its captured scopes.
87      *
88      * @param offset zero-indexed value that represents where variable lives
89      * @param value to set
90      * @param depth how many captured scopes down this variable should be set
91      */

92     public void setValue(int offset, IRubyObject value, int depth) {
93         if (depth > 0) {
94             assert parent != null : "If depth > 0, then parent should not ever be null";
95             
96             parent.setValue(offset, value, depth - 1);
97         } else {
98             assert offset < variableValues.length : "Setting " + offset + " to " + value + ", O: " + this;
99
100             variableValues[offset] = value;
101         }
102     }
103
104     /**
105      * Set all values which represent 'normal' parameters in a call list to this dynamic
106      * scope. Function calls bind to local scopes by assuming that the indexes or the
107      * arg list correspond to that of the local scope (plus 2 since $_ and $~ always take
108      * the first two slots). We pass in a second argument because we sometimes get more
109      * values than we are expecting. The rest get compacted by original caller into
110      * rest args.
111      *
112      * @param values up to size specified to be mapped as ordinary parm values
113      * @param size is the number of values to assign as ordinary parm values
114      */

115     public void setArgValues(IRubyObject[] values, int size) {
116         for (int i = 0; i < size; i++) {
117             setValue(i + 2, values[i], 0);
118         }
119     }
120
121     /**
122      *
123      * Make a larger dynamic scope if the static scope grew.
124      *
125      * Eval's with bindings require us to possibly change the size of the dynamic scope if
126      * things like 'eval "b = 2", binding' happens.
127      *
128      */

129     public void growIfNeeded() {
130         int dynamicSize = variableValues == null ? 0: variableValues.length;
131         
132         if (staticScope.getNumberOfVariables() > dynamicSize) {
133             IRubyObject values[] = new IRubyObject[staticScope.getNumberOfVariables()];
134             
135             if (dynamicSize > 0) {
136                 System.arraycopy(variableValues, 0, values, 0, dynamicSize);
137             }
138             
139             variableValues = values;
140         }
141     }
142
143     // FIXME: Depending on profiling we may want to cache information on location and depth of
144
// both $_ and/or $~ since in some situations they may happen a lot. isDefined should be
145
// fairly cheap, but you never know...
146

147     public void setLastLine(IRubyObject value) {
148         int location = staticScope.isDefined("$_");
149         
150         setValue(location & 0xffff, value, location >> 16);
151     }
152     
153     public IRubyObject getLastLine() {
154         int location = staticScope.isDefined("$_");
155
156         return getValue(location & 0xffff, location >> 16);
157     }
158
159     public void setBackRef(IRubyObject value) {
160         int location = staticScope.isDefined("$~");
161         
162         setValue(location & 0xffff, value, location >> 16);
163     }
164     
165     public IRubyObject getBackRef() {
166         int location = staticScope.isDefined("$~");
167         
168         return getValue(location & 0xffff, location >> 16);
169     }
170     
171     public DynamicScope getBindingScope() {
172         return bindingScope;
173     }
174     
175     public void setBindingScope(DynamicScope bindingScope) {
176         this.bindingScope = bindingScope;
177     }
178     
179     /**
180      * Get next 'captured' scope.
181      *
182      * @return the scope captured by this scope for implementing closures
183      *
184      */

185     public DynamicScope getNextCapturedScope() {
186         return parent;
187     }
188
189     /**
190      * Get the static scope associated with this DynamicScope.
191      *
192      * @return static complement to this scope
193      */

194     public StaticScope getStaticScope() {
195         return staticScope;
196     }
197     
198     public String JavaDoc toString() {
199         return toString(new StringBuffer JavaDoc(), "");
200     }
201
202     // Helper function to give a good view of current dynamic scope with captured scopes
203
private String JavaDoc toString(StringBuffer JavaDoc buf, String JavaDoc indent) {
204         buf.append(indent).append("Static Type[" + hashCode() + "]: " +
205                 (staticScope instanceof BlockStaticScope ? "block" : "local")+" [");
206         int size = staticScope.getNumberOfVariables();
207         
208         if (size != 0) {
209             String JavaDoc names[] = staticScope.getVariables();
210             for (int i = 0; i < size-1; i++) {
211                 buf.append(names[i]).append("=");
212
213                 if (variableValues[i] == null) {
214                     buf.append("null");
215                 } else {
216                     buf.append(variableValues[i]);
217                 }
218                 
219                 buf.append(",");
220             }
221             buf.append(names[size-1]).append("=");
222             
223             assert variableValues.length == names.length : "V: " + variableValues.length +
224                 " != N: " + names.length + " for " + buf;
225             
226             if (variableValues[size-1] == null) {
227                 buf.append("null");
228             } else {
229                 buf.append(variableValues[size-1]);
230             }
231             
232         }
233         
234         buf.append("]");
235         if (parent != null) {
236             buf.append("\n");
237             parent.toString(buf, indent + " ");
238         }
239         
240         return buf.toString();
241     }
242 }
243
Popular Tags