-
-
Notifications
You must be signed in to change notification settings - Fork 352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
review: feature: introduce the concept of "Pattern" #1686
Conversation
Cool! Could you give an example snippet of how to use this? |
} | ||
|
||
static Pattern create(Factory factory) { | ||
return PatternBuilder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you explain as comments what it's meant to do?
5ff89d4
to
140a388
Compare
140a388
to
d943134
Compare
Here is example of code which is matched by pattern above try (ListPrinter lp = elementPrinterHelper.createListPrinter(false, "(", false, false, ",", true, false, ")")) {
for (Entry<String, CtExpression> e : annotation.getValues().entrySet()) {
lp.printSeparatorIfAppropriate();
if ((annotation.getValues().size() == 1 && "value".equals(e.getKey())) == false) {
//it is not a default value attribute. We must print a attribute name too.
printer.writeIdentifier(e.getKey()).writeSpace().writeOperator("=").writeSpace();
}
elementPrinterHelper.writeAnnotationElement(annotation.getFactory(), e.getValue());
}
} The Pattern match provides a actual parameter values for each defined parameter. Such parameters + another pattern can be used to generate new code based on the actual values and then replace old code by new code -> to do a refactoring based on the pattern matching/generating. See CodeReplaceTest#testTemplateReplace for running example. This example transforms the matched code above by newly generated code like this: elementPrinterHelper.printList(annotation.getValues().entrySet(), false, "(", false, false, ",", true, false, ")"), e -> {
if ((annotation.getValues().size() == 1 && "value".equals(e.getKey())) == false) {
//it is not a default value attribute. We must print a attribute name too.
printer.writeIdentifier(e.getKey()).writeSpace().writeOperator("=").writeSpace();
}
elementPrinterHelper.writeAnnotationElement(annotation.getFactory(), e.getValue());
}); The example consists of these files:
/**
* Looks for all matches of Pattern defined by `OldPattern_ParamsInNestedType.class`
* and replaces each match with code generated by Pattern defined by `NewPattern.class`
* @param rootElement the root element of AST whose children has to be transformed
*/
@SuppressWarnings("unchecked")
public static void replaceOldByNew(CtElement rootElement) {
CtType<?> targetType = (rootElement instanceof CtType) ? (CtType) rootElement : rootElement.getParent(CtType.class);
Factory f = rootElement.getFactory();
Pattern newPattern = NewPattern.createPattern(f);
Pattern oldPattern = OldPattern.createPattern(f);
oldPattern.forEachMatch(rootElement, (match) -> {
RoleHandler rh = RoleHandlerHelper.getRoleHandlerWrtParent(match.getMatchingElement(CtElement.class, false));
match.replaceMatchesBy(newPattern.applyToType(targetType, (Class) rh.getValueClass(), match.getParametersMap()));
});
} It really works now. The tests are passing well. |
f325ef0
to
66cd486
Compare
68f00d6
to
3d6e4a4
Compare
3d6e4a4
to
ae91d70
Compare
I was wrong. Adding of the removed part of
What next? |
it seems that the next step is to merge #2016? |
Yes, I will work on it next days ... or if you would have time, I welcome any refactoring you do there. Just put note there so we are not doing it parallel. I will add comment into #2016 before I start too. |
Conflicts: src/main/java/spoon/Metamodel.java src/main/java/spoon/template/BlockTemplate.java src/main/java/spoon/template/ExpressionTemplate.java src/main/java/spoon/template/StatementTemplate.java src/test/java/spoon/MavenLauncherTest.java src/test/java/spoon/test/api/MetamodelTest.java src/test/java/spoon/test/architecture/SpoonArchitectureEnforcerTest.java
I just merged master. Now I will check whether new metamodel is still fitting to Pattern needs and then will refactor Pattern to use new Metamodel. |
3d6d60a
to
7e7f89f
Compare
It is finished from my point of view. Note: I moved hardcoded metamodel to test, so we can still check correctness of spoon metamodel. |
I moved MetamodelTest.testRuntimeMetamodel and related classes to #2050 |
API changes: 4 (Detected by Revapi) Old API: fr.inria.gforge.spoon:spoon-core:jar:6.3.0-20180609.225321-133 / New API: fr.inria.gforge.spoon:spoon-core:jar:6.3.0-SNAPSHOT
|
Pavel, thanks a lot for this great contribution! Having new and big features in Spoon is really awesome. Next one on our roadmap: the sniper mode! |
Hallelujah :-))) |
There is a regression on the template side, in https://github.com/SpoonLabs/spoon-examples, see https://ci.inria.fr/sos/job/spoon-examples/507/console Could you have a look at it? |
I will have a look in the evening ... if I make internet at home running after tonight storm ... |
This PR introduces a new concept
Pattern
, which is an improvement of TemplateMatcher, it allows to match EVERY attribute of Spoon model - not only a subset like current TemplateMatcher.The concept of Pattern is like this:
Pattern
consists of List ofRootNode
s. Main implementation ofRootNode
isConstantNode
, which handles constant values of attributes andElementNode
, which knows the node type and a Map<CtRole, RootNode> of nodes for handling of specific attributes. SoElementNode
s andConstantNode
s together makes up the tree of the pattern - it mirrors to be generated/matched Spoon AST.ParameterNode
which linksParameterInfo
, which defines which value from Map of parameters (ParameterValueProvider
) has to substituted.Both algorithms generating of code from template and matching code by template are primary behavior of new patterns and are 100% compatible. Everything what can be generated can be matched and opposite.