1 #ifndef SASS_PRELEXER_H 2 #define SASS_PRELEXER_H 3 4 #include <cstring> 5 #include "lexer.hpp" 6 7 namespace Sass { 8 // using namespace Lexer; 9 namespace Prelexer { 10 11 //#################################### 12 // KEYWORD "REGEX" MATCHERS 13 //#################################### 14 15 // Match Sass boolean keywords. 16 const char* kwd_true(const char* src); 17 const char* kwd_false(const char* src); 18 const char* kwd_only(const char* src); 19 const char* kwd_and(const char* src); 20 const char* kwd_or(const char* src); 21 const char* kwd_not(const char* src); 22 const char* kwd_eq(const char* src); 23 const char* kwd_neq(const char* src); 24 const char* kwd_gt(const char* src); 25 const char* kwd_gte(const char* src); 26 const char* kwd_lt(const char* src); 27 const char* kwd_lte(const char* src); 28 const char* kwd_using(const char* src); 29 30 // Match standard control chars 31 const char* kwd_at(const char* src); 32 const char* kwd_dot(const char* src); 33 const char* kwd_comma(const char* src); 34 const char* kwd_colon(const char* src); 35 const char* kwd_slash(const char* src); 36 const char* kwd_star(const char* src); 37 const char* kwd_plus(const char* src); 38 const char* kwd_minus(const char* src); 39 40 //#################################### 41 // SPECIAL "REGEX" CONSTRUCTS 42 //#################################### 43 44 // Match a sequence of characters delimited by the supplied chars. 45 template <char beg, char end, bool esc> delimited_by(const char * src)46 const char* delimited_by(const char* src) { 47 src = exactly<beg>(src); 48 if (!src) return 0; 49 const char* stop; 50 while (true) { 51 if (!*src) return 0; 52 stop = exactly<end>(src); 53 if (stop && (!esc || *(src - 1) != '\\')) return stop; 54 src = stop ? stop : src + 1; 55 } 56 } 57 58 // skip to delimiter (mx) inside given range 59 // this will savely skip over all quoted strings 60 // recursive skip stuff delimited by start/stop 61 // first start/opener must be consumed already! 62 template<prelexer start, prelexer stop> skip_over_scopes(const char * src,const char * end)63 const char* skip_over_scopes(const char* src, const char* end) { 64 65 size_t level = 0; 66 bool in_squote = false; 67 bool in_dquote = false; 68 bool in_backslash_escape = false; 69 70 while ((end == nullptr || src < end) && *src != '\0') { 71 // has escaped sequence? 72 if (in_backslash_escape) { 73 in_backslash_escape = false; 74 } 75 else if (*src == '\\') { 76 in_backslash_escape = true; 77 } 78 else if (*src == '"') { 79 in_dquote = ! in_dquote; 80 } 81 else if (*src == '\'') { 82 in_squote = ! in_squote; 83 } 84 else if (in_dquote || in_squote) { 85 // take everything literally 86 } 87 88 // find another opener inside? 89 else if (const char* pos = start(src)) { 90 ++ level; // increase counter 91 src = pos - 1; // advance position 92 } 93 94 // look for the closer (maybe final, maybe not) 95 else if (const char* final = stop(src)) { 96 // only close one level? 97 if (level > 0) -- level; 98 // return position at end of stop 99 // delimiter may be multiple chars 100 else return final; 101 // advance position 102 src = final - 1; 103 } 104 105 // next 106 ++ src; 107 } 108 109 return 0; 110 } 111 112 // skip to a skip delimited by parentheses 113 // uses smart `skip_over_scopes` internally 114 const char* parenthese_scope(const char* src); 115 116 // skip to delimiter (mx) inside given range 117 // this will savely skip over all quoted strings 118 // recursive skip stuff delimited by start/stop 119 // first start/opener must be consumed already! 120 template<prelexer start, prelexer stop> skip_over_scopes(const char * src)121 const char* skip_over_scopes(const char* src) { 122 return skip_over_scopes<start, stop>(src, nullptr); 123 } 124 125 // Match a sequence of characters delimited by the supplied chars. 126 template <prelexer start, prelexer stop> recursive_scopes(const char * src)127 const char* recursive_scopes(const char* src) { 128 // parse opener 129 src = start(src); 130 // abort if not found 131 if (!src) return 0; 132 // parse the rest until final closer 133 return skip_over_scopes<start, stop>(src); 134 } 135 136 // Match a sequence of characters delimited by the supplied strings. 137 template <const char* beg, const char* end, bool esc> delimited_by(const char * src)138 const char* delimited_by(const char* src) { 139 src = exactly<beg>(src); 140 if (!src) return 0; 141 const char* stop; 142 while (true) { 143 if (!*src) return 0; 144 stop = exactly<end>(src); 145 if (stop && (!esc || *(src - 1) != '\\')) return stop; 146 src = stop ? stop : src + 1; 147 } 148 } 149 150 // Tries to match a certain number of times (between the supplied interval). 151 template<prelexer mx, size_t lo, size_t hi> between(const char * src)152 const char* between(const char* src) { 153 for (size_t i = 0; i < lo; ++i) { 154 src = mx(src); 155 if (!src) return 0; 156 } 157 for (size_t i = lo; i <= hi; ++i) { 158 const char* new_src = mx(src); 159 if (!new_src) return src; 160 src = new_src; 161 } 162 return src; 163 } 164 165 // equivalent of STRING_REGULAR_EXPRESSIONS 166 const char* re_string_double_open(const char* src); 167 const char* re_string_double_close(const char* src); 168 const char* re_string_single_open(const char* src); 169 const char* re_string_single_close(const char* src); 170 const char* re_string_uri_open(const char* src); 171 const char* re_string_uri_close(const char* src); 172 173 // Match a line comment. 174 const char* line_comment(const char* src); 175 176 // Match a block comment. 177 const char* block_comment(const char* src); 178 // Match either. 179 const char* comment(const char* src); 180 // Match double- and single-quoted strings. 181 const char* double_quoted_string(const char* src); 182 const char* single_quoted_string(const char* src); 183 const char* quoted_string(const char* src); 184 // Match interpolants. 185 const char* interpolant(const char* src); 186 // Match number prefix ([\+\-]+) 187 const char* number_prefix(const char* src); 188 189 // Match zero plus white-space or line_comments 190 const char* optional_css_whitespace(const char* src); 191 const char* css_whitespace(const char* src); 192 // Match optional_css_whitepace plus block_comments 193 const char* optional_css_comments(const char* src); 194 const char* css_comments(const char* src); 195 196 // Match one backslash escaped char 197 const char* escape_seq(const char* src); 198 199 // Match CSS css variables. 200 const char* custom_property_name(const char* src); 201 // Match a CSS identifier. 202 const char* identifier(const char* src); 203 const char* identifier_alpha(const char* src); 204 const char* identifier_alnum(const char* src); 205 const char* strict_identifier(const char* src); 206 const char* strict_identifier_alpha(const char* src); 207 const char* strict_identifier_alnum(const char* src); 208 // Match a CSS unit identifier. 209 const char* one_unit(const char* src); 210 const char* multiple_units(const char* src); 211 const char* unit_identifier(const char* src); 212 // const char* strict_identifier_alnums(const char* src); 213 // Match reference selector. 214 const char* re_reference_combinator(const char* src); 215 const char* static_reference_combinator(const char* src); 216 const char* schema_reference_combinator(const char* src); 217 218 // Match interpolant schemas 219 const char* identifier_schema(const char* src); 220 const char* value_schema(const char* src); 221 const char* sass_value(const char* src); 222 // const char* filename(const char* src); 223 // const char* filename_schema(const char* src); 224 // const char* url_schema(const char* src); 225 // const char* url_value(const char* src); 226 const char* vendor_prefix(const char* src); 227 228 const char* re_special_directive(const char* src); 229 const char* re_prefixed_directive(const char* src); 230 const char* re_almost_any_value_token(const char* src); 231 232 // Match CSS '@' keywords. 233 const char* at_keyword(const char* src); 234 const char* kwd_import(const char* src); 235 const char* kwd_at_root(const char* src); 236 const char* kwd_with_directive(const char* src); 237 const char* kwd_without_directive(const char* src); 238 const char* kwd_media(const char* src); 239 const char* kwd_supports_directive(const char* src); 240 // const char* keyframes(const char* src); 241 // const char* keyf(const char* src); 242 const char* kwd_mixin(const char* src); 243 const char* kwd_function(const char* src); 244 const char* kwd_return_directive(const char* src); 245 const char* kwd_include_directive(const char* src); 246 const char* kwd_content_directive(const char* src); 247 const char* kwd_charset_directive(const char* src); 248 const char* kwd_extend(const char* src); 249 250 const char* unicode_seq(const char* src); 251 252 const char* kwd_if_directive(const char* src); 253 const char* kwd_else_directive(const char* src); 254 const char* elseif_directive(const char* src); 255 256 const char* kwd_for_directive(const char* src); 257 const char* kwd_from(const char* src); 258 const char* kwd_to(const char* src); 259 const char* kwd_through(const char* src); 260 261 const char* kwd_each_directive(const char* src); 262 const char* kwd_in(const char* src); 263 264 const char* kwd_while_directive(const char* src); 265 266 const char* re_nothing(const char* src); 267 268 const char* re_special_fun(const char* src); 269 270 const char* kwd_warn(const char* src); 271 const char* kwd_err(const char* src); 272 const char* kwd_dbg(const char* src); 273 274 const char* kwd_null(const char* src); 275 276 const char* re_selector_list(const char* src); 277 const char* re_type_selector(const char* src); 278 const char* re_static_expression(const char* src); 279 280 // identifier that can start with hyphens 281 const char* css_identifier(const char* src); 282 const char* css_ip_identifier(const char* src); 283 284 // Match CSS type selectors 285 const char* namespace_schema(const char* src); 286 const char* namespace_prefix(const char* src); 287 const char* type_selector(const char* src); 288 const char* hyphens_and_identifier(const char* src); 289 const char* hyphens_and_name(const char* src); 290 const char* universal(const char* src); 291 // Match CSS id names. 292 const char* id_name(const char* src); 293 // Match CSS class names. 294 const char* class_name(const char* src); 295 // Attribute name in an attribute selector 296 const char* attribute_name(const char* src); 297 // Match placeholder selectors. 298 const char* placeholder(const char* src); 299 // Match CSS numeric constants. 300 const char* op(const char* src); 301 const char* sign(const char* src); 302 const char* unsigned_number(const char* src); 303 const char* number(const char* src); 304 const char* coefficient(const char* src); 305 const char* binomial(const char* src); 306 const char* percentage(const char* src); 307 const char* ampersand(const char* src); 308 const char* dimension(const char* src); 309 const char* hex(const char* src); 310 const char* hexa(const char* src); 311 const char* hex0(const char* src); 312 // const char* rgb_prefix(const char* src); 313 // Match CSS uri specifiers. 314 const char* uri_prefix(const char* src); 315 // Match CSS "!important" keyword. 316 const char* kwd_important(const char* src); 317 // Match CSS "!optional" keyword. 318 const char* kwd_optional(const char* src); 319 // Match Sass "!default" keyword. 320 const char* default_flag(const char* src); 321 const char* global_flag(const char* src); 322 // Match CSS pseudo-class/element prefixes 323 const char* pseudo_prefix(const char* src); 324 // Match CSS function call openers. 325 const char* re_functional(const char* src); 326 const char* re_pseudo_selector(const char* src); 327 const char* functional_schema(const char* src); 328 const char* pseudo_not(const char* src); 329 // Match CSS 'odd' and 'even' keywords for functional pseudo-classes. 330 const char* even(const char* src); 331 const char* odd(const char* src); 332 // Match CSS attribute-matching operators. 333 const char* exact_match(const char* src); 334 const char* class_match(const char* src); 335 const char* dash_match(const char* src); 336 const char* prefix_match(const char* src); 337 const char* suffix_match(const char* src); 338 const char* substring_match(const char* src); 339 // Match CSS combinators. 340 // const char* adjacent_to(const char* src); 341 // const char* precedes(const char* src); 342 // const char* parent_of(const char* src); 343 // const char* ancestor_of(const char* src); 344 345 // Match SCSS variable names. 346 const char* variable(const char* src); 347 const char* calc_fn_call(const char* src); 348 349 // IE stuff 350 const char* ie_progid(const char* src); 351 const char* ie_expression(const char* src); 352 const char* ie_property(const char* src); 353 const char* ie_keyword_arg(const char* src); 354 const char* ie_keyword_arg_value(const char* src); 355 const char* ie_keyword_arg_property(const char* src); 356 357 // characters that terminate parsing of a list 358 const char* list_terminator(const char* src); 359 const char* space_list_terminator(const char* src); 360 361 // match url() 362 const char* H(const char* src); 363 const char* W(const char* src); 364 // `UNICODE` makes VS sad 365 const char* UUNICODE(const char* src); 366 const char* NONASCII(const char* src); 367 const char* ESCAPE(const char* src); 368 const char* real_uri(const char* src); 369 const char* real_uri_suffix(const char* src); 370 // const char* real_uri_prefix(const char* src); 371 const char* real_uri_value(const char* src); 372 373 // Path matching functions. 374 // const char* folder(const char* src); 375 // const char* folders(const char* src); 376 377 378 const char* static_string(const char* src); 379 const char* static_component(const char* src); 380 const char* static_property(const char* src); 381 const char* static_value(const char* src); 382 383 const char* css_variable_value(const char* src); 384 const char* css_variable_top_level_value(const char* src); 385 386 // Utility functions for finding and counting characters in a string. 387 template<char c> find_first(const char * src)388 const char* find_first(const char* src) { 389 while (*src && *src != c) ++src; 390 return *src ? src : 0; 391 } 392 template<prelexer mx> find_first(const char * src)393 const char* find_first(const char* src) { 394 while (*src && !mx(src)) ++src; 395 return *src ? src : 0; 396 } 397 template<prelexer mx> find_first_in_interval(const char * beg,const char * end)398 const char* find_first_in_interval(const char* beg, const char* end) { 399 bool esc = false; 400 while ((beg < end) && *beg) { 401 if (esc) esc = false; 402 else if (*beg == '\\') esc = true; 403 else if (mx(beg)) return beg; 404 ++beg; 405 } 406 return 0; 407 } 408 template<prelexer mx, prelexer skip> find_first_in_interval(const char * beg,const char * end)409 const char* find_first_in_interval(const char* beg, const char* end) { 410 bool esc = false; 411 while ((beg < end) && *beg) { 412 if (esc) esc = false; 413 else if (*beg == '\\') esc = true; 414 else if (const char* pos = skip(beg)) beg = pos; 415 else if (mx(beg)) return beg; 416 ++beg; 417 } 418 return 0; 419 } 420 template <prelexer mx> count_interval(const char * beg,const char * end)421 unsigned int count_interval(const char* beg, const char* end) { 422 unsigned int counter = 0; 423 bool esc = false; 424 while (beg < end && *beg) { 425 const char* p; 426 if (esc) { 427 esc = false; 428 ++beg; 429 } else if (*beg == '\\') { 430 esc = true; 431 ++beg; 432 } else if ((p = mx(beg))) { 433 ++counter; 434 beg = p; 435 } 436 else { 437 ++beg; 438 } 439 } 440 return counter; 441 } 442 443 template <size_t size, prelexer mx, prelexer pad> padded_token(const char * src)444 const char* padded_token(const char* src) 445 { 446 size_t got = 0; 447 const char* pos = src; 448 while (got < size) { 449 if (!mx(pos)) break; 450 ++ pos; ++ got; 451 } 452 while (got < size) { 453 if (!pad(pos)) break; 454 ++ pos; ++ got; 455 } 456 return got ? pos : 0; 457 } 458 459 template <size_t min, size_t max, prelexer mx> minmax_range(const char * src)460 const char* minmax_range(const char* src) 461 { 462 size_t got = 0; 463 const char* pos = src; 464 while (got < max) { 465 if (!mx(pos)) break; 466 ++ pos; ++ got; 467 } 468 if (got < min) return 0; 469 if (got > max) return 0; 470 return pos; 471 } 472 473 template <char min, char max> char_range(const char * src)474 const char* char_range(const char* src) 475 { 476 if (*src < min) return 0; 477 if (*src > max) return 0; 478 return src + 1; 479 } 480 481 } 482 } 483 484 #endif 485