Coverage Report

Created: 2026-02-14 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libsass/src/fn_utils.cpp
Line
Count
Source
1
// sass.hpp must go before all system headers to get the
2
// __EXTENSIONS__ fix on Solaris.
3
#include "sass.hpp"
4
5
#include "parser.hpp"
6
#include "fn_utils.hpp"
7
#include "util_string.hpp"
8
9
namespace Sass {
10
11
  Definition* make_native_function(Signature sig, Native_Function func, Context& ctx)
12
516
  {
13
516
    SourceFile* source = SASS_MEMORY_NEW(SourceFile, "[built-in function]", sig, std::string::npos);
14
516
    Parser sig_parser(source, ctx, ctx.traces);
15
516
    sig_parser.lex<Prelexer::identifier>();
16
516
    sass::string name(Util::normalize_underscores(sig_parser.lexed));
17
516
    Parameters_Obj params = sig_parser.parse_parameters();
18
516
    return SASS_MEMORY_NEW(Definition,
19
516
                          SourceSpan(source),
20
516
                          sig,
21
516
                          name,
22
516
                          params,
23
516
                          func,
24
516
                          false);
25
516
  }
26
27
  Definition* make_c_function(Sass_Function_Entry c_func, Context& ctx)
28
0
  {
29
0
    using namespace Prelexer;
30
0
    const char* sig = sass_function_get_signature(c_func);
31
0
    SourceFile* source = SASS_MEMORY_NEW(SourceFile, "[c function]", sig, std::string::npos);
32
0
    Parser sig_parser(source, ctx, ctx.traces);
33
    // allow to overload generic callback plus @warn, @error and @debug with custom functions
34
0
    sig_parser.lex < alternatives < identifier, exactly <'*'>,
35
0
                                    exactly < Constants::warn_kwd >,
36
0
                                    exactly < Constants::error_kwd >,
37
0
                                    exactly < Constants::debug_kwd >
38
0
                  >              >();
39
0
    sass::string name(Util::normalize_underscores(sig_parser.lexed));
40
0
    Parameters_Obj params = sig_parser.parse_parameters();
41
0
    return SASS_MEMORY_NEW(Definition,
42
0
                          SourceSpan(source),
43
0
                          sig,
44
0
                          name,
45
0
                          params,
46
0
                          c_func);
47
0
  }
48
49
  namespace Functions {
50
51
    sass::string function_name(Signature sig)
52
0
    {
53
0
      sass::string str(sig);
54
0
      return str.substr(0, str.find('('));
55
0
    }
56
57
    Map* get_arg_m(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces)
58
0
    {
59
0
      AST_Node* value = env[argname];
60
0
      if (Map* map = Cast<Map>(value)) return map;
61
0
      List* list = Cast<List>(value);
62
0
      if (list && list->length() == 0) {
63
0
        return SASS_MEMORY_NEW(Map, pstate, 0);
64
0
      }
65
0
      return get_arg<Map>(argname, env, sig, pstate, traces);
66
0
    }
67
68
    double get_arg_r(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces, double lo, double hi)
69
0
    {
70
0
      Number* val = get_arg<Number>(argname, env, sig, pstate, traces);
71
0
      Number tmpnr(val);
72
0
      tmpnr.reduce();
73
0
      double v = tmpnr.value();
74
0
      if (!(lo <= v && v <= hi)) {
75
0
        sass::ostream msg;
76
0
        msg << "argument `" << argname << "` of `" << sig << "` must be between ";
77
0
        msg << lo << " and " << hi;
78
0
        error(msg.str(), pstate, traces);
79
0
      }
80
0
      return v;
81
0
    }
82
83
    Number* get_arg_n(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces)
84
0
    {
85
0
      Number* val = get_arg<Number>(argname, env, sig, pstate, traces);
86
0
      val = SASS_MEMORY_COPY(val);
87
0
      val->reduce();
88
0
      return val;
89
0
    }
90
91
    double get_arg_val(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces)
92
0
    {
93
0
      Number* val = get_arg<Number>(argname, env, sig, pstate, traces);
94
0
      Number tmpnr(val);
95
0
      tmpnr.reduce();
96
0
      return tmpnr.value();
97
0
    }
98
99
    double color_num(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces)
100
0
    {
101
0
      Number* val = get_arg<Number>(argname, env, sig, pstate, traces);
102
0
      Number tmpnr(val);
103
0
      tmpnr.reduce();
104
0
      if (tmpnr.unit() == "%") {
105
0
        return std::min(std::max(tmpnr.value() * 255 / 100.0, 0.0), 255.0);
106
0
      } else {
107
0
        return std::min(std::max(tmpnr.value(), 0.0), 255.0);
108
0
      }
109
0
    }
110
111
0
    double alpha_num(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces) {
112
0
      Number* val = get_arg<Number>(argname, env, sig, pstate, traces);
113
0
      Number tmpnr(val);
114
0
      tmpnr.reduce();
115
0
      if (tmpnr.unit() == "%") {
116
0
        return std::min(std::max(tmpnr.value(), 0.0), 100.0);
117
0
      } else {
118
0
        return std::min(std::max(tmpnr.value(), 0.0), 1.0);
119
0
      }
120
0
    }
121
122
0
    SelectorListObj get_arg_sels(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces, Context& ctx) {
123
0
      ExpressionObj exp = ARG(argname, Expression);
124
0
      if (exp->concrete_type() == Expression::NULL_VAL) {
125
0
        sass::ostream msg;
126
0
        msg << argname << ": null is not a valid selector: it must be a string,\n";
127
0
        msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'";
128
0
        error(msg.str(), exp->pstate(), traces);
129
0
      }
130
0
      if (String_Constant* str = Cast<String_Constant>(exp)) {
131
0
        str->quote_mark(0);
132
0
      }
133
0
      sass::string exp_src = exp->to_string(ctx.c_options);
134
0
      ItplFile* source = SASS_MEMORY_NEW(ItplFile, exp_src.c_str(), exp->pstate());
135
0
      return Parser::parse_selector(source, ctx, traces, false);
136
0
    }
137
138
0
    CompoundSelectorObj get_arg_sel(const sass::string& argname, Env& env, Signature sig, SourceSpan pstate, Backtraces traces, Context& ctx) {
139
0
      ExpressionObj exp = ARG(argname, Expression);
140
0
      if (exp->concrete_type() == Expression::NULL_VAL) {
141
0
        sass::ostream msg;
142
0
        msg << argname << ": null is not a string for `" << function_name(sig) << "'";
143
0
        error(msg.str(), exp->pstate(), traces);
144
0
      }
145
0
      if (String_Constant* str = Cast<String_Constant>(exp)) {
146
0
        str->quote_mark(0);
147
0
      }
148
0
      sass::string exp_src = exp->to_string(ctx.c_options);
149
0
      ItplFile* source = SASS_MEMORY_NEW(ItplFile, exp_src.c_str(), exp->pstate());
150
0
      SelectorListObj sel_list = Parser::parse_selector(source, ctx, traces, false);
151
0
      if (sel_list->length() == 0) return {};
152
0
      return sel_list->first()->first();
153
0
    }
154
155
156
  }
157
158
}