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