IS an IP local?

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?

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
john's picture

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
javafile = new
def var parseunit as ParseUnit.
parseunit = new ParseUnit(javafile).

     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 case.

catch e as Error:
  message e:GetMessage(1) view-as alert-box.
end catch.

tamhas's picture

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?

john's picture

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()
	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	:
			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

tamhas's picture

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.

tamhas's picture

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!

john's picture

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.

tamhas's picture

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?

john's picture

Re: does an indent...

Yes, that's correct.

tamhas's picture

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?

john's picture


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.

tamhas's picture

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.