INRIA / spoon

Spoon is a metaprogramming library to analyze and transform Java source code. :spoon: is made with :heart:, :beers: and :sparkles:. It parses source files to build a well-designed AST with powerful analysis and transformation API.
http://spoon.gforge.inria.fr/
Other
1.74k stars 347 forks source link

add support for multi-phase processing and processor orchestration #1075

Open slipperyseal opened 7 years ago

slipperyseal commented 7 years ago

Hi everyone,

i'v started writing a transcoder using spoon and I'v based my code on the Launcher example which uses a Factory/ProcessingManager (see below) which then sends CtClass and CtInterface instances to two AbstractProcessors. My question is around the best way to approach multi-phase processing. I can happily extract all the class information from CtClass/CtInterface but I find I'm going to need to scan source tree twice. Scan one to do analysis and the second scan when I generate the output.

I guess my question is what the recommended approach for this is. If I simply keep my own references to all the CtClass/CtInterface instances could this cause memory issues, having all nodes is loaded in memory. Does the processor throw away each class as it moves to the next?

Or, do I just run two of these?

        final String[] args = { "--input", path, "--output-type", "nooutput" };
        launcher.setArgs(args);
        launcher.run();

        runProcessingManager();
        runProcessingManager();
    }

    private void runProcessingManager() {
        Factory factory = launcher.getFactory();
        ProcessingManager processingManager = new QueueProcessingManager(factory);
        processingManager.addProcessor(new ClassProcessor());
        processingManager.addProcessor(new InterfaceProcessor());
        processingManager.process(factory.Class().getAll());
    }
surli commented 7 years ago

Hi @slipperyseal

maybe I'm totally wrong - I'm still a newbie with using Spoon - but why don't you override the method isToBeProcessed in your processors (see AbstractProcessor) to match the element you want to process and then add directly your processor to the launcher using launcher.addProcessor(...)? In the launcher, the model will be built and then each processor will be launched on it, avoiding you to call the process method...

pvojtechovsky commented 7 years ago

If I simply keep my own references to all the CtClass/CtInterface instances could this cause memory issues, having all nodes is loaded in memory. Does the processor throw away each class as it moves to the next?

Whole spoon model is already loaded in memory and stays there. So the collecting of the list of references to the existing spoon model elements should not be a problem.

slipperyseal commented 7 years ago

hi @surli - thanks, yeah i was already using isToBeProcessed to have it call process. was just trying to determine the best method for a multi-pass approach.

thanks @pvojtechovsky - i guess that makes sense that all the inter-class references are loaded up into one big model. I'll run the processor once, keep the references and run my own phases across those.

monperrus commented 7 years ago

specifying a list of processors is the only way to do it declaratively. otherwise, you have to write the multiple phases imperatively.

this discussion seems related to point "Processor orchestration" of the roadmap.

slipperyseal commented 7 years ago

thanks everyone. I noticed that the Processor is simply fed the type list from factory.Class().getAll() which is all I needed anyway.

I've started writing a Java to C++ transcompiler. I'm probably not writing it in the best way (yet), but I've already got basic class structure, abstract methods and interfaces and simple assignment and return values for limited test cases.

https://github.com/slipperyseal/trebuchet

Happy new year!

monperrus commented 7 years ago

https://github.com/slipperyseal/trebuchet

really cool!

monperrus commented 5 years ago

see 'Source model analysis using the JJTraveler visitor combinator framework'