Source Code Cross Referenced for Var.java in  » Scripting » jacl » tcl » lang » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Scripting » jacl » tcl.lang 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Var.java
0003:         *
0004:         * Copyright (c) 1997 Sun Microsystems, Inc.
0005:         *
0006:         * See the file "license.terms" for information on usage and
0007:         * redistribution of this file, and for a DISCLAIMER OF ALL
0008:         * WARRANTIES.
0009:         * 
0010:         * RCS: @(#) $Id: Var.java,v 1.34 2006/06/10 04:15:59 mdejong Exp $
0011:         *
0012:         */
0013:        package tcl.lang;
0014:
0015:        import java.util.*;
0016:
0017:        /*
0018:         * Implements variables in Tcl. The Var class encapsulates most of the functionality
0019:         * of the methods in generic/tclVar.c and the structure Tcl_Var from the C version.
0020:         */
0021:
0022:        public class Var {
0023:
0024:            /**
0025:             * Flag bits for variables. The first three (SCALAR, ARRAY, and
0026:             * LINK) are mutually exclusive and give the "type" of the variable.
0027:             * UNDEFINED is independent of the variable's type. Note that
0028:             * using an int field here instead of allocating 9 boolean
0029:             * members makes the resulting object take up less memory.
0030:             * If there were only 8 boolean fields then the size of
0031:             * the Var object would be the same.
0032:             *
0033:             * SCALAR -			1 means this is a scalar variable and not
0034:             *				an array or link. The tobj field contains
0035:             *				the variable's value.
0036:             * ARRAY -			1 means this is an array variable rather
0037:             *				than a scalar variable or link. The
0038:             *				arraymap field points to the array's
0039:             *				hashtable for its elements.
0040:             * LINK -			1 means this Var structure contains a
0041:             *				reference to another Var structure that
0042:             *				either has the real value or is itself
0043:             *				another LINK pointer. Variables like
0044:             *				this come about through "upvar" and "global"
0045:             *				commands, or through references to variables
0046:             *				in enclosing namespaces.
0047:             * UNDEFINED -		1 means that the variable is in the process
0048:             *				of being deleted. An undefined variable
0049:             *				logically does not exist and survives only
0050:             *				while it has a trace, or if it is a global
0051:             *				variable currently being used by some
0052:             *				procedure.
0053:             * IN_HASHTABLE -		1 means this variable is in a hashtable. 0 if
0054:             *				a local variable that was assigned a slot
0055:             *				in a procedure frame by	the compiler so the
0056:             *				Var storage is part of the call frame.
0057:             * TRACE_EXISTS -		1 means that trace(s) exist on this
0058:             *				scalar or array variable. This flag is
0059:             *				set when (var.traces == null), it is
0060:             *				cleared when there are no more traces.
0061:             * TRACE_ACTIVE -		1 means that trace processing is currently
0062:             *				underway for a read or write access, so
0063:             *				new read or write accesses should not cause
0064:             *				trace procedures to be called and the
0065:             *				variable can't be deleted.
0066:             * ARRAY_ELEMENT -		1 means that this variable is an array
0067:             *				element, so it is not legal for it to be
0068:             *				an array itself (the ARRAY flag had
0069:             *				better not be set).
0070:             * NAMESPACE_VAR -		1 means that this variable was declared
0071:             *				as a namespace variable. This flag ensures
0072:             *				it persists until its namespace is
0073:             *				destroyed or until the variable is unset;
0074:             *				it will persist even if it has not been
0075:             *				initialized and is marked undefined.
0076:             *				The variable's refCount is incremented to
0077:             *				reflect the "reference" from its namespace.
0078:             * NO_CACHE -		1 means that code should not be able to hold
0079:             *				a cached reference to this variable. This flag
0080:             *				is only set for Var objects returned by
0081:             *				a namespace or interp resolver. It is not possible
0082:             *				to clear this flag, so the variable can't
0083:             *				be cached as long as it is alive.
0084:             * NON_LOCAL -		1 means that the variable exists in the
0085:             *				compiled local table, but it is not a
0086:             *				local or imported local. This flag is
0087:             *				only set in compiled code when scoped
0088:             *				global var refs like $::myvar are found.
0089:             *				These variables are not considered part
0090:             *				of a variable frame and can't be found
0091:             *				at runtime.
0092:             */
0093:
0094:            static final int SCALAR = 0x1;
0095:            static final int ARRAY = 0x2;
0096:            static final int LINK = 0x4;
0097:            static final int UNDEFINED = 0x8;
0098:            static final int IN_HASHTABLE = 0x10;
0099:            static final int TRACE_ACTIVE = 0x20;
0100:            static final int ARRAY_ELEMENT = 0x40;
0101:            static final int NAMESPACE_VAR = 0x80;
0102:            static final int NO_CACHE = 0x100;
0103:            static final int NON_LOCAL = 0x200;
0104:            static final int TRACE_EXISTS = 0x400;
0105:
0106:            // Flag used only with makeUpvar()
0107:            static final int EXPLICIT_LOCAL_NAME = 0x1000;
0108:
0109:            // Methods to read various flag bits of variables.
0110:
0111:            final boolean isVarScalar() {
0112:                return ((flags & SCALAR) != 0);
0113:            }
0114:
0115:            final boolean isVarLink() {
0116:                return ((flags & LINK) != 0);
0117:            }
0118:
0119:            final boolean isVarArray() {
0120:                return ((flags & ARRAY) != 0);
0121:            }
0122:
0123:            final boolean isVarUndefined() {
0124:                return ((flags & UNDEFINED) != 0);
0125:            }
0126:
0127:            final boolean isVarArrayElement() {
0128:                return ((flags & ARRAY_ELEMENT) != 0);
0129:            }
0130:
0131:            final boolean isVarNamespace() {
0132:                return ((flags & NAMESPACE_VAR) != 0);
0133:            }
0134:
0135:            final boolean isVarInHashtable() {
0136:                return ((flags & IN_HASHTABLE) != 0);
0137:            }
0138:
0139:            final boolean isVarTraceExists() {
0140:                return ((flags & TRACE_EXISTS) != 0);
0141:            }
0142:
0143:            final boolean isVarNoCache() {
0144:                return ((flags & NO_CACHE) != 0);
0145:            }
0146:
0147:            // True when a compiled local variable should
0148:            // not be a member of the var frame.
0149:
0150:            final boolean isVarNonLocal() {
0151:                return ((flags & NON_LOCAL) != 0);
0152:            }
0153:
0154:            // Methods to ensure that various flag bits are set properly for variables.
0155:
0156:            final void setVarScalar() {
0157:                flags = (flags & ~(ARRAY | LINK)) | SCALAR;
0158:            }
0159:
0160:            final void setVarArray() {
0161:                flags = (flags & ~(SCALAR | LINK)) | ARRAY;
0162:            }
0163:
0164:            final void setVarLink() {
0165:                flags = (flags & ~(SCALAR | ARRAY)) | LINK;
0166:            }
0167:
0168:            final void setVarArrayElement() {
0169:                flags = (flags & ~ARRAY) | ARRAY_ELEMENT;
0170:            }
0171:
0172:            final void setVarUndefined() {
0173:                flags |= UNDEFINED;
0174:            }
0175:
0176:            final void setVarNamespace() {
0177:                flags |= NAMESPACE_VAR;
0178:            }
0179:
0180:            final void setVarInHashtable() {
0181:                flags |= IN_HASHTABLE;
0182:            }
0183:
0184:            final void setVarNonLocal() {
0185:                flags |= NON_LOCAL;
0186:            }
0187:
0188:            final void setVarNoCache() {
0189:                flags |= NO_CACHE;
0190:            }
0191:
0192:            final void setVarTraceExists() {
0193:                flags |= TRACE_EXISTS;
0194:            }
0195:
0196:            final void clearVarUndefined() {
0197:                flags &= ~UNDEFINED;
0198:            }
0199:
0200:            final void clearVarInHashtable() {
0201:                flags &= ~IN_HASHTABLE;
0202:            }
0203:
0204:            final void clearVarTraceExists() {
0205:                flags &= ~TRACE_EXISTS;
0206:            }
0207:
0208:            /**
0209:             * A Var object is one of the following three types.
0210:             *
0211:             *  <li>Scalar variable - tobj is the object stored in the var.
0212:             *	<li> Array variable - arraymap is the hashtable that stores
0213:             *     all the elements. <p>
0214:             *  <li> Upvar (Link) - linkto is the variable associated by this upvar.
0215:             * </ul>
0216:             */
0217:
0218:            TclObject tobj;
0219:            HashMap arraymap;
0220:            Var linkto;
0221:
0222:            /**
0223:             * List that holds the traces that were placed in this Var
0224:             */
0225:
0226:            ArrayList traces;
0227:
0228:            ArrayList sidVec;
0229:
0230:            /**
0231:             * Miscellaneous bits of information about variable.
0232:             *
0233:             * @see Var#SCALAR
0234:             * @see Var#ARRAY
0235:             * @see Var#LINK
0236:             * @see Var#UNDEFINED
0237:             * @see Var#IN_HASHTABLE
0238:             * @see Var#TRACE_ACTIVE
0239:             * @see Var#ARRAY_ELEMENT
0240:             * @see Var#NAMESPACE_VAR
0241:             */
0242:
0243:            int flags;
0244:
0245:            /**
0246:             * If variable is in a hashtable, either the
0247:             * hash table entry that refers to this
0248:             * variable or null if the variable has been
0249:             * detached from its hash table (e.g. an
0250:             * array is deleted, but some of its
0251:             * elements are still referred to in
0252:             * upvars). null if the variable is not in a
0253:             * hashtable. This is used to delete an
0254:             * variable from its hashtable if it is no
0255:             * longer needed.
0256:             */
0257:
0258:            HashMap table;
0259:
0260:            /**
0261:             * The key under which this variable is stored in the hash table.
0262:             */
0263:
0264:            String hashKey;
0265:
0266:            /**
0267:             * Counts number of active uses of this
0268:             * variable, not including its entry in the
0269:             * call frame or the hash table: 1 for each
0270:             * additional variable whose link points
0271:             * here, 1 for each nested trace active on
0272:             * variable, and 1 if the variable is a 
0273:             * namespace variable. This record can't be
0274:             * deleted until refCount becomes 0.
0275:             */
0276:
0277:            int refCount;
0278:
0279:            /**
0280:             * Reference to the namespace that contains
0281:             * this variable. This is set only for namespace
0282:             * variables. A local variable in a procedure
0283:             * will always have a null ns field.
0284:             */
0285:
0286:            Namespace ns;
0287:
0288:            /**
0289:             * NewVar -> Var
0290:             * 
0291:             * Construct a variable and initialize its fields.
0292:             */
0293:
0294:            Var() {
0295:                tobj = null;
0296:                arraymap = null;
0297:                linkto = null;
0298:                //name     = null; // Like hashKey in Jacl
0299:                ns = null;
0300:                hashKey = null; // Like hPtr in the C implementation
0301:                table = null; // Like hPtr in the C implementation
0302:                refCount = 0;
0303:                traces = null;
0304:                //search   = null;
0305:                sidVec = null; // Like search in the C implementation
0306:                flags = (SCALAR | UNDEFINED | IN_HASHTABLE);
0307:            }
0308:
0309:            /**
0310:             * Used to create a String that describes this variable.
0311:             */
0312:
0313:            public String toString() {
0314:                StringBuffer sb = new StringBuffer();
0315:                if (ns != null) {
0316:                    sb.append(ns.fullName);
0317:                    if (ns.fullName.equals("::")) {
0318:                        sb.append(hashKey);
0319:                    } else {
0320:                        sb.append("::");
0321:                        sb.append(hashKey);
0322:                    }
0323:                } else {
0324:                    sb.append(hashKey);
0325:                }
0326:
0327:                if (isVarScalar()) {
0328:                    sb.append(" ");
0329:                    sb.append("SCALAR");
0330:                }
0331:                if (isVarLink()) {
0332:                    sb.append(" ");
0333:                    sb.append("LINK");
0334:                }
0335:                if (isVarArray()) {
0336:                    sb.append(" ");
0337:                    sb.append("ARRAY");
0338:                }
0339:                if (isVarUndefined()) {
0340:                    sb.append(" ");
0341:                    sb.append("UNDEFINED");
0342:                }
0343:                if (isVarArrayElement()) {
0344:                    sb.append(" ");
0345:                    sb.append("ARRAY_ELEMENT");
0346:                }
0347:                if (isVarNamespace()) {
0348:                    sb.append(" ");
0349:                    sb.append("NAMESPACE_VAR");
0350:                }
0351:                if (isVarInHashtable()) {
0352:                    sb.append(" ");
0353:                    sb.append("IN_HASHTABLE");
0354:                }
0355:                if (isVarTraceExists()) {
0356:                    sb.append(" ");
0357:                    sb.append("TRACE_EXISTS");
0358:                }
0359:                if (isVarNoCache()) {
0360:                    sb.append(" ");
0361:                    sb.append("NO_CACHE");
0362:                }
0363:                return sb.toString();
0364:            }
0365:
0366:            /**
0367:             * Used by ArrayCmd to create a unique searchId string.  If the 
0368:             * sidVec List is empty then simply return 1.  Else return 1 
0369:             * plus the SearchId.index value of the last Object in the vector.
0370:             * 
0371:             * @param None
0372:             * @return The int value for unique SearchId string.
0373:             */
0374:
0375:            protected int getNextIndex() {
0376:                int size = sidVec.size();
0377:                if (size == 0) {
0378:                    return 1;
0379:                }
0380:                SearchId sid = (SearchId) sidVec.get(size - 1);
0381:                return (sid.getIndex() + 1);
0382:            }
0383:
0384:            /**
0385:             * Find the SearchId that in the sidVec List that is equal the 
0386:             * unique String s and returns the iterator associated with
0387:             * that SearchId.
0388:             *
0389:             * @param s String that ia a unique identifier for a SearchId object
0390:             * @return Iterator if a match is found else null.
0391:             */
0392:
0393:            protected Iterator getSearch(String s) {
0394:                SearchId sid;
0395:                for (int i = 0; i < sidVec.size(); i++) {
0396:                    sid = (SearchId) sidVec.get(i);
0397:                    if (sid.equals(s)) {
0398:                        return sid.getIterator();
0399:                    }
0400:                }
0401:                return null;
0402:            }
0403:
0404:            /**
0405:             * Find the SearchId object in the sidVec list and remove it.
0406:             *
0407:             * @param sid String that ia a unique identifier for a SearchId object.
0408:             */
0409:
0410:            protected boolean removeSearch(String sid) {
0411:                SearchId curSid;
0412:
0413:                for (int i = 0; i < sidVec.size(); i++) {
0414:                    curSid = (SearchId) sidVec.get(i);
0415:                    if (curSid.equals(sid)) {
0416:                        sidVec.remove(i);
0417:                        return true;
0418:                    }
0419:                }
0420:                return false;
0421:            }
0422:
0423:            // End of the instance method for the Var class, the rest of the methods
0424:            // are Var related methods ported from the code in generic/tclVar.c
0425:
0426:            // The strings below are used to indicate what went wrong when a
0427:            // variable access is denied.
0428:
0429:            static final String noSuchVar = "no such variable";
0430:            static final String isArray = "variable is array";
0431:            static final String needArray = "variable isn't array";
0432:            static final String noSuchElement = "no such element in array";
0433:            static final String danglingElement = "upvar refers to element in deleted array";
0434:            static final String danglingVar = "upvar refers to variable in deleted namespace";
0435:            static final String badNamespace = "parent namespace doesn't exist";
0436:            static final String missingName = "missing variable name";
0437:
0438:            // Return true if a variable name stored in a String
0439:            // indicates an array element. For example, this
0440:            // method would return true for "foo(bar) and false
0441:            // for "foo".
0442:
0443:            public static final boolean isArrayVarname(String varName) {
0444:                final int lastInd = varName.length() - 1;
0445:                if (varName.charAt(lastInd) == ')') {
0446:                    if (varName.indexOf('(') != -1) {
0447:                        return true;
0448:                    }
0449:                }
0450:                return false;
0451:            }
0452:
0453:            /**
0454:             * TclLookupVar -> lookupVar
0455:             *
0456:             * This procedure is used by virtually all of the variable
0457:             * code to locate a variable given its name(s).
0458:             *
0459:             * @param part1 if part2 isn't NULL, this is the name of an array.
0460:             *      Otherwise, this is a full variable name that could include 
0461:             *      a parenthesized array elemnt or a scalar.
0462:             * @param part2 Name of an element within array, or null.
0463:             * @param flags Only the TCL.GLOBAL_ONLY bit matters.
0464:             * @param msg Verb to use in error messages, e.g.  "read" or "set".
0465:             * @param create OR'ed combination of CRT_PART1 and CRT_PART2.
0466:             *      Tells which entries to create if they don't already exist.
0467:             * @param throwException true if an exception should be throw if the
0468:             *	    variable cannot be found.
0469:             * @return a two element array. a[0] is the variable indicated by
0470:             *      part1 and part2, or null if the variable couldn't be
0471:             *      found and throwException is false.
0472:             *      <p>
0473:             *      If the variable is found, a[1] is the array that
0474:             *      contains the variable (or null if the variable is a scalar).
0475:             *      If the variable can't be found and either createPart1 or
0476:             *      createPart2 are true, a new as-yet-undefined (VAR_UNDEFINED)
0477:             *      variable instance is created, entered into a hash
0478:             *      table, and returned.
0479:             *      Note: it's possible that var.value of the returned variable
0480:             *      may be null (variable undefined), even if createPart1 or createPart2
0481:             *      are true (these only cause the hash table entry or array to be created).
0482:             *      For example, the variable might be a global that has been unset but
0483:             *      is still referenced by a procedure, or a variable that has been unset
0484:             *      but it only being kept in existence by a trace.
0485:             * @exception TclException if the variable cannot be found and 
0486:             *      throwException is true.
0487:             *
0488:             */
0489:
0490:            static Var[] lookupVar(Interp interp, // Interpreter to use for lookup.
0491:                    String part1, // If part2 isn't null, this is the name of
0492:                    // an array. Otherwise, this
0493:                    // is a full variable name that could
0494:                    // include a parenthesized array element.
0495:                    String part2, // Name of element within array, or null.
0496:                    int flags, // Only TCL.GLOBAL_ONLY, TCL.NAMESPACE_ONLY,
0497:                    // and TCL.LEAVE_ERR_MSG bits matter.
0498:                    String msg, // Verb to use in error messages, e.g.
0499:                    // "read" or "set". Only needed if
0500:                    // TCL.LEAVE_ERR_MSG is set in flags.
0501:                    boolean createPart1, // If true, create hash table entry for part 1
0502:                    // of name, if it doesn't already exist. If
0503:                    // false, return error if it doesn't exist.
0504:                    boolean createPart2 // If true, create hash table entry for part 2
0505:            // of name, if it doesn't already exist. If
0506:            // false, throw exception if it doesn't exist.
0507:            ) throws TclException {
0508:                CallFrame varFrame = interp.varFrame;
0509:                // Reference to the procedure call frame whose
0510:                // variables are currently in use. Same as
0511:                // the current procedure's frame, if any,
0512:                // unless an "uplevel" is executing.
0513:                HashMap table; // to the hashtable, if any, in which
0514:                // to look up the variable.
0515:                Var var; // Used to search for global names.
0516:                String elName; // Name of array element or null.
0517:                int openParen;
0518:                // If this procedure parses a name into
0519:                // array and index, these point to the
0520:                // parens around the index.  Otherwise they
0521:                // are -1. These are needed to restore
0522:                // the parens after parsing the name.
0523:                Namespace varNs, cxtNs;
0524:                Interp.ResolverScheme res;
0525:
0526:                var = null;
0527:                varNs = null; // set non-null if a nonlocal variable
0528:
0529:                // Parse part1 into array name and index.
0530:                // Always check if part1 is an array element name and allow it only if
0531:                // part2 is not given.
0532:                // (if one does not care about creating array elements that can't be used
0533:                // from tcl, and prefer slightly better performance, one can put
0534:                // the following in an   if (part2 == null) { ... } block and remove
0535:                // the part2's test and error reporting  or move that code in array set)
0536:
0537:                elName = part2;
0538:                openParen = -1;
0539:                int lastInd = part1.length() - 1;
0540:                if ((lastInd > 0) && (part1.charAt(lastInd) == ')')) {
0541:                    openParen = part1.indexOf('(');
0542:                }
0543:                if (openParen != -1) {
0544:                    if (part2 != null) {
0545:                        if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0546:                            throw new TclVarException(interp, part1, part2,
0547:                                    msg, needArray);
0548:                        }
0549:                        return null;
0550:                    }
0551:                    elName = part1.substring(openParen + 1, lastInd);
0552:                    part2 = elName; // same as elName, only used in error reporting
0553:                    part1 = part1.substring(0, openParen);
0554:                }
0555:
0556:                // If this namespace has a variable resolver, then give it first
0557:                // crack at the variable resolution.  It may return a Var
0558:                // value, it may signal to continue onward, or it may signal
0559:                // an error.
0560:
0561:                if (((flags & TCL.GLOBAL_ONLY) != 0)
0562:                        || (interp.varFrame == null)) {
0563:                    cxtNs = interp.globalNs;
0564:                } else {
0565:                    cxtNs = interp.varFrame.ns;
0566:                }
0567:
0568:                if (cxtNs.resolver != null || interp.resolvers != null) {
0569:                    try {
0570:                        if (cxtNs.resolver != null) {
0571:                            var = cxtNs.resolver.resolveVar(interp, part1,
0572:                                    cxtNs, flags);
0573:                            if (var != null) {
0574:                                var.setVarNoCache();
0575:                            }
0576:                        } else {
0577:                            var = null;
0578:                        }
0579:
0580:                        if (var == null && interp.resolvers != null) {
0581:                            for (ListIterator iter = interp.resolvers
0582:                                    .listIterator(); var == null
0583:                                    && iter.hasNext();) {
0584:                                res = (Interp.ResolverScheme) iter.next();
0585:                                var = res.resolver.resolveVar(interp, part1,
0586:                                        cxtNs, flags);
0587:                                if (var != null) {
0588:                                    var.setVarNoCache();
0589:                                }
0590:                            }
0591:                        }
0592:                    } catch (TclException e) {
0593:                        var = null;
0594:                    }
0595:                }
0596:
0597:                // Look up part1. Look it up as either a namespace variable or as a
0598:                // local variable in a procedure call frame (varFrame).
0599:                // Interpret part1 as a namespace variable if:
0600:                //    1) so requested by a TCL.GLOBAL_ONLY or TCL.NAMESPACE_ONLY flag,
0601:                //    2) there is no active frame (we're at the global :: scope),
0602:                //    3) the active frame was pushed to define the namespace context
0603:                //       for a "namespace eval" or "namespace inscope" command,
0604:                //    4) the name has namespace qualifiers ("::"s).
0605:                // Otherwise, if part1 is a local variable, search first in the
0606:                // frame's array of compiler-allocated local variables, then in its
0607:                // hashtable for runtime-created local variables.
0608:                //
0609:                // If createPart1 and the variable isn't found, create the variable and,
0610:                // if necessary, create varFrame's local var hashtable.
0611:
0612:                if (((flags & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY)) != 0)
0613:                        || (varFrame == null) || !varFrame.isProcCallFrame
0614:                        || (part1.indexOf("::") != -1)) {
0615:                    String tail;
0616:
0617:                    // Don't pass TCL.LEAVE_ERR_MSG, we may yet create the variable,
0618:                    // or otherwise generate our own error!
0619:
0620:                    var = Namespace.findNamespaceVar(interp, part1, null, flags
0621:                            & ~TCL.LEAVE_ERR_MSG);
0622:                    if (var == null) {
0623:                        if (createPart1) { // var wasn't found so create it
0624:
0625:                            Namespace.GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
0626:                            Namespace.getNamespaceForQualName(interp, part1,
0627:                                    null, flags, gnfqnr);
0628:                            varNs = gnfqnr.ns;
0629:                            tail = gnfqnr.simpleName;
0630:
0631:                            if (varNs == null) {
0632:                                if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0633:                                    throw new TclVarException(interp, part1,
0634:                                            part2, msg, badNamespace);
0635:                                }
0636:                                return null;
0637:                            }
0638:                            if (tail == null) {
0639:                                if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0640:                                    throw new TclVarException(interp, part1,
0641:                                            part2, msg, missingName);
0642:                                }
0643:                                return null;
0644:                            }
0645:                            var = new Var();
0646:                            varNs.varTable.put(tail, var);
0647:
0648:                            // There is no hPtr member in Jacl, The hPtr combines the table
0649:                            // and the key used in a table lookup.
0650:                            var.hashKey = tail;
0651:                            var.table = varNs.varTable;
0652:
0653:                            var.ns = varNs;
0654:                        } else { // var wasn't found and not to create it
0655:                            if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0656:                                throw new TclVarException(interp, part1, part2,
0657:                                        msg, noSuchVar);
0658:                            }
0659:                            return null;
0660:                        }
0661:                    }
0662:                } else { // local var: look in frame varFrame
0663:
0664:                    if (varFrame.compiledLocals != null) { // look in compiled local array
0665:                        // Compiled local variable lookups would not
0666:                        // normally be done in compiled code via
0667:                        // lookupVar(). This lookup code would be
0668:                        // executed when a runtime get or set
0669:                        // operation is executed. A runtime get or
0670:                        // set operation could try to create a
0671:                        // var with the same name as a compiled local
0672:                        // var, so it would need to be created in the
0673:                        // compiled local array and not in the local
0674:                        // var hash table.
0675:
0676:                        Var[] compiledLocals = varFrame.compiledLocals;
0677:                        String[] compiledLocalsNames = varFrame.compiledLocalsNames;
0678:                        final int MAX = compiledLocals.length;
0679:
0680:                        for (int i = 0; i < MAX; i++) {
0681:                            if (compiledLocalsNames[i].equals(part1)) {
0682:                                Var clocal = compiledLocals[i];
0683:                                if (clocal == null) {
0684:                                    // No compiled local with this name, init it.
0685:                                    if (createPart1) {
0686:                                        var = new Var();
0687:                                        var.hashKey = part1;
0688:                                        var.clearVarInHashtable();
0689:
0690:                                        compiledLocals[i] = var;
0691:                                    }
0692:                                } else {
0693:                                    // Found existing compiled local var, make
0694:                                    // sure it is a not a scoped non-local.
0695:
0696:                                    if (clocal.isVarNonLocal()) {
0697:                                        throw new TclRuntimeError(
0698:                                                "can't lookup scoped variable \""
0699:                                                        + part1
0700:                                                        + "\" in local table");
0701:                                    }
0702:                                    var = clocal;
0703:                                }
0704:                                break;
0705:                            }
0706:                        }
0707:                    }
0708:
0709:                    if (var == null) { // look in the frame's var hash table
0710:                        table = varFrame.varTable;
0711:                        if (createPart1) {
0712:                            if (table == null) {
0713:                                table = new HashMap();
0714:                                varFrame.varTable = table;
0715:                            }
0716:                            var = (Var) table.get(part1);
0717:                            if (var == null) { // we are adding a new entry
0718:                                var = new Var();
0719:                                table.put(part1, var);
0720:
0721:                                // There is no hPtr member in Jacl, The hPtr combines
0722:                                // the table and the key used in a table lookup.
0723:                                var.hashKey = part1;
0724:                                var.table = table;
0725:                            }
0726:                        } else {
0727:                            if (table != null) {
0728:                                var = (Var) table.get(part1);
0729:                            }
0730:                            if (var == null) {
0731:                                if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0732:                                    throw new TclVarException(interp, part1,
0733:                                            part2, msg, noSuchVar);
0734:                                }
0735:                                return null;
0736:                            }
0737:                        }
0738:                    }
0739:                }
0740:
0741:                // If var is a link variable, we have a reference to some variable
0742:                // that was created through an "upvar" or "global" command. Traverse
0743:                // through any links until we find the referenced variable.
0744:
0745:                while (var.isVarLink()) {
0746:                    var = var.linkto;
0747:                }
0748:
0749:                // If we're not dealing with an array element, return var.
0750:
0751:                if (elName == null) {
0752:                    Var[] ret = interp.lookupVarResult;
0753:                    ret[0] = var;
0754:                    ret[1] = null;
0755:                    return ret;
0756:                }
0757:
0758:                return Var.lookupArrayElement(interp, part1, elName, flags,
0759:                        msg, createPart1, createPart2, var);
0760:            }
0761:
0762:            /* Given a ref to an array Var object, lookup the element
0763:             * in the array indicated by "part2". */
0764:
0765:            static Var[] lookupArrayElement(Interp interp, // Interpreter to use for lookup.
0766:                    String part1, // The name of an array, can't include elem.
0767:                    String part2, // Name of element within array, can't be null.
0768:                    int flags, // Only TCL.GLOBAL_ONLY, TCL.NAMESPACE_ONLY,
0769:                    // and TCL.LEAVE_ERR_MSG bits matter.
0770:                    String msg, // Verb to use in error messages, e.g.
0771:                    // "read" or "set". Only needed if
0772:                    // TCL.LEAVE_ERR_MSG is set in flags.
0773:                    boolean createPart1, // If true, create hash table entry for part 1
0774:                    // of name, if it doesn't already exist. If
0775:                    // false, return error if it doesn't exist.
0776:                    boolean createPart2, // If true, create hash table entry for part 2
0777:                    // of name, if it doesn't already exist. If
0778:                    // false, throw exception if it doesn't exist.
0779:                    Var var // Resolved ref to the array variable.
0780:            ) throws TclException {
0781:                // We're dealing with an array element. Make sure the variable is an
0782:                // array and look up the element (create the element if desired).
0783:
0784:                if (var.isVarUndefined() && !var.isVarArrayElement()) {
0785:                    if (!createPart1) {
0786:                        if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0787:                            throw new TclVarException(interp, part1, part2,
0788:                                    msg, noSuchVar);
0789:                        }
0790:                        return null;
0791:                    }
0792:
0793:                    // Make sure we are not resurrecting a namespace variable from a
0794:                    // deleted namespace!
0795:
0796:                    if (((var.flags & IN_HASHTABLE) != 0)
0797:                            && (var.table == null)) {
0798:                        if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0799:                            throw new TclVarException(interp, part1, part2,
0800:                                    msg, danglingVar);
0801:                        }
0802:                        return null;
0803:                    }
0804:
0805:                    var.setVarArray();
0806:                    var.clearVarUndefined();
0807:                    var.arraymap = new HashMap();
0808:                } else if (!var.isVarArray()) {
0809:                    if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0810:                        throw new TclVarException(interp, part1, part2, msg,
0811:                                needArray);
0812:                    }
0813:                    return null;
0814:                }
0815:
0816:                Var arrayVar = var;
0817:                HashMap arrayTable = var.arraymap;
0818:                if (createPart2) {
0819:                    Var searchvar = (Var) arrayTable.get(part2);
0820:
0821:                    if (searchvar == null) { // new entry
0822:                        if (var.sidVec != null) {
0823:                            deleteSearches(var);
0824:                        }
0825:
0826:                        var = new Var();
0827:                        arrayTable.put(part2, var);
0828:
0829:                        // There is no hPtr member in Jacl, The hPtr combines the table
0830:                        // and the key used in a table lookup.
0831:                        var.hashKey = part2;
0832:                        var.table = arrayTable;
0833:
0834:                        var.ns = arrayVar.ns; // Will be null for local vars
0835:                        var.setVarArrayElement();
0836:                    } else {
0837:                        var = searchvar;
0838:                    }
0839:                } else {
0840:                    var = (Var) arrayTable.get(part2);
0841:                    if (var == null) {
0842:                        if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0843:                            throw new TclVarException(interp, part1, part2,
0844:                                    msg, noSuchElement);
0845:                        }
0846:                        return null;
0847:                    }
0848:                }
0849:
0850:                Var[] ret = interp.lookupVarResult;
0851:                ret[0] = var; // The Var in the array
0852:                ret[1] = arrayVar; // The array Var
0853:                return ret;
0854:            }
0855:
0856:            /**
0857:             * Tcl_GetVar2Ex -> getVar
0858:             *
0859:             * Query the value of a variable, given a two-part name consisting
0860:             * of array name and element within array.
0861:             *
0862:             * @param interp the interp that holds the variable
0863:             * @param part1 1st part of the variable name.
0864:             * @param part2 2nd part of the variable name.
0865:             * @param flags misc flags that control the actions of this method.
0866:             * @return the value of the variable.
0867:             */
0868:
0869:            static TclObject getVar(Interp interp, // interpreter to look for the var in
0870:                    String part1, // Name of an array (if part2 is non-null)
0871:                    // or the name of a variable.
0872:                    String part2, // If non-null, gives the name of an element
0873:                    // in the array part1.
0874:                    int flags // OR-ed combination of TCL.GLOBAL_ONLY,
0875:            // and TCL.LEAVE_ERR_MSG bits.
0876:            ) throws TclException {
0877:                Var[] result = lookupVar(interp, part1, part2, flags, "read",
0878:                        false, true);
0879:
0880:                if (result == null) {
0881:                    // lookupVar() returns null only if TCL.LEAVE_ERR_MSG is
0882:                    // not part of the flags argument, return null in this case.
0883:
0884:                    return null;
0885:                }
0886:
0887:                return getVarPtr(interp, result[0], result[1], part1, part2,
0888:                        flags);
0889:            }
0890:
0891:            /**
0892:             * TclPtrGetVar -> getVarPtr
0893:             *
0894:             * Query the value of a variable, given refs to the variables
0895:             * Var objects.
0896:             *
0897:             * @param interp the interp that holds the variable
0898:             * @param part1 1st part of the variable name.
0899:             * @param part2 2nd part of the variable name.
0900:             * @param flags misc flags that control the actions of this method.
0901:             * @return the value of the variable.
0902:             */
0903:
0904:            static TclObject getVarPtr(Interp interp, // interpreter to look for the var in
0905:                    Var var, Var array, String part1, // Name of an array (if part2 is non-null)
0906:                    // or the name of a variable.
0907:                    String part2, // If non-null, gives the name of an element
0908:                    // in the array part1.
0909:                    int flags // OR-ed combination of TCL.GLOBAL_ONLY,
0910:            // and TCL.LEAVE_ERR_MSG bits.
0911:            ) throws TclException {
0912:                try {
0913:                    // Invoke any traces that have been set for the variable.
0914:
0915:                    if ((var.traces != null)
0916:                            || ((array != null) && (array.traces != null))) {
0917:                        String msg = callTraces(
0918:                                interp,
0919:                                array,
0920:                                var,
0921:                                part1,
0922:                                part2,
0923:                                (flags & (TCL.NAMESPACE_ONLY | TCL.GLOBAL_ONLY))
0924:                                        | TCL.TRACE_READS);
0925:                        if (msg != null) {
0926:                            if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0927:                                throw new TclVarException(interp, part1, part2,
0928:                                        "read", msg);
0929:                            }
0930:                            return null;
0931:                        }
0932:                    }
0933:
0934:                    if (var.isVarScalar() && !var.isVarUndefined()) {
0935:                        return var.tobj;
0936:                    }
0937:
0938:                    if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
0939:                        String msg;
0940:                        if (var.isVarUndefined() && (array != null)
0941:                                && !array.isVarUndefined()) {
0942:                            msg = noSuchElement;
0943:                        } else if (var.isVarArray()) {
0944:                            msg = isArray;
0945:                        } else {
0946:                            msg = noSuchVar;
0947:                        }
0948:                        throw new TclVarException(interp, part1, part2, "read",
0949:                                msg);
0950:                    }
0951:                } finally {
0952:                    // If the variable doesn't exist anymore and no-one's using it,
0953:                    // then free up the relevant structures and hash table entries.
0954:
0955:                    if (var.isVarUndefined()) {
0956:                        cleanupVar(var, array);
0957:                    }
0958:                }
0959:
0960:                return null;
0961:            }
0962:
0963:            /**
0964:             * Tcl_SetVar2Ex -> setVar
0965:             *
0966:             *	Given a two-part variable name, which may refer either to a scalar
0967:             *	variable or an element of an array, change the value of the variable
0968:             *	to a new Tcl object value. See the setVarPtr() method for the
0969:             *	arguments to be passed to this method.
0970:             */
0971:
0972:            static TclObject setVar(Interp interp, // interp to search for the var in
0973:                    String part1, // Name of an array (if part2 is non-null)
0974:                    // or the name of a variable.
0975:                    String part2, // If non-null, gives the name of an element
0976:                    // in the array part1.
0977:                    TclObject newValue, // New value for variable.
0978:                    int flags // Various flags that tell how to set value:
0979:            // any of TCL.GLOBAL_ONLY,
0980:            // TCL.NAMESPACE_ONLY, TCL.APPEND_VALUE,
0981:            // TCL.LIST_ELEMENT or TCL.LEAVE_ERR_MSG.
0982:            ) throws TclException {
0983:                Var[] result = lookupVar(interp, part1, part2, flags, "set",
0984:                        true, true);
0985:                if (result == null) {
0986:                    return null;
0987:                }
0988:
0989:                return setVarPtr(interp, result[0], result[1], part1, part2,
0990:                        newValue, flags);
0991:            }
0992:
0993:            /**
0994:             * TclPtrSetVar -> setVarPtr
0995:             *
0996:             *	This method implements setting of a variable value that has
0997:             *	already been resolved into Var refrences. Pass the resolved
0998:             *	var refrences and a two-part variable name, which may refer
0999:             *	either to a scalar or an element of an array. This method will
1000:             *	change the value of the variable to a new TclObject value.
1001:             *	If the named scalar or array or element
1002:             *	doesn't exist then this method will create one.
1003:             *
1004:             * @param interp the interp that holds the variable
1005:             * @param var a resolved Var ref
1006:             * @param array a resolved Var ref
1007:             * @param part1 1st part of the variable name.
1008:             * @param part2 2nd part of the variable name.
1009:             * @param newValue the new value for the variable
1010:             * @param flags misc flags that control the actions of this method
1011:             *
1012:             *	Returns a pointer to the TclObject holding the new value of the
1013:             *	variable. If the write operation was disallowed because an array was
1014:             *	expected but not found (or vice versa), then null is returned; if
1015:             *	the TCL.LEAVE_ERR_MSG flag is set, then an exception will be raised.
1016:             *  Note that the returned object may not be the same one referenced
1017:             *  by newValue because variable traces may modify the variable's value.
1018:             *	The value of the given variable is set. If either the array or the
1019:             *	entry didn't exist then a new variable is created.
1020:             *
1021:             *	The reference count is decremented for any old value of the variable
1022:             *	and incremented for its new value. If the new value for the variable
1023:             *	is not the same one referenced by newValue (perhaps as a result
1024:             *	of a variable trace), then newValue's ref count is left unchanged
1025:             *	by Tcl_SetVar2Ex. newValue's ref count is also left unchanged if
1026:             *	we are appending it as a string value: that is, if "flags" includes
1027:             *	TCL.APPEND_VALUE but not TCL.LIST_ELEMENT.
1028:             *
1029:             *	The reference count for the returned object is _not_ incremented: if
1030:             *	you want to keep a reference to the object you must increment its
1031:             *	ref count yourself.
1032:             */
1033:
1034:            static TclObject setVarPtr(Interp interp, // interp to search for the var in
1035:                    Var var, Var array, String part1, // Name of an array (if part2 is non-null)
1036:                    // or the name of a variable.
1037:                    String part2, // If non-null, gives the name of an element
1038:                    // in the array part1.
1039:                    TclObject newValue, // New value for variable.
1040:                    int flags // Various flags that tell how to set value:
1041:            // any of TCL.GLOBAL_ONLY,
1042:            // TCL.NAMESPACE_ONLY, TCL.APPEND_VALUE,
1043:            // TCL.LIST_ELEMENT or TCL.LEAVE_ERR_MSG.
1044:            ) throws TclException {
1045:                TclObject oldValue;
1046:                String bytes;
1047:
1048:                // If the variable is in a hashtable and its table field is null, then we
1049:                // may have an upvar to an array element where the array was deleted
1050:                // or an upvar to a namespace variable whose namespace was deleted.
1051:                // Generate an error (allowing the variable to be reset would screw up
1052:                // our storage allocation and is meaningless anyway).
1053:
1054:                if (((var.flags & IN_HASHTABLE) != 0) && (var.table == null)) {
1055:                    if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
1056:                        if (var.isVarArrayElement()) {
1057:                            throw new TclVarException(interp, part1, part2,
1058:                                    "set", danglingElement);
1059:                        } else {
1060:                            throw new TclVarException(interp, part1, part2,
1061:                                    "set", danglingVar);
1062:                        }
1063:                    }
1064:                    return null;
1065:                }
1066:
1067:                // It's an error to try to set an array variable itself.
1068:
1069:                if (var.isVarArray() && !var.isVarUndefined()) {
1070:                    if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
1071:                        throw new TclVarException(interp, part1, part2, "set",
1072:                                isArray);
1073:                    }
1074:                    return null;
1075:                }
1076:
1077:                // At this point, if we were appending, we used to call read traces: we
1078:                // treated append as a read-modify-write. However, it seemed unlikely to
1079:                // us that a real program would be interested in such reads being done
1080:                // during a set operation.
1081:
1082:                // Set the variable's new value. If appending, append the new value to
1083:                // the variable, either as a list element or as a string. Also, if
1084:                // appending, then if the variable's old value is unshared we can modify
1085:                // it directly, otherwise we must create a new copy to modify: this is
1086:                // "copy on write".
1087:
1088:                try {
1089:                    oldValue = var.tobj;
1090:
1091:                    if ((flags & TCL.APPEND_VALUE) != 0) {
1092:                        if (var.isVarUndefined() && (oldValue != null)) {
1093:                            oldValue.release(); // discard old value
1094:                            var.tobj = null;
1095:                            oldValue = null;
1096:                        }
1097:                        if ((flags & TCL.LIST_ELEMENT) != 0) { // append list element
1098:                            if (oldValue == null) {
1099:                                oldValue = TclList.newInstance();
1100:                                var.tobj = oldValue;
1101:                                oldValue.preserve(); // since var is referenced
1102:                            } else if (oldValue.isShared()) { // append to copy
1103:                                var.tobj = oldValue.duplicate();
1104:                                oldValue.release();
1105:                                oldValue = var.tobj;
1106:                                oldValue.preserve(); // since var is referenced
1107:                            }
1108:                            TclList.append(interp, oldValue, newValue);
1109:                        } else { // append string
1110:                            // We append newValue's bytes but don't change its ref count.
1111:
1112:                            bytes = newValue.toString();
1113:                            if (oldValue == null) {
1114:                                var.tobj = TclString.newInstance(bytes);
1115:                                var.tobj.preserve();
1116:                            } else {
1117:                                if (oldValue.isShared()) { // append to copy
1118:                                    var.tobj = oldValue.duplicate();
1119:                                    oldValue.release();
1120:                                    oldValue = var.tobj;
1121:                                    oldValue.preserve(); // since var is referenced
1122:                                }
1123:                                TclString.append(oldValue, bytes);
1124:                            }
1125:                        }
1126:                    } else {
1127:                        if ((flags & TCL.LIST_ELEMENT) != 0) { // set var to list element
1128:                            int listFlags;
1129:
1130:                            // We set the variable to the result of converting newValue's
1131:                            // string rep to a list element. We do not change newValue's
1132:                            // ref count.
1133:
1134:                            if (oldValue != null) {
1135:                                oldValue.release(); // discard old value
1136:                            }
1137:                            bytes = newValue.toString();
1138:                            listFlags = Util.scanElement(interp, bytes);
1139:                            StringBuffer sb = new StringBuffer(64);
1140:                            Util.convertElement(bytes, listFlags, sb);
1141:                            oldValue = TclString.newInstance(sb.toString());
1142:                            var.tobj = oldValue;
1143:                            var.tobj.preserve();
1144:                        } else if (newValue != oldValue) {
1145:                            var.tobj = newValue;
1146:                            newValue.preserve(); // var is another ref
1147:                            if (oldValue != null) {
1148:                                oldValue.release(); // discard old value
1149:                            }
1150:                        }
1151:                    }
1152:                    var.setVarScalar();
1153:                    var.clearVarUndefined();
1154:                    if (array != null) {
1155:                        array.clearVarUndefined();
1156:                    }
1157:
1158:                    // Invoke any write traces for the variable.
1159:
1160:                    if ((var.traces != null)
1161:                            || ((array != null) && (array.traces != null))) {
1162:
1163:                        String msg = callTraces(
1164:                                interp,
1165:                                array,
1166:                                var,
1167:                                part1,
1168:                                part2,
1169:                                (flags & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY))
1170:                                        | TCL.TRACE_WRITES);
1171:                        if (msg != null) {
1172:                            if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
1173:                                throw new TclVarException(interp, part1, part2,
1174:                                        "set", msg);
1175:                            }
1176:                            return null; // Same as "goto cleanup" in C verison
1177:                        }
1178:                    }
1179:
1180:                    // Return the variable's value unless the variable was changed in some
1181:                    // gross way by a trace (e.g. it was unset and then recreated as an
1182:                    // array).
1183:
1184:                    if (var.isVarScalar() && !var.isVarUndefined()) {
1185:                        return var.tobj;
1186:                    }
1187:
1188:                    // A trace changed the value in some gross way. Return an empty string
1189:                    // object.
1190:
1191:                    return TclString.newInstance("");
1192:                } finally {
1193:                    // If the variable doesn't exist anymore and no-one's using it,
1194:                    // then free up the relevant structures and hash table entries.
1195:
1196:                    if (var.isVarUndefined()) {
1197:                        cleanupVar(var, array);
1198:                    }
1199:                }
1200:            }
1201:
1202:            // This method is invoked to initialize a new compiled
1203:            // local scalar variable when the compiled local slot
1204:            // is null. Initializing a compiled local scalar is
1205:            // a very common operation, so it is highly optimized here.
1206:
1207:            static TclObject initVarCompiledLocalScalar(final Interp interp, // interp to search for the var in
1208:                    final String varname, // Name of scalar variable.
1209:                    final TclObject newValue, // New value for scalar variable.
1210:                    final Var[] compiledLocals, // compiled local array
1211:                    final int localIndex) // index into compiled local array, 0 to N.
1212:                    throws TclException {
1213:                // Extra checking
1214:                final boolean validate = false;
1215:
1216:                if (validate) {
1217:                    CallFrame varFrame = interp.varFrame;
1218:
1219:                    if (varFrame == null) {
1220:                        throw new TclRuntimeError("null interp.varFrame");
1221:                    }
1222:                    if (varFrame != interp.frame) {
1223:                        throw new TclRuntimeError(
1224:                                "interp.frame vs interp.varFrame mismatch");
1225:                    }
1226:                    if (varFrame.isProcCallFrame == false) {
1227:                        throw new TclRuntimeError(
1228:                                "expected isProcCallFrame to be true");
1229:                    }
1230:                    if (varFrame.compiledLocals == null) {
1231:                        throw new TclRuntimeError(
1232:                                "expected non-null compiledLocals");
1233:                    }
1234:
1235:                    // Double check that scalar name is not actually an array
1236:                    // name like "arr(foo)".
1237:
1238:                    if (Var.isArrayVarname(varname)) {
1239:                        throw new TclRuntimeError(
1240:                                "unexpected array variable name \"" + varname
1241:                                        + "\"");
1242:                    }
1243:
1244:                    // Look in local table, there should not be an entry
1245:                    HashMap table = varFrame.varTable;
1246:
1247:                    if (table != null && table.size() > 0) {
1248:                        Var var = (Var) table.get(varname);
1249:                        if (var != null) {
1250:                            throw new TclException(interp,
1251:                                    "duplicate var found in local table for "
1252:                                            + varname);
1253:                        }
1254:                    }
1255:
1256:                    if (compiledLocals[localIndex] != null) {
1257:                        throw new TclException(interp,
1258:                                "compiled local slot should be null for "
1259:                                        + varname);
1260:                    }
1261:
1262:                    // A compiled local that is a scoped value would never
1263:                    // be initialized by this method.
1264:
1265:                    if (varname.indexOf("::") != -1) {
1266:                        throw new TclRuntimeError(
1267:                                "scoped scalar should neve be initialized here "
1268:                                        + varname);
1269:                    }
1270:
1271:                } // end if (validate) block
1272:
1273:                // At this point, we know that a var with the
1274:                // same name can't exist in the local table.
1275:                // We also know that the compiled local slot
1276:                // is null, so the var can't exist in an
1277:                // undefined state. There are no funky state
1278:                // issues like a var with traces set or
1279:                // a var in another frame linked to this one.
1280:                // The varname will always be a simple scalar.
1281:
1282:                Var var = new Var();
1283:                if (validate) {
1284:                    // Double check Var init state assumptions.
1285:                    if (var.flags != (SCALAR | UNDEFINED | IN_HASHTABLE)) {
1286:                        throw new TclRuntimeError("invalid Var flags state");
1287:                    }
1288:                    if (var.tobj != null) {
1289:                        throw new TclRuntimeError(
1290:                                "expected null Var tobj value");
1291:                    }
1292:                    if (var.arraymap != null) {
1293:                        throw new TclRuntimeError(
1294:                                "expected null Var arraymap value");
1295:                    }
1296:                    if (var.linkto != null) {
1297:                        throw new TclRuntimeError(
1298:                                "expected null Var linkto value");
1299:                    }
1300:                    if (var.table != null) {
1301:                        throw new TclRuntimeError("expected null Var table");
1302:                    }
1303:                }
1304:
1305:                // Inline Var init and setVarPtr() logic that applies to
1306:                // scalar variables.
1307:
1308:                //var.setVarScalar();
1309:                //var.clearVarInHashtable();
1310:                //var.clearVarUndefined();
1311:                var.flags = SCALAR;
1312:
1313:                var.hashKey = varname;
1314:
1315:                // Assign TclObject value for scalar and incr ref count
1316:
1317:                var.tobj = newValue;
1318:                newValue.preserve();
1319:
1320:                // Add var to the compiled local array.
1321:
1322:                compiledLocals[localIndex] = var;
1323:
1324:                return newValue;
1325:            }
1326:
1327:            // This method is invoked to set a compiled local scalar
1328:            // variable when the resolved var is invalid. It will
1329:            // never be invoked when the compiled local slot is null.
1330:            // This method is not in the critical execution path.
1331:
1332:            static TclObject setVarCompiledLocalScalarInvalid(Interp interp, // interp to search for the var in
1333:                    String varname, // Name of scalar variable.
1334:                    TclObject newValue) // New value for scalar variable.
1335:                    throws TclException {
1336:                // Extra checking
1337:                final boolean validate = false;
1338:
1339:                if (validate) {
1340:                    // Lookup current variable frame on the stack. This method
1341:                    // is only even invoked after a CallFrame with a compiled
1342:                    // local array has already been pushed onto the stack.
1343:
1344:                    CallFrame varFrame = interp.varFrame;
1345:
1346:                    if (varFrame == null) {
1347:                        throw new TclRuntimeError("null interp.varFrame");
1348:                    }
1349:                    if (varFrame != interp.frame) {
1350:                        throw new TclRuntimeError(
1351:                                "interp.frame vs interp.varFrame mismatch");
1352:                    }
1353:                    if (varFrame.isProcCallFrame == false) {
1354:                        throw new TclRuntimeError(
1355:                                "expected isProcCallFrame to be true");
1356:                    }
1357:
1358:                    // Double check that scalar name is not actually an array
1359:                    // name like "arr(foo)".
1360:
1361:                    if (Var.isArrayVarname(varname)) {
1362:                        throw new TclRuntimeError(
1363:                                "unexpected array variable name \"" + varname
1364:                                        + "\"");
1365:                    }
1366:
1367:                    // A scoped var name should always be initialized
1368:                    // as a link var. A non-global scoped link var
1369:                    // should never be pass in here.
1370:
1371:                    if (!varname.startsWith("::")
1372:                            && (-1 != varname.indexOf("::"))) {
1373:                        throw new TclRuntimeError("unexpected scoped scalar");
1374:                    }
1375:
1376:                } // end if (validate) block
1377:
1378:                // This method would never be invoked with a null
1379:                // compiled locals slot. It could be invoked when
1380:                // the compiled local is unset, has traces,
1381:                // or when the link var is unset or has traces.
1382:
1383:                return setVar(interp, varname, null, newValue,
1384:                        TCL.LEAVE_ERR_MSG);
1385:            }
1386:
1387:            // This method is invoked to get the value of a
1388:            // scalar variable that does not have a valid
1389:            // resolved ref. This method could be invoked
1390:            // when traces are set on a compiled local,
1391:            // for example. This method is only
1392:            // ever invoked from a compiled proc
1393:            // implementation. This method is not in the
1394:            // critical execution path.
1395:
1396:            static TclObject getVarCompiledLocalScalarInvalid(Interp interp, // interp to search for the var in
1397:                    String varname) // Name of scalar variable.
1398:                    throws TclException {
1399:                // Extra checking
1400:                final boolean validate = false;
1401:
1402:                if (validate) {
1403:                    CallFrame varFrame = interp.varFrame;
1404:
1405:                    if (varFrame == null) {
1406:                        throw new TclRuntimeError("null interp.varFrame");
1407:                    }
1408:                    if (varFrame != interp.frame) {
1409:                        throw new TclRuntimeError(
1410:                                "interp.frame vs interp.varFrame mismatch");
1411:                    }
1412:
1413:                    if (varFrame.isProcCallFrame == false) {
1414:                        throw new TclRuntimeError(
1415:                                "expected isProcCallFrame to be true");
1416:                    }
1417:                    if (varFrame.compiledLocals == null) {
1418:                        throw new TclRuntimeError(
1419:                                "expected non-null compiledLocals");
1420:                    }
1421:
1422:                    if (varname == null) {
1423:                        throw new TclRuntimeError("varname can't be null");
1424:                    }
1425:
1426:                    // Double check that varname is not actually an array
1427:                    // name like "arr(foo)".
1428:
1429:                    if ((varname.charAt(varname.length() - 1) == ')')
1430:                            && (varname.indexOf('(') != -1)) {
1431:                        throw new TclRuntimeError(
1432:                                "unexpected array variable name \"" + varname
1433:                                        + "\"");
1434:                    }
1435:
1436:                    // A non-global scoped link var should never be passed in here.
1437:
1438:                    if (!varname.startsWith("::")
1439:                            && (-1 != varname.indexOf("::"))) {
1440:                        throw new TclRuntimeError("unexpected scoped scalar");
1441:                    }
1442:                }
1443:
1444:                return Var.getVar(interp, varname, null, TCL.LEAVE_ERR_MSG);
1445:            }
1446:
1447:            // This method is invoked to initialize a new compiled
1448:            // local array variable when the compiled local slot
1449:            // is null. Initializing a compiled local array is
1450:            // a very common operation, so it is optimized.
1451:
1452:            static TclObject initVarCompiledLocalArray(final Interp interp, // interp to search for the var in
1453:                    final String varname, // Name of scalar variable.
1454:                    final String key, // Array key, can't be null
1455:                    final TclObject newValue, // New value for array entry variable.
1456:                    final Var[] compiledLocals, // compiled local array
1457:                    final int localIndex) // index into compiled local array, 0 to N.
1458:                    throws TclException {
1459:                // Extra checking
1460:                final boolean validate = false;
1461:
1462:                if (validate) {
1463:                    // Lookup current variable frame on the stack. This method
1464:                    // is only even invoked after a CallFrame with a compiled
1465:                    // local array has already been pushed onto the stack.
1466:
1467:                    CallFrame varFrame = interp.varFrame;
1468:
1469:                    if (varFrame == null) {
1470:                        throw new TclRuntimeError("null interp.varFrame");
1471:                    }
1472:                    if (varFrame != interp.frame) {
1473:                        throw new TclRuntimeError(
1474:                                "interp.frame vs interp.varFrame mismatch");
1475:                    }
1476:                    if (varFrame.isProcCallFrame == false) {
1477:                        throw new TclRuntimeError(
1478:                                "expected isProcCallFrame to be true");
1479:                    }
1480:                    if (varFrame.compiledLocals == null) {
1481:                        throw new TclRuntimeError(
1482:                                "expected non-null compiledLocals");
1483:                    }
1484:
1485:                    // Double check that varname is not actually an array
1486:                    // name like "arr(foo)". A compiled array name should be
1487:                    // seperated into two elements.
1488:
1489:                    if (Var.isArrayVarname(varname)) {
1490:                        throw new TclRuntimeError(
1491:                                "unexpected array variable name \"" + varname
1492:                                        + "\"");
1493:                    }
1494:
1495:                    if (key == null) {
1496:                        throw new TclRuntimeError("null array key");
1497:                    }
1498:
1499:                    // Look in local table, there should not be an entry for this varname
1500:                    HashMap table = varFrame.varTable;
1501:
1502:                    if (table != null && table.size() > 0) {
1503:                        Var var = (Var) table.get(varname);
1504:                        if (var != null) {
1505:                            throw new TclException(interp,
1506:                                    "duplicate var found in local table for "
1507:                                            + varname);
1508:                        }
1509:                    }
1510:
1511:                    if (compiledLocals[localIndex] != null) {
1512:                        throw new TclException(interp,
1513:                                "compiled local slot should be null for "
1514:                                        + varname);
1515:                    }
1516:
1517:                    // A compiled local that is a scoped value would never
1518:                    // be initialized by this method.
1519:
1520:                    if (varname.indexOf("::") != -1) {
1521:                        throw new TclRuntimeError(
1522:                                "scoped scalar should neve be initialized here "
1523:                                        + varname);
1524:                    }
1525:
1526:                } // end if (validate)
1527:
1528:                // At this point, we know that a var with the
1529:                // same name can't exist in the local table.
1530:                // We also know that the compiled local slot
1531:                // is null, so the var can't exist in an
1532:                // undefined state. There are no funky state
1533:                // issues like a var with traces set or
1534:                // a var in another frame linked to this one.
1535:                // The varname will always be an unlinked array var.
1536:
1537:                Var var = new Var();
1538:                var.clearVarInHashtable();
1539:                var.hashKey = varname;
1540:
1541:                // Add var to the compiled local array
1542:                // so that it will be found and used
1543:                // by setVar().
1544:
1545:                compiledLocals[localIndex] = var;
1546:
1547:                // Set the variable, can't use setVarPtr()
1548:                // since lookupVar() does the array element
1549:                // create logic.
1550:
1551:                return setVar(interp, varname, key, newValue, TCL.LEAVE_ERR_MSG);
1552:            }
1553:
1554:            // This method is invoked to set a compiled local array
1555:            // variable when the resolved var is invalid. It will
1556:            // never be invoked when the compiled local slot is null.
1557:            // This method is not in the critical execution path.
1558:
1559:            static TclObject setVarCompiledLocalArrayInvalid(Interp interp, // interp to search for the var in
1560:                    String varname, // Name of scalar variable.
1561:                    String key, // Array key, can't be null
1562:                    TclObject newValue) // New value for scalar variable.
1563:                    throws TclException {
1564:                // Extra checking
1565:                final boolean validate = false;
1566:
1567:                if (validate) {
1568:                    // Lookup current variable frame on the stack. This method
1569:                    // is only even invoked after a CallFrame with a compiled
1570:                    // local array has already been pushed onto the stack.
1571:
1572:                    CallFrame varFrame = interp.varFrame;
1573:
1574:                    if (varFrame == null) {
1575:                        throw new TclRuntimeError("null interp.varFrame");
1576:                    }
1577:                    if (varFrame != interp.frame) {
1578:                        throw new TclRuntimeError(
1579:                                "interp.frame vs interp.varFrame mismatch");
1580:                    }
1581:                    if (varFrame.isProcCallFrame == false) {
1582:                        throw new TclRuntimeError(
1583:                                "expected isProcCallFrame to be true");
1584:                    }
1585:                    if (varFrame.compiledLocals == null) {
1586:                        throw new TclRuntimeError(
1587:                                "expected non-null compiledLocals");
1588:                    }
1589:
1590:                    // Double check that varname is not actually an array
1591:                    // name like "arr(foo)".
1592:
1593:                    if (Var.isArrayVarname(varname)) {
1594:                        throw new TclRuntimeError(
1595:                                "unexpected array variable name \"" + varname
1596:                                        + "\"");
1597:                    }
1598:
1599:                    if (key == null) {
1600:                        throw new TclRuntimeError("null array key");
1601:                    }
1602:
1603:                    // Look in local table, there should not be an entry for this varname
1604:                    HashMap table = varFrame.varTable;
1605:
1606:                    if (table != null && table.size() > 0) {
1607:                        Var var = (Var) table.get(varname);
1608:                        if (var != null) {
1609:                            throw new TclException(interp,
1610:                                    "duplicate var found in local table for "
1611:                                            + varname);
1612:                        }
1613:                    }
1614:
1615:                    // A compiled local that is a scoped value would never
1616:                    // be initialized by this method.
1617:
1618:                    if (varname.indexOf("::") != -1) {
1619:                        throw new TclRuntimeError(
1620:                                "scoped scalar should neve be initialized here "
1621:                                        + varname);
1622:                    }
1623:
1624:                } // end if (validate)
1625:
1626:                // The compiled local array var already exists, but it
1627:                // could not be resolved to a valid var. This can happen
1628:                // when an undefined variable linked into another scope is
1629:                // being defined for the first time. This can also
1630:                // happen when the compiled local is not an array.
1631:                // Handle these cases by invoking setVar() to either
1632:                // raise the proper error or set the var.
1633:
1634:                return setVar(interp, varname, key, newValue, TCL.LEAVE_ERR_MSG);
1635:            }
1636:
1637:            // This method is invoked to get the value of an
1638:            // array variable that is associated with a compiled
1639:            // local slot. This method is invoked when the
1640:            // compiled local slot is null or when the var
1641:            // can't be resolved to a valid array variable.
1642:            // This method will only attempt to read a variable.
1643:            // It will not init a compiled local slot.
1644:            // This method is only ever invoked from a compiled
1645:            // proc implementation. This method is not in the
1646:            // critical execution path.
1647:
1648:            static TclObject getVarCompiledLocalArrayInvalid(Interp interp, // interp to search for the var in
1649:                    String varname, // Name of array variable.
1650:                    String key) // array key, can't be null
1651:                    throws TclException {
1652:                // Extra checking
1653:                final boolean validate = false;
1654:
1655:                if (validate) {
1656:                    CallFrame varFrame = interp.varFrame;
1657:
1658:                    if (varFrame == null) {
1659:                        throw new TclRuntimeError("null interp.varFrame");
1660:                    }
1661:                    if (varFrame != interp.frame) {
1662:                        throw new TclRuntimeError(
1663:                                "interp.frame vs interp.varFrame mismatch");
1664:                    }
1665:                    if (varFrame.compiledLocals == null) {
1666:                        throw new TclRuntimeError(
1667:                                "expected non-null compiledLocals");
1668:                    }
1669:
1670:                    if (key == null) {
1671:                        throw new TclRuntimeError("array key can't be null");
1672:                    }
1673:
1674:                    // Double check that varname is not actually an array
1675:                    // name like "arr(foo)".
1676:
1677:                    if ((varname.charAt(varname.length() - 1) == ')')
1678:                            && (varname.indexOf('(') != -1)) {
1679:                        throw new TclRuntimeError(
1680:                                "unexpected array variable name \"" + varname
1681:                                        + "\"");
1682:                    }
1683:
1684:                } // end if (validate) block
1685:
1686:                return Var.getVar(interp, varname, key, TCL.LEAVE_ERR_MSG);
1687:            }
1688:
1689:            // This method is invoked to get the value of an
1690:            // array variable that is associated with a compiled
1691:            // local slot. This method is invoked when the
1692:            // compiled local slot contains a valid resolved ref.
1693:            // This method is only ever invoked from a compiled
1694:            // proc implementation. This method is in the
1695:            // critical execution path.
1696:
1697:            static TclObject getVarCompiledLocalArray(final Interp interp,
1698:                    final String varname, // name of array  variable
1699:                    final String key, // array key, can't be null
1700:                    final Var resolved, // resolved array variable
1701:                    final boolean leaveErrMsg) // If true, will raise a
1702:                    // TclException when the array
1703:                    // element does not exist. If
1704:                    // false, then return null.
1705:                    throws TclException {
1706:                int flags = 0;
1707:                if (leaveErrMsg) {
1708:                    // If leaveErrMsg is true, will raise a TclException
1709:                    // in lookupArrayElement() if the array element does
1710:                    // not exist or is an undefined var. If leaveErrMsg is
1711:                    // false, then return null so that the calling code
1712:                    // can handle an array variable that does not exist
1713:                    // without throwing and catching an exception.
1714:
1715:                    flags = TCL.LEAVE_ERR_MSG;
1716:                }
1717:
1718:                Var[] result = Var.lookupArrayElement(interp, varname, key,
1719:                        flags, "read", false, false, resolved);
1720:                if (result == null) {
1721:                    return null;
1722:                }
1723:
1724:                // Always pass TCL.LEAVE_ERR_MSG so that an exception
1725:                // will be raised in case a trace raises an exception.
1726:
1727:                return Var.getVarPtr(interp, result[0], result[1], varname,
1728:                        key, TCL.LEAVE_ERR_MSG);
1729:            }
1730:
1731:            // This method is invoked to set the value of an
1732:            // array variable that is associated with a compiled
1733:            // local slot. This method is invoked when the
1734:            // compiled local slot can be resolved to an array.
1735:            // This method is only ever invoked from a compiled
1736:            // proc implementation. This method is in the
1737:            // critical execution path.
1738:
1739:            static TclObject setVarCompiledLocalArray(final Interp interp,
1740:                    final String varname, // name of array variable
1741:                    final String key, // array key, can't be null
1742:                    final TclObject newValue, final Var resolved) // resolved array variable
1743:                    throws TclException {
1744:                // Raise TclException instead of returning null
1745:                final int flags = TCL.LEAVE_ERR_MSG;
1746:
1747:                Var[] result = lookupArrayElement(interp, varname, key, flags,
1748:                        "set", false, true, resolved);
1749:
1750:                return setVarPtr(interp, result[0], result[1], varname, key,
1751:                        newValue, flags);
1752:            }
1753:
1754:            /**
1755:             *  TclIncrVar2 -> incrVar
1756:             *
1757:             *	Given a two-part variable name, which may refer either to a scalar
1758:             *	variable or an element of an array, increment the Tcl object value
1759:             *  of the variable by a specified amount.
1760:             *
1761:             * @param part1 1st part of the variable name.
1762:             * @param part2 2nd part of the variable name.
1763:             * @param incrAmount Amount to be added to variable.
1764:             * @param flags misc flags that control the actions of this method
1765:             *
1766:             * Results:
1767:             *	Returns a reference to the TclObject holding the new value of the
1768:             *	variable. If the specified variable doesn't exist, or there is a
1769:             *	clash in array usage, or an error occurs while executing variable
1770:             *	traces, then a TclException will be raised.
1771:             *
1772:             * Side effects:
1773:             *	The value of the given variable is incremented by the specified
1774:             *	amount. If either the array or the entry didn't exist then a new
1775:             *	variable is created. The ref count for the returned object is _not_
1776:             *	incremented to reflect the returned reference; if you want to keep a
1777:             *	reference to the object you must increment its ref count yourself.
1778:             *
1779:             *----------------------------------------------------------------------
1780:             */
1781:
1782:            static TclObject incrVar(Interp interp, // Command interpreter in which variable is
1783:                    // to be found.
1784:                    String part1, // Reference to a string holding the name of
1785:                    // an array (if part2 is non-null) or the
1786:                    // name of a variable.
1787:                    String part2, // If non-null, reference to a string holding
1788:                    // the name of an element in the array
1789:                    // part1.
1790:                    int incrAmount, // Amount to be added to variable.
1791:                    int flags // Various flags that tell how to incr value:
1792:            // any of TCL.GLOBAL_ONLY,
1793:            // TCL.NAMESPACE_ONLY, TCL.APPEND_VALUE,
1794:            // TCL.LIST_ELEMENT, TCL.LEAVE_ERR_MSG.
1795:            ) throws TclException {
1796:                TclObject varValue = null;
1797:                boolean createdNewObj; // Set to true if var's value object is shared
1798:                // so we must increment a copy (i.e. copy
1799:                // on write).
1800:                int i;
1801:                boolean err;
1802:
1803:                // There are two possible error conditions that depend on the setting of
1804:                // TCL.LEAVE_ERR_MSG. an exception could be raised or null could be returned
1805:                err = false;
1806:                try {
1807:                    varValue = getVar(interp, part1, part2, flags);
1808:                } catch (TclException e) {
1809:                    err = true;
1810:                    throw e;
1811:                } finally {
1812:                    // FIXME : is this the correct way to catch the error?
1813:                    if (err || varValue == null) {
1814:                        interp
1815:                                .addErrorInfo("\n    (reading value of variable to increment)");
1816:                    }
1817:                }
1818:
1819:                // Increment the variable's value. If the object is unshared we can
1820:                // modify it directly, otherwise we must create a new copy to modify:
1821:                // this is "copy on write". The incr() method will free the old
1822:                // string rep since it is no longer valid.
1823:
1824:                createdNewObj = false;
1825:                if (varValue.isShared()) {
1826:                    varValue = varValue.duplicate();
1827:                    createdNewObj = true;
1828:                }
1829:
1830:                try {
1831:                    TclInteger.incr(interp, varValue, incrAmount);
1832:                } catch (TclException e) {
1833:                    if (createdNewObj) {
1834:                        varValue.release(); // free unneeded copy
1835:                    }
1836:                    throw e;
1837:                }
1838:
1839:                // Store the variable's new value and run any write traces.
1840:
1841:                return setVar(interp, part1, part2, varValue, flags);
1842:            }
1843:
1844:            /**
1845:             * Tcl_UnsetVar2 -> unsetVar
1846:             *
1847:             * Unset a variable, given a two-part name consisting of array
1848:             * name and element within array.
1849:             *
1850:             * @param part1 1st part of the variable name.
1851:             * @param part2 2nd part of the variable name.
1852:             * @param flags misc flags that control the actions of this method.
1853:             *
1854:             *	If part1 and part2 indicate a local or global variable in interp,
1855:             *	it is deleted.  If part1 is an array name and part2 is null, then
1856:             *	the whole array is deleted.
1857:             *
1858:             */
1859:
1860:            static void unsetVar(Interp interp, // Command interpreter in which var is
1861:                    // to be looked up.
1862:                    String part1, // Name of variable or array.
1863:                    String part2, // Name of element within array or null.
1864:                    int flags // OR-ed combination of any of
1865:            // TCL.GLOBAL_ONLY, TCL.NAMESPACE_ONLY,
1866:            // TCL.LEAVE_ERR_MSG.
1867:            ) throws TclException {
1868:                Var dummyVar;
1869:                Var var;
1870:                Var array;
1871:                //ActiveVarTrace active;
1872:                TclObject obj;
1873:                int result;
1874:
1875:                // FIXME : what about the null return vs exception thing here?
1876:                Var[] lookup_result = lookupVar(interp, part1, part2, flags,
1877:                        "unset", false, false);
1878:                if (lookup_result == null) {
1879:                    throw new TclRuntimeError("unexpected null reference");
1880:                }
1881:
1882:                var = lookup_result[0];
1883:                array = lookup_result[1];
1884:
1885:                result = (var.isVarUndefined() ? TCL.ERROR : TCL.OK);
1886:
1887:                if ((array != null) && (array.sidVec != null)) {
1888:                    deleteSearches(array);
1889:                }
1890:
1891:                // The code below is tricky, because of the possibility that
1892:                // a trace procedure might try to access a variable being
1893:                // deleted. To handle this situation gracefully, do things
1894:                // in three steps:
1895:                // 1. Copy the contents of the variable to a dummy variable
1896:                //    structure, and mark the original Var structure as undefined.
1897:                // 2. Invoke traces and clean up the variable, using the dummy copy.
1898:                // 3. If at the end of this the original variable is still
1899:                //    undefined and has no outstanding references, then delete
1900:                //	  it (but it could have gotten recreated by a trace).
1901:
1902:                dummyVar = new Var();
1903:                //FIXME: Var class really should implement clone to make a bit copy. 
1904:                dummyVar.tobj = var.tobj;
1905:                dummyVar.arraymap = var.arraymap;
1906:                dummyVar.linkto = var.linkto;
1907:                dummyVar.traces = var.traces;
1908:                dummyVar.flags = var.flags;
1909:                dummyVar.hashKey = var.hashKey;
1910:                dummyVar.table = var.table;
1911:                dummyVar.refCount = var.refCount;
1912:                dummyVar.ns = var.ns;
1913:
1914:                var.setVarUndefined();
1915:                var.setVarScalar();
1916:                var.tobj = null; // dummyVar points to any value object
1917:                var.arraymap = null;
1918:                var.linkto = null;
1919:                var.traces = null;
1920:                var.sidVec = null;
1921:
1922:                // Call trace procedures for the variable being deleted. Then delete
1923:                // its traces. Be sure to abort any other traces for the variable
1924:                // that are still pending. Special tricks:
1925:                // 1. We need to increment var's refCount around this: CallTraces
1926:                //    will use dummyVar so it won't increment var's refCount itself.
1927:                // 2. Turn off the TRACE_ACTIVE flag in dummyVar: we want to
1928:                //    call unset traces even if other traces are pending.
1929:
1930:                if ((dummyVar.traces != null)
1931:                        || ((array != null) && (array.traces != null))) {
1932:                    var.refCount++;
1933:                    dummyVar.flags &= ~TRACE_ACTIVE;
1934:                    callTraces(interp, array, dummyVar, part1, part2,
1935:                            (flags & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY))
1936:                                    | TCL.TRACE_UNSETS);
1937:
1938:                    dummyVar.traces = null;
1939:
1940:                    // Active trace stuff is not part of Jacl's interp
1941:
1942:                    var.refCount--;
1943:                }
1944:
1945:                // If the variable is an array, delete all of its elements. This must be
1946:                // done after calling the traces on the array, above (that's the way
1947:                // traces are defined). If it is a scalar, "discard" its object
1948:                // (decrement the ref count of its object, if any).
1949:
1950:                if (dummyVar.isVarArray() && !dummyVar.isVarUndefined()) {
1951:                    deleteArray(interp, part1, dummyVar,
1952:                            (flags & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY))
1953:                                    | TCL.TRACE_UNSETS);
1954:                }
1955:                if (dummyVar.isVarScalar() && (dummyVar.tobj != null)) {
1956:                    obj = dummyVar.tobj;
1957:                    obj.release();
1958:                    dummyVar.tobj = null;
1959:                }
1960:
1961:                // If the variable was a namespace variable, decrement its reference count.
1962:
1963:                if ((var.flags & NAMESPACE_VAR) != 0) {
1964:                    var.flags &= ~NAMESPACE_VAR;
1965:                    var.refCount--;
1966:                }
1967:
1968:                // Finally, if the variable is truly not in use then free up its Var
1969:                // structure and remove it from its hash table, if any. The ref count of
1970:                // its value object, if any, was decremented above.
1971:
1972:                cleanupVar(var, array);
1973:
1974:                Var.setUndefinedToNull(interp, part1, part2);
1975:
1976:                // It's an error to unset an undefined variable.
1977:
1978:                if (result != TCL.OK) {
1979:                    if ((flags & TCL.LEAVE_ERR_MSG) != 0) {
1980:                        throw new TclVarException(interp, part1, part2,
1981:                                "unset", ((array == null) ? noSuchVar
1982:                                        : noSuchElement));
1983:                    }
1984:                }
1985:            }
1986:
1987:            /**
1988:             * Tcl_TraceVar2 -> traceVar
1989:             *
1990:             * Trace a variable, given a two-part name consisting of array
1991:             * name and element within array.
1992:             *
1993:             * @param part1 1st part of the variable name.
1994:             * @param part2 2nd part of the variable name.
1995:             * @param flags misc flags that control the actions of this method.
1996:             * @param trace the trace to comand to add.
1997:             */
1998:
1999:            static void traceVar(Interp interp, // interp in which var is located
2000:                    String part1, // Name of scalar variable or array.
2001:                    String part2, // Name of element within array;  null means
2002:                    // trace applies to scalar variable or array
2003:                    // as-a-whole.
2004:                    int flags, // OR-ed collection of bits, including any
2005:                    // of TCL.TRACE_READS, TCL.TRACE_WRITES,
2006:                    // TCL.TRACE_UNSETS, TCL.GLOBAL_ONLY,
2007:                    // and TCL.NAMESPACE_ONLY.
2008:                    VarTrace proc // Procedure to call when specified ops are
2009:            // invoked upon var.
2010:            ) throws TclException {
2011:                Var[] result;
2012:                Var var, array;
2013:
2014:                // FIXME: what about the exception problem here?
2015:                result = lookupVar(interp, part1, part2,
2016:                        (flags | TCL.LEAVE_ERR_MSG), "trace", true, true);
2017:                if (result == null) {
2018:                    throw new TclException(interp, "");
2019:                }
2020:
2021:                var = result[0];
2022:                array = result[1];
2023:
2024:                // Set up trace information. Set a flag to indicate that traces
2025:                // exists so that resolveScalar() can determine if traces
2026:                // are set by checking only the Var flags filed. The rest of
2027:                // the code in this module makes use of the var.traces field.
2028:
2029:                if (var.traces == null) {
2030:                    var.setVarTraceExists();
2031:                    var.traces = new ArrayList();
2032:                }
2033:
2034:                TraceRecord rec = new TraceRecord();
2035:                rec.trace = proc;
2036:                rec.flags = flags
2037:                        & (TCL.TRACE_READS | TCL.TRACE_WRITES
2038:                                | TCL.TRACE_UNSETS | TCL.TRACE_ARRAY);
2039:
2040:                var.traces.add(0, rec);
2041:
2042:                // FIXME: is this needed ?? It was in Jacl but not 8.1
2043:
2044:                /*
2045:                // When inserting a trace for an array on an UNDEFINED variable,
2046:                // the search IDs for that array are reset.
2047:
2048:                if (array != null && var.isVarUndefined()) {
2049:                    array.sidVec = null;
2050:                }
2051:                 */
2052:            }
2053:
2054:            /**
2055:             * Tcl_UntraceVar2 -> untraceVar
2056:             *
2057:             * Untrace a variable, given a two-part name consisting of array
2058:             * name and element within array. This will Remove a
2059:             * previously-created trace for a variable.
2060:             *
2061:             * @param interp Interpreter containing variable.
2062:             * @param part1 1st part of the variable name.
2063:             * @param part2 2nd part of the variable name.
2064:             * @param flags misc flags that control the actions of this method.
2065:             * @param proc the trace to delete.
2066:             */
2067:
2068:            static void untraceVar(Interp interp, // Interpreter containing variable.
2069:                    String part1, // Name of variable or array.
2070:                    String part2, // Name of element within array; null means
2071:                    // trace applies to scalar variable or array
2072:                    // as-a-whole. 
2073:                    int flags, // OR-ed collection of bits describing
2074:                    // current trace, including any of
2075:                    // TCL.TRACE_READS, TCL.TRACE_WRITES,
2076:                    // TCL.TRACE_UNSETS, TCL.GLOBAL_ONLY,
2077:                    // and TCL.NAMESPACE_ONLY.
2078:                    VarTrace proc // Procedure assocated with trace.
2079:            ) {
2080:                Var[] result = null;
2081:                Var var;
2082:
2083:                try {
2084:                    result = lookupVar(interp, part1, part2, flags
2085:                            & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY), null,
2086:                            false, false);
2087:                    if (result == null) {
2088:                        return;
2089:                    }
2090:                } catch (TclException e) {
2091:                    // FIXME: check for problems in exception in lookupVar
2092:
2093:                    // We have set throwException argument to false in the
2094:                    // lookupVar() call, so an exception should never be
2095:                    // thrown.
2096:
2097:                    throw new TclRuntimeError("unexpected TclException: " + e);
2098:                }
2099:
2100:                var = result[0];
2101:
2102:                if (var.traces != null) {
2103:                    int len = var.traces.size();
2104:                    for (int i = 0; i < len; i++) {
2105:                        TraceRecord rec = (TraceRecord) var.traces.get(i);
2106:                        if (rec.trace == proc) {
2107:                            var.traces.remove(i);
2108:                            break;
2109:                        }
2110:                    }
2111:
2112:                    // If there are no more traces, then null
2113:                    // the var.traces field since logic in this
2114:                    // module depends on a null traces field.
2115:
2116:                    if (var.traces.size() == 0) {
2117:                        var.traces = null;
2118:                        var.clearVarTraceExists();
2119:                    }
2120:                }
2121:
2122:                // If this is the last trace on the variable, and the variable is
2123:                // unset and unused, then free up the variable.
2124:
2125:                if (var.isVarUndefined()) {
2126:                    cleanupVar(var, null);
2127:                }
2128:            }
2129:
2130:            /**
2131:             * Tcl_VarTraceInfo2 -> getTraces
2132:             *
2133:             * @return the list of traces of a variable.
2134:             *
2135:             * @param interp Interpreter containing variable.
2136:             * @param part1 1st part of the variable name.
2137:             * @param part2 2nd part of the variable name (can be null).
2138:             * @param flags misc flags that control the actions of this method.
2139:             */
2140:
2141:            static protected ArrayList getTraces(Interp interp, // Interpreter containing variable.
2142:                    String part1, // Name of variable or array.
2143:                    String part2, // Name of element within array; null means
2144:                    // trace applies to scalar variable or array
2145:                    // as-a-whole.
2146:                    int flags // OR-ed combination of TCL.GLOBAL_ONLY,
2147:            // TCL.NAMESPACE_ONLY.
2148:            ) throws TclException {
2149:                Var[] result;
2150:
2151:                result = lookupVar(interp, part1, part2, flags
2152:                        & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY), null, false,
2153:                        false);
2154:
2155:                if (result == null) {
2156:                    return null;
2157:                }
2158:
2159:                return result[0].traces;
2160:            }
2161:
2162:            /**
2163:             * MakeUpvar -> makeUpvar
2164:             *
2165:             * Create a reference of a variable in otherFrame in the current
2166:             * CallFrame, given a two-part name consisting of array name and
2167:             * element within array.
2168:             *
2169:             * @param interp Interp containing the variables
2170:             * @param frame CallFrame containing "other" variable.
2171:             *     null means use global context.
2172:             * @param otherP1 the 1st part name of the variable in the "other" frame.
2173:             * @param otherP2 the 2nd part name of the variable in the "other" frame.
2174:             * @param otherFlags the flags for scaope of "other" variable
2175:             * @param myName Name of scalar variable which will refer to otherP1/otherP2.
2176:             * @param myFlags only the TCL.GLOBAL_ONLY bit matters, 
2177:             *    indicating the scope of myName.
2178:             * @exception TclException if the upvar cannot be created. 
2179:             */
2180:
2181:            // FIXME: Tcl 8.4 implements resolver logic specific to upvar with the flag
2182:            // LOOKUP_FOR_UPVAR. Port this logic and test cases to Jacl.
2183:            protected static void makeUpvar(Interp interp, // Interpreter containing variables. Used
2184:                    // for error messages, too.
2185:                    CallFrame frame, // Call frame containing "other" variable.
2186:                    // null means use global :: context.
2187:                    String otherP1, // Two-part name of variable in framePtr. 
2188:                    String otherP2, int otherFlags, // 0, TCL.GLOBAL_ONLY or TCL.NAMESPACE_ONLY:
2189:                    // indicates scope of "other" variable.
2190:                    String myName, // Name of variable which will refer to
2191:                    // otherP1/otherP2. Must be a scalar.
2192:                    int myFlags, // 0, TCL.GLOBAL_ONLY or TCL.NAMESPACE_ONLY:
2193:                    // indicates scope of myName. Also accepts
2194:                    // the special Var.EXPLICIT_LOCAL_NAME flag
2195:                    // which is used to ignore namespace lookup
2196:                    // rules for myname.
2197:                    int localIndex // If != -1, this is the index into the
2198:            // compiledLocals array where the upvar
2199:            // variable could be stored.
2200:            ) throws TclException {
2201:                Var other, var, array;
2202:                Var[] result = null;
2203:                CallFrame varFrame;
2204:                CallFrame savedFrame = null;
2205:                HashMap table;
2206:                Namespace ns, altNs;
2207:                String tail;
2208:                boolean newvar = false;
2209:                boolean foundInCompiledLocalsArray = false;
2210:                boolean foundInLocalTable = false;
2211:                Var[] compiledLocals = null;
2212:
2213:                // Find "other" in "frame". If not looking up other in just the
2214:                // current namespace, temporarily replace the current var frame
2215:                // pointer in the interpreter in order to use TclLookupVar.
2216:
2217:                try {
2218:                    if ((otherFlags & TCL.NAMESPACE_ONLY) == 0) {
2219:                        savedFrame = interp.varFrame;
2220:                        interp.varFrame = frame;
2221:                    }
2222:
2223:                    // If the special EXPLICIT_LOCAL_NAME flag is passed, then
2224:                    // do nothing instead of raising a TclException when the
2225:                    // other lookup fails.
2226:
2227:                    int otherLookupFlags = (otherFlags | TCL.LEAVE_ERR_MSG);
2228:                    if ((myFlags & EXPLICIT_LOCAL_NAME) != 0) {
2229:                        otherLookupFlags = otherFlags;
2230:                    }
2231:
2232:                    result = Var.lookupVar(interp, otherP1, otherP2,
2233:                            otherLookupFlags, "access", true, true);
2234:                } finally {
2235:                    // Reset interp.varFrame
2236:
2237:                    if ((otherFlags & TCL.NAMESPACE_ONLY) == 0) {
2238:                        interp.varFrame = savedFrame;
2239:                    }
2240:                }
2241:
2242:                if (result == null) {
2243:                    // EXPLICIT_LOCAL_NAME flag passed and lookup failed.
2244:                    return;
2245:                }
2246:
2247:                other = result[0];
2248:                array = result[1];
2249:
2250:                if (other == null) {
2251:                    // Should not be returned since TCL.LEAVE_ERR_MSG
2252:                    // was passed to generate a TclException.
2253:                    throw new TclRuntimeError("unexpected null reference");
2254:                }
2255:
2256:                // This module assumes that a link target will never
2257:                // be a link var. In this way, a link var is
2258:                // always resolved to either a scalar or an array
2259:                // by following a single link. The lookupVar() method
2260:                // should always return either a scalar or an array.
2261:
2262:                if (other.isVarLink()) {
2263:                    throw new TclRuntimeError(
2264:                            "other var resolved to a link var");
2265:                }
2266:
2267:                // Now create a variable entry for "myName". Create it as either a
2268:                // namespace variable or as a local variable in a procedure call
2269:                // frame. Interpret myName as a namespace variable if:
2270:                //    1) so requested by a TCL.GLOBAL_ONLY or TCL.NAMESPACE_ONLY flag,
2271:                //    2) there is no active frame (we're at the global :: scope),
2272:                //    3) the active frame was pushed to define the namespace context
2273:                //       for a "namespace eval" or "namespace inscope" command,
2274:                //    4) the name has namespace qualifiers ("::"s), unless
2275:                //       the special EXPLICIT_LOCAL_NAME flag is set.
2276:                // If creating myName in the active procedure, look in its
2277:                // hashtable for runtime-created local variables. Create that
2278:                // procedure's local variable hashtable if necessary.
2279:
2280:                varFrame = interp.varFrame;
2281:                if (((myFlags & (TCL.GLOBAL_ONLY | TCL.NAMESPACE_ONLY)) != 0)
2282:                        || (varFrame == null)
2283:                        || !varFrame.isProcCallFrame
2284:                        || ((myName.indexOf("::") != -1) && ((myFlags & EXPLICIT_LOCAL_NAME) == 0))) {
2285:
2286:                    Namespace.GetNamespaceForQualNameResult gnfqnr = interp.getnfqnResult;
2287:                    Namespace.getNamespaceForQualName(interp, myName, null,
2288:                            myFlags, gnfqnr);
2289:                    ns = gnfqnr.ns;
2290:                    altNs = gnfqnr.altNs;
2291:                    tail = gnfqnr.simpleName;
2292:
2293:                    if (ns == null) {
2294:                        ns = altNs;
2295:                    }
2296:                    if (ns == null) {
2297:                        throw new TclException(interp, "bad variable name \""
2298:                                + myName + "\": unknown namespace");
2299:                    }
2300:
2301:                    // Check that we are not trying to create a namespace var linked to
2302:                    // a local variable in a procedure. If we allowed this, the local
2303:                    // variable in the shorter-lived procedure frame could go away
2304:                    // leaving the namespace var's reference invalid.
2305:
2306:                    if (((otherP2 != null) ? array.ns : other.ns) == null) {
2307:                        throw new TclException(
2308:                                interp,
2309:                                "bad variable name \""
2310:                                        + myName
2311:                                        + "\": upvar won't create namespace variable that refers to procedure variable");
2312:                    }
2313:
2314:                    var = (Var) ns.varTable.get(tail);
2315:                    if (var == null) { // we are adding a new entry
2316:                        newvar = true;
2317:                        var = new Var();
2318:                        ns.varTable.put(tail, var);
2319:
2320:                        // There is no hPtr member in Jacl, The hPtr combines the table
2321:                        // and the key used in a table lookup.
2322:                        var.hashKey = tail;
2323:                        var.table = ns.varTable;
2324:
2325:                        var.ns = ns; // Namespace var
2326:                    }
2327:                } else {
2328:                    var = null;
2329:
2330:                    compiledLocals = varFrame.compiledLocals;
2331:                    if (compiledLocals != null) { // look in compiled local array
2332:                        // A compiled local array is defined, so
2333:                        // check in the compiled local array for
2334:                        // a variable with this name. In the case
2335:                        // where the compiled local index is known,
2336:                        // we only need to check one index. Note
2337:                        // that an explicit non-local name should
2338:                        // be matched.
2339:
2340:                        if (localIndex == -1) {
2341:                            // compiled local slot is not known, search by name.
2342:                            final int MAX = compiledLocals.length;
2343:                            String[] compiledLocalsNames = varFrame.compiledLocalsNames;
2344:
2345:                            for (int i = 0; i < MAX; i++) {
2346:                                if (compiledLocalsNames[i].equals(myName)) {
2347:                                    foundInCompiledLocalsArray = true;
2348:                                    localIndex = i;
2349:                                    var = compiledLocals[i];
2350:                                    break;
2351:                                }
2352:                            }
2353:                        } else {
2354:                            // Slot the var should live in is known at compile time.
2355:                            // Check to see if compiled local var exists already.
2356:
2357:                            foundInCompiledLocalsArray = true;
2358:                            var = compiledLocals[localIndex];
2359:                        }
2360:                    }
2361:
2362:                    if (!foundInCompiledLocalsArray) { // look in frame's local var hashtable
2363:                        table = varFrame.varTable;
2364:
2365:                        // Note: Don't create var in the local table when it
2366:                        // should be created in the compiledLocals array.
2367:
2368:                        if (table == null) {
2369:                            table = new HashMap();
2370:                            varFrame.varTable = table;
2371:                        }
2372:
2373:                        if (table != null) {
2374:                            var = (Var) table.get(myName);
2375:                        }
2376:
2377:                        if (var == null) { // we are adding a new entry
2378:                            newvar = true;
2379:                            var = new Var();
2380:                            table.put(myName, var);
2381:
2382:                            var.hashKey = myName;
2383:                            var.table = table;
2384:                        }
2385:                        if (var != null) {
2386:                            foundInLocalTable = true;
2387:                        }
2388:                    }
2389:
2390:                    // Var should live in the compiled local
2391:                    // array, but it does not exist yet. Create
2392:                    // a new Var instance that will be assigned
2393:                    // to the compiled local array slot. This
2394:                    // Var instance will become a link var.
2395:
2396:                    if (foundInCompiledLocalsArray && (var == null)) {
2397:                        newvar = true;
2398:                        var = new Var();
2399:                        var.hashKey = myName;
2400:                        var.clearVarInHashtable();
2401:                    }
2402:                }
2403:
2404:                if (!newvar) {
2405:                    // The variable already exists. Make sure this variable "var"
2406:                    // isn't the same as "other" (avoid circular links). Also, if
2407:                    // it's not an upvar then it's an error. If it is an upvar, then
2408:                    // just disconnect it from the thing it currently refers to.
2409:
2410:                    if (var == other) {
2411:                        throw new TclException(interp,
2412:                                "can't upvar from variable to itself");
2413:                    }
2414:                    if (var.isVarLink()) {
2415:                        Var link = var.linkto;
2416:                        if (link == other) {
2417:                            // Already linked to the variable, no-op
2418:                            return;
2419:                        }
2420:                        link.refCount--;
2421:                        if (link.isVarUndefined()) {
2422:                            cleanupVar(link, null);
2423:                        }
2424:                    } else if (!var.isVarUndefined()) {
2425:                        throw new TclException(interp, "variable \"" + myName
2426:                                + "\" already exists");
2427:                    } else if (var.traces != null) {
2428:                        throw new TclException(interp, "variable \"" + myName
2429:                                + "\" has traces: can't use for upvar");
2430:                    }
2431:                    // FIXME: Is it possible that the other var
2432:                    // would not be a var link type but it would
2433:                    // be undefined waiting to be cleaned up?
2434:                    // For example, a linked var in another scope?
2435:                    // Add a test case for this.
2436:                }
2437:
2438:                var.setVarLink();
2439:                var.clearVarUndefined();
2440:                var.linkto = other;
2441:                other.refCount++;
2442:
2443:                // If the link var should be stored in the compiledLocals
2444:                // array then do that now. A variable with this same
2445:                // name would never appear in the local table. Also mark
2446:                // this variable as non-local for scoped global.
2447:
2448:                if (foundInCompiledLocalsArray) {
2449:                    if (newvar) {
2450:                        compiledLocals[localIndex] = var;
2451:                    }
2452:
2453:                    if ((myFlags & EXPLICIT_LOCAL_NAME) != 0) {
2454:                        var.setVarNonLocal();
2455:                    }
2456:                }
2457:
2458:                return;
2459:            }
2460:
2461:            /*
2462:             *----------------------------------------------------------------------
2463:             *
2464:             * Tcl_GetVariableFullName -> getVariableFullName
2465:             *
2466:             *  Given a Var token returned by Namespace.FindNamespaceVar, this
2467:             *	procedure appends to an object the namespace variable's full
2468:             *	name, qualified by a sequence of parent namespace names.
2469:             *
2470:             * Results:
2471:             *  None.
2472:             *
2473:             * Side effects:
2474:             *  The variable's fully-qualified name is returned.
2475:             *
2476:             *----------------------------------------------------------------------
2477:             */
2478:
2479:            public static String getVariableFullName(Interp interp, // Interpreter containing the variable.
2480:                    Var var // Token for the variable returned by a
2481:            // previous call to Tcl_FindNamespaceVar.
2482:            ) {
2483:                StringBuffer buff = new StringBuffer();
2484:
2485:                // Add the full name of the containing namespace (if any), followed by
2486:                // the "::" separator, then the variable name.
2487:
2488:                if (var != null) {
2489:                    if (!var.isVarArrayElement()) {
2490:                        if (var.ns != null) {
2491:                            buff.append(var.ns.fullName);
2492:                            if (var.ns != interp.globalNs) {
2493:                                buff.append("::");
2494:                            }
2495:                        }
2496:                        // Jacl's Var class does not include the "name" member
2497:                        // We use the "hashKey" member which is equivalent
2498:
2499:                        if (var.hashKey != null) {
2500:                            buff.append(var.hashKey);
2501:                        }
2502:                    }
2503:                }
2504:
2505:                return buff.toString();
2506:            }
2507:
2508:            /**
2509:             * CallTraces -> callTraces
2510:             *
2511:             * This procedure is invoked to find and invoke relevant
2512:             * trace procedures associated with a particular operation on
2513:             * a variable.  This procedure invokes traces both on the
2514:             * variable and on its containing array (where relevant).
2515:             *
2516:             * @param interp Interpreter containing variable.
2517:             * @param array array variable that contains the variable, or null
2518:             *   if the variable isn't an element of an array.
2519:             * @param var Variable whose traces are to be invoked.
2520:             * @param part1 the first part of a variable name.
2521:             * @param part2 the second part of a variable name.
2522:             * @param flags Flags to pass to trace procedures: indicates
2523:             *   what's happening to variable, plus other stuff like
2524:             *   TCL.GLOBAL_ONLY, TCL.NAMESPACE_ONLY, and TCL.INTERP_DESTROYED.
2525:             * @return null if no trace procedures were invoked, or
2526:             *   if all the invoked trace procedures returned successfully.
2527:             *   The return value is non-null if a trace procedure returned an
2528:             *   error (in this case no more trace procedures were invoked
2529:             *   after the error was returned). In this case the return value
2530:             *   is a pointer to a string describing the error.
2531:             */
2532:
2533:            static protected String callTraces(Interp interp, Var array,
2534:                    Var var, String part1, String part2, int flags) {
2535:                TclObject oldResult;
2536:                int i;
2537:
2538:                // If there are already similar trace procedures active for the
2539:                // variable, don't call them again.
2540:
2541:                if ((var.flags & Var.TRACE_ACTIVE) != 0) {
2542:                    return null;
2543:                }
2544:                var.flags |= Var.TRACE_ACTIVE;
2545:                var.refCount++;
2546:
2547:                // If the variable name hasn't been parsed into array name and
2548:                // element, do it here.  If there really is an array element,
2549:                // make a copy of the original name so that nulls can be
2550:                // inserted into it to separate the names (can't modify the name
2551:                // string in place, because the string might get used by the
2552:                // callbacks we invoke).
2553:
2554:                // FIXME : a util method that parsed an array variable
2555:                // name into array and element component parts could
2556:                // be useful. There are a number of places where this
2557:                // is done inline in the code.
2558:                if (part2 == null) {
2559:                    int len = part1.length();
2560:
2561:                    if (len > 0) {
2562:                        if (part1.charAt(len - 1) == ')') {
2563:                            for (i = 0; i < len - 1; i++) {
2564:                                if (part1.charAt(i) == '(') {
2565:                                    break;
2566:                                }
2567:                            }
2568:                            if (i < len - 1) {
2569:                                if (i < len - 2) {
2570:                                    part2 = part1.substring(i + 1, len - 1);
2571:                                    part1 = part1.substring(0, i);
2572:                                }
2573:                            }
2574:                        }
2575:                    }
2576:                }
2577:
2578:                oldResult = interp.getResult();
2579:                oldResult.preserve();
2580:                interp.resetResult();
2581:
2582:                try {
2583:                    // Invoke traces on the array containing the variable, if relevant.
2584:
2585:                    if (array != null) {
2586:                        array.refCount++;
2587:                    }
2588:                    if ((array != null) && (array.traces != null)) {
2589:                        for (i = 0; (array.traces != null)
2590:                                && (i < array.traces.size()); i++) {
2591:                            TraceRecord rec = (TraceRecord) array.traces.get(i);
2592:                            if ((rec.flags & flags) != 0) {
2593:                                try {
2594:                                    rec.trace.traceProc(interp, part1, part2,
2595:                                            flags);
2596:                                } catch (TclException e) {
2597:                                    if ((flags & TCL.TRACE_UNSETS) == 0) {
2598:                                        return interp.getResult().toString();
2599:                                    }
2600:                                }
2601:                            }
2602:                        }
2603:                    }
2604:
2605:                    // Invoke traces on the variable itself.
2606:
2607:                    if ((flags & TCL.TRACE_UNSETS) != 0) {
2608:                        flags |= TCL.TRACE_DESTROYED;
2609:                    }
2610:
2611:                    for (i = 0; (var.traces != null) && (i < var.traces.size()); i++) {
2612:                        TraceRecord rec = (TraceRecord) var.traces.get(i);
2613:                        if ((rec.flags & flags) != 0) {
2614:                            try {
2615:                                rec.trace
2616:                                        .traceProc(interp, part1, part2, flags);
2617:                            } catch (TclException e) {
2618:                                if ((flags & TCL.TRACE_UNSETS) == 0) {
2619:                                    return interp.getResult().toString();
2620:                                }
2621:                            }
2622:                        }
2623:                    }
2624:
2625:                    return null;
2626:                } finally {
2627:                    if (array != null) {
2628:                        array.refCount--;
2629:                    }
2630:                    var.flags &= ~TRACE_ACTIVE;
2631:                    var.refCount--;
2632:
2633:                    interp.setResult(oldResult);
2634:                    oldResult.release();
2635:                }
2636:            }
2637:
2638:            /**
2639:             * DeleteSearches -> deleteSearches
2640:             *
2641:             *	This procedure is called to free up all of the searches
2642:             *	associated with an array variable.
2643:             *
2644:             * @param interp Interpreter containing array.
2645:             * @param arrayVar the array variable to delete searches from.
2646:             */
2647:
2648:            static protected void deleteSearches(Var arrayVar) // Variable whose searches are to be deleted.
2649:            {
2650:                arrayVar.sidVec = null;
2651:            }
2652:
2653:            /**
2654:             * TclDeleteVars -> deleteVars
2655:             *
2656:             *	This procedure is called to recycle all the storage space
2657:             *	associated with a table of variables. For this procedure
2658:             *	to work correctly, it must not be possible for any of the
2659:             *	variables in the table to be accessed from Tcl commands
2660:             *	(e.g. from trace procedures).
2661:             *
2662:             * @param interp Interpreter containing array.
2663:             * @param table HashMap that holds the Vars to delete
2664:             */
2665:
2666:            static protected void deleteVars(Interp interp, HashMap table) {
2667:                int flags;
2668:                Namespace currNs = Namespace.getCurrentNamespace(interp);
2669:
2670:                // Determine what flags to pass to the trace callback procedures.
2671:
2672:                flags = TCL.TRACE_UNSETS;
2673:                if (table == interp.globalNs.varTable) {
2674:                    flags |= (TCL.INTERP_DESTROYED | TCL.GLOBAL_ONLY);
2675:                } else if (table == currNs.varTable) {
2676:                    flags |= TCL.NAMESPACE_ONLY;
2677:                }
2678:
2679:                for (Iterator iter = table.entrySet().iterator(); iter
2680:                        .hasNext();) {
2681:                    Map.Entry entry = (Map.Entry) iter.next();
2682:                    deleteVar(interp, (Var) entry.getValue(), flags);
2683:                }
2684:                table.clear();
2685:            }
2686:
2687:            /**
2688:            // FIXME: Make more like TclDeleteCompiledLocalVars()
2689:             * TclDeleteVars -> deleteVars
2690:             *
2691:             *	This procedure is called to recycle all the storage space
2692:             *	associated with an array of variables. For this procedure
2693:             *	to work correctly, it must not be possible for any of the
2694:             *	variables in the array to be accessed from Tcl commands
2695:             *	(e.g. from trace procedures).
2696:             *
2697:             * @param interp Interpreter containing array.
2698:             * @param compiledLocals array of compiled local variables
2699:             */
2700:
2701:            static protected void deleteVars(Interp interp, Var[] compiledLocals) {
2702:                // A compiled local array only ever exists for a compiled
2703:                // proc, so flags is always the same.
2704:
2705:                final int flags = TCL.TRACE_UNSETS;
2706:
2707:                final int max = compiledLocals.length;
2708:
2709:                for (int i = 0; i < max; i++) {
2710:                    Var clocal = compiledLocals[i];
2711:                    if (clocal != null) {
2712:                        // Cleanup the Var instance and then
2713:                        // null out the compiled local slots.
2714:
2715:                        deleteVar(interp, clocal, flags);
2716:                        compiledLocals[i] = null;
2717:                    }
2718:                }
2719:            }
2720:
2721:            /**
2722:             * deleteVar
2723:             *
2724:             *	This procedure is called to recycle all the storage space
2725:             *	associated with a single Var instance.
2726:             *
2727:             * @param interp Interpreter containing array.
2728:             * @param var A Var refrence to be deleted
2729:             * @param flags flags to pass to trace callbacks.
2730:             */
2731:
2732:            static protected void deleteVar(Interp interp, Var var, int flags) {
2733:                // For global/upvar variables referenced in procedures, decrement
2734:                // the reference count on the variable referred to, and free
2735:                // the referenced variable if it's no longer needed. Note that
2736:                // we always delete the link in another table, this should be
2737:                // fine since this method is invoked after the regular variables
2738:                // are deleted.
2739:
2740:                if ((var.flags & LINK) != 0) {
2741:                    // Follow link to either scalar or array variable
2742:                    Var link = var.linkto;
2743:                    link.refCount--;
2744:                    if ((link.refCount == 0)
2745:                            && (link.traces == null)
2746:                            // (link.isVarUndefined() && link.isVarInHashtable())
2747:                            && ((link.flags & (UNDEFINED | IN_HASHTABLE)) == (UNDEFINED | IN_HASHTABLE))) {
2748:                        if (link.hashKey == null) {
2749:                            var.linkto = null; // Drops reference to the link Var
2750:                        } else if (link.table != var.table) {
2751:                            link.table.remove(link.hashKey);
2752:                            link.table = null; // Drops the link var's table reference
2753:                            var.linkto = null; // Drops reference to the link Var
2754:                        }
2755:                    }
2756:                }
2757:
2758:                // free up the variable's space (no need to free the hash entry
2759:                // here, unless we're dealing with a global variable: the
2760:                // hash entries will be deleted automatically when the whole
2761:                // table is deleted). Note that we give callTraces the variable's
2762:                // fully-qualified name so that any called trace procedures can
2763:                // refer to these variables being deleted.
2764:
2765:                if (var.traces != null) {
2766:                    String fullname = getVariableFullName(interp, var);
2767:
2768:                    callTraces(interp, null, var, fullname, null, flags);
2769:
2770:                    // The var.traces = null statement later will drop all the
2771:                    // references to the traces which will free them up
2772:                }
2773:
2774:                if ((var.flags & ARRAY) != 0) {
2775:                    deleteArray(interp, var.hashKey, var, flags);
2776:                    var.arraymap = null;
2777:                } else if (((var.flags & SCALAR) != 0) && (var.tobj != null)) {
2778:                    TclObject obj = var.tobj;
2779:                    obj.release();
2780:                    var.tobj = null;
2781:                }
2782:
2783:                var.hashKey = null;
2784:                var.table = null;
2785:                var.traces = null;
2786:                var.setVarUndefined();
2787:                var.setVarScalar();
2788:
2789:                // If the variable was a namespace variable, decrement its 
2790:                // reference count. We are in the process of destroying its
2791:                // namespace so that namespace will no longer "refer" to the
2792:                // variable.
2793:
2794:                if ((var.flags & NAMESPACE_VAR) != 0) {
2795:                    var.flags &= ~NAMESPACE_VAR;
2796:                    var.refCount--;
2797:                }
2798:
2799:                // Recycle the variable's memory space if there aren't any upvar's
2800:                // pointing to it. If there are upvars to this variable, then the
2801:                // variable will get freed when the last upvar goes away. This
2802:                // variable could still be alive after this method finishes since
2803:                // it could be refrenced in a namespace. The code will catch
2804:                // that case by looking at the IN_HASHTABLE flag and seeing
2805:                // if the table member is null.
2806:
2807:                //	if (var.refCount == 0) {
2808:                //	    // When we drop the last reference it will be freeded
2809:                //	}
2810:            }
2811:
2812:            /**
2813:             * DeleteArray -> deleteArray
2814:             *
2815:             * This procedure is called to free up everything in an array
2816:             * variable.  It's the caller's responsibility to make sure
2817:             * that the array is no longer accessible before this procedure
2818:             * is called.
2819:             *
2820:             * @param interp Interpreter containing array.
2821:             * @param arrayName name of array (used for trace callbacks).
2822:             * @param var the array variable to delete.
2823:             * @param flags Flags to pass to CallTraces.
2824:             */
2825:
2826:            static protected void deleteArray(Interp interp, // Interpreter containing array.
2827:                    String arrayName, // Name of array (used for trace callbacks)
2828:                    Var var, // Reference to Var instance
2829:                    int flags // Flags to pass to callTraces:
2830:            // TCL.TRACE_UNSETS and sometimes
2831:            // TCL.INTERP_DESTROYED,
2832:            // TCL.NAMESPACE_ONLY, or
2833:            // TCL.GLOBAL_ONLY.
2834:            ) {
2835:                Var el;
2836:                TclObject obj;
2837:
2838:                deleteSearches(var);
2839:                HashMap table = var.arraymap;
2840:
2841:                for (Iterator iter = table.entrySet().iterator(); iter
2842:                        .hasNext();) {
2843:                    Map.Entry entry = (Map.Entry) iter.next();
2844:                    //String key = (String) entry.getKey();
2845:                    el = (Var) entry.getValue();
2846:
2847:                    if (el.isVarScalar() && (el.tobj != null)) {
2848:                        obj = el.tobj;
2849:                        obj.release();
2850:                        el.tobj = null;
2851:                    }
2852:
2853:                    String tmpkey = (String) el.hashKey;
2854:                    // There is no hPtr member in Jacl, The hPtr combines the table
2855:                    // and the key used in a table lookup.
2856:                    el.hashKey = null;
2857:                    el.table = null;
2858:                    if (el.traces != null) {
2859:                        el.flags &= ~TRACE_ACTIVE;
2860:                        // FIXME : Old Jacl impl passed a dummy var to callTraces, should we?
2861:                        callTraces(interp, null, el, arrayName, tmpkey, flags);
2862:                        el.traces = null;
2863:                        // Active trace stuff is not part of Jacl
2864:                    }
2865:                    el.setVarUndefined();
2866:                    el.setVarScalar();
2867:                    if (el.refCount == 0) {
2868:                        // We are no longer using the element
2869:                        // element Vars are IN_HASHTABLE
2870:                    }
2871:                }
2872:                table.clear();
2873:                var.arraymap = null;
2874:            }
2875:
2876:            /**
2877:             * CleanupVar -> cleanupVar
2878:             *
2879:             * This procedure is called when it looks like it may be OK
2880:             * to free up the variable's record and hash table entry, and
2881:             * those of its containing parent.  It's called, for example,
2882:             * when a trace on a variable deletes the variable.
2883:             *
2884:             * @param var variable that may be a candidate for being expunged.
2885:             * @param array Array that contains the variable, or NULL if this
2886:             *   variable isn't an array element.
2887:             */
2888:
2889:            static protected void cleanupVar(Var var, Var array) {
2890:                if (var.isVarUndefined() && (var.refCount == 0)
2891:                        && (var.traces == null)
2892:                        && ((var.flags & IN_HASHTABLE) != 0)) {
2893:                    if (var.table != null) {
2894:                        var.table.remove(var.hashKey);
2895:                        var.table = null;
2896:                        var.hashKey = null;
2897:                    }
2898:                }
2899:                if (array != null) {
2900:                    if (array.isVarUndefined() && (array.refCount == 0)
2901:                            && (array.traces == null)
2902:                            && ((array.flags & IN_HASHTABLE) != 0)) {
2903:                        if (array.table != null) {
2904:                            array.table.remove(array.hashKey);
2905:                            array.table = null;
2906:                            array.hashKey = null;
2907:                        }
2908:                    }
2909:                }
2910:            }
2911:
2912:            // CompiledLocal utilitiy methods.
2913:
2914:            // The resolveScalar() method will
2915:            // attempt to resolve a scalar Var ref
2916:            // in the compiled local array.
2917:            // If the Var can't be resolved as
2918:            // a valid scalar, then null will
2919:            // be returned.
2920:            //
2921:            // A resolved scalar is invalid when any
2922:            // of the following conditions is true.
2923:            //
2924:            // When the variable is not a scalar.
2925:            // When the variable is an array element.
2926:            // When the variable is undefined.
2927:            // When the variable has traces.
2928:            // When the variable can't be cached.
2929:
2930:            static Var resolveScalar(Var v) {
2931:                int flags = v.flags;
2932:                if ((flags & LINK) != 0) {
2933:                    v = v.linkto;
2934:                    flags = v.flags;
2935:                }
2936:
2937:                // Can't resolve var if it is not a scalar, if it is
2938:                // an array element, if it is undefined, if it has traces,
2939:                // or it can't be cached because it is a resolver var.
2940:
2941:                if ((flags & (LINK | ARRAY | ARRAY_ELEMENT | UNDEFINED
2942:                        | TRACE_EXISTS | NO_CACHE)) != 0) {
2943:                    return null;
2944:                }
2945:                return v;
2946:            }
2947:
2948:            // The resolveArray() method will
2949:            // attempt to resolve an array Var ref
2950:            // in the compiled local array.
2951:            // If the Var can't be resolved as
2952:            // a valid array variable, then null will
2953:            // be returned.
2954:            //
2955:            // A resolved array is invalid when any
2956:            // of the following conditions is true.
2957:            //
2958:            // When the variable is not an array.
2959:            // When the variable is undefined.
2960:            //
2961:            // Note that an array with traces is
2962:            // considered valid since the array
2963:            // methods support invoking traces.
2964:
2965:            static Var resolveArray(Var v) {
2966:                int flags = v.flags;
2967:                if ((flags & LINK) != 0) {
2968:                    v = v.linkto;
2969:                    flags = v.flags;
2970:                }
2971:
2972:                // Can't resolve var if it is not an array,
2973:                // if it is undefined, or it can't be cached
2974:                // because it is a resolver var. An array
2975:                // var with traces can be resolved.
2976:
2977:                if ((flags & (LINK | SCALAR | UNDEFINED | NO_CACHE)) != 0) {
2978:                    return null;
2979:                }
2980:                return v;
2981:            }
2982:
2983:            // Helper method invoked to null out a compiled local
2984:            // slot for a non-linked local variable that is now
2985:            // undefined. The unset command has no way of knowing
2986:            // if a variable being unset lives in the compiled
2987:            // local array, so this method is invoked after
2988:            // each unset operation to keep the compiled local
2989:            // array up to date. Variables linked into another
2990:            // scope can be undefined, so ignore those.
2991:
2992:            static void setUndefinedToNull(Interp interp, String part1,
2993:                    String part2) {
2994:                CallFrame varFrame = interp.varFrame;
2995:                if (varFrame == null) {
2996:                    return; // Invoked from global scope
2997:                }
2998:
2999:                if (varFrame.compiledLocals != null) {
3000:                    Var[] compiledLocals = varFrame.compiledLocals;
3001:                    final int MAX = compiledLocals.length;
3002:
3003:                    for (int i = 0; i < MAX; i++) {
3004:                        Var clocal = compiledLocals[i];
3005:                        if (clocal != null && !clocal.isVarNonLocal()
3006:                                && clocal.hashKey.equals(part1)) {
3007:                            if (!clocal.isVarLink() && clocal.isVarUndefined()) {
3008:                                // Set the compiled local slot to null
3009:                                // if there are no other vars linked to
3010:                                // this var.
3011:                                if (clocal.refCount == 0) {
3012:                                    compiledLocals[i] = null;
3013:                                }
3014:                            }
3015:                            return;
3016:                        }
3017:                    }
3018:                }
3019:            }
3020:
3021:            /*
3022:             *----------------------------------------------------------------------
3023:             *
3024:             * AppendLocals --
3025:             *
3026:             *	Append the local variables for the current frame to the
3027:             *	specified list object. This method is used by InfoCmd.
3028:             *
3029:             * Results:
3030:             *	None.
3031:             *
3032:             * Side effects:
3033:             *	None.
3034:             *
3035:             *----------------------------------------------------------------------
3036:             */
3037:
3038:            static void AppendLocals(Interp interp, // Current interp
3039:                    TclObject list, // list to append to
3040:                    String pattern, // Pattern to match against.
3041:                    boolean includeLinks) // true if upvars should be included
3042:                    throws TclException {
3043:                Var var;
3044:                String varName;
3045:                CallFrame frame = interp.varFrame;
3046:
3047:                HashMap localVarTable = frame.varTable;
3048:                if (localVarTable != null) {
3049:                    for (Iterator iter = localVarTable.entrySet().iterator(); iter
3050:                            .hasNext();) {
3051:                        Map.Entry entry = (Map.Entry) iter.next();
3052:                        varName = (String) entry.getKey();
3053:                        var = (Var) entry.getValue();
3054:                        if (!var.isVarUndefined()
3055:                                && (includeLinks || !var.isVarLink())) {
3056:                            if ((pattern == null)
3057:                                    || Util.stringMatch(varName, pattern)) {
3058:                                TclList.append(interp, list, TclString
3059:                                        .newInstance(varName));
3060:                            }
3061:                        }
3062:                    }
3063:                }
3064:
3065:                Var[] compiledLocals = frame.compiledLocals;
3066:                if (compiledLocals != null) {
3067:                    final int max = compiledLocals.length;
3068:                    for (int i = 0; i < max; i++) {
3069:                        Var clocal = compiledLocals[i];
3070:                        if (clocal != null && !clocal.isVarNonLocal()) {
3071:                            var = clocal;
3072:                            varName = (String) var.hashKey;
3073:
3074:                            if (!var.isVarUndefined()
3075:                                    && (includeLinks || !var.isVarLink())) {
3076:                                if ((pattern == null)
3077:                                        || Util.stringMatch(varName, pattern)) {
3078:                                    TclList.append(interp, list, TclString
3079:                                            .newInstance(varName));
3080:                                }
3081:                            }
3082:                        }
3083:                    }
3084:                }
3085:            }
3086:
3087:        } // End of Var class
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.