I recognize that if an IP is not in the current compile unit and isn't run in a handle, that it can be difficult determining where it is. Even run in a handle it could be tricky determining where it is because the handle could be passed in to the compile unit. But, is there any reasonably easy way of determining that an IP *is* local so that one can take those out of the pool of what needs to be resolved?
right track
You were on the right track, and it looks like
ArrayList<>is not a problem. I mis-remembered something about OE not working with generics, but I guess we're OK.Here's a mix of some of your code with some of mine. This works for me.
using Progress.Lang.*. using proparse.utilities.OutputWindow. using org.prorefactor.treeparser.ParseUnit from assembly. using org.prorefactor.core.JPNode from assembly. using org.prorefactor.treeparser.SymbolScope from assembly. using org.prorefactor.treeparser.Block from assembly. using com.joanju.proparse.ProParserTokenTypes from assembly. def var filenameToParse as char no-undo initial "tools/proparse/utilities/DirectoryParser.cls". run proparse/setup/setup.p. def var javafile as java.io.File. javafile = new java.io.File(filenameToParse). def var parseunit as ParseUnit. parseunit = new ParseUnit(javafile). parseunit:treeParser01(). define variable mobNode as JPNode no-undo. define variable mobScope as class SymbolScope no-undo. define variable mobBlock as class Block no-undo. define variable mobChildScopes as class java.util.ArrayList no-undo. define variable minWhich as integer no-undo. mobChildScopes = parseUnit:getRootScope():getChildScopes(). do minWhich = 0 to mobChildScopes:size() - 1: mobScope = cast( mobChildScopes:get( minWhich ), SymbolScope). mobBlock = mobScope:getRootBlock(). mobNode = mobBlock:getNode(). message mobNode:getText() view-as alert-box. case mobNode:getType(): when ProParserTokenTypes:METHOD then do: def var idNode as JPNode no-undo. idNode = mobNode:FindDirectChild(ProParserTokenTypes:ID). if (idNode ne ?) then message idNode:GetText() view-as alert-box. end. end case. end. catch e as Error: message e:GetMessage(1) view-as alert-box. end catch.One approach that has
One approach that has occured to me is to go through all of the nodes of ProParserTokenType:run, get the toStringFullText of the firstChild, then, if that is of type ProParserTokenTypes:filename, decide if it is a compile unit or not. If not, then collect it. Meanwhile, I could collect all nodes of ProParserTokenTypes:procedure (does that really mean internal procedure?) and collect those. Then, at the end of the compile unit, compare the two lists. If one from the first list is on the second list, then it is internal, otherwise it is external.
Something better?
getting a unit's procedures
Proparse builds tables of symbols and scopes, which you can use. Some groovy borrowed from AutoDox2:
import com.joanju.proparse.ProToken; import org.prorefactor.core.JPNode; import org.prorefactor.core.TokenTypes; import org.prorefactor.nodetypes.BlockNode; import org.prorefactor.treeparser.Block; import org.prorefactor.treeparser.ParseUnit import org.prorefactor.treeparser.Routine import org.prorefactor.treeparser.SymbolScope; ParseUnit unit void buildRoutines() { def functionRoutineDoxs = new HashMap() def funcAndProcDoxs = new HashMap() def functionForwardRoutines = new HashMap() def inSuperRoutines = new HashMap() scopes_loop: for (SymbolScope scope : unit.getRootScope().getChildScopes()) { Block block = scope.getRootBlock(); JPNode blockNode = block.getNode(); int blockNodeType = blockNode.getType(); // We only want methods, not triggers or CAN-FIND scopes. switch (blockNodeType) { case TokenTypes.PROCEDURE : case TokenTypes.FUNCTION : case TokenTypes.METHOD : case TokenTypes.CONSTRUCTOR : break default : continue scopes_loop } def routine = (Routine) blockNode.getSymbol() boolean isFunc = blockNodeType==TokenTypes.FUNCTION boolean isProc = blockNodeType==TokenTypes.PROCEDURE def name = routine.getName().toLowerCase() // IN SUPER functions and procedures need to be documented, but they // might be overridden by local func/proc of the same name. Keep these // in a separate list for now, and only add them if there's no local equivalent. if ((isFunc || isProc) && blockNode.findDirectChild(TokenTypes.IN_KW) && blockNode.findDirectChild(TokenTypes.SUPER) ) { inSuperRoutines.put(name, routine) continue scopes_loop } // We need FUNCTION FORWARDs because the formal args are // optional in the function definition block if there is a // function forward declaration. if (isFunc && blockNode.findDirectChild(TokenTypes.FORWARDS)) { functionForwardRoutines.put(name, routine) continue scopes_loop } } }Some of this makes sense and
Some of this makes sense and some doesn't ... in part because of the amount of Groovy or Java I have looked at. So, some questions.
The routine starts by defining 4 hashmaps which I would guess were intended to be lists of each of the types of blocks, but I only see any further reference of the second two. Am I missing something.
Can you give me a hint how the for loop will translate into ABL? I already have a TreeWalker structure like your sample Proparse scripting code, but I gather this is a completely separate operation using getRootScope() on the parse unit. But, that is a void method, so what is getChildScopes() applied to? I.e., how would I say this in ABL?
I see that getChildScopes() returns java.util.ArrayList sooo what do I do with that in ABL? Do I define a variable of that type and then apply the same methods I see here to get a JPNode and then an int?
The switch doesn't include destructor. Shouldn't it?
In the Javadoc, I don't see blockNode as having a getSymbol() method, nor in its parent Symbol. Am I missing something?
I gather that the if test is testing that it is a function or procedure, that it contains an IN keyword, and that it contains the word SUPER. Is this going to be true for calls to IPs in SUPERs when there is no IN SUPER listed? Or just if that is explicitly stated?
I think I get the rest. I might experiment my way through this, but a couple of pointers might hurry me along.
Another pair of questions:
Another pair of questions: In the if test near the end, you say blockNode.findDirectChild(TokenTypes.IN_KW). From the context, this appears to be a test to see if there is an IN keyword, but findDirectChild() has a return type of JPNode, so I am guessing that in Groovy, if a method that returns an object returns null, i.e., there isn't one, then this can be used in an IF as false and if it does make a return then that is equivalent to true? So, in ABL, I would do something more like
IFNode = blockNode:findDirectChild(TokenTypes.IN_KW).
if IFNode <> ? then ...
?
Second, what would one do to find the name of the handle which followed IN.
Lots of variations in RUN statements!
more groovy -> abl
You are correct: Groovy has nifty if() semantics. Nulls and empty strings evaluate to false.
For your second question: As with writing Prolint rules, a tree printer ("tokenlister") is very helpful. Your first step is to write an example of the abl you want to be able to analyze, and run it through the tree printer.
Does an indent in the
Does an indent in the tokenlister imply child? I.e.,
RUN run 3 C:\work\OETools\PPScript\src\testtokens.p
FILENAME x 3 C:\work\OETools\PPScript\src\testtokens.p
IN in 3 C:\work\OETools\PPScript\src\testtokens.p
Field_ref 0 C:\work\OETools\PPScript\src\testtokens.p
ID h 3 C:\work\OETools\PPScript\src\testtokens.p
PERIOD . 3 C:\work\OETools\PPScript\src\testtokens.p
Field_ref is a child of IN and the ID of the Field_ref is a child of Field_ref?
Re: does an indent...
Yes, that's correct.
I am trying to fiddle my way
I am trying to fiddle my way through this and the piece which really has me stumped is the for loop. As I read this,
* unit is the ParseUnit which is the current focus.
* getRootScope() returns SymbolScopeRoot.
* getChildScopes() (a method on SymbolScope, parent of SymbolScopeRoot returns java.util.ArrayList
so the for loop is going to iterate through the ArrayList setting each entry to scope which is of type SymbolScope.
So, conceptually I get this, but how do I deal with java.util.ArrayList in ABL?
ArrayList
Good question, and because it actually returns ArrayList, I think it depends on the version of OE whether we can handle this from ABL or not. I'll have to look into it and get back to you.
Well, I'm glad that it isn't
Well, I'm glad that it isn't a stupid question! :)
I am working in 11.0.