#include <cctype>
#include <iostream>
#include "constants.hpp"
#include "prelexer.hpp"
namespace Sass {
using namespace Constants;
namespace Prelexer {
using std::cerr; using std::endl;
// Matches zero characters (always succeeds without consuming input).
const char* epsilon(char *src) {
return src;
}
// Matches the empty string.
const char* empty(char *src) {
return *src ? 0 : src;
}
// Match any single character.
const char* any_char(const char* src) { return *src ? src++ : src; }
// Match a single character satisfying the ctype predicates.
const char* space(const char* src) { return std::isspace(*src) ? src+1 : 0; }
const char* alpha(const char* src) { return std::isalpha(*src) ? src+1 : 0; }
const char* digit(const char* src) { return std::isdigit(*src) ? src+1 : 0; }
const char* xdigit(const char* src) { return std::isxdigit(*src) ? src+1 : 0; }
const char* alnum(const char* src) { return std::isalnum(*src) ? src+1 : 0; }
const char* punct(const char* src) { return std::ispunct(*src) ? src+1 : 0; }
// Match multiple ctype characters.
const char* spaces(const char* src) { return one_plus<space>(src); }
const char* alphas(const char* src) { return one_plus<alpha>(src); }
const char* digits(const char* src) { return one_plus<digit>(src); }
const char* xdigits(const char* src) { return one_plus<xdigit>(src); }
const char* alnums(const char* src) { return one_plus<alnum>(src); }
const char* puncts(const char* src) { return one_plus<punct>(src); }
// Match a line comment.
const char* line_comment(const char* src) { return to_endl<slash_slash>(src); }
// Match a block comment.
const char* block_comment(const char* src) {
return sequence< optional_spaces, delimited_by<slash_star, star_slash, false> >(src);
}
// Match either comment.
const char* comment(const char* src) {
return alternatives<block_comment, line_comment>(src);
}
// Match double- and single-quoted strings.
const char* double_quoted_string(const char* src) {
return delimited_by<'"', '"', true>(src);
}
const char* single_quoted_string(const char* src) {
return delimited_by<'\'', '\'', true>(src);
}
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 delimited_by<hash_lbrace, rbrace, false>(src);
}
// Whitespace handling.
const char* optional_spaces(const char* src) { return optional<spaces>(src); }
const char* optional_comment(const char* src) { return optional<comment>(src); }
const char* spaces_and_comments(const char* src) {
return zero_plus< alternatives<spaces, comment> >(src);
}
const char* no_spaces(const char* src) {
return negate< spaces >(src);
}
// Match CSS identifiers.
const char* identifier(const char* src) {
return sequence< optional< exactly<'-'> >,
alternatives< alpha, exactly<'_'> >,
zero_plus< alternatives< alnum,
exactly<'-'>,
exactly<'_'> > > >(src);
}
// Match interpolant schemas
const char* identifier_schema(const char* src) {
// follows this pattern: (x*ix*)+ ... well, not quite
return one_plus< sequence< zero_plus< alternatives< identifier, exactly<'-'> > >,
interpolant,
zero_plus< alternatives< identifier, number, exactly<'-'> > > > >(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 > >,
interpolant,
zero_plus< alternatives< identifier, percentage, dimension, hex, number, string_constant > > > >(src);
}
const char* filename_schema(const char* src) {
return one_plus< sequence< zero_plus< alternatives< identifier, number, exactly<'.'>, exactly<'/'> > >,
interpolant,
zero_plus< alternatives< identifier, number, exactly<'.'>, exactly<'/'> > > > >(src);
}
const char* filename(const char* src) {
return one_plus< alternatives< identifier, number, exactly<'.'> > >(src);
}
// Match CSS '@' keywords.
const char* at_keyword(const char* src) {
return sequence<exactly<'@'>, identifier>(src);
}
const char* import(const char* src) {
return exactly<import_kwd>(src);
}
const char* media(const char* src) {
return exactly<media_kwd>(src);
}
const char* keyframes(const char* src) {
return sequence< exactly<'@'>, optional< vendor_prefix >, exactly< keyframes_kwd > >(src);
}
const char* vendor_prefix(const char* src) {
return alternatives< exactly< vendor_opera_kwd >, exactly< vendor_webkit_kwd >, exactly< vendor_mozilla_kwd >, exactly< vendor_ms_kwd >, exactly< vendor_khtml_kwd > >(src);
}
const char* keyf(const char* src) {
return one_plus< alternatives< to, from, percentage > >(src);
}
const char* mixin(const char* src) {
return exactly<mixin_kwd>(src);
}
const char* function(const char* src) {
return exactly<function_kwd>(src);
}
const char* return_directive(const char* src) {
return exactly<return_kwd>(src);
}
const char* include(const char* src) {
return exactly<include_kwd>(src);
}
const char* content(const char* src) {
return exactly<content_kwd>(src);
}
const char* extend(const char* src) {
return exactly<extend_kwd>(src);
}
const char* if_directive(const char* src) {
return exactly<if_kwd>(src);
}
const char* else_directive(const char* src) {
return exactly<else_kwd>(src);
}
const char* elseif_directive(const char* src) {
return sequence< else_directive,
spaces_and_comments,
exactly< if_after_else_kwd > >(src);
}
const char* for_directive(const char* src) {
return exactly<for_kwd>(src);
}
const char* from(const char* src) {
return exactly<from_kwd>(src);
}
const char* to(const char* src) {
return exactly<to_kwd>(src);
}
const char* through(const char* src) {
return exactly<through_kwd>(src);
}
const char* each_directive(const char* src) {
return exactly<each_kwd>(src);
}
const char* in(const char* src) {
return exactly<in_kwd>(src);
}
const char* while_directive(const char* src) {
return exactly<while_kwd>(src);
}
const char* name(const char* src) {
return one_plus< alternatives< alnum,
exactly<'-'>,
exactly<'_'> > >(src);
}
const char* warn(const char* src) {
return exactly<warn_kwd>(src);
}
const char* directive(const char* src) {
return sequence< exactly<'@'>, identifier >(src);
}
// Match CSS type selectors
const char* namespace_prefix(const char* src) {
return sequence< optional< alternatives< identifier, exactly<'*'> > >,
exactly<'|'> >(src);
}
const char* type_selector(const char* src) {
return sequence< optional<namespace_prefix>, identifier>(src);
}
const char* universal(const char* src) {
return sequence< optional<namespace_prefix>, exactly<'*'> >(src);
}
// Match CSS id names.
const char* id_name(const char* src) {
return sequence<exactly<'#'>, name>(src);
}
// Match CSS class names.
const char* class_name(const char* src) {
return sequence<exactly<'.'>, identifier>(src);
}
// Match CSS numeric constants.
const char* sign(const char* src) {
return class_char<sign_chars>(src);
}
const char* unsigned_number(const char* src) {
return alternatives<sequence< zero_plus<digits>,
exactly<'.'>,
one_plus<digits> >,
digits>(src);
}
const char* number(const char* src) {
return sequence< optional<sign>, unsigned_number>(src);
}
const char* coefficient(const char* src) {
return alternatives< sequence< optional<sign>, digits >,
sign >(src);
}
const char* binomial(const char* src) {
return sequence< optional<sign>,
optional<digits>,
exactly<'n'>, optional_spaces,
sign, optional_spaces,
digits >(src);
}
const char* percentage(const char* src) {
return sequence< number, exactly<'%'> >(src);
}
const char* em(const char* src) {
return sequence< number, exactly<em_kwd> >(src);
}
const char* dimension(const char* src) {
return sequence<number, identifier>(src);
}
const char* hex(const char* src) {
const char* p = sequence< exactly<'#'>, one_plus<xdigit> >(src);
int len = p - src;
return (len != 4 && len != 7) ? 0 : p;
}
const char* rgb_prefix(const char* src) {
return exactly<rgb_kwd>(src);
}
// Match CSS uri specifiers.
const char* uri_prefix(const char* src) {
return exactly<url_kwd>(src);
}
// TODO: rename the following two functions
const char* uri(const char* src) {
return sequence< exactly<url_kwd>,
optional<spaces>,
string_constant,
optional<spaces>,
exactly<')'> >(src);
}
const char* url_value(const char* src) {
return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
one_plus< sequence< zero_plus< exactly<'/'> >, filename > >, // one or more folders and/or trailing filename
optional< exactly<'/'> > >(src);
}
const char* url_schema(const char* src) {
return sequence< optional< sequence< identifier, exactly<':'> > >, // optional protocol
filename_schema >(src); // optional trailing slash
}
// Match CSS "!important" keyword.
const char* important(const char* src) {
return sequence< exactly<'!'>,
spaces_and_comments,
exactly<important_kwd> >(src);
}
// Match Sass "!default" keyword.
const char* default_flag(const char* src) {
return sequence< exactly<'!'>,
spaces_and_comments,
exactly<default_kwd> >(src);
}
// Match CSS pseudo-class/element prefixes.
const char* pseudo_prefix(const char* src) {
return sequence< exactly<':'>, optional< exactly<':'> > >(src);
}
// Match CSS function call openers.
const char* functional(const char* src) {
return sequence< alternatives< identifier_schema, identifier >, exactly<'('> >(src);
}
// Match the CSS negation pseudo-class.
const char* pseudo_not(const char* src) {
return exactly< pseudo_not_kwd >(src);
}
// Match CSS 'odd' and 'even' keywords for functional pseudo-classes.
const char* even(const char* src) {
return exactly<even_kwd>(src);
}
const char* odd(const char* src) {
return exactly<odd_kwd>(src);
}
// Match CSS attribute-matching operators.
const char* exact_match(const char* src) { return exactly<'='>(src); }
const char* class_match(const char* src) { return exactly<tilde_equal>(src); }
const char* dash_match(const char* src) { return exactly<pipe_equal>(src); }
const char* prefix_match(const char* src) { return exactly<caret_equal>(src); }
const char* suffix_match(const char* src) { return exactly<dollar_equal>(src); }
const char* substring_match(const char* src) { return exactly<star_equal>(src); }
// Match CSS combinators.
const char* adjacent_to(const char* src) {
return sequence< optional_spaces, exactly<'+'> >(src);
}
const char* precedes(const char* src) {
return sequence< optional_spaces, exactly<'~'> >(src);
}
const char* parent_of(const char* src) {
return sequence< optional_spaces, exactly<'>'> >(src);
}
const char* ancestor_of(const char* src) {
return sequence< spaces, negate< exactly<'{'> > >(src);
}
// Match SCSS variable names.
const char* variable(const char* src) {
return sequence<exactly<'$'>, name>(src);
}
// Match Sass boolean keywords.
const char* true_val(const char* src) {
return exactly<true_kwd>(src);
}
const char* false_val(const char* src) {
return exactly<false_kwd>(src);
}
const char* and_op(const char* src) {
return exactly<and_kwd>(src);
}
const char* or_op(const char* src) {
return exactly<or_kwd>(src);
}
const char* not_op(const char* src) {
return exactly<not_kwd>(src);
}
const char* eq_op(const char* src) {
return exactly<eq>(src);
}
const char* neq_op(const char* src) {
return exactly<neq>(src);
}
const char* gt_op(const char* src) {
return exactly<gt>(src);
}
const char* gte_op(const char* src) {
return exactly<gte>(src);
}
const char* lt_op(const char* src) {
return exactly<lt>(src);
}
const char* lte_op(const char* src) {
return exactly<lte>(src);
}
// Path matching functions.
const char* folder(const char* src) {
return sequence< zero_plus< any_char_except<'/'> >,
exactly<'/'> >(src);
}
const char* folders(const char* src) {
return zero_plus< folder >(src);
}
const char* chunk(const char* src) {
char inside_str = 0;
const char* p = src;
size_t depth = 0;
while (true) {
if (!*p) {
return 0;
}
else if (!inside_str && (*p == '"' || *p == '\'')) {
inside_str = *p;
}
else if (*p == inside_str && *(p-1) != '\\') {
inside_str = 0;
}
else if (*p == '(' && !inside_str) {
++depth;
}
else if (*p == ')' && !inside_str) {
if (depth == 0) return p;
else --depth;
}
++p;
}
// unreachable
return 0;
}
}
}