From 0dad85646d1dc7e2c9099c9e8b7cba829ebf6efc Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 00:55:09 +0100 Subject: [PATCH 01/30] Add functions utility compile unit --- Makefile.conf | 1 + src/fn_utils.cpp | 10 ++++++++++ src/fn_utils.hpp | 12 ++++++++++++ win/libsass.targets | 2 ++ win/libsass.vcxproj.filters | 6 ++++++ 5 files changed, 31 insertions(+) create mode 100644 src/fn_utils.cpp create mode 100644 src/fn_utils.hpp diff --git a/Makefile.conf b/Makefile.conf index 5ba968b68..161ee9767 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -10,6 +10,7 @@ SOURCES = \ node.cpp \ context.cpp \ constants.cpp \ + fn_utils.cpp \ functions.cpp \ color_maps.cpp \ environment.cpp \ diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp new file mode 100644 index 000000000..e069240d1 --- /dev/null +++ b/src/fn_utils.cpp @@ -0,0 +1,10 @@ +#include "sass.hpp" +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + } + +} diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp new file mode 100644 index 000000000..8363240eb --- /dev/null +++ b/src/fn_utils.hpp @@ -0,0 +1,12 @@ +#ifndef SASS_FN_UTILS_H +#define SASS_FN_UTILS_H + +namespace Sass { + + namespace Functions { + + } + +} + +#endif diff --git a/win/libsass.targets b/win/libsass.targets index c1c7d45f3..8bf68df60 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -32,6 +32,7 @@ + @@ -86,6 +87,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 980f00f3f..1f301f769 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -108,6 +108,9 @@ Headers + + Headers + Headers @@ -269,6 +272,9 @@ Sources + + Sources + Sources From d82802719bfd494ab87f1a5754154cb811cd3a60 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 01:09:40 +0100 Subject: [PATCH 02/30] Move macros and helpers to fn_utils - Remove obsolete ctx parameter - make ARGSEL(S) macro specific --- src/ast.hpp | 1 - src/ast_fwd_decl.hpp | 6 ++ src/context.cpp | 1 + src/fn_utils.cpp | 143 +++++++++++++++++++++++++ src/fn_utils.hpp | 63 ++++++++++++ src/functions.cpp | 229 +++-------------------------------------- src/functions.hpp | 7 +- src/sass_functions.hpp | 2 +- 8 files changed, 228 insertions(+), 224 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index a2be8685c..07728103e 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -944,7 +944,6 @@ namespace Sass { // by a type tag. ///////////////////////////////////////////////////////////////////////////// struct Backtrace; - typedef const char* Signature; typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, std::vector); class Definition : public Has_Block { public: diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index 5145a092b..4a3ff69b1 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -419,8 +419,14 @@ namespace Sass { typedef std::set CompoundSelectorSet; typedef std::unordered_set SimpleSelectorDict; + typedef std::vector BlockStack; + typedef std::vector CallStack; + typedef std::vector MediaStack; + typedef std::vector SelectorStack; typedef std::vector* ImporterStack; + typedef const char* Signature; + // only to switch implementations for testing #define environment_map std::map diff --git a/src/context.cpp b/src/context.cpp index dae2cbd75..272b99cb1 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -29,6 +29,7 @@ #include "sass2scss.h" #include "prelexer.hpp" #include "emitter.hpp" +#include "fn_utils.hpp" namespace Sass { using namespace Constants; diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp index e069240d1..47ec759a4 100644 --- a/src/fn_utils.cpp +++ b/src/fn_utils.cpp @@ -1,10 +1,153 @@ #include "sass.hpp" +#include "parser.hpp" #include "fn_utils.hpp" +#include "functions.hpp" +#include "error_handling.hpp" namespace Sass { + Definition_Ptr make_native_function(Signature sig, Native_Function func, Context& ctx) + { + Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[built-in function]")); + sig_parser.lex(); + std::string name(Util::normalize_underscores(sig_parser.lexed)); + Parameters_Obj params = sig_parser.parse_parameters(); + return SASS_MEMORY_NEW(Definition, + ParserState("[built-in function]"), + sig, + name, + params, + func, + false); + } + + Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx) + { + using namespace Prelexer; + + const char* sig = sass_function_get_signature(c_func); + Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[c function]")); + // allow to overload generic callback plus @warn, @error and @debug with custom functions + sig_parser.lex < alternatives < identifier, exactly <'*'>, + exactly < Constants::warn_kwd >, + exactly < Constants::error_kwd >, + exactly < Constants::debug_kwd > + > >(); + std::string name(Util::normalize_underscores(sig_parser.lexed)); + Parameters_Obj params = sig_parser.parse_parameters(); + return SASS_MEMORY_NEW(Definition, + ParserState("[c function]"), + sig, + name, + params, + c_func, + false, true); + } + namespace Functions { + Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) + { + // Minimal error handling -- the expectation is that built-ins will be written correctly! + Map_Ptr val = Cast(env[argname]); + if (val) return val; + + List_Ptr lval = Cast(env[argname]); + if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0); + + // fallback on get_arg for error handling + val = get_arg(argname, env, sig, pstate, traces); + return val; + } + + double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi) + { + // Minimal error handling -- the expectation is that built-ins will be written correctly! + Number_Ptr val = get_arg(argname, env, sig, pstate, traces); + Number tmpnr(val); + tmpnr.reduce(); + double v = tmpnr.value(); + if (!(lo <= v && v <= hi)) { + std::stringstream msg; + msg << "argument `" << argname << "` of `" << sig << "` must be between "; + msg << lo << " and " << hi; + error(msg.str(), pstate, traces); + } + return v; + } + + Number_Ptr get_arg_n(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) + { + Number_Ptr val = get_arg(argname, env, sig, pstate, traces); + val = SASS_MEMORY_COPY(val); + val->reduce(); + return val; + } + + double get_arg_val(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) + { + Number_Ptr val = get_arg(argname, env, sig, pstate, traces); + Number tmpnr(val); + tmpnr.reduce(); + return tmpnr.value(); + } + + double color_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) + { + Number_Ptr val = get_arg(argname, env, sig, pstate, traces); + Number tmpnr(val); + tmpnr.reduce(); + if (tmpnr.unit() == "%") { + return std::min(std::max(tmpnr.value() * 255 / 100.0, 0.0), 255.0); + } else { + return std::min(std::max(tmpnr.value(), 0.0), 255.0); + } + } + + double alpha_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) { + Number_Ptr val = get_arg(argname, env, sig, pstate, traces); + Number tmpnr(val); + tmpnr.reduce(); + if (tmpnr.unit() == "%") { + return std::min(std::max(tmpnr.value(), 0.0), 100.0); + } else { + return std::min(std::max(tmpnr.value(), 0.0), 1.0); + } + } + + Selector_List_Obj get_arg_sels(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) { + Expression_Obj exp = ARG(argname, Expression); + if (exp->concrete_type() == Expression::NULL_VAL) { + std::stringstream msg; + msg << argname << ": null is not a valid selector: it must be a string,\n"; + msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'"; + error(msg.str(), pstate, traces); + } + if (String_Constant_Ptr str = Cast(exp)) { + str->quote_mark(0); + } + std::string exp_src = exp->to_string(ctx.c_options); + return Parser::parse_selector(exp_src.c_str(), ctx, traces); + } + + Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) { + Expression_Obj exp = ARG(argname, Expression); + if (exp->concrete_type() == Expression::NULL_VAL) { + std::stringstream msg; + msg << argname << ": null is not a string for `" << function_name(sig) << "'"; + error(msg.str(), pstate, traces); + } + if (String_Constant_Ptr str = Cast(exp)) { + str->quote_mark(0); + } + std::string exp_src = exp->to_string(ctx.c_options); + Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx, traces); + if (sel_list->length() == 0) return NULL; + Complex_Selector_Obj first = sel_list->first(); + if (!first->tail()) return first->head(); + return first->tail()->head(); + } + } } diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index 8363240eb..eaeac0228 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -1,10 +1,73 @@ #ifndef SASS_FN_UTILS_H #define SASS_FN_UTILS_H +#include "backtrace.hpp" +#include "environment.hpp" +#include "ast_fwd_decl.hpp" + namespace Sass { + #define BUILT_IN(name) Expression_Ptr \ + name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, std::vector selector_stack) + + #define ARG(argname, argtype) get_arg(argname, env, sig, pstate, traces) + #define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces) + + // return a number object (copied since we want to have reduced units) + #define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy + + // special function for weird hsla percent (10px == 10% == 10 != 0.1) + #define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double + + // macros for common ranges (u mean unsigned or upper, r for full range) + #define DARG_U_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 1.0) // double + #define DARG_R_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 1.0, 1.0) // double + #define DARG_U_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 255.0) // double + #define DARG_R_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 255.0, 255.0) // double + #define DARG_U_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 100.0) // double + #define DARG_R_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 100.0, 100.0) // double + + // macros for color related inputs (rbg and alpha/opacity values) + #define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double + #define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double + + #define ARGSEL(argname) get_arg_sel(argname, env, sig, pstate, traces, ctx) + #define ARGSELS(argname) get_arg_sels(argname, env, sig, pstate, traces, ctx) + + typedef const char* Signature; + + typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); + + Definition_Ptr make_native_function(Signature, Native_Function, Context& ctx); + Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx); + namespace Functions { + template + T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) + { + T* val = Cast(env[argname]); + if (!val) { + std::string msg("argument `"); + msg += argname; + msg += "` of `"; + msg += sig; + msg += "` must be a "; + msg += T::type_name(); + error(msg, pstate, traces); + } + return val; + } + + Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces); // maps only + Number_Ptr get_arg_n(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces); // numbers only + double alpha_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces); // colors only + double color_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces); // colors only + double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi); // colors only + double get_arg_val(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces); // shared + Selector_List_Obj get_arg_sels(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx); // selectors only + Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx); // selectors only + } } diff --git a/src/functions.cpp b/src/functions.cpp index 9b118d53a..b3fdf44f7 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -31,69 +31,12 @@ #include "wincrypt.h" #endif -#define ARG(argname, argtype) get_arg(argname, env, sig, pstate, traces) -#define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces, ctx) - -// return a number object (copied since we want to have reduced units) -#define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy - -// special function for weird hsla percent (10px == 10% == 10 != 0.1) -#define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double - -// macros for common ranges (u mean unsigned or upper, r for full range) -#define DARG_U_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 1.0) // double -#define DARG_R_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 1.0, 1.0) // double -#define DARG_U_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 255.0) // double -#define DARG_R_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 255.0, 255.0) // double -#define DARG_U_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 100.0) // double -#define DARG_R_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 100.0, 100.0) // double - -// macros for color related inputs (rbg and alpha/opacity values) -#define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double -#define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double +#include "fn_utils.hpp" namespace Sass { using std::stringstream; using std::endl; - Definition_Ptr make_native_function(Signature sig, Native_Function func, Context& ctx) - { - Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[built-in function]")); - sig_parser.lex(); - std::string name(Util::normalize_underscores(sig_parser.lexed)); - Parameters_Obj params = sig_parser.parse_parameters(); - return SASS_MEMORY_NEW(Definition, - ParserState("[built-in function]"), - sig, - name, - params, - func, - false); - } - - Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx) - { - using namespace Prelexer; - - const char* sig = sass_function_get_signature(c_func); - Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[c function]")); - // allow to overload generic callback plus @warn, @error and @debug with custom functions - sig_parser.lex < alternatives < identifier, exactly <'*'>, - exactly < Constants::warn_kwd >, - exactly < Constants::error_kwd >, - exactly < Constants::debug_kwd > - > >(); - std::string name(Util::normalize_underscores(sig_parser.lexed)); - Parameters_Obj params = sig_parser.parse_parameters(); - return SASS_MEMORY_NEW(Definition, - ParserState("[c function]"), - sig, - name, - params, - c_func, - false, true); - } - std::string function_name(Signature sig) { std::string str(sig); @@ -122,152 +65,6 @@ namespace Sass { catch (...) { throw; } } - template - T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) - { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - T* val = Cast(env[argname]); - if (!val) { - std::string msg("argument `"); - msg += argname; - msg += "` of `"; - msg += sig; - msg += "` must be a "; - msg += T::type_name(); - error(msg, pstate, traces); - } - return val; - } - - Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) - { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - Map_Ptr val = Cast(env[argname]); - if (val) return val; - - List_Ptr lval = Cast(env[argname]); - if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0); - - // fallback on get_arg for error handling - val = get_arg(argname, env, sig, pstate, traces); - return val; - } - - double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi) - { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - Number_Ptr val = get_arg(argname, env, sig, pstate, traces); - Number tmpnr(val); - tmpnr.reduce(); - double v = tmpnr.value(); - if (!(lo <= v && v <= hi)) { - std::stringstream msg; - msg << "argument `" << argname << "` of `" << sig << "` must be between "; - msg << lo << " and " << hi; - error(msg.str(), pstate, traces); - } - return v; - } - - Number_Ptr get_arg_n(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) - { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - Number_Ptr val = get_arg(argname, env, sig, pstate, traces); - val = SASS_MEMORY_COPY(val); - val->reduce(); - return val; - } - - double get_arg_v(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) - { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - Number_Ptr val = get_arg(argname, env, sig, pstate, traces); - Number tmpnr(val); - tmpnr.reduce(); - /* - if (tmpnr.unit() == "%") { - tmpnr.value(tmpnr.value() / 100); - tmpnr.numerators.clear(); - } else { - if (!tmpnr.is_unitless()) error("argument " + argname + " of `" + std::string(sig) + "` must be unitless", pstate); - } - */ - return tmpnr.value(); - } - - double get_arg_val(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) - { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - Number_Ptr val = get_arg(argname, env, sig, pstate, traces); - Number tmpnr(val); - tmpnr.reduce(); - return tmpnr.value(); - } - - double color_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) - { - Number_Ptr val = get_arg(argname, env, sig, pstate, traces); - Number tmpnr(val); - tmpnr.reduce(); - if (tmpnr.unit() == "%") { - return std::min(std::max(tmpnr.value() * 255 / 100.0, 0.0), 255.0); - } else { - return std::min(std::max(tmpnr.value(), 0.0), 255.0); - } - } - - - inline double alpha_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) { - Number_Ptr val = get_arg(argname, env, sig, pstate, traces); - Number tmpnr(val); - tmpnr.reduce(); - if (tmpnr.unit() == "%") { - return std::min(std::max(tmpnr.value(), 0.0), 100.0); - } else { - return std::min(std::max(tmpnr.value(), 0.0), 1.0); - } - } - - #define ARGSEL(argname, seltype, contextualize) get_arg_sel(argname, env, sig, pstate, traces, ctx) - - template - T get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx); - - template <> - Selector_List_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) { - Expression_Obj exp = ARG(argname, Expression); - if (exp->concrete_type() == Expression::NULL_VAL) { - std::stringstream msg; - msg << argname << ": null is not a valid selector: it must be a string,\n"; - msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'"; - error(msg.str(), pstate, traces); - } - if (String_Constant_Ptr str = Cast(exp)) { - str->quote_mark(0); - } - std::string exp_src = exp->to_string(ctx.c_options); - return Parser::parse_selector(exp_src.c_str(), ctx, traces); - } - - template <> - Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) { - Expression_Obj exp = ARG(argname, Expression); - if (exp->concrete_type() == Expression::NULL_VAL) { - std::stringstream msg; - msg << argname << ": null is not a string for `" << function_name(sig) << "'"; - error(msg.str(), pstate, traces); - } - if (String_Constant_Ptr str = Cast(exp)) { - str->quote_mark(0); - } - std::string exp_src = exp->to_string(ctx.c_options); - Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx, traces); - if (sel_list->length() == 0) return NULL; - Complex_Selector_Obj first = sel_list->first(); - if (!first->tail()) return first->head(); - return first->tail()->head(); - } - #ifdef __MINGW32__ uint64_t GetSeed() { @@ -2097,8 +1894,8 @@ namespace Sass { Signature selector_unify_sig = "selector-unify($selector1, $selector2)"; BUILT_IN(selector_unify) { - Selector_List_Obj selector1 = ARGSEL("$selector1", Selector_List_Obj, p_contextualize); - Selector_List_Obj selector2 = ARGSEL("$selector2", Selector_List_Obj, p_contextualize); + Selector_List_Obj selector1 = ARGSELS("$selector1"); + Selector_List_Obj selector2 = ARGSELS("$selector2"); Selector_List_Obj result = selector1->unify_with(selector2); Listize listize; @@ -2108,7 +1905,7 @@ namespace Sass { Signature simple_selectors_sig = "simple-selectors($selector)"; BUILT_IN(simple_selectors) { - Compound_Selector_Obj sel = ARGSEL("$selector", Compound_Selector_Obj, p_contextualize); + Compound_Selector_Obj sel = ARGSEL("$selector"); List_Ptr l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA); @@ -2125,9 +1922,9 @@ namespace Sass { Signature selector_extend_sig = "selector-extend($selector, $extendee, $extender)"; BUILT_IN(selector_extend) { - Selector_List_Obj selector = ARGSEL("$selector", Selector_List_Obj, p_contextualize); - Selector_List_Obj extendee = ARGSEL("$extendee", Selector_List_Obj, p_contextualize); - Selector_List_Obj extender = ARGSEL("$extender", Selector_List_Obj, p_contextualize); + Selector_List_Obj selector = ARGSELS("$selector"); + Selector_List_Obj extendee = ARGSELS("$extendee"); + Selector_List_Obj extender = ARGSELS("$extender"); Subset_Map subset_map; extender->populate_extends(extendee, subset_map); @@ -2142,9 +1939,9 @@ namespace Sass { Signature selector_replace_sig = "selector-replace($selector, $original, $replacement)"; BUILT_IN(selector_replace) { - Selector_List_Obj selector = ARGSEL("$selector", Selector_List_Obj, p_contextualize); - Selector_List_Obj original = ARGSEL("$original", Selector_List_Obj, p_contextualize); - Selector_List_Obj replacement = ARGSEL("$replacement", Selector_List_Obj, p_contextualize); + Selector_List_Obj selector = ARGSELS("$selector"); + Selector_List_Obj original = ARGSELS("$original"); + Selector_List_Obj replacement = ARGSELS("$replacement"); Subset_Map subset_map; replacement->populate_extends(original, subset_map); Extend extend(subset_map); @@ -2158,7 +1955,7 @@ namespace Sass { Signature selector_parse_sig = "selector-parse($selector)"; BUILT_IN(selector_parse) { - Selector_List_Obj sel = ARGSEL("$selector", Selector_List_Obj, p_contextualize); + Selector_List_Obj sel = ARGSELS("$selector"); Listize listize; return sel->perform(&listize); @@ -2167,8 +1964,8 @@ namespace Sass { Signature is_superselector_sig = "is-superselector($super, $sub)"; BUILT_IN(is_superselector) { - Selector_List_Obj sel_sup = ARGSEL("$super", Selector_List_Obj, p_contextualize); - Selector_List_Obj sel_sub = ARGSEL("$sub", Selector_List_Obj, p_contextualize); + Selector_List_Obj sel_sup = ARGSELS("$super"); + Selector_List_Obj sel_sub = ARGSELS("$sub"); bool result = sel_sup->is_superselector_of(sel_sub); return SASS_MEMORY_NEW(Boolean, pstate, result); } diff --git a/src/functions.hpp b/src/functions.hpp index 7019be934..fa6d5d7f0 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -6,18 +6,13 @@ #include "environment.hpp" #include "ast_fwd_decl.hpp" #include "sass/functions.h" - -#define BUILT_IN(name) Expression_Ptr \ -name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, std::vector selector_stack) +#include "fn_utils.hpp" namespace Sass { struct Backtrace; typedef const char* Signature; typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, std::vector); - Definition_Ptr make_native_function(Signature, Native_Function, Context& ctx); - Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx); - std::string function_name(Signature); namespace Functions { diff --git a/src/sass_functions.hpp b/src/sass_functions.hpp index 3b646d67e..482ed641b 100644 --- a/src/sass_functions.hpp +++ b/src/sass_functions.hpp @@ -3,7 +3,7 @@ #include "sass.h" #include "environment.hpp" -#include "functions.hpp" +#include "fn_utils.hpp" // Struct to hold custom function callback struct Sass_Function { From c07f4a333cbe35f276dab3f5f0ac0336dcca88ba Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 01:39:27 +0100 Subject: [PATCH 03/30] Protect some header defines from redefining --- src/sass.hpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/sass.hpp b/src/sass.hpp index f0550490c..68f15f923 100644 --- a/src/sass.hpp +++ b/src/sass.hpp @@ -14,11 +14,17 @@ // aplies to MSVC and MinGW #ifdef _WIN32 // we do not want the ERROR macro -# define NOGDI +# ifndef NOGDI +# define NOGDI +# endif // we do not want the min/max macro -# define NOMINMAX +# ifndef NOMINMAX +# define NOMINMAX +# endif // we do not want the IN/OUT macro -# define _NO_W32_PSEUDO_MODIFIERS +# ifndef _NO_W32_PSEUDO_MODIFIERS +# define _NO_W32_PSEUDO_MODIFIERS +# endif #endif From 8b74edeeff0838dd18ead666eb4fb257220692e2 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 01:50:24 +0100 Subject: [PATCH 04/30] Move number functions to own compile unit --- Makefile.conf | 1 + src/fn_numbers.cpp | 217 ++++++++++++++++++++++++++++++++++++ src/fn_numbers.hpp | 45 ++++++++ src/fn_utils.hpp | 3 - src/functions.hpp | 25 ----- win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 + 7 files changed, 271 insertions(+), 28 deletions(-) create mode 100644 src/fn_numbers.cpp create mode 100644 src/fn_numbers.hpp diff --git a/Makefile.conf b/Makefile.conf index 161ee9767..8ebba3ad2 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -11,6 +11,7 @@ SOURCES = \ context.cpp \ constants.cpp \ fn_utils.cpp \ + fn_numbers.cpp \ functions.cpp \ color_maps.cpp \ environment.cpp \ diff --git a/src/fn_numbers.cpp b/src/fn_numbers.cpp new file mode 100644 index 000000000..249d69856 --- /dev/null +++ b/src/fn_numbers.cpp @@ -0,0 +1,217 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ast.hpp" +#include "sass.hpp" +#include "units.hpp" +#include "fn_utils.hpp" +#include "fn_numbers.hpp" + +#ifdef __MINGW32__ +#include "windows.h" +#include "wincrypt.h" +#endif + +namespace Sass { + + namespace Functions { + + #ifdef __MINGW32__ + uint64_t GetSeed() + { + HCRYPTPROV hp = 0; + BYTE rb[8]; + CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); + CryptGenRandom(hp, sizeof(rb), rb); + CryptReleaseContext(hp, 0); + + uint64_t seed; + memcpy(&seed, &rb[0], sizeof(seed)); + + return seed; + } + #else + uint64_t GetSeed() + { + std::random_device rd; + return rd(); + } + #endif + + // note: the performance of many implementations of + // random_device degrades sharply once the entropy pool + // is exhausted. For practical use, random_device is + // generally only used to seed a PRNG such as mt19937. + static std::mt19937 rand(static_cast(GetSeed())); + + /////////////////// + // NUMBER FUNCTIONS + /////////////////// + + Signature percentage_sig = "percentage($number)"; + BUILT_IN(percentage) + { + Number_Obj n = ARGN("$number"); + if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate, traces); + return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%"); + } + + Signature round_sig = "round($number)"; + BUILT_IN(round) + { + Number_Obj r = ARGN("$number"); + r->value(Sass::round(r->value(), ctx.c_options.precision)); + r->pstate(pstate); + return r.detach(); + } + + Signature ceil_sig = "ceil($number)"; + BUILT_IN(ceil) + { + Number_Obj r = ARGN("$number"); + r->value(std::ceil(r->value())); + r->pstate(pstate); + return r.detach(); + } + + Signature floor_sig = "floor($number)"; + BUILT_IN(floor) + { + Number_Obj r = ARGN("$number"); + r->value(std::floor(r->value())); + r->pstate(pstate); + return r.detach(); + } + + Signature abs_sig = "abs($number)"; + BUILT_IN(abs) + { + Number_Obj r = ARGN("$number"); + r->value(std::abs(r->value())); + r->pstate(pstate); + return r.detach(); + } + + Signature min_sig = "min($numbers...)"; + BUILT_IN(min) + { + List_Ptr arglist = ARG("$numbers", List); + Number_Obj least = NULL; + for (size_t i = 0, L = arglist->length(); i < L; ++i) { + Expression_Obj val = arglist->value_at_index(i); + Number_Obj xi = Cast(val); + if (!xi) { + error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate, traces); + } + if (least) { + if (*xi < *least) least = xi; + } else least = xi; + } + return least.detach(); + } + + Signature max_sig = "max($numbers...)"; + BUILT_IN(max) + { + List_Ptr arglist = ARG("$numbers", List); + Number_Obj greatest = NULL; + for (size_t i = 0, L = arglist->length(); i < L; ++i) { + Expression_Obj val = arglist->value_at_index(i); + Number_Obj xi = Cast(val); + if (!xi) { + error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate, traces); + } + if (greatest) { + if (*greatest < *xi) greatest = xi; + } else greatest = xi; + } + return greatest.detach(); + } + + Signature random_sig = "random($limit:false)"; + BUILT_IN(random) + { + AST_Node_Obj arg = env["$limit"]; + Value_Ptr v = Cast(arg); + Number_Ptr l = Cast(arg); + Boolean_Ptr b = Cast(arg); + if (l) { + double lv = l->value(); + if (lv < 1) { + std::stringstream err; + err << "$limit " << lv << " must be greater than or equal to 1 for `random'"; + error(err.str(), pstate, traces); + } + bool eq_int = std::fabs(trunc(lv) - lv) < NUMBER_EPSILON; + if (!eq_int) { + std::stringstream err; + err << "Expected $limit to be an integer but got " << lv << " for `random'"; + error(err.str(), pstate, traces); + } + std::uniform_real_distribution<> distributor(1, lv + 1); + uint_fast32_t distributed = static_cast(distributor(rand)); + return SASS_MEMORY_NEW(Number, pstate, (double)distributed); + } + else if (b) { + std::uniform_real_distribution<> distributor(0, 1); + double distributed = static_cast(distributor(rand)); + return SASS_MEMORY_NEW(Number, pstate, distributed); + } else if (v) { + traces.push_back(Backtrace(pstate)); + throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number", v); + } else { + traces.push_back(Backtrace(pstate)); + throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number"); + } + } + + Signature unique_id_sig = "unique-id()"; + BUILT_IN(unique_id) + { + std::stringstream ss; + std::uniform_real_distribution<> distributor(0, 4294967296); // 16^8 + uint_fast32_t distributed = static_cast(distributor(rand)); + ss << "u" << std::setfill('0') << std::setw(8) << std::hex << distributed; + return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str()); + } + + Signature unit_sig = "unit($number)"; + BUILT_IN(unit) + { + Number_Obj arg = ARGN("$number"); + std::string str(quote(arg->unit(), '"')); + return SASS_MEMORY_NEW(String_Quoted, pstate, str); + } + + Signature unitless_sig = "unitless($number)"; + BUILT_IN(unitless) + { + Number_Obj arg = ARGN("$number"); + bool unitless = arg->is_unitless(); + return SASS_MEMORY_NEW(Boolean, pstate, unitless); + } + + Signature comparable_sig = "comparable($number-1, $number-2)"; + BUILT_IN(comparable) + { + Number_Obj n1 = ARGN("$number-1"); + Number_Obj n2 = ARGN("$number-2"); + if (n1->is_unitless() || n2->is_unitless()) { + return SASS_MEMORY_NEW(Boolean, pstate, true); + } + // normalize into main units + n1->normalize(); n2->normalize(); + Units &lhs_unit = *n1, &rhs_unit = *n2; + bool is_comparable = (lhs_unit == rhs_unit); + return SASS_MEMORY_NEW(Boolean, pstate, is_comparable); + } + + } + +} \ No newline at end of file diff --git a/src/fn_numbers.hpp b/src/fn_numbers.hpp new file mode 100644 index 000000000..dba96be0b --- /dev/null +++ b/src/fn_numbers.hpp @@ -0,0 +1,45 @@ +#ifndef SASS_FN_NUMBERS_H +#define SASS_FN_NUMBERS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + // return a number object (copied since we want to have reduced units) + #define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy + + extern Signature percentage_sig; + extern Signature round_sig; + extern Signature ceil_sig; + extern Signature floor_sig; + extern Signature abs_sig; + extern Signature min_sig; + extern Signature max_sig; + extern Signature inspect_sig; + extern Signature random_sig; + extern Signature unique_id_sig; + extern Signature unit_sig; + extern Signature unitless_sig; + extern Signature comparable_sig; + + BUILT_IN(percentage); + BUILT_IN(round); + BUILT_IN(ceil); + BUILT_IN(floor); + BUILT_IN(abs); + BUILT_IN(min); + BUILT_IN(max); + BUILT_IN(inspect); + BUILT_IN(random); + BUILT_IN(unique_id); + BUILT_IN(unit); + BUILT_IN(unitless); + BUILT_IN(comparable); + + } + +} + +#endif \ No newline at end of file diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index eaeac0228..c373a71fb 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -13,9 +13,6 @@ namespace Sass { #define ARG(argname, argtype) get_arg(argname, env, sig, pstate, traces) #define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces) - // return a number object (copied since we want to have reduced units) - #define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy - // special function for weird hsla percent (10px == 10% == 10 != 0.1) #define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double diff --git a/src/functions.hpp b/src/functions.hpp index fa6d5d7f0..23a789930 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -55,15 +55,6 @@ namespace Sass { extern Signature str_slice_sig; extern Signature to_upper_case_sig; extern Signature to_lower_case_sig; - extern Signature percentage_sig; - extern Signature round_sig; - extern Signature ceil_sig; - extern Signature floor_sig; - extern Signature abs_sig; - extern Signature min_sig; - extern Signature max_sig; - extern Signature inspect_sig; - extern Signature random_sig; extern Signature length_sig; extern Signature nth_sig; extern Signature index_sig; @@ -72,9 +63,6 @@ namespace Sass { extern Signature zip_sig; extern Signature list_separator_sig; extern Signature type_of_sig; - extern Signature unit_sig; - extern Signature unitless_sig; - extern Signature comparable_sig; extern Signature variable_exists_sig; extern Signature global_variable_exists_sig; extern Signature function_exists_sig; @@ -91,7 +79,6 @@ namespace Sass { extern Signature map_has_key_sig; extern Signature keywords_sig; extern Signature set_nth_sig; - extern Signature unique_id_sig; extern Signature selector_nest_sig; extern Signature selector_append_sig; extern Signature selector_extend_sig; @@ -139,15 +126,7 @@ namespace Sass { BUILT_IN(str_slice); BUILT_IN(to_upper_case); BUILT_IN(to_lower_case); - BUILT_IN(percentage); - BUILT_IN(round); - BUILT_IN(ceil); - BUILT_IN(floor); - BUILT_IN(abs); - BUILT_IN(min); - BUILT_IN(max); BUILT_IN(inspect); - BUILT_IN(random); BUILT_IN(length); BUILT_IN(nth); BUILT_IN(index); @@ -156,9 +135,6 @@ namespace Sass { BUILT_IN(zip); BUILT_IN(list_separator); BUILT_IN(type_of); - BUILT_IN(unit); - BUILT_IN(unitless); - BUILT_IN(comparable); BUILT_IN(variable_exists); BUILT_IN(global_variable_exists); BUILT_IN(function_exists); @@ -175,7 +151,6 @@ namespace Sass { BUILT_IN(map_has_key); BUILT_IN(keywords); BUILT_IN(set_nth); - BUILT_IN(unique_id); BUILT_IN(selector_nest); BUILT_IN(selector_append); BUILT_IN(selector_extend); diff --git a/win/libsass.targets b/win/libsass.targets index 8bf68df60..176f29e2a 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -34,6 +34,7 @@ + @@ -88,6 +89,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 1f301f769..46f42ae59 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -114,6 +114,9 @@ Headers + + Headers + Headers @@ -275,6 +278,9 @@ Sources + + Sources + Sources From 83f641c5b71bc1622d9ce78a4c721c0fd753b799 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 01:54:16 +0100 Subject: [PATCH 05/30] Move selector functions to own compile unit Remove selector signatures --- Makefile.conf | 1 + src/context.cpp | 2 + src/fn_selectors.cpp | 238 ++++++++++++++++++++ src/fn_selectors.hpp | 35 +++ src/fn_utils.hpp | 3 - src/functions.cpp | 424 +----------------------------------- src/functions.hpp | 16 -- win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 + 9 files changed, 286 insertions(+), 441 deletions(-) create mode 100644 src/fn_selectors.cpp create mode 100644 src/fn_selectors.hpp diff --git a/Makefile.conf b/Makefile.conf index 8ebba3ad2..e13fc1baf 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -12,6 +12,7 @@ SOURCES = \ constants.cpp \ fn_utils.cpp \ fn_numbers.cpp \ + fn_selectors.cpp \ functions.cpp \ color_maps.cpp \ environment.cpp \ diff --git a/src/context.cpp b/src/context.cpp index 272b99cb1..0fdc614f5 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -30,6 +30,8 @@ #include "prelexer.hpp" #include "emitter.hpp" #include "fn_utils.hpp" +#include "fn_numbers.hpp" +#include "fn_selectors.hpp" namespace Sass { using namespace Constants; diff --git a/src/fn_selectors.cpp b/src/fn_selectors.cpp new file mode 100644 index 000000000..eff7b0dad --- /dev/null +++ b/src/fn_selectors.cpp @@ -0,0 +1,238 @@ +#include "parser.hpp" +#include "extend.hpp" +#include "fn_utils.hpp" +#include "fn_selectors.hpp" + +namespace Sass { + + namespace Functions { + + Signature selector_nest_sig = "selector-nest($selectors...)"; + BUILT_IN(selector_nest) + { + List_Ptr arglist = ARG("$selectors", List); + + // Not enough parameters + if( arglist->length() == 0 ) + error("$selectors: At least one selector must be passed for `selector-nest'", pstate, traces); + + // Parse args into vector of selectors + SelectorStack parsedSelectors; + for (size_t i = 0, L = arglist->length(); i < L; ++i) { + Expression_Obj exp = Cast(arglist->value_at_index(i)); + if (exp->concrete_type() == Expression::NULL_VAL) { + std::stringstream msg; + msg << "$selectors: null is not a valid selector: it must be a string,\n"; + msg << "a list of strings, or a list of lists of strings for 'selector-nest'"; + error(msg.str(), pstate, traces); + } + if (String_Constant_Obj str = Cast(exp)) { + str->quote_mark(0); + } + std::string exp_src = exp->to_string(ctx.c_options); + Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces); + parsedSelectors.push_back(sel); + } + + // Nothing to do + if( parsedSelectors.empty() ) { + return SASS_MEMORY_NEW(Null, pstate); + } + + // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector. + SelectorStack::iterator itr = parsedSelectors.begin(); + Selector_List_Obj result = *itr; + ++itr; + + for(;itr != parsedSelectors.end(); ++itr) { + Selector_List_Obj child = *itr; + std::vector exploded; + selector_stack.push_back(result); + Selector_List_Obj rv = child->resolve_parent_refs(selector_stack, traces); + selector_stack.pop_back(); + for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) { + exploded.push_back((*rv)[m]); + } + result->elements(exploded); + } + + Listize listize; + return Cast(result->perform(&listize)); + } + + Signature selector_append_sig = "selector-append($selectors...)"; + BUILT_IN(selector_append) + { + List_Ptr arglist = ARG("$selectors", List); + + // Not enough parameters + if( arglist->length() == 0 ) + error("$selectors: At least one selector must be passed for `selector-append'", pstate, traces); + + // Parse args into vector of selectors + SelectorStack parsedSelectors; + for (size_t i = 0, L = arglist->length(); i < L; ++i) { + Expression_Obj exp = Cast(arglist->value_at_index(i)); + if (exp->concrete_type() == Expression::NULL_VAL) { + std::stringstream msg; + msg << "$selectors: null is not a valid selector: it must be a string,\n"; + msg << "a list of strings, or a list of lists of strings for 'selector-append'"; + error(msg.str(), pstate, traces); + } + if (String_Constant_Ptr str = Cast(exp)) { + str->quote_mark(0); + } + std::string exp_src = exp->to_string(); + Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces); + parsedSelectors.push_back(sel); + } + + // Nothing to do + if( parsedSelectors.empty() ) { + return SASS_MEMORY_NEW(Null, pstate); + } + + // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector. + SelectorStack::iterator itr = parsedSelectors.begin(); + Selector_List_Obj result = *itr; + ++itr; + + for(;itr != parsedSelectors.end(); ++itr) { + Selector_List_Obj child = *itr; + std::vector newElements; + + // For every COMPLEX_SELECTOR in `result` + // For every COMPLEX_SELECTOR in `child` + // let parentSeqClone equal a copy of result->elements[i] + // let childSeq equal child->elements[j] + // Append all of childSeq head elements into parentSeqClone + // Set the innermost tail of parentSeqClone, to childSeq's tail + // Replace result->elements with newElements + for (size_t i = 0, resultLen = result->length(); i < resultLen; ++i) { + for (size_t j = 0, childLen = child->length(); j < childLen; ++j) { + Complex_Selector_Obj parentSeqClone = SASS_MEMORY_CLONE((*result)[i]); + Complex_Selector_Obj childSeq = (*child)[j]; + Complex_Selector_Obj base = childSeq->tail(); + + // Must be a simple sequence + if( childSeq->combinator() != Complex_Selector::Combinator::ANCESTOR_OF ) { + std::string msg("Can't append \""); + msg += childSeq->to_string(); + msg += "\" to \""; + msg += parentSeqClone->to_string(); + msg += "\" for `selector-append'"; + error(msg, pstate, traces); + } + + // Cannot be a Universal selector + Element_Selector_Obj pType = Cast(childSeq->head()->first()); + if(pType && pType->name() == "*") { + std::string msg("Can't append \""); + msg += childSeq->to_string(); + msg += "\" to \""; + msg += parentSeqClone->to_string(); + msg += "\" for `selector-append'"; + error(msg, pstate, traces); + } + + // TODO: Add check for namespace stuff + + // append any selectors in childSeq's head + parentSeqClone->innermost()->head()->concat(base->head()); + + // Set parentSeqClone new tail + parentSeqClone->innermost()->tail( base->tail() ); + + newElements.push_back(parentSeqClone); + } + } + + result->elements(newElements); + } + + Listize listize; + return Cast(result->perform(&listize)); + } + + Signature selector_unify_sig = "selector-unify($selector1, $selector2)"; + BUILT_IN(selector_unify) + { + Selector_List_Obj selector1 = ARGSELS("$selector1"); + Selector_List_Obj selector2 = ARGSELS("$selector2"); + + Selector_List_Obj result = selector1->unify_with(selector2); + Listize listize; + return Cast(result->perform(&listize)); + } + + Signature simple_selectors_sig = "simple-selectors($selector)"; + BUILT_IN(simple_selectors) + { + Compound_Selector_Obj sel = ARGSEL("$selector"); + + List_Ptr l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA); + + for (size_t i = 0, L = sel->length(); i < L; ++i) { + Simple_Selector_Obj ss = (*sel)[i]; + std::string ss_string = ss->to_string() ; + + l->append(SASS_MEMORY_NEW(String_Quoted, ss->pstate(), ss_string)); + } + + return l; + } + + Signature selector_extend_sig = "selector-extend($selector, $extendee, $extender)"; + BUILT_IN(selector_extend) + { + Selector_List_Obj selector = ARGSELS("$selector"); + Selector_List_Obj extendee = ARGSELS("$extendee"); + Selector_List_Obj extender = ARGSELS("$extender"); + + Subset_Map subset_map; + extender->populate_extends(extendee, subset_map); + Extend extend(subset_map); + + Selector_List_Obj result = extend.extendSelectorList(selector, false); + + Listize listize; + return Cast(result->perform(&listize)); + } + + Signature selector_replace_sig = "selector-replace($selector, $original, $replacement)"; + BUILT_IN(selector_replace) + { + Selector_List_Obj selector = ARGSELS("$selector"); + Selector_List_Obj original = ARGSELS("$original"); + Selector_List_Obj replacement = ARGSELS("$replacement"); + Subset_Map subset_map; + replacement->populate_extends(original, subset_map); + Extend extend(subset_map); + + Selector_List_Obj result = extend.extendSelectorList(selector, true); + + Listize listize; + return Cast(result->perform(&listize)); + } + + Signature selector_parse_sig = "selector-parse($selector)"; + BUILT_IN(selector_parse) + { + Selector_List_Obj sel = ARGSELS("$selector"); + + Listize listize; + return Cast(sel->perform(&listize)); + } + + Signature is_superselector_sig = "is-superselector($super, $sub)"; + BUILT_IN(is_superselector) + { + Selector_List_Obj sel_sup = ARGSELS("$super"); + Selector_List_Obj sel_sub = ARGSELS("$sub"); + bool result = sel_sup->is_superselector_of(sel_sub); + return SASS_MEMORY_NEW(Boolean, pstate, result); + } + + } + +} \ No newline at end of file diff --git a/src/fn_selectors.hpp b/src/fn_selectors.hpp new file mode 100644 index 000000000..d5c106cd2 --- /dev/null +++ b/src/fn_selectors.hpp @@ -0,0 +1,35 @@ +#ifndef SASS_FN_SELECTORS_H +#define SASS_FN_SELECTORS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + #define ARGSEL(argname) get_arg_sel(argname, env, sig, pstate, traces, ctx) + #define ARGSELS(argname) get_arg_sels(argname, env, sig, pstate, traces, ctx) + + BUILT_IN(selector_nest); + BUILT_IN(selector_append); + BUILT_IN(selector_extend); + BUILT_IN(selector_replace); + BUILT_IN(selector_unify); + BUILT_IN(is_superselector); + BUILT_IN(simple_selectors); + BUILT_IN(selector_parse); + + extern Signature selector_nest_sig; + extern Signature selector_append_sig; + extern Signature selector_extend_sig; + extern Signature selector_replace_sig; + extern Signature selector_unify_sig; + extern Signature is_superselector_sig; + extern Signature simple_selectors_sig; + extern Signature selector_parse_sig; + + } + +} + +#endif diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index c373a71fb..0cd66b002 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -28,9 +28,6 @@ namespace Sass { #define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double #define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double - #define ARGSEL(argname) get_arg_sel(argname, env, sig, pstate, traces, ctx) - #define ARGSELS(argname) get_arg_sels(argname, env, sig, pstate, traces, ctx) - typedef const char* Signature; typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); diff --git a/src/functions.cpp b/src/functions.cpp index b3fdf44f7..b2a0306a8 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -23,15 +23,11 @@ #include #include #include -#include #include -#ifdef __MINGW32__ -#include "windows.h" -#include "wincrypt.h" -#endif - #include "fn_utils.hpp" +#include "fn_numbers.hpp" +#include "fn_selectors.hpp" namespace Sass { using std::stringstream; @@ -65,34 +61,6 @@ namespace Sass { catch (...) { throw; } } - #ifdef __MINGW32__ - uint64_t GetSeed() - { - HCRYPTPROV hp = 0; - BYTE rb[8]; - CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - CryptGenRandom(hp, sizeof(rb), rb); - CryptReleaseContext(hp, 0); - - uint64_t seed; - memcpy(&seed, &rb[0], sizeof(seed)); - - return seed; - } - #else - uint64_t GetSeed() - { - std::random_device rd; - return rd(); - } - #endif - - // note: the performance of many implementations of - // random_device degrades sharply once the entropy pool - // is exhausted. For practical use, random_device is - // generally only used to seed a PRNG such as mt19937. - static std::mt19937 rand(static_cast(GetSeed())); - // features static std::set features { "global-variable-shadowing", @@ -1057,128 +1025,6 @@ namespace Sass { return SASS_MEMORY_NEW(String_Quoted, pstate, str); } } - - /////////////////// - // NUMBER FUNCTIONS - /////////////////// - - Signature percentage_sig = "percentage($number)"; - BUILT_IN(percentage) - { - Number_Obj n = ARGN("$number"); - if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate, traces); - return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%"); - } - - Signature round_sig = "round($number)"; - BUILT_IN(round) - { - Number_Obj r = ARGN("$number"); - r->value(Sass::round(r->value(), ctx.c_options.precision)); - r->pstate(pstate); - return r.detach(); - } - - Signature ceil_sig = "ceil($number)"; - BUILT_IN(ceil) - { - Number_Obj r = ARGN("$number"); - r->value(std::ceil(r->value())); - r->pstate(pstate); - return r.detach(); - } - - Signature floor_sig = "floor($number)"; - BUILT_IN(floor) - { - Number_Obj r = ARGN("$number"); - r->value(std::floor(r->value())); - r->pstate(pstate); - return r.detach(); - } - - Signature abs_sig = "abs($number)"; - BUILT_IN(abs) - { - Number_Obj r = ARGN("$number"); - r->value(std::abs(r->value())); - r->pstate(pstate); - return r.detach(); - } - - Signature min_sig = "min($numbers...)"; - BUILT_IN(min) - { - List_Ptr arglist = ARG("$numbers", List); - Number_Obj least = NULL; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj val = arglist->value_at_index(i); - Number_Obj xi = Cast(val); - if (!xi) { - error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate, traces); - } - if (least) { - if (*xi < *least) least = xi; - } else least = xi; - } - return least.detach(); - } - - Signature max_sig = "max($numbers...)"; - BUILT_IN(max) - { - List_Ptr arglist = ARG("$numbers", List); - Number_Obj greatest = NULL; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj val = arglist->value_at_index(i); - Number_Obj xi = Cast(val); - if (!xi) { - error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate, traces); - } - if (greatest) { - if (*greatest < *xi) greatest = xi; - } else greatest = xi; - } - return greatest.detach(); - } - - Signature random_sig = "random($limit:false)"; - BUILT_IN(random) - { - AST_Node_Obj arg = env["$limit"]; - Value_Ptr v = Cast(arg); - Number_Ptr l = Cast(arg); - Boolean_Ptr b = Cast(arg); - if (l) { - double lv = l->value(); - if (lv < 1) { - stringstream err; - err << "$limit " << lv << " must be greater than or equal to 1 for `random'"; - error(err.str(), pstate, traces); - } - bool eq_int = std::fabs(trunc(lv) - lv) < NUMBER_EPSILON; - if (!eq_int) { - stringstream err; - err << "Expected $limit to be an integer but got " << lv << " for `random'"; - error(err.str(), pstate, traces); - } - std::uniform_real_distribution<> distributor(1, lv + 1); - uint_fast32_t distributed = static_cast(distributor(rand)); - return SASS_MEMORY_NEW(Number, pstate, (double)distributed); - } - else if (b) { - std::uniform_real_distribution<> distributor(0, 1); - double distributed = static_cast(distributor(rand)); - return SASS_MEMORY_NEW(Number, pstate, distributed); - } else if (v) { - traces.push_back(Backtrace(pstate)); - throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number", v); - } else { - traces.push_back(Backtrace(pstate)); - throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number"); - } - } - ///////////////// // LIST FUNCTIONS ///////////////// @@ -1537,37 +1383,6 @@ namespace Sass { return SASS_MEMORY_NEW(String_Quoted, pstate, v->type()); } - Signature unit_sig = "unit($number)"; - BUILT_IN(unit) - { - Number_Obj arg = ARGN("$number"); - std::string str(quote(arg->unit(), '"')); - return SASS_MEMORY_NEW(String_Quoted, pstate, str); - } - - Signature unitless_sig = "unitless($number)"; - BUILT_IN(unitless) - { - Number_Obj arg = ARGN("$number"); - bool unitless = arg->is_unitless(); - return SASS_MEMORY_NEW(Boolean, pstate, unitless); - } - - Signature comparable_sig = "comparable($number-1, $number-2)"; - BUILT_IN(comparable) - { - Number_Obj n1 = ARGN("$number-1"); - Number_Obj n2 = ARGN("$number-2"); - if (n1->is_unitless() || n2->is_unitless()) { - return SASS_MEMORY_NEW(Boolean, pstate, true); - } - // normalize into main units - n1->normalize(); n2->normalize(); - Units &lhs_unit = *n1, &rhs_unit = *n2; - bool is_comparable = (lhs_unit == rhs_unit); - return SASS_MEMORY_NEW(Boolean, pstate, is_comparable); - } - Signature variable_exists_sig = "variable-exists($name)"; BUILT_IN(variable_exists) { @@ -1744,241 +1559,6 @@ namespace Sass { } // return v; } - Signature selector_nest_sig = "selector-nest($selectors...)"; - BUILT_IN(selector_nest) - { - List_Ptr arglist = ARG("$selectors", List); - - // Not enough parameters - if( arglist->length() == 0 ) - error("$selectors: At least one selector must be passed for `selector-nest'", pstate, traces); - - // Parse args into vector of selectors - std::vector parsedSelectors; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj exp = Cast(arglist->value_at_index(i)); - if (exp->concrete_type() == Expression::NULL_VAL) { - std::stringstream msg; - msg << "$selectors: null is not a valid selector: it must be a string,\n"; - msg << "a list of strings, or a list of lists of strings for 'selector-nest'"; - error(msg.str(), pstate, traces); - } - if (String_Constant_Obj str = Cast(exp)) { - str->quote_mark(0); - } - std::string exp_src = exp->to_string(ctx.c_options); - Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces); - parsedSelectors.push_back(sel); - } - - // Nothing to do - if( parsedSelectors.empty() ) { - return SASS_MEMORY_NEW(Null, pstate); - } - - // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector. - std::vector::iterator itr = parsedSelectors.begin(); - Selector_List_Obj result = *itr; - ++itr; - - for(;itr != parsedSelectors.end(); ++itr) { - Selector_List_Obj child = *itr; - std::vector exploded; - selector_stack.push_back(result); - Selector_List_Obj rv = child->resolve_parent_refs(selector_stack, traces); - selector_stack.pop_back(); - for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) { - exploded.push_back((*rv)[m]); - } - result->elements(exploded); - } - - Listize listize; - return result->perform(&listize); - } - - Signature selector_append_sig = "selector-append($selectors...)"; - BUILT_IN(selector_append) - { - List_Ptr arglist = ARG("$selectors", List); - - // Not enough parameters - if( arglist->length() == 0 ) - error("$selectors: At least one selector must be passed for `selector-append'", pstate, traces); - - // Parse args into vector of selectors - std::vector parsedSelectors; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj exp = Cast(arglist->value_at_index(i)); - if (exp->concrete_type() == Expression::NULL_VAL) { - std::stringstream msg; - msg << "$selectors: null is not a valid selector: it must be a string,\n"; - msg << "a list of strings, or a list of lists of strings for 'selector-append'"; - error(msg.str(), pstate, traces); - } - if (String_Constant_Ptr str = Cast(exp)) { - str->quote_mark(0); - } - std::string exp_src = exp->to_string(); - Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces); - parsedSelectors.push_back(sel); - } - - // Nothing to do - if( parsedSelectors.empty() ) { - return SASS_MEMORY_NEW(Null, pstate); - } - - // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector. - std::vector::iterator itr = parsedSelectors.begin(); - Selector_List_Obj result = *itr; - ++itr; - - for(;itr != parsedSelectors.end(); ++itr) { - Selector_List_Obj child = *itr; - std::vector newElements; - - // For every COMPLEX_SELECTOR in `result` - // For every COMPLEX_SELECTOR in `child` - // let parentSeqClone equal a copy of result->elements[i] - // let childSeq equal child->elements[j] - // Append all of childSeq head elements into parentSeqClone - // Set the innermost tail of parentSeqClone, to childSeq's tail - // Replace result->elements with newElements - for (size_t i = 0, resultLen = result->length(); i < resultLen; ++i) { - for (size_t j = 0, childLen = child->length(); j < childLen; ++j) { - Complex_Selector_Obj parentSeqClone = SASS_MEMORY_CLONE((*result)[i]); - Complex_Selector_Obj childSeq = (*child)[j]; - Complex_Selector_Obj base = childSeq->tail(); - - // Must be a simple sequence - if( childSeq->combinator() != Complex_Selector::Combinator::ANCESTOR_OF ) { - std::string msg("Can't append \""); - msg += childSeq->to_string(); - msg += "\" to \""; - msg += parentSeqClone->to_string(); - msg += "\" for `selector-append'"; - error(msg, pstate, traces); - } - - // Cannot be a Universal selector - Element_Selector_Obj pType = Cast(childSeq->head()->first()); - if(pType && pType->name() == "*") { - std::string msg("Can't append \""); - msg += childSeq->to_string(); - msg += "\" to \""; - msg += parentSeqClone->to_string(); - msg += "\" for `selector-append'"; - error(msg, pstate, traces); - } - - // TODO: Add check for namespace stuff - - // append any selectors in childSeq's head - parentSeqClone->innermost()->head()->concat(base->head()); - - // Set parentSeqClone new tail - parentSeqClone->innermost()->tail( base->tail() ); - - newElements.push_back(parentSeqClone); - } - } - - result->elements(newElements); - } - - Listize listize; - return result->perform(&listize); - } - - Signature selector_unify_sig = "selector-unify($selector1, $selector2)"; - BUILT_IN(selector_unify) - { - Selector_List_Obj selector1 = ARGSELS("$selector1"); - Selector_List_Obj selector2 = ARGSELS("$selector2"); - - Selector_List_Obj result = selector1->unify_with(selector2); - Listize listize; - return result->perform(&listize); - } - - Signature simple_selectors_sig = "simple-selectors($selector)"; - BUILT_IN(simple_selectors) - { - Compound_Selector_Obj sel = ARGSEL("$selector"); - - List_Ptr l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA); - - for (size_t i = 0, L = sel->length(); i < L; ++i) { - Simple_Selector_Obj ss = (*sel)[i]; - std::string ss_string = ss->to_string() ; - - l->append(SASS_MEMORY_NEW(String_Quoted, ss->pstate(), ss_string)); - } - - return l; - } - - Signature selector_extend_sig = "selector-extend($selector, $extendee, $extender)"; - BUILT_IN(selector_extend) - { - Selector_List_Obj selector = ARGSELS("$selector"); - Selector_List_Obj extendee = ARGSELS("$extendee"); - Selector_List_Obj extender = ARGSELS("$extender"); - - Subset_Map subset_map; - extender->populate_extends(extendee, subset_map); - Extend extend(subset_map); - - Selector_List_Obj result = extend.extendSelectorList(selector, false); - - Listize listize; - return result->perform(&listize); - } - - Signature selector_replace_sig = "selector-replace($selector, $original, $replacement)"; - BUILT_IN(selector_replace) - { - Selector_List_Obj selector = ARGSELS("$selector"); - Selector_List_Obj original = ARGSELS("$original"); - Selector_List_Obj replacement = ARGSELS("$replacement"); - Subset_Map subset_map; - replacement->populate_extends(original, subset_map); - Extend extend(subset_map); - - Selector_List_Obj result = extend.extendSelectorList(selector, true); - - Listize listize; - return result->perform(&listize); - } - - Signature selector_parse_sig = "selector-parse($selector)"; - BUILT_IN(selector_parse) - { - Selector_List_Obj sel = ARGSELS("$selector"); - - Listize listize; - return sel->perform(&listize); - } - - Signature is_superselector_sig = "is-superselector($super, $sub)"; - BUILT_IN(is_superselector) - { - Selector_List_Obj sel_sup = ARGSELS("$super"); - Selector_List_Obj sel_sub = ARGSELS("$sub"); - bool result = sel_sup->is_superselector_of(sel_sub); - return SASS_MEMORY_NEW(Boolean, pstate, result); - } - - Signature unique_id_sig = "unique-id()"; - BUILT_IN(unique_id) - { - std::stringstream ss; - std::uniform_real_distribution<> distributor(0, 4294967296); // 16^8 - uint_fast32_t distributed = static_cast(distributor(rand)); - ss << "u" << std::setfill('0') << std::setw(8) << std::hex << distributed; - return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str()); - } Signature is_bracketed_sig = "is-bracketed($list)"; BUILT_IN(is_bracketed) diff --git a/src/functions.hpp b/src/functions.hpp index 23a789930..6787fe91d 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -79,14 +79,6 @@ namespace Sass { extern Signature map_has_key_sig; extern Signature keywords_sig; extern Signature set_nth_sig; - extern Signature selector_nest_sig; - extern Signature selector_append_sig; - extern Signature selector_extend_sig; - extern Signature selector_replace_sig; - extern Signature selector_unify_sig; - extern Signature is_superselector_sig; - extern Signature simple_selectors_sig; - extern Signature selector_parse_sig; extern Signature is_bracketed_sig; extern Signature content_exists_sig; extern Signature get_function_sig; @@ -151,14 +143,6 @@ namespace Sass { BUILT_IN(map_has_key); BUILT_IN(keywords); BUILT_IN(set_nth); - BUILT_IN(selector_nest); - BUILT_IN(selector_append); - BUILT_IN(selector_extend); - BUILT_IN(selector_replace); - BUILT_IN(selector_unify); - BUILT_IN(is_superselector); - BUILT_IN(simple_selectors); - BUILT_IN(selector_parse); BUILT_IN(is_bracketed); BUILT_IN(content_exists); BUILT_IN(get_function); diff --git a/win/libsass.targets b/win/libsass.targets index 176f29e2a..2af43d6db 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -35,6 +35,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 46f42ae59..6c13df030 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -117,6 +117,9 @@ Headers + + Headers + Headers @@ -281,6 +284,9 @@ Sources + + Sources + Sources From 37cfb4c265050a7671385544505de32fc1f41c23 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 01:59:55 +0100 Subject: [PATCH 06/30] Move color functions to own compile unit --- Makefile.conf | 1 + src/context.cpp | 1 + src/fn_colors.cpp | 741 ++++++++++++++++++++++++++++++++++++ src/fn_colors.hpp | 85 +++++ src/fn_utils.cpp | 1 - src/fn_utils.hpp | 3 +- src/functions.cpp | 730 +---------------------------------- src/functions.hpp | 57 --- win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 + 10 files changed, 839 insertions(+), 788 deletions(-) create mode 100644 src/fn_colors.cpp create mode 100644 src/fn_colors.hpp diff --git a/Makefile.conf b/Makefile.conf index e13fc1baf..08c455667 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -11,6 +11,7 @@ SOURCES = \ context.cpp \ constants.cpp \ fn_utils.cpp \ + fn_colors.cpp \ fn_numbers.cpp \ fn_selectors.cpp \ functions.cpp \ diff --git a/src/context.cpp b/src/context.cpp index 0fdc614f5..58dbc7663 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -30,6 +30,7 @@ #include "prelexer.hpp" #include "emitter.hpp" #include "fn_utils.hpp" +#include "fn_colors.hpp" #include "fn_numbers.hpp" #include "fn_selectors.hpp" diff --git a/src/fn_colors.cpp b/src/fn_colors.cpp new file mode 100644 index 000000000..cc4613b6a --- /dev/null +++ b/src/fn_colors.cpp @@ -0,0 +1,741 @@ +#include +#include "ast.hpp" +#include "fn_utils.hpp" +#include "fn_colors.hpp" + +namespace Sass { + + namespace Functions { + + bool special_number(String_Constant_Ptr s) { + if (s) { + std::string calc("calc("); + std::string var("var("); + std::string ss(s->value()); + return std::equal(calc.begin(), calc.end(), ss.begin()) || + std::equal(var.begin(), var.end(), ss.begin()); + } + return false; + } + + Signature rgb_sig = "rgb($red, $green, $blue)"; + BUILT_IN(rgb) + { + if ( + special_number(Cast(env["$red"])) || + special_number(Cast(env["$green"])) || + special_number(Cast(env["$blue"])) + ) { + return SASS_MEMORY_NEW(String_Constant, pstate, "rgb(" + + env["$red"]->to_string() + + ", " + + env["$green"]->to_string() + + ", " + + env["$blue"]->to_string() + + ")" + ); + } + + return SASS_MEMORY_NEW(Color, + pstate, + COLOR_NUM("$red"), + COLOR_NUM("$green"), + COLOR_NUM("$blue")); + } + + Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)"; + BUILT_IN(rgba_4) + { + if ( + special_number(Cast(env["$red"])) || + special_number(Cast(env["$green"])) || + special_number(Cast(env["$blue"])) || + special_number(Cast(env["$alpha"])) + ) { + return SASS_MEMORY_NEW(String_Constant, pstate, "rgba(" + + env["$red"]->to_string() + + ", " + + env["$green"]->to_string() + + ", " + + env["$blue"]->to_string() + + ", " + + env["$alpha"]->to_string() + + ")" + ); + } + + return SASS_MEMORY_NEW(Color, + pstate, + COLOR_NUM("$red"), + COLOR_NUM("$green"), + COLOR_NUM("$blue"), + ALPHA_NUM("$alpha")); + } + + Signature rgba_2_sig = "rgba($color, $alpha)"; + BUILT_IN(rgba_2) + { + if ( + special_number(Cast(env["$color"])) + ) { + return SASS_MEMORY_NEW(String_Constant, pstate, "rgba(" + + env["$color"]->to_string() + + ", " + + env["$alpha"]->to_string() + + ")" + ); + } + + Color_Ptr c_arg = ARG("$color", Color); + + if ( + special_number(Cast(env["$alpha"])) + ) { + std::stringstream strm; + strm << "rgba(" + << (int)c_arg->r() << ", " + << (int)c_arg->g() << ", " + << (int)c_arg->b() << ", " + << env["$alpha"]->to_string() + << ")"; + return SASS_MEMORY_NEW(String_Constant, pstate, strm.str()); + } + + Color_Ptr new_c = SASS_MEMORY_COPY(c_arg); + new_c->a(ALPHA_NUM("$alpha")); + new_c->disp(""); + return new_c; + } + + //////////////// + // RGB FUNCTIONS + //////////////// + + Signature red_sig = "red($color)"; + BUILT_IN(red) + { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->r()); } + + Signature green_sig = "green($color)"; + BUILT_IN(green) + { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->g()); } + + Signature blue_sig = "blue($color)"; + BUILT_IN(blue) + { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->b()); } + + Color* colormix(Context& ctx, ParserState& pstate, Color* color1, Color* color2, double weight) { + double p = weight/100; + double w = 2*p - 1; + double a = color1->a() - color2->a(); + + double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0; + double w2 = 1 - w1; + + return SASS_MEMORY_NEW(Color, + pstate, + Sass::round(w1*color1->r() + w2*color2->r(), ctx.c_options.precision), + Sass::round(w1*color1->g() + w2*color2->g(), ctx.c_options.precision), + Sass::round(w1*color1->b() + w2*color2->b(), ctx.c_options.precision), + color1->a()*p + color2->a()*(1-p)); + } + + Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)"; + BUILT_IN(mix) + { + Color_Obj color1 = ARG("$color-1", Color); + Color_Obj color2 = ARG("$color-2", Color); + double weight = DARG_U_PRCT("$weight"); + return colormix(ctx, pstate, color1, color2, weight); + + } + + //////////////// + // HSL FUNCTIONS + //////////////// + + // RGB to HSL helper function + struct HSL { double h; double s; double l; }; + HSL rgb_to_hsl(double r, double g, double b) + { + + // Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV + r /= 255.0; g /= 255.0; b /= 255.0; + + double max = std::max(r, std::max(g, b)); + double min = std::min(r, std::min(g, b)); + double delta = max - min; + + double h = 0; + double s; + double l = (max + min) / 2.0; + + if (max == min) { + h = s = 0; // achromatic + } + else { + if (l < 0.5) s = delta / (max + min); + else s = delta / (2.0 - max - min); + + if (r == max) h = (g - b) / delta + (g < b ? 6 : 0); + else if (g == max) h = (b - r) / delta + 2; + else if (b == max) h = (r - g) / delta + 4; + } + + HSL hsl_struct; + hsl_struct.h = h / 6 * 360; + hsl_struct.s = s * 100; + hsl_struct.l = l * 100; + + return hsl_struct; + } + + // hue to RGB helper function + double h_to_rgb(double m1, double m2, double h) { + while (h < 0) h += 1; + while (h > 1) h -= 1; + if (h*6.0 < 1) return m1 + (m2 - m1)*h*6; + if (h*2.0 < 1) return m2; + if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6; + return m1; + } + + Color_Ptr hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate) + { + h /= 360.0; + s /= 100.0; + l /= 100.0; + + if (l < 0) l = 0; + if (s < 0) s = 0; + if (l > 1) l = 1; + if (s > 1) s = 1; + while (h < 0) h += 1; + while (h > 1) h -= 1; + + // if saturation is exacly zero, we loose + // information for hue, since it will evaluate + // to zero if converted back from rgb. Setting + // saturation to a very tiny number solves this. + if (s == 0) s = 1e-10; + + // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color. + double m2; + if (l <= 0.5) m2 = l*(s+1.0); + else m2 = (l+s)-(l*s); + double m1 = (l*2.0)-m2; + // round the results -- consider moving this into the Color constructor + double r = (h_to_rgb(m1, m2, h + 1.0/3.0) * 255.0); + double g = (h_to_rgb(m1, m2, h) * 255.0); + double b = (h_to_rgb(m1, m2, h - 1.0/3.0) * 255.0); + + return SASS_MEMORY_NEW(Color, pstate, r, g, b, a); + } + + Signature hsl_sig = "hsl($hue, $saturation, $lightness)"; + BUILT_IN(hsl) + { + if ( + special_number(Cast(env["$hue"])) || + special_number(Cast(env["$saturation"])) || + special_number(Cast(env["$lightness"])) + ) { + return SASS_MEMORY_NEW(String_Constant, pstate, "hsl(" + + env["$hue"]->to_string() + + ", " + + env["$saturation"]->to_string() + + ", " + + env["$lightness"]->to_string() + + ")" + ); + } + + return hsla_impl(ARGVAL("$hue"), + ARGVAL("$saturation"), + ARGVAL("$lightness"), + 1.0, + ctx, + pstate); + } + + Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)"; + BUILT_IN(hsla) + { + if ( + special_number(Cast(env["$hue"])) || + special_number(Cast(env["$saturation"])) || + special_number(Cast(env["$lightness"])) || + special_number(Cast(env["$alpha"])) + ) { + return SASS_MEMORY_NEW(String_Constant, pstate, "hsla(" + + env["$hue"]->to_string() + + ", " + + env["$saturation"]->to_string() + + ", " + + env["$lightness"]->to_string() + + ", " + + env["$alpha"]->to_string() + + ")" + ); + } + + return hsla_impl(ARGVAL("$hue"), + ARGVAL("$saturation"), + ARGVAL("$lightness"), + ARGVAL("$alpha"), + ctx, + pstate); + } + + Signature hue_sig = "hue($color)"; + BUILT_IN(hue) + { + Color_Ptr rgb_color = ARG("$color", Color); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + return SASS_MEMORY_NEW(Number, pstate, hsl_color.h, "deg"); + } + + Signature saturation_sig = "saturation($color)"; + BUILT_IN(saturation) + { + Color_Ptr rgb_color = ARG("$color", Color); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + return SASS_MEMORY_NEW(Number, pstate, hsl_color.s, "%"); + } + + Signature lightness_sig = "lightness($color)"; + BUILT_IN(lightness) + { + Color_Ptr rgb_color = ARG("$color", Color); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + return SASS_MEMORY_NEW(Number, pstate, hsl_color.l, "%"); + } + + Signature adjust_hue_sig = "adjust-hue($color, $degrees)"; + BUILT_IN(adjust_hue) + { + Color_Ptr rgb_color = ARG("$color", Color); + double degrees = ARGVAL("$degrees"); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + return hsla_impl(hsl_color.h + degrees, + hsl_color.s, + hsl_color.l, + rgb_color->a(), + ctx, + pstate); + } + + Signature lighten_sig = "lighten($color, $amount)"; + BUILT_IN(lighten) + { + Color_Ptr rgb_color = ARG("$color", Color); + double amount = DARG_U_PRCT("$amount"); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + //Check lightness is not negative before lighten it + double hslcolorL = hsl_color.l; + if (hslcolorL < 0) { + hslcolorL = 0; + } + + return hsla_impl(hsl_color.h, + hsl_color.s, + hslcolorL + amount, + rgb_color->a(), + ctx, + pstate); + } + + Signature darken_sig = "darken($color, $amount)"; + BUILT_IN(darken) + { + Color_Ptr rgb_color = ARG("$color", Color); + double amount = DARG_U_PRCT("$amount"); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + + //Check lightness if not over 100, before darken it + double hslcolorL = hsl_color.l; + if (hslcolorL > 100) { + hslcolorL = 100; + } + + return hsla_impl(hsl_color.h, + hsl_color.s, + hslcolorL - amount, + rgb_color->a(), + ctx, + pstate); + } + + Signature saturate_sig = "saturate($color, $amount: false)"; + BUILT_IN(saturate) + { + // CSS3 filter function overload: pass literal through directly + if (!Cast(env["$amount"])) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color"]->to_string(ctx.c_options) + ")"); + } + + double amount = DARG_U_PRCT("$amount"); + Color_Ptr rgb_color = ARG("$color", Color); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + + double hslcolorS = hsl_color.s + amount; + + // Saturation cannot be below 0 or above 100 + if (hslcolorS < 0) { + hslcolorS = 0; + } + if (hslcolorS > 100) { + hslcolorS = 100; + } + + return hsla_impl(hsl_color.h, + hslcolorS, + hsl_color.l, + rgb_color->a(), + ctx, + pstate); + } + + Signature desaturate_sig = "desaturate($color, $amount)"; + BUILT_IN(desaturate) + { + Color_Ptr rgb_color = ARG("$color", Color); + double amount = DARG_U_PRCT("$amount"); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + + double hslcolorS = hsl_color.s - amount; + + // Saturation cannot be below 0 or above 100 + if (hslcolorS <= 0) { + hslcolorS = 0; + } + if (hslcolorS > 100) { + hslcolorS = 100; + } + + return hsla_impl(hsl_color.h, + hslcolorS, + hsl_color.l, + rgb_color->a(), + ctx, + pstate); + } + + Signature grayscale_sig = "grayscale($color)"; + BUILT_IN(grayscale) + { + // CSS3 filter function overload: pass literal through directly + Number_Ptr amount = Cast(env["$color"]); + if (amount) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")"); + } + + Color_Ptr rgb_color = ARG("$color", Color); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + return hsla_impl(hsl_color.h, + 0.0, + hsl_color.l, + rgb_color->a(), + ctx, + pstate); + } + + Signature complement_sig = "complement($color)"; + BUILT_IN(complement) + { + Color_Ptr rgb_color = ARG("$color", Color); + HSL hsl_color = rgb_to_hsl(rgb_color->r(), + rgb_color->g(), + rgb_color->b()); + return hsla_impl(hsl_color.h - 180.0, + hsl_color.s, + hsl_color.l, + rgb_color->a(), + ctx, + pstate); + } + + Signature invert_sig = "invert($color, $weight: 100%)"; + BUILT_IN(invert) + { + // CSS3 filter function overload: pass literal through directly + Number_Ptr amount = Cast(env["$color"]); + if (amount) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")"); + } + + double weight = DARG_U_PRCT("$weight"); + Color_Ptr rgb_color = ARG("$color", Color); + Color_Obj inv = SASS_MEMORY_NEW(Color, + pstate, + 255 - rgb_color->r(), + 255 - rgb_color->g(), + 255 - rgb_color->b(), + rgb_color->a()); + return colormix(ctx, pstate, inv, rgb_color, weight); + } + + //////////////////// + // OPACITY FUNCTIONS + //////////////////// + Signature alpha_sig = "alpha($color)"; + Signature opacity_sig = "opacity($color)"; + BUILT_IN(alpha) + { + String_Constant_Ptr ie_kwd = Cast(env["$color"]); + if (ie_kwd) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")"); + } + + // CSS3 filter function overload: pass literal through directly + Number_Ptr amount = Cast(env["$color"]); + if (amount) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")"); + } + + return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->a()); + } + + Signature opacify_sig = "opacify($color, $amount)"; + Signature fade_in_sig = "fade-in($color, $amount)"; + BUILT_IN(opacify) + { + Color_Ptr color = ARG("$color", Color); + double amount = DARG_U_FACT("$amount"); + double alpha = std::min(color->a() + amount, 1.0); + return SASS_MEMORY_NEW(Color, + pstate, + color->r(), + color->g(), + color->b(), + alpha); + } + + Signature transparentize_sig = "transparentize($color, $amount)"; + Signature fade_out_sig = "fade-out($color, $amount)"; + BUILT_IN(transparentize) + { + Color_Ptr color = ARG("$color", Color); + double amount = DARG_U_FACT("$amount"); + double alpha = std::max(color->a() - amount, 0.0); + return SASS_MEMORY_NEW(Color, + pstate, + color->r(), + color->g(), + color->b(), + alpha); + } + + //////////////////////// + // OTHER COLOR FUNCTIONS + //////////////////////// + + Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; + BUILT_IN(adjust_color) + { + Color_Ptr color = ARG("$color", Color); + Number_Ptr r = Cast(env["$red"]); + Number_Ptr g = Cast(env["$green"]); + Number_Ptr b = Cast(env["$blue"]); + Number_Ptr h = Cast(env["$hue"]); + Number_Ptr s = Cast(env["$saturation"]); + Number_Ptr l = Cast(env["$lightness"]); + Number_Ptr a = Cast(env["$alpha"]); + + bool rgb = r || g || b; + bool hsl = h || s || l; + + if (rgb && hsl) { + error("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", pstate, traces); + } + if (rgb) { + double rr = r ? DARG_R_BYTE("$red") : 0; + double gg = g ? DARG_R_BYTE("$green") : 0; + double bb = b ? DARG_R_BYTE("$blue") : 0; + double aa = a ? DARG_R_FACT("$alpha") : 0; + return SASS_MEMORY_NEW(Color, + pstate, + color->r() + rr, + color->g() + gg, + color->b() + bb, + color->a() + aa); + } + if (hsl) { + HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b()); + double ss = s ? DARG_R_PRCT("$saturation") : 0; + double ll = l ? DARG_R_PRCT("$lightness") : 0; + double aa = a ? DARG_R_FACT("$alpha") : 0; + return hsla_impl(hsl_struct.h + (h ? h->value() : 0), + hsl_struct.s + ss, + hsl_struct.l + ll, + color->a() + aa, + ctx, + pstate); + } + if (a) { + return SASS_MEMORY_NEW(Color, + pstate, + color->r(), + color->g(), + color->b(), + color->a() + (a ? a->value() : 0)); + } + error("not enough arguments for `adjust-color'", pstate, traces); + // unreachable + return color; + } + + Signature scale_color_sig = "scale-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; + BUILT_IN(scale_color) + { + Color_Ptr color = ARG("$color", Color); + Number_Ptr r = Cast(env["$red"]); + Number_Ptr g = Cast(env["$green"]); + Number_Ptr b = Cast(env["$blue"]); + Number_Ptr h = Cast(env["$hue"]); + Number_Ptr s = Cast(env["$saturation"]); + Number_Ptr l = Cast(env["$lightness"]); + Number_Ptr a = Cast(env["$alpha"]); + + bool rgb = r || g || b; + bool hsl = h || s || l; + + if (rgb && hsl) { + error("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", pstate, traces); + } + if (rgb) { + double rscale = (r ? DARG_R_PRCT("$red") : 0.0) / 100.0; + double gscale = (g ? DARG_R_PRCT("$green") : 0.0) / 100.0; + double bscale = (b ? DARG_R_PRCT("$blue") : 0.0) / 100.0; + double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0; + return SASS_MEMORY_NEW(Color, + pstate, + color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()), + color->g() + gscale * (gscale > 0.0 ? 255 - color->g() : color->g()), + color->b() + bscale * (bscale > 0.0 ? 255 - color->b() : color->b()), + color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a())); + } + if (hsl) { + double hscale = (h ? DARG_R_PRCT("$hue") : 0.0) / 100.0; + double sscale = (s ? DARG_R_PRCT("$saturation") : 0.0) / 100.0; + double lscale = (l ? DARG_R_PRCT("$lightness") : 0.0) / 100.0; + double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0; + HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b()); + hsl_struct.h += hscale * (hscale > 0.0 ? 360.0 - hsl_struct.h : hsl_struct.h); + hsl_struct.s += sscale * (sscale > 0.0 ? 100.0 - hsl_struct.s : hsl_struct.s); + hsl_struct.l += lscale * (lscale > 0.0 ? 100.0 - hsl_struct.l : hsl_struct.l); + double alpha = color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()); + return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate); + } + if (a) { + double ascale = (DARG_R_PRCT("$alpha")) / 100.0; + return SASS_MEMORY_NEW(Color, + pstate, + color->r(), + color->g(), + color->b(), + color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a())); + } + error("not enough arguments for `scale-color'", pstate, traces); + // unreachable + return color; + } + + Signature change_color_sig = "change-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; + BUILT_IN(change_color) + { + Color_Ptr color = ARG("$color", Color); + Number_Ptr r = Cast(env["$red"]); + Number_Ptr g = Cast(env["$green"]); + Number_Ptr b = Cast(env["$blue"]); + Number_Ptr h = Cast(env["$hue"]); + Number_Ptr s = Cast(env["$saturation"]); + Number_Ptr l = Cast(env["$lightness"]); + Number_Ptr a = Cast(env["$alpha"]); + + bool rgb = r || g || b; + bool hsl = h || s || l; + + if (rgb && hsl) { + error("Cannot specify HSL and RGB values for a color at the same time for `change-color'", pstate, traces); + } + if (rgb) { + return SASS_MEMORY_NEW(Color, + pstate, + r ? DARG_U_BYTE("$red") : color->r(), + g ? DARG_U_BYTE("$green") : color->g(), + b ? DARG_U_BYTE("$blue") : color->b(), + a ? DARG_U_BYTE("$alpha") : color->a()); + } + if (hsl) { + HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b()); + if (h) hsl_struct.h = std::fmod(h->value(), 360.0); + if (s) hsl_struct.s = DARG_U_PRCT("$saturation"); + if (l) hsl_struct.l = DARG_U_PRCT("$lightness"); + double alpha = a ? DARG_U_FACT("$alpha") : color->a(); + return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate); + } + if (a) { + double alpha = DARG_U_FACT("$alpha"); + return SASS_MEMORY_NEW(Color, + pstate, + color->r(), + color->g(), + color->b(), + alpha); + } + error("not enough arguments for `change-color'", pstate, traces); + // unreachable + return color; + } + + template + static double cap_channel(double c) { + if (c > range) return range; + else if (c < 0) return 0; + else return c; + } + + Signature ie_hex_str_sig = "ie-hex-str($color)"; + BUILT_IN(ie_hex_str) + { + Color_Ptr c = ARG("$color", Color); + double r = cap_channel<0xff>(c->r()); + double g = cap_channel<0xff>(c->g()); + double b = cap_channel<0xff>(c->b()); + double a = cap_channel<1> (c->a()) * 255; + + std::stringstream ss; + ss << '#' << std::setw(2) << std::setfill('0'); + ss << std::hex << std::setw(2) << static_cast(Sass::round(a, ctx.c_options.precision)); + ss << std::hex << std::setw(2) << static_cast(Sass::round(r, ctx.c_options.precision)); + ss << std::hex << std::setw(2) << static_cast(Sass::round(g, ctx.c_options.precision)); + ss << std::hex << std::setw(2) << static_cast(Sass::round(b, ctx.c_options.precision)); + + std::string result(ss.str()); + for (size_t i = 0, L = result.length(); i < L; ++i) { + result[i] = std::toupper(result[i]); + } + return SASS_MEMORY_NEW(String_Quoted, pstate, result); + } + + } + +} \ No newline at end of file diff --git a/src/fn_colors.hpp b/src/fn_colors.hpp new file mode 100644 index 000000000..a474c64b5 --- /dev/null +++ b/src/fn_colors.hpp @@ -0,0 +1,85 @@ +#ifndef SASS_FN_COLORS_H +#define SASS_FN_COLORS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + // macros for common ranges (u mean unsigned or upper, r for full range) + #define DARG_U_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 1.0) // double + #define DARG_R_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 1.0, 1.0) // double + #define DARG_U_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 255.0) // double + #define DARG_R_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 255.0, 255.0) // double + #define DARG_U_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 100.0) // double + #define DARG_R_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 100.0, 100.0) // double + + // macros for color related inputs (rbg and alpha/opacity values) + #define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double + #define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double + + extern Signature rgb_sig; + extern Signature rgba_4_sig; + extern Signature rgba_2_sig; + extern Signature red_sig; + extern Signature green_sig; + extern Signature blue_sig; + extern Signature mix_sig; + extern Signature hsl_sig; + extern Signature hsla_sig; + extern Signature hue_sig; + extern Signature saturation_sig; + extern Signature lightness_sig; + extern Signature adjust_hue_sig; + extern Signature lighten_sig; + extern Signature darken_sig; + extern Signature saturate_sig; + extern Signature desaturate_sig; + extern Signature grayscale_sig; + extern Signature complement_sig; + extern Signature invert_sig; + extern Signature alpha_sig; + extern Signature opacity_sig; + extern Signature opacify_sig; + extern Signature fade_in_sig; + extern Signature transparentize_sig; + extern Signature fade_out_sig; + extern Signature adjust_color_sig; + extern Signature scale_color_sig; + extern Signature change_color_sig; + extern Signature ie_hex_str_sig; + + BUILT_IN(rgb); + BUILT_IN(rgba_4); + BUILT_IN(rgba_2); + BUILT_IN(red); + BUILT_IN(green); + BUILT_IN(blue); + BUILT_IN(mix); + BUILT_IN(hsl); + BUILT_IN(hsla); + BUILT_IN(hue); + BUILT_IN(saturation); + BUILT_IN(lightness); + BUILT_IN(adjust_hue); + BUILT_IN(lighten); + BUILT_IN(darken); + BUILT_IN(saturate); + BUILT_IN(desaturate); + BUILT_IN(grayscale); + BUILT_IN(complement); + BUILT_IN(invert); + BUILT_IN(alpha); + BUILT_IN(opacify); + BUILT_IN(transparentize); + BUILT_IN(adjust_color); + BUILT_IN(scale_color); + BUILT_IN(change_color); + BUILT_IN(ie_hex_str); + + } + +} + +#endif diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp index 47ec759a4..3127968ca 100644 --- a/src/fn_utils.cpp +++ b/src/fn_utils.cpp @@ -2,7 +2,6 @@ #include "parser.hpp" #include "fn_utils.hpp" #include "functions.hpp" -#include "error_handling.hpp" namespace Sass { diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index 0cd66b002..6b743ab16 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -1,9 +1,10 @@ #ifndef SASS_FN_UTILS_H #define SASS_FN_UTILS_H - +#include "units.hpp" #include "backtrace.hpp" #include "environment.hpp" #include "ast_fwd_decl.hpp" +#include "error_handling.hpp" namespace Sass { diff --git a/src/functions.cpp b/src/functions.cpp index b2a0306a8..b2ba02451 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -26,6 +26,7 @@ #include #include "fn_utils.hpp" +#include "fn_colors.hpp" #include "fn_numbers.hpp" #include "fn_selectors.hpp" @@ -70,735 +71,6 @@ namespace Sass { "custom-property" }; - //////////////// - // RGB FUNCTIONS - //////////////// - - inline bool special_number(String_Constant_Ptr s) { - if (s) { - std::string calc("calc("); - std::string var("var("); - std::string ss(s->value()); - return std::equal(calc.begin(), calc.end(), ss.begin()) || - std::equal(var.begin(), var.end(), ss.begin()); - } - return false; - } - - Signature rgb_sig = "rgb($red, $green, $blue)"; - BUILT_IN(rgb) - { - if ( - special_number(Cast(env["$red"])) || - special_number(Cast(env["$green"])) || - special_number(Cast(env["$blue"])) - ) { - return SASS_MEMORY_NEW(String_Constant, pstate, "rgb(" - + env["$red"]->to_string() - + ", " - + env["$green"]->to_string() - + ", " - + env["$blue"]->to_string() - + ")" - ); - } - - return SASS_MEMORY_NEW(Color, - pstate, - COLOR_NUM("$red"), - COLOR_NUM("$green"), - COLOR_NUM("$blue")); - } - - Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)"; - BUILT_IN(rgba_4) - { - if ( - special_number(Cast(env["$red"])) || - special_number(Cast(env["$green"])) || - special_number(Cast(env["$blue"])) || - special_number(Cast(env["$alpha"])) - ) { - return SASS_MEMORY_NEW(String_Constant, pstate, "rgba(" - + env["$red"]->to_string() - + ", " - + env["$green"]->to_string() - + ", " - + env["$blue"]->to_string() - + ", " - + env["$alpha"]->to_string() - + ")" - ); - } - - return SASS_MEMORY_NEW(Color, - pstate, - COLOR_NUM("$red"), - COLOR_NUM("$green"), - COLOR_NUM("$blue"), - ALPHA_NUM("$alpha")); - } - - Signature rgba_2_sig = "rgba($color, $alpha)"; - BUILT_IN(rgba_2) - { - if ( - special_number(Cast(env["$color"])) - ) { - return SASS_MEMORY_NEW(String_Constant, pstate, "rgba(" - + env["$color"]->to_string() - + ", " - + env["$alpha"]->to_string() - + ")" - ); - } - - Color_Ptr c_arg = ARG("$color", Color); - - if ( - special_number(Cast(env["$alpha"])) - ) { - std::stringstream strm; - strm << "rgba(" - << (int)c_arg->r() << ", " - << (int)c_arg->g() << ", " - << (int)c_arg->b() << ", " - << env["$alpha"]->to_string() - << ")"; - return SASS_MEMORY_NEW(String_Constant, pstate, strm.str()); - } - - Color_Ptr new_c = SASS_MEMORY_COPY(c_arg); - new_c->a(ALPHA_NUM("$alpha")); - new_c->disp(""); - return new_c; - } - - Signature red_sig = "red($color)"; - BUILT_IN(red) - { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->r()); } - - Signature green_sig = "green($color)"; - BUILT_IN(green) - { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->g()); } - - Signature blue_sig = "blue($color)"; - BUILT_IN(blue) - { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->b()); } - - Color* colormix(Context& ctx, ParserState& pstate, Color* color1, Color* color2, double weight) { - double p = weight/100; - double w = 2*p - 1; - double a = color1->a() - color2->a(); - - double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0; - double w2 = 1 - w1; - - return SASS_MEMORY_NEW(Color, - pstate, - Sass::round(w1*color1->r() + w2*color2->r(), ctx.c_options.precision), - Sass::round(w1*color1->g() + w2*color2->g(), ctx.c_options.precision), - Sass::round(w1*color1->b() + w2*color2->b(), ctx.c_options.precision), - color1->a()*p + color2->a()*(1-p)); - } - - Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)"; - BUILT_IN(mix) - { - Color_Obj color1 = ARG("$color-1", Color); - Color_Obj color2 = ARG("$color-2", Color); - double weight = DARG_U_PRCT("$weight"); - return colormix(ctx, pstate, color1, color2, weight); - - } - - //////////////// - // HSL FUNCTIONS - //////////////// - - // RGB to HSL helper function - struct HSL { double h; double s; double l; }; - HSL rgb_to_hsl(double r, double g, double b) - { - - // Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV - r /= 255.0; g /= 255.0; b /= 255.0; - - double max = std::max(r, std::max(g, b)); - double min = std::min(r, std::min(g, b)); - double delta = max - min; - - double h = 0; - double s; - double l = (max + min) / 2.0; - - if (max == min) { - h = s = 0; // achromatic - } - else { - if (l < 0.5) s = delta / (max + min); - else s = delta / (2.0 - max - min); - - if (r == max) h = (g - b) / delta + (g < b ? 6 : 0); - else if (g == max) h = (b - r) / delta + 2; - else if (b == max) h = (r - g) / delta + 4; - } - - HSL hsl_struct; - hsl_struct.h = h / 6 * 360; - hsl_struct.s = s * 100; - hsl_struct.l = l * 100; - - return hsl_struct; - } - - // hue to RGB helper function - double h_to_rgb(double m1, double m2, double h) { - while (h < 0) h += 1; - while (h > 1) h -= 1; - if (h*6.0 < 1) return m1 + (m2 - m1)*h*6; - if (h*2.0 < 1) return m2; - if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6; - return m1; - } - - Color_Ptr hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate) - { - h /= 360.0; - s /= 100.0; - l /= 100.0; - - if (l < 0) l = 0; - if (s < 0) s = 0; - if (l > 1) l = 1; - if (s > 1) s = 1; - while (h < 0) h += 1; - while (h > 1) h -= 1; - - // if saturation is exacly zero, we loose - // information for hue, since it will evaluate - // to zero if converted back from rgb. Setting - // saturation to a very tiny number solves this. - if (s == 0) s = 1e-10; - - // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color. - double m2; - if (l <= 0.5) m2 = l*(s+1.0); - else m2 = (l+s)-(l*s); - double m1 = (l*2.0)-m2; - // round the results -- consider moving this into the Color constructor - double r = (h_to_rgb(m1, m2, h + 1.0/3.0) * 255.0); - double g = (h_to_rgb(m1, m2, h) * 255.0); - double b = (h_to_rgb(m1, m2, h - 1.0/3.0) * 255.0); - - return SASS_MEMORY_NEW(Color, pstate, r, g, b, a); - } - - Signature hsl_sig = "hsl($hue, $saturation, $lightness)"; - BUILT_IN(hsl) - { - if ( - special_number(Cast(env["$hue"])) || - special_number(Cast(env["$saturation"])) || - special_number(Cast(env["$lightness"])) - ) { - return SASS_MEMORY_NEW(String_Constant, pstate, "hsl(" - + env["$hue"]->to_string() - + ", " - + env["$saturation"]->to_string() - + ", " - + env["$lightness"]->to_string() - + ")" - ); - } - - return hsla_impl(ARGVAL("$hue"), - ARGVAL("$saturation"), - ARGVAL("$lightness"), - 1.0, - ctx, - pstate); - } - - Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)"; - BUILT_IN(hsla) - { - if ( - special_number(Cast(env["$hue"])) || - special_number(Cast(env["$saturation"])) || - special_number(Cast(env["$lightness"])) || - special_number(Cast(env["$alpha"])) - ) { - return SASS_MEMORY_NEW(String_Constant, pstate, "hsla(" - + env["$hue"]->to_string() - + ", " - + env["$saturation"]->to_string() - + ", " - + env["$lightness"]->to_string() - + ", " - + env["$alpha"]->to_string() - + ")" - ); - } - - return hsla_impl(ARGVAL("$hue"), - ARGVAL("$saturation"), - ARGVAL("$lightness"), - ARGVAL("$alpha"), - ctx, - pstate); - } - - Signature hue_sig = "hue($color)"; - BUILT_IN(hue) - { - Color_Ptr rgb_color = ARG("$color", Color); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - return SASS_MEMORY_NEW(Number, pstate, hsl_color.h, "deg"); - } - - Signature saturation_sig = "saturation($color)"; - BUILT_IN(saturation) - { - Color_Ptr rgb_color = ARG("$color", Color); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - return SASS_MEMORY_NEW(Number, pstate, hsl_color.s, "%"); - } - - Signature lightness_sig = "lightness($color)"; - BUILT_IN(lightness) - { - Color_Ptr rgb_color = ARG("$color", Color); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - return SASS_MEMORY_NEW(Number, pstate, hsl_color.l, "%"); - } - - Signature adjust_hue_sig = "adjust-hue($color, $degrees)"; - BUILT_IN(adjust_hue) - { - Color_Ptr rgb_color = ARG("$color", Color); - double degrees = ARGVAL("$degrees"); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - return hsla_impl(hsl_color.h + degrees, - hsl_color.s, - hsl_color.l, - rgb_color->a(), - ctx, - pstate); - } - - Signature lighten_sig = "lighten($color, $amount)"; - BUILT_IN(lighten) - { - Color_Ptr rgb_color = ARG("$color", Color); - double amount = DARG_U_PRCT("$amount"); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - //Check lightness is not negative before lighten it - double hslcolorL = hsl_color.l; - if (hslcolorL < 0) { - hslcolorL = 0; - } - - return hsla_impl(hsl_color.h, - hsl_color.s, - hslcolorL + amount, - rgb_color->a(), - ctx, - pstate); - } - - Signature darken_sig = "darken($color, $amount)"; - BUILT_IN(darken) - { - Color_Ptr rgb_color = ARG("$color", Color); - double amount = DARG_U_PRCT("$amount"); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - - //Check lightness if not over 100, before darken it - double hslcolorL = hsl_color.l; - if (hslcolorL > 100) { - hslcolorL = 100; - } - - return hsla_impl(hsl_color.h, - hsl_color.s, - hslcolorL - amount, - rgb_color->a(), - ctx, - pstate); - } - - Signature saturate_sig = "saturate($color, $amount: false)"; - BUILT_IN(saturate) - { - // CSS3 filter function overload: pass literal through directly - if (!Cast(env["$amount"])) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color"]->to_string(ctx.c_options) + ")"); - } - - double amount = DARG_U_PRCT("$amount"); - Color_Ptr rgb_color = ARG("$color", Color); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - - double hslcolorS = hsl_color.s + amount; - - // Saturation cannot be below 0 or above 100 - if (hslcolorS < 0) { - hslcolorS = 0; - } - if (hslcolorS > 100) { - hslcolorS = 100; - } - - return hsla_impl(hsl_color.h, - hslcolorS, - hsl_color.l, - rgb_color->a(), - ctx, - pstate); - } - - Signature desaturate_sig = "desaturate($color, $amount)"; - BUILT_IN(desaturate) - { - Color_Ptr rgb_color = ARG("$color", Color); - double amount = DARG_U_PRCT("$amount"); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - - double hslcolorS = hsl_color.s - amount; - - // Saturation cannot be below 0 or above 100 - if (hslcolorS <= 0) { - hslcolorS = 0; - } - if (hslcolorS > 100) { - hslcolorS = 100; - } - - return hsla_impl(hsl_color.h, - hslcolorS, - hsl_color.l, - rgb_color->a(), - ctx, - pstate); - } - - Signature grayscale_sig = "grayscale($color)"; - BUILT_IN(grayscale) - { - // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = Cast(env["$color"]); - if (amount) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")"); - } - - Color_Ptr rgb_color = ARG("$color", Color); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - return hsla_impl(hsl_color.h, - 0.0, - hsl_color.l, - rgb_color->a(), - ctx, - pstate); - } - - Signature complement_sig = "complement($color)"; - BUILT_IN(complement) - { - Color_Ptr rgb_color = ARG("$color", Color); - HSL hsl_color = rgb_to_hsl(rgb_color->r(), - rgb_color->g(), - rgb_color->b()); - return hsla_impl(hsl_color.h - 180.0, - hsl_color.s, - hsl_color.l, - rgb_color->a(), - ctx, - pstate); - } - - Signature invert_sig = "invert($color, $weight: 100%)"; - BUILT_IN(invert) - { - // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = Cast(env["$color"]); - if (amount) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")"); - } - - double weight = DARG_U_PRCT("$weight"); - Color_Ptr rgb_color = ARG("$color", Color); - Color_Obj inv = SASS_MEMORY_NEW(Color, - pstate, - 255 - rgb_color->r(), - 255 - rgb_color->g(), - 255 - rgb_color->b(), - rgb_color->a()); - return colormix(ctx, pstate, inv, rgb_color, weight); - } - - //////////////////// - // OPACITY FUNCTIONS - //////////////////// - Signature alpha_sig = "alpha($color)"; - Signature opacity_sig = "opacity($color)"; - BUILT_IN(alpha) - { - String_Constant_Ptr ie_kwd = Cast(env["$color"]); - if (ie_kwd) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")"); - } - - // CSS3 filter function overload: pass literal through directly - Number_Ptr amount = Cast(env["$color"]); - if (amount) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")"); - } - - return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->a()); - } - - Signature opacify_sig = "opacify($color, $amount)"; - Signature fade_in_sig = "fade-in($color, $amount)"; - BUILT_IN(opacify) - { - Color_Ptr color = ARG("$color", Color); - double amount = DARG_U_FACT("$amount"); - double alpha = std::min(color->a() + amount, 1.0); - return SASS_MEMORY_NEW(Color, - pstate, - color->r(), - color->g(), - color->b(), - alpha); - } - - Signature transparentize_sig = "transparentize($color, $amount)"; - Signature fade_out_sig = "fade-out($color, $amount)"; - BUILT_IN(transparentize) - { - Color_Ptr color = ARG("$color", Color); - double amount = DARG_U_FACT("$amount"); - double alpha = std::max(color->a() - amount, 0.0); - return SASS_MEMORY_NEW(Color, - pstate, - color->r(), - color->g(), - color->b(), - alpha); - } - - //////////////////////// - // OTHER COLOR FUNCTIONS - //////////////////////// - - Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; - BUILT_IN(adjust_color) - { - Color_Ptr color = ARG("$color", Color); - Number_Ptr r = Cast(env["$red"]); - Number_Ptr g = Cast(env["$green"]); - Number_Ptr b = Cast(env["$blue"]); - Number_Ptr h = Cast(env["$hue"]); - Number_Ptr s = Cast(env["$saturation"]); - Number_Ptr l = Cast(env["$lightness"]); - Number_Ptr a = Cast(env["$alpha"]); - - bool rgb = r || g || b; - bool hsl = h || s || l; - - if (rgb && hsl) { - error("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", pstate, traces); - } - if (rgb) { - double rr = r ? DARG_R_BYTE("$red") : 0; - double gg = g ? DARG_R_BYTE("$green") : 0; - double bb = b ? DARG_R_BYTE("$blue") : 0; - double aa = a ? DARG_R_FACT("$alpha") : 0; - return SASS_MEMORY_NEW(Color, - pstate, - color->r() + rr, - color->g() + gg, - color->b() + bb, - color->a() + aa); - } - if (hsl) { - HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b()); - double ss = s ? DARG_R_PRCT("$saturation") : 0; - double ll = l ? DARG_R_PRCT("$lightness") : 0; - double aa = a ? DARG_R_FACT("$alpha") : 0; - return hsla_impl(hsl_struct.h + (h ? h->value() : 0), - hsl_struct.s + ss, - hsl_struct.l + ll, - color->a() + aa, - ctx, - pstate); - } - if (a) { - return SASS_MEMORY_NEW(Color, - pstate, - color->r(), - color->g(), - color->b(), - color->a() + (a ? a->value() : 0)); - } - error("not enough arguments for `adjust-color'", pstate, traces); - // unreachable - return color; - } - - Signature scale_color_sig = "scale-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; - BUILT_IN(scale_color) - { - Color_Ptr color = ARG("$color", Color); - Number_Ptr r = Cast(env["$red"]); - Number_Ptr g = Cast(env["$green"]); - Number_Ptr b = Cast(env["$blue"]); - Number_Ptr h = Cast(env["$hue"]); - Number_Ptr s = Cast(env["$saturation"]); - Number_Ptr l = Cast(env["$lightness"]); - Number_Ptr a = Cast(env["$alpha"]); - - bool rgb = r || g || b; - bool hsl = h || s || l; - - if (rgb && hsl) { - error("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", pstate, traces); - } - if (rgb) { - double rscale = (r ? DARG_R_PRCT("$red") : 0.0) / 100.0; - double gscale = (g ? DARG_R_PRCT("$green") : 0.0) / 100.0; - double bscale = (b ? DARG_R_PRCT("$blue") : 0.0) / 100.0; - double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0; - return SASS_MEMORY_NEW(Color, - pstate, - color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()), - color->g() + gscale * (gscale > 0.0 ? 255 - color->g() : color->g()), - color->b() + bscale * (bscale > 0.0 ? 255 - color->b() : color->b()), - color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a())); - } - if (hsl) { - double hscale = (h ? DARG_R_PRCT("$hue") : 0.0) / 100.0; - double sscale = (s ? DARG_R_PRCT("$saturation") : 0.0) / 100.0; - double lscale = (l ? DARG_R_PRCT("$lightness") : 0.0) / 100.0; - double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0; - HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b()); - hsl_struct.h += hscale * (hscale > 0.0 ? 360.0 - hsl_struct.h : hsl_struct.h); - hsl_struct.s += sscale * (sscale > 0.0 ? 100.0 - hsl_struct.s : hsl_struct.s); - hsl_struct.l += lscale * (lscale > 0.0 ? 100.0 - hsl_struct.l : hsl_struct.l); - double alpha = color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()); - return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate); - } - if (a) { - double ascale = (DARG_R_PRCT("$alpha")) / 100.0; - return SASS_MEMORY_NEW(Color, - pstate, - color->r(), - color->g(), - color->b(), - color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a())); - } - error("not enough arguments for `scale-color'", pstate, traces); - // unreachable - return color; - } - - Signature change_color_sig = "change-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)"; - BUILT_IN(change_color) - { - Color_Ptr color = ARG("$color", Color); - Number_Ptr r = Cast(env["$red"]); - Number_Ptr g = Cast(env["$green"]); - Number_Ptr b = Cast(env["$blue"]); - Number_Ptr h = Cast(env["$hue"]); - Number_Ptr s = Cast(env["$saturation"]); - Number_Ptr l = Cast(env["$lightness"]); - Number_Ptr a = Cast(env["$alpha"]); - - bool rgb = r || g || b; - bool hsl = h || s || l; - - if (rgb && hsl) { - error("Cannot specify HSL and RGB values for a color at the same time for `change-color'", pstate, traces); - } - if (rgb) { - return SASS_MEMORY_NEW(Color, - pstate, - r ? DARG_U_BYTE("$red") : color->r(), - g ? DARG_U_BYTE("$green") : color->g(), - b ? DARG_U_BYTE("$blue") : color->b(), - a ? DARG_U_BYTE("$alpha") : color->a()); - } - if (hsl) { - HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b()); - if (h) hsl_struct.h = std::fmod(h->value(), 360.0); - if (s) hsl_struct.s = DARG_U_PRCT("$saturation"); - if (l) hsl_struct.l = DARG_U_PRCT("$lightness"); - double alpha = a ? DARG_U_FACT("$alpha") : color->a(); - return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate); - } - if (a) { - double alpha = DARG_U_FACT("$alpha"); - return SASS_MEMORY_NEW(Color, - pstate, - color->r(), - color->g(), - color->b(), - alpha); - } - error("not enough arguments for `change-color'", pstate, traces); - // unreachable - return color; - } - - template - static double cap_channel(double c) { - if (c > range) return range; - else if (c < 0) return 0; - else return c; - } - - Signature ie_hex_str_sig = "ie-hex-str($color)"; - BUILT_IN(ie_hex_str) - { - Color_Ptr c = ARG("$color", Color); - double r = cap_channel<0xff>(c->r()); - double g = cap_channel<0xff>(c->g()); - double b = cap_channel<0xff>(c->b()); - double a = cap_channel<1> (c->a()) * 255; - - std::stringstream ss; - ss << '#' << std::setw(2) << std::setfill('0'); - ss << std::hex << std::setw(2) << static_cast(Sass::round(a, ctx.c_options.precision)); - ss << std::hex << std::setw(2) << static_cast(Sass::round(r, ctx.c_options.precision)); - ss << std::hex << std::setw(2) << static_cast(Sass::round(g, ctx.c_options.precision)); - ss << std::hex << std::setw(2) << static_cast(Sass::round(b, ctx.c_options.precision)); - - std::string result(ss.str()); - for (size_t i = 0, L = result.length(); i < L; ++i) { - result[i] = std::toupper(result[i]); - } - return SASS_MEMORY_NEW(String_Quoted, pstate, result); - } - /////////////////// // STRING FUNCTIONS /////////////////// diff --git a/src/functions.hpp b/src/functions.hpp index 6787fe91d..58c57b87f 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -17,36 +17,6 @@ namespace Sass { namespace Functions { - extern Signature rgb_sig; - extern Signature rgba_4_sig; - extern Signature rgba_2_sig; - extern Signature red_sig; - extern Signature green_sig; - extern Signature blue_sig; - extern Signature mix_sig; - extern Signature hsl_sig; - extern Signature hsla_sig; - extern Signature hue_sig; - extern Signature saturation_sig; - extern Signature lightness_sig; - extern Signature adjust_hue_sig; - extern Signature lighten_sig; - extern Signature darken_sig; - extern Signature saturate_sig; - extern Signature desaturate_sig; - extern Signature grayscale_sig; - extern Signature complement_sig; - extern Signature invert_sig; - extern Signature alpha_sig; - extern Signature opacity_sig; - extern Signature opacify_sig; - extern Signature fade_in_sig; - extern Signature transparentize_sig; - extern Signature fade_out_sig; - extern Signature adjust_color_sig; - extern Signature scale_color_sig; - extern Signature change_color_sig; - extern Signature ie_hex_str_sig; extern Signature unquote_sig; extern Signature quote_sig; extern Signature str_length_sig; @@ -83,33 +53,6 @@ namespace Sass { extern Signature content_exists_sig; extern Signature get_function_sig; - BUILT_IN(rgb); - BUILT_IN(rgba_4); - BUILT_IN(rgba_2); - BUILT_IN(red); - BUILT_IN(green); - BUILT_IN(blue); - BUILT_IN(mix); - BUILT_IN(hsl); - BUILT_IN(hsla); - BUILT_IN(hue); - BUILT_IN(saturation); - BUILT_IN(lightness); - BUILT_IN(adjust_hue); - BUILT_IN(lighten); - BUILT_IN(darken); - BUILT_IN(saturate); - BUILT_IN(desaturate); - BUILT_IN(grayscale); - BUILT_IN(complement); - BUILT_IN(invert); - BUILT_IN(alpha); - BUILT_IN(opacify); - BUILT_IN(transparentize); - BUILT_IN(adjust_color); - BUILT_IN(scale_color); - BUILT_IN(change_color); - BUILT_IN(ie_hex_str); BUILT_IN(sass_unquote); BUILT_IN(sass_quote); BUILT_IN(str_length); diff --git a/win/libsass.targets b/win/libsass.targets index 2af43d6db..97dbecec8 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -34,6 +34,7 @@ + @@ -90,6 +91,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 6c13df030..db2f369ad 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -114,6 +114,9 @@ Headers + + Headers + Headers @@ -281,6 +284,9 @@ Sources + + Sources + Sources From ac4e48b1d509d19616cb1da390813582ddc2bc60 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 02:05:13 +0100 Subject: [PATCH 07/30] Move string functions to own compile unit --- Makefile.conf | 1 + src/context.cpp | 1 + src/fn_strings.cpp | 258 ++++++++++++++++++++++++++++++++++++ src/fn_strings.hpp | 34 +++++ src/functions.cpp | 247 +--------------------------------- src/functions.hpp | 17 --- win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 + 8 files changed, 303 insertions(+), 263 deletions(-) create mode 100644 src/fn_strings.cpp create mode 100644 src/fn_strings.hpp diff --git a/Makefile.conf b/Makefile.conf index 08c455667..d5c2e23e3 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -13,6 +13,7 @@ SOURCES = \ fn_utils.cpp \ fn_colors.cpp \ fn_numbers.cpp \ + fn_strings.cpp \ fn_selectors.cpp \ functions.cpp \ color_maps.cpp \ diff --git a/src/context.cpp b/src/context.cpp index 58dbc7663..d8c688e5f 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -32,6 +32,7 @@ #include "fn_utils.hpp" #include "fn_colors.hpp" #include "fn_numbers.hpp" +#include "fn_strings.hpp" #include "fn_selectors.hpp" namespace Sass { diff --git a/src/fn_strings.cpp b/src/fn_strings.cpp new file mode 100644 index 000000000..7949cc4f1 --- /dev/null +++ b/src/fn_strings.cpp @@ -0,0 +1,258 @@ +#include "ast.hpp" +#include "fn_utils.hpp" +#include "fn_strings.hpp" + +namespace Sass { + + namespace Functions { + + void handle_utf8_error (const ParserState& pstate, Backtraces traces) + { + try { + throw; + } + catch (utf8::invalid_code_point) { + std::string msg("utf8::invalid_code_point"); + error(msg, pstate, traces); + } + catch (utf8::not_enough_room) { + std::string msg("utf8::not_enough_room"); + error(msg, pstate, traces); + } + catch (utf8::invalid_utf8) { + std::string msg("utf8::invalid_utf8"); + error(msg, pstate, traces); + } + catch (...) { throw; } + } + + /////////////////// + // STRING FUNCTIONS + /////////////////// + + Signature unquote_sig = "unquote($string)"; + BUILT_IN(sass_unquote) + { + AST_Node_Obj arg = env["$string"]; + if (String_Quoted_Ptr string_quoted = Cast(arg)) { + String_Constant_Ptr result = SASS_MEMORY_NEW(String_Constant, pstate, string_quoted->value()); + // remember if the string was quoted (color tokens) + result->is_delayed(true); // delay colors + return result; + } + else if (String_Constant_Ptr str = Cast(arg)) { + return str; + } + else if (Value_Ptr ex = Cast(arg)) { + Sass_Output_Style oldstyle = ctx.c_options.output_style; + ctx.c_options.output_style = SASS_STYLE_NESTED; + std::string val(arg->to_string(ctx.c_options)); + val = Cast(arg) ? "null" : val; + ctx.c_options.output_style = oldstyle; + + deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate); + return ex; + } + throw std::runtime_error("Invalid Data Type for unquote"); + } + + Signature quote_sig = "quote($string)"; + BUILT_IN(sass_quote) + { + AST_Node_Obj arg = env["$string"]; + // only set quote mark to true if already a string + if (String_Quoted_Ptr qstr = Cast(arg)) { + qstr->quote_mark('*'); + return qstr; + } + // all other nodes must be converted to a string node + std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote())); + String_Quoted_Ptr result = SASS_MEMORY_NEW(String_Quoted, pstate, str); + result->quote_mark('*'); + return result; + } + + + Signature str_length_sig = "str-length($string)"; + BUILT_IN(str_length) + { + size_t len = std::string::npos; + try { + String_Constant_Ptr s = ARG("$string", String_Constant); + len = UTF_8::code_point_count(s->value(), 0, s->value().size()); + + } + // handle any invalid utf8 errors + // other errors will be re-thrown + catch (...) { handle_utf8_error(pstate, traces); } + // return something even if we had an error (-1) + return SASS_MEMORY_NEW(Number, pstate, (double)len); + } + + Signature str_insert_sig = "str-insert($string, $insert, $index)"; + BUILT_IN(str_insert) + { + std::string str; + try { + String_Constant_Ptr s = ARG("$string", String_Constant); + str = s->value(); + str = unquote(str); + String_Constant_Ptr i = ARG("$insert", String_Constant); + std::string ins = i->value(); + ins = unquote(ins); + double index = ARGVAL("$index"); + size_t len = UTF_8::code_point_count(str, 0, str.size()); + + if (index > 0 && index <= len) { + // positive and within string length + str.insert(UTF_8::offset_at_position(str, static_cast(index) - 1), ins); + } + else if (index > len) { + // positive and past string length + str += ins; + } + else if (index == 0) { + str = ins + str; + } + else if (std::abs(index) <= len) { + // negative and within string length + index += len + 1; + str.insert(UTF_8::offset_at_position(str, static_cast(index)), ins); + } + else { + // negative and past string length + str = ins + str; + } + + if (String_Quoted_Ptr ss = Cast(s)) { + if (ss->quote_mark()) str = quote(str); + } + } + // handle any invalid utf8 errors + // other errors will be re-thrown + catch (...) { handle_utf8_error(pstate, traces); } + return SASS_MEMORY_NEW(String_Quoted, pstate, str); + } + + Signature str_index_sig = "str-index($string, $substring)"; + BUILT_IN(str_index) + { + size_t index = std::string::npos; + try { + String_Constant_Ptr s = ARG("$string", String_Constant); + String_Constant_Ptr t = ARG("$substring", String_Constant); + std::string str = s->value(); + str = unquote(str); + std::string substr = t->value(); + substr = unquote(substr); + + size_t c_index = str.find(substr); + if(c_index == std::string::npos) { + return SASS_MEMORY_NEW(Null, pstate); + } + index = UTF_8::code_point_count(str, 0, c_index) + 1; + } + // handle any invalid utf8 errors + // other errors will be re-thrown + catch (...) { handle_utf8_error(pstate, traces); } + // return something even if we had an error (-1) + return SASS_MEMORY_NEW(Number, pstate, (double)index); + } + + Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)"; + BUILT_IN(str_slice) + { + std::string newstr; + try { + String_Constant_Ptr s = ARG("$string", String_Constant); + double start_at = ARGVAL("$start-at"); + double end_at = ARGVAL("$end-at"); + String_Quoted_Ptr ss = Cast(s); + + std::string str = unquote(s->value()); + + size_t size = utf8::distance(str.begin(), str.end()); + + if (!Cast(env["$end-at"])) { + end_at = -1; + } + + if (end_at == 0 || (end_at + size) < 0) { + if (ss && ss->quote_mark()) newstr = quote(""); + return SASS_MEMORY_NEW(String_Quoted, pstate, newstr); + } + + if (end_at < 0) { + end_at += size + 1; + if (end_at == 0) end_at = 1; + } + if (end_at > size) { end_at = (double)size; } + if (start_at < 0) { + start_at += size + 1; + if (start_at < 0) start_at = 0; + } + else if (start_at == 0) { ++ start_at; } + + if (start_at <= end_at) + { + std::string::iterator start = str.begin(); + utf8::advance(start, start_at - 1, str.end()); + std::string::iterator end = start; + utf8::advance(end, end_at - start_at + 1, str.end()); + newstr = std::string(start, end); + } + if (ss) { + if(ss->quote_mark()) newstr = quote(newstr); + } + } + // handle any invalid utf8 errors + // other errors will be re-thrown + catch (...) { handle_utf8_error(pstate, traces); } + return SASS_MEMORY_NEW(String_Quoted, pstate, newstr); + } + + Signature to_upper_case_sig = "to-upper-case($string)"; + BUILT_IN(to_upper_case) + { + String_Constant_Ptr s = ARG("$string", String_Constant); + std::string str = s->value(); + + for (size_t i = 0, L = str.length(); i < L; ++i) { + if (Sass::Util::isAscii(str[i])) { + str[i] = std::toupper(str[i]); + } + } + + if (String_Quoted_Ptr ss = Cast(s)) { + String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss); + cpy->value(str); + return cpy; + } else { + return SASS_MEMORY_NEW(String_Quoted, pstate, str); + } + } + + Signature to_lower_case_sig = "to-lower-case($string)"; + BUILT_IN(to_lower_case) + { + String_Constant_Ptr s = ARG("$string", String_Constant); + std::string str = s->value(); + + for (size_t i = 0, L = str.length(); i < L; ++i) { + if (Sass::Util::isAscii(str[i])) { + str[i] = std::tolower(str[i]); + } + } + + if (String_Quoted_Ptr ss = Cast(s)) { + String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss); + cpy->value(str); + return cpy; + } else { + return SASS_MEMORY_NEW(String_Quoted, pstate, str); + } + } + + } + +} diff --git a/src/fn_strings.hpp b/src/fn_strings.hpp new file mode 100644 index 000000000..4a1ed1900 --- /dev/null +++ b/src/fn_strings.hpp @@ -0,0 +1,34 @@ +#ifndef SASS_FN_STRINGS_H +#define SASS_FN_STRINGS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + extern Signature unquote_sig; + extern Signature quote_sig; + extern Signature str_length_sig; + extern Signature str_insert_sig; + extern Signature str_index_sig; + extern Signature str_slice_sig; + extern Signature to_upper_case_sig; + extern Signature to_lower_case_sig; + extern Signature length_sig; + + BUILT_IN(sass_unquote); + BUILT_IN(sass_quote); + BUILT_IN(str_length); + BUILT_IN(str_insert); + BUILT_IN(str_index); + BUILT_IN(str_slice); + BUILT_IN(to_upper_case); + BUILT_IN(to_lower_case); + BUILT_IN(length); + + } + +} + +#endif diff --git a/src/functions.cpp b/src/functions.cpp index b2ba02451..b0b8e7a66 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -28,6 +28,7 @@ #include "fn_utils.hpp" #include "fn_colors.hpp" #include "fn_numbers.hpp" +#include "fn_strings.hpp" #include "fn_selectors.hpp" namespace Sass { @@ -42,26 +43,6 @@ namespace Sass { namespace Functions { - inline void handle_utf8_error (const ParserState& pstate, Backtraces traces) - { - try { - throw; - } - catch (utf8::invalid_code_point) { - std::string msg("utf8::invalid_code_point"); - error(msg, pstate, traces); - } - catch (utf8::not_enough_room) { - std::string msg("utf8::not_enough_room"); - error(msg, pstate, traces); - } - catch (utf8::invalid_utf8) { - std::string msg("utf8::invalid_utf8"); - error(msg, pstate, traces); - } - catch (...) { throw; } - } - // features static std::set features { "global-variable-shadowing", @@ -71,232 +52,6 @@ namespace Sass { "custom-property" }; - /////////////////// - // STRING FUNCTIONS - /////////////////// - - Signature unquote_sig = "unquote($string)"; - BUILT_IN(sass_unquote) - { - AST_Node_Obj arg = env["$string"]; - if (String_Quoted_Ptr string_quoted = Cast(arg)) { - String_Constant_Ptr result = SASS_MEMORY_NEW(String_Constant, pstate, string_quoted->value()); - // remember if the string was quoted (color tokens) - result->is_delayed(true); // delay colors - return result; - } - else if (String_Constant_Ptr str = Cast(arg)) { - return str; - } - else if (Expression_Ptr ex = Cast(arg)) { - Sass_Output_Style oldstyle = ctx.c_options.output_style; - ctx.c_options.output_style = SASS_STYLE_NESTED; - std::string val(arg->to_string(ctx.c_options)); - val = Cast(arg) ? "null" : val; - ctx.c_options.output_style = oldstyle; - - deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate); - return ex; - } - throw std::runtime_error("Invalid Data Type for unquote"); - } - - Signature quote_sig = "quote($string)"; - BUILT_IN(sass_quote) - { - AST_Node_Obj arg = env["$string"]; - // only set quote mark to true if already a string - if (String_Quoted_Ptr qstr = Cast(arg)) { - qstr->quote_mark('*'); - return qstr; - } - // all other nodes must be converted to a string node - std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote())); - String_Quoted_Ptr result = SASS_MEMORY_NEW(String_Quoted, pstate, str); - result->quote_mark('*'); - return result; - } - - - Signature str_length_sig = "str-length($string)"; - BUILT_IN(str_length) - { - size_t len = std::string::npos; - try { - String_Constant_Ptr s = ARG("$string", String_Constant); - len = UTF_8::code_point_count(s->value(), 0, s->value().size()); - - } - // handle any invalid utf8 errors - // other errors will be re-thrown - catch (...) { handle_utf8_error(pstate, traces); } - // return something even if we had an error (-1) - return SASS_MEMORY_NEW(Number, pstate, (double)len); - } - - Signature str_insert_sig = "str-insert($string, $insert, $index)"; - BUILT_IN(str_insert) - { - std::string str; - try { - String_Constant_Ptr s = ARG("$string", String_Constant); - str = s->value(); - str = unquote(str); - String_Constant_Ptr i = ARG("$insert", String_Constant); - std::string ins = i->value(); - ins = unquote(ins); - double index = ARGVAL("$index"); - size_t len = UTF_8::code_point_count(str, 0, str.size()); - - if (index > 0 && index <= len) { - // positive and within string length - str.insert(UTF_8::offset_at_position(str, static_cast(index) - 1), ins); - } - else if (index > len) { - // positive and past string length - str += ins; - } - else if (index == 0) { - str = ins + str; - } - else if (std::abs(index) <= len) { - // negative and within string length - index += len + 1; - str.insert(UTF_8::offset_at_position(str, static_cast(index)), ins); - } - else { - // negative and past string length - str = ins + str; - } - - if (String_Quoted_Ptr ss = Cast(s)) { - if (ss->quote_mark()) str = quote(str); - } - } - // handle any invalid utf8 errors - // other errors will be re-thrown - catch (...) { handle_utf8_error(pstate, traces); } - return SASS_MEMORY_NEW(String_Quoted, pstate, str); - } - - Signature str_index_sig = "str-index($string, $substring)"; - BUILT_IN(str_index) - { - size_t index = std::string::npos; - try { - String_Constant_Ptr s = ARG("$string", String_Constant); - String_Constant_Ptr t = ARG("$substring", String_Constant); - std::string str = s->value(); - str = unquote(str); - std::string substr = t->value(); - substr = unquote(substr); - - size_t c_index = str.find(substr); - if(c_index == std::string::npos) { - return SASS_MEMORY_NEW(Null, pstate); - } - index = UTF_8::code_point_count(str, 0, c_index) + 1; - } - // handle any invalid utf8 errors - // other errors will be re-thrown - catch (...) { handle_utf8_error(pstate, traces); } - // return something even if we had an error (-1) - return SASS_MEMORY_NEW(Number, pstate, (double)index); - } - - Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)"; - BUILT_IN(str_slice) - { - std::string newstr; - try { - String_Constant_Ptr s = ARG("$string", String_Constant); - double start_at = ARGVAL("$start-at"); - double end_at = ARGVAL("$end-at"); - String_Quoted_Ptr ss = Cast(s); - - std::string str = unquote(s->value()); - - size_t size = utf8::distance(str.begin(), str.end()); - - if (!Cast(env["$end-at"])) { - end_at = -1; - } - - if (end_at == 0 || (end_at + size) < 0) { - if (ss && ss->quote_mark()) newstr = quote(""); - return SASS_MEMORY_NEW(String_Quoted, pstate, newstr); - } - - if (end_at < 0) { - end_at += size + 1; - if (end_at == 0) end_at = 1; - } - if (end_at > size) { end_at = (double)size; } - if (start_at < 0) { - start_at += size + 1; - if (start_at < 0) start_at = 0; - } - else if (start_at == 0) { ++ start_at; } - - if (start_at <= end_at) - { - std::string::iterator start = str.begin(); - utf8::advance(start, start_at - 1, str.end()); - std::string::iterator end = start; - utf8::advance(end, end_at - start_at + 1, str.end()); - newstr = std::string(start, end); - } - if (ss) { - if(ss->quote_mark()) newstr = quote(newstr); - } - } - // handle any invalid utf8 errors - // other errors will be re-thrown - catch (...) { handle_utf8_error(pstate, traces); } - return SASS_MEMORY_NEW(String_Quoted, pstate, newstr); - } - - Signature to_upper_case_sig = "to-upper-case($string)"; - BUILT_IN(to_upper_case) - { - String_Constant_Ptr s = ARG("$string", String_Constant); - std::string str = s->value(); - - for (size_t i = 0, L = str.length(); i < L; ++i) { - if (Sass::Util::isAscii(str[i])) { - str[i] = std::toupper(str[i]); - } - } - - if (String_Quoted_Ptr ss = Cast(s)) { - String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss); - cpy->value(str); - return cpy; - } else { - return SASS_MEMORY_NEW(String_Quoted, pstate, str); - } - } - - Signature to_lower_case_sig = "to-lower-case($string)"; - BUILT_IN(to_lower_case) - { - String_Constant_Ptr s = ARG("$string", String_Constant); - std::string str = s->value(); - - for (size_t i = 0, L = str.length(); i < L; ++i) { - if (Sass::Util::isAscii(str[i])) { - str[i] = std::tolower(str[i]); - } - } - - if (String_Quoted_Ptr ss = Cast(s)) { - String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss); - cpy->value(str); - return cpy; - } else { - return SASS_MEMORY_NEW(String_Quoted, pstate, str); - } - } ///////////////// // LIST FUNCTIONS ///////////////// diff --git a/src/functions.hpp b/src/functions.hpp index 58c57b87f..e6bbc07ce 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -17,14 +17,6 @@ namespace Sass { namespace Functions { - extern Signature unquote_sig; - extern Signature quote_sig; - extern Signature str_length_sig; - extern Signature str_insert_sig; - extern Signature str_index_sig; - extern Signature str_slice_sig; - extern Signature to_upper_case_sig; - extern Signature to_lower_case_sig; extern Signature length_sig; extern Signature nth_sig; extern Signature index_sig; @@ -53,15 +45,6 @@ namespace Sass { extern Signature content_exists_sig; extern Signature get_function_sig; - BUILT_IN(sass_unquote); - BUILT_IN(sass_quote); - BUILT_IN(str_length); - BUILT_IN(str_insert); - BUILT_IN(str_index); - BUILT_IN(str_slice); - BUILT_IN(to_upper_case); - BUILT_IN(to_lower_case); - BUILT_IN(inspect); BUILT_IN(length); BUILT_IN(nth); BUILT_IN(index); diff --git a/win/libsass.targets b/win/libsass.targets index 97dbecec8..21e74f82f 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -36,6 +36,7 @@ + @@ -93,6 +94,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index db2f369ad..30b43fbf0 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -120,6 +120,9 @@ Headers + + Headers + Headers @@ -290,6 +293,9 @@ Sources + + Sources + Sources From 4d1e036a72a2f7ff72a7ad4093cf6f6054d6822a Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 02:11:35 +0100 Subject: [PATCH 08/30] Move list functions to own compile unit --- Makefile.conf | 1 + src/context.cpp | 1 + src/fn_lists.cpp | 284 ++++++++++++++++++++++++++++++++++++ src/fn_lists.hpp | 34 +++++ src/functions.cpp | 273 +--------------------------------- src/functions.hpp | 20 --- win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 + 8 files changed, 329 insertions(+), 292 deletions(-) create mode 100644 src/fn_lists.cpp create mode 100644 src/fn_lists.hpp diff --git a/Makefile.conf b/Makefile.conf index d5c2e23e3..9b4bfc84c 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -11,6 +11,7 @@ SOURCES = \ context.cpp \ constants.cpp \ fn_utils.cpp \ + fn_lists.cpp \ fn_colors.cpp \ fn_numbers.cpp \ fn_strings.cpp \ diff --git a/src/context.cpp b/src/context.cpp index d8c688e5f..67354254a 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -30,6 +30,7 @@ #include "prelexer.hpp" #include "emitter.hpp" #include "fn_utils.hpp" +#include "fn_lists.hpp" #include "fn_colors.hpp" #include "fn_numbers.hpp" #include "fn_strings.hpp" diff --git a/src/fn_lists.cpp b/src/fn_lists.cpp new file mode 100644 index 000000000..b17da6398 --- /dev/null +++ b/src/fn_lists.cpp @@ -0,0 +1,284 @@ +#include "listize.hpp" +#include "operators.hpp" +#include "fn_utils.hpp" +#include "fn_lists.hpp" + +namespace Sass { + + namespace Functions { + + ///////////////// + // LIST FUNCTIONS + ///////////////// + + Signature keywords_sig = "keywords($args)"; + BUILT_IN(keywords) + { + List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); // copy + Map_Obj result = SASS_MEMORY_NEW(Map, pstate, 1); + for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) { + Expression_Obj obj = arglist->at(i); + Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX + std::string name = std::string(arg->name()); + name = name.erase(0, 1); // sanitize name (remove dollar sign) + *result << std::make_pair(SASS_MEMORY_NEW(String_Quoted, + pstate, name), + arg->value()); + } + return result.detach(); + } + + Signature length_sig = "length($list)"; + BUILT_IN(length) + { + if (Selector_List_Ptr sl = Cast(env["$list"])) { + return SASS_MEMORY_NEW(Number, pstate, (double)sl->length()); + } + Expression_Ptr v = ARG("$list", Expression); + if (v->concrete_type() == Expression::MAP) { + Map_Ptr map = Cast(env["$list"]); + return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1)); + } + if (v->concrete_type() == Expression::SELECTOR) { + if (Compound_Selector_Ptr h = Cast(v)) { + return SASS_MEMORY_NEW(Number, pstate, (double)h->length()); + } else if (Selector_List_Ptr ls = Cast(v)) { + return SASS_MEMORY_NEW(Number, pstate, (double)ls->length()); + } else { + return SASS_MEMORY_NEW(Number, pstate, 1); + } + } + + List_Ptr list = Cast(env["$list"]); + return SASS_MEMORY_NEW(Number, + pstate, + (double)(list ? list->size() : 1)); + } + + Signature nth_sig = "nth($list, $n)"; + BUILT_IN(nth) + { + double nr = ARGVAL("$n"); + Map_Ptr m = Cast(env["$list"]); + if (Selector_List_Ptr sl = Cast(env["$list"])) { + size_t len = m ? m->length() : sl->length(); + bool empty = m ? m->empty() : sl->empty(); + if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces); + double index = std::floor(nr < 0 ? len + nr : nr - 1); + if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces); + // return (*sl)[static_cast(index)]; + Listize listize; + return Cast((*sl)[static_cast(index)]->perform(&listize)); + } + List_Obj l = Cast(env["$list"]); + if (nr == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate, traces); + // if the argument isn't a list, then wrap it in a singleton list + if (!m && !l) { + l = SASS_MEMORY_NEW(List, pstate, 1); + l->append(ARG("$list", Expression)); + } + size_t len = m ? m->length() : l->length(); + bool empty = m ? m->empty() : l->empty(); + if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces); + double index = std::floor(nr < 0 ? len + nr : nr - 1); + if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces); + + if (m) { + l = SASS_MEMORY_NEW(List, pstate, 1); + l->append(m->keys()[static_cast(index)]); + l->append(m->at(m->keys()[static_cast(index)])); + return l.detach(); + } + else { + Value_Obj rv = l->value_at_index(static_cast(index)); + rv->set_delayed(false); + return rv.detach(); + } + } + + Signature set_nth_sig = "set-nth($list, $n, $value)"; + BUILT_IN(set_nth) + { + Map_Obj m = Cast(env["$list"]); + List_Obj l = Cast(env["$list"]); + Number_Obj n = ARG("$n", Number); + Expression_Obj v = ARG("$value", Expression); + if (!l) { + l = SASS_MEMORY_NEW(List, pstate, 1); + l->append(ARG("$list", Expression)); + } + if (m) { + l = m->to_list(pstate); + } + if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces); + double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1); + if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces); + List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator(), false, l->is_bracketed()); + for (size_t i = 0, L = l->length(); i < L; ++i) { + result->append(((i == index) ? v : (*l)[i])); + } + return result; + } + + Signature index_sig = "index($list, $value)"; + BUILT_IN(index) + { + Map_Obj m = Cast(env["$list"]); + List_Obj l = Cast(env["$list"]); + Expression_Obj v = ARG("$value", Expression); + if (!l) { + l = SASS_MEMORY_NEW(List, pstate, 1); + l->append(ARG("$list", Expression)); + } + if (m) { + l = m->to_list(pstate); + } + for (size_t i = 0, L = l->length(); i < L; ++i) { + if (Operators::eq(l->value_at_index(i), v)) return SASS_MEMORY_NEW(Number, pstate, (double)(i+1)); + } + return SASS_MEMORY_NEW(Null, pstate); + } + + Signature join_sig = "join($list1, $list2, $separator: auto, $bracketed: auto)"; + BUILT_IN(join) + { + Map_Obj m1 = Cast(env["$list1"]); + Map_Obj m2 = Cast(env["$list2"]); + List_Obj l1 = Cast(env["$list1"]); + List_Obj l2 = Cast(env["$list2"]); + String_Constant_Obj sep = ARG("$separator", String_Constant); + enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE); + Value* bracketed = ARG("$bracketed", Value); + bool is_bracketed = (l1 ? l1->is_bracketed() : false); + if (!l1) { + l1 = SASS_MEMORY_NEW(List, pstate, 1); + l1->append(ARG("$list1", Expression)); + sep_val = (l2 ? l2->separator() : SASS_SPACE); + is_bracketed = (l2 ? l2->is_bracketed() : false); + } + if (!l2) { + l2 = SASS_MEMORY_NEW(List, pstate, 1); + l2->append(ARG("$list2", Expression)); + } + if (m1) { + l1 = m1->to_list(pstate); + sep_val = SASS_COMMA; + } + if (m2) { + l2 = m2->to_list(pstate); + } + size_t len = l1->length() + l2->length(); + std::string sep_str = unquote(sep->value()); + if (sep_str == "space") sep_val = SASS_SPACE; + else if (sep_str == "comma") sep_val = SASS_COMMA; + else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces); + String_Constant_Obj bracketed_as_str = Cast(bracketed); + bool bracketed_is_auto = bracketed_as_str && unquote(bracketed_as_str->value()) == "auto"; + if (!bracketed_is_auto) { + is_bracketed = !bracketed->is_false(); + } + List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val, false, is_bracketed); + result->concat(l1); + result->concat(l2); + return result.detach(); + } + + Signature append_sig = "append($list, $val, $separator: auto)"; + BUILT_IN(append) + { + Map_Obj m = Cast(env["$list"]); + List_Obj l = Cast(env["$list"]); + Expression_Obj v = ARG("$val", Expression); + if (Selector_List_Ptr sl = Cast(env["$list"])) { + Listize listize; + l = Cast(sl->perform(&listize)); + } + String_Constant_Obj sep = ARG("$separator", String_Constant); + if (!l) { + l = SASS_MEMORY_NEW(List, pstate, 1); + l->append(ARG("$list", Expression)); + } + if (m) { + l = m->to_list(pstate); + } + List_Ptr result = SASS_MEMORY_COPY(l); + std::string sep_str(unquote(sep->value())); + if (sep_str != "auto") { // check default first + if (sep_str == "space") result->separator(SASS_SPACE); + else if (sep_str == "comma") result->separator(SASS_COMMA); + else error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces); + } + if (l->is_arglist()) { + result->append(SASS_MEMORY_NEW(Argument, + v->pstate(), + v, + "", + false, + false)); + + } else { + result->append(v); + } + return result; + } + + Signature zip_sig = "zip($lists...)"; + BUILT_IN(zip) + { + List_Obj arglist = SASS_MEMORY_COPY(ARG("$lists", List)); + size_t shortest = 0; + for (size_t i = 0, L = arglist->length(); i < L; ++i) { + List_Obj ith = Cast(arglist->value_at_index(i)); + Map_Obj mith = Cast(arglist->value_at_index(i)); + if (!ith) { + if (mith) { + ith = mith->to_list(pstate); + } else { + ith = SASS_MEMORY_NEW(List, pstate, 1); + ith->append(arglist->value_at_index(i)); + } + if (arglist->is_arglist()) { + Argument_Obj arg = (Argument_Ptr)(arglist->at(i).ptr()); // XXX + arg->value(ith); + } else { + (*arglist)[i] = ith; + } + } + shortest = (i ? std::min(shortest, ith->length()) : ith->length()); + } + List_Ptr zippers = SASS_MEMORY_NEW(List, pstate, shortest, SASS_COMMA); + size_t L = arglist->length(); + for (size_t i = 0; i < shortest; ++i) { + List_Ptr zipper = SASS_MEMORY_NEW(List, pstate, L); + for (size_t j = 0; j < L; ++j) { + zipper->append(Cast(arglist->value_at_index(j))->at(i)); + } + zippers->append(zipper); + } + return zippers; + } + + Signature list_separator_sig = "list_separator($list)"; + BUILT_IN(list_separator) + { + List_Obj l = Cast(env["$list"]); + if (!l) { + l = SASS_MEMORY_NEW(List, pstate, 1); + l->append(ARG("$list", Expression)); + } + return SASS_MEMORY_NEW(String_Quoted, + pstate, + l->separator() == SASS_COMMA ? "comma" : "space"); + } + + Signature is_bracketed_sig = "is-bracketed($list)"; + BUILT_IN(is_bracketed) + { + Value_Obj value = ARG("$list", Value); + List_Obj list = Cast(value); + return SASS_MEMORY_NEW(Boolean, pstate, list && list->is_bracketed()); + } + + } + +} \ No newline at end of file diff --git a/src/fn_lists.hpp b/src/fn_lists.hpp new file mode 100644 index 000000000..260023aeb --- /dev/null +++ b/src/fn_lists.hpp @@ -0,0 +1,34 @@ +#ifndef SASS_FN_LISTS_H +#define SASS_FN_LISTS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + extern Signature length_sig; + extern Signature nth_sig; + extern Signature index_sig; + extern Signature join_sig; + extern Signature append_sig; + extern Signature zip_sig; + extern Signature list_separator_sig; + extern Signature is_bracketed_sig; + extern Signature keywords_sig; + + BUILT_IN(length); + BUILT_IN(nth); + BUILT_IN(index); + BUILT_IN(join); + BUILT_IN(append); + BUILT_IN(zip); + BUILT_IN(list_separator); + BUILT_IN(is_bracketed); + BUILT_IN(keywords); + + } + +} + +#endif diff --git a/src/functions.cpp b/src/functions.cpp index b0b8e7a66..e098e96c3 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -26,6 +26,7 @@ #include #include "fn_utils.hpp" +#include "fn_lists.hpp" #include "fn_colors.hpp" #include "fn_numbers.hpp" #include "fn_strings.hpp" @@ -52,253 +53,6 @@ namespace Sass { "custom-property" }; - ///////////////// - // LIST FUNCTIONS - ///////////////// - - Signature length_sig = "length($list)"; - BUILT_IN(length) - { - if (Selector_List_Ptr sl = Cast(env["$list"])) { - return SASS_MEMORY_NEW(Number, pstate, (double)sl->length()); - } - Expression_Ptr v = ARG("$list", Expression); - if (v->concrete_type() == Expression::MAP) { - Map_Ptr map = Cast(env["$list"]); - return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1)); - } - if (v->concrete_type() == Expression::SELECTOR) { - if (Compound_Selector_Ptr h = Cast(v)) { - return SASS_MEMORY_NEW(Number, pstate, (double)h->length()); - } else if (Selector_List_Ptr ls = Cast(v)) { - return SASS_MEMORY_NEW(Number, pstate, (double)ls->length()); - } else { - return SASS_MEMORY_NEW(Number, pstate, 1); - } - } - - List_Ptr list = Cast(env["$list"]); - return SASS_MEMORY_NEW(Number, - pstate, - (double)(list ? list->size() : 1)); - } - - Signature nth_sig = "nth($list, $n)"; - BUILT_IN(nth) - { - double nr = ARGVAL("$n"); - Map_Ptr m = Cast(env["$list"]); - if (Selector_List_Ptr sl = Cast(env["$list"])) { - size_t len = m ? m->length() : sl->length(); - bool empty = m ? m->empty() : sl->empty(); - if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces); - double index = std::floor(nr < 0 ? len + nr : nr - 1); - if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces); - // return (*sl)[static_cast(index)]; - Listize listize; - return (*sl)[static_cast(index)]->perform(&listize); - } - List_Obj l = Cast(env["$list"]); - if (nr == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate, traces); - // if the argument isn't a list, then wrap it in a singleton list - if (!m && !l) { - l = SASS_MEMORY_NEW(List, pstate, 1); - l->append(ARG("$list", Expression)); - } - size_t len = m ? m->length() : l->length(); - bool empty = m ? m->empty() : l->empty(); - if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces); - double index = std::floor(nr < 0 ? len + nr : nr - 1); - if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces); - - if (m) { - l = SASS_MEMORY_NEW(List, pstate, 1); - l->append(m->keys()[static_cast(index)]); - l->append(m->at(m->keys()[static_cast(index)])); - return l.detach(); - } - else { - Expression_Obj rv = l->value_at_index(static_cast(index)); - rv->set_delayed(false); - return rv.detach(); - } - } - - Signature set_nth_sig = "set-nth($list, $n, $value)"; - BUILT_IN(set_nth) - { - Map_Obj m = Cast(env["$list"]); - List_Obj l = Cast(env["$list"]); - Number_Obj n = ARG("$n", Number); - Expression_Obj v = ARG("$value", Expression); - if (!l) { - l = SASS_MEMORY_NEW(List, pstate, 1); - l->append(ARG("$list", Expression)); - } - if (m) { - l = m->to_list(pstate); - } - if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces); - double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1); - if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces); - List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator(), false, l->is_bracketed()); - for (size_t i = 0, L = l->length(); i < L; ++i) { - result->append(((i == index) ? v : (*l)[i])); - } - return result; - } - - Signature index_sig = "index($list, $value)"; - BUILT_IN(index) - { - Map_Obj m = Cast(env["$list"]); - List_Obj l = Cast(env["$list"]); - Expression_Obj v = ARG("$value", Expression); - if (!l) { - l = SASS_MEMORY_NEW(List, pstate, 1); - l->append(ARG("$list", Expression)); - } - if (m) { - l = m->to_list(pstate); - } - for (size_t i = 0, L = l->length(); i < L; ++i) { - if (Operators::eq(l->value_at_index(i), v)) return SASS_MEMORY_NEW(Number, pstate, (double)(i+1)); - } - return SASS_MEMORY_NEW(Null, pstate); - } - - Signature join_sig = "join($list1, $list2, $separator: auto, $bracketed: auto)"; - BUILT_IN(join) - { - Map_Obj m1 = Cast(env["$list1"]); - Map_Obj m2 = Cast(env["$list2"]); - List_Obj l1 = Cast(env["$list1"]); - List_Obj l2 = Cast(env["$list2"]); - String_Constant_Obj sep = ARG("$separator", String_Constant); - enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE); - Value* bracketed = ARG("$bracketed", Value); - bool is_bracketed = (l1 ? l1->is_bracketed() : false); - if (!l1) { - l1 = SASS_MEMORY_NEW(List, pstate, 1); - l1->append(ARG("$list1", Expression)); - sep_val = (l2 ? l2->separator() : SASS_SPACE); - is_bracketed = (l2 ? l2->is_bracketed() : false); - } - if (!l2) { - l2 = SASS_MEMORY_NEW(List, pstate, 1); - l2->append(ARG("$list2", Expression)); - } - if (m1) { - l1 = m1->to_list(pstate); - sep_val = SASS_COMMA; - } - if (m2) { - l2 = m2->to_list(pstate); - } - size_t len = l1->length() + l2->length(); - std::string sep_str = unquote(sep->value()); - if (sep_str == "space") sep_val = SASS_SPACE; - else if (sep_str == "comma") sep_val = SASS_COMMA; - else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces); - String_Constant_Obj bracketed_as_str = Cast(bracketed); - bool bracketed_is_auto = bracketed_as_str && unquote(bracketed_as_str->value()) == "auto"; - if (!bracketed_is_auto) { - is_bracketed = !bracketed->is_false(); - } - List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val, false, is_bracketed); - result->concat(l1); - result->concat(l2); - return result.detach(); - } - - Signature append_sig = "append($list, $val, $separator: auto)"; - BUILT_IN(append) - { - Map_Obj m = Cast(env["$list"]); - List_Obj l = Cast(env["$list"]); - Expression_Obj v = ARG("$val", Expression); - if (Selector_List_Ptr sl = Cast(env["$list"])) { - Listize listize; - l = Cast(sl->perform(&listize)); - } - String_Constant_Obj sep = ARG("$separator", String_Constant); - if (!l) { - l = SASS_MEMORY_NEW(List, pstate, 1); - l->append(ARG("$list", Expression)); - } - if (m) { - l = m->to_list(pstate); - } - List_Ptr result = SASS_MEMORY_COPY(l); - std::string sep_str(unquote(sep->value())); - if (sep_str != "auto") { // check default first - if (sep_str == "space") result->separator(SASS_SPACE); - else if (sep_str == "comma") result->separator(SASS_COMMA); - else error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces); - } - if (l->is_arglist()) { - result->append(SASS_MEMORY_NEW(Argument, - v->pstate(), - v, - "", - false, - false)); - - } else { - result->append(v); - } - return result; - } - - Signature zip_sig = "zip($lists...)"; - BUILT_IN(zip) - { - List_Obj arglist = SASS_MEMORY_COPY(ARG("$lists", List)); - size_t shortest = 0; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { - List_Obj ith = Cast(arglist->value_at_index(i)); - Map_Obj mith = Cast(arglist->value_at_index(i)); - if (!ith) { - if (mith) { - ith = mith->to_list(pstate); - } else { - ith = SASS_MEMORY_NEW(List, pstate, 1); - ith->append(arglist->value_at_index(i)); - } - if (arglist->is_arglist()) { - Argument_Obj arg = (Argument_Ptr)(arglist->at(i).ptr()); // XXX - arg->value(ith); - } else { - (*arglist)[i] = ith; - } - } - shortest = (i ? std::min(shortest, ith->length()) : ith->length()); - } - List_Ptr zippers = SASS_MEMORY_NEW(List, pstate, shortest, SASS_COMMA); - size_t L = arglist->length(); - for (size_t i = 0; i < shortest; ++i) { - List_Ptr zipper = SASS_MEMORY_NEW(List, pstate, L); - for (size_t j = 0; j < L; ++j) { - zipper->append(Cast(arglist->value_at_index(j))->at(i)); - } - zippers->append(zipper); - } - return zippers; - } - - Signature list_separator_sig = "list_separator($list)"; - BUILT_IN(list_separator) - { - List_Obj l = Cast(env["$list"]); - if (!l) { - l = SASS_MEMORY_NEW(List, pstate, 1); - l->append(ARG("$list", Expression)); - } - return SASS_MEMORY_NEW(String_Quoted, - pstate, - l->separator() == SASS_COMMA ? "comma" : "space"); - } - ///////////////// // MAP FUNCTIONS ///////////////// @@ -382,23 +136,6 @@ namespace Sass { return result; } - Signature keywords_sig = "keywords($args)"; - BUILT_IN(keywords) - { - List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); // copy - Map_Obj result = SASS_MEMORY_NEW(Map, pstate, 1); - for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) { - Expression_Obj obj = arglist->at(i); - Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX - std::string name = std::string(arg->name()); - name = name.erase(0, 1); // sanitize name (remove dollar sign) - *result << std::make_pair(SASS_MEMORY_NEW(String_Quoted, - pstate, name), - arg->value()); - } - return result.detach(); - } - ////////////////////////// // INTROSPECTION FUNCTIONS ////////////////////////// @@ -587,14 +324,6 @@ namespace Sass { // return v; } - Signature is_bracketed_sig = "is-bracketed($list)"; - BUILT_IN(is_bracketed) - { - Value_Obj value = ARG("$list", Value); - List_Obj list = Cast(value); - return SASS_MEMORY_NEW(Boolean, pstate, list && list->is_bracketed()); - } - Signature content_exists_sig = "content-exists()"; BUILT_IN(content_exists) { diff --git a/src/functions.hpp b/src/functions.hpp index e6bbc07ce..547283361 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -17,13 +17,6 @@ namespace Sass { namespace Functions { - extern Signature length_sig; - extern Signature nth_sig; - extern Signature index_sig; - extern Signature join_sig; - extern Signature append_sig; - extern Signature zip_sig; - extern Signature list_separator_sig; extern Signature type_of_sig; extern Signature variable_exists_sig; extern Signature global_variable_exists_sig; @@ -39,19 +32,9 @@ namespace Sass { extern Signature map_keys_sig; extern Signature map_values_sig; extern Signature map_has_key_sig; - extern Signature keywords_sig; - extern Signature set_nth_sig; - extern Signature is_bracketed_sig; extern Signature content_exists_sig; extern Signature get_function_sig; - BUILT_IN(length); - BUILT_IN(nth); - BUILT_IN(index); - BUILT_IN(join); - BUILT_IN(append); - BUILT_IN(zip); - BUILT_IN(list_separator); BUILT_IN(type_of); BUILT_IN(variable_exists); BUILT_IN(global_variable_exists); @@ -67,9 +50,6 @@ namespace Sass { BUILT_IN(map_keys); BUILT_IN(map_values); BUILT_IN(map_has_key); - BUILT_IN(keywords); - BUILT_IN(set_nth); - BUILT_IN(is_bracketed); BUILT_IN(content_exists); BUILT_IN(get_function); } diff --git a/win/libsass.targets b/win/libsass.targets index 21e74f82f..3c2140388 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -34,6 +34,7 @@ + @@ -92,6 +93,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 30b43fbf0..fb2a715a1 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -114,6 +114,9 @@ Headers + + Headers + Headers @@ -287,6 +290,9 @@ Sources + + Sources + Sources From 47354add573d8f6ced7b70f084dbda7c2d923fea Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 02:19:40 +0100 Subject: [PATCH 09/30] Move map functions to own compile unit --- Makefile.conf | 1 + src/context.cpp | 1 + src/fn_maps.cpp | 94 +++++++++++++++++++++++++++++++++++++ src/fn_maps.hpp | 30 ++++++++++++ src/functions.cpp | 84 +-------------------------------- src/functions.hpp | 12 ----- win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 +++ 8 files changed, 135 insertions(+), 95 deletions(-) create mode 100644 src/fn_maps.cpp create mode 100644 src/fn_maps.hpp diff --git a/Makefile.conf b/Makefile.conf index 9b4bfc84c..fa74da819 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -11,6 +11,7 @@ SOURCES = \ context.cpp \ constants.cpp \ fn_utils.cpp \ + fn_maps.cpp \ fn_lists.cpp \ fn_colors.cpp \ fn_numbers.cpp \ diff --git a/src/context.cpp b/src/context.cpp index 67354254a..368863270 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -30,6 +30,7 @@ #include "prelexer.hpp" #include "emitter.hpp" #include "fn_utils.hpp" +#include "fn_maps.hpp" #include "fn_lists.hpp" #include "fn_colors.hpp" #include "fn_numbers.hpp" diff --git a/src/fn_maps.cpp b/src/fn_maps.cpp new file mode 100644 index 000000000..54a659433 --- /dev/null +++ b/src/fn_maps.cpp @@ -0,0 +1,94 @@ +#include "operators.hpp" +#include "fn_utils.hpp" +#include "fn_maps.hpp" + +namespace Sass { + + namespace Functions { + + ///////////////// + // MAP FUNCTIONS + ///////////////// + + Signature map_get_sig = "map-get($map, $key)"; + BUILT_IN(map_get) + { + // leaks for "map-get((), foo)" if not Obj + // investigate why this is (unexpected) + Map_Obj m = ARGM("$map", Map); + Expression_Obj v = ARG("$key", Expression); + try { + Value_Obj val = m->at(v); + if (!val) return SASS_MEMORY_NEW(Null, pstate); + val->set_delayed(false); + return val.detach(); + } catch (const std::out_of_range&) { + return SASS_MEMORY_NEW(Null, pstate); + } + catch (...) { throw; } + } + + Signature map_has_key_sig = "map-has-key($map, $key)"; + BUILT_IN(map_has_key) + { + Map_Obj m = ARGM("$map", Map); + Expression_Obj v = ARG("$key", Expression); + return SASS_MEMORY_NEW(Boolean, pstate, m->has(v)); + } + + Signature map_keys_sig = "map-keys($map)"; + BUILT_IN(map_keys) + { + Map_Obj m = ARGM("$map", Map); + List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA); + for ( auto key : m->keys()) { + result->append(key); + } + return result; + } + + Signature map_values_sig = "map-values($map)"; + BUILT_IN(map_values) + { + Map_Obj m = ARGM("$map", Map); + List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA); + for ( auto key : m->keys()) { + result->append(m->at(key)); + } + return result; + } + + Signature map_merge_sig = "map-merge($map1, $map2)"; + BUILT_IN(map_merge) + { + Map_Obj m1 = ARGM("$map1", Map); + Map_Obj m2 = ARGM("$map2", Map); + + size_t len = m1->length() + m2->length(); + Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, len); + // concat not implemented for maps + *result += m1; + *result += m2; + return result; + } + + Signature map_remove_sig = "map-remove($map, $keys...)"; + BUILT_IN(map_remove) + { + bool remove; + Map_Obj m = ARGM("$map", Map); + List_Obj arglist = ARG("$keys", List); + Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, 1); + for (auto key : m->keys()) { + remove = false; + for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) { + remove = Operators::eq(key, arglist->value_at_index(j)); + } + if (!remove) *result << std::make_pair(key, m->at(key)); + } + return result; + } + + } + +} \ No newline at end of file diff --git a/src/fn_maps.hpp b/src/fn_maps.hpp new file mode 100644 index 000000000..9551ec33e --- /dev/null +++ b/src/fn_maps.hpp @@ -0,0 +1,30 @@ +#ifndef SASS_FN_MAPS_H +#define SASS_FN_MAPS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + #define ARGM(argname, argtype) get_arg_m(argname, env, sig, pstate, traces) + + extern Signature map_get_sig; + extern Signature map_merge_sig; + extern Signature map_remove_sig; + extern Signature map_keys_sig; + extern Signature map_values_sig; + extern Signature map_has_key_sig; + + BUILT_IN(map_get); + BUILT_IN(map_merge); + BUILT_IN(map_remove); + BUILT_IN(map_keys); + BUILT_IN(map_values); + BUILT_IN(map_has_key); + + } + +} + +#endif diff --git a/src/functions.cpp b/src/functions.cpp index e098e96c3..d8ecdc826 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -26,6 +26,7 @@ #include #include "fn_utils.hpp" +#include "fn_maps.hpp" #include "fn_lists.hpp" #include "fn_colors.hpp" #include "fn_numbers.hpp" @@ -53,89 +54,6 @@ namespace Sass { "custom-property" }; - ///////////////// - // MAP FUNCTIONS - ///////////////// - - Signature map_get_sig = "map-get($map, $key)"; - BUILT_IN(map_get) - { - // leaks for "map-get((), foo)" if not Obj - // investigate why this is (unexpected) - Map_Obj m = ARGM("$map", Map, ctx); - Expression_Obj v = ARG("$key", Expression); - try { - Expression_Obj val = m->at(v); - if (!val) return SASS_MEMORY_NEW(Null, pstate); - val->set_delayed(false); - return val.detach(); - } catch (const std::out_of_range&) { - return SASS_MEMORY_NEW(Null, pstate); - } - catch (...) { throw; } - } - - Signature map_has_key_sig = "map-has-key($map, $key)"; - BUILT_IN(map_has_key) - { - Map_Obj m = ARGM("$map", Map, ctx); - Expression_Obj v = ARG("$key", Expression); - return SASS_MEMORY_NEW(Boolean, pstate, m->has(v)); - } - - Signature map_keys_sig = "map-keys($map)"; - BUILT_IN(map_keys) - { - Map_Obj m = ARGM("$map", Map, ctx); - List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA); - for ( auto key : m->keys()) { - result->append(key); - } - return result; - } - - Signature map_values_sig = "map-values($map)"; - BUILT_IN(map_values) - { - Map_Obj m = ARGM("$map", Map, ctx); - List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA); - for ( auto key : m->keys()) { - result->append(m->at(key)); - } - return result; - } - - Signature map_merge_sig = "map-merge($map1, $map2)"; - BUILT_IN(map_merge) - { - Map_Obj m1 = ARGM("$map1", Map, ctx); - Map_Obj m2 = ARGM("$map2", Map, ctx); - - size_t len = m1->length() + m2->length(); - Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, len); - // concat not implemented for maps - *result += m1; - *result += m2; - return result; - } - - Signature map_remove_sig = "map-remove($map, $keys...)"; - BUILT_IN(map_remove) - { - bool remove; - Map_Obj m = ARGM("$map", Map, ctx); - List_Obj arglist = ARG("$keys", List); - Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, 1); - for (auto key : m->keys()) { - remove = false; - for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) { - remove = Operators::eq(key, arglist->value_at_index(j)); - } - if (!remove) *result << std::make_pair(key, m->at(key)); - } - return result; - } - ////////////////////////// // INTROSPECTION FUNCTIONS ////////////////////////// diff --git a/src/functions.hpp b/src/functions.hpp index 547283361..da683abf9 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -26,12 +26,6 @@ namespace Sass { extern Signature call_sig; extern Signature not_sig; extern Signature if_sig; - extern Signature map_get_sig; - extern Signature map_merge_sig; - extern Signature map_remove_sig; - extern Signature map_keys_sig; - extern Signature map_values_sig; - extern Signature map_has_key_sig; extern Signature content_exists_sig; extern Signature get_function_sig; @@ -44,12 +38,6 @@ namespace Sass { BUILT_IN(call); BUILT_IN(sass_not); BUILT_IN(sass_if); - BUILT_IN(map_get); - BUILT_IN(map_merge); - BUILT_IN(map_remove); - BUILT_IN(map_keys); - BUILT_IN(map_values); - BUILT_IN(map_has_key); BUILT_IN(content_exists); BUILT_IN(get_function); } diff --git a/win/libsass.targets b/win/libsass.targets index 3c2140388..c26d7f858 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -34,6 +34,7 @@ + @@ -93,6 +94,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index fb2a715a1..9c0e3b562 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -114,6 +114,9 @@ Headers + + Headers + Headers @@ -290,6 +293,9 @@ Sources + + Sources + Sources From c1b367617216254a53288000e927ea2e86995d03 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 02:31:01 +0100 Subject: [PATCH 10/30] Move misc functions to own compile unit - clean up definitions of function macros --- Makefile.conf | 1 + src/context.cpp | 1 + src/error_handling.hpp | 1 + src/file.cpp | 1 + src/fn_miscs.cpp | 252 ++++++++++++++++++++++++++++++++++++ src/fn_miscs.hpp | 40 ++++++ src/fn_utils.cpp | 6 + src/fn_utils.hpp | 13 -- src/functions.cpp | 245 +---------------------------------- src/functions.hpp | 36 +----- src/sass.cpp | 1 + win/libsass.targets | 2 + win/libsass.vcxproj.filters | 6 + 13 files changed, 313 insertions(+), 292 deletions(-) create mode 100644 src/fn_miscs.cpp create mode 100644 src/fn_miscs.hpp diff --git a/Makefile.conf b/Makefile.conf index fa74da819..6e42a8677 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -11,6 +11,7 @@ SOURCES = \ context.cpp \ constants.cpp \ fn_utils.cpp \ + fn_miscs.cpp \ fn_maps.cpp \ fn_lists.cpp \ fn_colors.cpp \ diff --git a/src/context.cpp b/src/context.cpp index 368863270..e2cffd1db 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -30,6 +30,7 @@ #include "prelexer.hpp" #include "emitter.hpp" #include "fn_utils.hpp" +#include "fn_miscs.hpp" #include "fn_maps.hpp" #include "fn_lists.hpp" #include "fn_colors.hpp" diff --git a/src/error_handling.hpp b/src/error_handling.hpp index f863792ea..099f26dcc 100644 --- a/src/error_handling.hpp +++ b/src/error_handling.hpp @@ -4,6 +4,7 @@ #include #include #include +#include "units.hpp" #include "position.hpp" #include "backtrace.hpp" #include "ast_fwd_decl.hpp" diff --git a/src/file.cpp b/src/file.cpp index 32d4a7c63..44c2e3221 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -21,6 +21,7 @@ #include "prelexer.hpp" #include "utf8_string.hpp" #include "sass_functions.hpp" +#include "error_handling.hpp" #include "sass2scss.h" #ifdef _WIN32 diff --git a/src/fn_miscs.cpp b/src/fn_miscs.cpp new file mode 100644 index 000000000..70bbd403d --- /dev/null +++ b/src/fn_miscs.cpp @@ -0,0 +1,252 @@ +#include "ast.hpp" +#include "expand.hpp" +#include "fn_utils.hpp" +#include "fn_miscs.hpp" +#include "debugger.hpp" + +namespace Sass { + + namespace Functions { + + // features + static std::set features { + "global-variable-shadowing", + "extend-selector-pseudoclass", + "at-error", + "units-level-3", + "custom-property" + }; + + ////////////////////////// + // INTROSPECTION FUNCTIONS + ////////////////////////// + + Signature type_of_sig = "type-of($value)"; + BUILT_IN(type_of) + { + Expression_Ptr v = ARG("$value", Expression); + return SASS_MEMORY_NEW(String_Quoted, pstate, v->type()); + } + + Signature variable_exists_sig = "variable-exists($name)"; + BUILT_IN(variable_exists) + { + std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); + + if(d_env.has("$"+s)) { + return SASS_MEMORY_NEW(Boolean, pstate, true); + } + else { + return SASS_MEMORY_NEW(Boolean, pstate, false); + } + } + + Signature global_variable_exists_sig = "global-variable-exists($name)"; + BUILT_IN(global_variable_exists) + { + std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); + + if(d_env.has_global("$"+s)) { + return SASS_MEMORY_NEW(Boolean, pstate, true); + } + else { + return SASS_MEMORY_NEW(Boolean, pstate, false); + } + } + + Signature function_exists_sig = "function-exists($name)"; + BUILT_IN(function_exists) + { + String_Constant_Ptr ss = Cast(env["$name"]); + if (!ss) { + error("$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces); + } + + std::string name = Util::normalize_underscores(unquote(ss->value())); + + if(d_env.has_global(name+"[f]")) { + return SASS_MEMORY_NEW(Boolean, pstate, true); + } + else { + return SASS_MEMORY_NEW(Boolean, pstate, false); + } + } + + Signature mixin_exists_sig = "mixin-exists($name)"; + BUILT_IN(mixin_exists) + { + std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); + + if(d_env.has_global(s+"[m]")) { + return SASS_MEMORY_NEW(Boolean, pstate, true); + } + else { + return SASS_MEMORY_NEW(Boolean, pstate, false); + } + } + + Signature feature_exists_sig = "feature-exists($name)"; + BUILT_IN(feature_exists) + { + std::string s = unquote(ARG("$name", String_Constant)->value()); + + if(features.find(s) == features.end()) { + return SASS_MEMORY_NEW(Boolean, pstate, false); + } + else { + return SASS_MEMORY_NEW(Boolean, pstate, true); + } + } + + Signature call_sig = "call($name, $args...)"; + BUILT_IN(call) + { + std::string name; + Function_Ptr ff = Cast(env["$name"]); + String_Constant_Ptr ss = Cast(env["$name"]); + + if (ss) { + name = Util::normalize_underscores(unquote(ss->value())); + std::cerr << "DEPRECATION WARNING: "; + std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl; + std::cerr << "in Sass 4.0. Use call(get-function(" + quote(name) + ")) instead." << std::endl; + std::cerr << std::endl; + } else if (ff) { + name = ff->name(); + } + + List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); + + Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate); + // std::string full_name(name + "[f]"); + // Definition_Ptr def = d_env.has(full_name) ? Cast((d_env)[full_name]) : 0; + // Parameters_Ptr params = def ? def->parameters() : 0; + // size_t param_size = params ? params->length() : 0; + for (size_t i = 0, L = arglist->length(); i < L; ++i) { + Expression_Obj expr = arglist->value_at_index(i); + // if (params && params->has_rest_parameter()) { + // Parameter_Obj p = param_size > i ? (*params)[i] : 0; + // List_Ptr list = Cast(expr); + // if (list && p && !p->is_rest_parameter()) expr = (*list)[0]; + // } + if (arglist->is_arglist()) { + Expression_Obj obj = arglist->at(i); + Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX + args->append(SASS_MEMORY_NEW(Argument, + pstate, + expr, + arg ? arg->name() : "", + arg ? arg->is_rest_argument() : false, + arg ? arg->is_keyword_argument() : false)); + } else { + args->append(SASS_MEMORY_NEW(Argument, pstate, expr)); + } + } + Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, args); + Expand expand(ctx, &d_env, &selector_stack); + func->via_call(true); // calc invoke is allowed + if (ff) func->func(ff); + return func->perform(&expand.eval); + } + + //////////////////// + // BOOLEAN FUNCTIONS + //////////////////// + + Signature not_sig = "not($value)"; + BUILT_IN(sass_not) + { + return SASS_MEMORY_NEW(Boolean, pstate, ARG("$value", Expression)->is_false()); + } + + Signature if_sig = "if($condition, $if-true, $if-false)"; + // BUILT_IN(sass_if) + // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); } + BUILT_IN(sass_if) + { + Expand expand(ctx, &d_env, &selector_stack); + Expression_Obj cond = ARG("$condition", Expression)->perform(&expand.eval); + bool is_true = !cond->is_false(); + Expression_Obj res = ARG(is_true ? "$if-true" : "$if-false", Expression); + Value_Obj qwe = Cast(res->perform(&expand.eval)); + // if (qwe == 0) debug_ast(res); + // res = res->perform(&expand.eval.val_eval); + qwe->set_delayed(false); // clone? + return qwe.detach(); + } + + ////////////////////////// + // MISCELLANEOUS FUNCTIONS + ////////////////////////// + + // value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String) + // unquoted_string(value.to_sass) + + Signature inspect_sig = "inspect($value)"; + BUILT_IN(inspect) + { + Expression_Ptr v = ARG("$value", Expression); + if (v->concrete_type() == Expression::NULL_VAL) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "null"); + } else if (v->concrete_type() == Expression::BOOLEAN && v->is_false()) { + return SASS_MEMORY_NEW(String_Quoted, pstate, "false"); + } else if (v->concrete_type() == Expression::STRING) { + return Cast(v); + } else { + // ToDo: fix to_sass for nested parentheses + Sass_Output_Style old_style; + old_style = ctx.c_options.output_style; + ctx.c_options.output_style = TO_SASS; + Emitter emitter(ctx.c_options); + Inspect i(emitter); + i.in_declaration = false; + v->perform(&i); + ctx.c_options.output_style = old_style; + return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer()); + } + // return v; + } + + Signature content_exists_sig = "content-exists()"; + BUILT_IN(content_exists) + { + if (!d_env.has_global("is_in_mixin")) { + error("Cannot call content-exists() except within a mixin.", pstate, traces); + } + return SASS_MEMORY_NEW(Boolean, pstate, d_env.has_lexical("@content[m]")); + } + + Signature get_function_sig = "get-function($name, $css: false)"; + BUILT_IN(get_function) + { + String_Constant_Ptr ss = Cast(env["$name"]); + if (!ss) { + error("$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces); + } + + std::string name = Util::normalize_underscores(unquote(ss->value())); + std::string full_name = name + "[f]"; + + Boolean_Obj css = ARG("$css", Boolean); + if (!css->is_false()) { + Definition_Ptr def = SASS_MEMORY_NEW(Definition, + pstate, + name, + SASS_MEMORY_NEW(Parameters, pstate), + SASS_MEMORY_NEW(Block, pstate, 0, false), + Definition::FUNCTION); + return SASS_MEMORY_NEW(Function, pstate, def, true); + } + + + if (!d_env.has_global(full_name)) { + error("Function not found: " + name, pstate, traces); + } + + Definition_Ptr def = Cast(d_env[full_name]); + return SASS_MEMORY_NEW(Function, pstate, def, false); + } + + } + +} \ No newline at end of file diff --git a/src/fn_miscs.hpp b/src/fn_miscs.hpp new file mode 100644 index 000000000..aec693e92 --- /dev/null +++ b/src/fn_miscs.hpp @@ -0,0 +1,40 @@ +#ifndef SASS_FN_MISCS_H +#define SASS_FN_MISCS_H + +#include "fn_utils.hpp" + +namespace Sass { + + namespace Functions { + + extern Signature type_of_sig; + extern Signature variable_exists_sig; + extern Signature global_variable_exists_sig; + extern Signature function_exists_sig; + extern Signature mixin_exists_sig; + extern Signature feature_exists_sig; + extern Signature call_sig; + extern Signature not_sig; + extern Signature if_sig; + extern Signature set_nth_sig; + extern Signature content_exists_sig; + extern Signature get_function_sig; + + BUILT_IN(type_of); + BUILT_IN(variable_exists); + BUILT_IN(global_variable_exists); + BUILT_IN(function_exists); + BUILT_IN(mixin_exists); + BUILT_IN(feature_exists); + BUILT_IN(call); + BUILT_IN(sass_not); + BUILT_IN(sass_if); + BUILT_IN(set_nth); + BUILT_IN(content_exists); + BUILT_IN(get_function); + + } + +} + +#endif diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp index 3127968ca..b4986037e 100644 --- a/src/fn_utils.cpp +++ b/src/fn_utils.cpp @@ -45,6 +45,12 @@ namespace Sass { namespace Functions { + std::string function_name(Signature sig) + { + std::string str(sig); + return str.substr(0, str.find('(')); + } + Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) { // Minimal error handling -- the expectation is that built-ins will be written correctly! diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index 6b743ab16..b6ce97d17 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -12,23 +12,10 @@ namespace Sass { name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, std::vector selector_stack) #define ARG(argname, argtype) get_arg(argname, env, sig, pstate, traces) - #define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces) // special function for weird hsla percent (10px == 10% == 10 != 0.1) #define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double - // macros for common ranges (u mean unsigned or upper, r for full range) - #define DARG_U_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 1.0) // double - #define DARG_R_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 1.0, 1.0) // double - #define DARG_U_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 255.0) // double - #define DARG_R_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 255.0, 255.0) // double - #define DARG_U_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 100.0) // double - #define DARG_R_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 100.0, 100.0) // double - - // macros for color related inputs (rbg and alpha/opacity values) - #define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double - #define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double - typedef const char* Signature; typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); diff --git a/src/functions.cpp b/src/functions.cpp index d8ecdc826..15ca7632e 100644 --- a/src/functions.cpp +++ b/src/functions.cpp @@ -26,6 +26,7 @@ #include #include "fn_utils.hpp" +#include "fn_miscs.hpp" #include "fn_maps.hpp" #include "fn_lists.hpp" #include "fn_colors.hpp" @@ -34,252 +35,8 @@ #include "fn_selectors.hpp" namespace Sass { - using std::stringstream; - using std::endl; - - std::string function_name(Signature sig) - { - std::string str(sig); - return str.substr(0, str.find('(')); - } namespace Functions { - // features - static std::set features { - "global-variable-shadowing", - "extend-selector-pseudoclass", - "at-error", - "units-level-3", - "custom-property" - }; - - ////////////////////////// - // INTROSPECTION FUNCTIONS - ////////////////////////// - - Signature type_of_sig = "type-of($value)"; - BUILT_IN(type_of) - { - Expression_Ptr v = ARG("$value", Expression); - return SASS_MEMORY_NEW(String_Quoted, pstate, v->type()); - } - - Signature variable_exists_sig = "variable-exists($name)"; - BUILT_IN(variable_exists) - { - std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); - - if(d_env.has("$"+s)) { - return SASS_MEMORY_NEW(Boolean, pstate, true); - } - else { - return SASS_MEMORY_NEW(Boolean, pstate, false); - } - } - - Signature global_variable_exists_sig = "global-variable-exists($name)"; - BUILT_IN(global_variable_exists) - { - std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); - - if(d_env.has_global("$"+s)) { - return SASS_MEMORY_NEW(Boolean, pstate, true); - } - else { - return SASS_MEMORY_NEW(Boolean, pstate, false); - } - } - - Signature function_exists_sig = "function-exists($name)"; - BUILT_IN(function_exists) - { - String_Constant_Ptr ss = Cast(env["$name"]); - if (!ss) { - error("$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces); - } - - std::string name = Util::normalize_underscores(unquote(ss->value())); - - if(d_env.has_global(name+"[f]")) { - return SASS_MEMORY_NEW(Boolean, pstate, true); - } - else { - return SASS_MEMORY_NEW(Boolean, pstate, false); - } - } - - Signature mixin_exists_sig = "mixin-exists($name)"; - BUILT_IN(mixin_exists) - { - std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); - - if(d_env.has_global(s+"[m]")) { - return SASS_MEMORY_NEW(Boolean, pstate, true); - } - else { - return SASS_MEMORY_NEW(Boolean, pstate, false); - } - } - - Signature feature_exists_sig = "feature-exists($name)"; - BUILT_IN(feature_exists) - { - std::string s = unquote(ARG("$name", String_Constant)->value()); - - if(features.find(s) == features.end()) { - return SASS_MEMORY_NEW(Boolean, pstate, false); - } - else { - return SASS_MEMORY_NEW(Boolean, pstate, true); - } - } - - Signature call_sig = "call($name, $args...)"; - BUILT_IN(call) - { - std::string name; - Function_Ptr ff = Cast(env["$name"]); - String_Constant_Ptr ss = Cast(env["$name"]); - - if (ss) { - name = Util::normalize_underscores(unquote(ss->value())); - std::cerr << "DEPRECATION WARNING: "; - std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl; - std::cerr << "in Sass 4.0. Use call(get-function(" + quote(name) + ")) instead." << std::endl; - std::cerr << std::endl; - } else if (ff) { - name = ff->name(); - } - - List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); - - Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate); - // std::string full_name(name + "[f]"); - // Definition_Ptr def = d_env.has(full_name) ? Cast((d_env)[full_name]) : 0; - // Parameters_Ptr params = def ? def->parameters() : 0; - // size_t param_size = params ? params->length() : 0; - for (size_t i = 0, L = arglist->length(); i < L; ++i) { - Expression_Obj expr = arglist->value_at_index(i); - // if (params && params->has_rest_parameter()) { - // Parameter_Obj p = param_size > i ? (*params)[i] : 0; - // List_Ptr list = Cast(expr); - // if (list && p && !p->is_rest_parameter()) expr = (*list)[0]; - // } - if (arglist->is_arglist()) { - Expression_Obj obj = arglist->at(i); - Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX - args->append(SASS_MEMORY_NEW(Argument, - pstate, - expr, - arg ? arg->name() : "", - arg ? arg->is_rest_argument() : false, - arg ? arg->is_keyword_argument() : false)); - } else { - args->append(SASS_MEMORY_NEW(Argument, pstate, expr)); - } - } - Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, args); - Expand expand(ctx, &d_env, &selector_stack); - func->via_call(true); // calc invoke is allowed - if (ff) func->func(ff); - return func->perform(&expand.eval); - } - - //////////////////// - // BOOLEAN FUNCTIONS - //////////////////// - - Signature not_sig = "not($value)"; - BUILT_IN(sass_not) - { - return SASS_MEMORY_NEW(Boolean, pstate, ARG("$value", Expression)->is_false()); - } - - Signature if_sig = "if($condition, $if-true, $if-false)"; - // BUILT_IN(sass_if) - // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); } - BUILT_IN(sass_if) - { - Expand expand(ctx, &d_env, &selector_stack); - Expression_Obj cond = ARG("$condition", Expression)->perform(&expand.eval); - bool is_true = !cond->is_false(); - Expression_Obj res = ARG(is_true ? "$if-true" : "$if-false", Expression); - res = res->perform(&expand.eval); - res->set_delayed(false); // clone? - return res.detach(); - } - - ////////////////////////// - // MISCELLANEOUS FUNCTIONS - ////////////////////////// - - // value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String) - // unquoted_string(value.to_sass) - - Signature inspect_sig = "inspect($value)"; - BUILT_IN(inspect) - { - Expression_Ptr v = ARG("$value", Expression); - if (v->concrete_type() == Expression::NULL_VAL) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "null"); - } else if (v->concrete_type() == Expression::BOOLEAN && v->is_false()) { - return SASS_MEMORY_NEW(String_Quoted, pstate, "false"); - } else if (v->concrete_type() == Expression::STRING) { - return v; - } else { - // ToDo: fix to_sass for nested parentheses - Sass_Output_Style old_style; - old_style = ctx.c_options.output_style; - ctx.c_options.output_style = TO_SASS; - Emitter emitter(ctx.c_options); - Inspect i(emitter); - i.in_declaration = false; - v->perform(&i); - ctx.c_options.output_style = old_style; - return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer()); - } - // return v; - } - - Signature content_exists_sig = "content-exists()"; - BUILT_IN(content_exists) - { - if (!d_env.has_global("is_in_mixin")) { - error("Cannot call content-exists() except within a mixin.", pstate, traces); - } - return SASS_MEMORY_NEW(Boolean, pstate, d_env.has_lexical("@content[m]")); - } - - Signature get_function_sig = "get-function($name, $css: false)"; - BUILT_IN(get_function) - { - String_Constant_Ptr ss = Cast(env["$name"]); - if (!ss) { - error("$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces); - } - - std::string name = Util::normalize_underscores(unquote(ss->value())); - std::string full_name = name + "[f]"; - - Boolean_Obj css = ARG("$css", Boolean); - if (!css->is_false()) { - Definition_Ptr def = SASS_MEMORY_NEW(Definition, - pstate, - name, - SASS_MEMORY_NEW(Parameters, pstate), - SASS_MEMORY_NEW(Block, pstate, 0, false), - Definition::FUNCTION); - return SASS_MEMORY_NEW(Function, pstate, def, true); - } - - - if (!d_env.has_global(full_name)) { - error("Function not found: " + name, pstate, traces); - } - - Definition_Ptr def = Cast(d_env[full_name]); - return SASS_MEMORY_NEW(Function, pstate, def, false); - } } } diff --git a/src/functions.hpp b/src/functions.hpp index da683abf9..c91000f66 100644 --- a/src/functions.hpp +++ b/src/functions.hpp @@ -1,46 +1,12 @@ #ifndef SASS_FUNCTIONS_H #define SASS_FUNCTIONS_H -#include "listize.hpp" -#include "position.hpp" -#include "environment.hpp" -#include "ast_fwd_decl.hpp" -#include "sass/functions.h" -#include "fn_utils.hpp" - namespace Sass { - struct Backtrace; - typedef const char* Signature; - typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, std::vector); - - std::string function_name(Signature); namespace Functions { - extern Signature type_of_sig; - extern Signature variable_exists_sig; - extern Signature global_variable_exists_sig; - extern Signature function_exists_sig; - extern Signature mixin_exists_sig; - extern Signature feature_exists_sig; - extern Signature call_sig; - extern Signature not_sig; - extern Signature if_sig; - extern Signature content_exists_sig; - extern Signature get_function_sig; - - BUILT_IN(type_of); - BUILT_IN(variable_exists); - BUILT_IN(global_variable_exists); - BUILT_IN(function_exists); - BUILT_IN(mixin_exists); - BUILT_IN(feature_exists); - BUILT_IN(call); - BUILT_IN(sass_not); - BUILT_IN(sass_if); - BUILT_IN(content_exists); - BUILT_IN(get_function); } + } #endif diff --git a/src/sass.cpp b/src/sass.cpp index 98e349f48..06468f92d 100644 --- a/src/sass.cpp +++ b/src/sass.cpp @@ -7,6 +7,7 @@ #include "sass.h" #include "file.hpp" #include "util.hpp" +#include "context.hpp" #include "sass_context.hpp" #include "sass_functions.hpp" diff --git a/win/libsass.targets b/win/libsass.targets index c26d7f858..eb0aca770 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -34,6 +34,7 @@ + @@ -94,6 +95,7 @@ + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 9c0e3b562..836b4c298 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -114,6 +114,9 @@ Headers + + Headers + Headers @@ -293,6 +296,9 @@ Sources + + Sources + Sources From 7cb696a768e2e05669342e4a4924519b55a4e5d5 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 02:52:31 +0100 Subject: [PATCH 11/30] Rename stacks to use shorter typedefs --- src/ast.cpp | 4 ++-- src/ast.hpp | 6 +++--- src/ast_fwd_decl.hpp | 2 +- src/context.hpp | 4 ++-- src/cssize.cpp | 2 +- src/cssize.hpp | 2 +- src/eval.cpp | 2 +- src/expand.cpp | 10 +++++----- src/expand.hpp | 10 +++++----- src/fn_utils.hpp | 2 +- 10 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index c3b38efb9..341cbc3fb 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -1259,7 +1259,7 @@ namespace Sass { return list; } - Selector_List_Ptr Selector_List::resolve_parent_refs(std::vector& pstack, Backtraces& traces, bool implicit_parent) + Selector_List_Ptr Selector_List::resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent) { if (!this->has_parent_ref()) return this; Selector_List_Ptr ss = SASS_MEMORY_NEW(Selector_List, pstate()); @@ -1273,7 +1273,7 @@ namespace Sass { return ss; } - Selector_List_Ptr Complex_Selector::resolve_parent_refs(std::vector& pstack, Backtraces& traces, bool implicit_parent) + Selector_List_Ptr Complex_Selector::resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent) { Complex_Selector_Obj tail = this->tail(); Compound_Selector_Obj head = this->head(); diff --git a/src/ast.hpp b/src/ast.hpp index 07728103e..e5b0f06d9 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -944,7 +944,7 @@ namespace Sass { // by a type tag. ///////////////////////////////////////////////////////////////////////////// struct Backtrace; - typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, std::vector); + typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); class Definition : public Has_Block { public: enum Type { MIXIN, FUNCTION }; @@ -2860,7 +2860,7 @@ namespace Sass { Complex_Selector_Obj innermost() { return last(); }; size_t length() const; - Selector_List_Ptr resolve_parent_refs(std::vector& pstack, Backtraces& traces, bool implicit_parent = true); + Selector_List_Ptr resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent = true); virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = ""); virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapping = ""); virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = ""); @@ -2982,7 +2982,7 @@ namespace Sass { virtual bool has_parent_ref() const; virtual bool has_real_parent_ref() const; void remove_parent_selectors(); - Selector_List_Ptr resolve_parent_refs(std::vector& pstack, Backtraces& traces, bool implicit_parent = true); + Selector_List_Ptr resolve_parent_refs(SelectorStack& pstack, Backtraces& traces, bool implicit_parent = true); virtual bool is_superselector_of(Compound_Selector_Obj sub, std::string wrapping = ""); virtual bool is_superselector_of(Complex_Selector_Obj sub, std::string wrapping = ""); virtual bool is_superselector_of(Selector_List_Obj sub, std::string wrapping = ""); diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index 4a3ff69b1..90c362310 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -423,7 +423,7 @@ namespace Sass { typedef std::vector CallStack; typedef std::vector MediaStack; typedef std::vector SelectorStack; - typedef std::vector* ImporterStack; + typedef std::vector ImporterStack; typedef const char* Signature; diff --git a/src/context.hpp b/src/context.hpp index d3caba13e..027ffca22 100644 --- a/src/context.hpp +++ b/src/context.hpp @@ -46,14 +46,14 @@ namespace Sass { // generic ast node garbage container // used to avoid possible circular refs - std::vector ast_gc; + CallStack ast_gc; // resources add under our control // these are guaranteed to be freed std::vector strings; std::vector resources; std::map sheets; Subset_Map subset_map; - std::vector import_stack; + ImporterStack import_stack; std::vector callee_stack; std::vector traces; diff --git a/src/cssize.cpp b/src/cssize.cpp index 4c062a628..d5780dd70 100644 --- a/src/cssize.cpp +++ b/src/cssize.cpp @@ -11,7 +11,7 @@ namespace Sass { Cssize::Cssize(Context& ctx) : ctx(ctx), traces(ctx.traces), - block_stack(std::vector()), + block_stack(BlockStack()), p_stack(std::vector()) { } diff --git a/src/cssize.hpp b/src/cssize.hpp index 5a6c704b0..4dad47579 100644 --- a/src/cssize.hpp +++ b/src/cssize.hpp @@ -14,7 +14,7 @@ namespace Sass { Context& ctx; Backtraces& traces; - std::vector block_stack; + BlockStack block_stack; std::vector p_stack; Statement_Ptr fallback_impl(AST_Node_Ptr n); diff --git a/src/eval.cpp b/src/eval.cpp index 2ddfa93ea..010cb9bb9 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1529,7 +1529,7 @@ namespace Sass { Selector_List_Ptr Eval::operator()(Selector_List_Ptr s) { - std::vector rv; + SelectorStack rv; Selector_List_Obj sl = SASS_MEMORY_NEW(Selector_List, s->pstate()); sl->is_optional(s->is_optional()); sl->media_block(s->media_block()); diff --git a/src/expand.cpp b/src/expand.cpp index ccd2822df..0bf0b78eb 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -16,7 +16,7 @@ namespace Sass { // simple endless recursion protection const size_t maxRecursion = 500; - Expand::Expand(Context& ctx, Env* env, std::vector* stack) + Expand::Expand(Context& ctx, Env* env, SelectorStack* stack) : ctx(ctx), traces(ctx.traces), eval(Eval(*this)), @@ -25,10 +25,10 @@ namespace Sass { at_root_without_rule(false), old_at_root_without_rule(false), env_stack(std::vector()), - block_stack(std::vector()), - call_stack(std::vector()), - selector_stack(std::vector()), - media_block_stack(std::vector()) + block_stack(BlockStack()), + call_stack(CallStack()), + selector_stack(SelectorStack()), + media_block_stack(MediaStack()) { env_stack.push_back(0); env_stack.push_back(env); diff --git a/src/expand.hpp b/src/expand.hpp index 3464c98f6..3d6d1eb6b 100644 --- a/src/expand.hpp +++ b/src/expand.hpp @@ -31,10 +31,10 @@ namespace Sass { // it's easier to work with vectors std::vector env_stack; - std::vector block_stack; - std::vector call_stack; - std::vector selector_stack; - std::vector media_block_stack; + BlockStack block_stack; + CallStack call_stack; + SelectorStack selector_stack; + MediaStack media_block_stack; Boolean_Obj bool_true; @@ -44,7 +44,7 @@ namespace Sass { void expand_selector_list(Selector_Obj, Selector_List_Obj extender); public: - Expand(Context&, Env*, std::vector* stack = NULL); + Expand(Context&, Env*, SelectorStack* stack = NULL); ~Expand() { } Block_Ptr operator()(Block_Ptr); diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index b6ce97d17..ab03bbf4f 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -9,7 +9,7 @@ namespace Sass { #define BUILT_IN(name) Expression_Ptr \ - name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, std::vector selector_stack) + name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, SelectorStack selector_stack) #define ARG(argname, argtype) get_arg(argname, env, sig, pstate, traces) From aa7386f2fc5f9c3681fbe861220c40b5a7a910b5 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 03:12:15 +0100 Subject: [PATCH 12/30] Cleanup CRTP implementation --- src/ast.hpp | 140 ++++++++++++++++++------------------ src/ast_def_macros.hpp | 10 --- src/check_nesting.cpp | 7 -- src/check_nesting.hpp | 11 +-- src/cssize.cpp | 5 -- src/cssize.hpp | 6 +- src/eval.cpp | 5 -- src/eval.hpp | 20 +++--- src/expand.cpp | 9 --- src/expand.hpp | 6 +- src/extend.hpp | 6 +- src/inspect.cpp | 4 -- src/inspect.hpp | 4 -- src/listize.cpp | 5 -- src/listize.hpp | 6 +- src/operation.hpp | 44 +++++++++--- src/remove_placeholders.hpp | 5 +- src/to_value.cpp | 7 -- src/to_value.hpp | 5 -- 19 files changed, 133 insertions(+), 172 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index e5b0f06d9..3a62cbcef 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -135,7 +135,7 @@ namespace Sass { public: Offset off() { return pstate(); } Position pos() { return pstate(); } - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; inline AST_Node::~AST_Node() { } @@ -504,7 +504,7 @@ namespace Sass { return Statement::has_content(); } ATTACH_AST_OPERATIONS(Block) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////// @@ -545,7 +545,7 @@ namespace Sass { { statement_type(RULESET); } bool is_invisible() const; ATTACH_AST_OPERATIONS(Ruleset) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////// @@ -565,7 +565,7 @@ namespace Sass { { } bool bubbles() { return true; } ATTACH_AST_OPERATIONS(Bubble) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////// @@ -584,7 +584,7 @@ namespace Sass { name_(ptr->name_) { } ATTACH_AST_OPERATIONS(Trace) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////// @@ -602,7 +602,7 @@ namespace Sass { bool bubbles() { return true; } bool is_invisible() const; ATTACH_AST_OPERATIONS(Media_Block) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////////////////////////////// @@ -637,7 +637,7 @@ namespace Sass { keyword_.compare("@keyframes") == 0; } ATTACH_AST_OPERATIONS(Directive) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////////////////////////////// @@ -655,7 +655,7 @@ namespace Sass { : Has_Block(ptr), name_(ptr->name_) { statement_type(KEYFRAMERULE); } ATTACH_AST_OPERATIONS(Keyframe_Rule) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////// @@ -682,7 +682,7 @@ namespace Sass { { statement_type(DECLARATION); } virtual bool is_invisible() const; ATTACH_AST_OPERATIONS(Declaration) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////// @@ -708,7 +708,7 @@ namespace Sass { is_global_(ptr->is_global_) { statement_type(ASSIGNMENT); } ATTACH_AST_OPERATIONS(Assignment) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////////// @@ -735,7 +735,7 @@ namespace Sass { std::vector& urls() { return urls_; } std::vector& incs() { return incs_; } ATTACH_AST_OPERATIONS(Import) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; // not yet resolved single import @@ -754,7 +754,7 @@ namespace Sass { : Statement(ptr), resource_(ptr->resource_) { statement_type(IMPORT_STUB); } ATTACH_AST_OPERATIONS(Import_Stub) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////// @@ -770,7 +770,7 @@ namespace Sass { : Statement(ptr), message_(ptr->message_) { statement_type(WARNING); } ATTACH_AST_OPERATIONS(Warning) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////// @@ -786,7 +786,7 @@ namespace Sass { : Statement(ptr), message_(ptr->message_) { statement_type(ERROR); } ATTACH_AST_OPERATIONS(Error) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////// @@ -802,7 +802,7 @@ namespace Sass { : Statement(ptr), value_(ptr->value_) { statement_type(DEBUGSTMT); } ATTACH_AST_OPERATIONS(Debug) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////// @@ -823,7 +823,7 @@ namespace Sass { virtual bool is_invisible() const { return /* is_important() == */ false; } ATTACH_AST_OPERATIONS(Comment) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////// @@ -846,7 +846,7 @@ namespace Sass { return Has_Block::has_content() || (alternative_ && alternative_->has_content()); } ATTACH_AST_OPERATIONS(If) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////// @@ -871,7 +871,7 @@ namespace Sass { is_inclusive_(ptr->is_inclusive_) { statement_type(FOR); } ATTACH_AST_OPERATIONS(For) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////////////// @@ -888,7 +888,7 @@ namespace Sass { : Has_Block(ptr), variables_(ptr->variables_), list_(ptr->list_) { statement_type(EACH); } ATTACH_AST_OPERATIONS(Each) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////// @@ -904,7 +904,7 @@ namespace Sass { : Has_Block(ptr), predicate_(ptr->predicate_) { statement_type(WHILE); } ATTACH_AST_OPERATIONS(While) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////////////// @@ -920,7 +920,7 @@ namespace Sass { : Statement(ptr), value_(ptr->value_) { statement_type(RETURN); } ATTACH_AST_OPERATIONS(Return) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////// @@ -936,7 +936,7 @@ namespace Sass { : Statement(ptr), selector_(ptr->selector_) { statement_type(EXTEND); } ATTACH_AST_OPERATIONS(Extension) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////////////////////////////// @@ -1023,7 +1023,7 @@ namespace Sass { signature_(sig) { } ATTACH_AST_OPERATIONS(Definition) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////////////// @@ -1042,7 +1042,7 @@ namespace Sass { arguments_(ptr->arguments_) { } ATTACH_AST_OPERATIONS(Mixin_Call) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////////// @@ -1060,7 +1060,7 @@ namespace Sass { media_block_(ptr->media_block_) { statement_type(CONTENT); } ATTACH_AST_OPERATIONS(Content) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////////////////////////////// @@ -1123,7 +1123,7 @@ namespace Sass { virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(List) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////////////////////////////// @@ -1161,7 +1161,7 @@ namespace Sass { virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Map) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; inline static const std::string sass_op_to_name(enum Sass_OP op) { @@ -1275,7 +1275,7 @@ namespace Sass { } enum Sass_OP optype() const { return op_.operand; } ATTACH_AST_OPERATIONS(Binary_Expression) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////////// @@ -1331,7 +1331,7 @@ namespace Sass { return hash_; } ATTACH_AST_OPERATIONS(Unary_Expression) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////// @@ -1390,7 +1390,7 @@ namespace Sass { } ATTACH_AST_OPERATIONS(Argument) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////// @@ -1426,7 +1426,7 @@ namespace Sass { Argument_Obj get_keyword_argument(); ATTACH_AST_OPERATIONS(Arguments) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////// @@ -1458,7 +1458,7 @@ namespace Sass { virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Function) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////// @@ -1524,7 +1524,7 @@ namespace Sass { return hash_; } ATTACH_AST_OPERATIONS(Function_Call) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////// @@ -1543,7 +1543,7 @@ namespace Sass { arguments_(ptr->arguments_) { concrete_type(STRING); } ATTACH_AST_OPERATIONS(Function_Call_Schema) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////// @@ -1579,7 +1579,7 @@ namespace Sass { } ATTACH_AST_OPERATIONS(Variable) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////// @@ -1622,7 +1622,7 @@ namespace Sass { virtual bool operator== (const Number& rhs) const; virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Number) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////// @@ -1666,7 +1666,7 @@ namespace Sass { virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Color) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////// @@ -1683,7 +1683,7 @@ namespace Sass { { concrete_type(C_ERROR); } virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Custom_Error) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////// @@ -1700,7 +1700,7 @@ namespace Sass { { concrete_type(C_WARNING); } virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Custom_Warning) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////// @@ -1735,7 +1735,7 @@ namespace Sass { virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Boolean) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////// @@ -1758,7 +1758,7 @@ namespace Sass { return this->to_string() < rhs.to_string(); }; ATTACH_VIRTUAL_AST_OPERATIONS(String); - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; inline String::~String() { }; @@ -1809,7 +1809,7 @@ namespace Sass { virtual bool operator==(const Expression& rhs) const; ATTACH_AST_OPERATIONS(String_Schema) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////// @@ -1862,7 +1862,7 @@ namespace Sass { static char single_quote() { return '\''; } ATTACH_AST_OPERATIONS(String_Constant) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////// @@ -1886,7 +1886,7 @@ namespace Sass { virtual bool operator==(const Expression& rhs) const; virtual std::string inspect() const; // quotes are forced on inspection ATTACH_AST_OPERATIONS(String_Quoted) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////// @@ -1911,7 +1911,7 @@ namespace Sass { is_restricted_(ptr->is_restricted_) { } ATTACH_AST_OPERATIONS(Media_Query) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////// @@ -1933,7 +1933,7 @@ namespace Sass { is_interpolated_(ptr->is_interpolated_) { } ATTACH_AST_OPERATIONS(Media_Query_Expression) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////// @@ -1950,7 +1950,7 @@ namespace Sass { { statement_type(SUPPORTS); } bool bubbles() { return true; } ATTACH_AST_OPERATIONS(Supports_Block) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////////////////////////////// @@ -1966,7 +1966,7 @@ namespace Sass { { } virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; } ATTACH_AST_OPERATIONS(Supports_Condition) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////// @@ -1991,7 +1991,7 @@ namespace Sass { { } virtual bool needs_parens(Supports_Condition_Obj cond) const; ATTACH_AST_OPERATIONS(Supports_Operator) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////////////////// @@ -2009,7 +2009,7 @@ namespace Sass { { } virtual bool needs_parens(Supports_Condition_Obj cond) const; ATTACH_AST_OPERATIONS(Supports_Negation) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////// @@ -2030,7 +2030,7 @@ namespace Sass { { } virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; } ATTACH_AST_OPERATIONS(Supports_Declaration) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////// @@ -2049,7 +2049,7 @@ namespace Sass { { } virtual bool needs_parens(Supports_Condition_Obj cond) const { return false; } ATTACH_AST_OPERATIONS(Supports_Interpolation) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////// @@ -2070,7 +2070,7 @@ namespace Sass { { } bool exclude(std::string str); ATTACH_AST_OPERATIONS(At_Root_Query) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////// @@ -2120,7 +2120,7 @@ namespace Sass { return false; } ATTACH_AST_OPERATIONS(At_Root_Block) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////// @@ -2144,7 +2144,7 @@ namespace Sass { virtual bool operator== (const Expression& rhs) const; ATTACH_AST_OPERATIONS(Null) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////// @@ -2190,7 +2190,7 @@ namespace Sass { // } } ATTACH_AST_OPERATIONS(Parameter) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////////////////////////// @@ -2239,7 +2239,7 @@ namespace Sass { has_rest_parameter_(ptr->has_rest_parameter_) { } ATTACH_AST_OPERATIONS(Parameters) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////// @@ -2338,7 +2338,7 @@ namespace Sass { return hash_; } ATTACH_AST_OPERATIONS(Selector_Schema) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////// @@ -2433,7 +2433,7 @@ namespace Sass { bool operator<(const Simple_Selector& rhs) const; // default implementation should work for most of the simple selectors (otherwise overload) ATTACH_VIRTUAL_AST_OPERATIONS(Simple_Selector); - ATTACH_OPERATIONS(); + ATTACH_CRTP_PERFORM_METHODS(); }; inline Simple_Selector::~Simple_Selector() { } @@ -2463,7 +2463,7 @@ namespace Sass { std::string type() const { return "selector"; } static std::string type_name() { return "selector"; } ATTACH_AST_OPERATIONS(Parent_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////////////////////////// @@ -2486,7 +2486,7 @@ namespace Sass { } virtual ~Placeholder_Selector() {}; ATTACH_AST_OPERATIONS(Placeholder_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////////////////////////// @@ -2512,7 +2512,7 @@ namespace Sass { virtual bool operator<(const Simple_Selector& rhs) const; virtual bool operator<(const Element_Selector& rhs) const; ATTACH_AST_OPERATIONS(Element_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////// @@ -2532,7 +2532,7 @@ namespace Sass { } virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr); ATTACH_AST_OPERATIONS(Class_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////// @@ -2552,7 +2552,7 @@ namespace Sass { } virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr); ATTACH_AST_OPERATIONS(Id_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////////////////////// @@ -2591,7 +2591,7 @@ namespace Sass { virtual bool operator<(const Simple_Selector& rhs) const; virtual bool operator<(const Attribute_Selector& rhs) const; ATTACH_AST_OPERATIONS(Attribute_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ////////////////////////////////////////////////////////////////// @@ -2653,7 +2653,7 @@ namespace Sass { virtual bool operator<(const Pseudo_Selector& rhs) const; virtual Compound_Selector_Ptr unify_with(Compound_Selector_Ptr); ATTACH_AST_OPERATIONS(Pseudo_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; ///////////////////////////////////////////////// @@ -2682,7 +2682,7 @@ namespace Sass { virtual bool operator<(const Wrapped_Selector& rhs) const; virtual void cloneChildren(); ATTACH_AST_OPERATIONS(Wrapped_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////////// @@ -2787,7 +2787,7 @@ namespace Sass { Compound_Selector_Ptr minus(Compound_Selector_Ptr rhs); virtual void cloneChildren(); ATTACH_AST_OPERATIONS(Compound_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; //////////////////////////////////////////////////////////////////////////// @@ -2952,7 +2952,7 @@ namespace Sass { virtual void cloneChildren(); ATTACH_AST_OPERATIONS(Complex_Selector) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; /////////////////////////////////// @@ -3029,7 +3029,7 @@ namespace Sass { virtual bool operator==(const Expression& rhs) const; virtual void cloneChildren(); ATTACH_AST_OPERATIONS(Selector_List) - ATTACH_OPERATIONS() + ATTACH_CRTP_PERFORM_METHODS() }; // compare function for sorting and probably other other uses diff --git a/src/ast_def_macros.hpp b/src/ast_def_macros.hpp index b3a7f8d16..61e982156 100644 --- a/src/ast_def_macros.hpp +++ b/src/ast_def_macros.hpp @@ -35,16 +35,6 @@ class LocalOption { LocalOption cnt_##name(name, name + 1); \ if (name > MAX_NESTING) throw Exception::NestingLimitError(pstate, traces); \ -#define ATTACH_OPERATIONS()\ -virtual void perform(Operation* op) { (*op)(this); }\ -virtual AST_Node_Ptr perform(Operation* op) { return (*op)(this); }\ -virtual Statement_Ptr perform(Operation* op) { return (*op)(this); }\ -virtual Expression_Ptr perform(Operation* op) { return (*op)(this); }\ -virtual Selector_Ptr perform(Operation* op) { return (*op)(this); }\ -virtual std::string perform(Operation* op) { return (*op)(this); }\ -virtual union Sass_Value* perform(Operation* op) { return (*op)(this); }\ -virtual Value_Ptr perform(Operation* op) { return (*op)(this); } - #define ADD_PROPERTY(type, name)\ protected:\ type name##_;\ diff --git a/src/check_nesting.cpp b/src/check_nesting.cpp index 880bcca37..b43b03197 100644 --- a/src/check_nesting.cpp +++ b/src/check_nesting.cpp @@ -132,13 +132,6 @@ namespace Sass { return i; } - Statement_Ptr CheckNesting::fallback_impl(Statement_Ptr s) - { - Block_Ptr b1 = Cast(s); - Has_Block_Ptr b2 = Cast(s); - return b1 || b2 ? visit_children(s) : s; - } - bool CheckNesting::should_visit(Statement_Ptr node) { if (!this->parent) return true; diff --git a/src/check_nesting.hpp b/src/check_nesting.hpp index 62c38d9dc..687f4afdd 100644 --- a/src/check_nesting.hpp +++ b/src/check_nesting.hpp @@ -13,7 +13,6 @@ namespace Sass { Statement_Ptr parent; Definition_Ptr current_mixin_definition; - Statement_Ptr fallback_impl(Statement_Ptr); Statement_Ptr before(Statement_Ptr); Statement_Ptr visit_children(Statement_Ptr); @@ -27,11 +26,13 @@ namespace Sass { template Statement_Ptr fallback(U x) { - Statement_Ptr n = Cast(x); - if (this->should_visit(n)) { - return fallback_impl(n); + Statement_Ptr s = Cast(x); + if (s && this->should_visit(s)) { + Block_Ptr b1 = Cast(s); + Has_Block_Ptr b2 = Cast(s); + if (b1 || b2) return visit_children(s); } - return NULL; + return s; } private: diff --git a/src/cssize.cpp b/src/cssize.cpp index d5780dd70..cb4ab2c99 100644 --- a/src/cssize.cpp +++ b/src/cssize.cpp @@ -509,11 +509,6 @@ namespace Sass { return flatten(result); } - Statement_Ptr Cssize::fallback_impl(AST_Node_Ptr n) - { - return static_cast(n); - } - void Cssize::append_block(Block_Ptr b, Block_Ptr cur) { for (size_t i = 0, L = b->length(); i < L; ++i) { diff --git a/src/cssize.hpp b/src/cssize.hpp index 4dad47579..d6962fbf3 100644 --- a/src/cssize.hpp +++ b/src/cssize.hpp @@ -17,8 +17,6 @@ namespace Sass { BlockStack block_stack; std::vector p_stack; - Statement_Ptr fallback_impl(AST_Node_Ptr n); - public: Cssize(Context&); ~Cssize() { } @@ -66,8 +64,10 @@ namespace Sass { List_Ptr merge_media_queries(Media_Block_Ptr, Media_Block_Ptr); Media_Query_Ptr merge_media_query(Media_Query_Ptr, Media_Query_Ptr); + // generic fallback template - Statement_Ptr fallback(U x) { return fallback_impl(x); } + Statement_Ptr fallback(U x) + { return Cast(x); } void append_block(Block_Ptr, Block_Ptr); }; diff --git a/src/eval.cpp b/src/eval.cpp index 010cb9bb9..1a0c7a8bd 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1467,11 +1467,6 @@ namespace Sass { return 0; } - inline Expression_Ptr Eval::fallback_impl(AST_Node_Ptr n) - { - return static_cast(n); - } - // All the binary helpers. Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtraces traces, ParserState pstate) diff --git a/src/eval.hpp b/src/eval.hpp index aeaada87e..a5895fd89 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -14,9 +14,6 @@ namespace Sass { class Eval : public Operation_CRTP { - private: - Expression_Ptr fallback_impl(AST_Node_Ptr n); - public: Expand& exp; Context& ctx; @@ -78,18 +75,23 @@ namespace Sass { Compound_Selector_Ptr operator()(Compound_Selector_Ptr); Simple_Selector_Ptr operator()(Simple_Selector_Ptr s); Wrapped_Selector_Ptr operator()(Wrapped_Selector_Ptr s); + // they don't have any specific implementation (yet) - // Element_Selector_Ptr operator()(Element_Selector_Ptr s) { return s; }; - // Pseudo_Selector_Ptr operator()(Pseudo_Selector_Ptr s) { return s; }; - // Class_Selector_Ptr operator()(Class_Selector_Ptr s) { return s; }; - // Id_Selector_Ptr operator()(Id_Selector_Ptr s) { return s; }; - // Placeholder_Selector_Ptr operator()(Placeholder_Selector_Ptr s) { return s; }; + Id_Selector_Ptr operator()(Id_Selector_Ptr s) { return s; }; + Class_Selector_Ptr operator()(Class_Selector_Ptr s) { return s; }; + Pseudo_Selector_Ptr operator()(Pseudo_Selector_Ptr s) { return s; }; + Element_Selector_Ptr operator()(Element_Selector_Ptr s) { return s; }; + Attribute_Selector_Ptr operator()(Attribute_Selector_Ptr s) { return s; }; + Placeholder_Selector_Ptr operator()(Placeholder_Selector_Ptr s) { return s; }; + // actual evaluated selectors Selector_List_Ptr operator()(Selector_Schema_Ptr); Expression_Ptr operator()(Parent_Selector_Ptr); + // generic fallback template - Expression_Ptr fallback(U x) { return fallback_impl(x); } + Expression_Ptr fallback(U x) + { return Cast(x); } private: void interpolation(Context& ctx, std::string& res, Expression_Obj ex, bool into_quotes, bool was_itpl = false); diff --git a/src/expand.cpp b/src/expand.cpp index 0bf0b78eb..7db489c57 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -792,15 +792,6 @@ namespace Sass { return trace.detach(); } - // produce an error if something is not implemented - inline Statement_Ptr Expand::fallback_impl(AST_Node_Ptr n) - { - std::string err =std:: string("`Expand` doesn't handle ") + typeid(*n).name(); - String_Quoted_Obj msg = SASS_MEMORY_NEW(String_Quoted, ParserState("[WARN]"), err); - error("unknown internal error; please contact the LibSass maintainers", n->pstate(), traces); - return SASS_MEMORY_NEW(Warning, ParserState("[WARN]"), msg); - } - // process and add to last block on stack inline void Expand::append_block(Block_Ptr b) { diff --git a/src/expand.hpp b/src/expand.hpp index 3d6d1eb6b..d88305e09 100644 --- a/src/expand.hpp +++ b/src/expand.hpp @@ -38,8 +38,6 @@ namespace Sass { Boolean_Obj bool_true; - Statement_Ptr fallback_impl(AST_Node_Ptr n); - private: void expand_selector_list(Selector_Obj, Selector_List_Obj extender); @@ -71,10 +69,8 @@ namespace Sass { Statement_Ptr operator()(Mixin_Call_Ptr); Statement_Ptr operator()(Content_Ptr); - template - Statement_Ptr fallback(U x) { return fallback_impl(x); } - void append_block(Block_Ptr); + }; } diff --git a/src/extend.hpp b/src/extend.hpp index 03042f3e2..e222359e3 100644 --- a/src/extend.hpp +++ b/src/extend.hpp @@ -20,8 +20,6 @@ namespace Sass { Subset_Map& subset_map; Eval* eval; - void fallback_impl(AST_Node_Ptr n) { } - private: std::unordered_map< @@ -77,8 +75,10 @@ namespace Sass { void operator()(Media_Block_Ptr); void operator()(Directive_Ptr); + // ignore missed types template - void fallback(U x) { return fallback_impl(x); } + void fallback(U x) {} + }; } diff --git a/src/inspect.cpp b/src/inspect.cpp index 273ff8fb1..c82ae0757 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -1131,8 +1131,4 @@ namespace Sass { } - void Inspect::fallback_impl(AST_Node_Ptr n) - { - } - } diff --git a/src/inspect.hpp b/src/inspect.hpp index c36790b80..8f5e8af76 100644 --- a/src/inspect.hpp +++ b/src/inspect.hpp @@ -13,8 +13,6 @@ namespace Sass { // import all the class-specific methods and override as desired using Operation_CRTP::operator(); - void fallback_impl(AST_Node_Ptr n); - public: Inspect(const Emitter& emi); @@ -95,8 +93,6 @@ namespace Sass { virtual std::string lbracket(List_Ptr); virtual std::string rbracket(List_Ptr); - // template - // void fallback(U x) { fallback_impl(reinterpret_cast(x)); } }; } diff --git a/src/listize.cpp b/src/listize.cpp index cb921ae67..a18724e45 100644 --- a/src/listize.cpp +++ b/src/listize.cpp @@ -78,9 +78,4 @@ namespace Sass { return l.detach(); } - Expression_Ptr Listize::fallback_impl(AST_Node_Ptr n) - { - return Cast(n); - } - } diff --git a/src/listize.hpp b/src/listize.hpp index 9716ebefc..8fa148816 100644 --- a/src/listize.hpp +++ b/src/listize.hpp @@ -15,8 +15,6 @@ namespace Sass { class Listize : public Operation_CRTP { - Expression_Ptr fallback_impl(AST_Node_Ptr n); - public: Listize(); ~Listize() { } @@ -25,8 +23,10 @@ namespace Sass { Expression_Ptr operator()(Complex_Selector_Ptr); Expression_Ptr operator()(Compound_Selector_Ptr); + // generic fallback template - Expression_Ptr fallback(U x) { return fallback_impl(x); } + Expression_Ptr fallback(U x) + { return Cast(x); } }; } diff --git a/src/operation.hpp b/src/operation.hpp index 2d4fbec9d..02e604ac6 100644 --- a/src/operation.hpp +++ b/src/operation.hpp @@ -1,15 +1,33 @@ #ifndef SASS_OPERATION_H #define SASS_OPERATION_H +// base classes to implement curiously recurring template pattern (CRTP) +// https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern + #include "ast_fwd_decl.hpp" +#include "ast_def_macros.hpp" namespace Sass { + // you must add operators to every class + // ensures `this` of actual instance type + // we therefore call the specific operator + // they are virtual so most specific is used + #define ATTACH_CRTP_PERFORM_METHODS()\ + virtual void perform(Operation* op) { return (*op)(this); } \ + virtual Value_Ptr perform(Operation* op) { return (*op)(this); } \ + virtual std::string perform(Operation* op) { return (*op)(this); } \ + virtual AST_Node_Ptr perform(Operation* op) { return (*op)(this); } \ + virtual Selector_Ptr perform(Operation* op) { return (*op)(this); } \ + virtual Statement_Ptr perform(Operation* op) { return (*op)(this); } \ + virtual Expression_Ptr perform(Operation* op) { return (*op)(this); } \ + virtual union Sass_Value* perform(Operation* op) { return (*op)(this); } \ + virtual Supports_Condition_Ptr perform(Operation* op) { return (*op)(this); } \ + template class Operation { public: virtual T operator()(AST_Node_Ptr x) = 0; - virtual ~Operation() { } // statements virtual T operator()(Block_Ptr x) = 0; virtual T operator()(Ruleset_Ptr x) = 0; @@ -38,6 +56,7 @@ namespace Sass { virtual T operator()(Definition_Ptr x) = 0; virtual T operator()(Mixin_Call_Ptr x) = 0; // expressions + virtual T operator()(Null_Ptr x) = 0; virtual T operator()(List_Ptr x) = 0; virtual T operator()(Map_Ptr x) = 0; virtual T operator()(Function_Ptr x) = 0; @@ -62,7 +81,6 @@ namespace Sass { virtual T operator()(Media_Query_Ptr x) = 0; virtual T operator()(Media_Query_Expression_Ptr x) = 0; virtual T operator()(At_Root_Query_Ptr x) = 0; - virtual T operator()(Null_Ptr x) = 0; virtual T operator()(Parent_Selector_Ptr x) = 0; // parameters and arguments virtual T operator()(Parameter_Ptr x) = 0; @@ -81,15 +99,14 @@ namespace Sass { virtual T operator()(Compound_Selector_Ptr x)= 0; virtual T operator()(Complex_Selector_Ptr x) = 0; virtual T operator()(Selector_List_Ptr x) = 0; - - template - T fallback(U x) { return T(); } }; + // example: Operation_CRTP + // T is the base return type of all visitors + // D is the class derived visitor class + // normaly you want to implement all operators template class Operation_CRTP : public Operation { - public: - D& impl() { return static_cast(*this); } public: T operator()(AST_Node_Ptr x) { return static_cast(this)->fallback(x); } // statements @@ -120,6 +137,7 @@ namespace Sass { T operator()(Definition_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Mixin_Call_Ptr x) { return static_cast(this)->fallback(x); } // expressions + T operator()(Null_Ptr x) { return static_cast(this)->fallback(x); } T operator()(List_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Map_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Function_Ptr x) { return static_cast(this)->fallback(x); } @@ -144,7 +162,6 @@ namespace Sass { T operator()(Media_Query_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Media_Query_Expression_Ptr x) { return static_cast(this)->fallback(x); } T operator()(At_Root_Query_Ptr x) { return static_cast(this)->fallback(x); } - T operator()(Null_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Parent_Selector_Ptr x) { return static_cast(this)->fallback(x); } // parameters and arguments T operator()(Parameter_Ptr x) { return static_cast(this)->fallback(x); } @@ -164,8 +181,15 @@ namespace Sass { T operator()(Complex_Selector_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Selector_List_Ptr x) { return static_cast(this)->fallback(x); } - template - T fallback(U x) { return T(); } + // fallback with specific type U + // will be called if not overloaded + template T fallback(U x) + { + std::string msg(typeid(*this).name()); + msg += ": CRTP not implemented for "; + throw std::runtime_error(msg + typeid(*x).name()); + } + }; } diff --git a/src/remove_placeholders.hpp b/src/remove_placeholders.hpp index c13b63134..690b0f3eb 100644 --- a/src/remove_placeholders.hpp +++ b/src/remove_placeholders.hpp @@ -11,8 +11,6 @@ namespace Sass { class Remove_Placeholders : public Operation_CRTP { - void fallback_impl(AST_Node_Ptr n) {} - public: Selector_List_Ptr remove_placeholders(Selector_List_Ptr); @@ -26,8 +24,9 @@ namespace Sass { void operator()(Supports_Block_Ptr); void operator()(Directive_Ptr); + // ignore missed types template - void fallback(U x) { return fallback_impl(x); } + void fallback(U x) {} }; } diff --git a/src/to_value.cpp b/src/to_value.cpp index 3912c5510..f94c09a69 100644 --- a/src/to_value.cpp +++ b/src/to_value.cpp @@ -4,13 +4,6 @@ namespace Sass { - Value_Ptr To_Value::fallback_impl(AST_Node_Ptr n) - { - // throw a runtime error if this happens - // we want a well defined set of possible nodes - throw std::runtime_error("invalid node for to_value"); - } - // Custom_Error is a valid value Value_Ptr To_Value::operator()(Custom_Error_Ptr e) { diff --git a/src/to_value.hpp b/src/to_value.hpp index 8f64128c4..ba422b3d4 100644 --- a/src/to_value.hpp +++ b/src/to_value.hpp @@ -9,8 +9,6 @@ namespace Sass { class To_Value : public Operation_CRTP { - Value_Ptr fallback_impl(AST_Node_Ptr n); - private: Context& ctx; @@ -40,9 +38,6 @@ namespace Sass { Value_Ptr operator()(Selector_List_Ptr); Value_Ptr operator()(Binary_Expression_Ptr); - // fallback throws error - template - Value_Ptr fallback(U x) { return fallback_impl(x); } }; } From efc0331228d639505e41d18699bd133b6d82b4cf Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 03:36:36 +0100 Subject: [PATCH 13/30] Rename ast2c and move c2ast to own compile unit --- Makefile.conf | 3 +- src/{to_c.cpp => ast2c.cpp} | 29 +++++++------- src/{to_c.hpp => ast2c.hpp} | 17 ++++----- src/c2ast.cpp | 64 +++++++++++++++++++++++++++++++ src/c2ast.hpp | 14 +++++++ src/eval.cpp | 76 ++++++------------------------------- src/eval.hpp | 2 - src/fn_colors.cpp | 3 +- src/fn_strings.cpp | 3 ++ win/libsass.targets | 6 ++- win/libsass.vcxproj.filters | 10 ++++- 11 files changed, 129 insertions(+), 98 deletions(-) rename src/{to_c.cpp => ast2c.cpp} (63%) rename src/{to_c.hpp => ast2c.hpp} (71%) create mode 100644 src/c2ast.cpp create mode 100644 src/c2ast.hpp diff --git a/Makefile.conf b/Makefile.conf index 6e42a8677..2725c6bf0 100644 --- a/Makefile.conf +++ b/Makefile.conf @@ -51,7 +51,8 @@ SOURCES = \ sass2scss.cpp \ backtrace.cpp \ operators.cpp \ - to_c.cpp \ + ast2c.cpp \ + c2ast.cpp \ to_value.cpp \ source_map.cpp \ subset_map.cpp \ diff --git a/src/to_c.cpp b/src/ast2c.cpp similarity index 63% rename from src/to_c.cpp rename to src/ast2c.cpp index 8a6ea8d51..be9ea800f 100644 --- a/src/to_c.cpp +++ b/src/ast2c.cpp @@ -1,28 +1,25 @@ #include "sass.hpp" -#include "to_c.hpp" +#include "ast2c.hpp" #include "ast.hpp" namespace Sass { - union Sass_Value* To_C::fallback_impl(AST_Node_Ptr n) - { return sass_make_error("unknown type for C-API"); } - - union Sass_Value* To_C::operator()(Boolean_Ptr b) + union Sass_Value* AST2C::operator()(Boolean_Ptr b) { return sass_make_boolean(b->value()); } - union Sass_Value* To_C::operator()(Number_Ptr n) + union Sass_Value* AST2C::operator()(Number_Ptr n) { return sass_make_number(n->value(), n->unit().c_str()); } - union Sass_Value* To_C::operator()(Custom_Warning_Ptr w) + union Sass_Value* AST2C::operator()(Custom_Warning_Ptr w) { return sass_make_warning(w->message().c_str()); } - union Sass_Value* To_C::operator()(Custom_Error_Ptr e) + union Sass_Value* AST2C::operator()(Custom_Error_Ptr e) { return sass_make_error(e->message().c_str()); } - union Sass_Value* To_C::operator()(Color_Ptr c) + union Sass_Value* AST2C::operator()(Color_Ptr c) { return sass_make_color(c->r(), c->g(), c->b(), c->a()); } - union Sass_Value* To_C::operator()(String_Constant_Ptr s) + union Sass_Value* AST2C::operator()(String_Constant_Ptr s) { if (s->quote_mark()) { return sass_make_qstring(s->value().c_str()); @@ -31,10 +28,10 @@ namespace Sass { } } - union Sass_Value* To_C::operator()(String_Quoted_Ptr s) + union Sass_Value* AST2C::operator()(String_Quoted_Ptr s) { return sass_make_qstring(s->value().c_str()); } - union Sass_Value* To_C::operator()(List_Ptr l) + union Sass_Value* AST2C::operator()(List_Ptr l) { union Sass_Value* v = sass_make_list(l->length(), l->separator(), l->is_bracketed()); for (size_t i = 0, L = l->length(); i < L; ++i) { @@ -43,7 +40,7 @@ namespace Sass { return v; } - union Sass_Value* To_C::operator()(Map_Ptr m) + union Sass_Value* AST2C::operator()(Map_Ptr m) { union Sass_Value* v = sass_make_map(m->length()); int i = 0; @@ -55,7 +52,7 @@ namespace Sass { return v; } - union Sass_Value* To_C::operator()(Arguments_Ptr a) + union Sass_Value* AST2C::operator()(Arguments_Ptr a) { union Sass_Value* v = sass_make_list(a->length(), SASS_COMMA, false); for (size_t i = 0, L = a->length(); i < L; ++i) { @@ -64,11 +61,11 @@ namespace Sass { return v; } - union Sass_Value* To_C::operator()(Argument_Ptr a) + union Sass_Value* AST2C::operator()(Argument_Ptr a) { return a->value()->perform(this); } // not strictly necessary because of the fallback - union Sass_Value* To_C::operator()(Null_Ptr n) + union Sass_Value* AST2C::operator()(Null_Ptr n) { return sass_make_null(); } }; diff --git a/src/to_c.hpp b/src/ast2c.hpp similarity index 71% rename from src/to_c.hpp rename to src/ast2c.hpp index a5331e3bf..428791619 100644 --- a/src/to_c.hpp +++ b/src/ast2c.hpp @@ -1,5 +1,5 @@ -#ifndef SASS_TO_C_H -#define SASS_TO_C_H +#ifndef SASS_AST2C_H +#define SASS_AST2C_H #include "ast_fwd_decl.hpp" #include "operation.hpp" @@ -7,14 +7,12 @@ namespace Sass { - class To_C : public Operation_CRTP { - // override this to define a catch-all - union Sass_Value* fallback_impl(AST_Node_Ptr n); + class AST2C : public Operation_CRTP { public: - To_C() { } - ~To_C() { } + AST2C() { } + ~AST2C() { } union Sass_Value* operator()(Boolean_Ptr); union Sass_Value* operator()(Number_Ptr); @@ -29,9 +27,10 @@ namespace Sass { union Sass_Value* operator()(Arguments_Ptr); union Sass_Value* operator()(Argument_Ptr); - // dispatch to fallback implementation + // return sass error if type is not supported union Sass_Value* fallback(AST_Node_Ptr x) - { return fallback_impl(x); } + { return sass_make_error("unknown type for C-API"); } + }; } diff --git a/src/c2ast.cpp b/src/c2ast.cpp new file mode 100644 index 000000000..c766fa184 --- /dev/null +++ b/src/c2ast.cpp @@ -0,0 +1,64 @@ +#include "ast.hpp" +#include "units.hpp" +#include "position.hpp" +#include "backtrace.hpp" +#include "sass/values.h" +#include "ast_fwd_decl.hpp" +#include "error_handling.hpp" + +namespace Sass { + + Value_Ptr c2ast(union Sass_Value* v, Backtraces traces, ParserState pstate) + { + using std::strlen; + using std::strcpy; + Value_Ptr e = NULL; + switch (sass_value_get_tag(v)) { + case SASS_BOOLEAN: { + e = SASS_MEMORY_NEW(Boolean, pstate, !!sass_boolean_get_value(v)); + } break; + case SASS_NUMBER: { + e = SASS_MEMORY_NEW(Number, pstate, sass_number_get_value(v), sass_number_get_unit(v)); + } break; + case SASS_COLOR: { + e = SASS_MEMORY_NEW(Color, pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v)); + } break; + case SASS_STRING: { + if (sass_string_is_quoted(v)) + e = SASS_MEMORY_NEW(String_Quoted, pstate, sass_string_get_value(v)); + else { + e = SASS_MEMORY_NEW(String_Constant, pstate, sass_string_get_value(v)); + } + } break; + case SASS_LIST: { + List_Ptr l = SASS_MEMORY_NEW(List, pstate, sass_list_get_length(v), sass_list_get_separator(v)); + for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) { + l->append(c2ast(sass_list_get_value(v, i), traces, pstate)); + } + l->is_bracketed(sass_list_get_is_bracketed(v)); + e = l; + } break; + case SASS_MAP: { + Map_Ptr m = SASS_MEMORY_NEW(Map, pstate); + for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) { + *m << std::make_pair( + c2ast(sass_map_get_key(v, i), traces, pstate), + c2ast(sass_map_get_value(v, i), traces, pstate)); + } + e = m; + } break; + case SASS_NULL: { + e = SASS_MEMORY_NEW(Null, pstate); + } break; + case SASS_ERROR: { + error("Error in C function: " + std::string(sass_error_get_message(v)), pstate, traces); + } break; + case SASS_WARNING: { + error("Warning in C function: " + std::string(sass_warning_get_message(v)), pstate, traces); + } break; + default: break; + } + return e; + } + +} diff --git a/src/c2ast.hpp b/src/c2ast.hpp new file mode 100644 index 000000000..d6c0a97c3 --- /dev/null +++ b/src/c2ast.hpp @@ -0,0 +1,14 @@ +#ifndef SASS_C2AST_H +#define SASS_C2AST_H + +#include "position.hpp" +#include "backtrace.hpp" +#include "ast_fwd_decl.hpp" + +namespace Sass { + + Value_Ptr c2ast(union Sass_Value* v, Backtraces traces, ParserState pstate); + +} + +#endif diff --git a/src/eval.cpp b/src/eval.cpp index 1a0c7a8bd..512c420e2 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -17,7 +17,8 @@ #include "position.hpp" #include "sass/values.h" #include "to_value.hpp" -#include "to_c.hpp" +#include "ast2c.hpp" +#include "c2ast.hpp" #include "context.hpp" #include "backtrace.hpp" #include "lexer.hpp" @@ -333,9 +334,9 @@ namespace Sass { Sass_Function_Entry c_function = def->c_function(); Sass_Function_Fn c_func = sass_function_get_function(c_function); - To_C to_c; + AST2C ast2c; union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); - sass_list_set_value(c_args, 0, message->perform(&to_c)); + sass_list_set_value(c_args, 0, message->perform(&ast2c)); union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); ctx.c_options.output_style = outstyle; ctx.callee_stack.pop_back(); @@ -381,9 +382,9 @@ namespace Sass { Sass_Function_Entry c_function = def->c_function(); Sass_Function_Fn c_func = sass_function_get_function(c_function); - To_C to_c; + AST2C ast2c; union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); - sass_list_set_value(c_args, 0, message->perform(&to_c)); + sass_list_set_value(c_args, 0, message->perform(&ast2c)); union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); ctx.c_options.output_style = outstyle; ctx.callee_stack.pop_back(); @@ -425,9 +426,9 @@ namespace Sass { Sass_Function_Entry c_function = def->c_function(); Sass_Function_Fn c_func = sass_function_get_function(c_function); - To_C to_c; + AST2C ast2c; union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); - sass_list_set_value(c_args, 0, message->perform(&to_c)); + sass_list_set_value(c_args, 0, message->perform(&ast2c)); union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); ctx.c_options.output_style = outstyle; ctx.callee_stack.pop_back(); @@ -1054,14 +1055,14 @@ namespace Sass { { env } }); - To_C to_c; + AST2C ast2c; union Sass_Value* c_args = sass_make_list(params->length(), SASS_COMMA, false); for(size_t i = 0; i < params->length(); i++) { Parameter_Obj param = params->at(i); std::string key = param->name(); AST_Node_Obj node = fn_env.get_local(key); Expression_Obj arg = Cast(node); - sass_list_set_value(c_args, i, arg->perform(&to_c)); + sass_list_set_value(c_args, i, arg->perform(&ast2c)); } union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); if (sass_value_get_tag(c_val) == SASS_ERROR) { @@ -1069,7 +1070,7 @@ namespace Sass { } else if (sass_value_get_tag(c_val) == SASS_WARNING) { error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), traces); } - result = cval_to_astnode(c_val, traces, c->pstate()); + result = c2ast(c_val, traces, c->pstate()); ctx.callee_stack.pop_back(); traces.pop_back(); @@ -1467,61 +1468,6 @@ namespace Sass { return 0; } - // All the binary helpers. - - Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtraces traces, ParserState pstate) - { - using std::strlen; - using std::strcpy; - Expression_Ptr e = NULL; - switch (sass_value_get_tag(v)) { - case SASS_BOOLEAN: { - e = SASS_MEMORY_NEW(Boolean, pstate, !!sass_boolean_get_value(v)); - } break; - case SASS_NUMBER: { - e = SASS_MEMORY_NEW(Number, pstate, sass_number_get_value(v), sass_number_get_unit(v)); - } break; - case SASS_COLOR: { - e = SASS_MEMORY_NEW(Color, pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v)); - } break; - case SASS_STRING: { - if (sass_string_is_quoted(v)) - e = SASS_MEMORY_NEW(String_Quoted, pstate, sass_string_get_value(v)); - else { - e = SASS_MEMORY_NEW(String_Constant, pstate, sass_string_get_value(v)); - } - } break; - case SASS_LIST: { - List_Ptr l = SASS_MEMORY_NEW(List, pstate, sass_list_get_length(v), sass_list_get_separator(v)); - for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) { - l->append(cval_to_astnode(sass_list_get_value(v, i), traces, pstate)); - } - l->is_bracketed(sass_list_get_is_bracketed(v)); - e = l; - } break; - case SASS_MAP: { - Map_Ptr m = SASS_MEMORY_NEW(Map, pstate); - for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) { - *m << std::make_pair( - cval_to_astnode(sass_map_get_key(v, i), traces, pstate), - cval_to_astnode(sass_map_get_value(v, i), traces, pstate)); - } - e = m; - } break; - case SASS_NULL: { - e = SASS_MEMORY_NEW(Null, pstate); - } break; - case SASS_ERROR: { - error("Error in C function: " + std::string(sass_error_get_message(v)), pstate, traces); - } break; - case SASS_WARNING: { - error("Warning in C function: " + std::string(sass_warning_get_message(v)), pstate, traces); - } break; - default: break; - } - return e; - } - Selector_List_Ptr Eval::operator()(Selector_List_Ptr s) { SelectorStack rv; diff --git a/src/eval.hpp b/src/eval.hpp index a5895fd89..a0cb97aae 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -98,8 +98,6 @@ namespace Sass { }; - Expression_Ptr cval_to_astnode(union Sass_Value* v, Backtraces traces, ParserState pstate = ParserState("[AST]")); - } #endif diff --git a/src/fn_colors.cpp b/src/fn_colors.cpp index cc4613b6a..642e9d4f4 100644 --- a/src/fn_colors.cpp +++ b/src/fn_colors.cpp @@ -1,3 +1,4 @@ +#include #include #include "ast.hpp" #include "fn_utils.hpp" @@ -738,4 +739,4 @@ namespace Sass { } -} \ No newline at end of file +} diff --git a/src/fn_strings.cpp b/src/fn_strings.cpp index 7949cc4f1..16ed74b34 100644 --- a/src/fn_strings.cpp +++ b/src/fn_strings.cpp @@ -1,4 +1,7 @@ +#include +#include "utf8.h" #include "ast.hpp" +#include "sass.hpp" #include "fn_utils.hpp" #include "fn_strings.hpp" diff --git a/win/libsass.targets b/win/libsass.targets index eb0aca770..62780aeac 100644 --- a/win/libsass.targets +++ b/win/libsass.targets @@ -63,7 +63,8 @@ - + + @@ -124,7 +125,8 @@ - + + diff --git a/win/libsass.vcxproj.filters b/win/libsass.vcxproj.filters index 836b4c298..407fac783 100644 --- a/win/libsass.vcxproj.filters +++ b/win/libsass.vcxproj.filters @@ -198,7 +198,10 @@ Headers - + + Headers + + Headers @@ -383,7 +386,10 @@ Sources - + + Sources + + Sources From 064d6dec7be3637e566a696b68e83e73ed88bfd9 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 03:38:59 +0100 Subject: [PATCH 14/30] Move AST memory macros to macro header --- src/ast.cpp | 32 --------------------------- src/ast.hpp | 36 ------------------------------ src/ast_def_macros.hpp | 50 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 68 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index 341cbc3fb..e38a5e5cb 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -2124,38 +2124,6 @@ namespace Sass { return ret; } - ////////////////////////////////////////////////////////////////////////////////////////// - // Copy implementations - ////////////////////////////////////////////////////////////////////////////////////////// - - #ifdef DEBUG_SHARED_PTR - - #define IMPLEMENT_AST_OPERATORS(klass) \ - klass##_Ptr klass::copy(std::string file, size_t line) const { \ - klass##_Ptr cpy = new klass(this); \ - cpy->trace(file, line); \ - return cpy; \ - } \ - klass##_Ptr klass::clone(std::string file, size_t line) const { \ - klass##_Ptr cpy = copy(file, line); \ - cpy->cloneChildren(); \ - return cpy; \ - } \ - - #else - - #define IMPLEMENT_AST_OPERATORS(klass) \ - klass##_Ptr klass::copy() const { \ - return new klass(this); \ - } \ - klass##_Ptr klass::clone() const { \ - klass##_Ptr cpy = copy(); \ - cpy->cloneChildren(); \ - return cpy; \ - } \ - - #endif - IMPLEMENT_AST_OPERATORS(Supports_Operator); IMPLEMENT_AST_OPERATORS(Supports_Negation); IMPLEMENT_AST_OPERATORS(Compound_Selector); diff --git a/src/ast.hpp b/src/ast.hpp index 3a62cbcef..dd6d2d1d2 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -13,42 +13,6 @@ #include "sass/base.h" #include "ast_fwd_decl.hpp" -#ifdef DEBUG_SHARED_PTR - -#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \ - virtual klass##_Ptr copy(std::string, size_t) const = 0; \ - virtual klass##_Ptr clone(std::string, size_t) const = 0; \ - -#define ATTACH_AST_OPERATIONS(klass) \ - virtual klass##_Ptr copy(std::string, size_t) const; \ - virtual klass##_Ptr clone(std::string, size_t) const; \ - -#else - -#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \ - virtual klass##_Ptr copy() const = 0; \ - virtual klass##_Ptr clone() const = 0; \ - -#define ATTACH_AST_OPERATIONS(klass) \ - virtual klass##_Ptr copy() const; \ - virtual klass##_Ptr clone() const; \ - -#endif - -#ifdef __clang__ - -/* - * There are some overloads used here that trigger the clang overload - * hiding warning. Specifically: - * - * Type type() which hides string type() from Expression - * - */ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Woverloaded-virtual" - -#endif - #include "util.hpp" #include "units.hpp" #include "context.hpp" diff --git a/src/ast_def_macros.hpp b/src/ast_def_macros.hpp index 61e982156..eadb1b1ac 100644 --- a/src/ast_def_macros.hpp +++ b/src/ast_def_macros.hpp @@ -67,4 +67,54 @@ public: \ void name(type name##__) { hash_ = 0; name##_ = name##__; } \ private: +#ifdef DEBUG_SHARED_PTR + +#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \ + virtual klass##_Ptr copy(std::string, size_t) const = 0; \ + virtual klass##_Ptr clone(std::string, size_t) const = 0; \ + +#define ATTACH_AST_OPERATIONS(klass) \ + virtual klass##_Ptr copy(std::string, size_t) const; \ + virtual klass##_Ptr clone(std::string, size_t) const; \ + +#else + +#define ATTACH_VIRTUAL_AST_OPERATIONS(klass) \ + virtual klass##_Ptr copy() const = 0; \ + virtual klass##_Ptr clone() const = 0; \ + +#define ATTACH_AST_OPERATIONS(klass) \ + virtual klass##_Ptr copy() const; \ + virtual klass##_Ptr clone() const; \ + +#endif + +#ifdef DEBUG_SHARED_PTR + + #define IMPLEMENT_AST_OPERATORS(klass) \ + klass##_Ptr klass::copy(std::string file, size_t line) const { \ + klass##_Ptr cpy = new klass(this); \ + cpy->trace(file, line); \ + return cpy; \ + } \ + klass##_Ptr klass::clone(std::string file, size_t line) const { \ + klass##_Ptr cpy = copy(file, line); \ + cpy->cloneChildren(); \ + return cpy; \ + } \ + +#else + + #define IMPLEMENT_AST_OPERATORS(klass) \ + klass##_Ptr klass::copy() const { \ + return new klass(this); \ + } \ + klass##_Ptr klass::clone() const { \ + klass##_Ptr cpy = copy(); \ + cpy->cloneChildren(); \ + return cpy; \ + } \ + +#endif + #endif From 10c25da521f59ad41fde62c031f2eaf69820b76b Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 04:09:52 +0100 Subject: [PATCH 15/30] Make Value inherit from PreValue --- src/ast.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index dd6d2d1d2..ae79d785d 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -209,14 +209,14 @@ namespace Sass { ////////////////////////////////////////////////////////////////////// // base class for values that support operations ////////////////////////////////////////////////////////////////////// - class Value : public Expression { + class Value : public PreValue { public: Value(ParserState pstate, bool d = false, bool e = false, bool i = false, Concrete_Type ct = NONE) - : Expression(pstate, d, e, i, ct) + : PreValue(pstate, d, e, i, ct) { } Value(const Value* ptr) - : Expression(ptr) + : PreValue(ptr) { } ATTACH_VIRTUAL_AST_OPERATIONS(Value); virtual bool operator== (const Expression& rhs) const = 0; From 0599b2ec443ba2eb25de4e037c26261c00a6d39f Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 05:58:33 +0100 Subject: [PATCH 16/30] Remove obsolete parameters --- src/ast_fwd_decl.hpp | 1 - src/bind.cpp | 2 +- src/bind.hpp | 2 +- src/eval.cpp | 4 ++-- src/expand.cpp | 2 +- src/fn_utils.hpp | 2 -- 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index 90c362310..e4037865f 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -426,7 +426,6 @@ namespace Sass { typedef std::vector ImporterStack; typedef const char* Signature; - // only to switch implementations for testing #define environment_map std::map diff --git a/src/bind.cpp b/src/bind.cpp index ec20ac838..fdae1fea6 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -10,7 +10,7 @@ namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Context* ctx, Env* env, Eval* eval) + void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Env* env, Eval* eval) { std::string callee(type + " " + name); diff --git a/src/bind.hpp b/src/bind.hpp index 93a503aa6..9e9e0ec4e 100644 --- a/src/bind.hpp +++ b/src/bind.hpp @@ -7,7 +7,7 @@ namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Context*, Env*, Eval*); + void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Env*, Eval*); } #endif diff --git a/src/eval.cpp b/src/eval.cpp index 512c420e2..585b56d6a 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1003,7 +1003,7 @@ namespace Sass { exp.env_stack.push_back(&fn_env); if (func || body) { - bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this); + bind(std::string("Function"), c->name(), params, args, &fn_env, this); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); ctx.callee_stack.push_back({ @@ -1043,7 +1043,7 @@ namespace Sass { // populates env with default values for params std::string ff(c->name()); - bind(std::string("Function"), c->name(), params, args, &ctx, &fn_env, this); + bind(std::string("Function"), c->name(), params, args, &fn_env, this); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); ctx.callee_stack.push_back({ diff --git a/src/expand.cpp b/src/expand.cpp index 7db489c57..1987c4907 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -740,7 +740,7 @@ namespace Sass { new_env.local_frame()["@content[m]"] = thunk; } - bind(std::string("Mixin"), c->name(), params, args, &ctx, &new_env, &eval); + bind(std::string("Mixin"), c->name(), params, args, &new_env, &eval); Block_Obj trace_block = SASS_MEMORY_NEW(Block, c->pstate()); Trace_Obj trace = SASS_MEMORY_NEW(Trace, c->pstate(), c->name(), trace_block); diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index ab03bbf4f..4d00d904c 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -16,8 +16,6 @@ namespace Sass { // special function for weird hsla percent (10px == 10% == 10 != 0.1) #define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double - typedef const char* Signature; - typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); Definition_Ptr make_native_function(Signature, Native_Function, Context& ctx); From 205dc65d0f1af1f5f715080432192195d64256be Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 04:18:45 +0100 Subject: [PATCH 17/30] Remove Function_Call_Schema class - handle in Function_Call directly --- src/ast.cpp | 39 +++++++++++++++++++- src/ast.hpp | 79 +++++++++++++--------------------------- src/ast_fwd_decl.hpp | 4 -- src/debugger.hpp | 8 ---- src/eval.cpp | 20 +++++----- src/eval.hpp | 1 - src/inspect.cpp | 6 --- src/inspect.hpp | 1 - src/memory/SharedPtr.hpp | 11 ++++++ src/operation.hpp | 2 - src/parser.cpp | 4 +- src/parser.hpp | 2 +- 12 files changed, 88 insertions(+), 89 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index e38a5e5cb..f03eb9ccc 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -2108,6 +2108,44 @@ namespace Sass { } } + Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie) + : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(0), via_call_(false), cookie_(cookie), hash_(0) + { concrete_type(FUNCTION); } + Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func) + : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) + { concrete_type(FUNCTION); } + Function_Call::Function_Call(ParserState pstate, std::string n, Arguments_Obj args) + : PreValue(pstate), sname_(SASS_MEMORY_NEW(String_Constant, pstate, n)), arguments_(args), via_call_(false), cookie_(0), hash_(0) + { concrete_type(FUNCTION); } + + bool Function_Call::operator==(const Expression& rhs) const + { + try + { + Function_Call_Ptr_Const m = Cast(&rhs); + if (!(m && *sname() == *m->sname())) return false; + if (!(m && arguments()->length() == m->arguments()->length())) return false; + for (size_t i =0, L = arguments()->length(); i < L; ++i) + if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false; + return true; + } + catch (std::bad_cast&) + { + return false; + } + catch (...) { throw; } + } + + size_t Function_Call::hash() + { + if (hash_ == 0) { + hash_ = std::hash()(name()); + for (auto argument : arguments()->elements()) + hash_combine(hash_, argument->hash()); + } + return hash_; + } + ////////////////////////////////////////////////////////////////////////////////////////// // Convert map to (key, value) list. ////////////////////////////////////////////////////////////////////////////////////////// @@ -2181,7 +2219,6 @@ namespace Sass { IMPLEMENT_AST_OPERATORS(Arguments); IMPLEMENT_AST_OPERATORS(Argument); IMPLEMENT_AST_OPERATORS(Unary_Expression); - IMPLEMENT_AST_OPERATORS(Function_Call_Schema); IMPLEMENT_AST_OPERATORS(Block); IMPLEMENT_AST_OPERATORS(Content); IMPLEMENT_AST_OPERATORS(Trace); diff --git a/src/ast.hpp b/src/ast.hpp index ae79d785d..f7874b36e 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -81,6 +81,12 @@ namespace Sass { : pstate_(ptr->pstate_) { } + // allow implicit conversion to string + // needed for by SharedPtr implementation + operator std::string() { + return to_string(); + } + // AST_Node(AST_Node& ptr) = delete; virtual ~AST_Node() = 0; @@ -1429,25 +1435,34 @@ namespace Sass { // Function calls. ////////////////// class Function_Call : public PreValue { - HASH_CONSTREF(std::string, name) + HASH_CONSTREF(String_Obj, sname) HASH_PROPERTY(Arguments_Obj, arguments) HASH_PROPERTY(Function_Obj, func) ADD_PROPERTY(bool, via_call) ADD_PROPERTY(void*, cookie) size_t hash_; public: - Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie) - : PreValue(pstate), name_(n), arguments_(args), func_(0), via_call_(false), cookie_(cookie), hash_(0) + Function_Call(ParserState pstate, std::string n, Arguments_Obj args, void* cookie); + Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func); + Function_Call(ParserState pstate, std::string n, Arguments_Obj args); + + Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, void* cookie) + : PreValue(pstate), sname_(n), arguments_(args), func_(0), via_call_(false), cookie_(cookie), hash_(0) { concrete_type(FUNCTION); } - Function_Call(ParserState pstate, std::string n, Arguments_Obj args, Function_Obj func) - : PreValue(pstate), name_(n), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) + Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args, Function_Obj func) + : PreValue(pstate), sname_(n), arguments_(args), func_(func), via_call_(false), cookie_(0), hash_(0) { concrete_type(FUNCTION); } - Function_Call(ParserState pstate, std::string n, Arguments_Obj args) - : PreValue(pstate), name_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0) + Function_Call(ParserState pstate, String_Obj n, Arguments_Obj args) + : PreValue(pstate), sname_(n), arguments_(args), via_call_(false), cookie_(0), hash_(0) { concrete_type(FUNCTION); } + + std::string name() { + return sname(); + } + Function_Call(const Function_Call* ptr) : PreValue(ptr), - name_(ptr->name_), + sname_(ptr->sname_), arguments_(ptr->arguments_), func_(ptr->func_), via_call_(ptr->via_call_), @@ -1460,53 +1475,11 @@ namespace Sass { return false; } - virtual bool operator==(const Expression& rhs) const - { - try - { - Function_Call_Ptr_Const m = Cast(&rhs); - if (!(m && name() == m->name())) return false; - if (!(m && arguments()->length() == m->arguments()->length())) return false; - for (size_t i =0, L = arguments()->length(); i < L; ++i) - if (!(*(*arguments())[i] == *(*m->arguments())[i])) return false; - return true; - } - catch (std::bad_cast&) - { - return false; - } - catch (...) { throw; } - } + virtual bool operator==(const Expression& rhs) const; - virtual size_t hash() - { - if (hash_ == 0) { - hash_ = std::hash()(name()); - for (auto argument : arguments()->elements()) - hash_combine(hash_, argument->hash()); - } - return hash_; - } - ATTACH_AST_OPERATIONS(Function_Call) - ATTACH_CRTP_PERFORM_METHODS() - }; + virtual size_t hash(); - ///////////////////////// - // Function call schemas. - ///////////////////////// - class Function_Call_Schema : public Expression { - ADD_PROPERTY(String_Obj, name) - ADD_PROPERTY(Arguments_Obj, arguments) - public: - Function_Call_Schema(ParserState pstate, String_Obj n, Arguments_Obj args) - : Expression(pstate), name_(n), arguments_(args) - { concrete_type(STRING); } - Function_Call_Schema(const Function_Call_Schema* ptr) - : Expression(ptr), - name_(ptr->name_), - arguments_(ptr->arguments_) - { concrete_type(STRING); } - ATTACH_AST_OPERATIONS(Function_Call_Schema) + ATTACH_AST_OPERATIONS(Function_Call) ATTACH_CRTP_PERFORM_METHODS() }; diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index e4037865f..6176233b9 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -149,9 +149,6 @@ namespace Sass { class Function_Call; typedef Function_Call* Function_Call_Ptr; typedef Function_Call const* Function_Call_Ptr_Const; - class Function_Call_Schema; - typedef Function_Call_Schema* Function_Call_Schema_Ptr; - typedef Function_Call_Schema const* Function_Call_Schema_Ptr_Const; class Custom_Warning; typedef Custom_Warning* Custom_Warning_Ptr; typedef Custom_Warning const* Custom_Warning_Ptr_Const; @@ -319,7 +316,6 @@ namespace Sass { IMPL_MEM_OBJ(Binary_Expression); IMPL_MEM_OBJ(Unary_Expression); IMPL_MEM_OBJ(Function_Call); - IMPL_MEM_OBJ(Function_Call_Schema); IMPL_MEM_OBJ(Custom_Warning); IMPL_MEM_OBJ(Custom_Error); IMPL_MEM_OBJ(Variable); diff --git a/src/debugger.hpp b/src/debugger.hpp index ee0d6eba7..40186140e 100644 --- a/src/debugger.hpp +++ b/src/debugger.hpp @@ -497,14 +497,6 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) std::cerr << " [" << expression->name() << "]" << std::endl; std::string name(expression->name()); if (env && env->has(name)) debug_ast(Cast((*env)[name]), ind + " -> ", env); - } else if (Cast(node)) { - Function_Call_Schema_Ptr expression = Cast(node); - std::cerr << ind << "Function_Call_Schema " << expression; - std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; - std::cerr << " (" << pstate_source_position(node) << ")"; - std::cerr << "" << std::endl; - debug_ast(expression->name(), ind + "name: ", env); - debug_ast(expression->arguments(), ind + " args: ", env); } else if (Cast(node)) { Function_Call_Ptr expression = Cast(node); std::cerr << ind << "Function_Call " << expression; diff --git a/src/eval.cpp b/src/eval.cpp index 585b56d6a..c5f514fd9 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -931,8 +931,18 @@ namespace Sass { stm << "Stack depth exceeded max of " << Constants::MaxCallStack; error(stm.str(), c->pstate(), traces); } + + if (Cast(c->sname())) { + Expression_Ptr evaluated_name = c->sname()->perform(this); + Expression_Ptr evaluated_args = c->arguments()->perform(this); + std::string str(evaluated_name->to_string()); + str += evaluated_args->to_string(); + return SASS_MEMORY_NEW(String_Constant, c->pstate(), str); + } + std::string name(Util::normalize_underscores(c->name())); std::string full_name(name + "[f]"); + // we make a clone here, need to implement that further Arguments_Obj args = c->arguments(); @@ -1090,16 +1100,6 @@ namespace Sass { return result.detach(); } - Expression_Ptr Eval::operator()(Function_Call_Schema_Ptr s) - { - Expression_Ptr evaluated_name = s->name()->perform(this); - Expression_Ptr evaluated_args = s->arguments()->perform(this); - String_Schema_Obj ss = SASS_MEMORY_NEW(String_Schema, s->pstate(), 2); - ss->append(evaluated_name); - ss->append(evaluated_args); - return ss->perform(this); - } - Expression_Ptr Eval::operator()(Variable_Ptr v) { Expression_Obj value = 0; diff --git a/src/eval.hpp b/src/eval.hpp index a0cb97aae..76bbb91e9 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -48,7 +48,6 @@ namespace Sass { Expression_Ptr operator()(Binary_Expression_Ptr); Expression_Ptr operator()(Unary_Expression_Ptr); Expression_Ptr operator()(Function_Call_Ptr); - Expression_Ptr operator()(Function_Call_Schema_Ptr); Expression_Ptr operator()(Variable_Ptr); Expression_Ptr operator()(Number_Ptr); Expression_Ptr operator()(Color_Ptr); diff --git a/src/inspect.cpp b/src/inspect.cpp index c82ae0757..a83ed25a6 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -513,12 +513,6 @@ namespace Sass { call->arguments()->perform(this); } - void Inspect::operator()(Function_Call_Schema_Ptr call) - { - call->name()->perform(this); - call->arguments()->perform(this); - } - void Inspect::operator()(Variable_Ptr var) { append_token(var->name(), var); diff --git a/src/inspect.hpp b/src/inspect.hpp index 8f5e8af76..774290d3f 100644 --- a/src/inspect.hpp +++ b/src/inspect.hpp @@ -51,7 +51,6 @@ namespace Sass { virtual void operator()(Binary_Expression_Ptr); virtual void operator()(Unary_Expression_Ptr); virtual void operator()(Function_Call_Ptr); - virtual void operator()(Function_Call_Schema_Ptr); // virtual void operator()(Custom_Warning_Ptr); // virtual void operator()(Custom_Error_Ptr); virtual void operator()(Variable_Ptr); diff --git a/src/memory/SharedPtr.hpp b/src/memory/SharedPtr.hpp index f20dfa39b..7e13bf06c 100644 --- a/src/memory/SharedPtr.hpp +++ b/src/memory/SharedPtr.hpp @@ -78,6 +78,9 @@ namespace Sass { static void setTaint(bool val) { taint = val; } + + virtual const std::string to_string() const = 0; + virtual ~SharedObj(); long getRefCount() { return refcounter; @@ -169,6 +172,14 @@ namespace Sass { } return *this; } + + // allow implicit conversion to string + // relies on base class implementation + operator const std::string() const { + if (node) return node->to_string(); + else return std::string("[NULLPTR]"); + } + ~SharedImpl() {}; public: operator T*() const { diff --git a/src/operation.hpp b/src/operation.hpp index 02e604ac6..92bb44680 100644 --- a/src/operation.hpp +++ b/src/operation.hpp @@ -63,7 +63,6 @@ namespace Sass { virtual T operator()(Binary_Expression_Ptr x) = 0; virtual T operator()(Unary_Expression_Ptr x) = 0; virtual T operator()(Function_Call_Ptr x) = 0; - virtual T operator()(Function_Call_Schema_Ptr x) = 0; virtual T operator()(Custom_Warning_Ptr x) = 0; virtual T operator()(Custom_Error_Ptr x) = 0; virtual T operator()(Variable_Ptr x) = 0; @@ -144,7 +143,6 @@ namespace Sass { T operator()(Binary_Expression_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Unary_Expression_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Function_Call_Ptr x) { return static_cast(this)->fallback(x); } - T operator()(Function_Call_Schema_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Custom_Warning_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Custom_Error_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Variable_Ptr x) { return static_cast(this)->fallback(x); } diff --git a/src/parser.cpp b/src/parser.cpp index 525f199d1..5b1fd81ed 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -2179,13 +2179,13 @@ namespace Sass { return SASS_MEMORY_NEW(Function_Call, call_pos, name, args); } - Function_Call_Schema_Obj Parser::parse_function_call_schema() + Function_Call_Obj Parser::parse_function_call_schema() { String_Obj name = parse_identifier_schema(); ParserState source_position_of_call = pstate; Arguments_Obj args = parse_arguments(); - return SASS_MEMORY_NEW(Function_Call_Schema, source_position_of_call, name, args); + return SASS_MEMORY_NEW(Function_Call, source_position_of_call, name, args); } Content_Obj Parser::parse_content_directive() diff --git a/src/parser.hpp b/src/parser.hpp index 83c7f34ba..31bac8dd7 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -285,7 +285,7 @@ namespace Sass { Expression_Obj parse_value(); Function_Call_Obj parse_calc_function(); Function_Call_Obj parse_function_call(); - Function_Call_Schema_Obj parse_function_call_schema(); + Function_Call_Obj parse_function_call_schema(); String_Obj parse_url_function_string(); String_Obj parse_url_function_argument(); String_Obj parse_interpolated_chunk(Token, bool constant = false, bool css = true); From 4c34d16a4f475fa719d39831b9a89d3d6657e52f Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 04:27:18 +0100 Subject: [PATCH 18/30] Remove obsolete `in_selector` flag --- src/eval.cpp | 2 -- src/inspect.cpp | 9 --------- src/sass.hpp | 7 ++----- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/eval.cpp b/src/eval.cpp index c5f514fd9..17bc910cd 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1534,10 +1534,8 @@ namespace Sass { { LOCAL_FLAG(is_in_selector_schema, true); // the parser will look for a brace to end the selector - ctx.c_options.in_selector = true; // do not compress colors Expression_Obj sel = s->contents()->perform(this); std::string result_str(sel->to_string(ctx.c_options)); - ctx.c_options.in_selector = false; // flag temporary only result_str = unquote(Util::rtrim(result_str)); char* temp_cstr = sass_copy_c_string(result_str.c_str()); ctx.strings.push_back(temp_cstr); // attach to context diff --git a/src/inspect.cpp b/src/inspect.cpp index a83ed25a6..7510b19da 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -42,9 +42,7 @@ namespace Sass { void Inspect::operator()(Ruleset_Ptr ruleset) { if (ruleset->selector()) { - opt.in_selector = true; ruleset->selector()->perform(this); - opt.in_selector = false; } if (ruleset->block()) { ruleset->block()->perform(this); @@ -623,11 +621,6 @@ namespace Sass { // maybe an unknown token std::string name = c->disp(); - if (opt.in_selector && name != "") { - append_token(name, c); - return; - } - // resolved color std::string res_name = name; @@ -915,9 +908,7 @@ namespace Sass { void Inspect::operator()(Selector_Schema_Ptr s) { - opt.in_selector = true; s->contents()->perform(this); - opt.in_selector = false; } void Inspect::operator()(Parent_Selector_Ptr p) diff --git a/src/sass.hpp b/src/sass.hpp index 68f15f923..fdeface14 100644 --- a/src/sass.hpp +++ b/src/sass.hpp @@ -96,13 +96,10 @@ struct Sass_Inspect_Options { // Precision for fractional numbers int precision; - // Do not compress colors in selectors - bool in_selector; - // initialization list (constructor with defaults) Sass_Inspect_Options(Sass_Output_Style style = Sass::NESTED, - int precision = 5, bool in_selector = false) - : output_style(style), precision(precision), in_selector(in_selector) + int precision = 5) + : output_style(style), precision(precision) { } }; From bbfcf49332176a926ee86006ccae65c4705ce5d3 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 04:34:06 +0100 Subject: [PATCH 19/30] Add distinct `Parent_Reference` class for values --- src/ast.cpp | 5 +++-- src/ast.hpp | 18 ++++++++++++++++++ src/ast_fwd_decl.hpp | 5 +++++ src/debugger.hpp | 9 +++++++++ src/eval.cpp | 17 +++++++++++++++++ src/eval.hpp | 1 + src/operation.hpp | 2 ++ src/parser.cpp | 2 +- 8 files changed, 56 insertions(+), 3 deletions(-) diff --git a/src/ast.cpp b/src/ast.cpp index f03eb9ccc..357bd778d 100644 --- a/src/ast.cpp +++ b/src/ast.cpp @@ -1590,8 +1590,8 @@ namespace Sass { bool Selector_Schema::has_real_parent_ref() const { if (String_Schema_Obj schema = Cast(contents())) { - Parent_Selector_Obj p = Cast(schema->at(0)); - return schema->length() > 0 && p && p->is_real_parent_ref(); + if (schema->length() == 0) return false; + return Cast(schema->at(0)); } return false; } @@ -2188,6 +2188,7 @@ namespace Sass { IMPLEMENT_AST_OPERATORS(Color); IMPLEMENT_AST_OPERATORS(Null); IMPLEMENT_AST_OPERATORS(Parent_Selector); + IMPLEMENT_AST_OPERATORS(Parent_Reference); IMPLEMENT_AST_OPERATORS(Import); IMPLEMENT_AST_OPERATORS(Import_Stub); IMPLEMENT_AST_OPERATORS(Function_Call); diff --git a/src/ast.hpp b/src/ast.hpp index f7874b36e..7ea0557d0 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -2403,6 +2403,24 @@ namespace Sass { ATTACH_CRTP_PERFORM_METHODS() }; + ////////////////////////////////// + // The Parent Reference Expression. + ////////////////////////////////// + class Parent_Reference : public Value { + public: + Parent_Reference(ParserState pstate) + : Value(pstate) {} + Parent_Reference(const Parent_Reference* ptr) + : Value(ptr) {} + std::string type() const { return "parent"; } + static std::string type_name() { return "parent"; } + virtual bool operator==(const Expression& rhs) const { + return true; // can they ever be not equal? + }; + ATTACH_AST_OPERATIONS(Parent_Reference) + ATTACH_CRTP_PERFORM_METHODS() + }; + ///////////////////////////////////////////////////////////////////////// // Placeholder selectors (e.g., "%foo") for use in extend-only selectors. ///////////////////////////////////////////////////////////////////////// diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index 6176233b9..611995df9 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -30,6 +30,10 @@ namespace Sass { typedef Simple_Selector* Simple_Selector_Ptr; typedef Simple_Selector const* Simple_Selector_Ptr_Const; + class Parent_Reference; + typedef Parent_Reference* Parent_Reference_Ptr; + typedef Parent_Reference const* Parent_Reference_Ptr_Const; + class PreValue; typedef PreValue* PreValue_Ptr; typedef PreValue const* PreValue_Ptr_Const; @@ -336,6 +340,7 @@ namespace Sass { IMPL_MEM_OBJ(At_Root_Query); IMPL_MEM_OBJ(Null); IMPL_MEM_OBJ(Parent_Selector); + IMPL_MEM_OBJ(Parent_Reference); IMPL_MEM_OBJ(Parameter); IMPL_MEM_OBJ(Parameters); IMPL_MEM_OBJ(Argument); diff --git a/src/debugger.hpp b/src/debugger.hpp index 40186140e..e969ea38b 100644 --- a/src/debugger.hpp +++ b/src/debugger.hpp @@ -111,6 +111,15 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) // Expression_Ptr expression = Cast(node); // std::cerr << ind << "Expression " << expression << " " << expression->concrete_type() << std::endl; + } else if (Cast(node)) { + Parent_Reference_Ptr selector = Cast(node); + std::cerr << ind << "Parent_Reference " << selector; +// if (selector->not_selector()) cerr << " [in_declaration]"; + std::cerr << " (" << pstate_source_position(node) << ")"; + std::cerr << " <" << selector->hash() << ">"; + std::cerr << " <" << prettyprint(selector->pstate().token.ws_before()) << ">" << std::endl; +// debug_ast(selector->selector(), ind + "->", env); + } else if (Cast(node)) { Parent_Selector_Ptr selector = Cast(node); std::cerr << ind << "Parent_Selector " << selector; diff --git a/src/eval.cpp b/src/eval.cpp index 17bc910cd..83e8a2d64 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1173,6 +1173,11 @@ namespace Sass { // XXX: this is never hit via spec tests ex = ex->perform(this); } + // parent selector needs another go + if (Cast(ex)) { + // XXX: this is never hit via spec tests + ex = ex->perform(this); + } if (List_Ptr l = Cast(ex)) { List_Obj ll = SASS_MEMORY_NEW(List, l->pstate(), 0, l->separator()); @@ -1575,6 +1580,18 @@ namespace Sass { } } + Expression_Ptr Eval::operator()(Parent_Reference_Ptr p) + { + if (Selector_List_Obj pr = selector()) { + exp.selector_stack.pop_back(); + Selector_List_Obj rv = operator()(pr); + exp.selector_stack.push_back(rv); + return rv.detach(); + } else { + return SASS_MEMORY_NEW(Null, p->pstate()); + } + } + Simple_Selector_Ptr Eval::operator()(Simple_Selector_Ptr s) { return s; diff --git a/src/eval.hpp b/src/eval.hpp index 76bbb91e9..004ebe66c 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -86,6 +86,7 @@ namespace Sass { // actual evaluated selectors Selector_List_Ptr operator()(Selector_Schema_Ptr); Expression_Ptr operator()(Parent_Selector_Ptr); + Expression_Ptr operator()(Parent_Reference_Ptr); // generic fallback template diff --git a/src/operation.hpp b/src/operation.hpp index 92bb44680..415e52b3a 100644 --- a/src/operation.hpp +++ b/src/operation.hpp @@ -81,6 +81,7 @@ namespace Sass { virtual T operator()(Media_Query_Expression_Ptr x) = 0; virtual T operator()(At_Root_Query_Ptr x) = 0; virtual T operator()(Parent_Selector_Ptr x) = 0; + virtual T operator()(Parent_Reference_Ptr x) = 0; // parameters and arguments virtual T operator()(Parameter_Ptr x) = 0; virtual T operator()(Parameters_Ptr x) = 0; @@ -161,6 +162,7 @@ namespace Sass { T operator()(Media_Query_Expression_Ptr x) { return static_cast(this)->fallback(x); } T operator()(At_Root_Query_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Parent_Selector_Ptr x) { return static_cast(this)->fallback(x); } + T operator()(Parent_Reference_Ptr x) { return static_cast(this)->fallback(x); } // parameters and arguments T operator()(Parameter_Ptr x) { return static_cast(this)->fallback(x); } T operator()(Parameters_Ptr x) { return static_cast(this)->fallback(x); } diff --git a/src/parser.cpp b/src/parser.cpp index 5b1fd81ed..15b5cf9a1 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1637,7 +1637,7 @@ namespace Sass { if (match< ampersand >()) { warning("In Sass, \"&&\" means two copies of the parent selector. You probably want to use \"and\" instead.", pstate); } - return SASS_MEMORY_NEW(Parent_Selector, pstate); } + return SASS_MEMORY_NEW(Parent_Reference, pstate); } if (lex< kwd_important >()) { return SASS_MEMORY_NEW(String_Constant, pstate, "!important"); } From 72e9a04e9321f916a036af72bf5fdd2bda2bfc59 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 04:54:43 +0100 Subject: [PATCH 20/30] Fix parsing of colors (remove dynamic cast on eval) --- src/eval.cpp | 15 --------------- src/inspect.cpp | 3 +++ src/parser.cpp | 24 ++++++++++++++++++------ src/parser.hpp | 8 +++++--- 4 files changed, 26 insertions(+), 24 deletions(-) diff --git a/src/eval.cpp b/src/eval.cpp index 83e8a2d64..4985e5210 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -600,10 +600,6 @@ namespace Sass { switch (op_type) { case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false; case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true; - case Sass_OP::LT: return *l_n < *r_c ? bool_true : bool_false; - case Sass_OP::GTE: return *l_n < *r_c ? bool_false : bool_true; - case Sass_OP::LTE: return *l_n < *r_c || *l_n == *r_c ? bool_true : bool_false; - case Sass_OP::GT: return *l_n < *r_c || *l_n == *r_c ? bool_false : bool_true; case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: return Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, b_in->pstate()); default: break; @@ -644,10 +640,6 @@ namespace Sass { switch (op_type) { case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false; case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true; - case Sass_OP::LT: return *l_c < *r_n ? bool_true : bool_false; - case Sass_OP::GTE: return *l_c < *r_n ? bool_false : bool_true; - case Sass_OP::LTE: return *l_c < *r_n || *l_c == *r_n ? bool_true : bool_false; - case Sass_OP::GT: return *l_c < *r_n || *l_c == *r_n ? bool_false : bool_true; case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: return Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, b_in->pstate()); default: break; @@ -1271,13 +1263,6 @@ namespace Sass { Expression_Ptr Eval::operator()(String_Constant_Ptr s) { - if (!s->is_delayed() && name_to_color(s->value())) { - Color_Ptr c = SASS_MEMORY_COPY(name_to_color(s->value())); // copy - c->pstate(s->pstate()); - c->disp(s->value()); - c->is_delayed(true); - return c; - } return s; } diff --git a/src/inspect.cpp b/src/inspect.cpp index 7510b19da..4aeb82436 100644 --- a/src/inspect.cpp +++ b/src/inspect.cpp @@ -645,6 +645,9 @@ namespace Sass { } std::stringstream hexlet; + // dart sass compressed all colors in regular css always + // ruby sass and libsass does it only when not delayed + // since color math is going to be removed, this can go too bool compressed = opt.output_style == COMPRESSED; hexlet << '#' << std::setw(1) << std::setfill('0'); // create a short color hexlet if there is any need for it diff --git a/src/parser.cpp b/src/parser.cpp index 15b5cf9a1..1b7dac6ac 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -1578,7 +1578,7 @@ namespace Sass { return nr; } - Expression_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed) + Value_Ptr Parser::lexed_hex_color(const ParserState& pstate, const std::string& parsed) { Color_Ptr color = NULL; if (parsed[0] != '#') { @@ -1628,6 +1628,19 @@ namespace Sass { return color; } + Value_Ptr Parser::color_or_string(const std::string& lexed) const + { + if (auto color = name_to_color(lexed)) { + auto c = SASS_MEMORY_NEW(Color, color); + c->is_delayed(true); + c->pstate(pstate); + c->disp(lexed); + return c; + } else { + return SASS_MEMORY_NEW(String_Constant, pstate, lexed); + } + } + // parse one value for a list Expression_Obj Parser::parse_value() { @@ -1670,7 +1683,7 @@ namespace Sass { { return SASS_MEMORY_NEW(Null, pstate); } if (lex< identifier >()) { - return SASS_MEMORY_NEW(String_Constant, pstate, lexed); + return color_or_string(lexed); } if (lex< percentage >()) @@ -1841,7 +1854,7 @@ namespace Sass { return schema->length() > 0 ? schema.detach() : NULL; } - String_Constant_Obj Parser::parse_static_value() + Value_Obj Parser::parse_static_value() { lex< static_value >(); Token str(lexed); @@ -1852,8 +1865,7 @@ namespace Sass { --str.end; --position; - String_Constant_Ptr str_node = SASS_MEMORY_NEW(String_Constant, pstate, str.time_wspace()); - return str_node; + return color_or_string(str.time_wspace());; } String_Obj Parser::parse_string() @@ -1986,7 +1998,7 @@ namespace Sass { } if (peek < exactly < '-' > >()) break; } - else if (lex< sequence < identifier > >()) { + else if (lex< identifier >()) { schema->append(SASS_MEMORY_NEW(String_Constant, pstate, lexed)); if ((*position == '"' || *position == '\'') || peek < alternatives < alpha > >()) { // need_space = true; diff --git a/src/parser.hpp b/src/parser.hpp index 31bac8dd7..e8f331f69 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -290,7 +290,7 @@ namespace Sass { String_Obj parse_url_function_argument(); String_Obj parse_interpolated_chunk(Token, bool constant = false, bool css = true); String_Obj parse_string(); - String_Constant_Obj parse_static_value(); + Value_Obj parse_static_value(); String_Schema_Obj parse_css_variable_value(bool top_level = true); String_Schema_Obj parse_css_variable_value_token(bool top_level = true); String_Obj parse_ie_property(); @@ -325,6 +325,8 @@ namespace Sass { Error_Obj parse_error(); Debug_Obj parse_debug(); + Value_Ptr color_or_string(const std::string& lexed) const; + // be more like ruby sass Expression_Obj lex_almost_any_value_token(); Expression_Obj lex_almost_any_value_chars(); @@ -380,12 +382,12 @@ namespace Sass { static Number_Ptr lexed_number(const ParserState& pstate, const std::string& parsed); static Number_Ptr lexed_dimension(const ParserState& pstate, const std::string& parsed); static Number_Ptr lexed_percentage(const ParserState& pstate, const std::string& parsed); - static Expression_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed); + static Value_Ptr lexed_hex_color(const ParserState& pstate, const std::string& parsed); private: Number_Ptr lexed_number(const std::string& parsed) { return lexed_number(pstate, parsed); }; Number_Ptr lexed_dimension(const std::string& parsed) { return lexed_dimension(pstate, parsed); }; Number_Ptr lexed_percentage(const std::string& parsed) { return lexed_percentage(pstate, parsed); }; - Expression_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); }; + Value_Ptr lexed_hex_color(const std::string& parsed) { return lexed_hex_color(pstate, parsed); }; static const char* re_attr_sensitive_close(const char* src); static const char* re_attr_insensitive_close(const char* src); From 025dc4eb80f47b6344f90934a540a4019f8c2943 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 06:08:30 +0100 Subject: [PATCH 21/30] Pass traces instead of full context to bind --- src/bind.cpp | 24 ++++++++++++------------ src/bind.hpp | 3 ++- src/eval.cpp | 4 ++-- src/expand.cpp | 2 +- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/src/bind.cpp b/src/bind.cpp index fdae1fea6..c6ad88bd8 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -10,7 +10,7 @@ namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Env* env, Eval* eval) + void bind(std::string type, std::string name, Parameters_Obj ps, Arguments_Obj as, Env* env, Eval* eval, Backtraces& traces) { std::string callee(type + " " + name); @@ -54,7 +54,7 @@ namespace Sass { std::stringstream msg; msg << "wrong number of arguments (" << LA << " for " << LP << ")"; msg << " for `" << name << "'"; - return error(msg.str(), as->pstate(), eval->exp.traces); + return error(msg.str(), as->pstate(), traces); } Parameter_Obj p = ps->at(ip); @@ -107,8 +107,8 @@ namespace Sass { false, false)); } else { - eval->exp.traces.push_back(Backtrace(key->pstate())); - throw Exception::InvalidVarKwdType(key->pstate(), eval->exp.traces, key->inspect(), a); + traces.push_back(Backtrace(key->pstate())); + throw Exception::InvalidVarKwdType(key->pstate(), traces, key->inspect(), a); } } @@ -222,15 +222,15 @@ namespace Sass { for (auto key : argmap->keys()) { String_Constant_Ptr val = Cast(key); if (val == NULL) { - eval->exp.traces.push_back(Backtrace(key->pstate())); - throw Exception::InvalidVarKwdType(key->pstate(), eval->exp.traces, key->inspect(), a); + traces.push_back(Backtrace(key->pstate())); + throw Exception::InvalidVarKwdType(key->pstate(), traces, key->inspect(), a); } std::string param = "$" + unquote(val->value()); if (!param_map.count(param)) { std::stringstream msg; msg << callee << " has no parameter named " << param; - error(msg.str(), a->pstate(), eval->exp.traces); + error(msg.str(), a->pstate(), traces); } env->local_frame()[param] = argmap->at(key); } @@ -245,7 +245,7 @@ namespace Sass { std::stringstream msg; msg << "parameter " << p->name() << " provided more than once in call to " << callee; - error(msg.str(), a->pstate(), eval->exp.traces); + error(msg.str(), a->pstate(), traces); } // ordinal arg -- bind it to the next param env->local_frame()[p->name()] = a->value(); @@ -259,7 +259,7 @@ namespace Sass { } else { std::stringstream msg; msg << callee << " has no parameter named " << a->name(); - error(msg.str(), a->pstate(), eval->exp.traces); + error(msg.str(), a->pstate(), traces); } } if (param_map[a->name()]) { @@ -267,14 +267,14 @@ namespace Sass { std::stringstream msg; msg << "argument " << a->name() << " of " << callee << "cannot be used as named argument"; - error(msg.str(), a->pstate(), eval->exp.traces); + error(msg.str(), a->pstate(), traces); } } if (env->has_local(a->name())) { std::stringstream msg; msg << "parameter " << p->name() << "provided more than once in call to " << callee; - error(msg.str(), a->pstate(), eval->exp.traces); + error(msg.str(), a->pstate(), traces); } env->local_frame()[a->name()] = a->value(); } @@ -299,7 +299,7 @@ namespace Sass { } else { // param is unbound and has no default value -- error - throw Exception::MissingArgument(as->pstate(), eval->exp.traces, name, leftover->name(), type); + throw Exception::MissingArgument(as->pstate(), traces, name, leftover->name(), type); } } } diff --git a/src/bind.hpp b/src/bind.hpp index 9e9e0ec4e..7ad87f8f8 100644 --- a/src/bind.hpp +++ b/src/bind.hpp @@ -2,12 +2,13 @@ #define SASS_BIND_H #include +#include "backtrace.hpp" #include "environment.hpp" #include "ast_fwd_decl.hpp" namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Env*, Eval*); + void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Env*, Eval*, Backtraces traces); } #endif diff --git a/src/eval.cpp b/src/eval.cpp index 4985e5210..77f948004 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -1005,7 +1005,7 @@ namespace Sass { exp.env_stack.push_back(&fn_env); if (func || body) { - bind(std::string("Function"), c->name(), params, args, &fn_env, this); + bind(std::string("Function"), c->name(), params, args, &fn_env, this, traces); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); ctx.callee_stack.push_back({ @@ -1045,7 +1045,7 @@ namespace Sass { // populates env with default values for params std::string ff(c->name()); - bind(std::string("Function"), c->name(), params, args, &fn_env, this); + bind(std::string("Function"), c->name(), params, args, &fn_env, this, traces); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); ctx.callee_stack.push_back({ diff --git a/src/expand.cpp b/src/expand.cpp index 1987c4907..3ff8b728d 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -740,7 +740,7 @@ namespace Sass { new_env.local_frame()["@content[m]"] = thunk; } - bind(std::string("Mixin"), c->name(), params, args, &new_env, &eval); + bind(std::string("Mixin"), c->name(), params, args, &new_env, &eval, traces); Block_Obj trace_block = SASS_MEMORY_NEW(Block, c->pstate()); Trace_Obj trace = SASS_MEMORY_NEW(Trace, c->pstate(), c->name(), trace_block); From 0c5e27ceb34cf2ac1442d0a0338057ae4d3dc7ec Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 06:09:13 +0100 Subject: [PATCH 22/30] Clean up `get_arg_m` in `fn_utils` --- src/bind.cpp | 1 + src/bind.hpp | 3 ++- src/fn_utils.cpp | 18 +++++++----------- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/bind.cpp b/src/bind.cpp index c6ad88bd8..1874667a8 100644 --- a/src/bind.cpp +++ b/src/bind.cpp @@ -1,6 +1,7 @@ #include "sass.hpp" #include "bind.hpp" #include "ast.hpp" +#include "backtrace.hpp" #include "context.hpp" #include "expand.hpp" #include "eval.hpp" diff --git a/src/bind.hpp b/src/bind.hpp index 7ad87f8f8..57bcd01f9 100644 --- a/src/bind.hpp +++ b/src/bind.hpp @@ -8,7 +8,8 @@ namespace Sass { - void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Env*, Eval*, Backtraces traces); + void bind(std::string type, std::string name, Parameters_Obj, Arguments_Obj, Env*, Eval*, Backtraces& traces); + } #endif diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp index b4986037e..7480f030f 100644 --- a/src/fn_utils.cpp +++ b/src/fn_utils.cpp @@ -53,21 +53,17 @@ namespace Sass { Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) { - // Minimal error handling -- the expectation is that built-ins will be written correctly! - Map_Ptr val = Cast(env[argname]); - if (val) return val; - - List_Ptr lval = Cast(env[argname]); - if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0); - - // fallback on get_arg for error handling - val = get_arg(argname, env, sig, pstate, traces); - return val; + AST_Node_Ptr value = env[argname]; + if (Map_Ptr map = Cast(value)) return map; + List_Ptr list = Cast(value); + if (list && list->length() == 0) { + return SASS_MEMORY_NEW(Map, pstate, 0); + } + return get_arg(argname, env, sig, pstate, traces); } double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi) { - // Minimal error handling -- the expectation is that built-ins will be written correctly! Number_Ptr val = get_arg(argname, env, sig, pstate, traces); Number tmpnr(val); tmpnr.reduce(); From 37e15bb71fc54c99725f8f2582f9681e03b4bb0f Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 06:23:28 +0100 Subject: [PATCH 23/30] Change `String_Schema` to only hold `PreValue` objects The API does not guarantee yet that everything stored in `String_Schema` is a Value, although it doesn't make much sense to allow anything else and as it turns out we don't! Use steamroller tactics to ensure we don't store anything else after evaluation from Binary_Expression. --- src/ast.hpp | 6 +++--- src/eval.cpp | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index 7ea0557d0..be9dc0e34 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -1703,16 +1703,16 @@ namespace Sass { // Interpolated strings. Meant to be reduced to flat strings during the // evaluation phase. /////////////////////////////////////////////////////////////////////// - class String_Schema : public String, public Vectorized { + class String_Schema : public String, public Vectorized { ADD_PROPERTY(bool, css) size_t hash_; public: String_Schema(ParserState pstate, size_t size = 0, bool css = true) - : String(pstate), Vectorized(size), css_(css), hash_(0) + : String(pstate), Vectorized(size), css_(css), hash_(0) { concrete_type(STRING); } String_Schema(const String_Schema* ptr) : String(ptr), - Vectorized(*ptr), + Vectorized(*ptr), css_(ptr->css_), hash_(ptr->hash_) { concrete_type(STRING); } diff --git a/src/eval.cpp b/src/eval.cpp index 77f948004..0b09ede23 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -663,9 +663,9 @@ namespace Sass { b->op(), s_l->last(), b->right()); bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // unverified for (size_t i = 0; i < s_l->length() - 1; ++i) { - ret_schema->append(s_l->at(i)->perform(this)); + ret_schema->append(Cast(s_l->at(i)->perform(this))); } - ret_schema->append(bin_ex->perform(this)); + ret_schema->append(Cast(bin_ex->perform(this))); return ret_schema->perform(this); } } @@ -676,9 +676,9 @@ namespace Sass { Binary_Expression_Obj bin_ex = SASS_MEMORY_NEW(Binary_Expression, b->pstate(), b->op(), b->left(), s_r->first()); bin_ex->is_delayed(b->left()->is_delayed() || b->right()->is_delayed()); // verified - ret_schema->append(bin_ex->perform(this)); + ret_schema->append(Cast(bin_ex->perform(this))); for (size_t i = 1; i < s_r->length(); ++i) { - ret_schema->append(s_r->at(i)->perform(this)); + ret_schema->append(Cast(s_r->at(i)->perform(this))); } return ret_schema->perform(this); } From d0b6338f630690c1c695df28752b83ebe64cd0d9 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 06:49:50 +0100 Subject: [PATCH 24/30] Clean up function macros and force to return PreValues --- src/ast.hpp | 3 +-- src/ast_fwd_decl.hpp | 1 - src/fn_miscs.cpp | 2 +- src/fn_utils.hpp | 17 ++++++++++++----- 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index be9dc0e34..5dd26f79c 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -27,6 +27,7 @@ #include "ast_def_macros.hpp" #include "ast_fwd_decl.hpp" #include "source_map.hpp" +#include "fn_utils.hpp" #include "sass.h" @@ -913,8 +914,6 @@ namespace Sass { // Definitions for both mixins and functions. The two cases are distinguished // by a type tag. ///////////////////////////////////////////////////////////////////////////// - struct Backtrace; - typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); class Definition : public Has_Block { public: enum Type { MIXIN, FUNCTION }; diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index 611995df9..26b330e09 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -426,7 +426,6 @@ namespace Sass { typedef std::vector SelectorStack; typedef std::vector ImporterStack; - typedef const char* Signature; // only to switch implementations for testing #define environment_map std::map diff --git a/src/fn_miscs.cpp b/src/fn_miscs.cpp index 70bbd403d..938e3f153 100644 --- a/src/fn_miscs.cpp +++ b/src/fn_miscs.cpp @@ -146,7 +146,7 @@ namespace Sass { Expand expand(ctx, &d_env, &selector_stack); func->via_call(true); // calc invoke is allowed if (ff) func->func(ff); - return func->perform(&expand.eval); + return Cast(func->perform(&expand.eval)); } //////////////////// diff --git a/src/fn_utils.hpp b/src/fn_utils.hpp index 4d00d904c..0ff39d8cf 100644 --- a/src/fn_utils.hpp +++ b/src/fn_utils.hpp @@ -8,16 +8,23 @@ namespace Sass { - #define BUILT_IN(name) Expression_Ptr \ - name(Env& env, Env& d_env, Context& ctx, Signature sig, ParserState pstate, Backtraces traces, SelectorStack selector_stack) + #define FN_PROTOTYPE \ + Env& env, \ + Env& d_env, \ + Context& ctx, \ + Signature sig, \ + ParserState pstate, \ + Backtraces& traces, \ + SelectorStack& selector_stack + + typedef const char* Signature; + typedef PreValue_Ptr (*Native_Function)(FN_PROTOTYPE); + #define BUILT_IN(name) PreValue_Ptr name(FN_PROTOTYPE) #define ARG(argname, argtype) get_arg(argname, env, sig, pstate, traces) - // special function for weird hsla percent (10px == 10% == 10 != 0.1) #define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double - typedef Expression_Ptr (*Native_Function)(Env&, Env&, Context&, Signature, ParserState, Backtraces, SelectorStack); - Definition_Ptr make_native_function(Signature, Native_Function, Context& ctx); Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx); From e0321a08f9468633a0177320b46df97a2646ad8a Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 07:33:33 +0100 Subject: [PATCH 25/30] Enhance stacktrace to report column numbers --- src/backtrace.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backtrace.cpp b/src/backtrace.cpp index 8da963a72..b9ee1dff1 100644 --- a/src/backtrace.cpp +++ b/src/backtrace.cpp @@ -24,6 +24,8 @@ namespace Sass { ss << indent; ss << "on line "; ss << trace.pstate.line + 1; + ss << ":"; + ss << trace.pstate.column + 1; ss << " of " << rel_path; // ss << trace.caller; first = false; @@ -33,6 +35,8 @@ namespace Sass { ss << indent; ss << "from line "; ss << trace.pstate.line + 1; + ss << ":"; + ss << trace.pstate.column + 1; ss << " of " << rel_path; } From 6e79ff7a34f59c1ef57d015e441f97557527ae16 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 07:34:37 +0100 Subject: [PATCH 26/30] Add display name for color to debugger --- src/debugger.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/debugger.hpp b/src/debugger.hpp index e969ea38b..b256c0da9 100644 --- a/src/debugger.hpp +++ b/src/debugger.hpp @@ -621,6 +621,7 @@ inline void debug_ast(AST_Node_Ptr node, std::string ind, Env* env) Color_Ptr expression = Cast(node); std::cerr << ind << "Color " << expression; std::cerr << " (" << pstate_source_position(node) << ")"; + std::cerr << " [name: " << expression->disp() << "] "; std::cerr << " [delayed: " << expression->is_delayed() << "] "; std::cerr << " [interpolant: " << expression->is_interpolant() << "] "; std::cerr << " [" << expression->r() << ":" << expression->g() << ":" << expression->b() << "@" << expression->a() << "]" << std::endl; From 090bab35446cddd31f492dd5785b791e88877fa9 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 07:36:00 +0100 Subject: [PATCH 27/30] Add get method for environment class --- src/environment.cpp | 14 ++++++++++++++ src/environment.hpp | 5 +++++ 2 files changed, 19 insertions(+) diff --git a/src/environment.cpp b/src/environment.cpp index e382e7e05..dccda1de8 100644 --- a/src/environment.cpp +++ b/src/environment.cpp @@ -206,6 +206,20 @@ namespace Sass { } }; + // use array access for getter and setter functions + template + T& Environment::get(const std::string& key) + { + auto cur = this; + while (cur) { + if (cur->has_local(key)) { + return cur->get_local(key); + } + cur = cur->parent_; + } + return get_local(key); + } + // use array access for getter and setter functions template T& Environment::operator[](const std::string& key) diff --git a/src/environment.hpp b/src/environment.hpp index a6939be23..a48839aa7 100644 --- a/src/environment.hpp +++ b/src/environment.hpp @@ -7,6 +7,7 @@ namespace Sass { + // this defeats the whole purpose of environment being templatable!! typedef environment_map::iterator EnvIter; class EnvResult { @@ -92,6 +93,10 @@ namespace Sass { // include all scopes available bool has(const std::string& key) const; + // look on the full stack for key + // include all scopes available + T& get(const std::string& key); + // look on the full stack for key // include all scopes available EnvResult find(const std::string& key); From 8f0bdc79c16ba873958a1c164e732dbda5045401 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 07:38:49 +0100 Subject: [PATCH 28/30] Remove obsolete function constructor arguments --- src/ast.hpp | 4 +--- src/expand.cpp | 12 ++++++------ src/expand.hpp | 6 +++--- src/fn_utils.cpp | 3 +-- 4 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/ast.hpp b/src/ast.hpp index 5dd26f79c..8f247f8cc 100644 --- a/src/ast.hpp +++ b/src/ast.hpp @@ -977,9 +977,7 @@ namespace Sass { Signature sig, std::string n, Parameters_Obj params, - Sass_Function_Entry c_func, - bool whatever, - bool whatever2) + Sass_Function_Entry c_func) : Has_Block(pstate, 0), name_(n), parameters_(params), diff --git a/src/expand.cpp b/src/expand.cpp index 3ff8b728d..0e2c22e17 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -28,7 +28,7 @@ namespace Sass { block_stack(BlockStack()), call_stack(CallStack()), selector_stack(SelectorStack()), - media_block_stack(MediaStack()) + media_stack(MediaStack()) { env_stack.push_back(0); env_stack.push_back(env); @@ -36,7 +36,7 @@ namespace Sass { call_stack.push_back(0); if (stack == NULL) { selector_stack.push_back(0); } else { selector_stack.insert(selector_stack.end(), stack->begin(), stack->end()); } - media_block_stack.push_back(0); + media_stack.push_back(0); } Env* Expand::environment() @@ -139,7 +139,7 @@ namespace Sass { if (block_stack.back()->is_root()) { env_stack.push_back(&env); } - sel->set_media_block(media_block_stack.back()); + sel->set_media_block(media_stack.back()); Block_Obj blk = 0; if (r->block()) blk = operator()(r->block()); Ruleset_Ptr rr = SASS_MEMORY_NEW(Ruleset, @@ -183,13 +183,13 @@ namespace Sass { Parser p(Parser::from_c_str(str, ctx, traces, mq->pstate())); mq = p.parse_media_queries(); // re-assign now cpy->media_queries(mq); - media_block_stack.push_back(cpy); + media_stack.push_back(cpy); Block_Obj blk = operator()(m->block()); Media_Block_Ptr mm = SASS_MEMORY_NEW(Media_Block, m->pstate(), mq, blk); - media_block_stack.pop_back(); + media_stack.pop_back(); mm->tabs(m->tabs()); return mm; } @@ -658,7 +658,7 @@ namespace Sass { } for (Complex_Selector_Obj cs : sl->elements()) { if (!cs.isNull() && !cs->head().isNull()) { - cs->head()->media_block(media_block_stack.back()); + cs->head()->media_block(media_stack.back()); } } selector_stack.push_back(0); diff --git a/src/expand.hpp b/src/expand.hpp index d88305e09..401843b67 100644 --- a/src/expand.hpp +++ b/src/expand.hpp @@ -31,10 +31,10 @@ namespace Sass { // it's easier to work with vectors std::vector env_stack; - BlockStack block_stack; - CallStack call_stack; + BlockStack block_stack; + CallStack call_stack; SelectorStack selector_stack; - MediaStack media_block_stack; + MediaStack media_stack; Boolean_Obj bool_true; diff --git a/src/fn_utils.cpp b/src/fn_utils.cpp index 7480f030f..2c86852b0 100644 --- a/src/fn_utils.cpp +++ b/src/fn_utils.cpp @@ -39,8 +39,7 @@ namespace Sass { sig, name, params, - c_func, - false, true); + c_func); } namespace Functions { From 09b36b03b807401b16e9cb48acb30def934bb416 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 07:56:22 +0100 Subject: [PATCH 29/30] Add EnvStack typedef --- src/environment.hpp | 1 + src/expand.cpp | 2 +- src/expand.hpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/environment.hpp b/src/environment.hpp index a48839aa7..08452ea32 100644 --- a/src/environment.hpp +++ b/src/environment.hpp @@ -112,6 +112,7 @@ namespace Sass { // define typedef for our use case typedef Environment Env; + typedef std::vector EnvStack; } diff --git a/src/expand.cpp b/src/expand.cpp index 0e2c22e17..9731d80fa 100644 --- a/src/expand.cpp +++ b/src/expand.cpp @@ -24,7 +24,7 @@ namespace Sass { in_keyframes(false), at_root_without_rule(false), old_at_root_without_rule(false), - env_stack(std::vector()), + env_stack(EnvStack()), block_stack(BlockStack()), call_stack(CallStack()), selector_stack(SelectorStack()), diff --git a/src/expand.hpp b/src/expand.hpp index 401843b67..1c494194e 100644 --- a/src/expand.hpp +++ b/src/expand.hpp @@ -30,7 +30,7 @@ namespace Sass { bool old_at_root_without_rule; // it's easier to work with vectors - std::vector env_stack; + EnvStack env_stack; BlockStack block_stack; CallStack call_stack; SelectorStack selector_stack; From 5564ab3376a78ba7046c14b76ff2bef11ebec237 Mon Sep 17 00:00:00 2001 From: Marcel Greter Date: Sat, 17 Mar 2018 08:01:02 +0100 Subject: [PATCH 30/30] Replace direct references with methods Easier to replace the implementation and better visible on what APIs we are depending on. --- src/ast_fwd_decl.hpp | 1 + src/eval.cpp | 163 ++++++++++++++++++++++++++----------------- src/eval.hpp | 8 +++ 3 files changed, 108 insertions(+), 64 deletions(-) diff --git a/src/ast_fwd_decl.hpp b/src/ast_fwd_decl.hpp index 26b330e09..a084f3069 100644 --- a/src/ast_fwd_decl.hpp +++ b/src/ast_fwd_decl.hpp @@ -421,6 +421,7 @@ namespace Sass { typedef std::unordered_set SimpleSelectorDict; typedef std::vector BlockStack; + typedef std::vector CalleeStack; typedef std::vector CallStack; typedef std::vector MediaStack; typedef std::vector SelectorStack; diff --git a/src/eval.cpp b/src/eval.cpp index 0b09ede23..9c5cf4c63 100644 --- a/src/eval.cpp +++ b/src/eval.cpp @@ -48,11 +48,48 @@ namespace Sass { return exp.environment(); } + const std::string Eval::cwd() + { + return ctx.cwd(); + } + + struct Sass_Inspect_Options& Eval::options() + { + return ctx.c_options; + } + + struct Sass_Compiler* Eval::compiler() + { + return ctx.c_compiler; + } + + EnvStack& Eval::env_stack() + { + return exp.env_stack; + } + Selector_List_Obj Eval::selector() { return exp.selector(); } + std::vector& Eval::callee_stack() + { + return ctx.callee_stack; + } + + + SelectorStack& Eval::selector_stack() + { + return exp.selector_stack; + } + + bool& Eval::old_at_root_without_rule() + { + return exp.old_at_root_without_rule; + } + + Expression_Ptr Eval::operator()(Block_Ptr b) { Expression_Ptr val = 0; @@ -65,7 +102,7 @@ namespace Sass { Expression_Ptr Eval::operator()(Assignment_Ptr a) { - Env* env = exp.environment(); + Env* env = environment(); std::string var(a->variable()); if (a->is_global()) { if (a->is_default()) { @@ -127,8 +164,8 @@ namespace Sass { Expression_Ptr Eval::operator()(If_Ptr i) { Expression_Obj rv = 0; - Env env(exp.environment()); - exp.env_stack.push_back(&env); + Env env(environment()); + env_stack().push_back(&env); Expression_Obj cond = i->predicate()->perform(this); if (!cond->is_false()) { rv = i->block()->perform(this); @@ -137,7 +174,7 @@ namespace Sass { Block_Obj alt = i->alternative(); if (alt) rv = alt->perform(this); } - exp.env_stack.pop_back(); + env_stack().pop_back(); return rv.detach(); } @@ -169,7 +206,7 @@ namespace Sass { double end = sass_end->value(); // only create iterator once in this environment Env env(environment(), true); - exp.env_stack.push_back(&env); + env_stack().push_back(&env); Block_Obj body = f->block(); Expression_Ptr val = 0; if (start < end) { @@ -193,7 +230,7 @@ namespace Sass { if (val) break; } } - exp.env_stack.pop_back(); + env_stack().pop_back(); return val; } @@ -204,7 +241,7 @@ namespace Sass { std::vector variables(e->variables()); Expression_Obj expr = e->list()->perform(this); Env env(environment(), true); - exp.env_stack.push_back(&env); + env_stack().push_back(&env); List_Obj list = 0; Map_Ptr map = 0; if (expr->concrete_type() == Expression::MAP) { @@ -280,7 +317,7 @@ namespace Sass { if (val) break; } } - exp.env_stack.pop_back(); + env_stack().pop_back(); return val.detach(); } @@ -289,17 +326,17 @@ namespace Sass { Expression_Obj pred = w->predicate(); Block_Obj body = w->block(); Env env(environment(), true); - exp.env_stack.push_back(&env); + env_stack().push_back(&env); Expression_Obj cond = pred->perform(this); while (!cond->is_false()) { Expression_Obj val = body->perform(this); if (val) { - exp.env_stack.pop_back(); + env_stack().pop_back(); return val.detach(); } cond = pred->perform(this); } - exp.env_stack.pop_back(); + env_stack().pop_back(); return 0; } @@ -310,16 +347,16 @@ namespace Sass { Expression_Ptr Eval::operator()(Warning_Ptr w) { - Sass_Output_Style outstyle = ctx.c_options.output_style; - ctx.c_options.output_style = NESTED; + Sass_Output_Style outstyle = options().output_style; + options().output_style = NESTED; Expression_Obj message = w->message()->perform(this); - Env* env = exp.environment(); + Env* env = environment(); // try to use generic function if (env->has("@warn[f]")) { // add call stack entry - ctx.callee_stack.push_back({ + callee_stack().push_back({ "@warn", w->pstate().path, w->pstate().line + 1, @@ -337,9 +374,9 @@ namespace Sass { AST2C ast2c; union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); sass_list_set_value(c_args, 0, message->perform(&ast2c)); - union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); - ctx.c_options.output_style = outstyle; - ctx.callee_stack.pop_back(); + union Sass_Value* c_val = c_func(c_args, c_function, compiler()); + options().output_style = outstyle; + callee_stack().pop_back(); sass_delete_value(c_args); sass_delete_value(c_val); return 0; @@ -351,23 +388,23 @@ namespace Sass { traces.push_back(Backtrace(w->pstate())); std::cerr << traces_to_string(traces, " "); std::cerr << std::endl; - ctx.c_options.output_style = outstyle; + options().output_style = outstyle; traces.pop_back(); return 0; } Expression_Ptr Eval::operator()(Error_Ptr e) { - Sass_Output_Style outstyle = ctx.c_options.output_style; - ctx.c_options.output_style = NESTED; + Sass_Output_Style outstyle = options().output_style; + options().output_style = NESTED; Expression_Obj message = e->message()->perform(this); - Env* env = exp.environment(); + Env* env = environment(); // try to use generic function if (env->has("@error[f]")) { // add call stack entry - ctx.callee_stack.push_back({ + callee_stack().push_back({ "@error", e->pstate().path, e->pstate().line + 1, @@ -385,9 +422,9 @@ namespace Sass { AST2C ast2c; union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); sass_list_set_value(c_args, 0, message->perform(&ast2c)); - union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); - ctx.c_options.output_style = outstyle; - ctx.callee_stack.pop_back(); + union Sass_Value* c_val = c_func(c_args, c_function, compiler()); + options().output_style = outstyle; + callee_stack().pop_back(); sass_delete_value(c_args); sass_delete_value(c_val); return 0; @@ -395,23 +432,23 @@ namespace Sass { } std::string result(unquote(message->to_sass())); - ctx.c_options.output_style = outstyle; + options().output_style = outstyle; error(result, e->pstate(), traces); return 0; } Expression_Ptr Eval::operator()(Debug_Ptr d) { - Sass_Output_Style outstyle = ctx.c_options.output_style; - ctx.c_options.output_style = NESTED; + Sass_Output_Style outstyle = options().output_style; + options().output_style = NESTED; Expression_Obj message = d->value()->perform(this); - Env* env = exp.environment(); + Env* env = environment(); // try to use generic function if (env->has("@debug[f]")) { // add call stack entry - ctx.callee_stack.push_back({ + callee_stack().push_back({ "@debug", d->pstate().path, d->pstate().line + 1, @@ -429,21 +466,20 @@ namespace Sass { AST2C ast2c; union Sass_Value* c_args = sass_make_list(1, SASS_COMMA, false); sass_list_set_value(c_args, 0, message->perform(&ast2c)); - union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); - ctx.c_options.output_style = outstyle; - ctx.callee_stack.pop_back(); + union Sass_Value* c_val = c_func(c_args, c_function, compiler()); + options().output_style = outstyle; + callee_stack().pop_back(); sass_delete_value(c_args); sass_delete_value(c_val); return 0; } - std::string cwd(ctx.cwd()); std::string result(unquote(message->to_sass())); - std::string abs_path(Sass::File::rel2abs(d->pstate().path, cwd, cwd)); - std::string rel_path(Sass::File::abs2rel(d->pstate().path, cwd, cwd)); + std::string abs_path(Sass::File::rel2abs(d->pstate().path, cwd(), cwd())); + std::string rel_path(Sass::File::abs2rel(d->pstate().path, cwd(), cwd())); std::string output_path(Sass::File::path_for_console(rel_path, abs_path, d->pstate().path)); - ctx.c_options.output_style = outstyle; + options().output_style = outstyle; std::cerr << output_path << ":" << d->pstate().line+1 << " DEBUG: " << result; std::cerr << std::endl; @@ -584,7 +620,7 @@ namespace Sass { case Sass_OP::LTE: return *l_n < *r_n || *l_n == *r_n ? bool_true : bool_false; case Sass_OP::GT: return *l_n < *r_n || *l_n == *r_n ? bool_false : bool_true; case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: - return Operators::op_numbers(op_type, *l_n, *r_n, ctx.c_options, b_in->pstate()); + return Operators::op_numbers(op_type, *l_n, *r_n, options(), b_in->pstate()); default: break; } } @@ -601,7 +637,7 @@ namespace Sass { case Sass_OP::EQ: return *l_n == *r_c ? bool_true : bool_false; case Sass_OP::NEQ: return *l_n == *r_c ? bool_false : bool_true; case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: - return Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, b_in->pstate()); + return Operators::op_number_color(op_type, *l_n, *r_c, options(), b_in->pstate()); default: break; } } @@ -624,7 +660,7 @@ namespace Sass { case Sass_OP::LTE: return *l_c < *r_c || *l_c == *r_c ? bool_true : bool_false; case Sass_OP::GT: return *l_c < *r_c || *l_c == *r_c ? bool_false : bool_true; case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: - return Operators::op_colors(op_type, *l_c, *r_c, ctx.c_options, b_in->pstate()); + return Operators::op_colors(op_type, *l_c, *r_c, options(), b_in->pstate()); default: break; } } @@ -641,7 +677,7 @@ namespace Sass { case Sass_OP::EQ: return *l_c == *r_n ? bool_true : bool_false; case Sass_OP::NEQ: return *l_c == *r_n ? bool_false : bool_true; case Sass_OP::ADD: case Sass_OP::SUB: case Sass_OP::MUL: case Sass_OP::DIV: case Sass_OP::MOD: - return Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, b_in->pstate()); + return Operators::op_color_number(op_type, *l_c, *r_n, options(), b_in->pstate()); default: break; } } @@ -753,11 +789,11 @@ namespace Sass { if (force_delay) { std::string str(""); - str += v_l->to_string(ctx.c_options); + str += v_l->to_string(options()); if (b->op().ws_before) str += " "; str += b->separator(); if (b->op().ws_after) str += " "; - str += v_r->to_string(ctx.c_options); + str += v_r->to_string(options()); String_Constant_Ptr val = SASS_MEMORY_NEW(String_Constant, b->pstate(), str); val->is_interpolant(b->left()->has_interpolant()); return val; @@ -778,7 +814,6 @@ namespace Sass { } catch (Exception::OperationError& err) { - // throw Exception::Base(b->pstate(), err.what()); traces.push_back(Backtrace(b->pstate())); throw Exception::SassValueError(traces, b->pstate(), err); } @@ -795,22 +830,22 @@ namespace Sass { Number_Ptr l_n = Cast(lhs); Number_Ptr r_n = Cast(rhs); l_n->reduce(); r_n->reduce(); - rv = Operators::op_numbers(op_type, *l_n, *r_n, ctx.c_options, pstate); + rv = Operators::op_numbers(op_type, *l_n, *r_n, options(), pstate); } else if (l_type == Expression::NUMBER && r_type == Expression::COLOR) { Number_Ptr l_n = Cast(lhs); Color_Ptr r_c = Cast(rhs); - rv = Operators::op_number_color(op_type, *l_n, *r_c, ctx.c_options, pstate); + rv = Operators::op_number_color(op_type, *l_n, *r_c, options(), pstate); } else if (l_type == Expression::COLOR && r_type == Expression::NUMBER) { Color_Ptr l_c = Cast(lhs); Number_Ptr r_n = Cast(rhs); - rv = Operators::op_color_number(op_type, *l_c, *r_n, ctx.c_options, pstate); + rv = Operators::op_color_number(op_type, *l_c, *r_n, options(), pstate); } else if (l_type == Expression::COLOR && r_type == Expression::COLOR) { Color_Ptr l_c = Cast(lhs); Color_Ptr r_c = Cast(rhs); - rv = Operators::op_colors(op_type, *l_c, *r_c, ctx.c_options, pstate); + rv = Operators::op_colors(op_type, *l_c, *r_c, options(), pstate); } else { To_Value to_value(ctx); @@ -831,7 +866,7 @@ namespace Sass { traces.push_back(Backtrace(v_r->pstate())); throw Exception::InvalidValue(traces, *v_r); } - Value_Ptr ex = Operators::op_strings(b->op(), *v_l, *v_r, ctx.c_options, pstate, !interpolant); // pass true to compress + Value_Ptr ex = Operators::op_strings(b->op(), *v_l, *v_r, options(), pstate, !interpolant); // pass true to compress if (String_Constant_Ptr str = Cast(ex)) { if (str->concrete_type() == Expression::STRING) @@ -883,7 +918,7 @@ namespace Sass { return cpy.detach(); // return the copy } else if (u->optype() == Unary_Expression::SLASH) { - std::string str = '/' + nr->to_string(ctx.c_options); + std::string str = '/' + nr->to_string(options()); return SASS_MEMORY_NEW(String_Constant, u->pstate(), str); } // nothing for positive @@ -956,7 +991,7 @@ namespace Sass { } String_Quoted_Ptr str = SASS_MEMORY_NEW(String_Quoted, c->pstate(), - lit->to_string(ctx.c_options)); + lit->to_string(options())); str->is_interpolant(c->is_interpolant()); return str; } else { @@ -1002,13 +1037,13 @@ namespace Sass { Parameters_Obj params = def->parameters(); Env fn_env(def->environment()); - exp.env_stack.push_back(&fn_env); + env_stack().push_back(&fn_env); if (func || body) { bind(std::string("Function"), c->name(), params, args, &fn_env, this, traces); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); - ctx.callee_stack.push_back({ + callee_stack().push_back({ c->name().c_str(), c->pstate().path, c->pstate().line + 1, @@ -1027,7 +1062,7 @@ namespace Sass { if (!result) { error(std::string("Function ") + c->name() + " finished without @return", c->pstate(), traces); } - ctx.callee_stack.pop_back(); + callee_stack().pop_back(); traces.pop_back(); } @@ -1048,7 +1083,7 @@ namespace Sass { bind(std::string("Function"), c->name(), params, args, &fn_env, this, traces); std::string msg(", in function `" + c->name() + "`"); traces.push_back(Backtrace(c->pstate(), msg)); - ctx.callee_stack.push_back({ + callee_stack().push_back({ c->name().c_str(), c->pstate().path, c->pstate().line + 1, @@ -1066,7 +1101,7 @@ namespace Sass { Expression_Obj arg = Cast(node); sass_list_set_value(c_args, i, arg->perform(&ast2c)); } - union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_compiler); + union Sass_Value* c_val = c_func(c_args, c_function, compiler()); if (sass_value_get_tag(c_val) == SASS_ERROR) { error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), traces); } else if (sass_value_get_tag(c_val) == SASS_WARNING) { @@ -1074,7 +1109,7 @@ namespace Sass { } result = c2ast(c_val, traces, c->pstate()); - ctx.callee_stack.pop_back(); + callee_stack().pop_back(); traces.pop_back(); sass_delete_value(c_args); if (c_val != c_args) @@ -1088,7 +1123,7 @@ namespace Sass { result = result->perform(this); result->is_interpolant(c->is_interpolant()); - exp.env_stack.pop_back(); + env_stack().pop_back(); return result.detach(); } @@ -1185,12 +1220,12 @@ namespace Sass { // here. Normally single list items are already unwrapped. if (l->size() > 1) { // string_to_output would fail "#{'_\a' '_\a'}"; - std::string str(ll->to_string(ctx.c_options)); + std::string str(ll->to_string(options())); str = read_hex_escapes(str); // read escapes newline_to_space(str); // replace directly res += str; // append to result string } else { - res += (ll->to_string(ctx.c_options)); + res += (ll->to_string(options())); } ll->is_interpolant(l->is_interpolant()); } @@ -1205,9 +1240,9 @@ namespace Sass { else { // ex = ex->perform(this); if (into_quotes && ex->is_interpolant()) { - res += evacuate_escapes(ex ? ex->to_string(ctx.c_options) : ""); + res += evacuate_escapes(ex ? ex->to_string(options()) : ""); } else { - std::string str(ex ? ex->to_string(ctx.c_options) : ""); + std::string str(ex ? ex->to_string(options()) : ""); if (into_quotes) str = read_hex_escapes(str); res += str; // append to result string } @@ -1525,7 +1560,7 @@ namespace Sass { LOCAL_FLAG(is_in_selector_schema, true); // the parser will look for a brace to end the selector Expression_Obj sel = s->contents()->perform(this); - std::string result_str(sel->to_string(ctx.c_options)); + std::string result_str(sel->to_string(options())); result_str = unquote(Util::rtrim(result_str)); char* temp_cstr = sass_copy_c_string(result_str.c_str()); ctx.strings.push_back(temp_cstr); // attach to context diff --git a/src/eval.hpp b/src/eval.hpp index 004ebe66c..741472e81 100644 --- a/src/eval.hpp +++ b/src/eval.hpp @@ -29,7 +29,15 @@ namespace Sass { Boolean_Obj bool_false; Env* environment(); + EnvStack& env_stack(); + const std::string cwd(); Selector_List_Obj selector(); + CalleeStack& callee_stack(); + SelectorStack& selector_stack(); + bool& old_at_root_without_rule(); + struct Sass_Inspect_Options& options(); + struct Sass_Inspect_Options options2(); + struct Sass_Compiler* compiler(); // for evaluating function bodies Expression_Ptr operator()(Block_Ptr);