49#include <snapdev/poison.h>
120 f_paths.push_back(path);
131 f_parents.push_back(parent);
136 f_parents.pop_back();
141 return f_parents.empty();
146 if(f_parents.size() < 2)
148 throw csspp_exception_logic(
"compiler.cpp:compiler::compiler_state_t::get_current_parent(): no previous parents available.");
152 return f_parents[f_parents.size() - 2];
160 std::string
const variable_name(name->get_string());
167 size_t pos(f_parents.size());
175 s->set_variable(variable_name, v);
182 f_root->set_variable(variable_name, v);
189 size_t pos(f_parents.size());
194 switch(s->get_type())
214 return f_root->get_variable(variable_name);
230 || value->size() != 2)
232 throw csspp_exception_logic(
"compiler.cpp:compiler::compiler_state_t::execute_user_function(): all functions must be two sub-values in a LIST, the first item being the variable.");
252 throw csspp_exception_logic(
"compiler.cpp:compiler::compiler_state_t::execute_user_function(): @mixin function is not defined inside a {}-block.");
256 root->copy_variable(f_root);
258 size_t max_val_children(val->size());
259 for(
size_t j(0); j < max_val_children; ++j)
261 root->add_child(val->get_child(j)->clone());
264 size_t const max_children(var->size());
265 size_t const max_input(func->size());
266 for(
size_t i(0); i < max_children; ++i)
272 throw csspp_exception_logic(
"compiler.cpp:compiler::compiler_state_t::execute_user_function(): FUNCTION children are not all ARG nodes.");
276 throw csspp_exception_logic(
"compiler.cpp:compiler::compiler_state_t::execute_user_function(): ARG is empty.");
297 default_param->remove_child(0);
298 if(default_param->size() == 1)
300 default_param = default_param->get_child(0);
305 value_list->take_over_children_of(default_param);
306 default_param = value_list;
309 param_value->add_child(arg_name);
310 param_value->add_child(default_param);
311 root->set_variable(arg_name->get_string(), param_value);
317 <<
"missing function variable named \""
318 << arg_name->get_string()
319 <<
"\" when calling "
320 << func->get_string()
332 throw csspp_exception_logic(
"compiler.cpp:compiler::replace_variable(): user parameter is not an ARG.");
334 if(user_param->size() == 1)
336 user_param = user_param->get_child(0);
343 list->take_over_children_of(user_param);
347 param_value->add_child(arg_name);
348 param_value->add_child(user_param->clone());
349 root->set_variable(arg_name->get_string(), param_value);
365 f_empty_on_undefined_variable = empty_on_undefined_variable;
370 return f_empty_on_undefined_variable;
376 if(script_name.empty())
378 return std::string();
382 if(script_name[0] ==
'/')
384 if(access(script_name.c_str(), R_OK) == 0)
389 return std::string();
396 f_paths.push_back(
"/usr/lib/csspp/scripts");
400 for(
auto it : f_paths)
402 std::string
const name(it ==
"" ? script_name : it +
"/" + script_name);
403 if(access(name.c_str(), R_OK) == 0)
410 return std::string();
440 throw csspp_exception_logic(
"compiler.cpp: compiler::set_date_time_variables(): function called too soon, root not set yet.");
447 strftime(buf,
sizeof(buf),
"%m/%d/%Y%T", &t);
453 var->set_string(
"_csspp_usdate");
455 arg->set_string(std::string(buf, 10));
460 var->set_string(
"_csspp_month");
462 arg->set_string(std::string(buf, 2));
467 var->set_string(
"_csspp_day");
469 arg->set_string(std::string(buf + 3, 2));
474 var->set_string(
"_csspp_year");
476 arg->set_string(std::string(buf + 6, 4));
481 var->set_string(
"_csspp_time");
483 arg->set_string(std::string(buf + 10, 8));
488 var->set_string(
"_csspp_hour");
490 arg->set_string(std::string(buf + 10, 2));
495 var->set_string(
"_csspp_minute");
497 arg->set_string(std::string(buf + 13, 2));
502 var->set_string(
"_csspp_second");
504 arg->set_string(std::string(buf + 16, 2));
532 throw csspp_exception_logic(
"compiler.cpp: compiler::compile(): compile() called without a root node pointer, call set_root() first.");
552 throw csspp_exception_logic(
"compiler.cpp: the stack of parents must always be empty before mark_selectors() returns.");
558 throw csspp_exception_logic(
"compiler.cpp: the stack of parents must always be empty before replace_variables() returns.");
564 throw csspp_exception_logic(
"compiler.cpp: the stack of parents must always be empty before compile() returns");
570 throw csspp_exception_logic(
"compiler.cpp: the stack of parents must always be empty before remove_empty_rules() returns");
576 throw csspp_exception_logic(
"compiler.cpp: the stack of parents must always be empty before expand_nested_components() returns");
587 header->set_string(
"import");
589 header_string->set_string(
"system/init.scss");
590 header->add_child(header_string);
599 footer->set_string(
"import");
601 footer_string->set_string(
"system/close.scss");
602 footer->add_child(footer_string);
611 no_logo->set_string(
"_csspp_no_logo");
622 switch(n->get_type())
637 && n->get_child(idx) == child)
669 std::stringstream ss;
670 ss <<
"unexpected token (type: " << n->get_type() <<
") in compile().";
722 size_t pos(parent->child_position(n));
723 parent->remove_child(pos);
724 parent->insert_child(pos, n->get_child(0));
734 throw csspp_exception_logic(
"compiler.cpp: found an ARG as the first child of COMPONENT_VALUE, compile_component_value() called twice on the same object?");
737 size_t const max_children(n->size());
739 for(
size_t idx(0); idx < max_children; ++idx)
747 if(count_cv == max_children)
755 size_t pos(parent->child_position(n));
756 parent->remove_child(pos);
757 for(
size_t idx(0); idx < max_children; ++idx, ++pos)
759 parent->insert_child(pos, n->get_child(idx));
765 else if(count_cv != 0)
767 std::cerr <<
"Invalid node:\n" << *n;
791 throw csspp_exception_logic(
"compiler.cpp: somehow a variable definition was found while compiling (1).");
813 throw csspp_exception_logic(
"compiler.cpp: somehow a variable definition was found while compiling (1).");
830 <<
"a qualified rule without selectors is not valid."
845 if(brackets->empty())
858 for(
size_t b(0); b < brackets->size();)
864 for(
size_t idx(0); idx < child->size();)
869 if(idx < child->size()
870 && item == child->get_child(idx))
880 if(b < brackets->size()
881 && child == brackets->get_child(b))
906 <<
"somehow a declaration list is missing a field name or ':'."
925 identifier = n->get_child(0);
927 <<
"the '[*|.|!]<field-name>: ...' syntax is not allowed in csspp, we offer other ways to control field names per browser and do not allow such tricks."
939 <<
"the '#<field-name>: ...' syntax is not allowed in csspp, we offer other ways to control field names per browser and do not allow such tricks."
945 <<
"expected an identifier to start a declaration value; got a: " << identifier->get_type() <<
" instead."
956 next = n->get_child(1);
963 <<
"expected a ':' after the identifier of this declaration value; got a: " << n->get_type() <<
" instead."
972 <<
"somehow a declaration list is missing fields, this happens if you used an invalid variable."
988 <<
"somehow a declaration list is missing fields, this happens if you used an invalid variable."
995 declaration->set_string(identifier->get_string());
999 size_t const max_children(n->size());
1000 for(
size_t i(1); i < max_children; ++i)
1004 declaration->add_child(n->get_child(1));
1017 throw csspp_exception_logic(
"compiler.cpp: got a node which was not of type COMPONENT_VALUE to replace with the DECLARATION.");
1026 if(compile_declaration_items)
1028 for(
size_t i(0); i < declaration->size(); ++i)
1031 switch(item->get_type())
1038 compile_declaration_items =
false;
1048 if(compile_declaration_items
1049 && !declaration->empty())
1055 && (child->get_string() ==
"alpha" || child->get_string() ==
"chroma" || child->get_string() ==
"gray" || child->get_string() ==
"opacity")
1056 && (declaration->get_string() ==
"filter" || declaration->get_string() ==
"-filter"))
1059 && child->get_string() ==
"progid"
1060 && (declaration->get_string() ==
"filter" || declaration->get_string() ==
"-filter"))
1074 <<
"the alpha(), chroma() and similar functions of the filter field are Internet Explorer specific extensions which are not supported across browsers."
1083 declaration_name->set_string(declaration->get_string());
1100 args_expr.set_variable_handler(&
f_state);
1101 args_expr.compile_args(divide_font_metrics);
1111 for(
size_t i(0); i < declaration->size(); ++i)
1115 switch(item->get_type())
1126 for(
size_t j(0); j < item->size();)
1145 std::stringstream errmsg;
1146 errmsg <<
"compiler.cpp: found unexpected node type "
1147 << component->get_type()
1148 <<
", expected a LIST.";
1152 && component == item->get_child(j))
1175 std::string
const at(n->get_string());
1182 parent->remove_child(n);
1185 << (expr ? expr->to_string(0) : std::string(
"@error reached"))
1192 parent->remove_child(n);
1195 << (expr ? expr->to_string(0) : std::string(
"@warning reached"))
1203 parent->remove_child(n);
1206 << (expr ? expr->to_string(0) : std::string(
"@message reached"))
1213 parent->remove_child(n);
1216 << (expr ? expr->to_string(0) : std::string(
"@debug reached"))
1226 parent->remove_child(n);
1232 <<
"the @charset is expected to be followed by exactly one string."
1237 std::string charset(n->get_child(0)->get_string());
1238 while(!charset.empty() && std::isspace(charset[0]))
1240 charset.erase(charset.begin(), charset.begin() + 1);
1242 while(!charset.empty() && std::isspace(charset.back()))
1244 charset.erase(charset.end() - 1, charset.end());
1246 for(
auto & c : charset)
1248 c = std::tolower(c);
1250 if(charset !=
"utf-8")
1253 <<
"we only support @charset \"utf-8\";, any other encoding is refused."
1265 || at ==
"supports")
1277 for(
size_t idx(0); idx < last->size();)
1293 if(idx < last->size()
1294 && child == last->get_child(idx))
1304 if(at ==
"font-face"
1307 || at ==
"-ms-viewport")
1314 if(last->size() > 0)
1319 list = last->get_child(0);
1324 for(
size_t idx(0); idx < list->size();)
1332 if(idx < list->size()
1333 && child == list->get_child(idx))
1354 <<
"@return must be followed by a valid expression."
1377 if(at ==
"keyframes"
1378 || at ==
"-o-keyframes"
1379 || at ==
"-webkit-keyframes")
1468 <<
"@keyframes must be followed by an identifier and '{' ... '}'."
1480 <<
"@keyframes must first be followed by an identifier."
1490 <<
"@keyframes must be followed by an identifier and '{' ... '}'."
1499 size_t const max_positions(positions->size());
1500 for(
size_t idx(0); idx < max_positions; ++idx)
1507 <<
"@keyframes is only expecting component values as child entries."
1511 if(component_value->size() != 2)
1515 <<
"@keyframes is expected to be followed by an identifier or a percent number and a '{'."
1524 <<
"@keyframes is expected to be followed by an identifier or a percent number and a '{'."
1528 if(components->size() != 1)
1532 <<
"@keyframes is expected to be followed by an identifier or a percent number and a '{'."
1542 sub_list->add_child(component_list);
1543 component_list = sub_list;
1549 <<
"@keyframes is expected to be followed by an identifier or a percent number and a list of component values '{' ... '}'."
1559 std::string
const l(
position->get_string());
1572 <<
"@keyframes position can be \"from\" or \"to\", other identifiers are not supported."
1579 p =
position->get_decimal_number();
1580 if(p < 0.0 || p > 1.0)
1584 <<
"@keyframes position must be a percentage between 0% and 100%."
1593 <<
"@keyframes positions must either be \"from\" or \"to\" or a percent number between 0% and 100%."
1603 frame->set_decimal_number(p);
1604 frame->take_over_children_of(component_list);
1606 list->add_child(frame);
1617 n->take_over_children_of(list);
1621 n->insert_child(0, identifier);
1631 static_cast<void>(
import);
1656 std::string script_name(expr->get_string());
1661 if(script_name.substr(0, 7) ==
"file://")
1663 script_name = script_name.substr(7);
1664 if(script_name.empty()
1665 || script_name[0] !=
'/')
1667 script_name =
"/" + script_name;
1680 std::string::size_type pos(script_name.find(
':'));
1681 if(pos != std::string::npos
1682 && script_name.substr(pos, 3) ==
"://")
1684 std::string
const protocol(script_name.substr(0, pos));
1685 auto s(protocol.c_str());
1686 for(; *s !=
'\0'; ++s)
1688 if((*s <
'a' || *s >
'z')
1689 && (*s <
'A' || *s >
'Z'))
1696 if(protocol !=
"file")
1701 script_name = script_name.substr(7);
1702 if(script_name.empty()
1703 || script_name[0] !=
'/')
1705 script_name =
"/" + script_name;
1714 std::string filename(
find_file(script_name));
1715 if(filename.empty() && script_name.length() > 5)
1717 if(script_name.substr(script_name.size() - 5) !=
".scss")
1720 filename =
find_file(script_name +
".scss");
1725 if(!filename.empty())
1732 parent->remove_child(idx);
1747 <<
"validation script \""
1749 <<
"\" could not be opened."
1767 size_t const max_results(list->size());
1768 for(
size_t i(0), j(idx); i < max_results; ++i, ++j)
1770 parent->insert_child(j, list->get_child(i));
1778 else if(script_name.empty())
1781 <<
"@import \"\"; and @import url(); are not valid."
1789 <<
"); left alone by the CSS Preprocessor, no matching file found."
1797 <<
"\"; left alone by the CSS Preprocessor, no matching file found."
1810 <<
"a @mixin definition expects exactly two parameters: an identifier or function and a {}-block."
1819 <<
"a @mixin definition expects a {}-block as its second parameter."
1832 <<
"a @mixin must use an IDENTIFIER or FUNCTION and no a VARIABLE or VARIABLE_FUNCTION."
1862 <<
"a @mixin expects either an IDENTIFIER or a FUNCTION as its first parameter."
1871 switch(n->get_type())
1895 n->get_last_child()->set_boolean(
true);
1899 for(
size_t idx(0); idx < n->size(); ++idx)
1919 switch(n->get_type())
1924 && n->get_last_child()->empty())
1940 for(
size_t idx(0); idx < n->size();)
1948 && child == n->get_child(idx))
1966 switch(n->get_type())
1975#if __cplusplus >= 201700
1994 size_t idx(is_variable_set
1999 while(idx < n->size())
2004 n->remove_child(idx);
2016 n->remove_child(idx);
2026 switch(child->get_type())
2041 && child == n->get_child(idx))
2084 std::string
const & variable_name(n->get_string());
2094 <<
"variable named \""
2104 || value->size() != 2)
2106 throw csspp_exception_logic(
"compiler.cpp:compiler::replace_variable(): all variable values must be two sub-values in a LIST, the first item being the variable.");
2119 <<
"variable named \""
2121 <<
"\" is not a function and it cannot be referenced as such."
2129 root->add_child(val->clone());
2130 size_t const max_children(var->size());
2131 size_t const max_input(n->size());
2132 for(
size_t i(0); i < max_children; ++i)
2138 throw csspp_exception_logic(
"compiler.cpp:compiler::replace_variable(): VARIABLE_FUNCTION children are not all ARG nodes.");
2163 default_param->remove_child(0);
2164 if(default_param->size() == 1)
2166 default_param = default_param->get_child(0);
2171 value_list->take_over_children_of(default_param);
2172 default_param = value_list;
2175 param_value->add_child(arg_name);
2176 param_value->add_child(default_param);
2177 root->set_variable(arg_name->get_string(), param_value);
2183 <<
"missing function variable named \""
2184 << arg_name->get_string()
2185 <<
"\" when calling "
2187 <<
"() or using @include "
2200 throw csspp_exception_logic(
"compiler.cpp:compiler::replace_variable(): user parameter is not an ARG.");
2202 if(user_param->size() == 1)
2204 user_param = user_param->get_child(0);
2211 list->take_over_children_of(user_param);
2215 param_value->add_child(arg_name);
2216 param_value->add_child(user_param->clone());
2217 root->set_variable(arg_name->get_string(), param_value);
2235 val = val->get_child(0);
2244 <<
"variable named \""
2246 <<
"\" is a function and it can only be referenced with a function ($"
2248 <<
"() or @include "
2256 switch(val->get_type())
2274 size_t const max_children(val->get_child(0)->size());
2275 for(
size_t j(0), i(idx); j < max_children; ++j, ++i)
2278 parent->insert_child(i, child->clone());
2339#if __cplusplus >= 201700
2347 size_t const max_children(val->size());
2348 for(
size_t j(0), i(idx); j < max_children; ++j, ++i)
2350 parent->insert_child(i, val->get_child(j)->clone());
2364 parent->insert_child(idx, val->clone());
2392 throw csspp_exception_logic(
"compiler.cpp: somehow a variable set is not exactly IDENTIFIER WHITESPACE* ':'.");
2408 bool set_if_unset(
false);
2409 std::string not_at_the_end;
2410 size_t pos(n->size());
2417 if(child->get_string() ==
"global")
2420 n->remove_child(pos);
2421 if(not_at_the_end.empty()
2422 && pos != n->size())
2424 not_at_the_end = child->get_string();
2427 else if(child->get_string() ==
"default")
2429 set_if_unset =
true;
2430 n->remove_child(pos);
2431 if(not_at_the_end.empty()
2432 && pos != n->size())
2434 not_at_the_end = child->get_string();
2439 if(!not_at_the_end.empty())
2442 <<
"A special flag, !"
2444 <<
" in this case, must only appear at the end of a declaration."
2463 list = n->get_child(0);
2468 list->take_over_children_of(n);
2473 && list->get_string() ==
"null")
2500 bool optional(
false);
2501 size_t const max_children(var->size());
2502 for(
size_t i(0); i < max_children; ++i)
2507 throw csspp_exception_logic(
"compiler.cpp:compiler::set_variable(): an argument is not an ARG node.");
2516 size_t const arg_size(arg->size());
2521 arg->remove_child(1);
2527 arg->remove_child(1);
2531 arg->remove_child(1);
2538 <<
"function declarations expect variable with optional parameters to use a ':' after the variable name and before the optional value."
2548 <<
"function declarations with optional parameters must make all parameters optional from the first one that is given an optional value up to the end of the list of arguments."
2556 <<
"function declarations expect variables for each of their arguments, not a "
2557 << param_var->get_type()
2583 std::string
const at(n->get_string());
2602 parent->remove_child(idx);
2612 parent->remove_child(idx);
2620 parent->remove_child(idx);
2629 parent->remove_child(idx);
2637 <<
"@include is expected to be followed by an IDENTIFIER or a FUNCTION naming the variable/mixin to include."
2647 <<
"@include is expected to be followed by an IDENTIFIER or a FUNCTION naming the variable/mixin to include."
2690 if(idx < parent->size())
2694 next = parent->get_child(idx);
2696 && next->get_string() ==
"else")
2699 next->set_integer(g_if_or_else_executed);
2706 if(n->size() != 2 || !expr)
2709 <<
"@if is expected to have exactly 2 parameters: an expression and a block. This @if has "
2710 <<
static_cast<int>(n->size())
2723 size_t const max_children(block->size());
2724 for(
size_t j(0); j < max_children; ++j, ++idx)
2726 parent->insert_child(idx, block->get_child(j));
2732 next->set_integer(g_if_or_else_false_so_far);
2744 if(idx < parent->size())
2746 next = parent->get_child(idx);
2748 && next->get_string() ==
"else")
2753 <<
"'@else { ... }' cannot follow another '@else { ... }'. Maybe you are missing an 'if expr'?"
2762 next->set_integer(g_if_or_else_executed);
2772 && n->get_child(0)->get_string() ==
"if");
2794 <<
"'@else if ...' is missing an expression or a block."
2804 int status(n->get_integer());
2805 if(status == g_if_or_else_undefined)
2808 <<
"a standalone @else is not legal, it has to be preceeded by an @if ... or @else if ..."
2818 bool r(status == g_if_or_else_false_so_far);
2821 if(n->size() != 2 || !expr)
2824 <<
"'@else { ... }' is expected to have 1 parameter, '@else if ... { ... }' is expected to have 2 parameters. This @else has "
2825 <<
static_cast<int>(n->size())
2845 status = g_if_or_else_executed;
2851 size_t const max_children(block->size());
2852 for(
size_t j(0); j < max_children; ++j, ++idx)
2854 parent->insert_child(idx, block->get_child(j));
2860 next->set_integer(status);
2866 std::string comment(n->get_string());
2868 std::string::size_type pos(comment.find(
'{'));
2869 while(pos != std::string::npos)
2871 if(pos + 2 < comment.length()
2872 && comment[pos + 1] ==
'$')
2874 std::string::size_type start_var(pos);
2875 std::string::size_type start_name(start_var + 2);
2878 && comment[start_var - 1] ==
'#')
2883 std::string::size_type end_var(comment.find(
'}', start_var + 2));
2884 if(end_var != std::string::npos)
2887 std::string
const full_name(comment.substr(start_name, end_var - start_name));
2890 bool is_function(
false);
2891 std::string variable_name(full_name);
2892 std::string::size_type func_pos(full_name.find(
'('));
2893 if(func_pos != std::string::npos)
2896 variable_name = full_name.substr(0, func_pos);
2905 || var_content->size() != 2)
2907 throw csspp_exception_logic(
"compiler.cpp:compiler::replace_variables_in_comment(): all variable values must be two sub-values in a LIST, the first item being the variable.");
2916 <<
"variable named \""
2918 <<
"\", is a function which is not supported in a comment."
2926 <<
"variable named \""
2928 <<
"\", is not a function, yet you referenced it as such (and functions are not yet supported in comments)."
2934 comment.erase(start_var, end_var + 1 - start_var);
2936 std::string
const value(val->to_string(0));
2938 comment.insert(start_var, value);
2943 pos = start_var + value.length() - 1;
2951 <<
"variable named \""
2953 <<
"\", used in a comment, is not set."
2960 pos = comment.find(
'{', pos + 1);
2963 n->set_string(comment);
2977 n->remove_child(term);
2978 if(pos >= n->size())
2982 term = n->get_child(pos);
2988 <<
"an attribute selector expects to first find an identifier."
2994 if(pos >= n->size())
3001 term = n->get_child(pos);
3004 n->remove_child(pos);
3005 if(pos >= n->size())
3013 term = n->get_child(pos);
3025 <<
"expected attribute operator missing, supported operators are '=', '!=', '~=', '^=', '$=', '*=', and '|='."
3032 if(pos >= n->size())
3037 term = n->get_child(pos);
3040 n->remove_child(pos);
3041 if(pos >= n->size())
3048 term = n->get_child(pos);
3057 <<
"attribute selector value must be an identifier, a string, an integer, or a decimal number, a "
3058 << term->get_type() <<
" is not acceptable."
3067 <<
"attribute selector cannot be followed by more than one value, found "
3068 << n->get_child(pos)->get_type() <<
" after the value, missing quotes?"
3080 parent->remove_child(parent_pos);
3084 parent->insert_child(parent_pos, colon);
3089 not_func->set_string(
"not");
3090 parent->insert_child(parent_pos, not_func);
3093 not_func->add_child(n);
3100 n->insert_child(1, equal);
3109 <<
"the attribute selector is expected to be an IDENTIFIER optionally followed by an operator and a value."
3116 if(pos >= n->size())
3118 throw csspp_exception_logic(
"compiler.cpp:compiler::selector_term(): selector_simple_term() called when not enough selectors are available.");
3122 switch(term->get_type())
3136 if(pos + 1 < n->size())
3140 if(pos + 2 >= n->size())
3143 <<
"the scope operator (|) requires a right hand side identifier or '*'."
3148 term = n->get_child(pos);
3153 <<
"the right hand side of a scope operator (|) must be an identifier or '*'."
3163 n->remove_child(term);
3171 if(pos >= n->size())
3174 <<
"a scope selector (|) must be followed by an identifier or '*'."
3178 term = n->get_child(pos);
3183 <<
"the right hand side of a scope operator (|) must be an identifier or '*'."
3191 if(pos >= n->size())
3196 <<
"a selector list cannot end with a standalone ':'."
3200 term = n->get_child(pos);
3201 switch(term->get_type())
3209 str->set_string(term->get_string());
3225 function_name->set_string(term->get_string());
3232 size_t const max_children(term->size());
3234 for(
size_t idx(0); idx < max_children; ++idx)
3244 an_b_node->set_integer(nc.
get_nth());
3246 term->add_child(an_b_node);
3266 if(term->get_string() ==
"not")
3270 <<
"the :not() selector does not accept an inner :not()."
3274 else if(term->get_string() ==
"lang")
3277 if(term->size() != 1)
3280 <<
"a lang() function selector must have exactly one identifier as its parameter."
3284 term = term->get_child(0);
3287 std::string lang(term->get_string());
3288 std::string country;
3289 std::string::size_type char_pos(lang.find(
'-'));
3290 if(char_pos != std::string::npos)
3292 country = lang.substr(char_pos + 1);
3293 lang = lang.substr(0, char_pos);
3294 char_pos = country.find(
'-');
3295 if(char_pos != std::string::npos)
3299 country = country.substr(0, char_pos);
3304 language_name->set_string(lang);
3311 if(!country.empty())
3315 country_name->set_string(country);
3327 <<
"a lang() function selector expects an identifier as its parameter."
3339 <<
"a ':' selector must be followed by an identifier or a function, a " << n->get_type() <<
" was found instead."
3349 if(pos >= n->size())
3352 <<
"a selector list cannot end with a standalone '.'."
3356 term = n->get_child(pos);
3360 <<
"a class selector (after a period: '.') must be an identifier."
3374 <<
"found token " << term->get_type() <<
", which cannot be used to start a selector expression."
3380 <<
"found function \"" << term->get_string() <<
"()\", which may be a valid selector token but only if immediately preceeded by one ':' (simple term)."
3386 <<
"found token " << term->get_type() <<
", which is not a valid selector token (simple term)."
3400 if(pos >= n->size())
3402 throw csspp_exception_logic(
"compiler.cpp:compiler::selector_term(): selector_term() called when not enough selectors are available.");
3406 switch(term->get_type())
3417 <<
"a selector reference (&) can only appear as the very first item in a list of selectors."
3428 if(pos >= n->size())
3431 <<
"a selector list cannot end with a standalone ':'."
3435 term = n->get_child(pos);
3436 switch(term->get_type())
3444 if(term->get_string() ==
"not")
3457 if(sub_pos < term->size())
3463 <<
"the :not() function accepts at most one simple term."
3479 if(pos >= n->size())
3482 <<
"a selector list cannot end with a '::' without an identifier after it."
3486 term = n->get_child(pos);
3490 <<
"a pseudo element name (defined after a '::' in a list of selectors) must be defined using an identifier."
3496 pseudo_element->set_string(term->get_string());
3503 if(pos + 1 < n->size())
3506 <<
"a pseudo element name (defined after a '::' in a list of selectors) must be defined as the last element in the list of selectors."
3516 <<
"a ':' selector must be followed by an identifier or a function, a " << term->get_type() <<
" was found instead."
3535 <<
"found token " << term->get_type() <<
", which cannot be used to start a selector expression."
3543 <<
"found function \"" << term->get_string() <<
"()\", which may be a valid selector token but only if immediately preceeded by one ':' (term)."
3549 <<
"found token " << term->get_type() <<
", which is not a valid selector token (term)."
3571 if(pos >= n->size())
3584 if(pos >= n->size())
3588 throw csspp_exception_logic(
"compiler.cpp: a component value has a WHITESPACE token before the OPEN_CURLYBRACKET.");
3590 term = n->get_child(pos);
3601 n->remove_child(pos - 1);
3611 if(pos >= n->size())
3614 <<
"found token " << term->get_type() <<
", which is expected to be followed by another selector term."
3620 term = n->get_child(pos);
3624 n->remove_child(term);
3627 if(pos >= n->size())
3631 throw csspp_exception_logic(
"compiler.cpp: a component value has a WHITESPACE token before the OPEN_CURLYBRACKET.");
3650 size_t const max_children(n->size());
3651 for(
size_t idx(0); idx < max_children; ++idx)
3661 throw csspp_exception_logic(
"compiler.cpp: parse_selector() just called argify() and yet a child is not an ARG.");
3673 std::map<std::string, bool> hash;
3674 for(
size_t j(0); j < arg->size(); ++j)
3679 if(hash.find(child->get_string()) != hash.end())
3683 << child->get_string()
3684 <<
" twice in selector: \""
3685 << arg->to_string(0)
3692 hash[child->get_string()] =
true;
3701 <<
"found multiple #id entries, note that in most cases, assuming your HTML is proper (identifiers are not repeated) then only the last #id is necessary."
3732 std::string filename(
find_file(script_name));
3733 if(filename.empty())
3735 if(script_name.substr(script_name.size() - 5) !=
".scss")
3738 filename =
find_file(script_name +
".scss");
3742 if(filename.empty())
3747 <<
"validation script \""
3749 <<
"\" was not found."
3775 <<
"validation script \""
3777 <<
"\" could not be opened."
3799 script->clear_variables();
3806 throw csspp_exception_logic(
"compiler.cpp: somehow add_validation_variable() was called without a current validation script set.");
3810 var->set_string(variable_name);
3813 v->add_child(value);
3823 throw csspp_exception_logic(
"compiler.cpp:compiler::run_validation(): already validating, cannot validate from within a validation script.");
3840 std::stringstream ignore;
3865 switch(n->get_type())
3870 for(
size_t idx(0); idx < n->size();)
3875 && child == n->get_child(idx))
3890 for(
size_t idx(0); idx < n->size();)
3896 && child == n->get_child(idx))
3910 for(
size_t idx(0); idx < n->size();)
3915 && child == n->get_child(idx))
3933 switch(n->get_type())
3962 size_t pos(parent->child_position(last));
3963 parent->insert_child(pos + 1, n);
3977 list->add_child(child);
3979 for(
size_t idx(0); idx < root->size(); ++idx)
3988 for(
size_t l(0); l < list->size(); ++l)
3992 for(
size_t a(0); a < arg->size(); ++a)
4000 clone->add_child(whitespace);
4002 clone->add_child(item->clone());
4006 n->insert_child(idx, clone);
4011 for(
size_t idx(0); idx < n->size();)
4017 && child == n->get_child(idx))
4026 for(
size_t idx(0); idx < n->size();)
4032 && child == n->get_child(idx))
4044 for(
size_t idx(0); idx < n->size();)
4049 && child == n->get_child(idx))
4058 for(
size_t idx(0); idx < n->size();)
4063 && child == n->get_child(idx))
4081 switch(n->get_type())
4103 std::string
const sub_name((name ==
"-csspp-null" ?
"" : name +
"-") + n->get_string());
4107 size_t pos(parent->child_position(root));
4108 parent->insert_child(pos + 1, n);
4109 n->set_string(sub_name);
4112 for(
size_t idx(0); idx < n->size();)
4117 && child == n->get_child(idx))
4134 throw csspp_exception_logic(
"compiler.cpp:compiler::expand_nested_declarations(): @-keyword cannot appear within a declaration.");
4149 for(
size_t idx(0); idx < n->size();)
4154 && child == n->get_child(idx))
4167 <<
"a nested declaration cannot include a rule."
void set_root(node::pointer_t root)
void push_parent(node::pointer_t parent)
bool f_empty_on_undefined_variable
bool get_empty_on_undefined_variable() const
virtual node::pointer_t execute_user_function(node::pointer_t func)
virtual node::pointer_t get_variable(std::string const &variable_name, bool global_only=false) const
void add_path(std::string const &path)
void set_variable(node::pointer_t variable, node::pointer_t value, bool global) const
void set_paths(compiler_state_t const &state)
bool empty_parents() const
void set_empty_on_undefined_variable(bool const empty_on_undefined_variable)
node::pointer_t get_root() const
node::pointer_t get_previous_parent() const
std::string find_file(std::string const &script_name)
void replace_else(node::pointer_t parent, node::pointer_t n, size_t idx)
void set_no_logo(bool no_logo=true)
void replace_if(node::pointer_t parent, node::pointer_t n, size_t idx)
bool selector_term(node::pointer_t n, size_t &pos)
void handle_mixin(node::pointer_t n)
void compile_component_value(node::pointer_t n)
void expand_nested_rules(node::pointer_t parent, node::pointer_t root, node::pointer_t &last, node::pointer_t n)
void replace_variables_in_comment(node::pointer_t n)
bool parse_selector(node::pointer_t n)
void compile_declaration(node::pointer_t n)
void replace_variables(node::pointer_t n)
compiler(bool validating=false)
void add_header_and_footer()
void replace_variable(node::pointer_t parent, node::pointer_t n, size_t &idx)
void add_path(std::string const &path)
node::pointer_t get_result() const
void expand_nested_declarations(std::string const &name, node::pointer_t parent, node::pointer_t &root, node::pointer_t n)
void set_root(node::pointer_t root)
void prepare_function_arguments(node::pointer_t var)
node::pointer_t at_keyword_expression(node::pointer_t n)
node::pointer_t f_return_result
void compile_declaration_values(node::pointer_t declaration)
std::string find_file(std::string const &script_name)
void compile_at_keyword(node::pointer_t n)
void replace_at_keyword(node::pointer_t parent, node::pointer_t n, size_t &idx)
void set_validation_script(std::string const &script_name)
bool selector_simple_term(node::pointer_t n, size_t &pos)
void set_empty_on_undefined_variable(bool const empty_on_undefined_variable)
bool f_compiler_validating
void replace_import(node::pointer_t parent, node::pointer_t import, size_t &idx)
void expand_nested_components(node::pointer_t n)
node::pointer_t f_current_validation_script
bool run_validation(bool check_only)
bool selector_list(node::pointer_t n, size_t &pos)
node::pointer_t get_root() const
void mark_selectors(node::pointer_t n)
void set_date_time_variables(time_t now)
void compile_qualified_rule(node::pointer_t n)
void add_validation_variable(std::string const &variable_name, node::pointer_t value)
bool selector_attribute_check(node::pointer_t parent, size_t &parent_pos, node::pointer_t n)
void set_variable(node::pointer_t n)
void remove_empty_rules(node::pointer_t n)
bool error_happened() const
static error & instance()
node::pointer_t compile()
void set_variable_handler(expression_variables_interface *handler)
static bool boolean(node::pointer_t n)
Check whether a node represents true or false.
std::shared_ptr< lexer > pointer_t
static int const g_to_string_flag_show_quotes
std::shared_ptr< node > pointer_t
std::string get_error() const
integer_t get_nth() const
bool parse(std::string const &an_plus_b)
node::pointer_t stylesheet()
static bool argify(node::pointer_t n, node_type_t const separator=node_type_t::COMMA)
static bool is_nested_declaration(node::pointer_t n)
static bool is_variable_set(node::pointer_t n, bool with_block)
compiler::compiler_state_t & f_state
safe_compiler_state_t(compiler::compiler_state_t &state)
compiler::compiler_state_t f_state_copy
safe_parents_t(compiler::compiler_state_t &state, node::pointer_t n)
compiler::compiler_state_t & f_state
integer_t const g_if_or_else_undefined
integer_t const g_if_or_else_executed
integer_t const g_if_or_else_false_so_far
The namespace of all the classes in the CSS Preprocessor.