Skip to content

Commit

Permalink
Improve parsing of quoted string with interpolations
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Jan 24, 2015
1 parent a53e582 commit 84cfeda
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 73 deletions.
2 changes: 1 addition & 1 deletion error_handling.cpp
Expand Up @@ -13,7 +13,7 @@ namespace Sass {

void error(string msg, ParserState pstate, Backtrace* bt)
{
if (!pstate.path.empty() && Prelexer::string_constant(pstate.path.c_str()))
if (!pstate.path.empty() && Prelexer::quoted_string(pstate.path.c_str()))
pstate.path = pstate.path.substr(1, pstate.path.size() - 1);

Backtrace top(bt, pstate, "");
Expand Down
26 changes: 13 additions & 13 deletions parser.cpp
Expand Up @@ -108,7 +108,7 @@ namespace Sass {
}
// ignore the @charset directive for now
else if (lex< exactly< charset_kwd > >()) {
lex< string_constant >();
lex< quoted_string >();
lex< one_plus< exactly<';'> > >();
}
else if (peek< at_keyword >()) {
Expand Down Expand Up @@ -164,7 +164,7 @@ namespace Sass {
Import* imp = new (ctx.mem) Import(pstate);
bool first = true;
do {
if (lex< string_constant >()) {
if (lex< quoted_string >()) {
string import_path(lexed);

// struct Sass_Options opt = sass_context_get_options(ctx)
Expand Down Expand Up @@ -514,10 +514,10 @@ namespace Sass {
return seq;
}
}
if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal, string_constant, dimension, percentage, number > > >()) {
if (sawsomething && lex< sequence< negate< functional >, alternatives< identifier_fragment, universal, quoted_string, dimension, percentage, number > > >()) {
// saw an ampersand, then allow type selectors with arbitrary number of hyphens at the beginning
(*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
} else if (lex< sequence< negate< functional >, alternatives< type_selector, universal, string_constant, dimension, percentage, number > > >()) {
} else if (lex< sequence< negate< functional >, alternatives< type_selector, universal, quoted_string, dimension, percentage, number > > >()) {
// if you see a type selector
(*seq) << new (ctx.mem) Type_Selector(pstate, lexed);
sawsomething = true;
Expand Down Expand Up @@ -546,7 +546,7 @@ namespace Sass {
if (lex< id_name >() || lex< class_name >()) {
return new (ctx.mem) Selector_Qualifier(pstate, lexed);
}
else if (lex< string_constant >() || lex< number >()) {
else if (lex< quoted_string >() || lex< number >()) {
return new (ctx.mem) Type_Selector(pstate, lexed);
}
else if (peek< pseudo_not >()) {
Expand Down Expand Up @@ -619,7 +619,7 @@ namespace Sass {
lex< identifier >();
expr = new (ctx.mem) String_Constant(p, lexed);
}
else if (lex< string_constant >()) {
else if (lex< quoted_string >()) {
expr = new (ctx.mem) String_Constant(p, lexed);
}
else if (peek< exactly<')'> >()) {
Expand Down Expand Up @@ -661,7 +661,7 @@ namespace Sass {
if (lex< identifier >()) {
value = new (ctx.mem) String_Constant(p, lexed, true);
}
else if (lex< string_constant >()) {
else if (lex< quoted_string >()) {
value = parse_interpolated_chunk(lexed);
}
else {
Expand Down Expand Up @@ -795,7 +795,7 @@ namespace Sass {
}
// ignore the @charset directive for now
else if (lex< exactly< charset_kwd > >()) {
lex< string_constant >();
lex< quoted_string >();
lex< one_plus< exactly<';'> > >();
}
else if (peek< at_keyword >()) {
Expand Down Expand Up @@ -1209,7 +1209,7 @@ namespace Sass {
if (lex< number >())
{ return new (ctx.mem) Textual(pstate, Textual::NUMBER, lexed); }

if (peek< string_constant >())
if (peek< quoted_string >())
{ return parse_string(); }

if (lex< variable >())
Expand Down Expand Up @@ -1278,7 +1278,7 @@ namespace Sass {

String* Parser::parse_string()
{
lex< string_constant >();
lex< quoted_string >();
Token str(lexed);
return parse_interpolated_chunk(str);
// const char* i = str.begin;
Expand Down Expand Up @@ -1408,7 +1408,7 @@ namespace Sass {
else if (lex< hex >()) {
(*schema) << new (ctx.mem) Textual(pstate, Textual::HEX, lexed);
}
else if (lex< string_constant >()) {
else if (lex< quoted_string >()) {
(*schema) << new (ctx.mem) String_Constant(pstate, lexed);
if (!num_items) schema->quote_mark(*lexed.begin);
}
Expand Down Expand Up @@ -1875,7 +1875,7 @@ namespace Sass {
(q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
(q = peek< percentage >(p)) ||
(q = peek< dimension >(p)) ||
(q = peek< string_constant >(p)) ||
(q = peek< quoted_string >(p)) ||
(q = peek< exactly<'*'> >(p)) ||
(q = peek< exactly<'('> >(p)) ||
(q = peek< exactly<')'> >(p)) ||
Expand Down Expand Up @@ -1933,7 +1933,7 @@ namespace Sass {
(q = peek< sequence< pseudo_prefix, identifier > >(p)) ||
(q = peek< percentage >(p)) ||
(q = peek< dimension >(p)) ||
(q = peek< string_constant >(p)) ||
(q = peek< quoted_string >(p)) ||
(q = peek< exactly<'*'> >(p)) ||
(q = peek< exactly<'('> >(p)) ||
(q = peek< exactly<')'> >(p)) ||
Expand Down
125 changes: 68 additions & 57 deletions prelexer.cpp
Expand Up @@ -84,54 +84,6 @@ namespace Sass {
>(src);
}

// Match double- and single-quoted strings.
const char* double_quoted_string(const char* src) {
src = exactly<'"'>(src);
if (!src) return 0;
const char* p;
while (1) {
if (!*src) return 0;
if((p = escape(src))) {
src = p;
continue;
}
else if((p = exactly<'"'>(src))) {
return p;
}
else {
++src;
}
}
return 0;
}
const char* single_quoted_string(const char* src) {
src = exactly<'\''>(src);
if (!src) return 0;
const char* p;
while (1) {
if (!*src) return 0;
if((p = escape(src))) {
src = p;
continue;
}
else if((p = exactly<'\''>(src))) {
return p;
}
else {
++src;
}
}
return 0;
}
const char* string_constant(const char* src) {
return alternatives<double_quoted_string, single_quoted_string>(src);
}
// Match interpolants.


const char* interpolant(const char* src) {
return smartdel_by<hash_lbrace, rbrace, false>(src);
}

// Whitespace handling.
const char* optional_spaces(const char* src) { return optional<spaces>(src); }
Expand Down Expand Up @@ -188,11 +140,64 @@ namespace Sass {
zero_plus< alternatives< identifier, number, exactly<'-'> > > > >,
negate< exactly<'%'> > >(src);
}

// interpolants can be recursive/nested
const char* interpolant(const char* src) {
return smartdel_by<hash_lbrace, rbrace, false>(src);
}

// $re_squote = /'(?:$re_itplnt|\\.|[^'])*'/
const char* single_quoted_string(const char* src) {
// match a single quoted string, while skipping interpolants
return sequence <
exactly <'\''>,
zero_plus <
alternatives <
// skip all escaped chars first
sequence < exactly < '\\' >, any_char >,
// skip interpolants
interpolant,
// skip non delimiters
any_char_except < '\'' >
>
>,
exactly <'\''>
>(src);
}

// $re_dquote = /"(?:$re_itp|\\.|[^"])*"/
const char* double_quoted_string(const char* src) {
// match a single quoted string, while skipping interpolants
return sequence <
exactly <'"'>,
zero_plus <
alternatives <
// skip all escaped chars first
sequence < exactly < '\\' >, any_char >,
// skip interpolants
interpolant,
// skip non delimiters
any_char_except < '"' >
>
>,
exactly <'"'>
>(src);
}

// $re_quoted = /(?:$re_squote|$re_dquote)/
const char* quoted_string(const char* src) {
// match a quoted string, while skipping interpolants
return alternatives<
single_quoted_string,
double_quoted_string
>(src);
}

const char* value_schema(const char* src) {
// follows this pattern: ([xyz]*i[xyz]*)+
return one_plus< sequence< zero_plus< alternatives< identifier, percentage, dimension, hex, number, string_constant > >,
return one_plus< sequence< zero_plus< alternatives< identifier, percentage, dimension, hex, number, quoted_string > >,
interpolant,
zero_plus< alternatives< identifier, percentage, dimension, hex, number, string_constant, exactly<'%'> > > > >(src);
zero_plus< alternatives< identifier, percentage, dimension, hex, number, quoted_string, exactly<'%'> > > > >(src);
}
const char* filename_schema(const char* src) {
return one_plus< sequence< zero_plus< alternatives< identifier, number, exactly<'.'>, exactly<'/'> > >,
Expand Down Expand Up @@ -439,7 +444,7 @@ namespace Sass {
const char* uri(const char* src) {
return sequence< exactly<url_kwd>,
optional<spaces>,
string_constant,
quoted_string,
optional<spaces>,
exactly<')'> >(src);
}
Expand Down Expand Up @@ -577,7 +582,7 @@ namespace Sass {
spaces_and_comments,
exactly<'='>,
spaces_and_comments,
alternatives< variable, identifier_schema, identifier, string_constant, number, hexa >,
alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >,
zero_plus< sequence<
spaces_and_comments,
exactly<','>,
Expand All @@ -587,7 +592,7 @@ namespace Sass {
spaces_and_comments,
exactly<'='>,
spaces_and_comments,
alternatives< variable, identifier_schema, identifier, string_constant, number, hexa >
alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
>
> >
> >,
Expand All @@ -604,12 +609,18 @@ namespace Sass {
}

// const char* ie_args(const char* src) {
// return sequence< alternatives< ie_keyword_arg, value_schema, string_constant, interpolant, number, identifier, delimited_by< '(', ')', true> >,
// zero_plus< sequence< spaces_and_comments, exactly<','>, spaces_and_comments, alternatives< ie_keyword_arg, value_schema, string_constant, interpolant, number, identifier, delimited_by<'(', ')', true> > > > >(src);
// return sequence< alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by< '(', ')', true> >,
// zero_plus< sequence< spaces_and_comments, exactly<','>, spaces_and_comments, alternatives< ie_keyword_arg, value_schema, quoted_string, interpolant, number, identifier, delimited_by<'(', ')', true> > > > >(src);
// }

const char* ie_keyword_arg(const char* src) {
return sequence< alternatives< variable, identifier_schema, identifier >, spaces_and_comments, exactly<'='>, spaces_and_comments, alternatives< variable, identifier_schema, identifier, string_constant, number, hexa > >(src);
return sequence<
alternatives< variable, identifier_schema, identifier >,
spaces_and_comments,
exactly<'='>,
spaces_and_comments,
alternatives< variable, identifier_schema, identifier, quoted_string, number, hexa >
>(src);
}

// Path matching functions.
Expand Down Expand Up @@ -676,7 +687,7 @@ namespace Sass {

const char* static_string(const char* src) {
const char* pos = src;
const char * s = string_constant(pos);
const char * s = quoted_string(pos);
Token t(pos, s, Position(0, 0));
const unsigned int p = count_interval< interpolant >(t.begin, t.end);
return (p == 0) ? t.end : 0;
Expand Down
9 changes: 7 additions & 2 deletions prelexer.hpp
Expand Up @@ -19,7 +19,12 @@ namespace Sass {
template <const char* prefix>
const char* exactly(const char* src) {
const char* pre = prefix;
while (*pre && *src == *pre) ++src, ++pre;
if (*src == 0) return 0;
// there is a small chance that the search prefix
// is longer than the rest of the string to look at
while (*pre && *src == *pre) {
++src, ++pre;
}
return *pre ? 0 : src;
}

Expand Down Expand Up @@ -423,7 +428,7 @@ namespace Sass {
// Match double- and single-quoted strings.
const char* double_quoted_string(const char* src);
const char* single_quoted_string(const char* src);
const char* string_constant(const char* src);
const char* quoted_string(const char* src);
// Match interpolants.
const char* interpolant(const char* src);

Expand Down

0 comments on commit 84cfeda

Please sign in to comment.