#ifndef SASS_PRELEXER_H #define SASS_PRELEXER_H #include namespace Sass { namespace Prelexer { typedef int (*ctype_predicate)(int); typedef const char* (*prelexer)(const char*); // Match a single character literal. template const char* exactly(const char* src) { return *src == pre ? src + 1 : 0; } // Match a string constant. template const char* exactly(const char* src) { const char* pre = prefix; 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; } // Match a single character that satifies the supplied ctype predicate. template const char* class_char(const char* src) { return pred(*src) ? src + 1 : 0; } // Match a single character that is a member of the supplied class. template const char* class_char(const char* src) { const char* cc = char_class; while (*cc && *src != *cc) ++cc; return *cc ? src + 1 : 0; } // Match a sequence of characters that all satisfy the supplied ctype predicate. template const char* class_chars(const char* src) { const char* p = src; while (pred(*p)) ++p; return p == src ? 0 : p; } // Match a sequence of characters that are all members of the supplied class. template const char* class_chars(const char* src) { const char* p = src; while (class_char(p)) ++p; return p == src ? 0 : p; } // Match a sequence of characters up to the next newline. template const char* until(const char* src) { if (*src == '\n' && exactly(src)) return 0; while (*src && *src != '\n' && !exactly(src)) ++src; return ++src; } // Match a sequence of characters up to the next newline. template const char* to_endl(const char* src) { if (!(src = exactly(src))) return 0; while (*src && *src != '\n') ++src; return src; } // Match a sequence of characters delimited by the supplied chars. template const char* delimited_by(const char* src) { src = exactly(src); if (!src) return 0; const char* stop; while (1) { if (!*src) return 0; stop = exactly(src); if (stop && (!esc || *(src - 1) != '\\')) return stop; src = stop ? stop : src + 1; } } // skip to delimiter (mx) inside given range // this will savely skip over all quoted strings // recursive skip stuff delimited by start/stop // first start/opener must be consumed already! template const char* skip_over_scopes(const char* src, const char* end = 0) { size_t level = 0; bool in_squote = false; bool in_dquote = false; // bool in_braces = false; while (*src) { // check for abort condition if (end && src >= end) break; // has escaped sequence? if (*src == '\\') { ++ src; // skip this (and next) } else if (*src == '"') { in_dquote = ! in_dquote; } else if (*src == '\'') { in_squote = ! in_squote; } else if (in_dquote || in_squote) { // take everything literally } // find another opener inside? else if (start(src)) { ++ level; // increase counter } // look for the closer (maybe final, maybe not) else if (const char* final = stop(src)) { // only close one level? if (level > 0) -- level; // return position at end of stop // delimiter may be multiple chars else return final; } // next ++ src; } return 0; } // Match a sequence of characters delimited by the supplied chars. template const char* recursive_scopes(const char* src) { // parse opener src = start(src); // abort if not found if (!src) return 0; // parse the rest until final closer return skip_over_scopes(src); } // Match a sequence of characters delimited by the supplied strings. template const char* delimited_by(const char* src) { src = exactly(src); if (!src) return 0; const char* stop; while (1) { if (!*src) return 0; stop = exactly(src); if (stop && (!esc || *(src - 1) != '\\')) return stop; src = stop ? stop : src + 1; } } // Match any single character. const char* any_char(const char* src); // Match any single character except the supplied one. template const char* any_char_except(const char* src) { return (*src && *src != c) ? src+1 : 0; } // Match word boundary (look ahead) const char* word_boundary(const char* src); // Matches zero characters (always succeeds without consuming input). // const char* epsilon(const char*); // Matches the empty string. // const char* empty(const char*); // Succeeds of the supplied matcher fails, and vice versa. template const char* negate(const char* src) { return mx(src) ? 0 : src; } // Tries to match a certain number of times (between the supplied interval). template const char* between(const char* src) { for (size_t i = 0; i < lo; ++i) { src = mx(src); if (!src) return 0; } for (size_t i = lo; i <= hi; ++i) { const char* new_src = mx(src); if (!new_src) return src; src = new_src; } return src; } // Tries the matchers in sequence and returns the first match (or none) template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)); return rslt; } // Same as above, but with 3 arguments. template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)); return rslt; } // Same as above, but with 4 arguments. template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)) || (rslt = mx4(src)); return rslt; } // Same as above, but with 5 arguments. template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)) || (rslt = mx4(src)) || (rslt = mx5(src)); return rslt; } // Same as above, but with 6 arguments. template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)) || (rslt = mx4(src)) || (rslt = mx5(src)) || (rslt = mx6(src)); return rslt; } // Same as above, but with 7 arguments. template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)) || (rslt = mx4(src)) || (rslt = mx5(src)) || (rslt = mx6(src)) || (rslt = mx7(src)); return rslt; } // Same as above, but with 8 arguments. template const char* alternatives(const char* src) { const char* rslt; (rslt = mx1(src)) || (rslt = mx2(src)) || (rslt = mx3(src)) || (rslt = mx4(src)) || (rslt = mx5(src)) || (rslt = mx6(src)) || (rslt = mx7(src)) || (rslt = mx8(src)); return rslt; } // Tries the matchers in sequence and succeeds if they all succeed. template const char* sequence(const char* src) { const char* rslt = src; (rslt = mx1(rslt)) && (rslt = mx2(rslt)); return rslt; } // Same as above, but with 3 arguments. template const char* sequence(const char* src) { const char* rslt = src; (rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt)); return rslt; } // Same as above, but with 4 arguments. template const char* sequence(const char* src) { const char* rslt = src; (rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt)) && (rslt = mx4(rslt)); return rslt; } // Same as above, but with 5 arguments. template const char* sequence(const char* src) { const char* rslt = src; (rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt)) && (rslt = mx4(rslt)) && (rslt = mx5(rslt)); return rslt; } // Same as above, but with 6 arguments. template const char* sequence(const char* src) { const char* rslt = src; (rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt)) && (rslt = mx4(rslt)) && (rslt = mx5(rslt)) && (rslt = mx6(rslt)); return rslt; } // Same as above, but with 7 arguments. template const char* sequence(const char* src) { const char* rslt = src; (rslt = mx1(rslt)) && (rslt = mx2(rslt)) && (rslt = mx3(rslt)) && (rslt = mx4(rslt)) && (rslt = mx5(rslt)) && (rslt = mx6(rslt)) && (rslt = mx7(rslt)); return rslt; } // Match a pattern or not. Always succeeds. template const char* optional(const char* src) { const char* p = mx(src); return p ? p : src; } // Match zero or more of the supplied pattern template const char* zero_plus(const char* src) { const char* p = mx(src); while (p) src = p, p = mx(src); return src; } // Match one or more of the supplied pattern template const char* one_plus(const char* src) { const char* p = mx(src); if (!p) return 0; while (p) src = p, p = mx(src); return src; } // Match a single character satisfying the ctype predicates. const char* space(const char* src); const char* alpha(const char* src); const char* digit(const char* src); const char* xdigit(const char* src); const char* alnum(const char* src); const char* punct(const char* src); // Match multiple ctype characters. const char* spaces(const char* src); const char* alphas(const char* src); const char* digits(const char* src); const char* xdigits(const char* src); const char* alnums(const char* src); const char* puncts(const char* src); // Match certain white-space charactes. const char* wspaces(const char* src); // const char* newline(const char* src); // const char* whitespace(const char* src); // Match a line comment. const char* line_comment(const char* src); const char* line_comment_prefix(const char* src); // Match a block comment. const char* block_comment(const char* src); const char* block_comment_prefix(const char* src); // Match either. const char* comment(const char* src); // Match double- and single-quoted strings. const char* double_quoted_string(const char* src); const char* single_quoted_string(const char* src); const char* quoted_string(const char* src); // Match interpolants. const char* interpolant(const char* src); // Match number prefix ([\+\-]+) const char* number_prefix(const char* src); // Whitespace handling. const char* optional_spaces(const char* src); // const char* optional_comment(const char* src); const char* optional_spaces_and_comments(const char* src); const char* spaces_and_comments(const char* src); const char* no_spaces(const char* src); const char* backslash_something(const char* src); // Match CSS css variables. const char* custom_property_name(const char* src); // Match a CSS identifier. const char* identifier(const char* src); const char* identifier_fragment(const char* src); // Match selector names. // const char* sel_ident(const char* src); // Match interpolant schemas const char* identifier_schema(const char* src); const char* value_schema(const char* src); const char* filename(const char* src); // const char* filename_schema(const char* src); // const char* url_schema(const char* src); // const char* url_value(const char* src); const char* vendor_prefix(const char* src); // Match CSS '@' keywords. const char* at_keyword(const char* src); const char* import(const char* src); const char* at_root(const char* src); const char* with_directive(const char* src); const char* without_directive(const char* src); const char* media(const char* src); const char* supports(const char* src); // const char* keyframes(const char* src); // const char* keyf(const char* src); const char* mixin(const char* src); const char* function(const char* src); const char* return_directive(const char* src); const char* include(const char* src); const char* content(const char* src); const char* extend(const char* src); const char* if_directive(const char* src); const char* else_directive(const char* src); const char* elseif_directive(const char* src); const char* for_directive(const char* src); const char* from(const char* src); const char* to(const char* src); const char* through(const char* src); const char* each_directive(const char* src); const char* in(const char* src); const char* while_directive(const char* src); const char* warn(const char* src); const char* err(const char* src); const char* dbg(const char* src); // const char* directive(const char* src); const char* at_keyword(const char* src); const char* null(const char* src); // Match CSS type selectors const char* namespace_prefix(const char* src); const char* type_selector(const char* src); const char* hyphens_and_identifier(const char* src); const char* hyphens_and_name(const char* src); const char* universal(const char* src); // Match CSS id names. const char* id_name(const char* src); // Match CSS class names. const char* class_name(const char* src); // Attribute name in an attribute selector const char* attribute_name(const char* src); // Match placeholder selectors. const char* placeholder(const char* src); // Match CSS numeric constants. const char* sign(const char* src); const char* unsigned_number(const char* src); const char* number(const char* src); const char* coefficient(const char* src); const char* binomial(const char* src); const char* percentage(const char* src); const char* dimension(const char* src); const char* hex(const char* src); const char* hexa(const char* src); const char* hex0(const char* src); // const char* rgb_prefix(const char* src); // Match CSS uri specifiers. const char* uri_prefix(const char* src); // const char* uri(const char* src); const char* url(const char* src); // Match CSS "!important" keyword. const char* important(const char* src); // Match CSS "!optional" keyword. const char* optional(const char* src); // Match Sass "!default" keyword. const char* default_flag(const char* src); const char* global_flag(const char* src); // Match CSS pseudo-class/element prefixes const char* pseudo_prefix(const char* src); // Match CSS function call openers. const char* functional(const char* src); const char* functional_schema(const char* src); const char* pseudo_not(const char* src); // Match CSS 'odd' and 'even' keywords for functional pseudo-classes. const char* even(const char* src); const char* odd(const char* src); // Match CSS attribute-matching operators. const char* exact_match(const char* src); const char* class_match(const char* src); const char* dash_match(const char* src); const char* prefix_match(const char* src); const char* suffix_match(const char* src); const char* substring_match(const char* src); // Match CSS combinators. // const char* adjacent_to(const char* src); // const char* precedes(const char* src); // const char* parent_of(const char* src); // const char* ancestor_of(const char* src); // Match SCSS variable names. const char* variable(const char* src); // Match Sass boolean keywords. const char* true_val(const char* src); const char* false_val(const char* src); const char* and_op(const char* src); const char* or_op(const char* src); const char* not_op(const char* src); const char* eq_op(const char* src); const char* neq_op(const char* src); const char* gt_op(const char* src); const char* gte_op(const char* src); const char* lt_op(const char* src); const char* lte_op(const char* src); // IE stuff const char* ie_progid(const char* src); const char* ie_expression(const char* src); const char* ie_property(const char* src); const char* ie_keyword_arg(const char* src); // match urls const char* url(const char* src); // Path matching functions. // const char* folder(const char* src); // const char* folders(const char* src); const char* static_string(const char* src); const char* static_component(const char* src); const char* static_value(const char* src); // Utility functions for finding and counting characters in a string. template const char* find_first(const char* src) { while (*src && *src != c) ++src; return *src ? src : 0; } template const char* find_first(const char* src) { while (*src && !mx(src)) ++src; return *src ? src : 0; } template const char* find_first_in_interval(const char* beg, const char* end) { bool esc = false; while ((beg < end) && *beg) { if (esc) esc = false; else if (*beg == '\\') esc = true; else if (mx(beg)) return beg; ++beg; } return 0; } template unsigned int count_interval(const char* beg, const char* end) { unsigned int counter = 0; bool esc = false; while (beg < end && *beg) { if (esc) esc = false; else if (*beg == '\\') esc = true; else if (*beg == c) ++counter; ++beg; } return counter; } template unsigned int count_interval(const char* beg, const char* end) { unsigned int counter = 0; bool esc = false; while (beg < end && *beg) { const char* p; if (esc) { esc = false; ++beg; } else if (*beg == '\\') { esc = true; ++beg; } else if ((p = mx(beg))) { ++counter; beg = p; } else { ++beg; } } return counter; } const char* chunk(const char* src); } } #endif