wasCSharpSQLite – Blame information for rev 3

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*
2 * CallFrame.java
3 *
4 * Copyright (c) 1997 Cornell University.
5 * Copyright (c) 1997-1998 Sun Microsystems, Inc.
6 *
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
9 * WARRANTIES.
10 *
11 * Included in SQLite3 port to C# for use in testharness only; 2008 Noah B Hart
12 *
13 * RCS @(#) $Id: CallFrame.java,v 1.10 2003/01/08 02:10:17 mdejong Exp $
14 *
15 */
16 using System.Collections;
17 using System.Text;
18  
19 namespace tcl.lang
20 {
21  
22 /// <summary> This class implements a frame in the call stack.
23 ///
24 /// This class can be overridden to define new variable scoping rules for
25 /// the Tcl interpreter.
26 /// </summary>
27  
28 public class CallFrame
29 {
30 internal ArrayList VarNames
31 {
32 // FIXME : need to port Tcl 8.1 implementation here
33  
34  
35 get
36 {
37 ArrayList vector = new ArrayList( 10 );
38  
39 if ( varTable == null )
40 {
41 return vector;
42 }
43  
44 for ( IEnumerator e1 = varTable.Values.GetEnumerator(); e1.MoveNext(); )
45 {
46 Var v = (Var)e1.Current;
47 if ( !v.isVarUndefined() )
48 {
49 vector.Add( v.hashKey );
50 }
51 }
52 return vector;
53 }
54  
55 }
56 /// <returns> an Vector the names of the (defined) local variables
57 /// in this CallFrame (excluding upvar's)
58 /// </returns>
59 internal ArrayList LocalVarNames
60 {
61  
62  
63 get
64 {
65 ArrayList vector = new ArrayList( 10 );
66  
67 if ( varTable == null )
68 {
69 return vector;
70 }
71  
72 for ( IEnumerator e1 = varTable.Values.GetEnumerator(); e1.MoveNext(); )
73 {
74 Var v = (Var)e1.Current;
75 if ( !v.isVarUndefined() && !v.isVarLink() )
76 {
77 vector.Add( v.hashKey );
78 }
79 }
80 return vector;
81 }
82  
83 }
84 /// <summary> The interpreter associated with this call frame.</summary>
85  
86 protected internal Interp interp;
87  
88  
89 /// <summary> The Namespace this CallFrame is executing in.
90 /// Used to resolve commands and global variables.
91 /// </summary>
92  
93 internal NamespaceCmd.Namespace ns;
94  
95 /// <summary> If true, the frame was pushed to execute a Tcl procedure
96 /// and may have local vars. If false, the frame was pushed to execute
97 /// a namespace command and var references are treated as references
98 /// to namespace vars; varTable is ignored.
99 /// </summary>
100  
101 internal bool isProcCallFrame;
102  
103 /// <summary> Stores the arguments of the procedure associated with this CallFrame.
104 /// Is null for global level.
105 /// </summary>
106  
107 internal TclObject[] objv;
108  
109 /// <summary> Value of interp.frame when this procedure was invoked
110 /// (i.e. next in stack of all active procedures).
111 /// </summary>
112  
113 protected internal CallFrame caller;
114  
115 /// <summary> Value of interp.varFrame when this procedure was invoked
116 /// (i.e. determines variable scoping within caller; same as
117 /// caller unless an "uplevel" command or something equivalent
118 /// was active in the caller).
119 /// </summary>
120  
121 protected internal CallFrame callerVar;
122  
123 /// <summary> Level of recursion. = 0 for the global level.</summary>
124  
125 protected internal int level;
126  
127 /// <summary> Stores the variables of this CallFrame.</summary>
128  
129 protected internal Hashtable varTable;
130  
131  
132 /// <summary> Creates a CallFrame for the global variables.</summary>
133 /// <param name="interp">current interpreter.
134 /// </param>
135  
136 internal CallFrame( Interp i )
137 {
138 interp = i;
139 ns = i.globalNs;
140 varTable = new Hashtable();
141 caller = null;
142 callerVar = null;
143 objv = null;
144 level = 0;
145 isProcCallFrame = true;
146 }
147  
148 /// <summary> Creates a CallFrame. It changes the following variables:
149 ///
150 /// <ul>
151 /// <li> this.caller
152 /// <li> this.callerVar
153 /// <li> interp.frame
154 /// <li> interp.varFrame
155 /// </ul>
156 /// </summary>
157 /// <param name="i">current interpreter.
158 /// </param>
159 /// <param name="proc">the procedure to invoke in this call frame.
160 /// </param>
161 /// <param name="objv">the arguments to the procedure.
162 /// </param>
163 /// <exception cref=""> TclException if error occurs in parameter bindings.
164 /// </exception>
165 internal CallFrame( Interp i, Procedure proc, TclObject[] objv )
166 : this( i )
167 {
168  
169 try
170 {
171 chain( proc, objv );
172 }
173 catch ( TclException e )
174 {
175 dispose();
176 throw;
177 }
178 }
179  
180 /// <summary> Chain this frame into the call frame stack and binds the parameters
181 /// values to the formal parameters of the procedure.
182 ///
183 /// </summary>
184 /// <param name="proc">the procedure.
185 /// </param>
186 /// <param name="proc">argv the parameter values.
187 /// </param>
188 /// <exception cref=""> TclException if wrong number of arguments.
189 /// </exception>
190 internal void chain( Procedure proc, TclObject[] objv )
191 {
192 // FIXME: double check this ns thing in case where proc is renamed to different ns.
193 this.ns = proc.ns;
194 this.objv = objv;
195 // FIXME : quick level hack : fix later
196 level = ( interp.varFrame == null ) ? 1 : ( interp.varFrame.level + 1 );
197 caller = interp.frame;
198 callerVar = interp.varFrame;
199 interp.frame = this;
200 interp.varFrame = this;
201  
202 // parameter bindings
203  
204 int numArgs = proc.argList.Length;
205  
206 if ( ( !proc.isVarArgs ) && ( objv.Length - 1 > numArgs ) )
207 {
208 wrongNumProcArgs( objv[0], proc );
209 }
210  
211 int i, j;
212 for ( i = 0, j = 1; i < numArgs; i++, j++ )
213 {
214 // Handle the special case of the last formal being
215 // "args". When it occurs, assign it a list consisting of
216 // all the remaining actual arguments.
217  
218 TclObject varName = proc.argList[i][0];
219 TclObject value = null;
220  
221 if ( ( i == ( numArgs - 1 ) ) && proc.isVarArgs )
222 {
223 value = TclList.newInstance();
224 value.preserve();
225 for ( int k = j; k < objv.Length; k++ )
226 {
227 TclList.append( interp, value, objv[k] );
228 }
229 interp.setVar( varName, value, 0 );
230 value.release();
231 }
232 else
233 {
234 if ( j < objv.Length )
235 {
236 value = objv[j];
237 }
238 else if ( proc.argList[i][1] != null )
239 {
240 value = proc.argList[i][1];
241 }
242 else
243 {
244 wrongNumProcArgs( objv[0], proc );
245 }
246 interp.setVar( varName, value, 0 );
247 }
248 }
249 }
250  
251 private string wrongNumProcArgs( TclObject name, Procedure proc )
252 {
253 int i;
254 StringBuilder sbuf = new StringBuilder( 200 );
255 sbuf.Append( "wrong # args: should be \"" );
256  
257 sbuf.Append( name.ToString() );
258 for ( i = 0; i < proc.argList.Length; i++ )
259 {
260 TclObject arg = proc.argList[i][0];
261 TclObject def = proc.argList[i][1];
262  
263 sbuf.Append( " " );
264 if ( def != null )
265 sbuf.Append( "?" );
266  
267 sbuf.Append( arg.ToString() );
268 if ( def != null )
269 sbuf.Append( "?" );
270 }
271 sbuf.Append( "\"" );
272 throw new TclException( interp, sbuf.ToString() );
273 }
274  
275 /// <param name="name">the name of the variable.
276 ///
277 /// </param>
278 /// <returns> true if a variable exists and is defined inside this
279 /// CallFrame, false otherwise
280 /// </returns>
281  
282 internal static bool exists( Interp interp, string name )
283 {
284 try
285 {
286 Var[] result = Var.lookupVar( interp, name, null, 0, "lookup", false, false );
287 if ( result == null )
288 {
289 return false;
290 }
291 if ( result[0].isVarUndefined() )
292 {
293 return false;
294 }
295 return true;
296 }
297 catch ( TclException e )
298 {
299 throw new TclRuntimeError( "unexpected TclException: " + e.Message, e );
300 }
301 }
302  
303 /// <returns> an Vector the names of the (defined) variables
304 /// in this CallFrame.
305 /// </returns>
306  
307 /// <summary> Tcl_GetFrame -> getFrame
308 ///
309 /// Given a description of a procedure frame, such as the first
310 /// argument to an "uplevel" or "upvar" command, locate the
311 /// call frame for the appropriate level of procedure.
312 ///
313 /// The return value is 1 if string was either a number or a number
314 /// preceded by "#" and it specified a valid frame. 0 is returned
315 /// if string isn't one of the two things above (in this case,
316 /// the lookup acts as if string were "1"). The frameArr[0] reference
317 /// will be filled by the reference of the desired frame (unless an
318 /// error occurs, in which case it isn't modified).
319 ///
320 /// </summary>
321 /// <param name="string">a string that specifies the level.
322 /// </param>
323 /// <exception cref=""> TclException if s is a valid level specifier but
324 /// refers to a bad level that doesn't exist.
325 /// </exception>
326  
327 internal static int getFrame( Interp interp, string inString, CallFrame[] frameArr )
328 {
329 int curLevel, level, result;
330 CallFrame frame;
331  
332 // Parse string to figure out which level number to go to.
333  
334 result = 1;
335 curLevel = ( interp.varFrame == null ) ? 0 : interp.varFrame.level;
336  
337 if ( ( inString.Length > 0 ) && ( inString[0] == '#' ) )
338 {
339 level = Util.getInt( interp, inString.Substring( 1 ) );
340 if ( level < 0 )
341 {
342 throw new TclException( interp, "bad level \"" + inString + "\"" );
343 }
344 }
345 else if ( ( inString.Length > 0 ) && System.Char.IsDigit( inString[0] ) )
346 {
347 level = Util.getInt( interp, inString );
348 level = curLevel - level;
349 }
350 else
351 {
352 level = curLevel - 1;
353 result = 0;
354 }
355  
356 // FIXME: is this a bad comment from some other proc?
357 // Figure out which frame to use, and modify the interpreter so
358 // its variables come from that frame.
359  
360 if ( level == 0 )
361 {
362 frame = null;
363 }
364 else
365 {
366 for ( frame = interp.varFrame; frame != null; frame = frame.callerVar )
367 {
368 if ( frame.level == level )
369 {
370 break;
371 }
372 }
373 if ( frame == null )
374 {
375 throw new TclException( interp, "bad level \"" + inString + "\"" );
376 }
377 }
378 frameArr[0] = frame;
379 return result;
380 }
381  
382  
383 /// <summary> This method is called when this CallFrame is no longer needed.
384 /// Removes the reference of this object from the interpreter so
385 /// that this object can be garbage collected.
386 /// <p>
387 /// For this procedure to work correctly, it must not be possible
388 /// for any of the variable in the table to be accessed from Tcl
389 /// commands (e.g. from trace procedures).
390 /// </summary>
391  
392 protected internal void dispose()
393 {
394 // Unchain this frame from the call stack.
395  
396 interp.frame = caller;
397 interp.varFrame = callerVar;
398 caller = null;
399 callerVar = null;
400  
401 if ( varTable != null )
402 {
403 Var.deleteVars( interp, varTable );
404 varTable.Clear();
405 varTable = null;
406 }
407 }
408 }
409 }