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:[email protected]
**********************************************************************