DSL template functions (specialization) [message #1786440] |
Thu, 03 May 2018 05:36  |
Eclipse User |
|
|
|
Hello,
I am currently working on a DSL that is basically a functional language.
We want to add a "specialization" feature which will allow us to have template functions.
The main idea is to have a template function which call one or more other functions.
These other functions can then be overridden in other files without rewriting the template function.
To illustrate the purpose, here is an example.
File Parent.mydsl
Parent 1.0.0
function suffix {
return "Parent"
}
function myTemplateFunction : string as input {
return input + call suffix
}
File Child.mydsl
Child 1.0.0
specializes Parent
specialized function suffix {
return "Child"
}
File Main.mydsl
Main 1.0.0
function main {
var string as parent = call Parent.myTemplateFunction("test") // => "testParent"
var string as child = call Child.myTemplateFunction("test") // => "testChild"
}
The problem I am facing is that Child.myTemplateFunction is not resolved.
This is normal because it is not defined in Child.mydsl.
I tried adding the EObjectDescription via the a custom ResourceDescriptionStrategy#createEObjectDescriptions to do as if Child contained a function named "myTemplateFunction", but it didn't work.
The grammar and the MWS2 file I used are in the attached files.
I would be very grateful if anyone can help me on this issue.
|
|
|
|
Re: DSL template functions (specialization) [message #1786572 is a reply to message #1786513] |
Mon, 07 May 2018 10:54  |
Eclipse User |
|
|
|
Hello,
Thanks for your answer.
We came up with another but somewhat similar solution because we also had to handle imports such as import "Parent-1.0.0.mydsl" for which we must also take care of the version.
I did not mention this point in the original post for simplicity's sake.
So, I'm posting this solution but with a simpler import statement, such as import Parent.
The grammar is modified as follows:
CommonInstance:
name=ID version=VERSION
('import' imports+=ImportDeclaration (',' imports+=ImportDeclaration)*)?
(specialization=Specialization)?
functions+=FunctionDefinition*;
ImportDeclaration:
referenced=[CommonInstance|ID];
...
Then, in MyDslScopeProvider (see attached MyDslScopeProvider.xtend file), we basically restrict the scope to limit to all functions belonging the imports and the file itself (this is done in the inner class DelegatingScope).
Then when we have function definition, we look for the parents and import their functions as is. This allows us to use parent's functions without the prefix Parent. in the specialized file.
Example:
Parent-1.0.0.mydsl
Parent 1.0.0
function suffix {
return "Parent"
}
function myTemplateFunction : string as input {
return input + call suffix
}
function parentHelperMethod : string as input {
return input + "Helper"
}
Child-1.0.0.mydsl
Child 1.0.0
specializes Parent
specialized function suffix {
return call parentHelperMethod("Child")
}
Then we look if any of the imported file is a specialized file. If yes, then we add its functions and its parent's functions in the scope while taking care to adjust the qualified name. The piece of code doing this is:
var parentScope = Scopes::scopeFor(
defs,
[QualifiedName.create(imported.get(it.eContainer as CommonInstance).name, it.name)],
new DelegatingScope(super.getScope(context, reference), root)
)
[QualifiedName.create(imported.get(it.eContainer as CommonInstance).name, it.name)] is doing the trick.
See the entire MyDslScopeProvider.xtend file for all the code.
The the Main.mydsl becomes:
Main 1.0.0
import Parent, Child
function main {
var string as parent = call Parent.myTemplateFunction("test") // => "testParent"
var string as child = call Child.myTemplateFunction("test") // => "testChildHelper"
}
Thanks for your support!
Cheers.
|
|
|
Powered by
FUDForum. Page generated in 0.04262 seconds