|
Packit Service |
7770af |
#ifndef SASS_LEXER_H
|
|
Packit Service |
7770af |
#define SASS_LEXER_H
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#include <cstring>
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
namespace Sass {
|
|
Packit Service |
7770af |
namespace Prelexer {
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
// BASIC CHARACTER MATCHERS
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match standard control chars
|
|
Packit Service |
7770af |
const char* kwd_at(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_dot(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_comma(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_colon(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_star(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_plus(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_minus(const char* src);
|
|
Packit Service |
7770af |
const char* kwd_slash(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
// BASIC CLASS MATCHERS
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// These are locale independant
|
|
Packit Service |
7770af |
bool is_space(const char& src);
|
|
Packit Service |
7770af |
bool is_alpha(const char& src);
|
|
Packit Service |
7770af |
bool is_punct(const char& src);
|
|
Packit Service |
7770af |
bool is_digit(const char& src);
|
|
Packit Service |
7770af |
bool is_alnum(const char& src);
|
|
Packit Service |
7770af |
bool is_xdigit(const char& src);
|
|
Packit Service |
7770af |
bool is_unicode(const char& src);
|
|
Packit Service |
7770af |
bool is_nonascii(const char& src);
|
|
Packit Service |
7770af |
bool is_character(const char& src);
|
|
Packit Service |
7770af |
bool is_uri_character(const char& src);
|
|
Packit Service |
7770af |
bool escapable_character(const char& src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match a single ctype predicate.
|
|
Packit Service |
7770af |
const char* space(const char* src);
|
|
Packit Service |
7770af |
const char* alpha(const char* src);
|
|
Packit Service |
7770af |
const char* digit(const char* src);
|
|
Packit Service |
7770af |
const char* xdigit(const char* src);
|
|
Packit Service |
7770af |
const char* alnum(const char* src);
|
|
Packit Service |
7770af |
const char* punct(const char* src);
|
|
Packit Service |
7770af |
const char* hyphen(const char* src);
|
|
Packit Service |
7770af |
const char* unicode(const char* src);
|
|
Packit Service |
7770af |
const char* nonascii(const char* src);
|
|
Packit Service |
7770af |
const char* character(const char* src);
|
|
Packit Service |
7770af |
const char* uri_character(const char* src);
|
|
Packit Service |
7770af |
const char* escapable_character(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match multiple ctype characters.
|
|
Packit Service |
7770af |
const char* spaces(const char* src);
|
|
Packit Service |
7770af |
const char* digits(const char* src);
|
|
Packit Service |
7770af |
const char* hyphens(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Whitespace handling.
|
|
Packit Service |
7770af |
const char* no_spaces(const char* src);
|
|
Packit Service |
7770af |
const char* optional_spaces(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match any single character (/./).
|
|
Packit Service |
7770af |
const char* any_char(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Assert word boundary (/\b/)
|
|
Packit Service |
7770af |
// Is a zero-width positive lookaheads
|
|
Packit Service |
7770af |
const char* word_boundary(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match a single linebreak (/(?:\n|\r\n?)/).
|
|
Packit Service |
7770af |
const char* re_linebreak(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Assert string boundaries (/\Z|\z|\A/)
|
|
Packit Service |
7770af |
// There are zero-width positive lookaheads
|
|
Packit Service |
7770af |
const char* end_of_line(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Assert end_of_file boundary (/\z/)
|
|
Packit Service |
7770af |
const char* end_of_file(const char* src);
|
|
Packit Service |
7770af |
// const char* start_of_string(const char* src);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Type definition for prelexer functions
|
|
Packit Service |
7770af |
typedef const char* (*prelexer)(const char*);
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
// BASIC "REGEX" CONSTRUCTORS
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match a single character literal.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:x)/
|
|
Packit Service |
7770af |
template <char chr>
|
|
Packit Service |
7770af |
const char* exactly(const char* src) {
|
|
Packit Service |
7770af |
return *src == chr ? src + 1 : 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match the full string literal.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:literal)/
|
|
Packit Service |
7770af |
template <const char* str>
|
|
Packit Service |
7770af |
const char* exactly(const char* src) {
|
|
Packit Service |
7770af |
if (str == NULL) return 0;
|
|
Packit Service |
7770af |
const char* pre = str;
|
|
Packit Service |
7770af |
if (src == NULL) return 0;
|
|
Packit Service |
7770af |
// there is a small chance that the search string
|
|
Packit Service |
7770af |
// is longer than the rest of the string to look at
|
|
Packit Service |
7770af |
while (*pre && *src == *pre) {
|
|
Packit Service |
7770af |
++src, ++pre;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// did the matcher finish?
|
|
Packit Service |
7770af |
return *pre == 0 ? src : 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match the full string literal.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:literal)/i
|
|
Packit Service |
7770af |
// only define lower case alpha chars
|
|
Packit Service |
7770af |
template <const char* str>
|
|
Packit Service |
7770af |
const char* insensitive(const char* src) {
|
|
Packit Service |
7770af |
if (str == NULL) return 0;
|
|
Packit Service |
7770af |
const char* pre = str;
|
|
Packit Service |
7770af |
if (src == NULL) return 0;
|
|
Packit Service |
7770af |
// there is a small chance that the search string
|
|
Packit Service |
7770af |
// is longer than the rest of the string to look at
|
|
Packit Service |
7770af |
while (*pre && (*src == *pre || *src+32 == *pre)) {
|
|
Packit Service |
7770af |
++src, ++pre;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
// did the matcher finish?
|
|
Packit Service |
7770af |
return *pre == 0 ? src : 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match for members of char class.
|
|
Packit Service |
7770af |
// Regex equivalent: /[axy]/
|
|
Packit Service |
7770af |
template <const char* char_class>
|
|
Packit Service |
7770af |
const char* class_char(const char* src) {
|
|
Packit Service |
7770af |
const char* cc = char_class;
|
|
Packit Service |
7770af |
while (*cc && *src != *cc) ++cc;
|
|
Packit Service |
7770af |
return *cc ? src + 1 : 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match for members of char class.
|
|
Packit Service |
7770af |
// Regex equivalent: /[axy]+/
|
|
Packit Service |
7770af |
template <const char* char_class>
|
|
Packit Service |
7770af |
const char* class_chars(const char* src) {
|
|
Packit Service |
7770af |
const char* p = src;
|
|
Packit Service |
7770af |
while (class_char<char_class>(p)) ++p;
|
|
Packit Service |
7770af |
return p == src ? 0 : p;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match for members of char class.
|
|
Packit Service |
7770af |
// Regex equivalent: /[^axy]/
|
|
Packit Service |
7770af |
template <const char* neg_char_class>
|
|
Packit Service |
7770af |
const char* neg_class_char(const char* src) {
|
|
Packit Service |
7770af |
if (*src == 0) return 0;
|
|
Packit Service |
7770af |
const char* cc = neg_char_class;
|
|
Packit Service |
7770af |
while (*cc && *src != *cc) ++cc;
|
|
Packit Service |
7770af |
return *cc ? 0 : src + 1;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match for members of char class.
|
|
Packit Service |
7770af |
// Regex equivalent: /[^axy]+/
|
|
Packit Service |
7770af |
template <const char* neg_char_class>
|
|
Packit Service |
7770af |
const char* neg_class_chars(const char* src) {
|
|
Packit Service |
7770af |
const char* p = src;
|
|
Packit Service |
7770af |
while (neg_class_char<neg_char_class>(p)) ++p;
|
|
Packit Service |
7770af |
return p == src ? 0 : p;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match all except the supplied one.
|
|
Packit Service |
7770af |
// Regex equivalent: /[^x]/
|
|
Packit Service |
7770af |
template <const char chr>
|
|
Packit Service |
7770af |
const char* any_char_but(const char* src) {
|
|
Packit Service |
7770af |
return (*src && *src != chr) ? src + 1 : 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Succeeds if the matcher fails.
|
|
Packit Service |
7770af |
// Aka. zero-width negative lookahead.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?!literal)/
|
|
Packit Service |
7770af |
template <prelexer mx>
|
|
Packit Service |
7770af |
const char* negate(const char* src) {
|
|
Packit Service |
7770af |
return mx(src) ? 0 : src;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Succeeds if the matcher succeeds.
|
|
Packit Service |
7770af |
// Aka. zero-width positive lookahead.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?=literal)/
|
|
Packit Service |
7770af |
// just hangs around until we need it
|
|
Packit Service |
7770af |
template <prelexer mx>
|
|
Packit Service |
7770af |
const char* lookahead(const char* src) {
|
|
Packit Service |
7770af |
return mx(src) ? src : 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Tries supplied matchers in order.
|
|
Packit Service |
7770af |
// Succeeds if one of them succeeds.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:FOO|BAR)/
|
|
Packit Service |
7770af |
template <const prelexer mx>
|
|
Packit Service |
7770af |
const char* alternatives(const char* src) {
|
|
Packit Service |
7770af |
const char* rslt;
|
|
Packit Service |
7770af |
if ((rslt = mx(src))) return rslt;
|
|
Packit Service |
7770af |
return 0;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
template <const prelexer mx1, const prelexer mx2, const prelexer... mxs>
|
|
Packit Service |
7770af |
const char* alternatives(const char* src) {
|
|
Packit Service |
7770af |
const char* rslt;
|
|
Packit Service |
7770af |
if ((rslt = mx1(src))) return rslt;
|
|
Packit Service |
7770af |
return alternatives<mx2, mxs...>(src);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Tries supplied matchers in order.
|
|
Packit Service |
7770af |
// Succeeds if all of them succeeds.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:FOO)(?:BAR)/
|
|
Packit Service |
7770af |
template <const prelexer mx1>
|
|
Packit Service |
7770af |
const char* sequence(const char* src) {
|
|
Packit Service |
7770af |
const char* rslt = src;
|
|
Packit Service |
7770af |
if (!(rslt = mx1(rslt))) return 0;
|
|
Packit Service |
7770af |
return rslt;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
template <const prelexer mx1, const prelexer mx2, const prelexer... mxs>
|
|
Packit Service |
7770af |
const char* sequence(const char* src) {
|
|
Packit Service |
7770af |
const char* rslt = src;
|
|
Packit Service |
7770af |
if (!(rslt = mx1(rslt))) return 0;
|
|
Packit Service |
7770af |
return sequence<mx2, mxs...>(rslt);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match a pattern or not. Always succeeds.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:literal)?/
|
|
Packit Service |
7770af |
template <prelexer mx>
|
|
Packit Service |
7770af |
const char* optional(const char* src) {
|
|
Packit Service |
7770af |
const char* p = mx(src);
|
|
Packit Service |
7770af |
return p ? p : src;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match zero or more of the patterns.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:literal)*/
|
|
Packit Service |
7770af |
template <prelexer mx>
|
|
Packit Service |
7770af |
const char* zero_plus(const char* src) {
|
|
Packit Service |
7770af |
const char* p = mx(src);
|
|
Packit Service |
7770af |
while (p) src = p, p = mx(src);
|
|
Packit Service |
7770af |
return src;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match one or more of the patterns.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:literal)+/
|
|
Packit Service |
7770af |
template <prelexer mx>
|
|
Packit Service |
7770af |
const char* one_plus(const char* src) {
|
|
Packit Service |
7770af |
const char* p = mx(src);
|
|
Packit Service |
7770af |
if (!p) return 0;
|
|
Packit Service |
7770af |
while (p) src = p, p = mx(src);
|
|
Packit Service |
7770af |
return src;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match mx non-greedy until delimiter.
|
|
Packit Service |
7770af |
// Other prelexers are greedy by default.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:$mx)*?(?=$delim)\b/
|
|
Packit Service |
7770af |
template <prelexer mx, prelexer delim>
|
|
Packit Service |
7770af |
const char* non_greedy(const char* src) {
|
|
Packit Service |
7770af |
while (!delim(src)) {
|
|
Packit Service |
7770af |
const char* p = mx(src);
|
|
Packit Service |
7770af |
if (p == src) return 0;
|
|
Packit Service |
7770af |
if (p == 0) return 0;
|
|
Packit Service |
7770af |
src = p;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
return src;
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
// ADVANCED "REGEX" CONSTRUCTORS
|
|
Packit Service |
7770af |
//####################################
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match with word boundary rule.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:$mx)\b/i
|
|
Packit Service |
7770af |
template <const char* str>
|
|
Packit Service |
7770af |
const char* keyword(const char* src) {
|
|
Packit Service |
7770af |
return sequence <
|
|
Packit Service |
7770af |
insensitive < str >,
|
|
Packit Service |
7770af |
word_boundary
|
|
Packit Service |
7770af |
>(src);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
// Match with word boundary rule.
|
|
Packit Service |
7770af |
// Regex equivalent: /(?:$mx)\b/
|
|
Packit Service |
7770af |
template <const char* str>
|
|
Packit Service |
7770af |
const char* word(const char* src) {
|
|
Packit Service |
7770af |
return sequence <
|
|
Packit Service |
7770af |
exactly < str >,
|
|
Packit Service |
7770af |
word_boundary
|
|
Packit Service |
7770af |
>(src);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
template <char chr>
|
|
Packit Service |
7770af |
const char* loosely(const char* src) {
|
|
Packit Service |
7770af |
return sequence <
|
|
Packit Service |
7770af |
optional_spaces,
|
|
Packit Service |
7770af |
exactly < chr >
|
|
Packit Service |
7770af |
>(src);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
template <const char* str>
|
|
Packit Service |
7770af |
const char* loosely(const char* src) {
|
|
Packit Service |
7770af |
return sequence <
|
|
Packit Service |
7770af |
optional_spaces,
|
|
Packit Service |
7770af |
exactly < str >
|
|
Packit Service |
7770af |
>(src);
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
}
|
|
Packit Service |
7770af |
|
|
Packit Service |
7770af |
#endif
|