Skip to content

Commit df34c2f

Browse files
committed
Improve ie property and expression parsing
Fixes #1188 Fixes #1102
1 parent 25cf79f commit df34c2f

File tree

6 files changed

+51
-24
lines changed

6 files changed

+51
-24
lines changed

debugger.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,10 @@ inline void debug_ast(AST_Node* node, string ind = "", Env* env = 0)
452452
cerr << ind << "Map " << expression;
453453
cerr << " (" << pstate_source_position(node) << ")";
454454
cerr << " [Hashed]" << endl;
455+
// for (auto i : expression->elements()) {
456+
// debug_ast(i.first, ind + " key: ");
457+
// debug_ast(i.second, ind + " val: ");
458+
// }
455459
} else if (dynamic_cast<List*>(node)) {
456460
List* expression = dynamic_cast<List*>(node);
457461
cerr << ind << "List " << expression;

eval.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1018,8 +1018,7 @@ namespace Sass {
10181018
is_rest_argument = false;
10191019
is_keyword_argument = true;
10201020
}
1021-
else
1022-
if(val->concrete_type() != Expression::LIST) {
1021+
else if(val->concrete_type() != Expression::LIST) {
10231022
List* wrapper = new (ctx.mem) List(val->pstate(),
10241023
0,
10251024
List::COMMA,

parser.cpp

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1458,28 +1458,23 @@ namespace Sass {
14581458
Token str(lexed);
14591459
const char* i = str.begin;
14601460
// see if there any interpolants
1461-
const char* q;
14621461
const char* p = find_first_in_interval< exactly<hash_lbrace> >(str.begin, str.end);
14631462
if (!p) {
14641463
String_Constant* str_node = new (ctx.mem) String_Constant(pstate, normalize_wspace(string(str.begin, str.end)));
14651464
str_node->is_delayed(true);
1465+
str_node->quote_mark('*');
14661466
return str_node;
14671467
}
14681468

14691469
String_Schema* schema = new (ctx.mem) String_Schema(pstate);
14701470
while (i < str.end) {
1471-
q = find_first_in_interval< alternatives< exactly<'"'>, exactly<'\''> > >(i, str.end);
14721471
p = find_first_in_interval< exactly<hash_lbrace> >(i, str.end);
1473-
if (q && (!p || p > q)) {
1474-
if (i < q) {
1475-
(*schema) << new (ctx.mem) String_Constant(pstate, string(i, q)); // accumulate the preceding segment if it's nonempty
1476-
}
1477-
(*schema) << new (ctx.mem) String_Constant(pstate, string(q, q+1)); // capture the quote mark separately
1478-
i = q+1;
1479-
}
1480-
else if (p) {
1472+
if (p) {
14811473
if (i < p) {
1482-
(*schema) << new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
1474+
String_Constant* part = new (ctx.mem) String_Constant(pstate, string(i, p)); // accumulate the preceding segment if it's nonempty
1475+
part->is_delayed(true);
1476+
part->quote_mark('*'); // avoid unquote in interpolation
1477+
(*schema) << part;
14831478
}
14841479
if (peek < sequence < optional_spaces, exactly<rbrace> > >(p+2)) { position = p+2;
14851480
css_error("Invalid CSS", " after ", ": expected expression (e.g. 1px, bold), was ");
@@ -1498,7 +1493,12 @@ namespace Sass {
14981493
}
14991494
}
15001495
else { // no interpolants left; add the last segment if nonempty
1501-
if (i < str.end) (*schema) << new (ctx.mem) String_Constant(pstate, string(i, str.end));
1496+
if (i < str.end) {
1497+
String_Constant* part = new (ctx.mem) String_Constant(pstate, string(i, str.end));
1498+
part->is_delayed(true);
1499+
part->quote_mark('*'); // avoid unquote in interpolation
1500+
(*schema) << part;
1501+
}
15021502
break;
15031503
}
15041504
}
@@ -1512,14 +1512,17 @@ namespace Sass {
15121512
*kwd_arg << new (ctx.mem) Variable(pstate, Util::normalize_underscores(lexed));
15131513
} else {
15141514
lex< alternatives< identifier_schema, identifier > >();
1515-
*kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
1515+
*kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
15161516
}
15171517
lex< exactly<'='> >();
1518-
*kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
1518+
*kwd_arg << new (ctx.mem) String_Constant(pstate, lexed);
15191519
if (peek< variable >()) *kwd_arg << parse_list();
15201520
else if (lex< number >()) *kwd_arg << new (ctx.mem) Textual(pstate, Textual::NUMBER, Util::normalize_decimals(lexed));
1521-
else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex > >()) {
1522-
*kwd_arg << new (ctx.mem) String_Quoted(pstate, lexed);
1521+
else if (lex< alternatives< identifier_schema, identifier, number, hexa, hex, quoted_string > >()) {
1522+
String_Constant* part = new (ctx.mem) String_Constant(pstate, lexed);
1523+
part->is_delayed(true);
1524+
part->quote_mark('*');
1525+
*kwd_arg << part;
15231526
}
15241527
return kwd_arg;
15251528
}

prelexer.cpp

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@ namespace Sass {
3434
{
3535
return sequence<
3636
zero_plus < space >,
37-
delimited_by<slash_star, star_slash, false> >(src);
37+
delimited_by<
38+
slash_star,
39+
star_slash,
40+
false
41+
>
42+
>(src);
3843
}
3944
/* not use anymore - remove?
4045
const char* block_comment_prefix(const char* src) {
@@ -606,7 +611,7 @@ namespace Sass {
606611
>(src);
607612
}
608613
const char* ie_expression(const char* src) {
609-
return sequence < word<expression_kwd>, delimited_by< '(', ')', true> >(src);
614+
return sequence < word<expression_kwd>, exactly<'('>, skip_over_scopes< exactly<'('>, exactly<')'> > >(src);
610615
}
611616
const char* ie_property(const char* src) {
612617
return alternatives < ie_expression, ie_progid >(src);

prelexer.hpp

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ namespace Sass {
5858
// recursive skip stuff delimited by start/stop
5959
// first start/opener must be consumed already!
6060
template<prelexer start, prelexer stop>
61-
const char* skip_over_scopes(const char* src, const char* end = 0) {
61+
const char* skip_over_scopes(const char* src, const char* end) {
6262

6363
size_t level = 0;
6464
bool in_squote = false;
@@ -85,8 +85,9 @@ namespace Sass {
8585
}
8686

8787
// find another opener inside?
88-
else if (start(src)) {
89-
++ level; // increase counter
88+
else if (const char* pos = start(src)) {
89+
++ level; // increase stack counter
90+
src = pos - 1; // advance position
9091
}
9192

9293
// look for the closer (maybe final, maybe not)
@@ -96,6 +97,8 @@ namespace Sass {
9697
// return position at end of stop
9798
// delimiter may be multiple chars
9899
else return final;
100+
// advance position
101+
src = final - 1;
99102
}
100103

101104
// next
@@ -105,6 +108,15 @@ namespace Sass {
105108
return 0;
106109
}
107110

111+
// skip to delimiter (mx) inside given range
112+
// this will savely skip over all quoted strings
113+
// recursive skip stuff delimited by start/stop
114+
// first start/opener must be consumed already!
115+
template<prelexer start, prelexer stop>
116+
const char* skip_over_scopes(const char* src) {
117+
return skip_over_scopes<start, stop>(src, 0);
118+
}
119+
108120
// Match a sequence of characters delimited by the supplied chars.
109121
template <prelexer start, prelexer stop>
110122
const char* recursive_scopes(const char* src) {

util.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -264,19 +264,23 @@ namespace Sass {
264264
bool esc = false;
265265
char inside_str = 0;
266266
string text = "";
267-
for(auto i : str) {
267+
for(const char& i : str) {
268268
if (!esc && i == '\\') {
269269
esc = true;
270+
ws = false;
270271
text += i;
271272
} else if (esc) {
272273
esc = false;
274+
ws = false;
273275
text += i;
274276
} else if (!inside_str && (i == '"' || i == '\'')) {
275277
inside_str = i;
278+
ws = false;
276279
text += i;
277280
} else if (inside_str) {
278281
if (i == inside_str)
279282
inside_str = false;
283+
ws = false;
280284
text += i;
281285
} else if (
282286
i == ' ' ||

0 commit comments

Comments
 (0)