Skip to content

Commit e82e30d

Browse files
committed
var support
1 parent 0ca410e commit e82e30d

File tree

2 files changed

+111
-39
lines changed

2 files changed

+111
-39
lines changed

src/main/javacc/CSS3Parser.jj

+41-9
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ TOKEN_MGR_DECLS :
171171

172172
// ident -?{nmstart}{nmchar}*
173173
// {ident} {return IDENT;}
174-
| < IDENT: ("-")? <NMSTART> ( <NMCHAR> )* >
174+
| < IDENT: (< MINUS >)? <NMSTART> ( <NMCHAR> )* >
175175

176176
// name {nmchar}+
177177
| < #NAME: ( <NMCHAR> )+ >
@@ -312,7 +312,7 @@ TOKEN_MGR_DECLS :
312312
| < MEDIA_SYM: "@" <M_LETTER> <E_LETTER> <D_LETTER> <I_LETTER> <A_LETTER> >
313313

314314
// "@{F}{O}{N}{T}-{F}{A}{C}{E}" {return FONT_FACE_SYM;}
315-
| < FONT_FACE_SYM: "@" <F_LETTER> <O_LETTER> <N_LETTER> <T_LETTER> "-" <F_LETTER> <A_LETTER> <C_LETTER> <E_LETTER> >
315+
| < FONT_FACE_SYM: "@" <F_LETTER> <O_LETTER> <N_LETTER> <T_LETTER> < MINUS > <F_LETTER> <A_LETTER> <C_LETTER> <E_LETTER> >
316316

317317
// @{C}{H}{A}{R}{S}{E}{T} {return CHARSET_SYM;}
318318
| < CHARSET_SYM: "@" <C_LETTER> <H_LETTER> <A_LETTER> <R_LETTER> <S_LETTER> <E_LETTER> <T_LETTER> >
@@ -381,21 +381,26 @@ TOKEN_MGR_DECLS :
381381
| < DIMENSION: <NUM> <IDENT> >
382382

383383
| < #H_PLACEHOLDER: (<H> | "?"){1,6} >
384-
| < UNICODE_RANGE: "u+" <H_PLACEHOLDER > ("-" < H_PLACEHOLDER >)? >
384+
| < UNICODE_RANGE: "u+" <H_PLACEHOLDER > (< MINUS > < H_PLACEHOLDER >)? >
385385

386386
// "url("{w}{string}{w}")" {return URI;}
387387
// "url("{w}{url}{w}")" {return URI;}
388388
| < URI: "url" <LROUND> ( <S> )* ( <STRING> | <URL> ) ( <S> )* <RROUND> > { matchedToken.image = ParserUtils.trimUrl(image); }
389389

390390
// {N}{O}{T} "(" {return FUNCTION_NOT;}
391-
| < FUNCTION_NOT: <N_LETTER> <O_LETTER> <T_LETTER> <LROUND> >
391+
| < FUNCTION_NOT: "not" <LROUND> >
392392

393393
// {L}{A}{N}{G} "(" {return FUNCTION_LANG;}
394-
| < FUNCTION_LANG: <L_LETTER> <A_LETTER> <N_LETTER> <G_LETTER> <LROUND> >
394+
| < FUNCTION_LANG: "lang" <LROUND> >
395395

396396
// {C}{A}{L}{C} "(" {return FUNCTION_CALC;}
397397
| < FUNCTION_CALC: "calc" <LROUND> >
398398

399+
// {V}{A}{R} "(" {return FUNCTION_VAR;}
400+
| < FUNCTION_VAR: "var" <LROUND> >
401+
402+
| < CUSTOM_PROPERTY_NAME: < MINUS > <MINUS > <NMSTART> ( <NMCHAR> )* >
403+
399404
// {ident} "(" {return FUNCTION;}
400405
| < FUNCTION: <IDENT> <LROUND> >
401406

@@ -481,7 +486,7 @@ void styleSheetRuleList() :
481486
getErrorHandler().warning(createSkipWarning("ignoringRule", cpe));
482487
}
483488

484-
if (!charsetProcessed) {
489+
if (!charsetProcessed) {
485490
if (t.kind == EOF) {
486491
return;
487492
}
@@ -859,7 +864,7 @@ void pageRule() :
859864
String pageSelectorList() :
860865
{
861866
String sel;
862-
LinkedList selectors = new LinkedList<String>();
867+
LinkedList selectors = new LinkedList<String>();
863868
}
864869
{
865870
sel = pageSelector() { selectors.add(sel); }
@@ -995,8 +1000,8 @@ String property() :
9951000
Token t;
9961001
}
9971002
{
998-
t = <IDENT> ( <S> )*
999-
{ return unescape(t.image, false); }
1003+
t = <IDENT> ( <S> )* { return unescape(t.image, false); }
1004+
| t = <CUSTOM_PROPERTY_NAME> ( <S> )* { return unescape(t.image, false); }
10001005
}
10011006

10021007
//
@@ -1575,6 +1580,7 @@ LexicalUnit term(LexicalUnit prev) :
15751580
| value = percentage(prev, op)
15761581
| value = function(prev)
15771582
| value = calc(prev)
1583+
| value = var(prev)
15781584
)
15791585
| t = <STRING> { value = LexicalUnitImpl.createString(prev, unescape(t.image, false)); }
15801586
| t = "progid:" { value = LexicalUnitImpl.createIdent(prev, skipUnit().trim()); }
@@ -1881,6 +1887,32 @@ LexicalUnit calcNumberValue(LexicalUnit prev) :
18811887
}
18821888
}
18831889

1890+
// var()
1891+
// https://developer.mozilla.org/en-US/docs/Web/CSS/var
1892+
// var( <custom-property-name> , <declaration-value>? )
1893+
//
1894+
LexicalUnit var(LexicalUnit prev) :
1895+
{
1896+
Token t;
1897+
LexicalUnit value, propertyName;
1898+
String funct = "";
1899+
}
1900+
{
1901+
t = <FUNCTION_VAR> { funct = unescape(t.image, false); }
1902+
( <S> )*
1903+
t = <CUSTOM_PROPERTY_NAME> { prev = LexicalUnitImpl.createIdent(prev, unescape(t.image, false)); propertyName = prev; }
1904+
( <S> )*
1905+
(
1906+
<COMMA> { prev = LexicalUnitImpl.createComma(prev); }
1907+
( <S> )*
1908+
prev = term(prev)
1909+
)*
1910+
<RROUND>
1911+
{
1912+
return functionInternal(prev, funct, propertyName);
1913+
}
1914+
}
1915+
18841916
//
18851917
// negation_arg
18861918
// : type_selector | universal | HASH | class | attrib | pseudo

src/test/java/com/gargoylesoftware/css/parser/CSS3ParserTest.java

+70-30
Original file line numberDiff line numberDiff line change
@@ -1212,40 +1212,80 @@ public void calcCalc() throws Exception {
12121212

12131213
@Test
12141214
public void calcExpressions() throws Exception {
1215-
calc("#c { top: calc() }", 1, 0, 0);
1215+
expression("h1 { top: calc() }", 1, 0, 0);
12161216

1217-
calc("#c { top: calc(14px) }");
1217+
expression("h1 { top: calc(14px) }");
12181218

1219-
calc("#c { top: calc(0.875em + 0.1875em) }");
1220-
calc("#c { top: calc(0.875em + -0.1875em) }");
1221-
calc("#c { top: calc(-0.875em + 0.1875em) }");
1222-
calc("#c { top: calc(0.875em - -0.1875em) }");
1219+
expression("h1 { top: calc(0.875em + 0.1875em) }");
1220+
expression("h1 { top: calc(0.875em + -0.1875em) }");
1221+
expression("h1 { top: calc(-0.875em + 0.1875em) }");
1222+
expression("h1 { top: calc(0.875em - -0.1875em) }");
12231223

1224-
calc("#c { top: calc(1px + 2px) }");
1225-
calc("#c { top: calc(((1px + 2px) + 3px) + 4px) }");
1224+
expression("h1 { top: calc(1px + 2px) }");
1225+
expression("h1 { top: calc(((1px + 2px) + 3px) + 4px) }");
12261226

1227-
calc("#c { top: calc(1px * 2px) }");
1228-
calc("#c { top: calc(((1px * 2px) * 3px) * 4px) }");
1227+
expression("h1 { top: calc(1px * 2px) }");
1228+
expression("h1 { top: calc(((1px * 2px) * 3px) * 4px) }");
12291229

1230-
calc("#c { top: calc(1px / 2px) }", 1, 0, 0);
1231-
calc("#c { top: calc(1px / (1 + 2px)) }", 1, 0, 0);
1232-
calc("#c { top: calc(1px / (1px + 2)) }", 1, 0, 0);
1233-
calc("#c { top: calc(1px / (1 + 2)) }");
1230+
expression("h1 { top: calc(1px / 2px) }", 1, 0, 0);
1231+
expression("h1 { top: calc(1px / (1 + 2px)) }", 1, 0, 0);
1232+
expression("h1 { top: calc(1px / (1px + 2)) }", 1, 0, 0);
1233+
expression("h1 { top: calc(1px / (1 + 2)) }");
12341234

1235-
calc("#c { top: calc(1px / calc(1 + 2) * (7em * 3)) }");
1235+
expression("h1 { top: calc(1px / calc(1 + 2) * (7em * 3)) }");
12361236

1237-
calc("#c { top: calc(14) }");
1238-
calc("#c { top: calc(14; }", 1, 0, 0);
1239-
calc("#c { top: calc(14 + (7)) }");
1240-
calc("#c { top: calc(14 + (7); }", 1, 0, 0);
1241-
calc("#c { top: calc(14 + (7 + 3) - 1) }");
1237+
expression("h1 { top: calc(14) }");
1238+
expression("h1 { top: calc(14; }", 1, 0, 0);
1239+
expression("h1 { top: calc(14 + (7)) }");
1240+
expression("h1 { top: calc(14 + (7); }", 1, 0, 0);
1241+
expression("h1 { top: calc(14 + (7 + 3) - 1) }");
12421242
}
12431243

1244-
private void calc(String cssText) throws Exception {
1245-
calc(cssText, 0, 0, 0);
1244+
public void varExpressions() throws Exception {
1245+
// test cases for successful parsing
1246+
expression("#v { --my-var: 3 }");
1247+
expression("#v { --my-var: 2px }");
1248+
expression("#v { --my-var: 10pt }");
1249+
expression("#v { --my-var: 11% }");
1250+
expression("#v { --my-var: rgb(255, 255, 255) }");
1251+
expression("#v { --my-var: rgba(255, 255, 255, 0) }");
1252+
expression("#v { --my-var: var(--test) }");
1253+
expression("#v { --my-var: \"test\" }");
1254+
expression("#v { --my-var: 3 }");
1255+
expression("#v { --my-var: 3; top: var(--my-var, 10) }");
1256+
expression("#v { --my-var: -2; top: var(--my-var, 10) }");
1257+
expression("#v { --my-var: -2; top: var(--my-var, 10, 11) }");
1258+
expression("#v { --my-var: -2; top: var(--my-var, 10, 11, 12, \"test\") }");
1259+
expression("#v { --my-var: -2; top: var(--my-var, 10, 11, 12, rgb(12, 24, 35)) }");
1260+
1261+
// special test cases with different expected result
1262+
expression("#v { --my-var: +11; top: var(--my-var, 10) }",
1263+
"#v { --my-var: 11; top: var(--my-var, 10) }");
1264+
expression("#v { --my-var: -2; top: var(--my-var, 10, 11, 12, 'test') }",
1265+
"#v { --my-var: -2; top: var(--my-var, 10, 11, 12, \"test\") }");
1266+
expression("#v { --my-var: 'test' }",
1267+
"#v { --my-var: \"test\" }");
1268+
1269+
// test cases for unsuccessful parsing
1270+
expression("#v { --my-var: var(test) }", 1, 0, 0);
1271+
expression("#v { --my-var: var() }", 1, 0, 0);
1272+
expression("#v { --my-var: var(-test) }", 1, 0, 0);
1273+
expression("#v { --my-var: var(---test) }", 1, 0, 0);
12461274
}
12471275

1248-
private void calc(String cssText, final int err, final int fatal, final int warn) throws Exception {
1276+
private void expression(String cssText) throws Exception {
1277+
expression(cssText, 0, 0, 0, cssText);
1278+
}
1279+
1280+
private void expression(String cssText, String expected) throws Exception {
1281+
expression(cssText, 0, 0, 0, expected);
1282+
}
1283+
1284+
private void expression(String cssText, final int err, final int fatal, final int warn) throws Exception {
1285+
expression(cssText, err, fatal, warn, cssText);
1286+
}
1287+
1288+
private void expression(String cssText, final int err, final int fatal, final int warn, String expected) throws Exception {
12491289
final CSSStyleSheetImpl sheet = parse(cssText, err, fatal, warn);
12501290

12511291
if (err == 0) {
@@ -1254,7 +1294,7 @@ private void calc(String cssText, final int err, final int fatal, final int warn
12541294
Assert.assertEquals(1, rules.getLength());
12551295

12561296
final CSSStyleRuleImpl rule = (CSSStyleRuleImpl) rules.getRules().get(0);
1257-
Assert.assertEquals("*" + cssText, rule.getCssText());
1297+
Assert.assertEquals(expected, rule.getCssText());
12581298
}
12591299
}
12601300

@@ -1488,13 +1528,13 @@ public void malformedDeclaration() throws Exception {
14881528
+ "<LENGTH_PX>, <LENGTH_CM>, <LENGTH_MM>, "
14891529
+ "<LENGTH_IN>, <LENGTH_PT>, <LENGTH_PC>, <ANGLE_DEG>, <ANGLE_RAD>, <ANGLE_GRAD>, <TIME_MS>, "
14901530
+ "<TIME_S>, <FREQ_HZ>, <FREQ_KHZ>, <RESOLUTION_DPI>, <RESOLUTION_DPCM>, <PERCENTAGE>, "
1491-
+ "<DIMENSION>, <UNICODE_RANGE>, <URI>, <FUNCTION_CALC>, <FUNCTION>, \"progid:\".)"
1531+
+ "<DIMENSION>, <UNICODE_RANGE>, <URI>, <FUNCTION_CALC>, <FUNCTION_VAR>, <FUNCTION>, \"progid:\".)"
14921532
+ " Error in expression. (Invalid token \";\". Was expecting one of: <S>, <NUMBER>, \"inherit\", "
14931533
+ "<IDENT>, <STRING>, \"-\", <PLUS>, <HASH>, <EMS>, <REM>, <EXS>, "
14941534
+ "<LENGTH_PX>, <LENGTH_CM>, <LENGTH_MM>, "
14951535
+ "<LENGTH_IN>, <LENGTH_PT>, <LENGTH_PC>, <ANGLE_DEG>, <ANGLE_RAD>, <ANGLE_GRAD>, <TIME_MS>, "
14961536
+ "<TIME_S>, <FREQ_HZ>, <FREQ_KHZ>, <RESOLUTION_DPI>, <RESOLUTION_DPCM>, <PERCENTAGE>, "
1497-
+ "<DIMENSION>, <UNICODE_RANGE>, <URI>, <FUNCTION_CALC>, <FUNCTION>, \"progid:\".)"
1537+
+ "<DIMENSION>, <UNICODE_RANGE>, <URI>, <FUNCTION_CALC>, <FUNCTION_VAR>, <FUNCTION>, \"progid:\".)"
14981538
+ " Error in declaration. (Invalid token \"{\". Was expecting one of: <S>, \":\".)"
14991539
+ " Error in style rule. (Invalid token \" \". Was expecting one of: <EOF>, \"}\", \";\".)"
15001540
+ " Error in declaration. (Invalid token \"{\". Was expecting one of: <S>, \":\".)";
@@ -1740,7 +1780,7 @@ public void unexpectedEndOfPageRule() throws Exception {
17401780

17411781
Assert.assertEquals(1, errorHandler.getErrorCount());
17421782
final String expected = "Error in @page rule. "
1743-
+ "(Invalid token \"<EOF>\". Was expecting one of: <S>, <IDENT>, \"}\", \";\", \"*\".)";
1783+
+ "(Invalid token \"<EOF>\". Was expecting one of: <S>, <IDENT>, \"}\", \";\", \"*\", <CUSTOM_PROPERTY_NAME>.)";
17441784
Assert.assertEquals(expected, errorHandler.getErrorMessage());
17451785
Assert.assertEquals("1", errorHandler.getErrorLines());
17461786
Assert.assertEquals("39", errorHandler.getErrorColumns());
@@ -1789,7 +1829,7 @@ public void unexpectedEndOfString() throws Exception {
17891829
+ "<LENGTH_PX>, <LENGTH_CM>, <LENGTH_MM>, "
17901830
+ "<LENGTH_IN>, <LENGTH_PT>, <LENGTH_PC>, <ANGLE_DEG>, <ANGLE_RAD>, <ANGLE_GRAD>, <TIME_MS>, "
17911831
+ "<TIME_S>, <FREQ_HZ>, <FREQ_KHZ>, <RESOLUTION_DPI>, <RESOLUTION_DPCM>, <PERCENTAGE>, "
1792-
+ "<DIMENSION>, <UNICODE_RANGE>, <URI>, <FUNCTION_CALC>, <FUNCTION>, \"progid:\".)";
1832+
+ "<DIMENSION>, <UNICODE_RANGE>, <URI>, <FUNCTION_CALC>, <FUNCTION_VAR>, <FUNCTION>, \"progid:\".)";
17931833
Assert.assertEquals(expected, errorHandler.getErrorMessage());
17941834
Assert.assertEquals("3", errorHandler.getErrorLines());
17951835
Assert.assertEquals("16", errorHandler.getErrorColumns());
@@ -3597,8 +3637,8 @@ public void realWorldBootstrap400() throws Exception {
35973637
+ "all and (min-width: 768px);"
35983638
+ "all and (min-width: 992px);"
35993639
+ "print;";
3600-
realWorld("realworld/bootstrap_4_0_0.css", 1033, 2442, media, 1, 1);
3601-
realWorld("realworld/bootstrap_4_0_0_min.css", 1033, 2442, media, 1, 1);
3640+
realWorld("realworld/bootstrap_4_0_0.css", 1033, 2470, media, 0, 0);
3641+
realWorld("realworld/bootstrap_4_0_0_min.css", 1033, 2470, media, 0, 0);
36023642
}
36033643

36043644
/**

0 commit comments

Comments
 (0)