Skip to content

Commit 81bb27a

Browse files
author
meri
committed
Refactorings and preparations for extend #151
1 parent f7dee73 commit 81bb27a

33 files changed

+523
-101
lines changed

src/main/antlr3/com/github/sommeri/less4j/core/parser/Less.g

+29-9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ tokens {
3939
RULESET;
4040
NESTED_APPENDER;
4141
SELECTOR;
42+
EXTENDED_SELECTOR;
4243
SIMPLE_SELECTOR;
4344
ESCAPED_SELECTOR;
4445
EXPRESSION;
@@ -476,18 +477,34 @@ general_body
476477
//If we remove LBRACE from the tree, a ruleset with an empty selector will report wrong line number in the warning.
477478
-> ^(BODY LBRACE $a* $rbrace*);
478479

480+
// if this is changed, changes are the extendedSelector must be changed too
479481
selector
480482
@init {enterRule(retval, RULE_SELECTOR);}
481-
: ((combinator)=>a+=combinator | )
482-
(a+=simpleSelector | a+=nestedAppender | a+=escapedSelectorOldSyntax)
483-
(
483+
: (
484484
((combinator)=>a+=combinator | )
485485
(a+=simpleSelector | a+=nestedAppender | a+=escapedSelectorOldSyntax)
486-
)*
486+
)+
487487
-> ^(SELECTOR $a* )
488488
;
489489
finally { leaveRule(); }
490490

491+
// if this is changed, changes are the selector must be changed too
492+
// Less keyword-pseudoclass "extend" takes selector as an argument. The selector can be optionally
493+
// followed by keyword all. The grammar is ambiguous as a result and its predictability suffers.
494+
extendedSelector
495+
@init {enterRule(retval, RULE_SELECTOR);}
496+
: ( { !predicates.matchingAllRparent(input)}?=>(
497+
((combinator)=>a+=combinator | )
498+
(a+=simpleSelector | a+=nestedAppender | a+=escapedSelectorOldSyntax)
499+
)
500+
)+
501+
( { predicates.matchingAllRparent(input)}?=>b+=IDENT
502+
|
503+
)
504+
-> ^(EXTENDED_SELECTOR ^(SELECTOR $a* ) $b*)
505+
;
506+
finally { leaveRule(); }
507+
491508
//TODO clean up, this version is just a proof of concept
492509
escapedSelectorOldSyntax: LPAREN VALUE_ESCAPE RPAREN-> ^(ESCAPED_SELECTOR VALUE_ESCAPE);
493510

@@ -557,11 +574,14 @@ attrib
557574
;
558575

559576
pseudo
560-
: (c+=COLON c+=COLON? a=IDENT ((
561-
{ predicates.insideNth(input)}?=> LPAREN (b1=nth| b2=variablereference) RPAREN
562-
| LPAREN b3=pseudoparameters RPAREN
563-
)?)
564-
) -> ^(PSEUDO $c+ $a $b1* $b2* $b3*)
577+
: (c+=COLON c+=COLON? a=IDENT (
578+
(LPAREN)=>(
579+
{ predicates.insideNth(input)}?=> LPAREN (b1=nth| b2=variablereference|b3=INTERPOLATED_VARIABLE) RPAREN
580+
| { predicates.insideExtend(input)}?=> LPAREN (b4=extendedSelector) RPAREN
581+
| LPAREN b5=pseudoparameters RPAREN
582+
)
583+
|)
584+
) -> ^(PSEUDO $c+ $a $b1* $b2* $b3* $b4* $b5*)
565585
;
566586

567587
pseudoparameters:
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
package com.github.sommeri.less4j.core.ast;
22

33
public enum ASTCssNodeType {
4-
UNKNOWN, CSS_CLASS, DECLARATION, STYLE_SHEET, RULE_SET, SELECTOR, SIMPLE_SELECTOR, PSEUDO_CLASS, PSEUDO_ELEMENT, SELECTOR_ATTRIBUTE, ID_SELECTOR, CHARSET_DECLARATION, FONT_FACE, IDENTIFIER_EXPRESSION, COMPOSED_EXPRESSION, STRING_EXPRESSION, NUMBER, COLOR_EXPRESSION, FUNCTION, MEDIA, COMMENT, SELECTOR_OPERATOR, SELECTOR_COMBINATOR, EXPRESSION_OPERATOR, NTH, NAMED_EXPRESSION, MEDIA_QUERY, FIXED_MEDIA_EXPRESSION, MEDIUM, MEDIUM_MODIFIER, MEDIUM_TYPE, MEDIUM_EX_FEATURE, VARIABLE_DECLARATION, VARIABLE, INDIRECT_VARIABLE, PARENTHESES_EXPRESSION, SIGNED_EXPRESSION, ARGUMENT_DECLARATION, MIXIN_REFERENCE, GUARD_CONDITION, COMPARISON_EXPRESSION, GUARD, NESTED_SELECTOR_APPENDER, REUSABLE_STRUCTURE, FAULTY_EXPRESSION, ESCAPED_SELECTOR, ESCAPED_VALUE, INTERPOLABLE_NAME, FIXED_NAME_PART, VARIABLE_NAME_PART, KEYFRAMES, KEYFRAMES_NAME, REUSABLE_STRUCTURE_NAME, VIEWPORT, GENERAL_BODY, PAGE, NAME, PAGE_MARGIN_BOX, IMPORT, FAULTY_NODE, ANONYMOUS, EMPTY_EXPRESSION, SYNTAX_ONLY_ELEMENT, UNICODE_RANGE_EXPRESSION, INTERPOLATED_MEDIA_EXPRESSION, DOCUMENT, SUPPORTS, SUPPORTS_QUERY, SUPPORTS_CONDITION_NEGATION, SUPPORTS_CONDITION_PARENTHESES, SUPPORTS_CONDITION_LOGICAL, SUPPORTS_LOGICAL_OPERATOR
4+
UNKNOWN, CSS_CLASS, DECLARATION, STYLE_SHEET, RULE_SET, SELECTOR, SIMPLE_SELECTOR, PSEUDO_CLASS, PSEUDO_ELEMENT, SELECTOR_ATTRIBUTE, ID_SELECTOR, CHARSET_DECLARATION, FONT_FACE, IDENTIFIER_EXPRESSION, COMPOSED_EXPRESSION, STRING_EXPRESSION, NUMBER, COLOR_EXPRESSION, FUNCTION, MEDIA, COMMENT, SELECTOR_OPERATOR, SELECTOR_COMBINATOR, EXPRESSION_OPERATOR, NTH, NAMED_EXPRESSION, MEDIA_QUERY, FIXED_MEDIA_EXPRESSION, MEDIUM, MEDIUM_MODIFIER, MEDIUM_TYPE, MEDIUM_EX_FEATURE, VARIABLE_DECLARATION, VARIABLE, INDIRECT_VARIABLE, PARENTHESES_EXPRESSION, SIGNED_EXPRESSION, ARGUMENT_DECLARATION, MIXIN_REFERENCE, GUARD_CONDITION, COMPARISON_EXPRESSION, GUARD, NESTED_SELECTOR_APPENDER, REUSABLE_STRUCTURE, FAULTY_EXPRESSION, ESCAPED_SELECTOR, ESCAPED_VALUE, INTERPOLABLE_NAME, FIXED_NAME_PART, VARIABLE_NAME_PART, KEYFRAMES, KEYFRAMES_NAME, REUSABLE_STRUCTURE_NAME, VIEWPORT, GENERAL_BODY, PAGE, NAME, PAGE_MARGIN_BOX, IMPORT, FAULTY_NODE, ANONYMOUS, EMPTY_EXPRESSION, SYNTAX_ONLY_ELEMENT, UNICODE_RANGE_EXPRESSION, INTERPOLATED_MEDIA_EXPRESSION, DOCUMENT, SUPPORTS, SUPPORTS_QUERY, SUPPORTS_CONDITION_NEGATION, SUPPORTS_CONDITION_PARENTHESES, SUPPORTS_CONDITION_LOGICAL, SUPPORTS_LOGICAL_OPERATOR, EXTEND
55
}

src/main/java/com/github/sommeri/less4j/core/ast/EscapedSelector.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.github.sommeri.less4j.core.ast;
22

3-
import java.util.Collections;
43
import java.util.List;
54

65
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
@@ -10,8 +9,8 @@ public class EscapedSelector extends SelectorPart {
109
private String value;
1110
private String quoteType;
1211

13-
public EscapedSelector(HiddenTokenAwareTree underlyingStructure, String value, String quoteTypes) {
14-
super(underlyingStructure);
12+
public EscapedSelector(HiddenTokenAwareTree underlyingStructure, String value, String quoteTypes, SelectorCombinator leadingCombinator) {
13+
super(underlyingStructure, leadingCombinator);
1514
this.value = value;
1615
this.quoteType = quoteTypes;
1716
}
@@ -44,8 +43,8 @@ public EscapedSelector clone() {
4443

4544

4645
@Override
47-
public List<? extends ASTCssNode> getChilds() {
48-
return Collections.emptyList();
46+
public List<ASTCssNode> getChilds() {
47+
return super.getChilds();
4948
}
5049

5150
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.github.sommeri.less4j.core.ast;
2+
3+
import java.util.List;
4+
5+
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
6+
import com.github.sommeri.less4j.utils.ArraysUtils;
7+
8+
public class Extend extends ASTCssNode {
9+
10+
private boolean all = false;
11+
private Selector target;
12+
13+
public Extend(HiddenTokenAwareTree underlyingStructure) {
14+
super(underlyingStructure);
15+
}
16+
17+
public Extend(HiddenTokenAwareTree underlyingStructure, Selector selector) {
18+
this(underlyingStructure, selector, false);
19+
}
20+
21+
public Extend(HiddenTokenAwareTree underlyingStructure, Selector target, boolean all) {
22+
super(underlyingStructure);
23+
this.target = target;
24+
this.all = all;
25+
}
26+
27+
public boolean isAll() {
28+
return all;
29+
}
30+
31+
public void setAll(boolean all) {
32+
this.all = all;
33+
}
34+
35+
public Selector getTarget() {
36+
return target;
37+
}
38+
39+
public void setTarget(Selector target) {
40+
this.target = target;
41+
}
42+
43+
@Override
44+
public List<? extends ASTCssNode> getChilds() {
45+
return ArraysUtils.asNonNullList(target);
46+
}
47+
48+
@Override
49+
public ASTCssNodeType getType() {
50+
return ASTCssNodeType.EXTEND;
51+
}
52+
53+
@Override
54+
public Extend clone() {
55+
Extend result = (Extend) super.clone();
56+
result.target = target==null?null:target.clone();
57+
result.configureParentToAllChilds();
58+
return result;
59+
}
60+
61+
}

src/main/java/com/github/sommeri/less4j/core/ast/InterpolableName.java

+10
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,14 @@ public void extendName(String extension) {
8282

8383
}
8484

85+
@Override
86+
public String toString() {
87+
StringBuilder builder = new StringBuilder();
88+
for (InterpolableNamePart part : getParts()) {
89+
builder.append(part);
90+
}
91+
return builder.toString();
92+
}
93+
94+
8595
}

src/main/java/com/github/sommeri/less4j/core/ast/InterpolableNamePart.java

+21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.github.sommeri.less4j.core.ast;
22

3+
import java.util.List;
4+
35
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
46

57
//interpolable name part MUST be a child of interpolable name
@@ -19,4 +21,23 @@ public InterpolableName getParent() {
1921
public InterpolableNamePart clone() {
2022
return (InterpolableNamePart) super.clone();
2123
}
24+
25+
@Override
26+
public List<? extends ASTCssNode> getChilds() {
27+
// TODO Auto-generated method stub
28+
return null;
29+
}
30+
31+
@Override
32+
public ASTCssNodeType getType() {
33+
// TODO Auto-generated method stub
34+
return null;
35+
}
36+
37+
@Override
38+
public String toString() {
39+
return getName();
40+
}
41+
42+
2243
}

src/main/java/com/github/sommeri/less4j/core/ast/NestedSelectorAppender.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.github.sommeri.less4j.core.ast;
22

3-
import java.util.Collections;
43
import java.util.List;
54

65
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
@@ -11,15 +10,15 @@ public class NestedSelectorAppender extends SelectorPart {
1110
private boolean directlyBefore;
1211
private boolean directlyAfter;
1312

14-
public NestedSelectorAppender(HiddenTokenAwareTree underlyingStructure, boolean directlyBefore, boolean directlyAfter) {
15-
super(underlyingStructure);
13+
public NestedSelectorAppender(HiddenTokenAwareTree underlyingStructure, boolean directlyBefore, boolean directlyAfter, SelectorCombinator leadingCombinator) {
14+
super(underlyingStructure, leadingCombinator);
1615
this.directlyBefore = directlyBefore;
1716
this.directlyAfter = directlyAfter;
1817
}
1918

2019
@Override
21-
public List<? extends ASTCssNode> getChilds() {
22-
return Collections.emptyList();
20+
public List<ASTCssNode> getChilds() {
21+
return super.getChilds();
2322
}
2423

2524
public boolean isDirectlyBefore() {

src/main/java/com/github/sommeri/less4j/core/ast/Selector.java

+27-18
Original file line numberDiff line numberDiff line change
@@ -8,37 +8,30 @@
88

99
public class Selector extends ASTCssNode implements Cloneable {
1010

11-
private SelectorCombinator leadingCombinator;
1211
private SelectorPart head;
1312
private Selector right;
1413

1514
public Selector(HiddenTokenAwareTree token) {
1615
super(token);
1716
}
1817

19-
public Selector(HiddenTokenAwareTree token, SelectorCombinator leadingCombinator, SelectorPart head) {
20-
this(token, leadingCombinator, head, null);
18+
public Selector(HiddenTokenAwareTree token, SelectorPart head) {
19+
this(token, head, null);
2120
}
2221

23-
public Selector(HiddenTokenAwareTree token, SelectorCombinator leadingCombinator, SelectorPart head, Selector right) {
22+
public Selector(HiddenTokenAwareTree token, SelectorPart head, Selector right) {
2423
super(token);
25-
this.leadingCombinator = leadingCombinator;
2624
this.head = head;
2725
this.right = right;
2826
}
2927

30-
public boolean hasLeadingCombinator() {
31-
return leadingCombinator!=null;
32-
}
33-
34-
public SelectorCombinator getLeadingCombinator() {
35-
return leadingCombinator;
36-
}
28+
public boolean isExtending() {
29+
if (hasRight())
30+
return getRightestPart().isExtending();
3731

38-
public void setLeadingCombinator(SelectorCombinator leadingCombinator) {
39-
this.leadingCombinator = leadingCombinator;
32+
return head.isExtending();
4033
}
41-
34+
4235
public SelectorPart getHead() {
4336
return head;
4437
}
@@ -57,7 +50,7 @@ public void setRight(Selector right) {
5750

5851
@Override
5952
public List<? extends ASTCssNode> getChilds() {
60-
return ArraysUtils.asNonNullList((ASTCssNode)leadingCombinator, head, right);
53+
return ArraysUtils.asNonNullList(head, right);
6154
}
6255

6356
public ASTCssNodeType getType() {
@@ -67,7 +60,6 @@ public ASTCssNodeType getType() {
6760
@Override
6861
public Selector clone() {
6962
Selector clone = (Selector) super.clone();
70-
clone.setLeadingCombinator(getLeadingCombinator()==null? null : getLeadingCombinator().clone());
7163
clone.setHead(getHead().clone());
7264
clone.setRight(!hasRight()? null : getRight().clone());
7365
clone.configureParentToAllChilds();
@@ -94,7 +86,6 @@ public boolean isCombined() {
9486
public String toString() {
9587
StringBuilder builder = new StringBuilder();
9688
builder.append("Selector [");
97-
builder.append(leadingCombinator);
9889
builder.append(head);
9990
builder.append(" ");
10091
builder.append(right);
@@ -165,4 +156,22 @@ private List<ElementSubsequent> extractReusableNameParts() {
165156

166157
return result;
167158
}
159+
160+
//FIXME: (!!!!!) remove
161+
@Deprecated
162+
public void setLeadingCombinator(SelectorCombinator combinator) {
163+
head.setLeadingCombinator(combinator);
164+
}
165+
166+
//FIXME: (!!!!!) remove
167+
@Deprecated
168+
public SelectorCombinator getLeadingCombinator() {
169+
return head.getLeadingCombinator();
170+
}
171+
172+
//FIXME: (!!!!!) remove
173+
@Deprecated
174+
public boolean hasLeadingCombinator() {
175+
return head.hasLeadingCombinator();
176+
}
168177
}
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
package com.github.sommeri.less4j.core.ast;
22

3+
import java.util.List;
4+
35
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
6+
import com.github.sommeri.less4j.utils.ArraysUtils;
47

58
public abstract class SelectorPart extends ASTCssNode {
69

7-
public SelectorPart(HiddenTokenAwareTree underlyingStructure) {
10+
private SelectorCombinator leadingCombinator;
11+
12+
public SelectorPart(HiddenTokenAwareTree underlyingStructure, SelectorCombinator leadingCombinator) {
813
super(underlyingStructure);
14+
this.leadingCombinator = leadingCombinator;
915
}
1016

11-
@Override
12-
public SelectorPart clone() {
13-
return (SelectorPart) super.clone();
17+
public SelectorCombinator getLeadingCombinator() {
18+
return leadingCombinator;
1419
}
1520

21+
public void setLeadingCombinator(SelectorCombinator leadingCombinator) {
22+
this.leadingCombinator = leadingCombinator;
23+
}
24+
25+
public boolean hasLeadingCombinator() {
26+
return leadingCombinator!=null;
27+
}
28+
1629
public boolean isClassesAndIdsOnlySelector() {
1730
return false;
1831
}
@@ -21,4 +34,20 @@ public boolean isAppender() {
2134
return false;
2235
}
2336

37+
public boolean isExtending() {
38+
return false;
39+
}
40+
41+
@Override
42+
public List<ASTCssNode> getChilds() {
43+
return ArraysUtils.asNonNullList((ASTCssNode)leadingCombinator);
44+
}
45+
46+
@Override
47+
public SelectorPart clone() {
48+
SelectorPart clone = (SelectorPart) super.clone();
49+
clone.setLeadingCombinator(getLeadingCombinator()==null? null : getLeadingCombinator().clone());
50+
return clone;
51+
}
52+
2453
}

0 commit comments

Comments
 (0)