|
1 | 1 | #include "sass.hpp"
|
| 2 | +#include "parser.hpp" |
2 | 3 | #include "fn_utils.hpp"
|
| 4 | +#include "functions.hpp" |
| 5 | +#include "error_handling.hpp" |
3 | 6 |
|
4 | 7 | namespace Sass {
|
5 | 8 |
|
| 9 | + Definition_Ptr make_native_function(Signature sig, Native_Function func, Context& ctx) |
| 10 | + { |
| 11 | + Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[built-in function]")); |
| 12 | + sig_parser.lex<Prelexer::identifier>(); |
| 13 | + std::string name(Util::normalize_underscores(sig_parser.lexed)); |
| 14 | + Parameters_Obj params = sig_parser.parse_parameters(); |
| 15 | + return SASS_MEMORY_NEW(Definition, |
| 16 | + ParserState("[built-in function]"), |
| 17 | + sig, |
| 18 | + name, |
| 19 | + params, |
| 20 | + func, |
| 21 | + false); |
| 22 | + } |
| 23 | + |
| 24 | + Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx) |
| 25 | + { |
| 26 | + using namespace Prelexer; |
| 27 | + |
| 28 | + const char* sig = sass_function_get_signature(c_func); |
| 29 | + Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[c function]")); |
| 30 | + // allow to overload generic callback plus @warn, @error and @debug with custom functions |
| 31 | + sig_parser.lex < alternatives < identifier, exactly <'*'>, |
| 32 | + exactly < Constants::warn_kwd >, |
| 33 | + exactly < Constants::error_kwd >, |
| 34 | + exactly < Constants::debug_kwd > |
| 35 | + > >(); |
| 36 | + std::string name(Util::normalize_underscores(sig_parser.lexed)); |
| 37 | + Parameters_Obj params = sig_parser.parse_parameters(); |
| 38 | + return SASS_MEMORY_NEW(Definition, |
| 39 | + ParserState("[c function]"), |
| 40 | + sig, |
| 41 | + name, |
| 42 | + params, |
| 43 | + c_func, |
| 44 | + false, true); |
| 45 | + } |
| 46 | + |
6 | 47 | namespace Functions {
|
7 | 48 |
|
| 49 | + Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) |
| 50 | + { |
| 51 | + // Minimal error handling -- the expectation is that built-ins will be written correctly! |
| 52 | + Map_Ptr val = Cast<Map>(env[argname]); |
| 53 | + if (val) return val; |
| 54 | + |
| 55 | + List_Ptr lval = Cast<List>(env[argname]); |
| 56 | + if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0); |
| 57 | + |
| 58 | + // fallback on get_arg for error handling |
| 59 | + val = get_arg<Map>(argname, env, sig, pstate, traces); |
| 60 | + return val; |
| 61 | + } |
| 62 | + |
| 63 | + double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi) |
| 64 | + { |
| 65 | + // Minimal error handling -- the expectation is that built-ins will be written correctly! |
| 66 | + Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces); |
| 67 | + Number tmpnr(val); |
| 68 | + tmpnr.reduce(); |
| 69 | + double v = tmpnr.value(); |
| 70 | + if (!(lo <= v && v <= hi)) { |
| 71 | + std::stringstream msg; |
| 72 | + msg << "argument `" << argname << "` of `" << sig << "` must be between "; |
| 73 | + msg << lo << " and " << hi; |
| 74 | + error(msg.str(), pstate, traces); |
| 75 | + } |
| 76 | + return v; |
| 77 | + } |
| 78 | + |
| 79 | + Number_Ptr get_arg_n(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) |
| 80 | + { |
| 81 | + Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces); |
| 82 | + val = SASS_MEMORY_COPY(val); |
| 83 | + val->reduce(); |
| 84 | + return val; |
| 85 | + } |
| 86 | + |
| 87 | + double get_arg_val(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) |
| 88 | + { |
| 89 | + Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces); |
| 90 | + Number tmpnr(val); |
| 91 | + tmpnr.reduce(); |
| 92 | + return tmpnr.value(); |
| 93 | + } |
| 94 | + |
| 95 | + double color_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) |
| 96 | + { |
| 97 | + Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces); |
| 98 | + Number tmpnr(val); |
| 99 | + tmpnr.reduce(); |
| 100 | + if (tmpnr.unit() == "%") { |
| 101 | + return std::min(std::max(tmpnr.value() * 255 / 100.0, 0.0), 255.0); |
| 102 | + } else { |
| 103 | + return std::min(std::max(tmpnr.value(), 0.0), 255.0); |
| 104 | + } |
| 105 | + } |
| 106 | + |
| 107 | + double alpha_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) { |
| 108 | + Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces); |
| 109 | + Number tmpnr(val); |
| 110 | + tmpnr.reduce(); |
| 111 | + if (tmpnr.unit() == "%") { |
| 112 | + return std::min(std::max(tmpnr.value(), 0.0), 100.0); |
| 113 | + } else { |
| 114 | + return std::min(std::max(tmpnr.value(), 0.0), 1.0); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + Selector_List_Obj get_arg_sels(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) { |
| 119 | + Expression_Obj exp = ARG(argname, Expression); |
| 120 | + if (exp->concrete_type() == Expression::NULL_VAL) { |
| 121 | + std::stringstream msg; |
| 122 | + msg << argname << ": null is not a valid selector: it must be a string,\n"; |
| 123 | + msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'"; |
| 124 | + error(msg.str(), pstate, traces); |
| 125 | + } |
| 126 | + if (String_Constant_Ptr str = Cast<String_Constant>(exp)) { |
| 127 | + str->quote_mark(0); |
| 128 | + } |
| 129 | + std::string exp_src = exp->to_string(ctx.c_options); |
| 130 | + return Parser::parse_selector(exp_src.c_str(), ctx, traces); |
| 131 | + } |
| 132 | + |
| 133 | + Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) { |
| 134 | + Expression_Obj exp = ARG(argname, Expression); |
| 135 | + if (exp->concrete_type() == Expression::NULL_VAL) { |
| 136 | + std::stringstream msg; |
| 137 | + msg << argname << ": null is not a string for `" << function_name(sig) << "'"; |
| 138 | + error(msg.str(), pstate, traces); |
| 139 | + } |
| 140 | + if (String_Constant_Ptr str = Cast<String_Constant>(exp)) { |
| 141 | + str->quote_mark(0); |
| 142 | + } |
| 143 | + std::string exp_src = exp->to_string(ctx.c_options); |
| 144 | + Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx, traces); |
| 145 | + if (sel_list->length() == 0) return NULL; |
| 146 | + Complex_Selector_Obj first = sel_list->first(); |
| 147 | + if (!first->tail()) return first->head(); |
| 148 | + return first->tail()->head(); |
| 149 | + } |
| 150 | + |
8 | 151 | }
|
9 | 152 |
|
10 | 153 | }
|
0 commit comments