Skip to content

Commit db3c5f9

Browse files
committed
parsed properly an+b, and the optional selectors list of all the :nth...() selectors
1 parent 5e4f7b3 commit db3c5f9

File tree

9 files changed

+585
-42
lines changed

9 files changed

+585
-42
lines changed

org/w3c/css/parser/CssSelectors.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,24 @@ public void setPseudoFun(ApplContext ac, String pseudo, CssExpression expression
288288
}
289289
}
290290

291+
public void setPseudoFun(ApplContext ac, String pseudo, CssExpression expression,
292+
ArrayList<CssSelectors> selector_list)
293+
throws InvalidParamException {
294+
295+
CssVersion version = ac.getCssVersion();
296+
String[] ps = PseudoFactory.getPseudoFunction(version);
297+
if (ps != null) {
298+
for (String s : ps) {
299+
if (pseudo.equals(s)) {
300+
addPseudoFunction(PseudoFactory.newPseudoFunction(pseudo, expression,
301+
selector_list, ac));
302+
return;
303+
}
304+
}
305+
throw new InvalidParamException("pseudo", ":" + pseudo, ac);
306+
}
307+
}
308+
291309

292310
public void addType(TypeSelector type) throws InvalidParamException {
293311
super.addType(type);

org/w3c/css/parser/analyzer/CssParser.jj

Lines changed: 79 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import org.w3c.css.util.InvalidParamException;
5959
import org.w3c.css.util.Util;
6060
import org.w3c.css.util.WarningParamException;
6161
import org.w3c.css.values.CssAngle;
62+
import org.w3c.css.values.CssANPlusB;
6263
import org.w3c.css.values.CssAttr;
6364
import org.w3c.css.values.CssBracket;
6465
import org.w3c.css.values.CssCalc;
@@ -671,6 +672,7 @@ TOKEN [IGNORE_CASE] :
671672
| < TIME : <NUM> ( "ms" | "s" ) >
672673
| < FREQ : <NUM> ( "Hz" | "kHz" ) >
673674
| < RESOLUTION : <NUM> ( "dpi" | "dpcm" | "dppx" | "x") >
675+
| < AN : <NUM> "n" >
674676
| < DIMEN_9 : <NUM> <NMSTART> ( <NMCHAR> )* "\\9" >
675677
| < DIMEN : <NUM> <NMSTART> ( <NMCHAR> )* >
676678
| < PERCENTAGE : <NUM> "%" >
@@ -763,21 +765,25 @@ TOKEN [IGNORE_CASE] :
763765
<DEFAULT>
764766
TOKEN [IGNORE_CASE] :
765767
{
766-
< FUNCTIONLANG : "lang(" >
767-
| <FUNCTIONDIR : "dir(" >
768-
| <FUNCTIONIS : "is(" >
769-
| <FUNCTIONWHERE : "where(" >
770-
| <FUNCTIONHAS : "has(" >
771-
| <FUNCTIONSLOTTED : "slotted(" >
772-
| <FUNCTIONHOST : "host(" >
773-
| <FUNCTIONHOSTCONTEXT : "host-context(" >
774-
| <FUNCTIONNOT : "not(" >
775-
| <FUNCTIONCALC : "calc(" | "-moz-calc(" | "-webkit-calc(" >
776-
| <FUNCTIONMIN : "min(" >
777-
| <FUNCTIONMAX : "max(" >
778-
| <FUNCTIONCLAMP : "clamp(" >
779-
| <FUNCTIONATTR : "attr(" >
780-
| <FUNCTIONVAR : "var(" >
768+
< FUNCTIONLANG : "lang(" >
769+
| <FUNCTIONDIR : "dir(" >
770+
| <FUNCTIONIS : "is(" >
771+
| <FUNCTIONWHERE : "where(" >
772+
| <FUNCTIONHAS : "has(" >
773+
| <FUNCTIONSLOTTED : "slotted(" >
774+
| <FUNCTIONHOST : "host(" >
775+
| <FUNCTIONHOSTCONTEXT : "host-context(" >
776+
| <FUNCTIONNTHCHILD : "nth-child(" >
777+
| <FUNCTIONNTHLASTCHILD : "nth-last-child(" >
778+
| <FUNCTIONNTHOFTYPE : "nth-of-type(" >
779+
| <FUNCTIONNTHLASTOFTYPE : "nth-last-of-type(" >
780+
| <FUNCTIONNOT : "not(" >
781+
| <FUNCTIONCALC : "calc(" | "-moz-calc(" | "-webkit-calc(" >
782+
| <FUNCTIONMIN : "min(" >
783+
| <FUNCTIONMAX : "max(" >
784+
| <FUNCTIONCLAMP : "clamp(" >
785+
| <FUNCTIONATTR : "attr(" >
786+
| <FUNCTIONVAR : "var(" >
781787
}
782788

783789
<DEFAULT>
@@ -1929,6 +1935,37 @@ char unaryOperator() :
19291935
| <PLUS> { return '+'; }
19301936
}
19311937

1938+
CssANPlusB anplusb() :
1939+
{
1940+
Token n = null;
1941+
Token b = null;
1942+
char op = ' ';
1943+
char pb = ' ';
1944+
CssANPlusB anpb = new CssANPlusB();
1945+
}
1946+
{
1947+
// odd/even/n-2/-n-3 ...
1948+
( n=ident() ( LOOKAHEAD(2) ( <S> )* ( ( pb=unaryOperator() ( <S> )* )? b=<NUMBER> ) )? ) {
1949+
anpb.set(n.image, pb, ((b != null) ? b.image : null), "An+B", ac);
1950+
return anpb;
1951+
}
1952+
// +/-num (so no N)
1953+
| LOOKAHEAD(2) ( ( op=unaryOperator() )? b=<NUMBER> ) {
1954+
anpb.set(""+op+b.image, ac);
1955+
return anpb;
1956+
}
1957+
// generic aN+b including aN and N+b where N is mandatory
1958+
| LOOKAHEAD(2) ( ( op=unaryOperator() )? n=<AN> ( LOOKAHEAD(2) ( <S> )* ( pb=unaryOperator() ( <S> )* )? ( b=<NUMBER> ) )? ) {
1959+
anpb.set(op, n.image, pb, b.image, "An+B", ac);
1960+
return anpb;
1961+
}
1962+
// DIMEN may match 2n- and possibly another number after
1963+
| ( ( op=unaryOperator() )? n=<DIMEN> ( LOOKAHEAD(2) ( <S> )* b=<NUMBER> )? ) {
1964+
anpb.set(op, n.image, ((b != null) ? b.image : null), "An+B", ac);
1965+
return anpb;
1966+
}
1967+
}
1968+
19321969
/**
19331970
* @exception ParseException exception during the parse
19341971
*/
@@ -2251,7 +2288,7 @@ CssSelectors complex_selector(CssSelectors sel) :
22512288
{
22522289
try {
22532290
current=compound_selector(sel)
2254-
( ( comb=combinator() {
2291+
( LOOKAHEAD(2) ( comb=combinator() {
22552292
if ((ac.getCssProfile() == CssProfile.MOBILE) ||
22562293
getAtRule().toString().equals("@media atsc-tv") ||
22572294
(ac.getCssVersion() == CssVersion.CSS1)) {
@@ -2669,13 +2706,17 @@ void pseudo(CssSelectors s) :
26692706
* @exception ParseException exception during the parse
26702707
*/
26712708
void pseudo_class_selector(CssSelectors s) :
2672-
{Token n;
2709+
{
2710+
Token n;
2711+
Token id = null;
26732712
Token language = null;
26742713
CssExpression param = null;
26752714
ArrayList<CssSelectors> selector_list = null;
26762715
CssSelectors sel = null;
26772716
String error_str = null;
2717+
String prefix = null;
26782718
CssExpression exp = new CssExpression();
2719+
CssANPlusB anpb = null;
26792720
}
26802721
{
26812722
<COLON> ( ( n=ident()
@@ -2699,7 +2740,7 @@ CssExpression exp = new CssExpression();
26992740
getBeginColumn(), getEndLine(), getEndColumn(), e));
27002741
}
27012742
}
2702-
| ( ( n=<FUNCTIONIS> | n=<FUNCTIONNOT> ) ( <S> )* selector_list=selector_list() ) {
2743+
| ( ( n=<FUNCTIONIS> | n=<FUNCTIONNOT> ) ( <S> )* selector_list=selector_list() ( <S> )* ) {
27032744
try {
27042745
s.setPseudoFun(ac, convertStringIndex(n.image, 0, n.image.length() -1, false).toLowerCase(), selector_list);
27052746
} catch(InvalidParamException e) {
@@ -2708,7 +2749,7 @@ CssExpression exp = new CssExpression();
27082749
getBeginColumn(), getEndLine(), getEndColumn(), e));
27092750
}
27102751
} // we must be more forgiving for :where()
2711-
| ( n=<FUNCTIONWHERE> ( <S> )* try { selector_list=selector_list() } catch (ParseException ignored) {
2752+
| ( n=<FUNCTIONWHERE> ( <S> )* try { selector_list=selector_list() ( <S> )* } catch (ParseException ignored) {
27122753
s.setPseudoFun(ac, convertStringIndex(n.image, 0, n.image.length() -1, false).toLowerCase(),
27132754
skip_to_matching_paren());
27142755
}
@@ -2722,7 +2763,7 @@ CssExpression exp = new CssExpression();
27222763
getBeginColumn(), getEndLine(), getEndColumn(), e));
27232764
}
27242765
}
2725-
| ( n=<FUNCTIONHAS> selector_list=relative_selector_list() ) {
2766+
| ( n=<FUNCTIONHAS> selector_list=relative_selector_list() ( <S> )* ) {
27262767
try {
27272768
s.setPseudoFun(ac, convertStringIndex(n.image, 0, n.image.length() -1, false).toLowerCase(), selector_list);
27282769
} catch(InvalidParamException e) {
@@ -2742,6 +2783,20 @@ CssExpression exp = new CssExpression();
27422783
getBeginColumn(), getEndLine(), getEndColumn(), e));
27432784
}
27442785
}
2786+
| ( ( n=<FUNCTIONNTHCHILD> | n=<FUNCTIONNTHLASTCHILD> | n=<FUNCTIONNTHOFTYPE> | n=<FUNCTIONNTHLASTOFTYPE> ) ( <S> )*
2787+
( ( anpb=anplusb() ( <S> )* ( id=ident() ( <S> )* selector_list=selector_list() ( <S> )* )? ) | error_str=skip_to_matching_paren() ) ) {
2788+
try {
2789+
exp.addValue(anpb);
2790+
if (id != null) {
2791+
setValue(new CssIdent(), exp, ' ', id, IDENT);
2792+
}
2793+
s.setPseudoFun(ac, convertStringIndex(n.image, 0, n.image.length() -1, false).toLowerCase(), exp, selector_list);
2794+
} catch(InvalidParamException e) {
2795+
removeThisRule();
2796+
ac.getFrame().addError(new CssError(getSourceFile(), getBeginLine(),
2797+
getBeginColumn(), getEndLine(), getEndColumn(), e));
2798+
}
2799+
}
27452800
| ( n=<FUNCTION> ( <S> )* param=expression() ) {
27462801
try {
27472802
s.setPseudoFun(ac, convertStringIndex(n.image, 0, n.image.length() -1, false).toLowerCase(),
@@ -3795,6 +3850,10 @@ String skip_to_matching_paren() {
37953850
case FUNCTIONHOST:
37963851
case FUNCTIONHOSTCONTEXT:
37973852
case FUNCTIONSLOTTED:
3853+
case FUNCTIONNTHCHILD:
3854+
case FUNCTIONNTHLASTCHILD:
3855+
case FUNCTIONNTHOFTYPE:
3856+
case FUNCTIONNTHLASTOFTYPE:
37983857
case FUNCTIONNOT:
37993858
case FUNCTIONCALC:
38003859
case FUNCTIONMIN:

org/w3c/css/selectors/PseudoFactory.java

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -220,18 +220,6 @@ public static PseudoFunctionSelector newPseudoFunction(String name,
220220
if (name.equals("not")) {
221221
return new PseudoFunctionNot(name, value);
222222
}
223-
if (name.equals("nth-child")) {
224-
return new PseudoFunctionNthChild(name, value);
225-
}
226-
if (name.equals("nth-last-child")) {
227-
return new PseudoFunctionNthLastChild(name, value);
228-
}
229-
if (name.equals("nth-of-type")) {
230-
return new PseudoFunctionNthOfType(name, value);
231-
}
232-
if (name.equals("nth-last-of-type")) {
233-
return new PseudoFunctionNthLastOfType(name, value);
234-
}
235223
if (name.equals("slotted")) {
236224
return new PseudoFunctionSlotted(name, value);
237225
}
@@ -295,4 +283,30 @@ public static PseudoFunctionSelector newPseudoFunction(String name,
295283
throw new InvalidParamException("pseudo",
296284
":" + name, ac);
297285
}
286+
287+
public static PseudoFunctionSelector newPseudoFunction(String name,
288+
CssExpression exp,
289+
ArrayList<CssSelectors> selector_list,
290+
291+
ApplContext ac)
292+
throws InvalidParamException {
293+
if (name == null) {
294+
throw new InvalidParamException("pseudo",
295+
"null pseudofunction", ac);
296+
}
297+
if (name.equals("nth-child")) {
298+
return new PseudoFunctionNthChild(name, exp, selector_list, ac);
299+
}
300+
if (name.equals("nth-last-child")) {
301+
return new PseudoFunctionNthLastChild(name, exp, selector_list, ac);
302+
}
303+
if (name.equals("nth-of-type")) {
304+
return new PseudoFunctionNthOfType(name, exp, selector_list, ac);
305+
}
306+
if (name.equals("nth-last-of-type")) {
307+
return new PseudoFunctionNthLastOfType(name, exp, selector_list, ac);
308+
}
309+
throw new InvalidParamException("pseudo",
310+
":" + name, ac);
311+
}
298312
}

org/w3c/css/selectors/pseudofunctions/PseudoFunctionNthChild.java

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,74 @@
44
// Please first read the full copyright statement in file COPYRIGHT.html
55
package org.w3c.css.selectors.pseudofunctions;
66

7+
import org.w3c.css.parser.CssSelectors;
78
import org.w3c.css.selectors.PseudoFunctionSelector;
9+
import org.w3c.css.util.ApplContext;
10+
import org.w3c.css.util.InvalidParamException;
11+
import org.w3c.css.values.CssANPlusB;
12+
import org.w3c.css.values.CssExpression;
13+
import org.w3c.css.values.CssIdent;
14+
import org.w3c.css.values.CssTypes;
15+
import org.w3c.css.values.CssValue;
16+
17+
import java.util.ArrayList;
818

919
/**
1020
* PseudoFunctionNthChild<br />
1121
* Created: Sep 2, 2005 4:22:54 PM<br />
1222
*/
1323
public class PseudoFunctionNthChild extends PseudoFunctionSelector {
1424

15-
public PseudoFunctionNthChild(String name, String value) {
25+
public static final CssIdent of = CssIdent.getIdent("of");
26+
27+
public PseudoFunctionNthChild(String name, CssExpression expression,
28+
ArrayList<CssSelectors> selector_list,
29+
ApplContext ac)
30+
throws InvalidParamException
31+
{
32+
CssANPlusB anpb = null;
33+
1634
setName(name);
17-
setParam(value);
35+
if (expression == null || expression.getCount() == 0) {
36+
throw new InvalidParamException("unrecognize", functionName(), ac);
37+
}
38+
CssValue val = expression.getValue();
39+
if (val.getType() != CssTypes.CSS_ANPLUSB) {
40+
throw new InvalidParamException("value", val.toString(), functionName(), ac);
41+
}
42+
anpb = (CssANPlusB) val;
43+
expression.next();
44+
45+
// no ident and selectors_list non-empty? -> fail
46+
if (expression.end() && selector_list != null) {
47+
throw new InvalidParamException("value", CssSelectors.toArrayString(selector_list),
48+
functionName(), ac);
49+
}
50+
if (!expression.end()) {
51+
val = expression.getValue();
52+
if (val.getRawType() != CssTypes.CSS_IDENT) {
53+
throw new InvalidParamException("value", val.toString(), functionName(), ac);
54+
}
55+
// waiting for "of"
56+
if (!of.equals(val.getIdent())) {
57+
throw new InvalidParamException("value", val.toString(), functionName(), ac);
58+
}
59+
expression.next();
60+
// nothing more expected
61+
if (!expression.end()) {
62+
throw new InvalidParamException("value", expression.getValue().toString(), functionName(), ac);
63+
}
64+
}
65+
// now build the string representation
66+
if (selector_list == null) {
67+
setParam(anpb.toString());
68+
} else {
69+
StringBuilder sb = new StringBuilder();
70+
sb.append(anpb.toString()).append(" of ");
71+
sb.append(CssSelectors.toArrayString(selector_list));
72+
setParam(sb.toString());
73+
}
74+
1875
}
1976

2077
}

0 commit comments

Comments
 (0)