Skip to content

Commit

Permalink
Media bubbling and mergin. Part of #42
Browse files Browse the repository at this point in the history
  • Loading branch information
meri committed Jan 24, 2013
1 parent c80f024 commit bf7faba
Show file tree
Hide file tree
Showing 46 changed files with 880 additions and 330 deletions.
54 changes: 36 additions & 18 deletions src/main/antlr3/com/github/sommeri/less4j/core/parser/Less.g
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ tokens {
styleSheet
@init {enterRule(retval, RULE_STYLESHEET);}
: ( a+=charSet* //the original ? was replaced by *, because it is possible (even if it makes no sense) and less.js is able to handle such situation
a+=bodylist
(a+=top_level_element)*
EOF ) -> ^(STYLE_SHEET ($a)*)
;
finally { leaveRule(); }
Expand Down Expand Up @@ -200,14 +200,22 @@ finally { leaveRule(); }
// Media can also have a ruleset in them.
//
//TODO media part of the grammar is throwing away tokens, so comments will not work correctly. fix that
media
media_queries_declaration:
m1+=mediaQuery (n+=COMMA m+=mediaQuery)*
-> ^(MEDIUM_DECLARATION $m1 ($n $m)*)
;

media_top_level
@init {enterRule(retval, RULE_MEDIA);}
: MEDIA_SYM m1+=media_queries_declaration b+=top_level_body_with_declaration
-> ^(MEDIA_SYM $m1* $b*)
;
finally { leaveRule(); }

media_in_general_body
@init {enterRule(retval, RULE_MEDIA);}
: MEDIA_SYM (m1+=mediaQuery (n+=COMMA m+=mediaQuery)*)
q1=LBRACE
((declaration) => b+=declaration SEMI
| b+=bodyset )*
q2=RBRACE
-> ^(MEDIA_SYM ^(MEDIUM_DECLARATION $m1 ($n $m)*) $q1 $b* $q2)
: MEDIA_SYM m1+=media_queries_declaration b+=general_body
-> ^(MEDIA_SYM $m1* $b*)
;
finally { leaveRule(); }

Expand Down Expand Up @@ -245,17 +253,13 @@ mediaFeature
: IDENT
;

bodylist
: bodyset*
;

bodyset
top_level_element
: (mixinReferenceWithSemi)=>mixinReferenceWithSemi
| (namespaceReferenceWithSemi)=>namespaceReferenceWithSemi
| (reusableStructureName LPAREN)=>reusableStructure
| (variabledeclaration)=>variabledeclaration
| ruleSet
| media
| media_top_level
| viewport
| keyframes
| page
Expand Down Expand Up @@ -289,10 +293,7 @@ finally { leaveRule(); }

fontface
@init {enterRule(retval, RULE_FONT_FACE);}
: FONT_FACE_SYM^
LBRACE!
declaration SEMI! (declaration SEMI!)*
RBRACE!
: FONT_FACE_SYM^ general_body
;
finally { leaveRule(); }

Expand Down Expand Up @@ -373,6 +374,22 @@ nestedAppender // this must be here because of special case & & <- the space bel
;

//css does not require ; in last declaration

top_level_body
: LBRACE
(a+=top_level_element)*
RBRACE
//If we remove LBRACE from the tree, a ruleset with an empty selector will report wrong line number in the warning.
-> ^(BODY LBRACE $a*);

top_level_body_with_declaration
: LBRACE
((declarationWithSemicolon)=> a+=declarationWithSemicolon
| a+=top_level_element)*
RBRACE
//If we remove LBRACE from the tree, a ruleset with an empty selector will report wrong line number in the warning.
-> ^(BODY LBRACE $a*);

general_body
: LBRACE
( ((declarationWithSemicolon)=> (a+=declarationWithSemicolon) )
Expand All @@ -382,6 +399,7 @@ general_body
| (reusableStructure)=>a+=reusableStructure
| a+=pageMarginBox
| a+=variabledeclaration
| a+=media_in_general_body
//| a+=imports
)*
(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
package com.github.sommeri.less4j.core.ast;

public enum ASTCssNodeType {
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, DECLARATIONS_BODY, SELECTOR_OPERATOR, SELECTOR_COMBINATOR, EXPRESSION_OPERATOR, NTH, NAMED_EXPRESSION, MEDIA_QUERY, 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, KEYFRAMES_BODY, REUSABLE_STRUCTURE_NAME, VIEWPORT, GENERAL_BODY, PAGE, NAME, PAGE_MA, PAGE_MARGIN_BOX, IMPORT, FAULTY_NODE, ANONYMOUS, EMPTY_EXPRESSION
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, 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, KEYFRAMES_BODY, REUSABLE_STRUCTURE_NAME, VIEWPORT, GENERAL_BODY, PAGE, NAME, PAGE_MA, PAGE_MARGIN_BOX, IMPORT, FAULTY_NODE, ANONYMOUS, EMPTY_EXPRESSION
}
81 changes: 54 additions & 27 deletions src/main/java/com/github/sommeri/less4j/core/ast/Body.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,114 +9,141 @@
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
import com.github.sommeri.less4j.utils.ArraysUtils;

public abstract class Body <T extends ASTCssNode> extends ASTCssNode {
public abstract class Body extends ASTCssNode {

private List<T> body = new ArrayList<T>();
private List<ASTCssNode> body = new ArrayList<ASTCssNode>();

public Body(HiddenTokenAwareTree underlyingStructure) {
super(underlyingStructure);
}

public Body(HiddenTokenAwareTree underlyingStructure, List<T> declarations) {
public Body(HiddenTokenAwareTree underlyingStructure, List<ASTCssNode> declarations) {
this(underlyingStructure);
body.addAll(declarations);
}

@Override
public List<T> getChilds() {
public List<ASTCssNode> getChilds() {
return body;
}

public List<T> getMembers() {
public List<ASTCssNode> getMembers() {
return body;
}

protected List<T> getBody() {
protected List<ASTCssNode> getBody() {
return body;
}

public boolean isEmpty() {
return body.isEmpty() && getOrphanComments().isEmpty();
}

public void addMembers(List<? extends T> members) {
public void removeAllMembers() {
body = new ArrayList<ASTCssNode>();
}

public void addMembers(List<ASTCssNode> members) {
body.addAll(members);
}

public void addMembersAfter(List<? extends T> nestedRulesets, ASTCssNode kid) {
public void addMembersAfter(List<? extends ASTCssNode> newMembers, ASTCssNode kid) {
int index = body.indexOf(kid);
if (index==-1)
index = body.size();
else
index++;

body.addAll(index, nestedRulesets);
body.addAll(index, newMembers);
}

public void addMemberAfter(ASTCssNode newMember, ASTCssNode kid) {
int index = body.indexOf(kid);
if (index==-1)
index = body.size();
else
index++;

}
body.add(index, newMember);

public void addMember(T member) {

}
public void addMember(ASTCssNode member) {
body.add(member);
}

public void replaceMember(T oldMember, List<T> newMembers) {
public void replaceMember(ASTCssNode oldMember, List<ASTCssNode> newMembers) {
body.addAll(body.indexOf(oldMember), newMembers);
body.remove(oldMember);
oldMember.setParent(null);
configureParentToAllChilds();
}

public void replaceMember(T oldMember, T newMember) {
public void replaceMember(ASTCssNode oldMember, ASTCssNode newMember) {
body.add(body.indexOf(oldMember), newMember);
body.remove(oldMember);
oldMember.setParent(null);
newMember.setParent(this);
}

public List<T> membersByType(ASTCssNodeType type) {
List<T> result = new ArrayList<T>();
List<T> body = getBody();
for (T node : body) {
public List<ASTCssNode> membersByType(ASTCssNodeType type) {
List<ASTCssNode> result = new ArrayList<ASTCssNode>();
List<ASTCssNode> body = getBody();
for (ASTCssNode node : body) {
if (node.getType()==type) {
result.add(node);
}
}
return result;
}

public List<T> membersByNotType(ASTCssNodeType type) {
List<T> result = new ArrayList<T>();
List<T> body = getBody();
for (T node : body) {
public List<ASTCssNode> membersByNotType(ASTCssNodeType type) {
List<ASTCssNode> result = new ArrayList<ASTCssNode>();
List<ASTCssNode> body = getBody();
for (ASTCssNode node : body) {
if (node.getType()!=type) {
result.add(node);
}
}
return result;
}

public boolean removeMember(T node) {
public boolean removeMember(ASTCssNode node) {
return body.remove(node);
}

public Set<ASTCssNodeType> getSupportedMembers() {
return new HashSet<ASTCssNodeType>(Arrays.asList(ASTCssNodeType.values()));
}

@SuppressWarnings("unchecked")
public Body<T> clone() {
Body<T> result = (Body<T>) super.clone();
public Body clone() {
Body result = (Body) super.clone();
result.body = ArraysUtils.deeplyClonedList(body);
result.configureParentToAllChilds();
return result;
}

public List<T> getDeclarations() {
public Body emptyClone() {
Body result = (Body) super.clone();
result.body = new ArrayList<ASTCssNode>();
return result;
}

public List<ASTCssNode> getDeclarations() {
return membersByType(ASTCssNodeType.DECLARATION);
}

public List<T> getNotDeclarations() {
public List<ASTCssNode> getNotDeclarations() {
return membersByNotType(ASTCssNodeType.DECLARATION);
}

@Override
public void setParent(ASTCssNode parent) {
if (parent!=null && !(parent instanceof BodyOwner))
throw new IllegalArgumentException("Body parent must be a BodyOwner: " + parent.getType());

super.setParent(parent);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.github.sommeri.less4j.core.ast;

public interface BodyOwner<T extends ASTCssNode> {

void setBody(T body);
T getBody();

}
18 changes: 15 additions & 3 deletions src/main/java/com/github/sommeri/less4j/core/ast/FontFace.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,27 @@
import java.util.List;

import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
import com.github.sommeri.less4j.utils.ArraysUtils;

public class FontFace extends Body<Declaration> {
public class FontFace extends ASTCssNode implements BodyOwner<GeneralBody> {

private GeneralBody body;

public FontFace(HiddenTokenAwareTree underlyingStructure) {
super(underlyingStructure);
}

public FontFace(HiddenTokenAwareTree underlyingStructure, List<Declaration> declarations) {
super(underlyingStructure, declarations);
public GeneralBody getBody() {
return body;
}

public void setBody(GeneralBody body) {
this.body = body;
}

@Override
public List<ASTCssNode> getChilds() {
return ArraysUtils.asNonNullList((ASTCssNode)body);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;

//FIXME: !validation! warning on viewport body with nested rulesets in output
public class GeneralBody extends Body<ASTCssNode> {
public class GeneralBody extends Body {

public GeneralBody(HiddenTokenAwareTree underlyingStructure) {
super(underlyingStructure);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;
import com.github.sommeri.less4j.utils.ArraysUtils;

public class Keyframes extends ASTCssNode {
public class Keyframes extends ASTCssNode implements BodyOwner<KeyframesBody> {

private String dialect;
private List<KeyframesName> names = new ArrayList<KeyframesName>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import com.github.sommeri.less4j.core.parser.HiddenTokenAwareTree;

public class KeyframesBody extends Body<ASTCssNode> {
public class KeyframesBody extends Body {

private static final Set<ASTCssNodeType> SUPPORTED_MEMBERS = new HashSet<ASTCssNodeType>();

Expand Down
Loading

0 comments on commit bf7faba

Please sign in to comment.