RE> What I?m not sure how to do (well, I?m unwilling to spend the time, because WTH) is capture spaces within a variable name.
If anyone puts spaces in a variable name, well, they deserve what they get. I also realized that constructions such as ARRAY TEXT($aMyTextArray;$ArraySize) contain both a declaration and a use of a variable, and also John DeSoi replied with a good idea to "smash" all strings enclosed in double quotes into just the double quotes, so that any $ contained within are not considered, so here is Version 2 of the method, that takes care of both, and also incorporates the new underscore-version of the regex: *** Version 2 *** //Bob Miller 04/30/18 CheckLocalDeclarations - called by macro to check that all local variables are declared. //Method name is passed by the macro as $1 //This method calls itself in a new process if only one parm is sent (eg. when it is called by the macro). C_TEXT($1;$2;$MethodName;$AllCodeButDeclarations;$LineDeclarationBlock;$ArrayDeclarationBlock;$NewProcessFlag) C_TEXT($MethodCode;$CR) C_TEXT($RegEx;$CodeLine) C_LONGINT($N;$NumLines;$ProcNo;$L;$NumDeclarations;$WhereCommentBegins;$WhereSemi;$WhereDollar) C_POINTER($DummyPtr) $CR:=Char(Carriage return)//I know I should use a constant, yes...still haven't got around to this. Case of : (Count parameters=1)//if called with only a single parm, then this method re-opens itself in its own process //Note below on New Process: I chose to leave the * off so I can run it again if I want, a new window is opened $ProcNo:=New process(Current method name;256*1024;Current method name;$1;"NewProcess") BRING TO FRONT($ProcNo) : (Count parameters=2) $MethodName:=$1 $NewProcessFlag:=$2//existence of $2 simply means we are in a new process, that's all it does METHOD GET CODE($MethodName;$MethodCode) ARRAY TEXT($aMethodCodeArr;0) TextToArrayList (->$MethodCode;->$aMethodCodeArr;"";"";"NoSort")//this takes text and puts each line as an array element $NumLines:=Size of array($aMethodCodeArr) For ($N;1;$NumLines)//go through all the lines of the method, separate into 4 pieces: variable declarations, array declarations, code, and comments. //We don't keep any comments.I don't know why I want to keep variable declarations separate from array declarations; it makes me feel better. $CodeLine:=$aMethodCodeArr{$N}//this is one line of code.We examine it. $WhereCommentBegins:=Position("//";$CodeLine)//find and remove all comments; they may contain local variable references, such as unused code If ($WhereCommentBegins>=1) $CodeLine:=Substring($CodeLine;1;$WhereCommentBegins-1) End if $CodeLine:=Replace string($CodeLine;Char(Tab);"")//remove leading TAB's, we want what we're looking for to be at position 1 $CodeLine:=DeLBlank ($CodeLine)//remove leading spaces from the code line, so we're assured what we are looking for will be at position 1 $CodeLine:=RemoveQuotedStrings ($CodeLine)//Thanks to John DeSoi; remove anything in double quotes, to prevent catching any $ that would be there Case of : (Position("C_";$CodeLine)=1)//this is a C_BOOLEAN or C_TEXT or C_Something declaration command and now will be at position 1 (no tabs, no spaces) $LineDeclarationBlock:=$LineDeclarationBlock+$CodeLine+$CR//this is all the code containing declarations : (Position("ARRAY ";$CodeLine)=1)//this is an ARRAY BOOLEAN or ARRAY TEXT or ARRAY Something command $WhereSemi:=Position(";";$CodeLine) If ($WhereSemi>0) $WhereDollar:=Position("$";$CodeLine;$WhereSemi)`Added this section in version 2: If ($WhereDollar>0)//if there is a dollar sign after the semicolon, eg ARRAY LONGINT($aLongintArray;$SizeOfArray) - then add this portion to $AllCodeButDeclarations $AllCodeButDeclarations:=$AllCodeButDeclarations+Substring($CodeLine;$WhereSemi;Length($CodeLine))+$CR End if $CodeLine:=Substring($CodeLine;1;$WhereSemi)+"0)"//force line to look only at the array declaration, because there could be a var after this End if $ArrayDeclarationBlock:=$ArrayDeclarationBlock+$CodeLine+$CR//this is all the code containing array declarations Else // this is not a declaration line If ($CodeLine#"")//make sure it is not a blank line; build up the code WITHOUT the declarations; we'll //later examine this to get all the variables that are in use $AllCodeButDeclarations:=$AllCodeButDeclarations+$CodeLine+$CR End if //$CodeLine#"" End case End for //$N;1;$NumLines // I haven't tried it, but Patrick Emanuel suggested this: "(?mi-s)(\\b[[:alpha:]][\\w+]*\\b)[?=\\:|\\;|\\)|\\>|\\<|\\{|\\}|\\]|\\[|\\r|\\n]|(\\$[\\w+]*\\b)|(<>[[:alpha:]][\\w+]*\\b)" $RegEx:="\\$[_a-zA-Z0-9]*"//many thanks to Lee Hinde for this, horray (version 2, with underscore)! // ++++++++++++Pull all declared local variables out ARRAY TEXT($aDeclaredLocals;0)// array of all locals pulled out of our code containing declaractions; these are "Declared Locals" ARRAY TEXT($aUniqueDeclaredLocals;0)// Same as above, reduced to a single instance for each local var ParseRegexToArray ($LineDeclarationBlock;$RegEx;->$aDeclaredLocals)//Takes the text $1, uses the RegEx $2, puts all matches in array $3 ARR_Distinct (->$aDeclaredLocals;->$aUniqueDeclaredLocals)//pulls out any duplicates, so only 1 instance is in $2 ARRAY TEXT($aLocalDeclaredMultiple;0) ARRAY LONGINT($aLocalDeclaredMultipleCount;0) ARRAY LONGINT($aIndex;0) If (Size of array($aDeclaredLocals)#Size of array($aUniqueDeclaredLocals))//check if any var is declared twice ARR_SizeArrays (0;->$aIndex) For ($L;1;Size of array($aUniqueDeclaredLocals)) $NumDeclarations:=ARR_FindInArray_All (->$aUniqueDeclaredLocals{$L};->$aDeclaredLocals;->$aIndex)//Takes the text $1, //looks for it in array $2, returns the number of times it finds it in $0.If we found it more than once, it was declared more than once. If ($NumDeclarations>1) APPEND TO ARRAY($aLocalDeclaredMultiple;$aUniqueDeclaredLocals{$L}) APPEND TO ARRAY($aLocalDeclaredMultipleCount;$NumDeclarations) End if End for End if //Size of array($aDeclaredLocals)#Size of array($aUniqueDeclaredLocals) // ++++++++++++Pull all declared local arrays out ARRAY TEXT($aDeclaredArrays;0)//Get array of all declared local arrays, just like above ARRAY TEXT($aUniqueDeclaredArrays;0) ParseRegexToArray ($ArrayDeclarationBlock;$RegEx;->$aDeclaredArrays) ARR_Distinct (->$aDeclaredArrays;->$aUniqueDeclaredArrays) If (Size of array($aDeclaredArrays)#Size of array($aUniqueDeclaredArrays))//check if any var is declared twice ARR_SizeArrays (0;->$aIndex) For ($L;1;Size of array($aUniqueDeclaredArrays)) $NumDeclarations:=ARR_FindInArray_All (->$aUniqueDeclaredArrays{$L};->$aDeclaredArrays;->$aIndex) If ($NumDeclarations>1) APPEND TO ARRAY($aLocalDeclaredMultiple;$aUniqueDeclaredArrays{$L}) APPEND TO ARRAY($aLocalDeclaredMultipleCount;$NumDeclarations) End if End for End if //Size of array($aDeclaredArrays)#Size of array($aUniqueDeclaredArrays) // ++++++++++++Pull all the local variables used in the code ARRAY TEXT($aVarsUsed;0)//Get array of all the local vars used in the code (not declared, but actually used) ARRAY TEXT($aUniqueVarsUsed;0) ParseRegexToArray ($AllCodeButDeclarations;$RegEx;->$aVarsUsed) ARR_Distinct (->$aVarsUsed;->$aUniqueVarsUsed) // ++++++++++++Compare the set of declared locals with the set of "locals used in code" //Note: ARR_Union, ARR_Subtract are part of a tech note by Charlie Vaas TN10-05 ArrayUtilities ARRAY TEXT($aDeclaredAllVars;0) ARR_Union (->$aUniqueDeclaredLocals;->$aUniqueDeclaredArrays;->$aDeclaredAllVars)//combine the declared vars with the declared arrays ARRAY TEXT($aUsedNotDeclared;0) ARR_Subtract (->$aUniqueVarsUsed;->$aDeclaredAllVars;->$aUsedNotDeclared)//do some array DIFFERENCE to get vars that are not declared ARRAY TEXT($aDeclaredNotUsed;0) ARR_Subtract (->$aDeclaredAllVars;->$aUniqueVarsUsed;->$aDeclaredNotUsed)//do some array DIFFERENCE to get vars that are declared not used // ++++++++++++We have our results in arrays, prepare text to display on a dialog C_TEXT(vMsgText;vMsgText1)//for CheckLocalVarsDlog - replace when we can send parms directly to forms in v16 (declaration is here because we are in our own process) vMsgText:=ArrayToText (->$aUsedNotDeclared;"; ")//this takes an array and converts the elements to a long text string with elements delimited by semicolon vMsgText1:=ArrayToText (->$aDeclaredNotUsed;$CR)//ditto, delimited by carriage return vMsgText2:="" For ($L;1;Size of array($aLocalDeclaredMultiple))//build up text string showing any vars that were declared more than once, along with the number of times it was declared vMsgText2:=vMsgText2+$aLocalDeclaredMultiple{$L}+" ("+String($aLocalDeclaredMultipleCount{$L})+"x)"+$CR End for If (vMsgText+vMsgText1+vMsgText2="") //do nothing, no need to open window if everything is OK (but YOU could say, "Everything seems to be OK" in fine 4D form if you wanted to) Else // I fully recognize it is now bad form to use process vars to communicate with a form, but hey, I'm still in v15... MyOpenFormWindow ($DummyPtr;"CheckLocalVarsDlog";"Check Local Variables: "+$MethodName;0;*)//$DummyPtr tells the method this is a project form, not a table form. //The form is CheckLocalVarsDlog, the next parm is the window title, then the window type, then star keeps the window open while this method completes. End if End case // Bob Miller Chomerics, a division of Parker Hannifin Corporation llllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllllll "PLEASE NOTE: The preceding information may be confidential or privileged. It only should be used or disseminated for the purpose of conducting business with Parker. If you are not an intended recipient, please notify the sender by replying to this message and then delete the information from your system. Thank you for your cooperation." ********************************************************************** 4D Internet Users Group (4D iNUG) FAQ: http://lists.4d.com/faqnug.html Archive: http://lists.4d.com/archives.html Options: https://lists.4d.com/mailman/options/4d_tech Unsub: mailto:4d_tech-unsubscr...@lists.4d.com **********************************************************************