1 #include "ast.hpp"
2 #include "expand.hpp"
3 #include "fn_utils.hpp"
4 #include "fn_miscs.hpp"
5 #include "util_string.hpp"
6 
7 namespace Sass {
8 
9   namespace Functions {
10 
11     //////////////////////////
12     // INTROSPECTION FUNCTIONS
13     //////////////////////////
14 
15     Signature type_of_sig = "type-of($value)";
BUILT_IN(type_of)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)";
BUILT_IN(variable_exists)23     BUILT_IN(variable_exists)
24     {
25       sass::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
26 
27       if(d_env.has("$"+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)";
BUILT_IN(global_variable_exists)36     BUILT_IN(global_variable_exists)
37     {
38       sass::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
39 
40       if(d_env.has_global("$"+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)";
BUILT_IN(function_exists)49     BUILT_IN(function_exists)
50     {
51       String_Constant* ss = Cast<String_Constant>(env["$name"]);
52       if (!ss) {
53         error("$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces);
54       }
55 
56       sass::string name = Util::normalize_underscores(unquote(ss->value()));
57 
58       if(d_env.has(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)";
BUILT_IN(mixin_exists)67     BUILT_IN(mixin_exists)
68     {
69       sass::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
70 
71       if(d_env.has(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)";
BUILT_IN(feature_exists)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...)";
BUILT_IN(call)95     BUILT_IN(call)
96     {
97       sass::string function;
98       Function* ff = Cast<Function>(env["$function"]);
99       String_Constant* ss = Cast<String_Constant>(env["$function"]);
100 
101       if (ss) {
102         function = Util::normalize_underscores(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(true); // calc invoke is allowed
142       if (ff) func->func(ff);
143       return Cast<PreValue>(func->perform(&expand.eval));
144     }
145 
146     ////////////////////
147     // BOOLEAN FUNCTIONS
148     ////////////////////
149 
150     Signature not_sig = "not($value)";
BUILT_IN(sass_not)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)";
BUILT_IN(sass_if)157     BUILT_IN(sass_if)
158     {
159       Expand expand(ctx, &d_env, &selector_stack, &original_stack);
160       ExpressionObj cond = ARG("$condition", Expression)->perform(&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>(res->perform(&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)";
BUILT_IN(inspect)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>(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(&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()";
BUILT_IN(content_exists)203     BUILT_IN(content_exists)
204     {
205       if (!d_env.has_global("is_in_mixin")) {
206         error("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)";
BUILT_IN(get_function)212     BUILT_IN(get_function)
213     {
214       String_Constant* ss = Cast<String_Constant>(env["$name"]);
215       if (!ss) {
216         error("$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces);
217       }
218 
219       sass::string name = Util::normalize_underscores(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(full_name)) {
235         error("Function not found: " + name, pstate, traces);
236       }
237 
238       Definition* def = Cast<Definition>(d_env[full_name]);
239       return SASS_MEMORY_NEW(Function, pstate, def, false);
240     }
241 
242   }
243 
244 }
245