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