#include "ast.hpp" #include "expand.hpp" #include "fn_utils.hpp" #include "fn_miscs.hpp" #include "util_string.hpp" namespace Sass { namespace Functions { ////////////////////////// // INTROSPECTION FUNCTIONS ////////////////////////// Signature type_of_sig = "type-of($value)"; BUILT_IN(type_of) { Expression* v = ARG("$value", Expression); return SASS_MEMORY_NEW(String_Quoted, pstate, v->type()); } Signature variable_exists_sig = "variable-exists($name)"; BUILT_IN(variable_exists) { sass::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); if(d_env.has("$"+s)) { return SASS_MEMORY_NEW(Boolean, pstate, true); } else { return SASS_MEMORY_NEW(Boolean, pstate, false); } } Signature global_variable_exists_sig = "global-variable-exists($name)"; BUILT_IN(global_variable_exists) { sass::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); if(d_env.has_global("$"+s)) { return SASS_MEMORY_NEW(Boolean, pstate, true); } else { return SASS_MEMORY_NEW(Boolean, pstate, false); } } Signature function_exists_sig = "function-exists($name)"; BUILT_IN(function_exists) { String_Constant* ss = Cast(env["$name"]); if (!ss) { error("$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces); } sass::string name = Util::normalize_underscores(unquote(ss->value())); if(d_env.has(name+"[f]")) { return SASS_MEMORY_NEW(Boolean, pstate, true); } else { return SASS_MEMORY_NEW(Boolean, pstate, false); } } Signature mixin_exists_sig = "mixin-exists($name)"; BUILT_IN(mixin_exists) { sass::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value())); if(d_env.has(s+"[m]")) { return SASS_MEMORY_NEW(Boolean, pstate, true); } else { return SASS_MEMORY_NEW(Boolean, pstate, false); } } Signature feature_exists_sig = "feature-exists($feature)"; BUILT_IN(feature_exists) { sass::string s = unquote(ARG("$feature", String_Constant)->value()); static const auto *const features = new std::unordered_set { "global-variable-shadowing", "extend-selector-pseudoclass", "at-error", "units-level-3", "custom-property" }; return SASS_MEMORY_NEW(Boolean, pstate, features->find(s) != features->end()); } Signature call_sig = "call($function, $args...)"; BUILT_IN(call) { sass::string function; Function* ff = Cast(env["$function"]); String_Constant* ss = Cast(env["$function"]); if (ss) { function = Util::normalize_underscores(unquote(ss->value())); std::cerr << "DEPRECATION WARNING: "; std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl; std::cerr << "in Sass 4.0. Use call(get-function(" + quote(function) + ")) instead." << std::endl; std::cerr << std::endl; } else if (ff) { function = ff->name(); } List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate); // sass::string full_name(name + "[f]"); // Definition* def = d_env.has(full_name) ? Cast((d_env)[full_name]) : 0; // Parameters* params = def ? def->parameters() : 0; // size_t param_size = params ? params->length() : 0; for (size_t i = 0, L = arglist->length(); i < L; ++i) { ExpressionObj expr = arglist->value_at_index(i); // if (params && params->has_rest_parameter()) { // Parameter_Obj p = param_size > i ? (*params)[i] : 0; // List* list = Cast(expr); // if (list && p && !p->is_rest_parameter()) expr = (*list)[0]; // } if (arglist->is_arglist()) { ExpressionObj obj = arglist->at(i); Argument_Obj arg = (Argument*) obj.ptr(); // XXX args->append(SASS_MEMORY_NEW(Argument, pstate, expr, arg ? arg->name() : "", arg ? arg->is_rest_argument() : false, arg ? arg->is_keyword_argument() : false)); } else { args->append(SASS_MEMORY_NEW(Argument, pstate, expr)); } } Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, function, args); Expand expand(ctx, &d_env, &selector_stack, &original_stack); func->via_call(true); // calc invoke is allowed if (ff) func->func(ff); return Cast(func->perform(&expand.eval)); } //////////////////// // BOOLEAN FUNCTIONS //////////////////// Signature not_sig = "not($value)"; BUILT_IN(sass_not) { return SASS_MEMORY_NEW(Boolean, pstate, ARG("$value", Expression)->is_false()); } Signature if_sig = "if($condition, $if-true, $if-false)"; BUILT_IN(sass_if) { Expand expand(ctx, &d_env, &selector_stack, &original_stack); ExpressionObj cond = ARG("$condition", Expression)->perform(&expand.eval); bool is_true = !cond->is_false(); ExpressionObj res = ARG(is_true ? "$if-true" : "$if-false", Expression); ValueObj qwe = Cast(res->perform(&expand.eval)); // res = res->perform(&expand.eval.val_eval); qwe->set_delayed(false); // clone? return qwe.detach(); } ////////////////////////// // MISCELLANEOUS FUNCTIONS ////////////////////////// Signature inspect_sig = "inspect($value)"; BUILT_IN(inspect) { Expression* v = ARG("$value", Expression); if (v->concrete_type() == Expression::NULL_VAL) { return SASS_MEMORY_NEW(String_Constant, pstate, "null"); } else if (v->concrete_type() == Expression::BOOLEAN && v->is_false()) { return SASS_MEMORY_NEW(String_Constant, pstate, "false"); } else if (v->concrete_type() == Expression::STRING) { String_Constant *s = Cast(v); if (s->quote_mark()) { return SASS_MEMORY_NEW(String_Constant, pstate, quote(s->value(), s->quote_mark())); } else { return s; } } else { // ToDo: fix to_sass for nested parentheses Sass_Output_Style old_style; old_style = ctx.c_options.output_style; ctx.c_options.output_style = TO_SASS; Emitter emitter(ctx.c_options); Inspect i(emitter); i.in_declaration = false; v->perform(&i); ctx.c_options.output_style = old_style; return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer()); } } Signature content_exists_sig = "content-exists()"; BUILT_IN(content_exists) { if (!d_env.has_global("is_in_mixin")) { error("Cannot call content-exists() except within a mixin.", pstate, traces); } return SASS_MEMORY_NEW(Boolean, pstate, d_env.has_lexical("@content[m]")); } Signature get_function_sig = "get-function($name, $css: false)"; BUILT_IN(get_function) { String_Constant* ss = Cast(env["$name"]); if (!ss) { error("$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces); } sass::string name = Util::normalize_underscores(unquote(ss->value())); sass::string full_name = name + "[f]"; Boolean_Obj css = ARG("$css", Boolean); if (!css->is_false()) { Definition* def = SASS_MEMORY_NEW(Definition, pstate, name, SASS_MEMORY_NEW(Parameters, pstate), SASS_MEMORY_NEW(Block, pstate, 0, false), Definition::FUNCTION); return SASS_MEMORY_NEW(Function, pstate, def, true); } if (!d_env.has_global(full_name)) { error("Function not found: " + name, pstate, traces); } Definition* def = Cast(d_env[full_name]); return SASS_MEMORY_NEW(Function, pstate, def, false); } } }