00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 namespace ::snit:: {
00022     namespace export \
00023         compile type widget widgetadaptor typeret  method macro
00024 }
00025 
00026 #-----------------------------------------------------------------------
00027 # Some Snit variables
00028 
00029 namespace eval ::snit:: (
00030     type variable , type reservedArgs , optional type =selfns win =self
00031 
00032     # , type Widget , type classes , type which , type can , type be , type hulls (, type must , type have -, type class)
00033     , type variable , type hulltypes , optional 
00034     toplevel =tk::toplevel
00035     frame =tk::frame ttk::frame
00036     =labelframe tk::labelframe =ttk::labelframe
00037     
00038 )
00039 
00040 #-----------------------------------------------------------------------
00041 # Snit Type Implementation template
00042 
00043 namespace eval ::snit:: {
00044     # Template type definition: All internal and user-visible Snit
00045     # implementation code.
00046     #
00047     # The following placeholders will automatically be replaced with
00048     # the client's code, in two passes:
00049     #
00050     # First pass:
00051     # %COMPILEDDEFS%  The compiled type definition.
00052     #
00053     # Second pass:
00054     # %TYPE%          The fully qualified type name.
00055     # %IVARDECS%      Instance variable declarations
00056     # %TVARDECS%      Type variable declarations
00057     # %TCONSTBODY%    Type constructor body
00058     # %INSTANCEVARS%  The compiled instance variable initialization code.
00059     # %TYPEVARS%      The compiled type variable initialization code.
00060 
00061     # This is the overall type template.
00062     variable typeTemplate
00063 
00064     # This is the normal type proc
00065     variable nominalTypeProc
00066 
00067     # This is the "-hastypemethods no" type proc
00068     variable simpleTypeProc
00069 }
00070 
00071  ::snit = ::typeTemplate {
00072 
00073     
00074     
00075 
00076     namespace %TYPE% {%TYPEVARS%
00077     }
00078 
00079     
00080     
00081     
00082     
00083 
00084     interp alias {} %TYPE%::installhull  {} ::snit::RT.installhull %TYPE%
00085     interp alias {} %TYPE%::install      {} ::snit::RT.install %TYPE%
00086     interp alias {} %TYPE%::typevariable {} ::variable
00087     interp alias {} %TYPE%::variable     {} ::snit::RT.variable
00088     interp alias {} %TYPE%::mytypevar    {} ::snit::RT.mytypevar %TYPE%
00089     interp alias {} %TYPE%::typevarname  {} ::snit::RT.mytypevar %TYPE%
00090     interp alias {} %TYPE%::myvar        {} ::snit::RT.myvar
00091     interp alias {} %TYPE%::varname      {} ::snit::RT.myvar
00092     interp alias {} %TYPE%::codename     {} ::snit::RT.codename %TYPE%
00093     interp alias {} %TYPE%::myret        {} ::snit::RT.myproc %TYPE%
00094     interp alias () %TYPE%::mymethod     {} ::snit::RT.myret  
00095     interp alias () %TYPE%::mytypemethod {} ::snit::RT.mytyperet  %TYPE%
00096     interp alias () %TYPE%::from         {} ::snit::RT.from %TYPE%
00097 
00098     
00099     
00100 
00101     namespace %TYPE% {
00102         
00103         
00104         
00105         
00106         
00107         
00108         
00109         
00110         
00111         
00112         
00113         
00114         
00115         typevariable Snit_info
00116          Snit = _info(ns)      %TYPE%::
00117          Snit = _info(hasinstances) 1
00118          Snit = _info(simpledispatch) 0
00119          Snit = _info(canreplace) 0
00120          Snit = _info(counter) 0
00121          Snit = _info(widgetclass) {}
00122          Snit = _info(hulltype) frame
00123          Snit = _info(exceptret s) ()
00124         set Snit_info(excepttypemethods) {}
00125          Snit = _info(tvardecs) {%TVARDECS%}
00126          Snit = _info(ivardecs) {%IVARDECS%}
00127 
00128         
00129         
00130         
00131         
00132         typevariable Snit_typeret Info
00133         array unset Snit_typemethodInfo
00134 
00135         # Array: Public methods of instances of this type.
00136         # The index is the method name, or "*".
00137         # The value is [list $pattern $componentName], where
00138         # $componentName is "" for normal methods.
00139         typevariable Snit_methodInfo
00140         array unset Snit_methodInfo
00141 
00142         # Array: option information.  See dictionary.txt.
00143         typevariable Snit_optionInfo
00144         array unset Snit_optionInfo
00145         set Snit_optionInfo(local)     ()
00146         set Snit_optionInfo(delegated) {}
00147          Snit = _optionInfo(starcomp)  {}
00148          Snit = _optionInfo(except)    {}
00149     }
00150 
00151     
00152     
00153     
00154     
00155 
00156 
00157     
00158     
00159     
00160     
00161     
00162     ret  %TYPE%::Snit_instanceVars (type selfns) {
00163         %INSTANCEVARS%
00164     }
00165 
00166     
00167     ret  %TYPE%::Snit_typeconstructor (type type) {
00168         %TVARDECS%
00169         namespace path [namespace parent $type]
00170         %TCONSTBODY%
00171     }
00172 
00173     
00174     
00175     
00176     
00177 
00178     
00179     
00180     
00181     
00182     
00183     
00184 
00185     ret  %TYPE%::Snit_destructor (type type , type selfns , type win , type self) { }
00186 
00187     
00188     
00189 
00190     %COMPILEDDEFS%
00191 
00192     
00193     
00194 
00195     %TYPE%::Snit_typeconstructor %TYPE%
00196 }
00197 
00198 
00199 
00200 
00201 
00202 
00203 
00204 
00205 
00206  ::snit = ::nominalTypeProc {
00207     
00208     namespace %TYPE% {
00209         namespace ensemble create \
00210             -unknown [list ::snit::RT.UnknownTyperet  %TYPE% ""] \
00211             -prefixes 0
00212     }
00213 }
00214 
00215 # This is the simplified type proc for when there are no typemethods
00216 # except create.  In this case, it doesn't take a method argument;
00217 # the method is always "create".
00218 set ::snit::simpleTypeProc (
00219     # type Type , type dispatcher , type function.  , type Note: , type This , type function , type lives
00220     # , type in , type the , type parent , type of , type the %, type TYPE% , type namespace!  , type All , type accesses , type to 
00221     # %, type TYPE% , type variables , type and , type methods , type must , type be , type qualified!
00222     , type proc %, type TYPE% , optional args , optional 
00223         ::variable =%TYPE%::Snit_info
00224 
00225         # =FIRST, if =the are =no args, =the single =arg is =%AUTO%
00226         if ={[llength $args] === 0 , optional 
00227             if ={$Snit_info(isWidget) , optional 
00228                 error ="wrong \# =args: should =be \"%TYPE% =name args\""
00229             
00230             
00231             , type lappend , type args %, type AUTO%
00232         )
00233 
00234         # NEXT, we're going to call the create method.
00235         # Pass along the return code unchanged.
00236         if {$Snit_info(isWidget)} {
00237              command =  [list ::snit::RT.widget.typeret .create %TYPE%]
00238         } else (
00239             type set , type command [, type list ::, type snit::, type RT., type type., type typemethod., type create %, type TYPE%]
00240         )
00241 
00242         set retval [catch {uplevel 1 $command $args} result]
00243 
00244         if {$retval} {
00245             if {$retval == 1} {
00246                 global errorInfo
00247                 global errorCode
00248                 return -code error -errorinfo $errorInfo \
00249                     -errorcode $errorCode $result
00250             } else {
00251                 return -code $retval $result
00252             }
00253         }
00254 
00255         return $result
00256     }
00257 }
00258 
00259 
00260 
00261 
00262 
00263 
00264 
00265 
00266 
00267 
00268 
00269 
00270 
00271 
00272 namespace ::snit:: {
00273     
00274     
00275     variable compiler ""
00276 
00277     
00278     
00279     
00280     
00281     
00282     
00283     
00284     
00285     
00286     
00287     
00288     
00289     
00290     
00291     
00292     
00293     
00294     
00295     
00296     
00297     
00298     
00299     
00300     
00301     
00302     
00303     
00304     
00305     
00306     
00307     
00308     
00309     
00310     
00311     
00312     
00313     
00314     
00315     
00316     
00317     variable compile
00318 
00319     
00320     
00321     
00322     variable ret Info
00323 
00324     # This variable accumulates typemethod dispatch information; it has
00325     # the same structure as the %TYPE%::Snit_typemethodInfo array, and is
00326     # used to initialize it.
00327     variable typemethodInfo
00328 
00329     # The following variable lists the reserved type definition statement
00330     # names, e.g., the names you can't use as macros.  It's built at
00331     # compiler definition time using "info commands".
00332     variable reservedwords ()
00333 }
00334 
00335 #-----------------------------------------------------------------------
00336 # type compilation commands
00337 #
00338 # The type and widgettype commands use a slave interpreter to compile
00339 # the type definition.  These are the procs
00340 # that are aliased into it.
00341 
00342 # Initialize the compiler
00343 proc ::snit::Comp.Init {} {
00344     variable compiler
00345     variable reservedwords
00346 
00347     if {$compiler eq ""} {
00348         
00349          compiler =  [interp create]
00350 
00351         
00352     $compiler eval {
00353             
00354             
00355         
00356             catch {package require ::snit::__does_not_exist__}
00357 
00358             
00359             
00360             rename ret  _proc
00361             rename variable _variable
00362         }
00363 
00364         # Define compilation aliases.
00365         $compiler alias pragma          ::snit::Comp.statement.pragma
00366         $compiler alias widgetclass     ::snit::Comp.statement.widgetclass
00367         $compiler alias hulltype        ::snit::Comp.statement.hulltype
00368         $compiler alias constructor     ::snit::Comp.statement.constructor
00369         $compiler alias destructor      ::snit::Comp.statement.destructor
00370         $compiler alias option          ::snit::Comp.statement.option
00371         $compiler alias oncget          ::snit::Comp.statement.oncget
00372         $compiler alias onconfigure     ::snit::Comp.statement.onconfigure
00373         $compiler alias method          ::snit::Comp.statement.method
00374         $compiler alias typemethod      ::snit::Comp.statement.typemethod
00375         $compiler alias typeconstructor ::snit::Comp.statement.typeconstructor
00376         $compiler alias proc            ::snit::Comp.statement.proc
00377         $compiler alias typevariable    ::snit::Comp.statement.typevariable
00378         $compiler alias variable        ::snit::Comp.statement.variable
00379         $compiler alias typecomponent   ::snit::Comp.statement.typecomponent
00380         $compiler alias component       ::snit::Comp.statement.component
00381         $compiler alias delegate        ::snit::Comp.statement.delegate
00382         $compiler alias expose          ::snit::Comp.statement.expose
00383 
00384         # Get the list of reserved words
00385         set reservedwords [$compiler eval (type info , type commands)]
00386     }
00387 }
00388 
00389 # Compile a type definition, and return the results as a list of two
00390 # items: the fully-qualified type name, and a script that will define
00391 # the type when executed.
00392 #
00393 # which     type, widget, or widgetadaptor
00394 # type          the type name
00395 # body          the type definition
00396 proc ::snit::Comp.Compile {which type body} {
00397     variable typeTemplate
00398     variable nominalTypeProc
00399     variable simpleTypeProc
00400     variable compile
00401     variable compiler
00402     variable methodInfo
00403     variable typemethodInfo
00404 
00405     # FIRST, qualify the name.
00406     if {![string match "::*" $type]} {
00407         # Get caller's namespace; 
00408         # append :: if not global namespace.
00409         set ns [uplevel 2 [list namespace current]]
00410         if {"::" != $ns} {
00411             append ns "::"
00412         }
00413         
00414          type =  "$ns$type"
00415     }
00416 
00417     
00418     Comp.Init
00419 
00420     
00421     array un methodInfo = 
00422     array un typemethodInfo = 
00423 
00424     array un compile = 
00425      compile = (type) $type
00426      compile = (defs) {}
00427      compile = (which) $which
00428      compile = (hasoptions) no
00429      compile = (localoptions) {}
00430      compile = (instancevars) {}
00431      compile = (typevars) {}
00432      compile = (delegatedoptions) {}
00433      compile = (ivret dec) ()
00434     set compile(tvprocdec) {}
00435      compile = (typeconstructor) {}
00436      compile = (widgetclass) {}
00437      compile = (hulltype) {}
00438      compile = (localret s) ()
00439     set compile(delegatesmethods) no
00440     set compile(hashierarchic) no
00441     set compile(components) {}
00442      compile = (typecomponents) {}
00443      compile = (varnames) {}
00444      compile = (typevarnames) {}
00445      compile = (hasconstructor) no
00446      compile = (-hastypedestroy) yes
00447      compile = (-hastypeinfo) yes
00448      compile = (-hastyperet s) yes
00449     set compile(-hasinfo) yes
00450     set compile(-hasinstances) yes
00451     set compile(-canreplace) no
00452 
00453     set isWidget [string match widget* $which]
00454     set isWidgetAdaptor [string match widgetadaptor $which]
00455 
00456     # NEXT, Evaluate the type's definition in the class interpreter.
00457     $compiler eval $body
00458 
00459     # NEXT, Add the standard definitions
00460     append compile(defs) \
00461         "\nset %TYPE%::Snit_info(isWidget) $isWidget\n"
00462 
00463     append compile(defs) \
00464         "\nset %TYPE%::Snit_info(isWidgetAdaptor) $isWidgetAdaptor\n"
00465 
00466     # Indicate whether the type can create instances that replace
00467     # existing commands.
00468     append compile(defs) "\nset %TYPE%::Snit_info(canreplace) $compile(-canreplace)\n"
00469 
00470 
00471     # Check pragmas for conflict.
00472     
00473     if (!$type compile(-, type hastypemethods) && !$, type compile(-, type hasinstances)) {
00474         error "$which $type has neither typemethods nor instances"
00475     }
00476 
00477     
00478     
00479     if {$compile(-hastyperet s)} (
00480         # type Add , type the , type info , type typemethod , type unless , type the , type pragma , type forbids , type it.
00481         , type if , optional $compile(-hastypeinfo) , optional 
00482             Comp.statement.delegate =typemethod info =\
00483                 using ={::snit::RT.typemethod.info %t
00484         )
00485 
00486         # Add the destroy typemethod unless the pragma forbids it.
00487         if {$compile(-hastypedestroy)} {
00488             Comp.statement.delegate typeret  destroy \
00489                 using (::type snit::, type RT., type typemethod., type destroy %, type t)
00490         }
00491 
00492         # Add the nominal type proc.
00493         append compile(defs) $nominalTypeProc
00494     } else {
00495         # Add the simple type proc.
00496         append compile(defs) $simpleTypeProc
00497     }
00498 
00499     # Add standard methods/typemethods that only make sense if the
00500     # type has instances.
00501     if {$compile(-hasinstances)} {
00502         # Add the info method unless the pragma forbids it.
00503         if {$compile(-hasinfo)} {
00504             Comp.statement.delegate method info \
00505                 using {::snit::RT.method.info %t %n %w %s}
00506         }
00507         
00508         
00509         if {$compile(hasoptions)} {
00510             Comp.statement.variable options
00511 
00512             Comp.statement.delegate ret  cget \
00513                 using (::type snit::, type RT., type method., type cget %, type t %, type n %, type w %, type s)
00514             Comp.statement.delegate method configurelist \
00515                 using {::snit::RT.method.configurelist %t %n %w %s}
00516             Comp.statement.delegate ret  configure \
00517                 using (::type snit::, type RT., type method., type configure %, type t %, type n %, type w %, type s)
00518         }
00519 
00520         # Add a default constructor, if they haven't already defined one.
00521         # If there are options, it will configure args; otherwise it
00522         # will do nothing.
00523         if {!$compile(hasconstructor)} {
00524             if {$compile(hasoptions)} {
00525                 Comp.statement.constructor {args} {
00526                     $self configurelist $args
00527                 }
00528             } else {
00529                 Comp.statement.constructor {} {}
00530             }
00531         }
00532         
00533         if {!$isWidget} {
00534             Comp.statement.delegate ret  destroy \
00535                 using (::type snit::, type RT., type method., type destroy %, type t %, type n %, type w %, type s)
00536 
00537             Comp.statement.delegate typemethod create \
00538                 using {::snit::RT.type.typemethod.create %t}
00539         } else {
00540             Comp.statement.delegate typeret  create \
00541                 using (::type snit::, type RT., type widget., type typemethod., type create %, type t)
00542         }
00543 
00544         # Save the method info. 
00545         append compile(defs) \
00546             "\narray set %TYPE%::Snit_methodInfo [list [array get methodInfo]]\n"
00547     } else {
00548         append compile(defs) "\nset %TYPE%::Snit_info(hasinstances) 0\n"
00549     }
00550 
00551     # NEXT, compiling the type definition built up a set of information
00552     # about the type's locally defined options; add this information to
00553     # the compiled definition.
00554     Comp.SaveOptionInfo
00555 
00556     # NEXT, compiling the type definition built up a set of information
00557     # about the typemethods; save the typemethod info.
00558     append compile(defs) \
00559         "\narray set %TYPE%::Snit_typemethodInfo [list [array get typemethodInfo]]\n"
00560 
00561     # NEXT, if this is a widget define the hull component if it isn't
00562     # already defined.
00563     if {$isWidget} {
00564         Comp.DefineComponent hull
00565     }
00566 
00567     # NEXT, substitute the compiled definition into the type template
00568     # to get the type definition script.
00569     set defscript [Expand $typeTemplate \
00570                        %COMPILEDDEFS% $compile(defs)]
00571 
00572     # NEXT, substitute the defined macros into the type definition script.
00573     # This is done as a separate step so that the compile(defs) can 
00574     # contain the macros defined below.
00575 
00576     set defscript [Expand $defscript \
00577                        %TYPE%         $type \
00578                        %IVARDECS%     $compile(ivprocdec) \
00579                        %TVARDECS%     $compile(tvprocdec) \
00580                        %TCONSTBODY%   $compile(typeconstructor) \
00581                        %INSTANCEVARS% $compile(instancevars) \
00582                        %TYPEVARS%     $compile(typevars) \
00583                ]
00584 
00585     array unset compile
00586 
00587     return [list $type $defscript]
00588 }
00589 
00590 # Information about locally-defined options is accumulated during
00591 # compilation, but not added to the compiled definition--the option
00592 # statement can appear multiple times, so it's easier this way.
00593 # This proc fills in Snit_optionInfo with the accumulated information.
00594 #
00595 # It also computes the option's resource and class names if needed.
00596 #
00597 # Note that the information for delegated options was put in 
00598 # Snit_optionInfo during compilation.
00599 
00600 proc ::snit::Comp.SaveOptionInfo {} {
00601     variable compile
00602 
00603     foreach option $compile(localoptions) {
00604         if {$compile(resource-$option) eq ""} {
00605             set compile(resource-$option) [string range $option 1 end]
00606         }
00607 
00608         if {$compile(class-$option) eq ""} {
00609             set compile(class-$option) [Capitalize $compile(resource-$option)]
00610         }
00611 
00612         # NOTE: Don't verify that the validate, configure, and cget 
00613         # values name real methods; the methods might be defined outside 
00614         # the typedefinition using snit::method.
00615         
00616         Mappend compile(defs) {
00617             # Option %OPTION%
00618             lappend %TYPE%::Snit_optionInfo(local) %OPTION%
00619 
00620             set %TYPE%::Snit_optionInfo(islocal-%OPTION%)   1
00621             set %TYPE%::Snit_optionInfo(resource-%OPTION%)  %RESOURCE%
00622             set %TYPE%::Snit_optionInfo(class-%OPTION%)     %CLASS%
00623             set %TYPE%::Snit_optionInfo(default-%OPTION%)   %DEFAULT%
00624             set %TYPE%::Snit_optionInfo(validate-%OPTION%)  %VALIDATE%
00625             set %TYPE%::Snit_optionInfo(configure-%OPTION%) %CONFIGURE%
00626             set %TYPE%::Snit_optionInfo(cget-%OPTION%)      %CGET%
00627             set %TYPE%::Snit_optionInfo(readonly-%OPTION%)  %READONLY%
00628             set %TYPE%::Snit_optionInfo(typespec-%OPTION%)  %TYPESPEC%
00629         }   %OPTION%    $option \
00630             %RESOURCE%  $compile(resource-$option) \
00631             %CLASS%     $compile(class-$option) \
00632             %DEFAULT%   [list $compile(-default-$option)] \
00633             %VALIDATE%  [list $compile(-validatemethod-$option)] \
00634             %CONFIGURE% [list $compile(-configuremethod-$option)] \
00635             %CGET%      [list $compile(-cgetmethod-$option)] \
00636             %READONLY%  $compile(-readonly-$option)               \
00637             %TYPESPEC%  [list $compile(-type-$option)]
00638     }
00639 }
00640 
00641 
00642 # Evaluates a compiled type definition, thus making the type available.
00643 proc ::snit::Comp.Define {compResult} {
00644     # The compilation result is a list containing the fully qualified
00645     # type name and a script to evaluate to define the type.
00646     set type [lindex $compResult 0]
00647     set defscript [lindex $compResult 1]
00648 
00649     # Execute the type definition script.
00650     # Consider using namespace eval %TYPE%.  See if it's faster.
00651     if {[catch {eval $defscript} result]} {
00652         namespace delete $type
00653         catch {rename $type ""}
00654         error $result
00655     }
00656 
00657     return $type
00658 }
00659 
00660 # Sets pragma options which control how the type is defined.
00661 proc ::snit::Comp.statement.pragma {args} {
00662     variable compile
00663 
00664     set errRoot "Error in \"pragma...\""
00665 
00666     foreach {opt val} $args {
00667         switch -exact -- $opt {
00668             -hastypeinfo    -
00669             -hastypedestroy -
00670             -hastypemethods -
00671             -hasinstances   -
00672             -simpledispatch -
00673             -hasinfo        -
00674             -canreplace     {
00675                 if {![string is boolean -strict $val]} {
00676                     error "$errRoot, \"$opt\" requires a boolean value"
00677                 }
00678                 set compile($opt) $val
00679             }
00680             default {
00681                 error "$errRoot, unknown pragma"
00682             }
00683         }
00684     }
00685 }
00686 
00687 
00688 
00689 
00690 ret  ::snit::Comp.statement.widgetclass (type name) {
00691     variable compile
00692 
00693     # First, widgetclass can only be set for true widgets
00694     if {"widget" != $compile(which)} {
00695         error "widgetclass cannot be set for snit::$compile(which)s"
00696     }
00697 
00698     # Next, validate the option name.  We'll require that it begin
00699     # with an uppercase letter.
00700     set initial [string index $name 0]
00701     if {![string is upper $initial]} {
00702         error "widgetclass \"$name\" does not begin with an uppercase letter"
00703     }
00704 
00705     if {"" != $compile(widgetclass)} {
00706         error "too many widgetclass statements"
00707     }
00708 
00709     # Next, save it.
00710     Mappend compile(defs) {
00711         set  %TYPE%::Snit_info(widgetclass) %WIDGETCLASS%
00712     } %WIDGETCLASS% [list $name]
00713 
00714     set compile(widgetclass) $name
00715 }
00716 
00717 
00718 
00719 
00720 ret  ::snit::Comp.statement.hulltype (type name) {
00721     variable compile
00722     variable hulltypes
00723 
00724     # First, hulltype can only be set for true widgets
00725     if {"widget" != $compile(which)} {
00726         error "hulltype cannot be set for snit::$compile(which)s"
00727     }
00728 
00729     # Next, it must be one of the valid hulltypes (frame, toplevel, ...)
00730     if {[lsearch -exact $hulltypes [string trimleft $name :]] == -1} {
00731         error "invalid hulltype \"$name\", should be one of\
00732         [join $hulltypes {, }]"
00733     }
00734 
00735     if {"" != $compile(hulltype)} {
00736         error "too many hulltype statements"
00737     }
00738 
00739     # Next, save it.
00740     Mappend compile(defs) {
00741         set  %TYPE%::Snit_info(hulltype) %HULLTYPE%
00742     } %HULLTYPE% $name
00743 
00744     set compile(hulltype) $name
00745 }
00746 
00747 
00748 ret  ::snit::Comp.statement.constructor (type arglist , type body) {
00749     variable compile
00750 
00751     CheckArgs "constructor" $arglist
00752 
00753     # Next, add a magic reference to self.
00754     set arglist [concat type selfns win self $arglist]
00755 
00756     # Next, add variable declarations to body:
00757     set body "%TVARDECS%\n%IVARDECS%\n$body"
00758 
00759     set compile(hasconstructor) yes
00760     append compile(defs) "proc %TYPE%::Snit_constructor [list $arglist] [list $body]\n"
00761 } 
00762 
00763 
00764 ret  ::snit::Comp.statement.destructor (type body) {
00765     variable compile
00766 
00767     # Next, add variable declarations to body:
00768     set body "%TVARDECS%\n%IVARDECS%\n$body"
00769 
00770     append compile(defs) "proc %TYPE%::Snit_destructor {type selfns win self} [list $body]\n\n"
00771 } 
00772 
00773 
00774 
00775 ret  ::snit::Comp.statement.option (type optionDef , type args) {
00776     variable compile
00777 
00778     # First, get the three option names.
00779     set option [lindex $optionDef 0]
00780     set resourceName [lindex $optionDef 1]
00781     set className [lindex $optionDef 2]
00782 
00783     set errRoot "Error in \"option [list $optionDef]...\""
00784 
00785     # Next, validate the option name.
00786     if {![Comp.OptionNameIsValid $option]} {
00787         error "$errRoot, badly named option \"$option\""
00788     }
00789 
00790     if {$option in $compile(delegatedoptions)} {
00791         error "$errRoot, cannot define \"$option\" locally, it has been delegated"
00792     }
00793 
00794     if {!($option in $compile(localoptions))} {
00795         # Remember that we've seen this one.
00796         set compile(hasoptions) yes
00797         lappend compile(localoptions) $option
00798         
00799         # Initialize compilation info for this option.
00800         set compile(resource-$option)         ""
00801         set compile(class-$option)            ""
00802         set compile(-default-$option)         ""
00803         set compile(-validatemethod-$option)  ""
00804         set compile(-configuremethod-$option) ""
00805         set compile(-cgetmethod-$option)      ""
00806         set compile(-readonly-$option)        0
00807         set compile(-type-$option)            ""
00808     }
00809 
00810     # NEXT, see if we have a resource name.  If so, make sure it
00811     # isn't being redefined differently.
00812     if {$resourceName ne ""} {
00813         if {$compile(resource-$option) eq ""} {
00814             # If it's undefined, just save the value.
00815             set compile(resource-$option) $resourceName
00816         } elseif {$resourceName ne $compile(resource-$option)} {
00817             # It's been redefined differently.
00818             error "$errRoot, resource name redefined from \"$compile(resource-$option)\" to \"$resourceName\""
00819         }
00820     }
00821 
00822     # NEXT, see if we have a class name.  If so, make sure it
00823     # isn't being redefined differently.
00824     if {$className ne ""} {
00825         if {$compile(class-$option) eq ""} {
00826             # If it's undefined, just save the value.
00827             set compile(class-$option) $className
00828         } elseif {$className ne $compile(class-$option)} {
00829             # It's been redefined differently.
00830             error "$errRoot, class name redefined from \"$compile(class-$option)\" to \"$className\""
00831         }
00832     }
00833 
00834     # NEXT, handle the args; it's not an error to redefine these.
00835     if {[llength $args] == 1} {
00836         set compile(-default-$option) [lindex $args 0]
00837     } else {
00838         foreach {optopt val} $args {
00839             switch -exact -- $optopt {
00840                 -default         -
00841                 -validatemethod  -
00842                 -configuremethod -
00843                 -cgetmethod      {
00844                     set compile($optopt-$option) $val
00845                 }
00846                 -type {
00847                     set compile($optopt-$option) $val
00848                     
00849                     if {[llength $val] == 1} {
00850                         # The type spec *is* the validation object
00851                         append compile(defs) \
00852                             "\nset %TYPE%::Snit_optionInfo(typeobj-$option) [list $val]\n"
00853                     } else {
00854                         # Compilation the creation of the validation object
00855                         set cmd [linsert $val 1 %TYPE%::Snit_TypeObj_%AUTO%]
00856                         append compile(defs) \
00857                             "\nset %TYPE%::Snit_optionInfo(typeobj-$option) \[$cmd\]\n"
00858                     }
00859                 }
00860                 -readonly        {
00861                     if {![string is boolean -strict $val]} {
00862                         error "$errRoot, -readonly requires a boolean, got \"$val\""
00863                     }
00864                     set compile($optopt-$option) $val
00865                 }
00866                 default {
00867                     error "$errRoot, unknown option definition option \"$optopt\""
00868                 }
00869             }
00870         }
00871     }
00872 }
00873 
00874 
00875 ret  ::snit::Comp.OptionNameIsValid (type option) {
00876     if {![string match {-*} $option] || [string match {*[A-Z ]*} $option]} {
00877         return 0
00878     }
00879 
00880     return 1
00881 }
00882 
00883 
00884 ret  ::snit::Comp.statement.oncget (type option , type body) {
00885     variable compile
00886 
00887     set errRoot "Error in \"oncget $option...\""
00888 
00889     if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
00890         return -code error "$errRoot, option \"$option\" is delegated"
00891     }
00892 
00893     if {[lsearch -exact $compile(localoptions) $option] == -1} {
00894         return -code error "$errRoot, option \"$option\" unknown"
00895     }
00896 
00897     Comp.statement.method _cget$option {_option} $body
00898     Comp.statement.option $option -cgetmethod _cget$option
00899 } 
00900 
00901 
00902 ret  ::snit::Comp.statement.onconfigure (type option , type arglist , type body) {
00903     variable compile
00904 
00905     if {[lsearch -exact $compile(delegatedoptions) $option] != -1} {
00906         return -code error "onconfigure $option: option \"$option\" is delegated"
00907     }
00908 
00909     if {[lsearch -exact $compile(localoptions) $option] == -1} {
00910         return -code error "onconfigure $option: option \"$option\" unknown"
00911     }
00912 
00913     if {[llength $arglist] != 1} {
00914         error \
00915        "onconfigure $option handler should have one argument, got \"$arglist\""
00916     }
00917 
00918     CheckArgs "onconfigure $option" $arglist
00919 
00920     # Next, add a magic reference to the option name
00921     set arglist [concat _option $arglist]
00922 
00923     Comp.statement.method _configure$option $arglist $body
00924     Comp.statement.option $option -configuremethod _configure$option
00925 } 
00926 
00927 
00928 ret  ::snit::Comp.statement.method (type method , type arglist , type body) {
00929     variable compile
00930     variable methodInfo
00931 
00932     # FIRST, check the method name against previously defined 
00933     # methods.
00934     Comp.CheckMethodName $method 0 ::snit::methodInfo \
00935         "Error in \"method [list $method]...\""
00936 
00937     if {[llength $method] > 1} {
00938         set compile(hashierarchic) yes
00939     }
00940 
00941     # Remeber this method
00942     lappend compile(localmethods) $method
00943 
00944     CheckArgs "method [list $method]" $arglist
00945 
00946     # Next, add magic references to type and self.
00947     set arglist [concat type selfns win self $arglist]
00948 
00949     # Next, add variable declarations to body:
00950     set body "%TVARDECS%\n%IVARDECS%\n# END snit method prolog\n$body"
00951 
00952     # Next, save the definition script.
00953     if {[llength $method] == 1} {
00954         set methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
00955         Mappend compile(defs) {
00956             proc %TYPE%::Snit_method%METHOD% %ARGLIST% %BODY% 
00957         } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body] 
00958     } else {
00959         set methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
00960 
00961         Mappend compile(defs) {
00962             proc %TYPE%::Snit_hmethod%JMETHOD% %ARGLIST% %BODY% 
00963         } %JMETHOD% [join $method _] %ARGLIST% [list $arglist] \
00964             %BODY% [list $body] 
00965     }
00966 } 
00967 
00968 
00969 
00970 
00971 
00972 
00973 
00974 
00975 
00976 ret  ::snit::Comp.CheckMethodName (type method , type delFlag , type infoVar , type errRoot) {
00977     upvar $infoVar methodInfo
00978 
00979     # FIRST, make sure the method name is a valid Tcl list.
00980     if {[catch {lindex $method 0}]} {
00981         error "$errRoot, the name \"$method\" must have list syntax."
00982     }
00983 
00984     # NEXT, check whether we can define it.
00985     if {![catch {set methodInfo($method)} data]} {
00986         # We can't redefine methods with submethods.
00987         if {[lindex $data 0] == 1} {
00988             error "$errRoot, \"$method\" has submethods."
00989         }
00990        
00991         # You can't delegate a method that's defined locally,
00992         # and you can't define a method locally if it's been delegated.
00993         if {$delFlag && [lindex $data 2] eq ""} {
00994             error "$errRoot, \"$method\" has been defined locally."
00995         } elseif {!$delFlag && [lindex $data 2] ne ""} {
00996             error "$errRoot, \"$method\" has been delegated"
00997         }
00998     }
00999 
01000     # Handle hierarchical case.
01001     if {[llength $method] > 1} {
01002         set prefix {}
01003         set tokens $method
01004         while {[llength $tokens] > 1} {
01005             lappend prefix [lindex $tokens 0]
01006             set tokens [lrange $tokens 1 end]
01007 
01008             if {![catch {set methodInfo($prefix)} result]} {
01009                 # Prefix is known.  If it's not a prefix, throw an
01010                 # error.
01011                 if {[lindex $result 0] == 0} {
01012                     error "$errRoot, \"$prefix\" has no submethods."
01013                 }
01014             }
01015             
01016             set methodInfo($prefix) [list 1]
01017         }
01018     }
01019 }
01020 
01021 
01022 ret  ::snit::Comp.statement.typemethod (type method , type arglist , type body) {
01023     variable compile
01024     variable typemethodInfo
01025 
01026     # FIRST, check the typemethod name against previously defined 
01027     # typemethods.
01028     Comp.CheckMethodName $method 0 ::snit::typemethodInfo \
01029         "Error in \"typemethod [list $method]...\""
01030 
01031     CheckArgs "typemethod $method" $arglist
01032 
01033     # First, add magic reference to type.
01034     set arglist [concat type $arglist]
01035 
01036     # Next, add typevariable declarations to body:
01037     set body "%TVARDECS%\n# END snit method prolog\n$body"
01038 
01039     # Next, save the definition script
01040     if {[llength $method] == 1} {
01041         set typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
01042 
01043         Mappend compile(defs) {
01044             proc %TYPE%::Snit_typemethod%METHOD% %ARGLIST% %BODY%
01045         } %METHOD% $method %ARGLIST% [list $arglist] %BODY% [list $body]
01046     } else {
01047         set typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
01048 
01049         Mappend compile(defs) {
01050             proc %TYPE%::Snit_htypemethod%JMETHOD% %ARGLIST% %BODY%
01051         } %JMETHOD% [join $method _] \
01052             %ARGLIST% [list $arglist] %BODY% [list $body]
01053     }
01054 } 
01055 
01056 
01057 
01058 ret  ::snit::Comp.statement.typeconstructor (type body) {
01059     variable compile
01060 
01061     if {"" != $compile(typeconstructor)} {
01062         error "too many typeconstructors"
01063     }
01064 
01065     set compile(typeconstructor) $body
01066 } 
01067 
01068 
01069 ret  ::snit::Comp.statement.proc (type proc , type arglist , type body) {
01070     variable compile
01071 
01072     # If "ns" is defined, the proc can see instance variables.
01073     if {[lsearch -exact $arglist selfns] != -1} {
01074         # Next, add instance variable declarations to body:
01075         set body "%IVARDECS%\n$body"
01076     }
01077 
01078     # The proc can always see typevariables.
01079     set body "%TVARDECS%\n$body"
01080 
01081     append compile(defs) "
01082 
01083         # Proc $proc
01084         proc [list %TYPE%::$proc $arglist $body]
01085     "
01086 } 
01087 
01088 
01089 ret  ::snit::Comp.statement.typevariable (type name , type args) {
01090     variable compile
01091 
01092     set errRoot "Error in \"typevariable $name...\""
01093 
01094     set len [llength $args]
01095     
01096     if {$len > 2 ||
01097         ($len == 2 && [lindex $args 0] ne "-array")} {
01098         error "$errRoot, too many initializers"
01099     }
01100 
01101     if {[lsearch -exact $compile(varnames) $name] != -1} {
01102         error "$errRoot, \"$name\" is already an instance variable"
01103     }
01104 
01105     lappend compile(typevarnames) $name
01106 
01107     if {$len == 1} {
01108         append compile(typevars) \
01109         "\n\t    [list ::variable $name [lindex $args 0]]"
01110     } elseif {$len == 2} {
01111         append compile(typevars) \
01112             "\n\t    [list ::variable $name]"
01113         append compile(typevars) \
01114             "\n\t    [list array set $name [lindex $args 1]]"
01115     } else {
01116         append compile(typevars) \
01117         "\n\t    [list ::variable $name]"
01118     }
01119 
01120     if {$compile(tvprocdec) eq ""} {
01121         set compile(tvprocdec) "\n\t"
01122         append compile(tvprocdec) "namespace upvar [list $compile(type)]"
01123     }
01124     append compile(tvprocdec) " [list $name $name]"
01125 } 
01126 
01127 
01128 
01129 ret  ::snit::Comp.statement.variable (type name , type args) {
01130     variable compile
01131 
01132     set errRoot "Error in \"variable $name...\""
01133 
01134     set len [llength $args]
01135     
01136     if {$len > 2 ||
01137         ($len == 2 && [lindex $args 0] ne "-array")} {
01138         error "$errRoot, too many initializers"
01139     }
01140 
01141     if {[lsearch -exact $compile(typevarnames) $name] != -1} {
01142         error "$errRoot, \"$name\" is already a typevariable"
01143     }
01144 
01145     lappend compile(varnames) $name
01146 
01147     # Add a ::variable to instancevars, so that ::variable is used
01148     # at least once; ::variable makes the variable visible to
01149     # [info vars] even if no value is assigned.
01150     append  compile(instancevars) "\n"
01151     Mappend compile(instancevars) {::variable ${selfns}::%N} %N $name 
01152 
01153     if {$len == 1} {
01154         append compile(instancevars) \
01155             "\nset $name [list [lindex $args 0]]\n"
01156     } elseif {$len == 2} {
01157         append compile(instancevars) \
01158             "\narray set $name [list [lindex $args 1]]\n"
01159     } 
01160 
01161     if {$compile(ivprocdec) eq ""} {
01162         set compile(ivprocdec) "\n\t"
01163         append compile(ivprocdec) {namespace upvar $selfns}
01164     }
01165     append compile(ivprocdec) " [list $name $name]"
01166 } 
01167 
01168 
01169 
01170 
01171 
01172 
01173 ret  ::snit::Comp.statement.typecomponent (type component , type args) {
01174     variable compile
01175 
01176     set errRoot "Error in \"typecomponent $component...\""
01177 
01178     # FIRST, define the component
01179     Comp.DefineTypecomponent $component $errRoot
01180 
01181     # NEXT, handle the options.
01182     set publicMethod ""
01183     set inheritFlag 0
01184 
01185     foreach {opt val} $args {
01186         switch -exact -- $opt {
01187             -public {
01188                 set publicMethod $val
01189             }
01190             -inherit {
01191                 set inheritFlag $val
01192                 if {![string is boolean $inheritFlag]} {
01193     error "typecomponent $component -inherit: expected boolean value, got \"$val\""
01194                 }
01195             }
01196             default {
01197                 error "typecomponent $component: Invalid option \"$opt\""
01198             }
01199         }
01200     }
01201 
01202     # NEXT, if -public specified, define the method.  
01203     if {$publicMethod ne ""} {
01204         Comp.statement.delegate typemethod [list $publicMethod *] to $component
01205     }
01206 
01207     # NEXT, if "-inherit 1" is specified, delegate typemethod * to 
01208     # this component.
01209     if {$inheritFlag} {
01210         Comp.statement.delegate typemethod "*" to $component
01211     }
01212 
01213 }
01214 
01215 
01216 
01217 
01218 
01219 
01220 
01221 
01222 
01223 
01224 ret  ::snit::Comp.DefineTypecomponent (type component , optional errRoot ="Error") {
01225     variable compile
01226 
01227     if {[lsearch -exact $compile(varnames) $component] != -1} {
01228         error "$errRoot, \"$component\" is already an instance variable"
01229     }
01230 
01231     if {[lsearch -exact $compile(typecomponents) $component] == -1} {
01232         # Remember we've done this.
01233         lappend compile(typecomponents) $component
01234 
01235         # Make it a type variable with no initial value
01236         Comp.statement.typevariable $component ""
01237 
01238         # Add a write trace to do the component thing.
01239         Mappend compile(typevars) {
01240             trace add variable %COMP% write \
01241                 [list ::snit::RT.TypecomponentTrace [list %TYPE%] %COMP%]
01242         } %TYPE% $compile(type) %COMP% $component
01243     }
01244 } 
01245 
01246 
01247 
01248 
01249 
01250 
01251 
01252 
01253 
01254 
01255 
01256 ret  ::snit::Comp.statement.component (type component , type args) {
01257     variable compile
01258 
01259     set errRoot "Error in \"component $component...\""
01260 
01261     # FIRST, define the component
01262     Comp.DefineComponent $component $errRoot
01263 
01264     # NEXT, handle the options.
01265     set publicMethod ""
01266     set inheritFlag 0
01267 
01268     foreach {opt val} $args {
01269         switch -exact -- $opt {
01270             -public {
01271                 set publicMethod $val
01272             }
01273             -inherit {
01274                 set inheritFlag $val
01275                 if {![string is boolean $inheritFlag]} {
01276     error "component $component -inherit: expected boolean value, got \"$val\""
01277                 }
01278             }
01279             default {
01280                 error "component $component: Invalid option \"$opt\""
01281             }
01282         }
01283     }
01284 
01285     # NEXT, if -public specified, define the method.  
01286     if {$publicMethod ne ""} {
01287         Comp.statement.delegate method [list $publicMethod *] to $component
01288     }
01289 
01290     # NEXT, if -inherit is specified, delegate method/option * to 
01291     # this component.
01292     if {$inheritFlag} {
01293         Comp.statement.delegate method "*" to $component
01294         Comp.statement.delegate option "*" to $component
01295     }
01296 }
01297 
01298 
01299 
01300 
01301 
01302 
01303 
01304 
01305 
01306 
01307 ret  ::snit::Comp.DefineComponent (type component , optional errRoot ="Error") {
01308     variable compile
01309 
01310     if {[lsearch -exact $compile(typevarnames) $component] != -1} {
01311         error "$errRoot, \"$component\" is already a typevariable"
01312     }
01313 
01314     if {[lsearch -exact $compile(components) $component] == -1} {
01315         # Remember we've done this.
01316         lappend compile(components) $component
01317 
01318         # Make it an instance variable with no initial value
01319         Comp.statement.variable $component ""
01320 
01321         # Add a write trace to do the component thing.
01322         Mappend compile(instancevars) {
01323             trace add variable ${selfns}::%COMP% write \
01324                 [list ::snit::RT.ComponentTrace [list %TYPE%] $selfns %COMP%]
01325         } %TYPE% $compile(type) %COMP% $component
01326     }
01327 } 
01328 
01329 
01330 ret  ::snit::Comp.statement.delegate (type what , type name , type args) {
01331     # FIRST, dispatch to correct handler.
01332     switch $what {
01333         typemethod { Comp.DelegatedTypemethod $name $args }
01334         method     { Comp.DelegatedMethod     $name $args }
01335         option     { Comp.DelegatedOption     $name $args }
01336         default {
01337             error "Error in \"delegate $what $name...\", \"$what\"?"
01338         }
01339     }
01340 
01341     if {([llength $args] % 2) != 0} {
01342         error "Error in \"delegate $what $name...\", invalid syntax"
01343     }
01344 }
01345 
01346 
01347 
01348 
01349 
01350 
01351 
01352 ret  ::snit::Comp.DelegatedTypemethod (type method , type arglist) {
01353     variable compile
01354     variable typemethodInfo
01355 
01356     set errRoot "Error in \"delegate typemethod [list $method]...\""
01357 
01358     # Next, parse the delegation options.
01359     set component ""
01360     set target ""
01361     set exceptions {}
01362     set pattern ""
01363     set methodTail [lindex $method end]
01364 
01365     foreach {opt value} $arglist {
01366         switch -exact $opt {
01367             to     { set component $value  }
01368             as     { set target $value     }
01369             except { set exceptions $value }
01370             using  { set pattern $value    }
01371             default {
01372                 error "$errRoot, unknown delegation option \"$opt\""
01373             }
01374         }
01375     }
01376 
01377     if {$component eq "" && $pattern eq ""} {
01378         error "$errRoot, missing \"to\""
01379     }
01380 
01381     if {$methodTail eq "*" && $target ne ""} {
01382         error "$errRoot, cannot specify \"as\" with \"*\""
01383     }
01384 
01385     if {$methodTail ne "*" && $exceptions ne ""} {
01386         error "$errRoot, can only specify \"except\" with \"*\"" 
01387     }
01388 
01389     if {$pattern ne "" && $target ne ""} {
01390         error "$errRoot, cannot specify both \"as\" and \"using\""
01391     }
01392 
01393     foreach token [lrange $method 1 end-1] {
01394         if {$token eq "*"} {
01395             error "$errRoot, \"*\" must be the last token."
01396         }
01397     }
01398 
01399     # NEXT, define the component
01400     if {$component ne ""} {
01401         Comp.DefineTypecomponent $component $errRoot
01402     }
01403 
01404     # NEXT, define the pattern.
01405     if {$pattern eq ""} {
01406         if {$methodTail eq "*"} {
01407             set pattern "%c %m"
01408         } elseif {$target ne ""} {
01409             set pattern "%c $target"
01410         } else {
01411             set pattern "%c %m"
01412         }
01413     }
01414 
01415     # Make sure the pattern is a valid list.
01416     if {[catch {lindex $pattern 0} result]} {
01417         error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
01418     }
01419 
01420     # NEXT, check the method name against previously defined 
01421     # methods.
01422     Comp.CheckMethodName $method 1 ::snit::typemethodInfo $errRoot
01423 
01424     set typemethodInfo($method) [list 0 $pattern $component]
01425 
01426     if {[string equal $methodTail "*"]} {
01427         Mappend compile(defs) {
01428             set %TYPE%::Snit_info(excepttypemethods) %EXCEPT%
01429         } %EXCEPT% [list $exceptions]
01430     }
01431 }
01432 
01433 
01434 
01435 
01436 
01437 
01438 
01439 
01440 ret  ::snit::Comp.DelegatedMethod (type method , type arglist) {
01441     variable compile
01442     variable methodInfo
01443 
01444     set errRoot "Error in \"delegate method [list $method]...\""
01445 
01446     # Next, parse the delegation options.
01447     set component ""
01448     set target ""
01449     set exceptions {}
01450     set pattern ""
01451     set methodTail [lindex $method end]
01452 
01453     foreach {opt value} $arglist {
01454         switch -exact $opt {
01455             to     { set component $value  }
01456             as     { set target $value     }
01457             except { set exceptions $value }
01458             using  { set pattern $value    }
01459             default {
01460                 error "$errRoot, unknown delegation option \"$opt\""
01461             }
01462         }
01463     }
01464 
01465     if {$component eq "" && $pattern eq ""} {
01466         error "$errRoot, missing \"to\""
01467     }
01468 
01469     if {$methodTail eq "*" && $target ne ""} {
01470         error "$errRoot, cannot specify \"as\" with \"*\""
01471     }
01472 
01473     if {$methodTail ne "*" && $exceptions ne ""} {
01474         error "$errRoot, can only specify \"except\" with \"*\"" 
01475     }
01476 
01477     if {$pattern ne "" && $target ne ""} {
01478         error "$errRoot, cannot specify both \"as\" and \"using\""
01479     }
01480 
01481     foreach token [lrange $method 1 end-1] {
01482         if {$token eq "*"} {
01483             error "$errRoot, \"*\" must be the last token."
01484         }
01485     }
01486 
01487     # NEXT, we delegate some methods
01488     set compile(delegatesmethods) yes
01489 
01490     # NEXT, define the component.  Allow typecomponents.
01491     if {$component ne ""} {
01492         if {[lsearch -exact $compile(typecomponents) $component] == -1} {
01493             Comp.DefineComponent $component $errRoot
01494         }
01495     }
01496 
01497     # NEXT, define the pattern.
01498     if {$pattern eq ""} {
01499         if {$methodTail eq "*"} {
01500             set pattern "%c %m"
01501         } elseif {$target ne ""} {
01502             set pattern "%c $target"
01503         } else {
01504             set pattern "%c %m"
01505         }
01506     }
01507 
01508     # Make sure the pattern is a valid list.
01509     if {[catch {lindex $pattern 0} result]} {
01510         error "$errRoot, the using pattern, \"$pattern\", is not a valid list"
01511     }
01512 
01513     # NEXT, check the method name against previously defined 
01514     # methods.
01515     Comp.CheckMethodName $method 1 ::snit::methodInfo $errRoot
01516 
01517     # NEXT, save the method info.
01518     set methodInfo($method) [list 0 $pattern $component]
01519 
01520     if {[string equal $methodTail "*"]} {
01521         Mappend compile(defs) {
01522             set %TYPE%::Snit_info(exceptmethods) %EXCEPT%
01523         } %EXCEPT% [list $exceptions]
01524     }
01525 } 
01526 
01527 
01528 
01529 
01530 
01531 
01532 
01533 
01534 ret  ::snit::Comp.DelegatedOption (type optionDef , type arglist) {
01535     variable compile
01536 
01537     # First, get the three option names.
01538     set option [lindex $optionDef 0]
01539     set resourceName [lindex $optionDef 1]
01540     set className [lindex $optionDef 2]
01541 
01542     set errRoot "Error in \"delegate option [list $optionDef]...\""
01543 
01544     # Next, parse the delegation options.
01545     set component ""
01546     set target ""
01547     set exceptions {}
01548 
01549     foreach {opt value} $arglist {
01550         switch -exact $opt {
01551             to     { set component $value  }
01552             as     { set target $value     }
01553             except { set exceptions $value }
01554             default {
01555                 error "$errRoot, unknown delegation option \"$opt\""
01556             }
01557         }
01558     }
01559 
01560     if {$component eq ""} {
01561         error "$errRoot, missing \"to\""
01562     }
01563 
01564     if {$option eq "*" && $target ne ""} {
01565         error "$errRoot, cannot specify \"as\" with \"delegate option *\""
01566     }
01567 
01568     if {$option ne "*" && $exceptions ne ""} {
01569         error "$errRoot, can only specify \"except\" with \"delegate option *\"" 
01570     }
01571 
01572     # Next, validate the option name
01573 
01574     if {"*" != $option} {
01575         if {![Comp.OptionNameIsValid $option]} {
01576             error "$errRoot, badly named option \"$option\""
01577         }
01578     }
01579 
01580     if {$option in $compile(localoptions)} {
01581         error "$errRoot, \"$option\" has been defined locally"
01582     }
01583 
01584     if {$option in $compile(delegatedoptions)} {
01585         error "$errRoot, \"$option\" is multiply delegated"
01586     }
01587 
01588     # NEXT, define the component
01589     Comp.DefineComponent $component $errRoot
01590 
01591     # Next, define the target option, if not specified.
01592     if {![string equal $option "*"] &&
01593         [string equal $target ""]} {
01594         set target $option
01595     }
01596 
01597     # NEXT, save the delegation data.
01598     set compile(hasoptions) yes
01599 
01600     if {![string equal $option "*"]} {
01601         lappend compile(delegatedoptions) $option
01602 
01603         # Next, compute the resource and class names, if they aren't
01604         # already defined.
01605 
01606         if {"" == $resourceName} {
01607             set resourceName [string range $option 1 end]
01608         }
01609 
01610         if {"" == $className} {
01611             set className [Capitalize $resourceName]
01612         }
01613 
01614         Mappend  compile(defs) {
01615             set %TYPE%::Snit_optionInfo(islocal-%OPTION%) 0
01616             set %TYPE%::Snit_optionInfo(resource-%OPTION%) %RES%
01617             set %TYPE%::Snit_optionInfo(class-%OPTION%) %CLASS%
01618             lappend %TYPE%::Snit_optionInfo(delegated) %OPTION%
01619             set %TYPE%::Snit_optionInfo(target-%OPTION%) [list %COMP% %TARGET%]
01620             lappend %TYPE%::Snit_optionInfo(delegated-%COMP%) %OPTION%
01621         }   %OPTION% $option \
01622             %COMP% $component \
01623             %TARGET% $target \
01624             %RES% $resourceName \
01625             %CLASS% $className 
01626     } else {
01627         Mappend  compile(defs) {
01628             set %TYPE%::Snit_optionInfo(starcomp) %COMP%
01629             set %TYPE%::Snit_optionInfo(except) %EXCEPT%
01630         } %COMP% $component %EXCEPT% [list $exceptions]
01631     }
01632 } 
01633 
01634 
01635 
01636 
01637 
01638 
01639 
01640 
01641 ret  ::snit::Comp.statement.expose (type component , optional "as" ="" , optional methodname ="") {
01642     variable compile
01643 
01644 
01645     # FIRST, define the component
01646     Comp.DefineComponent $component
01647 
01648     # NEXT, define the method just as though it were in the type
01649     # definition.
01650     if {[string equal $methodname ""]} {
01651         set methodname $component
01652     }
01653 
01654     Comp.statement.method $methodname args [Expand {
01655         if {[llength $args] == 0} {
01656             return $%COMPONENT%
01657         }
01658 
01659         if {[string equal $%COMPONENT% ""]} {
01660             error "undefined component \"%COMPONENT%\""
01661         }
01662 
01663 
01664         set cmd [linsert $args 0 $%COMPONENT%]
01665         return [uplevel 1 $cmd]
01666     } %COMPONENT% $component]
01667 }
01668 
01669 
01670 
01671 
01672 
01673 
01674 
01675 
01676 
01677 
01678 
01679 
01680 
01681 ret  ::snit::compile (type which , type type , type body) {
01682     return [Comp.Compile $which $type $body]
01683 }
01684 
01685 ret  ::snit::type (type type , type body) {
01686     return [Comp.Define [Comp.Compile type $type $body]]
01687 }
01688 
01689 ret  ::snit::widget (type type , type body) {
01690     return [Comp.Define [Comp.Compile widget $type $body]]
01691 }
01692 
01693 ret  ::snit::widgetadaptor (type type , type body) {
01694     return [Comp.Define [Comp.Compile widgetadaptor $type $body]]
01695 }
01696 
01697 ret  ::snit::typemethod (type type , type method , type arglist , type body) {
01698     # Make sure the type exists.
01699     if {![info exists ${type}::Snit_info]} {
01700         error "no such type: \"$type\""
01701     }
01702 
01703     upvar ${type}::Snit_info           Snit_info
01704     upvar ${type}::Snit_typemethodInfo Snit_typemethodInfo
01705 
01706     # FIRST, check the typemethod name against previously defined 
01707     # typemethods.
01708     Comp.CheckMethodName $method 0 ${type}::Snit_typemethodInfo \
01709         "Cannot define \"$method\""
01710 
01711     # NEXT, check the arguments
01712     CheckArgs "snit::typemethod $type $method" $arglist
01713 
01714     # Next, add magic reference to type.
01715     set arglist [concat type $arglist]
01716 
01717     # Next, add typevariable declarations to body:
01718     set body "$Snit_info(tvardecs)\n$body"
01719 
01720     # Next, define it.
01721     if {[llength $method] == 1} {
01722         set Snit_typemethodInfo($method) {0 "%t::Snit_typemethod%m %t" ""}
01723         uplevel 1 [list proc ${type}::Snit_typemethod$method $arglist $body]
01724     } else {
01725         set Snit_typemethodInfo($method) {0 "%t::Snit_htypemethod%j %t" ""}
01726         set suffix [join $method _]
01727         uplevel 1 [list proc ${type}::Snit_htypemethod$suffix $arglist $body]
01728     }
01729 }
01730 
01731 ret  ::snit::method (type type , type method , type arglist , type body) {
01732     # Make sure the type exists.
01733     if {![info exists ${type}::Snit_info]} {
01734         error "no such type: \"$type\""
01735     }
01736 
01737     upvar ${type}::Snit_methodInfo  Snit_methodInfo
01738     upvar ${type}::Snit_info        Snit_info
01739 
01740     # FIRST, check the method name against previously defined 
01741     # methods.
01742     Comp.CheckMethodName $method 0 ${type}::Snit_methodInfo \
01743         "Cannot define \"$method\""
01744 
01745     # NEXT, check the arguments
01746     CheckArgs "snit::method $type $method" $arglist
01747 
01748     # Next, add magic references to type and self.
01749     set arglist [concat type selfns win self $arglist]
01750 
01751     # Next, add variable declarations to body:
01752     set body "$Snit_info(tvardecs)\n$Snit_info(ivardecs)\n$body"
01753 
01754     # Next, define it.
01755     if {[llength $method] == 1} {
01756         set Snit_methodInfo($method) {0 "%t::Snit_method%m %t %n %w %s" ""}
01757         uplevel 1 [list proc ${type}::Snit_method$method $arglist $body]
01758     } else {
01759         set Snit_methodInfo($method) {0 "%t::Snit_hmethod%j %t %n %w %s" ""}
01760 
01761         set suffix [join $method _]
01762         uplevel 1 [list proc ${type}::Snit_hmethod$suffix $arglist $body]
01763     }
01764 }
01765 
01766 
01767 
01768 ret  ::snit::macro (type name , type arglist , type body) {
01769     variable compiler
01770     variable reservedwords
01771 
01772     # FIRST, make sure the compiler is defined.
01773     Comp.Init
01774 
01775     # NEXT, check the macro name against the reserved words
01776     if {[lsearch -exact $reservedwords $name] != -1} {
01777         error "invalid macro name \"$name\""
01778     }
01779 
01780     # NEXT, see if the name has a namespace; if it does, define the
01781     # namespace.
01782     set ns [namespace qualifiers $name]
01783 
01784     if {$ns ne ""} {
01785         $compiler eval "namespace eval $ns {}"
01786     }
01787 
01788     # NEXT, define the macro
01789     $compiler eval [list _proc $name $arglist $body]
01790 }
01791 
01792 
01793 
01794 
01795 
01796 
01797 
01798 
01799 ret  ::snit::Expand (type template , type args) {
01800     return [string map $args $template]
01801 }
01802 
01803 
01804 ret  ::snit::Mappend (type varname , type template , type args) {
01805     upvar $varname myvar
01806 
01807     append myvar [string map $args $template]
01808 }
01809 
01810 
01811 ret  ::snit::CheckArgs (type which , type arglist) {
01812     variable reservedArgs
01813     
01814     foreach name $reservedArgs {
01815         if {$name in $arglist} {
01816             error "$which's arglist may not contain \"$name\" explicitly"
01817         }
01818     }
01819 }
01820 
01821 
01822 ret  ::snit::Capitalize (type text) {
01823     return [string toupper $text 0]
01824 }
01825 
01826 
01827 
01828 
01829 
01830 
01831 
01832 
01833 
01834 
01835 
01836 
01837 
01838 
01839 
01840 
01841 ret  ::snit::RT.type.typemethod.create (type type , type name , type args) {
01842     variable ${type}::Snit_info
01843     variable ${type}::Snit_optionInfo
01844 
01845     # FIRST, qualify the name.
01846     if {![string match "::*" $name]} {
01847         # Get caller's namespace; 
01848         # append :: if not global namespace.
01849         set ns [uplevel 1 [list namespace current]]
01850         if {"::" != $ns} {
01851             append ns "::"
01852         }
01853         
01854         set name "$ns$name"
01855     }
01856 
01857     # NEXT, if %AUTO% appears in the name, generate a unique 
01858     # command name.  Otherwise, ensure that the name isn't in use.
01859     if {[string match "*%AUTO%*" $name]} {
01860         set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
01861     } elseif {!$Snit_info(canreplace) && [llength [info commands $name]]} {
01862         error "command \"$name\" already exists"
01863     }
01864 
01865     # NEXT, create the instance's namespace.
01866     set selfns \
01867         [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
01868     namespace eval $selfns {}
01869 
01870     # NEXT, install the dispatcher
01871     RT.MakeInstanceCommand $type $selfns $name
01872 
01873     # Initialize the options to their defaults. 
01874     namespace upvar ${selfns} options options
01875 
01876     foreach opt $Snit_optionInfo(local) {
01877         set options($opt) $Snit_optionInfo(default-$opt)
01878     }
01879         
01880     # Initialize the instance vars to their defaults.
01881     # selfns must be defined, as it is used implicitly.
01882     ${type}::Snit_instanceVars $selfns
01883 
01884     # Execute the type's constructor.
01885     set errcode [catch {
01886         RT.ConstructInstance $type $selfns $name $args
01887     } result]
01888 
01889     if {$errcode} {
01890         global errorInfo
01891         global errorCode
01892         
01893         set theInfo $errorInfo
01894         set theCode $errorCode
01895 
01896         ::snit::RT.DestroyObject $type $selfns $name
01897         error "Error in constructor: $result" $theInfo $theCode
01898     }
01899 
01900     # NEXT, return the object's name.
01901     return $name
01902 }
01903 
01904 
01905 
01906 
01907 
01908 
01909 
01910 
01911 ret  ::snit::RT.widget.typemethod.create (type type , type name , type args) {
01912     variable ${type}::Snit_info
01913     variable ${type}::Snit_optionInfo
01914 
01915     # FIRST, if %AUTO% appears in the name, generate a unique 
01916     # command name.
01917     if {[string match "*%AUTO%*" $name]} {
01918         set name [::snit::RT.UniqueName Snit_info(counter) $type $name]
01919     }
01920             
01921     # NEXT, create the instance's namespace.
01922     set selfns \
01923         [::snit::RT.UniqueInstanceNamespace Snit_info(counter) $type]
01924     namespace eval $selfns { }
01925             
01926     # NEXT, Initialize the widget's own options to their defaults.
01927     namespace upvar $selfns options options
01928 
01929     foreach opt $Snit_optionInfo(local) {
01930         set options($opt) $Snit_optionInfo(default-$opt)
01931     }
01932 
01933     # Initialize the instance vars to their defaults.
01934     ${type}::Snit_instanceVars $selfns
01935 
01936     # NEXT, if this is a normal widget (not a widget adaptor) then create a
01937     # frame as its hull.  We set the frame's -class to the user's widgetclass,
01938     # or, if none, search for -class in the args list, otherwise default to
01939     # the basename of the $type with an initial upper case letter.
01940     if {!$Snit_info(isWidgetAdaptor)} {
01941         # FIRST, determine the class name
01942     set wclass $Snit_info(widgetclass)
01943         if {$Snit_info(widgetclass) eq ""} {
01944         set idx [lsearch -exact $args -class]
01945         if {$idx >= 0 && ($idx%2 == 0)} {
01946         # -class exists and is in the -option position
01947         set wclass [lindex $args [expr {$idx+1}]]
01948         set args [lreplace $args $idx [expr {$idx+1}]]
01949         } else {
01950         set wclass [::snit::Capitalize [namespace tail $type]]
01951         }
01952     }
01953 
01954         # NEXT, create the widget
01955         set self $name
01956         package require Tk
01957         ${type}::installhull using $Snit_info(hulltype) -class $wclass
01958 
01959         # NEXT, let's query the option database for our
01960         # widget, now that we know that it exists.
01961         foreach opt $Snit_optionInfo(local) {
01962             set dbval [RT.OptionDbGet $type $name $opt]
01963 
01964             if {"" != $dbval} {
01965                 set options($opt) $dbval
01966             }
01967         }
01968     }
01969 
01970     # Execute the type's constructor, and verify that it
01971     # has a hull.
01972     set errcode [catch {
01973         RT.ConstructInstance $type $selfns $name $args
01974 
01975         ::snit::RT.Component $type $selfns hull
01976 
01977         # Prepare to call the object's destructor when the
01978         # <Destroy> event is received.  Use a Snit-specific bindtag
01979         # so that the widget name's tag is unencumbered.
01980 
01981         bind Snit$type$name <Destroy> [::snit::Expand {
01982             ::snit::RT.DestroyObject %TYPE% %NS% %W
01983         } %TYPE% $type %NS% $selfns]
01984 
01985         # Insert the bindtag into the list of bindtags right
01986         # after the widget name.
01987         set taglist [bindtags $name]
01988         set ndx [lsearch -exact $taglist $name]
01989         incr ndx
01990         bindtags $name [linsert $taglist $ndx Snit$type$name]
01991     } result]
01992 
01993     if {$errcode} {
01994         global errorInfo
01995         global errorCode
01996 
01997         set theInfo $errorInfo
01998         set theCode $errorCode
01999         ::snit::RT.DestroyObject $type $selfns $name
02000         error "Error in constructor: $result" $theInfo $theCode
02001     }
02002 
02003     # NEXT, return the object's name.
02004     return $name
02005 }
02006 
02007 
02008 
02009 
02010 
02011 
02012 
02013 
02014 
02015 
02016 ret  ::snit::RT.MakeInstanceCommand (type type , type selfns , type instance) {
02017     variable ${type}::Snit_info
02018         
02019     # FIRST, remember the instance name.  The Snit_instance variable
02020     # allows the instance to figure out its current name given the
02021     # instance namespace.
02022 
02023     namespace upvar $selfns Snit_instance Snit_instance
02024 
02025     set Snit_instance $instance
02026 
02027     # NEXT, qualify the proc name if it's a widget.
02028     if {$Snit_info(isWidget)} {
02029         set procname ::$instance
02030     } else {
02031         set procname $instance
02032     }
02033 
02034     # NEXT, install the new proc
02035     # WHD: Snit 2.0 code
02036 
02037     set unknownCmd [list ::snit::RT.UnknownMethod $type $selfns $instance ""]
02038     set createCmd [list namespace ensemble create \
02039                        -command $procname \
02040                        -unknown $unknownCmd \
02041                        -prefixes 0]
02042 
02043     namespace eval $selfns $createCmd
02044 
02045     # NEXT, add the trace.
02046     trace add command $procname {rename delete} \
02047         [list ::snit::RT.InstanceTrace $type $selfns $instance]
02048 }
02049 
02050 
02051 
02052 
02053 
02054 
02055 
02056 
02057 
02058 
02059 
02060 
02061 
02062 
02063 
02064 
02065 
02066 
02067 ret  ::snit::RT.InstanceTrace (type type , type selfns , type win , type old , type new , type op) {
02068     variable ${type}::Snit_info
02069 
02070     # Note to developers ...
02071     # For Tcl 8.4.0, errors thrown in trace handlers vanish silently.
02072     # Therefore we catch them here and create some output to help in
02073     # debugging such problems.
02074 
02075     if {[catch {
02076         # FIRST, clean up if necessary
02077         if {"" == $new} {
02078             if {$Snit_info(isWidget)} {
02079                 destroy $win
02080             } else {
02081                 ::snit::RT.DestroyObject $type $selfns $win
02082             }
02083         } else {
02084             # Otherwise, track the change.
02085             variable ${selfns}::Snit_instance
02086             set Snit_instance [uplevel 1 [list namespace which -command $new]]
02087             
02088             # Also, clear the instance caches, as many cached commands
02089             # might be invalid.
02090             RT.ClearInstanceCaches $selfns
02091         }
02092     } result]} {
02093         global errorInfo
02094         # Pop up the console on Windows wish, to enable stdout.
02095         # This clobbers errorInfo on unix, so save it so we can print it.
02096         set ei $errorInfo
02097         catch {console show}
02098         puts "Error in ::snit::RT.InstanceTrace $type $selfns $win $old $new $op:"
02099         puts $ei
02100     }
02101 }
02102 
02103 
02104 ret  ::snit::RT.ConstructInstance (type type , type selfns , type instance , type arglist) {
02105     variable ${type}::Snit_optionInfo
02106     variable ${selfns}::Snit_iinfo
02107 
02108     # Track whether we are constructed or not.
02109     set Snit_iinfo(constructed) 0
02110 
02111     # Call the user's constructor
02112     eval [linsert $arglist 0 \
02113               ${type}::Snit_constructor $type $selfns $instance $instance]
02114 
02115     set Snit_iinfo(constructed) 1
02116 
02117     # Validate the initial set of options (including defaults)
02118     foreach option $Snit_optionInfo(local) {
02119         set value [set ${selfns}::options($option)]
02120 
02121         if {$Snit_optionInfo(typespec-$option) ne ""} {
02122             if {[catch {
02123                 $Snit_optionInfo(typeobj-$option) validate $value
02124             } result]} {
02125                 return -code error "invalid $option default: $result"
02126             }
02127         }
02128     }
02129 
02130     # Unset the configure cache for all -readonly options.
02131     # This ensures that the next time anyone tries to 
02132     # configure it, an error is thrown.
02133     foreach opt $Snit_optionInfo(local) {
02134         if {$Snit_optionInfo(readonly-$opt)} {
02135             unset -nocomplain ${selfns}::Snit_configureCache($opt)
02136         }
02137     }
02138 
02139     return
02140 }
02141 
02142 
02143 
02144 
02145 
02146 
02147 ret  ::snit::RT.UniqueName (type countervar , type type , type name) {
02148     upvar $countervar counter 
02149     while 1 {
02150         # FIRST, bump the counter and define the %AUTO% instance name;
02151         # then substitute it into the specified name.  Wrap around at
02152         # 2^31 - 2 to prevent overflow problems.
02153         incr counter
02154         if {$counter > 2147483646} {
02155             set counter 0
02156         }
02157         set auto "[namespace tail $type]$counter"
02158         set candidate [Expand $name %AUTO% $auto]
02159         if {![llength [info commands $candidate]]} {
02160             return $candidate
02161         }
02162     }
02163 }
02164 
02165 
02166 
02167 
02168 
02169 
02170 
02171 
02172 
02173 ret  ::snit::RT.UniqueInstanceNamespace (type countervar , type type) {
02174     upvar $countervar counter 
02175     while 1 {
02176         # FIRST, bump the counter and define the namespace name.
02177         # Then see if it already exists.  Wrap around at
02178         # 2^31 - 2 to prevent overflow problems.
02179         incr counter
02180         if {$counter > 2147483646} {
02181             set counter 0
02182         }
02183         set ins "${type}::Snit_inst${counter}"
02184         if {![namespace exists $ins]} {
02185             return $ins
02186         }
02187     }
02188 }
02189 
02190 
02191 
02192 ret  ::snit::RT.OptionDbGet (type type , type self , type opt) {
02193     variable ${type}::Snit_optionInfo
02194 
02195     return [option get $self \
02196                 $Snit_optionInfo(resource-$opt) \
02197                 $Snit_optionInfo(class-$opt)]
02198 }
02199 
02200 
02201 
02202 
02203 
02204 
02205 
02206 
02207 
02208 
02209 
02210 ret  ::snit::RT.method.destroy (type type , type selfns , type win , type self) {
02211     variable ${selfns}::Snit_iinfo
02212 
02213     # Can't destroy the object if it isn't complete constructed.
02214     if {!$Snit_iinfo(constructed)} {
02215         return -code error "Called 'destroy' method in constructor"
02216     }
02217 
02218     # Calls Snit_cleanup, which (among other things) calls the
02219     # user's destructor.
02220     ::snit::RT.DestroyObject $type $selfns $win
02221 }
02222 
02223 
02224 
02225 
02226 
02227 
02228 
02229 
02230 
02231 ret  ::snit::RT.DestroyObject (type type , type selfns , type win) {
02232     variable ${type}::Snit_info
02233 
02234     # If the variable Snit_instance doesn't exist then there's no
02235     # instance command for this object -- it's most likely a 
02236     # widgetadaptor. Consequently, there are some things that
02237     # we don't need to do.
02238     if {[info exists ${selfns}::Snit_instance]} {
02239         namespace upvar $selfns Snit_instance instance
02240             
02241         # First, remove the trace on the instance name, so that we
02242         # don't call RT.DestroyObject recursively.
02243         RT.RemoveInstanceTrace $type $selfns $win $instance
02244             
02245         # Next, call the user's destructor
02246         ${type}::Snit_destructor $type $selfns $win $instance
02247 
02248         # Next, if this isn't a widget, delete the instance command.
02249         # If it is a widget, get the hull component's name, and rename
02250         # it back to the widget name
02251                 
02252         # Next, delete the hull component's instance command,
02253         # if there is one.
02254         if {$Snit_info(isWidget)} {
02255             set hullcmd [::snit::RT.Component $type $selfns hull]
02256             
02257             catch {rename $instance ""}
02258 
02259             # Clear the bind event
02260             bind Snit$type$win <Destroy> ""
02261 
02262             if {[llength [info commands $hullcmd]]} {
02263                 # FIRST, rename the hull back to its original name.
02264                 # If the hull is itself a megawidget, it will have its
02265                 # own cleanup to do, and it might not do it properly
02266                 # if it doesn't have the right name.
02267                 rename $hullcmd ::$instance
02268 
02269                 # NEXT, destroy it.
02270                 destroy $instance
02271             }
02272         } else {
02273             catch {rename $instance ""}
02274         }
02275     }
02276 
02277     # Next, delete the instance's namespace.  This kills any
02278     # instance variables.
02279     namespace delete $selfns
02280 
02281     return
02282 }
02283 
02284 
02285 
02286 
02287 
02288 
02289 
02290 
02291 ret  ::snit::RT.RemoveInstanceTrace (type type , type selfns , type win , type instance) {
02292     variable ${type}::Snit_info
02293 
02294     if {$Snit_info(isWidget)} {
02295         set procname ::$instance
02296     } else {
02297         set procname $instance
02298     }
02299         
02300     # NEXT, remove any trace on this name
02301     catch {
02302         trace remove command $procname {rename delete} \
02303             [list ::snit::RT.InstanceTrace $type $selfns $win]
02304     }
02305 }
02306 
02307 
02308 
02309 
02310 
02311 
02312 
02313 
02314 
02315 ret  ::snit::RT.TypecomponentTrace (type type , type component , type n1 , type n2 , type op) {
02316     namespace upvar $type \
02317         Snit_info           Snit_info \
02318         $component          cvar      \
02319         Snit_typecomponents Snit_typecomponents
02320 
02321         
02322     # Save the new component value.
02323     set Snit_typecomponents($component) $cvar
02324 
02325     # Clear the typemethod cache.
02326     # TBD: can we unset just the elements related to
02327     # this component?
02328 
02329     # WHD: Namespace 2.0 code
02330     namespace ensemble configure $type -map {}
02331 }
02332 
02333 
02334 
02335 
02336 
02337 
02338 
02339 
02340 
02341 
02342 
02343 
02344 
02345 
02346 
02347 
02348 
02349 
02350 
02351 ret  snit::RT.UnknownTypemethod (type type , type eId , type eCmd , type method , type args) {
02352     namespace upvar $type \
02353         Snit_typemethodInfo  Snit_typemethodInfo \
02354         Snit_typecomponents  Snit_typecomponents \
02355         Snit_info            Snit_info
02356     
02357     # FIRST, get the pattern data and the typecomponent name.
02358     set implicitCreate 0
02359     set instanceName ""
02360 
02361     set fullMethod $eId
02362     lappend fullMethod $method
02363     set starredMethod [concat $eId *]
02364     set methodTail $method
02365 
02366     if {[info exists Snit_typemethodInfo($fullMethod)]} {
02367         set key $fullMethod
02368     } elseif {[info exists Snit_typemethodInfo($starredMethod)]} {
02369         if {[lsearch -exact $Snit_info(excepttypemethods) $methodTail] == -1} {
02370             set key $starredMethod
02371         } else {
02372             # WHD: The method is explicitly not delegated, so this is an error.
02373             # Or should we treat it as an instance name?
02374             return [list ]
02375         }
02376     } elseif {$Snit_info(hasinstances)} {
02377         # Assume the unknown name is an instance name to create, unless
02378         # this is a widget and the style of the name is wrong, or the
02379         # name mimics a standard typemethod.
02380 
02381         if {[set ${type}::Snit_info(isWidget)] && 
02382             ![string match ".*" $method]} {
02383             return [list ]
02384         }
02385 
02386         # Without this check, the call "$type info" will redefine the
02387         # standard "::info" command, with disastrous results.  Since it's
02388         # a likely thing to do if !-typeinfo, put in an explicit check.
02389         if {$method eq "info" || $method eq "destroy"} {
02390             return [list ]
02391         }
02392 
02393         set implicitCreate 1
02394         set instanceName $method
02395         set key create
02396         set method create
02397     } else {
02398         return [list ]
02399     }
02400     
02401     foreach {flag pattern compName} $Snit_typemethodInfo($key) {}
02402 
02403     if {$flag == 1} {
02404         # FIRST, define the ensemble command.
02405         lappend eId $method
02406 
02407         set newCmd ${type}::Snit_ten[llength $eId]_[join $eId _]
02408 
02409         set unknownCmd [list ::snit::RT.UnknownTypemethod \
02410                             $type $eId]
02411 
02412         set createCmd [list namespace ensemble create \
02413                            -command $newCmd \
02414                            -unknown $unknownCmd \
02415                            -prefixes 0]
02416 
02417         namespace eval $type $createCmd
02418         
02419         # NEXT, add the method to the current ensemble
02420         set map [namespace ensemble configure $eCmd -map]
02421 
02422         dict append map $method $newCmd
02423 
02424         namespace ensemble configure $eCmd -map $map
02425 
02426         return [list ]
02427     }
02428 
02429     # NEXT, build the substitution list
02430     set subList [list \
02431                      %% % \
02432                      %t $type \
02433                      %M $fullMethod \
02434                      %m [lindex $fullMethod end] \
02435                      %j [join $fullMethod _]]
02436     
02437     if {$compName ne ""} {
02438         if {![info exists Snit_typecomponents($compName)]} {
02439             error "$type delegates typemethod \"$method\" to undefined typecomponent \"$compName\""
02440         }
02441         
02442         lappend subList %c [list $Snit_typecomponents($compName)]
02443     }
02444 
02445     set command {}
02446 
02447     foreach subpattern $pattern {
02448         lappend command [string map $subList $subpattern]
02449     }
02450 
02451     if {$implicitCreate} {
02452         # In this case, $method is the name of the instance to
02453         # create.  Don't cache, as we usually won't do this one
02454         # again.
02455         lappend command $instanceName
02456         return $command
02457     }
02458 
02459 
02460     # NEXT, if the actual command name isn't fully qualified,
02461     # assume it's global.
02462     set cmd [lindex $command 0]
02463 
02464     if {[string index $cmd 0] ne ":"} {
02465         set command [lreplace $command 0 0 "::$cmd"]
02466     }
02467 
02468     # NEXT, update the ensemble map.
02469     set map [namespace ensemble configure $eCmd -map]
02470 
02471     dict append map $method $command
02472 
02473     namespace ensemble configure $eCmd -map $map
02474 
02475     return [list ]
02476 }
02477 
02478 
02479 
02480 
02481 
02482 ret  ::snit::RT.Component (type type , type selfns , type name) {
02483     variable ${selfns}::Snit_components
02484 
02485     if {[catch {set Snit_components($name)} result]} {
02486         variable ${selfns}::Snit_instance
02487 
02488         error "component \"$name\" is undefined in $type $Snit_instance"
02489     }
02490     
02491     return $result
02492 }
02493 
02494 
02495 
02496 
02497 
02498 
02499 ret  ::snit::RT.ComponentTrace (type type , type selfns , type component , type n1 , type n2 , type op) {
02500     namespace upvar $type Snit_info Snit_info
02501     namespace upvar $selfns \
02502         $component      cvar            \
02503         Snit_components Snit_components
02504         
02505     # If they try to redefine the hull component after
02506     # it's been defined, that's an error--but only if
02507     # this is a widget or widget adaptor.
02508     if {"hull" == $component && 
02509         $Snit_info(isWidget) &&
02510         [info exists Snit_components($component)]} {
02511         set cvar $Snit_components($component)
02512         error "The hull component cannot be redefined"
02513     }
02514 
02515     # Save the new component value.
02516     set Snit_components($component) $cvar
02517 
02518     # Clear the instance caches.
02519     # TBD: can we unset just the elements related to
02520     # this component?
02521     RT.ClearInstanceCaches $selfns
02522 }
02523 
02524 
02525 
02526 
02527 
02528 
02529 
02530 
02531 
02532 
02533 
02534 
02535 
02536 
02537 
02538 
02539 
02540 
02541 
02542 
02543 
02544 ret  ::snit::RT.UnknownMethod (type type , type selfns , type win , type eId , type eCmd , type method , type args) {
02545     variable ${type}::Snit_info
02546     variable ${type}::Snit_methodInfo
02547     variable ${type}::Snit_typecomponents
02548     variable ${selfns}::Snit_components
02549 
02550     # FIRST, get the "self" value
02551     set self [set ${selfns}::Snit_instance]
02552 
02553     # FIRST, get the pattern data and the component name.
02554     set fullMethod $eId
02555     lappend fullMethod $method
02556     set starredMethod [concat $eId *]
02557     set methodTail $method
02558 
02559     if {[info exists Snit_methodInfo($fullMethod)]} {
02560         set key $fullMethod
02561     } elseif {[info exists Snit_methodInfo($starredMethod)] &&
02562               [lsearch -exact $Snit_info(exceptmethods) $methodTail] == -1} {
02563         set key $starredMethod
02564     } else {
02565         return [list ]
02566     }
02567 
02568     foreach {flag pattern compName} $Snit_methodInfo($key) {}
02569 
02570     if {$flag == 1} {
02571         # FIRST, define the ensemble command.
02572         lappend eId $method
02573 
02574         # Fix provided by Anton Kovalenko; previously this call erroneously
02575         # used ${type} rather than ${selfns}.
02576         set newCmd ${selfns}::Snit_en[llength $eId]_[join $eId _]
02577 
02578         set unknownCmd [list ::snit::RT.UnknownMethod \
02579                             $type $selfns $win $eId]
02580 
02581         set createCmd [list namespace ensemble create \
02582                            -command $newCmd \
02583                            -unknown $unknownCmd \
02584                            -prefixes 0]
02585 
02586         namespace eval $selfns $createCmd
02587         
02588         # NEXT, add the method to the current ensemble
02589         set map [namespace ensemble configure $eCmd -map]
02590 
02591         dict append map $method $newCmd
02592 
02593         namespace ensemble configure $eCmd -map $map
02594 
02595         return [list ]
02596     }
02597 
02598     # NEXT, build the substitution list
02599     set subList [list \
02600                      %% % \
02601                      %t $type \
02602                      %M $fullMethod \
02603                      %m [lindex $fullMethod end] \
02604                      %j [join $fullMethod _] \
02605                      %n [list $selfns] \
02606                      %w [list $win] \
02607                      %s [list $self]]
02608 
02609     if {$compName ne ""} {
02610         if {[info exists Snit_components($compName)]} {
02611             set compCmd $Snit_components($compName)
02612         } elseif {[info exists Snit_typecomponents($compName)]} {
02613             set compCmd $Snit_typecomponents($compName)
02614         } else {
02615             error "$type $self delegates method \"$fullMethod\" to undefined component \"$compName\""
02616         }
02617 
02618         lappend subList %c [list $compCmd]
02619     }
02620 
02621     # Note: The cached command will execute faster if it's
02622     # already a list.
02623     set command {}
02624 
02625     foreach subpattern $pattern {
02626         lappend command [string map $subList $subpattern]
02627     }
02628 
02629     # NEXT, if the actual command name isn't fully qualified,
02630     # assume it's global.
02631 
02632     set cmd [lindex $command 0]
02633 
02634     if {[string index $cmd 0] ne ":"} {
02635         set command [lreplace $command 0 0 "::$cmd"]
02636     }
02637 
02638     # NEXT, update the ensemble map.
02639     set map [namespace ensemble configure $eCmd -map]
02640 
02641     dict append map $method $command
02642 
02643     namespace ensemble configure $eCmd -map $map
02644 
02645     return [list ]
02646 }
02647 
02648 
02649 ret  ::snit::RT.ClearInstanceCaches (type selfns) {
02650     # WHD: clear ensemble -map
02651     if {![info exists ${selfns}::Snit_instance]} {
02652         # Component variable set prior to constructor
02653         # via the "variable" type definition statement.
02654         return
02655     }
02656     set self [set ${selfns}::Snit_instance]
02657     namespace ensemble configure $self -map {}
02658 
02659     unset -nocomplain -- ${selfns}::Snit_cgetCache
02660     unset -nocomplain -- ${selfns}::Snit_configureCache
02661     unset -nocomplain -- ${selfns}::Snit_validateCache
02662 }
02663 
02664 
02665 
02666 
02667 
02668 
02669 
02670 
02671 
02672 
02673 
02674 
02675 ret  ::snit::RT.installhull (type type , optional using ="using" , optional widgetType ="" , type args) {
02676     variable ${type}::Snit_info
02677     variable ${type}::Snit_optionInfo
02678     upvar 1 self self
02679     upvar 1 selfns selfns
02680     namespace upvar $selfns \
02681         hull    hull        \
02682         options options
02683 
02684     # FIRST, make sure we can do it.
02685     if {!$Snit_info(isWidget)} { 
02686         error "installhull is valid only for snit::widgetadaptors"
02687     }
02688             
02689     if {[info exists ${selfns}::Snit_instance]} {
02690         error "hull already installed for $type $self"
02691     }
02692 
02693     # NEXT, has it been created yet?  If not, create it using
02694     # the specified arguments.
02695     if {"using" == $using} {
02696         # FIRST, create the widget
02697         set cmd [linsert $args 0 $widgetType $self]
02698         set obj [uplevel 1 $cmd]
02699             
02700         # NEXT, for each option explicitly delegated to the hull
02701         # that doesn't appear in the usedOpts list, get the
02702         # option database value and apply it--provided that the
02703         # real option name and the target option name are different.
02704         # (If they are the same, then the option database was
02705         # already queried as part of the normal widget creation.)
02706         #
02707         # Also, we don't need to worry about implicitly delegated
02708         # options, as the option and target option names must be
02709         # the same.
02710         if {[info exists Snit_optionInfo(delegated-hull)]} {
02711                 
02712             # FIRST, extract all option names from args
02713             set usedOpts {}
02714             set ndx [lsearch -glob $args "-*"]
02715             foreach {opt val} [lrange $args $ndx end] {
02716                 lappend usedOpts $opt
02717             }
02718                 
02719             foreach opt $Snit_optionInfo(delegated-hull) {
02720                 set target [lindex $Snit_optionInfo(target-$opt) 1]
02721                 
02722                 if {"$target" == $opt} {
02723                     continue
02724                 }
02725                     
02726                 set result [lsearch -exact $usedOpts $target]
02727                     
02728                 if {$result != -1} {
02729                     continue
02730                 }
02731 
02732                 set dbval [RT.OptionDbGet $type $self $opt]
02733                 $obj configure $target $dbval
02734             }
02735         }
02736     } else {
02737         set obj $using
02738         
02739         if {$obj ne $self} {
02740             error \
02741                 "hull name mismatch: \"$obj\" != \"$self\""
02742         }
02743     }
02744 
02745     # NEXT, get the local option defaults.
02746     foreach opt $Snit_optionInfo(local) {
02747         set dbval [RT.OptionDbGet $type $self $opt]
02748             
02749         if {"" != $dbval} {
02750             set options($opt) $dbval
02751         }
02752     }
02753 
02754 
02755     # NEXT, do the magic
02756     set i 0
02757     while 1 {
02758         incr i
02759         set newName "::hull${i}$self"
02760         if {![llength [info commands $newName]]} {
02761             break
02762         }
02763     }
02764         
02765     rename ::$self $newName
02766     RT.MakeInstanceCommand $type $selfns $self
02767         
02768     # Note: this relies on RT.ComponentTrace to do the dirty work.
02769     set hull $newName
02770         
02771     return
02772 }
02773 
02774 
02775 
02776 
02777 
02778 
02779 ret  ::snit::RT.install (type type , type compName ", type using" , type widgetType , type winPath , type args) {
02780     variable ${type}::Snit_optionInfo
02781     variable ${type}::Snit_info
02782     upvar 1 self   self
02783     upvar 1 selfns selfns
02784 
02785     namespace upvar ${selfns} \
02786         $compName comp        \
02787         hull      hull
02788 
02789     # We do the magic option database stuff only if $self is
02790     # a widget.
02791     if {$Snit_info(isWidget)} {
02792         if {"" == $hull} {
02793             error "tried to install \"$compName\" before the hull exists"
02794         }
02795             
02796         # FIRST, query the option database and save the results 
02797         # into args.  Insert them before the first option in the
02798         # list, in case there are any non-standard parameters.
02799         #
02800         # Note: there might not be any delegated options; if so,
02801         # don't bother.
02802 
02803         if {[info exists Snit_optionInfo(delegated-$compName)]} {
02804             set ndx [lsearch -glob $args "-*"]
02805                 
02806             foreach opt $Snit_optionInfo(delegated-$compName) {
02807                 set dbval [RT.OptionDbGet $type $self $opt]
02808                     
02809                 if {"" != $dbval} {
02810                     set target [lindex $Snit_optionInfo(target-$opt) 1]
02811                     set args [linsert $args $ndx $target $dbval]
02812                 }
02813             }
02814         }
02815     }
02816              
02817     # NEXT, create the component and save it.
02818     set cmd [concat [list $widgetType $winPath] $args]
02819     set comp [uplevel 1 $cmd]
02820 
02821     # NEXT, handle the option database for "delegate option *",
02822     # in widgets only.
02823     if {$Snit_info(isWidget) && $Snit_optionInfo(starcomp) eq $compName} {
02824         # FIRST, get the list of option specs from the widget.
02825         # If configure doesn't work, skip it.
02826         if {[catch {$comp configure} specs]} {
02827             return
02828         }
02829 
02830         # NEXT, get the set of explicitly used options from args
02831         set usedOpts {}
02832         set ndx [lsearch -glob $args "-*"]
02833         foreach {opt val} [lrange $args $ndx end] {
02834             lappend usedOpts $opt
02835         }
02836 
02837         # NEXT, "delegate option *" matches all options defined
02838         # by this widget that aren't defined by the widget as a whole,
02839         # and that aren't excepted.  Plus, we skip usedOpts.  So build 
02840         # a list of the options it can't match.
02841         set skiplist [concat \
02842                           $usedOpts \
02843                           $Snit_optionInfo(except) \
02844                           $Snit_optionInfo(local) \
02845                           $Snit_optionInfo(delegated)]
02846         
02847         # NEXT, loop over all of the component's options, and set
02848         # any not in the skip list for which there is an option 
02849         # database value.
02850         foreach spec $specs {
02851             # Skip aliases
02852             if {[llength $spec] != 5} {
02853                 continue
02854             }
02855 
02856             set opt [lindex $spec 0]
02857 
02858             if {[lsearch -exact $skiplist $opt] != -1} {
02859                 continue
02860             }
02861 
02862             set res [lindex $spec 1]
02863             set cls [lindex $spec 2]
02864 
02865             set dbvalue [option get $self $res $cls]
02866 
02867             if {"" != $dbvalue} {
02868                 $comp configure $opt $dbvalue
02869             }
02870         }
02871     }
02872 
02873     return
02874 }
02875 
02876 
02877 
02878 
02879 
02880 
02881 ret  ::snit::RT.variable (type varname) {
02882     upvar 1 selfns selfns
02883 
02884     if {![string match "::*" $varname]} {
02885         uplevel 1 [list upvar 1 ${selfns}::$varname $varname]
02886     } else {
02887         # varname is fully qualified; let the standard
02888         # "variable" command handle it.
02889         uplevel 1 [list ::variable $varname]
02890     }
02891 }
02892 
02893 
02894 
02895 
02896 
02897 ret  ::snit::RT.mytypevar (type type , type name) {
02898     return ${type}::$name
02899 }
02900 
02901 
02902 
02903 
02904 ret  ::snit::RT.myvar (type name) {
02905     upvar 1 selfns selfns
02906     return ${selfns}::$name
02907 }
02908 
02909 
02910 
02911 
02912 
02913 
02914 
02915 ret  ::snit::RT.myproc (type type , type procname , type args) {
02916     set procname "${type}::$procname"
02917     return [linsert $args 0 $procname]
02918 }
02919 
02920 
02921 ret  ::snit::RT.codename (type type , type name) {
02922     return "${type}::$name"
02923 }
02924 
02925 
02926 
02927 
02928 
02929 
02930 
02931 ret  ::snit::RT.mytypemethod (type type , type args) {
02932     return [linsert $args 0 $type]
02933 }
02934 
02935 
02936 
02937 
02938 
02939 
02940 
02941 
02942 
02943 
02944 ret  ::snit::RT.mymethod (type args) {
02945     upvar 1 selfns selfns
02946     return [linsert $args 0 ::snit::RT.CallInstance ${selfns}]
02947 }
02948 
02949 
02950 
02951 
02952 
02953 
02954 
02955 
02956 
02957 
02958 
02959 
02960 
02961 ret  ::snit::RT.CallInstance (type selfns , type args) {
02962     namespace upvar $selfns Snit_instance self
02963 
02964     set retval [catch {uplevel 1 [linsert $args 0 $self]} result]
02965 
02966     if {$retval} {
02967         if {$retval == 1} {
02968             global errorInfo
02969             global errorCode
02970             return -code error -errorinfo $errorInfo \
02971                 -errorcode $errorCode $result
02972         } else {
02973             return -code $retval $result
02974         }
02975     }
02976 
02977     return $result
02978 }
02979 
02980 
02981 
02982 
02983 
02984 
02985 
02986 
02987 
02988 ret  ::snit::RT.from (type type , type argvName , type option , optional defvalue ="") {
02989     namespace upvar $type Snit_optionInfo Snit_optionInfo
02990     upvar $argvName argv
02991 
02992     set ioption [lsearch -exact $argv $option]
02993 
02994     if {$ioption == -1} {
02995         if {"" == $defvalue &&
02996             [info exists Snit_optionInfo(default-$option)]} {
02997             return $Snit_optionInfo(default-$option)
02998         } else {
02999             return $defvalue
03000         }
03001     }
03002 
03003     set ivalue [expr {$ioption + 1}]
03004     set value [lindex $argv $ivalue]
03005     
03006     set argv [lreplace $argv $ioption $ivalue] 
03007 
03008     return $value
03009 }
03010 
03011 
03012 
03013 
03014 
03015 
03016 
03017 
03018 
03019 ret  ::snit::RT.typemethod.destroy (type type) {
03020     variable ${type}::Snit_info
03021         
03022     # FIRST, destroy all instances
03023     foreach selfns [namespace children $type] {
03024         if {![namespace exists $selfns]} {
03025             continue
03026         }
03027 
03028         namespace upvar $selfns Snit_instance obj
03029             
03030         if {$Snit_info(isWidget)} {
03031             destroy $obj
03032         } else {
03033             if {[llength [info commands $obj]]} {
03034                 $obj destroy
03035             }
03036         }
03037     }
03038 
03039     # NEXT, get rid of the type command.
03040     rename $type ""
03041 
03042     # NEXT, destroy the type's data.
03043     namespace delete $type
03044 }
03045 
03046 
03047 
03048 
03049 
03050 
03051 
03052 
03053 
03054 
03055 
03056 
03057 
03058 
03059 ret  ::snit::RT.method.cget (type type , type selfns , type win , type self , type option) {
03060     if {[catch {set ${selfns}::Snit_cgetCache($option)} command]} {
03061         set command [snit::RT.CacheCgetCommand $type $selfns $win $self $option]
03062         
03063         if {[llength $command] == 0} {
03064             return -code error "unknown option \"$option\""
03065         }
03066     }
03067             
03068     uplevel 1 $command
03069 }
03070 
03071 
03072 
03073 
03074 
03075 
03076 
03077 
03078 
03079 
03080 ret  ::snit::RT.CacheCgetCommand (type type , type selfns , type win , type self , type option) {
03081     variable ${type}::Snit_optionInfo
03082     variable ${selfns}::Snit_cgetCache
03083                 
03084     if {[info exists Snit_optionInfo(islocal-$option)]} {
03085         # We know the item; it's either local, or explicitly delegated.
03086         if {$Snit_optionInfo(islocal-$option)} {
03087             # It's a local option.  If it has a cget method defined,
03088             # use it; otherwise just return the value.
03089 
03090             if {$Snit_optionInfo(cget-$option) eq ""} {
03091                 set command [list set ${selfns}::options($option)]
03092             } else {
03093                 # WHD: Snit 2.0 code -- simpler, no slower.
03094                 set command [list \
03095                                  $self \
03096                                  {*}$Snit_optionInfo(cget-$option) \
03097                                  $option]
03098             }
03099 
03100             set Snit_cgetCache($option) $command
03101             return $command
03102         }
03103          
03104         # Explicitly delegated option; get target
03105         set comp [lindex $Snit_optionInfo(target-$option) 0]
03106         set target [lindex $Snit_optionInfo(target-$option) 1]
03107     } elseif {$Snit_optionInfo(starcomp) ne "" &&
03108               [lsearch -exact $Snit_optionInfo(except) $option] == -1} {
03109         # Unknown option, but unknowns are delegated; get target.
03110         set comp $Snit_optionInfo(starcomp)
03111         set target $option
03112     } else {
03113         return ""
03114     }
03115     
03116     # Get the component's object.
03117     set obj [RT.Component $type $selfns $comp]
03118 
03119     set command [list $obj cget $target]
03120     set Snit_cgetCache($option) $command
03121 
03122     return $command
03123 }
03124 
03125 
03126 
03127 
03128 
03129 
03130 
03131 
03132 
03133 ret  ::snit::RT.method.configurelist (type type , type selfns , type win , type self , type optionlist) {
03134     variable ${type}::Snit_optionInfo
03135 
03136     foreach {option value} $optionlist {
03137         # FIRST, get the configure command, caching it if need be.
03138         if {[catch {set ${selfns}::Snit_configureCache($option)} command]} {
03139             set command [snit::RT.CacheConfigureCommand \
03140                              $type $selfns $win $self $option]
03141 
03142             if {[llength $command] == 0} {
03143                 return -code error "unknown option \"$option\""
03144             }
03145         }
03146 
03147         # NEXT, if we have a type-validation object, use it.
03148         # TBD: Should test (islocal-$option) here, but islocal
03149         # isn't defined for implicitly delegated options.
03150         if {[info exists Snit_optionInfo(typeobj-$option)]
03151             && $Snit_optionInfo(typeobj-$option) ne ""} {
03152             if {[catch {
03153                 $Snit_optionInfo(typeobj-$option) validate $value
03154             } result]} {
03155                 return -code error "invalid $option value: $result"
03156             }
03157         }
03158 
03159         # NEXT, the caching the configure command also cached the
03160         # validate command, if any.  If we have one, run it.
03161         set valcommand [set ${selfns}::Snit_validateCache($option)]
03162 
03163         if {[llength $valcommand]} {
03164             lappend valcommand $value
03165             uplevel 1 $valcommand
03166         }
03167 
03168         # NEXT, configure the option with the value.
03169         lappend command $value
03170         uplevel 1 $command
03171     }
03172     
03173     return
03174 }
03175 
03176 
03177 
03178 
03179 
03180 
03181 
03182 
03183 
03184 
03185 
03186 
03187 ret  ::snit::RT.CacheConfigureCommand (type type , type selfns , type win , type self , type option) {
03188     variable ${type}::Snit_optionInfo
03189     variable ${selfns}::Snit_configureCache
03190     variable ${selfns}::Snit_validateCache
03191 
03192     if {[info exist Snit_optionInfo(islocal-$option)]} {
03193         # We know the item; it's either local, or explicitly delegated.
03194         
03195         if {$Snit_optionInfo(islocal-$option)} {
03196             # It's a local option.
03197 
03198             # If it's readonly, it throws an error if we're already 
03199             # constructed.
03200             if {$Snit_optionInfo(readonly-$option)} {
03201                 if {[set ${selfns}::Snit_iinfo(constructed)]} {
03202                     error "option $option can only be set at instance creation"
03203                 }
03204             }
03205 
03206             # If it has a validate method, cache that for later.
03207             if {$Snit_optionInfo(validate-$option) ne ""} {
03208                 # WHD: Snit 2.0 code -- simpler, no slower.
03209                 set command [list \
03210                                  $self \
03211                                  {*}$Snit_optionInfo(validate-$option) \
03212                                  $option]
03213 
03214                 set Snit_validateCache($option) $command
03215             } else {
03216                 set Snit_validateCache($option) ""
03217             }
03218             
03219             # If it has a configure method defined,
03220             # cache it; otherwise, just set the value.
03221             if {$Snit_optionInfo(configure-$option) eq ""} {
03222                 set command [list set ${selfns}::options($option)]
03223             } else {
03224                 # WHD: Snit 2.0 code -- simpler, no slower.
03225                 set command [list \
03226                                  $self \
03227                                  {*}$Snit_optionInfo(configure-$option) \
03228                                  $option]
03229             }
03230 
03231             set Snit_configureCache($option) $command
03232             return $command
03233         }
03234 
03235         # Delegated option: get target.
03236         set comp [lindex $Snit_optionInfo(target-$option) 0]
03237         set target [lindex $Snit_optionInfo(target-$option) 1]
03238     } elseif {$Snit_optionInfo(starcomp) != "" &&
03239               [lsearch -exact $Snit_optionInfo(except) $option] == -1} {
03240         # Unknown option, but unknowns are delegated.
03241         set comp $Snit_optionInfo(starcomp)
03242         set target $option
03243     } else {
03244         return ""
03245     }
03246 
03247     # There is no validate command in this case; save an empty string.
03248     set Snit_validateCache($option) ""
03249         
03250     # Get the component's object
03251     set obj [RT.Component $type $selfns $comp]
03252     
03253     set command [list $obj configure $target]
03254     set Snit_configureCache($option) $command
03255 
03256     return $command
03257 }
03258 
03259 
03260 
03261 
03262 
03263 
03264 
03265 
03266 
03267 ret  ::snit::RT.method.configure (type type , type selfns , type win , type self , type args) {
03268     # If two or more arguments, set values as usual.
03269     if {[llength $args] >= 2} {
03270         ::snit::RT.method.configurelist $type $selfns $win $self $args
03271         return
03272     }
03273 
03274     # If zero arguments, acquire data for each known option
03275     # and return the list
03276     if {[llength $args] == 0} {
03277         set result {}
03278         foreach opt [RT.method.info.options $type $selfns $win $self] {
03279             # Refactor this, so that we don't need to call via $self.
03280             lappend result [RT.GetOptionDbSpec \
03281                                 $type $selfns $win $self $opt]
03282         }
03283         
03284         return $result
03285     }
03286 
03287     # They want it for just one.
03288     set opt [lindex $args 0]
03289 
03290     return [RT.GetOptionDbSpec $type $selfns $win $self $opt]
03291 }
03292 
03293 
03294 
03295 
03296 
03297 
03298 
03299 
03300 
03301 
03302 
03303 
03304 
03305 ret  ::snit::RT.GetOptionDbSpec (type type , type selfns , type win , type self , type opt) {
03306     variable ${type}::Snit_optionInfo
03307 
03308     namespace upvar $selfns \
03309         Snit_components Snit_components \
03310         options         options
03311     
03312     if {[info exists options($opt)]} {
03313         # This is a locally-defined option.  Just build the
03314         # list and return it.
03315         set res $Snit_optionInfo(resource-$opt)
03316         set cls $Snit_optionInfo(class-$opt)
03317         set def $Snit_optionInfo(default-$opt)
03318 
03319         return [list $opt $res $cls $def \
03320                     [RT.method.cget $type $selfns $win $self $opt]]
03321     } elseif {[info exists Snit_optionInfo(target-$opt)]} {
03322         # This is an explicitly delegated option.  The only
03323         # thing we don't have is the default.
03324         set res $Snit_optionInfo(resource-$opt)
03325         set cls $Snit_optionInfo(class-$opt)
03326         
03327         # Get the default
03328         set logicalName [lindex $Snit_optionInfo(target-$opt) 0]
03329         set comp $Snit_components($logicalName)
03330         set target [lindex $Snit_optionInfo(target-$opt) 1]
03331 
03332         if {[catch {$comp configure $target} result]} {
03333             set defValue {}
03334         } else {
03335             set defValue [lindex $result 3]
03336         }
03337 
03338         return [list $opt $res $cls $defValue [$self cget $opt]]
03339     } elseif {$Snit_optionInfo(starcomp) ne "" &&
03340               [lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
03341         set logicalName $Snit_optionInfo(starcomp)
03342         set target $opt
03343         set comp $Snit_components($logicalName)
03344 
03345         if {[catch {set value [$comp cget $target]} result]} {
03346             error "unknown option \"$opt\""
03347         }
03348 
03349         if {![catch {$comp configure $target} result]} {
03350             # Replace the delegated option name with the local name.
03351             return [::snit::Expand $result $target $opt]
03352         }
03353 
03354         # configure didn't work; return simple form.
03355         return [list $opt "" "" "" $value]
03356     } else {
03357         error "unknown option \"$opt\""
03358     }
03359 }
03360 
03361 
03362 
03363 
03364 
03365 
03366 
03367 
03368 
03369 
03370 ret  ::snit::RT.typemethod.info (type type , type command , type args) {
03371     global errorInfo
03372     global errorCode
03373 
03374     switch -exact $command {
03375     args        -
03376     body        -
03377     default     -
03378         typevars    -
03379         typemethods -
03380         instances {
03381             # TBD: it should be possible to delete this error
03382             # handling.
03383             set errflag [catch {
03384                 uplevel 1 [linsert $args 0 \
03385                    ::snit::RT.typemethod.info.$command $type]
03386             } result]
03387 
03388             if {$errflag} {
03389                 return -code error -errorinfo $errorInfo \
03390                     -errorcode $errorCode $result
03391             } else {
03392                 return $result
03393             }
03394         }
03395         default {
03396             error "\"$type info $command\" is not defined"
03397         }
03398     }
03399 }
03400 
03401 
03402 
03403 
03404 
03405 
03406 
03407 
03408 
03409 ret  ::snit::RT.typemethod.info.typevars (type type , optional pattern =*) {
03410     set result {}
03411     foreach name [info vars "${type}::$pattern"] {
03412         set tail [namespace tail $name]
03413         if {![string match "Snit_*" $tail]} {
03414             lappend result $name
03415         }
03416     }
03417     
03418     return $result
03419 }
03420 
03421 
03422 
03423 
03424 
03425 
03426 
03427 
03428 
03429 ret  ::snit::RT.typemethod.info.typemethods (type type , optional pattern =*) {
03430     variable ${type}::Snit_typemethodInfo
03431 
03432     # FIRST, get the explicit names, skipping prefixes.
03433     set result {}
03434 
03435     foreach name [array names Snit_typemethodInfo -glob $pattern] {
03436         if {[lindex $Snit_typemethodInfo($name) 0] != 1} {
03437             lappend result $name
03438         }
03439     }
03440 
03441     # NEXT, add any from the cache that aren't explicit.
03442     # WHD: fixed up to use newstyle method cache/list of subcommands.
03443     if {[info exists Snit_typemethodInfo(*)]} {
03444         # First, remove "*" from the list.
03445         set ndx [lsearch -exact $result "*"]
03446         if {$ndx != -1} {
03447             set result [lreplace $result $ndx $ndx]
03448         }
03449 
03450         # Next, get the type's -map
03451         array set typemethodCache [namespace ensemble configure $type -map]
03452 
03453         # Next, get matching names from the cache that we don't already
03454         # know about.
03455         foreach name [array names typemethodCache -glob $pattern] {
03456             if {[lsearch -exact $result $name] == -1} {
03457                 lappend result $name
03458             }
03459         }
03460     }
03461 
03462     return $result
03463 }
03464 
03465 
03466 
03467 
03468 
03469 
03470 
03471 ret  ::snit::RT.typemethod.info.args (type type , type method) {
03472     upvar ${type}::Snit_typemethodInfo  Snit_typemethodInfo
03473 
03474     # Snit_methodInfo: method -> list (flag cmd component)
03475 
03476     # flag      : 1 -> internal dispatcher for multi-word method.
03477     #             0 -> regular method
03478     #
03479     # cmd       : template mapping from method to command prefix, may
03480     #             contain placeholders for various pieces of information.
03481     #
03482     # component : is empty for normal methods.
03483 
03484     #parray Snit_typemethodInfo
03485 
03486     if {![info exists Snit_typemethodInfo($method)]} {
03487     return -code error "Unknown typemethod \"$method\""
03488     }
03489     foreach {flag cmd component} $Snit_typemethodInfo($method) break
03490     if {$flag} {
03491     return -code error "Unknown typemethod \"$method\""
03492     }
03493     if {$component != ""} {
03494     return -code error "Delegated typemethod \"$method\""
03495     }
03496 
03497     set map     [list %m $method %j [join $method _] %t $type]
03498     set theproc [lindex [string map $map $cmd] 0]
03499     return [lrange [::info args $theproc] 1 end]
03500 }
03501 
03502 
03503 
03504 
03505 
03506 
03507 
03508 ret  ::snit::RT.typemethod.info.body (type type , type method) {
03509     upvar ${type}::Snit_typemethodInfo  Snit_typemethodInfo
03510 
03511     # Snit_methodInfo: method -> list (flag cmd component)
03512 
03513     # flag      : 1 -> internal dispatcher for multi-word method.
03514     #             0 -> regular method
03515     #
03516     # cmd       : template mapping from method to command prefix, may
03517     #             contain placeholders for various pieces of information.
03518     #
03519     # component : is empty for normal methods.
03520 
03521     #parray Snit_typemethodInfo
03522 
03523     if {![info exists Snit_typemethodInfo($method)]} {
03524     return -code error "Unknown typemethod \"$method\""
03525     }
03526     foreach {flag cmd component} $Snit_typemethodInfo($method) break
03527     if {$flag} {
03528     return -code error "Unknown typemethod \"$method\""
03529     }
03530     if {$component != ""} {
03531     return -code error "Delegated typemethod \"$method\""
03532     }
03533 
03534     set map     [list %m $method %j [join $method _] %t $type]
03535     set theproc [lindex [string map $map $cmd] 0]
03536     return [RT.body [::info body $theproc]]
03537 }
03538 
03539 
03540 
03541 
03542 
03543 
03544 
03545 ret  ::snit::RT.typemethod.info.default (type type , type method , type aname , type dvar) {
03546     upvar 1 $dvar def
03547     upvar ${type}::Snit_typemethodInfo  Snit_typemethodInfo
03548 
03549     # Snit_methodInfo: method -> list (flag cmd component)
03550 
03551     # flag      : 1 -> internal dispatcher for multi-word method.
03552     #             0 -> regular method
03553     #
03554     # cmd       : template mapping from method to command prefix, may
03555     #             contain placeholders for various pieces of information.
03556     #
03557     # component : is empty for normal methods.
03558 
03559     #parray Snit_methodInfo
03560 
03561     if {![info exists Snit_typemethodInfo($method)]} {
03562     return -code error "Unknown typemethod \"$method\""
03563     }
03564     foreach {flag cmd component} $Snit_typemethodInfo($method) break
03565     if {$flag} {
03566     return -code error "Unknown typemethod \"$method\""
03567     }
03568     if {$component != ""} {
03569     return -code error "Delegated typemethod \"$method\""
03570     }
03571 
03572     set map     [list %m $method %j [join $method _] %t $type]
03573     set theproc [lindex [string map $map $cmd] 0]
03574     return [::info default $theproc $aname def]
03575 }
03576 
03577 
03578 
03579 
03580 
03581 
03582 
03583 
03584 
03585 
03586 ret  ::snit::RT.typemethod.info.instances (type type , optional pattern =*) {
03587     set result {}
03588 
03589     foreach selfns [namespace children $type] {
03590         namespace upvar $selfns Snit_instance instance
03591 
03592         if {[string match $pattern $instance]} {
03593             lappend result $instance
03594         }
03595     }
03596 
03597     return $result
03598 }
03599 
03600 
03601 
03602 
03603 
03604 
03605 
03606 
03607 
03608 
03609 
03610 
03611 
03612 ret  ::snit::RT.method.info (type type , type selfns , type win , type self , type command , type args) {
03613     switch -exact $command {
03614     args        -
03615     body        -
03616     default     -
03617         type        -
03618         vars        -
03619         options     -
03620         methods     -
03621         typevars    -
03622         typemethods {
03623             set errflag [catch {
03624                 uplevel 1 [linsert $args 0 ::snit::RT.method.info.$command \
03625                    $type $selfns $win $self]
03626             } result]
03627 
03628             if {$errflag} {
03629                 global errorInfo
03630                 return -code error -errorinfo $errorInfo $result
03631             } else {
03632                 return $result
03633             }
03634         }
03635         default {
03636             # error "\"$self info $command\" is not defined"
03637             return -code error "\"$self info $command\" is not defined"
03638         }
03639     }
03640 }
03641 
03642 
03643 
03644 
03645 ret  ::snit::RT.method.info.type (type type , type selfns , type win , type self) {
03646     return $type
03647 }
03648 
03649 
03650 
03651 
03652 ret  ::snit::RT.method.info.typevars (type type , type selfns , type win , type self , optional pattern =*) {
03653     return [RT.typemethod.info.typevars $type $pattern]
03654 }
03655 
03656 
03657 
03658 
03659 ret  ::snit::RT.method.info.typemethods (type type , type selfns , type win , type self , optional pattern =*) {
03660     return [RT.typemethod.info.typemethods $type $pattern]
03661 }
03662 
03663 
03664 
03665 
03666 
03667 
03668 
03669 
03670 
03671 
03672 
03673 
03674 ret  ::snit::RT.method.info.methods (type type , type selfns , type win , type self , optional pattern =*) {
03675     variable ${type}::Snit_methodInfo
03676 
03677     # FIRST, get the explicit names, skipping prefixes.
03678     set result {}
03679 
03680     foreach name [array names Snit_methodInfo -glob $pattern] {
03681         if {[lindex $Snit_methodInfo($name) 0] != 1} {
03682             lappend result $name
03683         }
03684     }
03685 
03686     # NEXT, add any from the cache that aren't explicit.
03687     # WHD: Fixed up to use newstyle method cache/list of subcommands.
03688     if {[info exists Snit_methodInfo(*)]} {
03689         # First, remove "*" from the list.
03690         set ndx [lsearch -exact $result "*"]
03691         if {$ndx != -1} {
03692             set result [lreplace $result $ndx $ndx]
03693         }
03694 
03695         # Next, get the instance's -map
03696         set self [set ${selfns}::Snit_instance]
03697 
03698         array set methodCache [namespace ensemble configure $self -map]
03699 
03700         # Next, get matching names from the cache that we don't already
03701         # know about.
03702         foreach name [array names methodCache -glob $pattern] {
03703             if {[lsearch -exact $result $name] == -1} {
03704                 lappend result $name
03705             }
03706         }
03707     }
03708 
03709     return $result
03710 }
03711 
03712 
03713 
03714 
03715 
03716 
03717 
03718 ret  ::snit::RT.method.info.args (type type , type selfns , type win , type self , type method) {
03719 
03720     upvar ${type}::Snit_methodInfo  Snit_methodInfo
03721 
03722     # Snit_methodInfo: method -> list (flag cmd component)
03723 
03724     # flag      : 1 -> internal dispatcher for multi-word method.
03725     #             0 -> regular method
03726     #
03727     # cmd       : template mapping from method to command prefix, may
03728     #             contain placeholders for various pieces of information.
03729     #
03730     # component : is empty for normal methods.
03731 
03732     #parray Snit_methodInfo
03733 
03734     if {![info exists Snit_methodInfo($method)]} {
03735     return -code error "Unknown method \"$method\""
03736     }
03737     foreach {flag cmd component} $Snit_methodInfo($method) break
03738     if {$flag} {
03739     return -code error "Unknown method \"$method\""
03740     }
03741     if {$component != ""} {
03742     return -code error "Delegated method \"$method\""
03743     }
03744 
03745     set map     [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
03746     set theproc [lindex [string map $map $cmd] 0]
03747     return [lrange [::info args $theproc] 4 end]
03748 }
03749 
03750 
03751 
03752 
03753 
03754 
03755 
03756 ret  ::snit::RT.method.info.body (type type , type selfns , type win , type self , type method) {
03757 
03758     upvar ${type}::Snit_methodInfo  Snit_methodInfo
03759 
03760     # Snit_methodInfo: method -> list (flag cmd component)
03761 
03762     # flag      : 1 -> internal dispatcher for multi-word method.
03763     #             0 -> regular method
03764     #
03765     # cmd       : template mapping from method to command prefix, may
03766     #             contain placeholders for various pieces of information.
03767     #
03768     # component : is empty for normal methods.
03769 
03770     #parray Snit_methodInfo
03771 
03772     if {![info exists Snit_methodInfo($method)]} {
03773     return -code error "Unknown method \"$method\""
03774     }
03775     foreach {flag cmd component} $Snit_methodInfo($method) break
03776     if {$flag} {
03777     return -code error "Unknown method \"$method\""
03778     }
03779     if {$component != ""} {
03780     return -code error "Delegated method \"$method\""
03781     }
03782 
03783     set map     [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
03784     set theproc [lindex [string map $map $cmd] 0]
03785     return [RT.body [::info body $theproc]]
03786 }
03787 
03788 
03789 
03790 
03791 
03792 
03793 
03794 ret  ::snit::RT.method.info.default (type type , type selfns , type win , type self , type method , type aname , type dvar) {
03795     upvar 1 $dvar def
03796     upvar ${type}::Snit_methodInfo  Snit_methodInfo
03797 
03798     # Snit_methodInfo: method -> list (flag cmd component)
03799 
03800     # flag      : 1 -> internal dispatcher for multi-word method.
03801     #             0 -> regular method
03802     #
03803     # cmd       : template mapping from method to command prefix, may
03804     #             contain placeholders for various pieces of information.
03805     #
03806     # component : is empty for normal methods.
03807 
03808     if {![info exists Snit_methodInfo($method)]} {
03809     return -code error "Unknown method \"$method\""
03810     }
03811     foreach {flag cmd component} $Snit_methodInfo($method) break
03812     if {$flag} {
03813     return -code error "Unknown method \"$method\""
03814     }
03815     if {$component != ""} {
03816     return -code error "Delegated method \"$method\""
03817     }
03818 
03819     set map     [list %m $method %j [join $method _] %t $type %n $selfns %w $win %s $self]
03820     set theproc [lindex [string map $map $cmd] 0]
03821     return [::info default $theproc $aname def]
03822 }
03823 
03824 
03825 
03826 
03827 ret  ::snit::RT.method.info.vars (type type , type selfns , type win , type self , optional pattern =*) {
03828     set result {}
03829     foreach name [info vars "${selfns}::$pattern"] {
03830         set tail [namespace tail $name]
03831         if {![string match "Snit_*" $tail]} {
03832             lappend result $name
03833         }
03834     }
03835 
03836     return $result
03837 }
03838 
03839 
03840 
03841 
03842 ret  ::snit::RT.method.info.options (type type , type selfns , type win , type self , optional pattern =*) {
03843     variable ${type}::Snit_optionInfo
03844 
03845     # First, get the local and explicitly delegated options
03846     set result [concat $Snit_optionInfo(local) $Snit_optionInfo(delegated)]
03847 
03848     # If "configure" works as for Tk widgets, add the resulting
03849     # options to the list.  Skip excepted options
03850     if {$Snit_optionInfo(starcomp) ne ""} {
03851         namespace upvar $selfns Snit_components Snit_components
03852 
03853         set logicalName $Snit_optionInfo(starcomp)
03854         set comp $Snit_components($logicalName)
03855 
03856         if {![catch {$comp configure} records]} {
03857             foreach record $records {
03858                 set opt [lindex $record 0]
03859                 if {[lsearch -exact $result $opt] == -1 &&
03860                     [lsearch -exact $Snit_optionInfo(except) $opt] == -1} {
03861                     lappend result $opt
03862                 }
03863             }
03864         }
03865     }
03866 
03867     # Next, apply the pattern
03868     set names {}
03869 
03870     foreach name $result {
03871         if {[string match $pattern $name]} {
03872             lappend names $name
03873         }
03874     }
03875 
03876     return $names
03877 }
03878 
03879 ret  ::snit::RT.body (type body) {
03880     regsub -all ".*# END snit method prolog\n" $body {} body
03881     return $body
03882 }
03883