Skip to content

Commit

Permalink
Move number functions to own compile unit
Browse files Browse the repository at this point in the history
  • Loading branch information
mgreter committed Mar 17, 2018
1 parent c07f4a3 commit 8b74ede
Show file tree
Hide file tree
Showing 7 changed files with 271 additions and 28 deletions.
1 change: 1 addition & 0 deletions Makefile.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ SOURCES = \
context.cpp \
constants.cpp \
fn_utils.cpp \
fn_numbers.cpp \
functions.cpp \
color_maps.cpp \
environment.cpp \
Expand Down
217 changes: 217 additions & 0 deletions src/fn_numbers.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#include <cstdint>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <random>
#include <sstream>
#include <iomanip>
#include <algorithm>

#include "ast.hpp"
#include "sass.hpp"
#include "units.hpp"
#include "fn_utils.hpp"
#include "fn_numbers.hpp"

#ifdef __MINGW32__
#include "windows.h"
#include "wincrypt.h"
#endif

namespace Sass {

namespace Functions {

#ifdef __MINGW32__
uint64_t GetSeed()
{
HCRYPTPROV hp = 0;
BYTE rb[8];
CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
CryptGenRandom(hp, sizeof(rb), rb);
CryptReleaseContext(hp, 0);

uint64_t seed;
memcpy(&seed, &rb[0], sizeof(seed));

return seed;
}
#else
uint64_t GetSeed()
{
std::random_device rd;
return rd();
}
#endif

// note: the performance of many implementations of
// random_device degrades sharply once the entropy pool
// is exhausted. For practical use, random_device is
// generally only used to seed a PRNG such as mt19937.
static std::mt19937 rand(static_cast<unsigned int>(GetSeed()));

///////////////////
// NUMBER FUNCTIONS
///////////////////

Signature percentage_sig = "percentage($number)";
BUILT_IN(percentage)
{
Number_Obj n = ARGN("$number");
if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate, traces);
return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%");
}

Signature round_sig = "round($number)";
BUILT_IN(round)
{
Number_Obj r = ARGN("$number");
r->value(Sass::round(r->value(), ctx.c_options.precision));
r->pstate(pstate);
return r.detach();
}

Signature ceil_sig = "ceil($number)";
BUILT_IN(ceil)
{
Number_Obj r = ARGN("$number");
r->value(std::ceil(r->value()));
r->pstate(pstate);
return r.detach();
}

Signature floor_sig = "floor($number)";
BUILT_IN(floor)
{
Number_Obj r = ARGN("$number");
r->value(std::floor(r->value()));
r->pstate(pstate);
return r.detach();
}

Signature abs_sig = "abs($number)";
BUILT_IN(abs)
{
Number_Obj r = ARGN("$number");
r->value(std::abs(r->value()));
r->pstate(pstate);
return r.detach();
}

Signature min_sig = "min($numbers...)";
BUILT_IN(min)
{
List_Ptr arglist = ARG("$numbers", List);
Number_Obj least = NULL;
for (size_t i = 0, L = arglist->length(); i < L; ++i) {
Expression_Obj val = arglist->value_at_index(i);
Number_Obj xi = Cast<Number>(val);
if (!xi) {
error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate, traces);
}
if (least) {
if (*xi < *least) least = xi;
} else least = xi;
}
return least.detach();
}

Signature max_sig = "max($numbers...)";
BUILT_IN(max)
{
List_Ptr arglist = ARG("$numbers", List);
Number_Obj greatest = NULL;
for (size_t i = 0, L = arglist->length(); i < L; ++i) {
Expression_Obj val = arglist->value_at_index(i);
Number_Obj xi = Cast<Number>(val);
if (!xi) {
error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate, traces);
}
if (greatest) {
if (*greatest < *xi) greatest = xi;
} else greatest = xi;
}
return greatest.detach();
}

Signature random_sig = "random($limit:false)";
BUILT_IN(random)
{
AST_Node_Obj arg = env["$limit"];
Value_Ptr v = Cast<Value>(arg);
Number_Ptr l = Cast<Number>(arg);
Boolean_Ptr b = Cast<Boolean>(arg);
if (l) {
double lv = l->value();
if (lv < 1) {
std::stringstream err;
err << "$limit " << lv << " must be greater than or equal to 1 for `random'";
error(err.str(), pstate, traces);
}
bool eq_int = std::fabs(trunc(lv) - lv) < NUMBER_EPSILON;
if (!eq_int) {
std::stringstream err;
err << "Expected $limit to be an integer but got " << lv << " for `random'";
error(err.str(), pstate, traces);
}
std::uniform_real_distribution<> distributor(1, lv + 1);
uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
return SASS_MEMORY_NEW(Number, pstate, (double)distributed);
}
else if (b) {
std::uniform_real_distribution<> distributor(0, 1);
double distributed = static_cast<double>(distributor(rand));
return SASS_MEMORY_NEW(Number, pstate, distributed);
} else if (v) {
traces.push_back(Backtrace(pstate));
throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number", v);
} else {
traces.push_back(Backtrace(pstate));
throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number");
}
}

Signature unique_id_sig = "unique-id()";
BUILT_IN(unique_id)
{
std::stringstream ss;
std::uniform_real_distribution<> distributor(0, 4294967296); // 16^8
uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
ss << "u" << std::setfill('0') << std::setw(8) << std::hex << distributed;
return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str());
}

Signature unit_sig = "unit($number)";
BUILT_IN(unit)
{
Number_Obj arg = ARGN("$number");
std::string str(quote(arg->unit(), '"'));
return SASS_MEMORY_NEW(String_Quoted, pstate, str);
}

Signature unitless_sig = "unitless($number)";
BUILT_IN(unitless)
{
Number_Obj arg = ARGN("$number");
bool unitless = arg->is_unitless();
return SASS_MEMORY_NEW(Boolean, pstate, unitless);
}

Signature comparable_sig = "comparable($number-1, $number-2)";
BUILT_IN(comparable)
{
Number_Obj n1 = ARGN("$number-1");
Number_Obj n2 = ARGN("$number-2");
if (n1->is_unitless() || n2->is_unitless()) {
return SASS_MEMORY_NEW(Boolean, pstate, true);
}
// normalize into main units
n1->normalize(); n2->normalize();
Units &lhs_unit = *n1, &rhs_unit = *n2;
bool is_comparable = (lhs_unit == rhs_unit);
return SASS_MEMORY_NEW(Boolean, pstate, is_comparable);
}

}

}
45 changes: 45 additions & 0 deletions src/fn_numbers.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef SASS_FN_NUMBERS_H
#define SASS_FN_NUMBERS_H

#include "fn_utils.hpp"

namespace Sass {

namespace Functions {

// return a number object (copied since we want to have reduced units)
#define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy

extern Signature percentage_sig;
extern Signature round_sig;
extern Signature ceil_sig;
extern Signature floor_sig;
extern Signature abs_sig;
extern Signature min_sig;
extern Signature max_sig;
extern Signature inspect_sig;
extern Signature random_sig;
extern Signature unique_id_sig;
extern Signature unit_sig;
extern Signature unitless_sig;
extern Signature comparable_sig;

BUILT_IN(percentage);
BUILT_IN(round);
BUILT_IN(ceil);
BUILT_IN(floor);
BUILT_IN(abs);
BUILT_IN(min);
BUILT_IN(max);
BUILT_IN(inspect);
BUILT_IN(random);
BUILT_IN(unique_id);
BUILT_IN(unit);
BUILT_IN(unitless);
BUILT_IN(comparable);

}

}

#endif
3 changes: 0 additions & 3 deletions src/fn_utils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ namespace Sass {
#define ARG(argname, argtype) get_arg<argtype>(argname, env, sig, pstate, traces)
#define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces)

// return a number object (copied since we want to have reduced units)
#define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy

// special function for weird hsla percent (10px == 10% == 10 != 0.1)
#define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double

Expand Down
25 changes: 0 additions & 25 deletions src/functions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,6 @@ namespace Sass {
extern Signature str_slice_sig;
extern Signature to_upper_case_sig;
extern Signature to_lower_case_sig;
extern Signature percentage_sig;
extern Signature round_sig;
extern Signature ceil_sig;
extern Signature floor_sig;
extern Signature abs_sig;
extern Signature min_sig;
extern Signature max_sig;
extern Signature inspect_sig;
extern Signature random_sig;
extern Signature length_sig;
extern Signature nth_sig;
extern Signature index_sig;
Expand All @@ -72,9 +63,6 @@ namespace Sass {
extern Signature zip_sig;
extern Signature list_separator_sig;
extern Signature type_of_sig;
extern Signature unit_sig;
extern Signature unitless_sig;
extern Signature comparable_sig;
extern Signature variable_exists_sig;
extern Signature global_variable_exists_sig;
extern Signature function_exists_sig;
Expand All @@ -91,7 +79,6 @@ namespace Sass {
extern Signature map_has_key_sig;
extern Signature keywords_sig;
extern Signature set_nth_sig;
extern Signature unique_id_sig;
extern Signature selector_nest_sig;
extern Signature selector_append_sig;
extern Signature selector_extend_sig;
Expand Down Expand Up @@ -139,15 +126,7 @@ namespace Sass {
BUILT_IN(str_slice);
BUILT_IN(to_upper_case);
BUILT_IN(to_lower_case);
BUILT_IN(percentage);
BUILT_IN(round);
BUILT_IN(ceil);
BUILT_IN(floor);
BUILT_IN(abs);
BUILT_IN(min);
BUILT_IN(max);
BUILT_IN(inspect);
BUILT_IN(random);
BUILT_IN(length);
BUILT_IN(nth);
BUILT_IN(index);
Expand All @@ -156,9 +135,6 @@ namespace Sass {
BUILT_IN(zip);
BUILT_IN(list_separator);
BUILT_IN(type_of);
BUILT_IN(unit);
BUILT_IN(unitless);
BUILT_IN(comparable);
BUILT_IN(variable_exists);
BUILT_IN(global_variable_exists);
BUILT_IN(function_exists);
Expand All @@ -175,7 +151,6 @@ namespace Sass {
BUILT_IN(map_has_key);
BUILT_IN(keywords);
BUILT_IN(set_nth);
BUILT_IN(unique_id);
BUILT_IN(selector_nest);
BUILT_IN(selector_append);
BUILT_IN(selector_extend);
Expand Down
2 changes: 2 additions & 0 deletions win/libsass.targets
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\file.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\fn_utils.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\functions.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\fn_numbers.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\inspect.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\json.hpp" />
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\kwd_arg_macros.hpp" />
Expand Down Expand Up @@ -88,6 +89,7 @@
<ClCompile Include="$(LIBSASS_SRC_DIR)\extend.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\file.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\fn_utils.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\fn_numbers.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\functions.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\inspect.cpp" />
<ClCompile Include="$(LIBSASS_SRC_DIR)\json.cpp" />
Expand Down
6 changes: 6 additions & 0 deletions win/libsass.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\functions.hpp">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\fn_numbers.hpp">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="$(LIBSASS_HEADERS_DIR)\inspect.hpp">
<Filter>Headers</Filter>
</ClInclude>
Expand Down Expand Up @@ -275,6 +278,9 @@
<ClCompile Include="$(LIBSASS_SRC_DIR)\fn_utils.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="$(LIBSASS_SRC_DIR)\fn_numbers.cpp">
<Filter>Sources</Filter>
</ClCompile>
<ClCompile Include="$(LIBSASS_SRC_DIR)\functions.cpp">
<Filter>Sources</Filter>
</ClCompile>
Expand Down

0 comments on commit 8b74ede

Please sign in to comment.