Thanks to everyone for all the responses!
I put the macro at the end of this posting.
Cannon Smith inquired:
RE> I don?t have a macro for you, but I?m curious to know why asking the
compiler to check the syntax isn?t enough?
1. It may not be a syntactical problem; I may have simply forgotten to
declare the variable. While I use the 'All Variables are Typed' option, I
find that 4D doesn't bark very loud if it can discern the typing.
2. The main reason is that I'm changing my coding style (a hard thing to
do) from putting all my declarations on the first few lines in the method
to putting them throughout the method, wherever the variable is used, so
there's more opportunity for missed and double declarations.
3. I used to clear arrays by doing yet another array declaration, such as
ARRAY TEXT($aText;0), which really isn't a best practice IMHO because way
back when we had ARRAY STRING it was possible to change a string length in
one place and not change it in another place - if you want to declare an
array, then declare it, if you want to resize it, then resize it. Separate
tools for separate operations. Hence, I look for "double declarations"
where I may have declared a variable twice.
4. I've found that while I'm meticulous about declaring my variables, when
I flub, it is often because of a mis-spelling.
C_TEXT($MyVeryLongVariableName) works fine, but later in the thick and
heat and smoke of a thundering coding session I might use
$MyVaryLongVariableName:=2 - syntactically this works, the compiler
probably won't bark, but I have a bug and an easy way to find it is to see
if I've declared it.
Thanks *VERY* much to Lee Hinde for pointing out that it is a lot easier
to examine what valid characters IN a local variable vs trying to examine
characters that might fall AFTER a local variable.
++++++
Here's the macro, set up to run when the method is saved:
<macro name="Check Local Vars" method_event="on_save" type_ahead="false"
version="2">
<text><method>CheckLocalDeclarations("<method_path/>")</method></text>
</macro>
+++++++
Here's the 4D code, CheckLocalDeclarations, that does the check. Provide
your own dialog to display vMsgText, vMsgText1, and vMsgText2 - or if you
are using v16, don't do this, just pass the values as parameters to the
form.
//Bob Miller04/27/18CheckLocalDeclarations - 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)
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)//cool technique I learned from Tim PENNER at 4D
$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
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
$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
$RegEx:="\\$[a-zA-Z0-9]*"//many thanks to Lee Hinde for this, horray!
// ++++++++++++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";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]
**********************************************************************