home *** CD-ROM | disk | FTP | other *** search
Wrap
#--------------------------------------------------------------------------- # # Copyright (c) 1997 by Cayenne Software, Inc. # # This software is furnished under a license and may be used only in # accordance with the terms of such license and with the inclusion of # the above copyright notice. This software or any other copies thereof # may not be provided or otherwise made available to any other person. # No title to and ownership of the software is hereby transferred. # # The information in this software is subject to change without notice # and should not be construed as a commitment by Cayenne Software, Inc. # #--------------------------------------------------------------------------- # # File : delphigtor.tcl # Author : # Original date : November 1997 # Description : Classes for code generation # #--------------------------------------------------------------------------- #--------------------------------------------------------------------------- # File: @(#)dpfilehand.tcl /main/titanic/3 #--------------------------------------------------------------------------- # Start user added include file section # End user added include file section require "filehandle.tcl" Class DPFileHandler : {FileHandler} { constructor method destructor method getFileName method getSpecialFiles method getFileTypes method getProjectFileName } global DPFileHandler::DPRType set DPFileHandler::DPRType "dpr" global DPFileHandler::PASType set DPFileHandler::PASType "pas" global DPFileHandler::DFMType set DPFileHandler::DFMType "txt" constructor DPFileHandler {class this} { set this [FileHandler::constructor $class $this] # Start constructor user section # End constructor user section return $this } method DPFileHandler::destructor {this} { # Start destructor user section # End destructor user section $this FileHandler::destructor } method DPFileHandler::getFileName {this class fileType} { return "[$class getUnitName].$fileType" } method DPFileHandler::getSpecialFiles {this} { set list [List new] $list append [$this getProjectFileName] return $list } method DPFileHandler::getFileTypes {this} { set list [List new] $list append ${DPFileHandler::DPRType} $list append ${DPFileHandler::PASType} $list append ${DPFileHandler::DFMType} return $list } method DPFileHandler::getProjectFileName {this} { return "[getCurrentSystemName].${DPFileHandler::DPRType}" } # Do not delete this line -- regeneration end marker #--------------------------------------------------------------------------- # File: @(#)dpgenerato.tcl /main/titanic/14 #--------------------------------------------------------------------------- # Start user added include file section # End user added include file section require "generator.tcl" Class DPGenerator : {Generator} { constructor method destructor method check method checkProject method checkSpecialFiles method generateProjectSections method generateProjectFile method generate method generateSpecialFiles attribute fileHandler attribute ooplModel } constructor DPGenerator {class this} { set this [Generator::constructor $class $this] # Start constructor user section $this fileHandler [DPFileHandler new] # End constructor user section return $this } method DPGenerator::destructor {this} { # Start destructor user section # End destructor user section $this Generator::destructor } method DPGenerator::check {this classList} { $classList foreach cl { $cl check } } method DPGenerator::checkProject {this} { set errornr 0 set nrStartupForms 0 set nrTForms 0 set formsList {} foreach class [[$this ooplModel] ooplClassSet] { if {[$class isExternal] || [$class isComponentDummy]} { continue } if {[$class getPropertyValue "is_mainform"] == 1} { if {[$class isForm] && ![$class isDataModule]} { if {$nrStartupForms != 0} { m4_error $E_DOUBLESTARTUP [$class getFormVarName] [$startupForm getFormVarName] incr errornr 1 } else { incr nrStartupForms set startupForm $class } } else { m4_warning $W_CANTBESTARTUP [$class getName] } } if {[$class isForm]} { set formsList [linsert $formsList 0 $class] if {![$class isDataModule]} { incr nrTForms } } } if {$nrTForms != 0 && $nrStartupForms == 0} { set FormNr 0 while {[[lindex $formsList $FormNr] isDataModule]} { incr FormNr } set startupForm [lindex $formsList $FormNr] m4_warning $W_NOSTARTUP [$startupForm getFormVarName] } return $errornr } method DPGenerator::checkSpecialFiles {this fileList} { set errornr 0 $fileList foreach specialFile { incr errornr [$this checkProject] } return $erronr } method DPGenerator::generateProjectSections {this uses code} { if {[$this checkProject] > 0} { return } set startupForm "" set nrStartupForms 0 set nrTForms 0 set systemUsesList {} set standardUsesList {} set formsList {} set newUsesList {} foreach class [[$this ooplModel] ooplClassSet] { if {[$class isExternal] || [$class isComponentDummy]} { continue } if {[$class getPropertyValue "is_mainform"] == 1} { if {[$class isForm] && ![$class isDataModule]} { set startupForm $class incr nrStartupForms } } if {[$class isForm]} { set formsList [linsert $formsList 0 $class] if {![$class isDataModule]} { incr nrTForms } } set libunit [$class getPropertyValue "libunit"] if {$libunit != "None" && $libunit != ""} { if {$libunit == "Other"} { set name [$class getPropertyValue "userlib"] } else { set name $libunit } if {[lsearch -exact $systemUsesList $name] == -1} { set systemUsesList [linsert $systemUsesList 0 $name] } } else { if {[lsearch -exact $standardUsesList $class] == -1} { set standardUsesList [linsert $standardUsesList 0 $class] } } } set first 1 foreach name $systemUsesList { if {$first} { set first 0 } else { $uses append ",\n" } $uses append "${name}" set newUsesList [linsert $newUsesList 0 $name] } foreach class $standardUsesList { if {$first} { set first 0 } else { $uses append ",\n" } $uses append "[$class getUnitName] in '[$class getUnitName].pas'" set newUsesList [linsert $newUsesList 0 [$class getUnitName]] # Append Delphi markers in project file # if {[$class isDataModule]} { $uses append " \{[$class getFormVarName]: TDataModule\}" } else { if {[$class isForm]} { $uses append " \{[$class getFormVarName]\}" } } } if {[$uses contents] != ""} { $uses append "\n" } if {$nrTForms != 0 && $nrStartupForms == 0} { set FormNr 0 while {[[lindex $formsList $FormNr] isDataModule]} { incr FormNr } set startupForm [lindex $formsList $FormNr] } $code indent + if {$startupForm != ""} { $code append "Application.CreateForm([$startupForm getFormTypeName], [$startupForm getFormVarName]);\n" } # foreach form $formsList { # if {[$form getFormVarName] != [$startupForm getFormVarName]} { # $code append "Application.CreateForm([$form getFormTypeName], [$form getFormVarName]); ${DPCookie::genProjectCode}\n" # } # } $code indent - return $newUsesList } method DPGenerator::generateProjectFile {this fileName uses code newUsesList} { set oldProject [DPTextSection new] set newProject [DPTextSection new] set cc [ClientContext::global] set projectName [getCurrentSystemName] set dprType ${DPFileHandler::DPRType} set genUsesList {} # # Read either the customization file or the existing project file # if {[catch {set fileDesc [fstorage::open [[$this fileHandler] getProjectFileName] r]}]} { # Search for customization file $oldProject append [$cc getCustomFileContents "default" "dpr" etc] } else { # Read existing file set done 0 while {![eof $fileDesc] && !$done} { set line [gets $fileDesc] if {![regexp {(//).*} $line]} { set done 1 $oldProject append "$line\n" } } while {![eof $fileDesc]} { set line [gets $fileDesc] $oldProject append "$line\n" } fstorage::close $fileDesc } # # Check existing project file for valid contents and grab sections # if {![regexp {[ ]*(program|library)[ ]*([^;]*);.((.*)uses.([^;]*);.)?(.*)begin.(.*)} [$oldProject contents] total prjType prjName dummy1 grab1 usesBody grab2 remain]} { m4_error $E_PRJCONTENTS return $newProject } if {![regexp {(.*)[ ]*end\..*(// Do not delete this block -- regeneration marker -- start)(.*)(// Do not delete this block -- regeneration marker -- end)} $remain total grabCode dummy1 genuses dummy2]} { m4_error $E_PRJCONTENTS return $newProject } # # Grab generated uses in existing project file # set tempList [split $genuses "\n"] foreach line $tempList { if {[regexp {^[ ]*//[ ]*([^ ]+)$} $line total name]} { set genUsesList [linsert $genUsesList 0 $name] } } # # Create project type and name # if {$prjName == "<default>"} { set prjName $projectName } $newProject append "${prjType} ${prjName};" $newProject append $grab1 # # Create uses list # set usesList [split $usesBody "\n"] if {$uses != ""} { $newProject append "\nuses\n" $newProject indent + set first 1 set oldremain "" foreach line $usesList { if {[regexp {^[ ]*(([^ ,;]+)([ ]+in[ ]+[^ ,;]+)?)([,;])?([ ]*.*)$} $line total name unitname filename dummy remain]} { if {[lsearch -exact $genUsesList $unitname] == -1 && [lsearch -exact $newUsesList $unitname] == -1} { if {$first} { set first 0 } else { $newProject append "," $newProject append "${oldremain}\n" } set oldremain $remain $newProject append "${name}" } } } if {!$first} { if {$uses != ""} { $newProject append "," } $newProject append "${oldremain}\n" } $newProject appendSect $uses $newProject append ";\n" $newProject indent - } $newProject append $grab2 # # Create project code # $newProject append "begin\n" if {[regexp {(.*)[ ]*Application\.Run;.(.*)} $grabCode total codeBody1 codeBody2]} { set codeList [split $codeBody1 "\n"] foreach line $codeList { if {![regexp "Application.CreateForm" $line]} { if {![regexp {^[ ]*$} $line]} { $newProject append "${line}\n" } } } $newProject appendSect $code $newProject indent + $newProject append "Application.Run;\n" $newProject indent - $newProject append $codeBody2 } $newProject append "end.\n\n\n" $newProject append "${DPCookie::genProjectStart}\n" foreach name $newUsesList { $newProject append "// ${name}\n" } $newProject append "${DPCookie::genProjectEnd}\n" return $newProject } method DPGenerator::generate {this classList} { set typeToClassDictionary [Dictionary new] set project [DPProject new] set regenerator [DPRegenerator new [$this fileHandler]] set pasType ${DPFileHandler::PASType} set formType ${DPFileHandler::DFMType} $classList foreach class { # Generation # m4_message $M_GEN_FOR [$class getName] $class generate $project # Regeneration # # Class file set fileDesc [[$this fileHandler] openFile $class $pasType] if {$fileDesc != ""} { $regenerator regenerate $project $class $fileDesc [$this fileHandler] closeFile $fileDesc } # Form file if {[$class isForm]} { set formfileDesc [[$this fileHandler] openFile $class $formType] if {$formfileDesc != ""} { $regenerator regenerateForm $project $class $formfileDesc [$this fileHandler] closeFile $formfileDesc } } $typeToClassDictionary set $class [Dictionary new] } $project generate $typeToClassDictionary return $typeToClassDictionary } method DPGenerator::generateSpecialFiles {this fileList} { $fileList foreach specialFile { set fileName [[$this fileHandler] getProjectFileName] set project [DPTextSection new] set usesSection [DPTextSection new] set codeSection [DPTextSection new] set newUsesList {} set newUsesList [$this generateProjectSections $usesSection $codeSection] expandHeaderIntoSection $fileName ${DPFileHandler::DPRType} $project $project appendSect [$this generateProjectFile $fileName $usesSection $codeSection $newUsesList] if {[$project contents] != ""} { if [section_equals_file $project $fileName] { m4_message $M_NOCHANGESPEC $fileName } else { m4_message $M_CREATINGSPEC $fileName [$this fileHandler] writeSectionToNamedFile $project $fileName } } } } # Do not delete this line -- regeneration end marker #--------------------------------------------------------------------------- # File: @(#)dpregenera.tcl /main/titanic/13 #--------------------------------------------------------------------------- # Start user added include file section # End user added include file section require "regenerato.tcl" Class DPRegenerator : {Regenerator} { constructor method destructor method sanityCheck method addUserCodeToMethod method grabMethodBody method grabUserIncludes method processCodeDef method grabComponentProperties method regenerateForm method regenerate attribute fileHandler } constructor DPRegenerator {class this fileHandler} { set this [Regenerator::constructor $class $this] $this fileHandler $fileHandler # Start constructor user section # End constructor user section return $this } method DPRegenerator::destructor {this} { # Start destructor user section # End destructor user section $this Regenerator::destructor } method DPRegenerator::sanityCheck {this fileDesc} { while {![eof $fileDesc]} { set line [gets $fileDesc] if {[string match *${DPCookie::obsoleteCode} $line]} { seek $fileDesc 0 return 1 } if {[regexp {(IFDEF OLDCODE)} $line]} { seek $fileDesc 0 return 2 } } seek $fileDesc 0 return 0 } method DPRegenerator::addUserCodeToMethod {this project class line userTypes userCode} { set dpclass [$project getUnit [$class getName]] set methodExpr {^[ ]*(class)?[ ]*(procedure|function|constructor|destructor)[ ]*([^.]*)\.([^(;:]*)(\(([^)]*)\))?[ ]*(:[ ]*([^ ]*))?;} regexp $methodExpr $line total classType methodType classname name dummy1 params dummy2 returnvalue if {$dpclass == ""} { return } # # Find procedure for class # set proc "" [$dpclass usermethodSet] foreach method { if {[string tolower [$method name]] == [string tolower $name]} { set proc $method } } if {$proc == ""} { [$dpclass eventSet] foreach method { if {[string tolower [$method name]] == [string tolower $name]} { set proc $method } } } # Not found, maybe it's the destructor? if {$proc == ""} { if {[$dpclass destructr] != ""} { if {[string tolower [[$dpclass destructr] name]] == [string tolower $name]} { set proc [$dpclass destructr] } } } # Not found, maybe it's the constructor? if {$proc == ""} { if {[$dpclass constructr] != ""} { if {[string tolower [[$dpclass constructr] name]] == [string tolower $name]} { set proc [$dpclass constructr] } } } # # If method still not found, add it to the obsolete code section # if {$proc == ""} { m4_warning $W_OBSOLMETHOD $name set obsCode [DPTextSection new] $obsCode append "${line}\n" $obsCode appendSect $userTypes $obsCode append "begin\n" $obsCode appendSect $userCode $obsCode append "end;\n" if {[$dpclass obsoletecode] == ""} { $dpclass obsoletecode $obsCode } else { [$dpclass obsoletecode] appendSect $obsCode } return } # # Dirty compare trick using target model! # # A temporary textsection is created with the complete method # definition to easily compare arguments and other method modifiers. # set tempSection [DPTextSection new] $proc generateDefinition $tempSection $dpclass # # If the method declaration changed, add an OLDCODE section. # Else, add the grabbed code parts. # if {[$tempSection contents] != $line} { set oldTypes [DPTextSection new] if {[$userTypes contents] != ""} { $oldTypes append "\{\$IFDEF OLDCODE\}\n" $oldTypes appendSect $userTypes $oldTypes append "\{\$ENDIF\}\n" } $proc usertypes $oldTypes set oldCode [DPTextSection new] if {[$userCode contents] != ""} { $oldCode append "\{\$IFDEF OLDCODE\}\n" $oldCode appendSect $userCode $oldCode append "\{\$ELSE\}\n" if {[$proc usercode] != ""} { $oldCode appendSect [$proc usercode] } else { $oldCode indent + $oldCode append "${DPCookie::implement0}\n" $oldCode indent - } $oldCode append "\{\$ENDIF\}\n" } $proc usercode $oldCode if {[$oldTypes contents] != "" || [$oldCode contents] != ""} { m4_warning $W_OLDCODEMETHOD $name } } else { $proc usercode $userCode $proc usertypes $userTypes } } method DPRegenerator::grabMethodBody {this fileDesc usercode usertypes} { # Note: This regenerator does not except multiple begin or ends on one line!!! # # Get user types part # set done 0 set nestinglevel 0 set tempSection [DPTextSection new] while {![eof $fileDesc] && !$done} { set line [gets $fileDesc] if {[regexp ${DPCookie::endUserSection} $line] || [regexp {(([ ]+begin)|(^begin))(([ ]+)|([ ]*$))} $line]} { set done 1 if {[regexp {(([ ]+begin)|(^begin))(([ ]+)|([ ]*$))} $line]} { set nestinglevel 1 } } else { if {[regexp ${DPCookie::startUserSection} $line]} { set tempSection [DPTextSection new] } else { $tempSection append "$line\n" } } } # Only add section if not only white space if {[regexp {[^ ]*} $tempSection]} { $usertypes appendSect $tempSection } # Get user code part # set done 0 set tempSection [DPTextSection new] while {![eof $fileDesc] && !$done} { set line [gets $fileDesc] if {[regexp {(([ ]+begin)|(^begin))(([ ]+)|([ ]*$))} $line total]} { incr nestinglevel } if {[regexp ${DPCookie::endUserSection} $line] || [regexp {(([ ]+end)|(^end));?(([ ]+)|([ ]*$))} $line total]} { if {[regexp {(([ ]+end)|(^end));?(([ ]+)|([ ]*$))} $line total]} { incr nestinglevel -1 if {$nestinglevel == 0} { set done 1 continue } } else { set done 1 continue } } else { if {[regexp ${DPCookie::startUserSection} $line]} { set tempSection [DPTextSection new] continue } } $tempSection append "$line\n" } # Only add section if not only white space if {[regexp {[^ ]*} [$tempSection contents]]} { $usercode appendSect $tempSection } return } method DPRegenerator::grabUserIncludes {this project class fileDesc} { set includes [DPTextSection new] set done 0 while {!$done} { if {[eof $fileDesc]} { m4_error $E_SYNTAX ${DPCookie::startUserInclude} "end of file" return "" } set line [gets $fileDesc] if {[regexp ${DPCookie::startUserInclude} $line]} { set done 1 } # If type declaration found, apparently no user includes exist if {[regexp "type" $line]} { return "" } } set done 0 while {!$done} { if {[eof $fileDesc]} { m4_error $E_SYNTAX ${DPCookie::endUserInclude} "end of file" return "" } set line [gets $fileDesc] if {[regexp ${DPCookie::endUserInclude} $line]} { set done 1 } else { $includes append "${line}\n" } } return [$includes contents] } method DPRegenerator::processCodeDef {this project class fileDesc} { # Check the implementation part of the unit for methods to regenerate or # make obsolete set methodExpr {^[ ]*(class)?[ ]*(procedure|function|constructor|destructor)[ ]*([^.]*)\.([^(;:]*)(\(([^)]*)\))?[ ]*(:[ ]*([^ ]*))?;} # Get all methods upto the regeneration marker # set done 0 while {![eof $fileDesc] && !$done} { set line [gets $fileDesc] if {[regexp ${DPCookie::regenMarker} $line]} { set done 1 } else { if {[regexp $methodExpr $line total]} { set ucode [DPTextSection new] set utypes [DPTextSection new] $this grabMethodBody $fileDesc $ucode $utypes $this addUserCodeToMethod $project $class $total $utypes $ucode } } } if {![regexp ${DPCookie::regenMarker} $line]} { m4_error $E_SYNTAX ${DPCookie::regenMarker} "end of file" } } method DPRegenerator::grabComponentProperties {this fileDesc line form} { set objectExpr {^[ ]*(object)[ ]*([^:]*)([^$]*)} # This is a recursive method. It calls itself for every object at # a deeper nesting level # while {[regexp $objectExpr $line total dummy1 name type]} { if {[$form name] == $name} { set component $form } else { if {[[$form control] exists $name]} { set component [$form getControl $name] [$component parent] addSortedChild $component [$component parent] removeChild $component } else { m4_warning $W_OBSOLCOMP $name # Skip (and remove) component while {![regexp {^[ ]*(end)[ ]*} $line]} { set line [gets $fileDesc] } continue } } set done 0 set tempSection [DPTextSection new] while {![eof $fileDesc] && !$done} { set line [gets $fileDesc] if {[regexp {^[ ]*(object)[ ]*} $line]} { set line [$this grabComponentProperties $fileDesc $line $form] } if {[regexp {^[ ]*(end)[ ]*} $line]} { set done 1 } else { # Do not add old event handlers (recognized by starting On/Before/After) # if {![regexp {[ ]+(on|before|after)[^ ]+} [string tolower $line]]} { regexp {[ ]*([^$]*)} $line total prop $tempSection append "${prop}\n" } } } # Add old properties # if {[regexp {[^ ]*} [$tempSection contents]]} { [$component properties] appendSect $tempSection } set line [gets $fileDesc] } return $line } # Generate all regeneration info from a form file. # # Note: All After/Before/On... properties are removed. # This is a trick to remove obsolete event handlers # without extensive checking. # method DPRegenerator::regenerateForm {this project class fileDesc} { set objectExpr {^[ ]*(object)[ ]*([^:]*)([^$]*)} # Search for form object set done 0 while {!$done} { if {[eof $fileDesc]} { m4_error $E_SYNTAX "end (of object)" "end of file" return } set line [gets $fileDesc] if {[regexp $objectExpr $line total dummy name type]} { set done 1 } } set form [$project getForm $name] $this grabComponentProperties $fileDesc $line $form } # Grab all regeneration info from an existing class file. # # Note: All TComponent classes are ignored. # method DPRegenerator::regenerate {this project class fileDesc} { # Process class file if {[$class baseType] != "TComponent"} { set sanity [$this sanityCheck $fileDesc] if {$sanity == 1} { m4_error $E_OBSOLETESECT [$class getName] return } else { if {$sanity == 2} { m4_error $E_OLDCODESECT [$class getName] return } } set classtype [$class getPropertyValue "class_type"] if {$classtype == ""} { set classtype "Class" } if {([$class get_obj_type] == "class") && ($classtype == "Class") } { set dpclass [$project getUnit [$class getName]] set userincludes [DPTextSection new] set impuserincludes [DPTextSection new] # Grab user includes in interface part $userincludes append [$this grabUserIncludes $project $class $fileDesc] # Skip all lines until the implementation part set done 0 while {!$done} { if {[eof $fileDesc]} { m4_error $E_SYNTAX "implementation" "end of file" return } set line [gets $fileDesc] if {[regexp "implementation" $line]} { set done 1 } } # Grab user includes in implementation part $impuserincludes append [$this grabUserIncludes $project $class $fileDesc] if {$dpclass != ""} { $dpclass userinclude $userincludes $dpclass impuserinclude $impuserincludes } $this processCodeDef $project $class $fileDesc } } } # Do not delete this line -- regeneration end marker