Language composition results in overlapping paths
In language composition, the source code of the imported language is conceptually at the same path as the source code of the importing language. Because of this, you get at least warnings from the Stratego compiler, when Stratego modules in the importing language contain wildcard imports for generated files such as signatures or pretty-printing rules:
[ strj | warning ] Found more than one matching subdirectory found for 'signatures'
This is actually a hint at a bigger issue. Module dependencies in the imported language break when building the importing language. Modules of the imported language are hidden by modules of the importing language, even when a module of the imported language depends on a module of the imported language. This is an issue (at least) in SDF3 and in Stratego. In the best case, this results in build failures, since part of the source code of the imported language is no longer included in the build. However, the error messages typically point out missing strategies in the imported language, which is confusing, since the imported language itself builds fine, but breaks in the build of the importing language. In even more subtle cases, the build succeeds, but the importing language shows unintended behavior. This can be hard to spot, and when you spot it, it is completely unclear what is going on, until you understand that overlapping paths result in unexpected module dependencies.
How to reproduce
Create a new Spoofax language project with project name
A
, leave everything else on default.Create a new file
syntax/I.sdf3
:module I context-free syntax I.I = [defined in language A]
Change
syntax/A.sdf3
tomodule A imports Common I context-free start-symbols Start context-free syntax Start = I
Add the following lines to the end of
metaborg.yaml
:exports: - language: Stratego-Sugar directory: src-gen - language: SDF directory: src-gen/syntax - language: TemplateLang directory: syntax - language: EditorService directory: src-gen - language: EditorService directory: editor
Next, create a second Spoofax language project with project name
B
, leave everything else on default.Change the dependencies in
metaborg.yaml
to include a source dependency:dependencies: compile: - org.metaborg:org.metaborg.meta.lang.esv:${metaborgVersion} - org.metaborg:org.metaborg.meta.lang.template:${metaborgVersion} - org.metaborg:org.metaborg.meta.lang.nabl:${metaborgVersion} - org.metaborg:org.metaborg.meta.lang.ts:${metaborgVersion} source: - org.metaborg:org.metaborg.meta.lib.analysis:${metaborgVersion} - org.example:A:0.1.0-SNAPSHOT
Create a new file
syntax/I.sdf3
:module I context-free syntax I.I = [defined in language B]
Change
syntax/B.sdf3
tomodule B imports A
Note that module
I
in projectB
is never imported. Reference navigation in SDF3 works as intended,A
inB.sdf3
brings you toA.sdf3
in projectA
, andI
inA.sdf3
brings you toI.sdf3
in the same project.Build both projects and create a new file
b.b
:defined in language A
This results in a parse error. Change
b.b
todefined in language B
This is accepted as a valid program, showing that
I.sdf3
from projectB
made it into the parse table, even though no module imports it.You can do similar things with Stratego modules.
Work-around
Use extra subfolders in the importing language. This allows you to distinguish modules of the imported language from modules of the importing language, including generated modules. Make sure to move files from the initial project, e.g.
trans/pp.str
into your subfolder.System information
Submitted by Guido Wachsmuth on 16 June 2016 at 17:34Eclipse: org.eclipse.platform.ide 4.5.2.M20160212-1500 Spoofax: org.metaborg.spoofax.eclipse 2.0.0.20160603-105626-master System: Mac OS X x86_64 10.11.4
Attachments
Issue Log
This is indeed a problem which I encountered as well. It is really noticeable with pretty-printers with overlapping sorts, which fail or start looping when composed. It also breaks wildcard imports in Stratego, since importing
signatures/-
will only import files from the first availablesignatures
directory, instead of all of them. This problem is caused by of a lack of a proper module/package/namespace system in our metalanguages.The best thing we can do with our current metalanguages is make sure that generated things which can overlap are qualified by language name. E.g. pretty-printer rules should be prefixed with the language names, Stratego files in src-gen should be generated into a subdirectory of the language name, etc.
The problem of using the language name here again is that it makes changing the language name harder, because strategy calls and imports will have the language name in them. However, if we use a single name consistently everywhere, we can more easily change the name with a single find/replace in users of a language. Using the language identifier is not really possible, since it has dots in them, e.g.
org.metaborg.meta.lang.template
.
Log in to post comments