mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
fixed hoisting processor to corresponding tests succeed
This commit is contained in:
parent
21125ebc46
commit
bf970d77fd
4 changed files with 52 additions and 38 deletions
|
@ -31,11 +31,18 @@ public class AlternativesGuard implements HoistingGuard {
|
|||
|
||||
@Override
|
||||
public String render() {
|
||||
return "(" + paths.stream()
|
||||
.filter(Predicate.not(Guard::isTrivial))
|
||||
.map(Guard::render)
|
||||
.collect(Collectors.joining(" && ")) +
|
||||
")";
|
||||
List<String> renderedGuards = paths.stream()
|
||||
.filter(Predicate.not(Guard::isTrivial))
|
||||
.map(Guard::render)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (renderedGuards.size() == 1) {
|
||||
return paths.get(0).render();
|
||||
} else {
|
||||
return "(" +
|
||||
String.join(" && ", renderedGuards) +
|
||||
")";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -11,6 +11,7 @@ package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
@ -225,7 +226,7 @@ public class HoistingProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private Set<List<Token>> getTokenForIndexes(AbstractElement path, List<Integer> indexes) throws TokenAnalysisAbortedException {
|
||||
private List<List<Token>> getTokenForIndexes(AbstractElement path, List<Integer> indexes) throws TokenAnalysisAbortedException {
|
||||
return getTokenForIndexes(path, new TokenAnalysisPaths(indexes), true).getTokenPaths();
|
||||
}
|
||||
|
||||
|
@ -247,13 +248,13 @@ public class HoistingProcessor {
|
|||
List<Integer> range = range(0, i);
|
||||
|
||||
try {
|
||||
tokenListSet1 = getTokenForIndexes(path1, range);
|
||||
tokenListSet1 = new HashSet<>(getTokenForIndexes(path1, range));
|
||||
} catch (TokenAnalysisAbortedException e) {
|
||||
tokenListSet1 = null;
|
||||
}
|
||||
|
||||
try {
|
||||
tokenListSet2 = getTokenForIndexes(path2, range);
|
||||
tokenListSet2 = new HashSet<>(getTokenForIndexes(path2, range));
|
||||
} catch (TokenAnalysisAbortedException e) {
|
||||
tokenListSet2 = null;
|
||||
}
|
||||
|
@ -266,15 +267,13 @@ public class HoistingProcessor {
|
|||
return false;
|
||||
}
|
||||
if (!tokenListSet1.equals(tokenListSet2)) {
|
||||
// TODO: hashCode method of Token classes
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// we can't analyze the paths any further
|
||||
// we can assume that the paths are identical because the path diff analysis would cause an error anyway.
|
||||
// TODO maybe warning?
|
||||
return true;
|
||||
// TODO maybe assume paths are equal and show warning instead of exception
|
||||
throw new TokenAnalysisAbortedException();
|
||||
}
|
||||
|
||||
private boolean arePathsIdentical(AbstractElement path1, AbstractElement path2) {
|
||||
|
@ -423,9 +422,13 @@ public class HoistingProcessor {
|
|||
return builder.toString();
|
||||
}
|
||||
|
||||
private List<Set<List<Token>>> findMinimalPathDifference(List<AbstractElement> paths) throws TokenAnalysisAbortedException {
|
||||
List<Set<List<Token>>> result = paths.stream()
|
||||
.map(p -> (Set<List<Token>>) null)
|
||||
private List<List<List<Token>>> findMinimalPathDifference(List<AbstractElement> paths) throws TokenAnalysisAbortedException {
|
||||
// first dimension of result corresponds to the paths
|
||||
// the second dimension are the alternatives of the path
|
||||
// the third dimension are tokens of the alternative of the path
|
||||
|
||||
List<List<List<Token>>> result = paths.stream()
|
||||
.map(p -> (List<List<Token>>) null)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
paths.forEach(p -> {
|
||||
|
@ -436,12 +439,12 @@ public class HoistingProcessor {
|
|||
log.info("current index list: " + indexList);
|
||||
|
||||
// will throw TokenAnalysisAborted if any path is too short
|
||||
List<Set<List<Token>>> tokenListSets = paths.stream()
|
||||
List<List<List<Token>>> tokenListsForPaths = paths.stream()
|
||||
//.peek(p -> log.info("next path: " + p))
|
||||
.map(p -> getTokenForIndexes(p, indexList))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
log.info("sets: " + tokenListSets);
|
||||
log.info("token lists: " + tokenListsForPaths);
|
||||
|
||||
int size = result.size();
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
@ -449,15 +452,16 @@ public class HoistingProcessor {
|
|||
continue;
|
||||
}
|
||||
|
||||
Set<List<Token>> tokenListSet = tokenListSets.get(i);
|
||||
if (!tokenListSet.stream()
|
||||
.anyMatch(tokenList -> tokenListSets.stream()
|
||||
.filter(s -> s != tokenListSet)
|
||||
List<List<Token>> tokenListOfCurrentPath = tokenListsForPaths.get(i);
|
||||
if (!tokenListOfCurrentPath.stream()
|
||||
.anyMatch(tokenList -> tokenListsForPaths.stream()
|
||||
.filter(s -> s != tokenListOfCurrentPath)
|
||||
// does any other path contain a similar token list (= alternative)
|
||||
.anyMatch(s -> s.contains(tokenList))
|
||||
)
|
||||
) {
|
||||
// token list set is unique for path i
|
||||
result.set(i, tokenListSet);
|
||||
result.set(i, tokenListOfCurrentPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -510,7 +514,7 @@ public class HoistingProcessor {
|
|||
.collect(Collectors.toList())
|
||||
)
|
||||
.map(TokenSequenceGuard::new)
|
||||
.collect(Collectors.toSet())
|
||||
.collect(Collectors.toList())
|
||||
)
|
||||
.map(AlternativeTokenSequenceGuard::new),
|
||||
guards.stream(),
|
||||
|
@ -522,23 +526,25 @@ public class HoistingProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
private AbstractElement cloneAbstractElement(AbstractElement element) {
|
||||
AbstractElement clone = (AbstractElement) XtextFactory.eINSTANCE.create(element.eClass());
|
||||
private EObject cloneEObject(EObject element) {
|
||||
EObject clone = XtextFactory.eINSTANCE.create(element.eClass());
|
||||
for (EStructuralFeature feature : element.eClass().getEAllStructuralFeatures()) {
|
||||
Object value = element.eGet(feature);
|
||||
if (value instanceof AbstractElement) {
|
||||
// if value is AbstractElement a deep copy is needed since an EObject can only be
|
||||
if (value instanceof EObject) {
|
||||
// if value is EObject a deep copy is needed since an EObject can only be
|
||||
// referenced by one other EObject.
|
||||
// Note: technically not correct, since this behavior relates to all EObjects, not
|
||||
// just AbstractElement, but I'm lazy.
|
||||
|
||||
value = cloneAbstractElement((AbstractElement) value);
|
||||
|
||||
value = cloneEObject((EObject) value);
|
||||
}
|
||||
clone.eSet(feature, value);
|
||||
}
|
||||
return clone;
|
||||
}
|
||||
|
||||
private AbstractElement cloneAbstractElement(AbstractElement element) {
|
||||
return (AbstractElement) cloneEObject(element);
|
||||
}
|
||||
|
||||
private HoistingGuard findGuardForGroup(Group group) {
|
||||
log.info("find guard for group");
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ public class PredicateGuard implements HoistingGuard {
|
|||
|
||||
@Override
|
||||
public String render() {
|
||||
return "(" + JavaCodeUtils.getSource(element.getCode()) + ")";
|
||||
return "(" + JavaCodeUtils.getSource(element.getCode()).trim() + ")";
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,9 +8,8 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.xtext.xtext.generator.parser.antlr.hoisting;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.xtext.AbstractElement;
|
||||
|
@ -19,13 +18,14 @@ import org.eclipse.xtext.AbstractElement;
|
|||
* @author overflow - Initial contribution and API
|
||||
*/
|
||||
public class TokenAnalysisPaths {
|
||||
private Set<TokenAnalysisPath> tokenPaths = new HashSet<>();
|
||||
private List<TokenAnalysisPath> tokenPaths = new LinkedList<>();
|
||||
private boolean isEmpty = false;
|
||||
|
||||
public Set<List<Token>> getTokenPaths() {
|
||||
public List<List<Token>> getTokenPaths() {
|
||||
return tokenPaths.stream()
|
||||
.map(TokenAnalysisPath::getTokenPath)
|
||||
.collect(Collectors.toSet());
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public TokenAnalysisPaths(List<Integer> indexes) {
|
||||
|
@ -35,7 +35,7 @@ public class TokenAnalysisPaths {
|
|||
public TokenAnalysisPaths(TokenAnalysisPaths prefix) {
|
||||
this.tokenPaths = prefix.tokenPaths.stream()
|
||||
.map(TokenAnalysisPath::new)
|
||||
.collect(Collectors.toSet());
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
|
@ -50,6 +50,7 @@ public class TokenAnalysisPaths {
|
|||
if (isEmpty) {
|
||||
return other;
|
||||
} else {
|
||||
// TODO: implement hashCode and equals to check for duplicates right awaz
|
||||
this.tokenPaths.addAll(other.tokenPaths);
|
||||
return this;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue