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