What is the best approach to incremental compilation when building DSL using Eclipse?

As suggested in the Eclipse documentation, I have an org.eclipse.core.resources.IncrementalProjectBuilder that compiles each source file, and I also have an org.eclipse.ui.editors.text.TextEditor that can edit each source file. Each source file is compiled into its own compilation unit, but it can refer to types from other (already compiled) source files.

Two tasks for which this is important:

  • Compilation (to make sure the types we use really exist)
  • Autocomplete (to see the type so we can see what properties / methods are present on it)

To do this, I want to keep the representation of all compiled types in memory (hereinafter referred to as "type storage").

My question is double:

  • The task described above is performed by the developer and the second task of the editor. So that both of them have access to this type of storage, should I create a static store somewhere that both of them can access, or does Eclipse provide a faster way to deal with this problem? Note that this is eclipse, not me, which creates instances and editors when they are needed.

  • When opening eclipse, I don’t want to rebuild the whole project so that I can refill the type store. My best solution so far is to save this data somewhere, and then re-pick up my store (possibly with an open project). How do other incremental compilers usually do this? I believe the Java approach is to use a special parser that efficiently extracts this data from class files.

Any ideas would be really appreciated. This is my first DSL.

+6
source share
1 answer

This is an interesting question and one that does not have a simple solution. I will try to describe a potential solution, as well as a little more detail about how JDT performs incremental compilation.

First, a little about JDT:

Yes, JDT does read class files for some information, but only for libraries that don't have source code. And this information is really used only for editing help (content support, navigation, etc.).

JDT computes incremental compilation by tracking dependencies between compilation units as they are compiled. This status information is stored on disk and is retrieved and updated after each compilation.

As a more complete example, let's say that after a complete build, the JDT determines that A.java depends on B.java, which depends on C.java.

If a structural change occurs in C.java (a structural change is a change that can affect external files (for example, adding / removing a non-file field or method)), then B.java will be recompiled. A.java will not be recompiled, since there were no structural changes in B.java.

After this clarification on how JDT works, here are a few possible answers to your questions:

  • Yes. This must be done through statically accessible global objects. JDT does this through the JavaCore and JavaModelManager objects. If you do not want to use global singletones, you can access your type store, accessible through your plug-in activator instance. The e4 project allows dependency injection, which is probably even better (but not really part of the core Eclipse APIs).
  • I think storing file system information is your best bet. The only real way to determine the incremental dependencies of a compilation is to make a complete assembly, so you need to save the information somewhere. Again, this is what JDT does. Information is stored in the .metadata jobs .metadata somewhere in the org.eclipse.core.resources plugin. You can look at the class org.eclipse.jdt.internal.core.builder.State to see the implementation.

So, this may not be the answer you are looking for, but I think this is the most promising way to approach your problem.

+2
source

Source: https://habr.com/ru/post/886499/


All Articles