Skip to content

Commit 784292b

Browse files
author
meri
committed
First clean up of #151 - only one match withing target selector supported.
1 parent 7b05d6f commit 784292b

File tree

5 files changed

+125
-80
lines changed

5 files changed

+125
-80
lines changed

src/main/java/com/github/sommeri/less4j/core/compiler/selectors/SelectorsComparatorForExtend.java

+86-75
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,13 @@
66
import com.github.sommeri.less4j.core.ast.ASTCssNode;
77
import com.github.sommeri.less4j.core.ast.Selector;
88
import com.github.sommeri.less4j.core.ast.SelectorPart;
9+
import com.github.sommeri.less4j.core.problems.BugHappened;
910
import com.github.sommeri.less4j.utils.ArraysUtils;
1011
import com.github.sommeri.less4j.utils.ListsComparator;
1112
import com.github.sommeri.less4j.utils.ListsComparator.MatchMarker;
1213

1314
public class SelectorsComparatorForExtend {
1415

15-
private SelectorsManipulator manipulator = new SelectorsManipulator();
1616
private SelectorsComparatorUtils utils = new SelectorsComparatorUtils();
1717
private ListsComparator listsComparator = new ListsComparator();
1818

@@ -58,107 +58,63 @@ private boolean containsInList(List<SelectorPart> lookForParts, List<SelectorPar
5858
//FIXME (!!!) document less.js ignores leading and final combinators
5959
private Selector replaceInList(List<SelectorPart> lookForParts, Selector inSelector, List<SelectorPart> replaceBy) {
6060
List<SelectorPart> inSelectorParts = inSelector.getParts();
61-
List<SelectorPart> newInSelectorParts = new ArrayList<SelectorPart>();
61+
SelectorPartsListBuilder builder = new SelectorPartsListBuilder();
6262

6363
List<MatchMarker<SelectorPart>> matches = listsComparator.findMatches(lookForParts, inSelectorParts, selectorPartsComparator);
6464
if (matches.isEmpty() || replaceBy == null || replaceBy.isEmpty())
6565
return null;
6666

67-
//underlying
68-
lookForParts = ArraysUtils.deeplyClonedList(lookForParts);
6967
replaceBy = ArraysUtils.deeplyClonedList(replaceBy);
7068

7169
SelectorPart firstMatch = matches.get(0).getFirst();
7270
SelectorPart lastMatch = matches.get(0).getLast();
7371

7472
if (firstMatch == lastMatch) {
7573
if (lookForParts.size() != 1)
76-
throw new IllegalStateException("WTF");
77-
78-
List<SelectorPart> replaceInside = replaceInside(lookForParts.get(0), lastMatch, replaceBy);
79-
int indexOfLastMatch = inSelectorParts.indexOf(lastMatch);
80-
inSelectorParts.remove(lastMatch);
81-
replaceInside.remove(null); //FIXME (!!!) hack there may be more than that
82-
inSelectorParts.addAll(indexOfLastMatch, replaceInside);
74+
throw new BugHappened("Impossible state happened.", lookForParts.isEmpty() ? null : lookForParts.get(0));
8375

76+
List<SelectorPart> replaceInside = replaceInsidePart(lookForParts.get(0), lastMatch, replaceBy);
77+
ArraysUtils.replace(lastMatch, inSelectorParts, replaceInside);
8478
inSelector.configureParentToAllChilds();
79+
8580
return inSelector;
8681
}
8782

88-
newInSelectorParts.addAll(chopUpTo(inSelectorParts, firstMatch));
89-
chopPrefix(inSelectorParts, 1);
83+
builder.moveUpTo(inSelectorParts, firstMatch);
84+
ArraysUtils.chopFirst(inSelectorParts);
85+
9086
SelectorPart firstRemainder = selectorPartsComparator.cutSuffix(lookForParts.get(0), firstMatch);
9187
if (firstRemainder != null) {
92-
SelectorPart firstReplaceBy = replaceBy.remove(0);
93-
manipulator.directlyJoinParts(firstRemainder, firstReplaceBy);
94-
newInSelectorParts.add(firstRemainder);
88+
builder.add(firstRemainder);
89+
builder.directlyAttach(replaceBy);
90+
} else {
91+
builder.addAll(replaceBy);
9592
}
9693

97-
newInSelectorParts.addAll(replaceBy);
98-
99-
//FIXME (!!!) extract to some ast manipulator - it is also in simple selector comparator
100-
removeFromParent(chopUpTo(inSelectorParts, lastMatch));
94+
removeFromParent(ArraysUtils.chopUpTo(inSelectorParts, lastMatch));
10195

102-
SelectorPart lastRemainder = lastMatch == firstMatch ? null : selectorPartsComparator.cutPrefix(ArraysUtils.last(lookForParts), lastMatch);
103-
//SelectorPart lastRemainder = selectorPartsComparator.cutPrefix(ArraysUtils.last(lookForParts), lastMatch);
104-
chopPrefix(inSelectorParts, 1);
105-
if (lastRemainder != null) {
106-
SelectorPart attachToPart = ArraysUtils.last(newInSelectorParts);
107-
manipulator.directlyJoinParts(attachToPart, lastRemainder);
108-
}
109-
newInSelectorParts.addAll(inSelectorParts);
96+
SelectorPart lastRemainder = selectorPartsComparator.cutPrefix(ArraysUtils.last(lookForParts), lastMatch);
97+
ArraysUtils.chopFirst(inSelectorParts);
98+
builder.directlyAttachNonNull(lastRemainder);
99+
builder.addAll(inSelectorParts);
110100

111-
inSelector.setParts(newInSelectorParts);
101+
inSelector.setParts(builder.getParts());
112102
inSelector.configureParentToAllChilds();
113103

114104
return inSelector;
115105
}
116106

117-
//FIXME (!!!!) test and refactor
118-
private List<SelectorPart> replaceInside(SelectorPart lookFor, SelectorPart inside, List<SelectorPart> replaceBy) {
107+
private List<SelectorPart> replaceInsidePart(SelectorPart lookFor, SelectorPart inside, List<SelectorPart> replaceBy) {
119108
SelectorPart[] split = selectorPartsComparator.splitOn(lookFor, inside);
120-
List<SelectorPart> result = new ArrayList<SelectorPart>();
121-
SelectorPart previous = null;
122-
for (int i = 0; i < split.length; i++) {
123-
List<SelectorPart> replaceByClone = ArraysUtils.deeplyClonedList(replaceBy);
124-
if (split[i] != null) {
125-
if (previous == null)
126-
result.add(split[i]);
127-
else
128-
manipulator.directlyJoinParts(previous, split[i]);
129-
130-
if (i != split.length - 1) {
131-
manipulator.directlyJoinParts(split[i], replaceByClone.remove(0));
132-
}
133-
}
134-
135-
if (i != split.length - 1) {
136-
result.addAll(replaceByClone);
109+
SelectorPartsListBuilder builder = new SelectorPartsListBuilder();
110+
if (split.length > 0) {
111+
builder.directlyAttachNonNull(split[0]);
112+
for (int i = 1; i < split.length; i++) {
113+
builder.directlyAttach(ArraysUtils.deeplyClonedList(replaceBy));
114+
builder.directlyAttachNonNull(split[i]);
137115
}
138-
previous = ArraysUtils.chopLast(replaceByClone);
139116
}
140-
return result;
141-
}
142-
143-
private List<SelectorPart> chopUpTo(List<SelectorPart> list, SelectorPart exclusiveTo) {
144-
int indx = list.indexOf(exclusiveTo);
145-
if (indx == -1)
146-
return new ArrayList<SelectorPart>();
147-
148-
List<SelectorPart> subList = list.subList(0, indx);
149-
List<SelectorPart> result = new ArrayList<SelectorPart>(subList);
150-
subList.clear();
151-
return result;
152-
}
153-
154-
private List<SelectorPart> chopPrefix(List<SelectorPart> list, int exclusiveTo) {
155-
if (exclusiveTo > list.size())
156-
exclusiveTo = list.size();
157-
158-
List<SelectorPart> subList = list.subList(0, exclusiveTo);
159-
List<SelectorPart> result = new ArrayList<SelectorPart>(subList);
160-
subList.clear();
161-
return result;
117+
return builder.getParts();
162118
}
163119

164120
private void removeFromParent(List<SelectorPart> removeThese) {
@@ -168,10 +124,6 @@ private void removeFromParent(List<SelectorPart> removeThese) {
168124
removeThese.clear();
169125
}
170126

171-
private List<SelectorPart> sublistCopy(List<SelectorPart> list, int first, int last) {
172-
return (first > last) ? new ArrayList<SelectorPart>() : new ArrayList<SelectorPart>(list.subList(first, last));
173-
}
174-
175127
private boolean containsEmbedded(List<SelectorPart> lookFor, List<SelectorPart> inSelectors) {
176128
for (SelectorPart inside : inSelectors) {
177129
if (containsEmbedded(lookFor, inside))
@@ -197,3 +149,62 @@ private boolean containsEmbedded(List<SelectorPart> lookFor, ASTCssNode inside)
197149
}
198150

199151
}
152+
153+
class SelectorPartsListBuilder {
154+
155+
private SelectorsManipulator manipulator = new SelectorsManipulator();
156+
private List<SelectorPart> newInSelectorParts = new ArrayList<SelectorPart>();
157+
158+
public SelectorPartsListBuilder() {
159+
}
160+
161+
public List<SelectorPart> getParts() {
162+
return newInSelectorParts;
163+
}
164+
165+
public void directlyAttachNonNull(SelectorPart part) {
166+
if (part != null)
167+
directlyAttach(part);
168+
}
169+
170+
public void directlyAttach(SelectorPart part) {
171+
if (newInSelectorParts.isEmpty()) {
172+
add(part);
173+
} else {
174+
SelectorPart tail = ArraysUtils.last(newInSelectorParts);
175+
manipulator.directlyJoinParts(tail, part);
176+
}
177+
}
178+
179+
public void directlyAttach(List<SelectorPart> list) {
180+
if (!newInSelectorParts.isEmpty()) {
181+
SelectorPart tail = ArraysUtils.last(newInSelectorParts);
182+
SelectorPart firstReplaceBy = list.remove(0);
183+
manipulator.directlyJoinParts(tail, firstReplaceBy);
184+
}
185+
addAll(list);
186+
}
187+
188+
public void addAll(List<SelectorPart> list) {
189+
newInSelectorParts.addAll(list);
190+
}
191+
192+
public void addNonNull(SelectorPart part) {
193+
if (part != null)
194+
add(part);
195+
}
196+
197+
public void add(SelectorPart part) {
198+
newInSelectorParts.add(part);
199+
}
200+
201+
public void moveUpTo(List<SelectorPart> inSelectorParts, SelectorPart firstMatch) {
202+
newInSelectorParts.addAll(ArraysUtils.chopUpTo(inSelectorParts, firstMatch));
203+
}
204+
205+
@Override
206+
public String toString() {
207+
return newInSelectorParts.toString();
208+
}
209+
210+
}

src/main/java/com/github/sommeri/less4j/core/compiler/selectors/SelectorsManipulator.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public Selector directJoin(Selector firstI, Selector secondI) {
107107
return first;
108108
}
109109

110-
public SelectorPart directlyJoinParts(SelectorPart first, SelectorPart second) {
110+
public void directlyJoinParts(SelectorPart first, SelectorPart second) {
111111
if (second.hasElement()) {
112112
String secondName = second.hasElement() ? second.getElementName().getName() : "";
113113
if (first.hasSubsequent()) {
@@ -120,7 +120,6 @@ public SelectorPart directlyJoinParts(SelectorPart first, SelectorPart second) {
120120

121121
first.addSubsequent(second.getSubsequent());
122122
first.configureParentToAllChilds();
123-
return first;
124123
}
125124

126125
private Collection<Selector> replaceFirstAppender(Selector selector, List<Selector> previousSelectors) {

src/main/java/com/github/sommeri/less4j/core/compiler/selectors/SimpleSelectorComparator.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
import java.util.List;
55

66
import com.github.sommeri.less4j.core.ast.ElementSubsequent;
7-
import com.github.sommeri.less4j.core.ast.Selector;
87
import com.github.sommeri.less4j.core.ast.SelectorCombinator;
98
import com.github.sommeri.less4j.core.ast.SimpleSelector;
109
import com.github.sommeri.less4j.utils.ArraysUtils;
@@ -66,6 +65,7 @@ public SimpleSelector cutSuffix(SimpleSelector lookFor, SimpleSelector inside) {
6665
MatchMarker<ElementSubsequent> match = listsComparator.suffixMatches(lfSubsequent, insideSubsequent, elementSubsequentComparator);
6766
return removeMatch(inside, insideSubsequent, match);
6867
} else {
68+
//suffix consumed whole selector
6969
return null;
7070
}
7171
}

src/main/java/com/github/sommeri/less4j/utils/ArraysUtils.java

+35
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import java.util.List;
66

77
import com.github.sommeri.less4j.core.ast.ASTCssNode;
8+
import com.github.sommeri.less4j.core.ast.SelectorPart;
89

910
public class ArraysUtils {
1011

@@ -79,6 +80,34 @@ public static <T> T first(List<T> values) {
7980
return values.get(0);
8081
}
8182

83+
public static <T> T chopFirst(List<T> values) {
84+
if (values.isEmpty())
85+
return null;
86+
87+
return values.remove(0);
88+
}
89+
90+
public static <T> List<T> chopUpTo(List<T> list, T exclusiveTo) {
91+
int indx = list.indexOf(exclusiveTo);
92+
if (indx == -1)
93+
return new ArrayList<T>();
94+
95+
List<T> subList = list.subList(0, indx);
96+
List<T> result = new ArrayList<T>(subList);
97+
subList.clear();
98+
return result;
99+
}
100+
101+
public static <T> List<T> chopPrefix(List<T> list, int exclusiveTo) {
102+
if (exclusiveTo > list.size())
103+
exclusiveTo = list.size();
104+
105+
List<T> subList = list.subList(0, exclusiveTo);
106+
List<T> result = new ArrayList<T>(subList);
107+
subList.clear();
108+
return result;
109+
}
110+
82111
public static <T> List<T> asNonNullList(T... a) {
83112
List<T> result = new ArrayList<T>();
84113
for (T t : a) {
@@ -129,4 +158,10 @@ public static <T> List<T> joinAll(List<T>... lists) {
129158
return result;
130159
}
131160

161+
public static <T> void replace(SelectorPart lookFor, List<T> inside, List<T> replaceBy) {
162+
int indx = inside.indexOf(lookFor);
163+
inside.remove(lookFor);
164+
inside.addAll(indx, replaceBy);
165+
}
166+
132167
}

src/test/java/com/github/sommeri/less4j/compiler/ExtendsTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ public ExtendsTest(File inputFile, File outputFile, File errorList, File mapdata
1919

2020
@Parameters(name="Less: {4}")
2121
public static Collection<Object[]> allTestsParameters() {
22-
return createTestFileUtils().loadTestFiles(standardCases);
23-
//return createTestFileUtils().loadTestFiles(extendAllMatch);
22+
//return createTestFileUtils().loadTestFiles(standardCases);
23+
return createTestFileUtils().loadTestFiles(extendAllMatch);
2424
}
2525

2626
protected void assertSourceMapValid(CompilationResult actual) {

0 commit comments

Comments
 (0)