1#include "ast.hpp"
2#include "expand.hpp"
3#include "fn_utils.hpp"
4#include "fn_miscs.hpp"
5#include "util_string.hpp"
6
7namespace Sass {
8
9 namespace Functions {
10
11 //////////////////////////
12 // INTROSPECTION FUNCTIONS
13 //////////////////////////
14
15 Signature type_of_sig = "type-of($value)";
16 BUILT_IN(type_of)
17 {
18 Expression* v = ARG("$value", Expression);
19 return SASS_MEMORY_NEW(String_Quoted, pstate, v->type());
20 }
21
22 Signature variable_exists_sig = "variable-exists($name)";
23 BUILT_IN(variable_exists)
24 {
25 sass::string s = Util::normalize_underscores(str: unquote(ARG("$name", String_Constant)->value()));
26
27 if(d_env.has(key: "$"+s)) {
28 return SASS_MEMORY_NEW(Boolean, pstate, true);
29 }
30 else {
31 return SASS_MEMORY_NEW(Boolean, pstate, false);
32 }
33 }
34
35 Signature global_variable_exists_sig = "global-variable-exists($name)";
36 BUILT_IN(global_variable_exists)
37 {
38 sass::string s = Util::normalize_underscores(str: unquote(ARG("$name", String_Constant)->value()));
39
40 if(d_env.has_global(key: "$"+s)) {
41 return SASS_MEMORY_NEW(Boolean, pstate, true);
42 }
43 else {
44 return SASS_MEMORY_NEW(Boolean, pstate, false);
45 }
46 }
47
48 Signature function_exists_sig = "function-exists($name)";
49 BUILT_IN(function_exists)
50 {
51 String_Constant* ss = Cast<String_Constant>(ptr: env["$name"]);
52 if (!ss) {
53 error(msg: "$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces);
54 }
55
56 sass::string name = Util::normalize_underscores(str: unquote(ss->value()));
57
58 if(d_env.has(key: name+"[f]")) {
59 return SASS_MEMORY_NEW(Boolean, pstate, true);
60 }
61 else {
62 return SASS_MEMORY_NEW(Boolean, pstate, false);
63 }
64 }
65
66 Signature mixin_exists_sig = "mixin-exists($name)";
67 BUILT_IN(mixin_exists)
68 {
69 sass::string s = Util::normalize_underscores(str: unquote(ARG("$name", String_Constant)->value()));
70
71 if(d_env.has(key: s+"[m]")) {
72 return SASS_MEMORY_NEW(Boolean, pstate, true);
73 }
74 else {
75 return SASS_MEMORY_NEW(Boolean, pstate, false);
76 }
77 }
78
79 Signature feature_exists_sig = "feature-exists($feature)";
80 BUILT_IN(feature_exists)
81 {
82 sass::string s = unquote(ARG("$feature", String_Constant)->value());
83
84 static const auto *const features = new std::unordered_set<sass::string> {
85 "global-variable-shadowing",
86 "extend-selector-pseudoclass",
87 "at-error",
88 "units-level-3",
89 "custom-property"
90 };
91 return SASS_MEMORY_NEW(Boolean, pstate, features->find(s) != features->end());
92 }
93
94 Signature call_sig = "call($function, $args...)";
95 BUILT_IN(call)
96 {
97 sass::string function;
98 Function* ff = Cast<Function>(ptr: env["$function"]);
99 String_Constant* ss = Cast<String_Constant>(ptr: env["$function"]);
100
101 if (ss) {
102 function = Util::normalize_underscores(str: unquote(ss->value()));
103 std::cerr << "DEPRECATION WARNING: ";
104 std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl;
105 std::cerr << "in Sass 4.0. Use call(get-function(" + quote(function) + ")) instead." << std::endl;
106 std::cerr << std::endl;
107 } else if (ff) {
108 function = ff->name();
109 }
110
111 List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List));
112
113 Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
114 // sass::string full_name(name + "[f]");
115 // Definition* def = d_env.has(full_name) ? Cast<Definition>((d_env)[full_name]) : 0;
116 // Parameters* params = def ? def->parameters() : 0;
117 // size_t param_size = params ? params->length() : 0;
118 for (size_t i = 0, L = arglist->length(); i < L; ++i) {
119 ExpressionObj expr = arglist->value_at_index(i);
120 // if (params && params->has_rest_parameter()) {
121 // Parameter_Obj p = param_size > i ? (*params)[i] : 0;
122 // List* list = Cast<List>(expr);
123 // if (list && p && !p->is_rest_parameter()) expr = (*list)[0];
124 // }
125 if (arglist->is_arglist()) {
126 ExpressionObj obj = arglist->at(i);
127 Argument_Obj arg = (Argument*) obj.ptr(); // XXX
128 args->append(SASS_MEMORY_NEW(Argument,
129 pstate,
130 expr,
131 arg ? arg->name() : "",
132 arg ? arg->is_rest_argument() : false,
133 arg ? arg->is_keyword_argument() : false));
134 } else {
135 args->append(SASS_MEMORY_NEW(Argument, pstate, expr));
136 }
137 }
138 Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, function, args);
139
140 Expand expand(ctx, &d_env, &selector_stack, &original_stack);
141 func->via_call(via_call__: true); // calc invoke is allowed
142 if (ff) func->func(func__: ff);
143 return Cast<PreValue>(ptr: func->perform(op: &expand.eval));
144 }
145
146 ////////////////////
147 // BOOLEAN FUNCTIONS
148 ////////////////////
149
150 Signature not_sig = "not($value)";
151 BUILT_IN(sass_not)
152 {
153 return SASS_MEMORY_NEW(Boolean, pstate, ARG("$value", Expression)->is_false());
154 }
155
156 Signature if_sig = "if($condition, $if-true, $if-false)";
157 BUILT_IN(sass_if)
158 {
159 Expand expand(ctx, &d_env, &selector_stack, &original_stack);
160 ExpressionObj cond = ARG("$condition", Expression)->perform(op: &expand.eval);
161 bool is_true = !cond->is_false();
162 ExpressionObj res = ARG(is_true ? "$if-true" : "$if-false", Expression);
163 ValueObj qwe = Cast<Value>(ptr: res->perform(op: &expand.eval));
164 // res = res->perform(&expand.eval.val_eval);
165 qwe->set_delayed(false); // clone?
166 return qwe.detach();
167 }
168
169 //////////////////////////
170 // MISCELLANEOUS FUNCTIONS
171 //////////////////////////
172
173 Signature inspect_sig = "inspect($value)";
174 BUILT_IN(inspect)
175 {
176 Expression* v = ARG("$value", Expression);
177 if (v->concrete_type() == Expression::NULL_VAL) {
178 return SASS_MEMORY_NEW(String_Constant, pstate, "null");
179 } else if (v->concrete_type() == Expression::BOOLEAN && v->is_false()) {
180 return SASS_MEMORY_NEW(String_Constant, pstate, "false");
181 } else if (v->concrete_type() == Expression::STRING) {
182 String_Constant *s = Cast<String_Constant>(ptr: v);
183 if (s->quote_mark()) {
184 return SASS_MEMORY_NEW(String_Constant, pstate, quote(s->value(), s->quote_mark()));
185 } else {
186 return s;
187 }
188 } else {
189 // ToDo: fix to_sass for nested parentheses
190 Sass_Output_Style old_style;
191 old_style = ctx.c_options.output_style;
192 ctx.c_options.output_style = TO_SASS;
193 Emitter emitter(ctx.c_options);
194 Inspect i(emitter);
195 i.in_declaration = false;
196 v->perform(op: &i);
197 ctx.c_options.output_style = old_style;
198 return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer());
199 }
200 }
201
202 Signature content_exists_sig = "content-exists()";
203 BUILT_IN(content_exists)
204 {
205 if (!d_env.has_global(key: "is_in_mixin")) {
206 error(msg: "Cannot call content-exists() except within a mixin.", pstate, traces);
207 }
208 return SASS_MEMORY_NEW(Boolean, pstate, d_env.has_lexical("@content[m]"));
209 }
210
211 Signature get_function_sig = "get-function($name, $css: false)";
212 BUILT_IN(get_function)
213 {
214 String_Constant* ss = Cast<String_Constant>(ptr: env["$name"]);
215 if (!ss) {
216 error(msg: "$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces);
217 }
218
219 sass::string name = Util::normalize_underscores(str: unquote(ss->value()));
220 sass::string full_name = name + "[f]";
221
222 Boolean_Obj css = ARG("$css", Boolean);
223 if (!css->is_false()) {
224 Definition* def = SASS_MEMORY_NEW(Definition,
225 pstate,
226 name,
227 SASS_MEMORY_NEW(Parameters, pstate),
228 SASS_MEMORY_NEW(Block, pstate, 0, false),
229 Definition::FUNCTION);
230 return SASS_MEMORY_NEW(Function, pstate, def, true);
231 }
232
233
234 if (!d_env.has_global(key: full_name)) {
235 error(msg: "Function not found: " + name, pstate, traces);
236 }
237
238 Definition* def = Cast<Definition>(ptr: d_env[full_name]);
239 return SASS_MEMORY_NEW(Function, pstate, def, false);
240 }
241
242 }
243
244}
245

source code of gtk/subprojects/libsass/src/fn_miscs.cpp