1+ #include  < cstdint> 
2+ #include  < cstdlib> 
3+ #include  < cmath> 
4+ #include  < cctype> 
5+ #include  < random> 
6+ #include  < sstream> 
7+ #include  < iomanip> 
8+ #include  < algorithm> 
9+ 
10+ #include  " ast.hpp" 
11+ #include  " sass.hpp" 
12+ #include  " units.hpp" 
13+ #include  " fn_utils.hpp" 
14+ #include  " fn_numbers.hpp" 
15+ 
16+ #ifdef  __MINGW32__
17+ #include  " windows.h" 
18+ #include  " wincrypt.h" 
19+ #endif 
20+ 
21+ namespace  Sass  {
22+ 
23+   namespace  Functions  {
24+ 
25+     #ifdef  __MINGW32__
26+       uint64_t  GetSeed ()
27+       {
28+         HCRYPTPROV hp = 0 ;
29+         BYTE rb[8 ];
30+         CryptAcquireContext (&hp, 0 , 0 , PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
31+         CryptGenRandom (hp, sizeof (rb), rb);
32+         CryptReleaseContext (hp, 0 );
33+ 
34+         uint64_t  seed;
35+         memcpy (&seed, &rb[0 ], sizeof (seed));
36+ 
37+         return  seed;
38+       }
39+     #else 
40+       uint64_t  GetSeed ()
41+       {
42+         std::random_device rd;
43+         return  rd ();
44+       }
45+     #endif 
46+ 
47+     //  note: the performance of many implementations of
48+     //  random_device degrades sharply once the entropy pool
49+     //  is exhausted. For practical use, random_device is
50+     //  generally only used to seed a PRNG such as mt19937.
51+     static  std::mt19937 rand (static_cast <unsigned  int >(GetSeed()));
52+ 
53+     // /////////////////
54+     //  NUMBER FUNCTIONS
55+     // /////////////////
56+ 
57+     Signature percentage_sig = " percentage($number)" 
58+     BUILT_IN (percentage)
59+     {
60+       Number_Obj n = ARGN (" $number" 
61+       if  (!n->is_unitless ()) error (" argument $number of `" std::string (sig) + " ` must be unitless" 
62+       return  SASS_MEMORY_NEW (Number, pstate, n->value () * 100 , " %" 
63+     }
64+ 
65+     Signature round_sig = " round($number)" 
66+     BUILT_IN (round)
67+     {
68+       Number_Obj r = ARGN (" $number" 
69+       r->value (Sass::round (r->value (), ctx.c_options .precision ));
70+       r->pstate (pstate);
71+       return  r.detach ();
72+     }
73+ 
74+     Signature ceil_sig = " ceil($number)" 
75+     BUILT_IN (ceil)
76+     {
77+       Number_Obj r = ARGN (" $number" 
78+       r->value (std::ceil (r->value ()));
79+       r->pstate (pstate);
80+       return  r.detach ();
81+     }
82+ 
83+     Signature floor_sig = " floor($number)" 
84+     BUILT_IN (floor)
85+     {
86+       Number_Obj r = ARGN (" $number" 
87+       r->value (std::floor (r->value ()));
88+       r->pstate (pstate);
89+       return  r.detach ();
90+     }
91+ 
92+     Signature abs_sig = " abs($number)" 
93+     BUILT_IN (abs)
94+     {
95+       Number_Obj r = ARGN (" $number" 
96+       r->value (std::abs (r->value ()));
97+       r->pstate (pstate);
98+       return  r.detach ();
99+     }
100+ 
101+     Signature min_sig = " min($numbers...)" 
102+     BUILT_IN (min)
103+     {
104+       List_Ptr arglist = ARG (" $numbers" 
105+       Number_Obj least = NULL ;
106+       for  (size_t  i = 0 , L = arglist->length (); i < L; ++i) {
107+         Expression_Obj val = arglist->value_at_index (i);
108+         Number_Obj xi = Cast<Number>(val);
109+         if  (!xi) {
110+           error (" \" " to_string (ctx.c_options ) + " \"  is not a number for `min'" 
111+         }
112+         if  (least) {
113+           if  (*xi < *least) least = xi;
114+         } else  least = xi;
115+       }
116+       return  least.detach ();
117+     }
118+ 
119+     Signature max_sig = " max($numbers...)" 
120+     BUILT_IN (max)
121+     {
122+       List_Ptr arglist = ARG (" $numbers" 
123+       Number_Obj greatest = NULL ;
124+       for  (size_t  i = 0 , L = arglist->length (); i < L; ++i) {
125+         Expression_Obj val = arglist->value_at_index (i);
126+         Number_Obj xi = Cast<Number>(val);
127+         if  (!xi) {
128+           error (" \" " to_string (ctx.c_options ) + " \"  is not a number for `max'" 
129+         }
130+         if  (greatest) {
131+           if  (*greatest < *xi) greatest = xi;
132+         } else  greatest = xi;
133+       }
134+       return  greatest.detach ();
135+     }
136+ 
137+     Signature random_sig = " random($limit:false)" 
138+     BUILT_IN (random)
139+     {
140+       AST_Node_Obj arg = env[" $limit" 
141+       Value_Ptr v = Cast<Value>(arg);
142+       Number_Ptr l = Cast<Number>(arg);
143+       Boolean_Ptr b = Cast<Boolean>(arg);
144+       if  (l) {
145+         double  lv = l->value ();
146+         if  (lv < 1 ) {
147+           std::stringstream err;
148+           err << " $limit " "  must be greater than or equal to 1 for `random'" 
149+           error (err.str (), pstate, traces);
150+         }
151+         bool  eq_int = std::fabs (trunc (lv) - lv) < NUMBER_EPSILON;
152+         if  (!eq_int) {
153+           std::stringstream err;
154+           err << " Expected $limit to be an integer but got " "  for `random'" 
155+           error (err.str (), pstate, traces);
156+         }
157+         std::uniform_real_distribution<> distributor (1 , lv + 1 );
158+         uint_fast32_t  distributed = static_cast <uint_fast32_t >(distributor (rand));
159+         return  SASS_MEMORY_NEW (Number, pstate, (double )distributed);
160+       }
161+       else  if  (b) {
162+         std::uniform_real_distribution<> distributor (0 , 1 );
163+         double  distributed = static_cast <double >(distributor (rand));
164+         return  SASS_MEMORY_NEW (Number, pstate, distributed);
165+       } else  if  (v) {
166+         traces.push_back (Backtrace (pstate));
167+         throw  Exception::InvalidArgumentType (pstate, traces, " random" " $limit" " number" 
168+       } else  {
169+         traces.push_back (Backtrace (pstate));
170+         throw  Exception::InvalidArgumentType (pstate, traces, " random" " $limit" " number" 
171+       }
172+     }
173+ 
174+     Signature unique_id_sig = " unique-id()" 
175+     BUILT_IN (unique_id)
176+     {
177+       std::stringstream ss;
178+       std::uniform_real_distribution<> distributor (0 , 4294967296 ); //  16^8
179+       uint_fast32_t  distributed = static_cast <uint_fast32_t >(distributor (rand));
180+       ss << " u" std::setfill (' 0' std::setw (8 ) << std::hex << distributed;
181+       return  SASS_MEMORY_NEW (String_Quoted, pstate, ss.str ());
182+     }
183+ 
184+     Signature unit_sig = " unit($number)" 
185+     BUILT_IN (unit)
186+     {
187+       Number_Obj arg = ARGN (" $number" 
188+       std::string str (quote (arg->unit (), ' "' 
189+       return  SASS_MEMORY_NEW (String_Quoted, pstate, str);
190+     }
191+ 
192+     Signature unitless_sig = " unitless($number)" 
193+     BUILT_IN (unitless)
194+     {
195+       Number_Obj arg = ARGN (" $number" 
196+       bool  unitless = arg->is_unitless ();
197+       return  SASS_MEMORY_NEW (Boolean, pstate, unitless);
198+     }
199+ 
200+     Signature comparable_sig = " comparable($number-1, $number-2)" 
201+     BUILT_IN (comparable)
202+     {
203+       Number_Obj n1 = ARGN (" $number-1" 
204+       Number_Obj n2 = ARGN (" $number-2" 
205+       if  (n1->is_unitless () || n2->is_unitless ()) {
206+         return  SASS_MEMORY_NEW (Boolean, pstate, true );
207+       }
208+       //  normalize into main units
209+       n1->normalize (); n2->normalize ();
210+       Units &lhs_unit = *n1, &rhs_unit = *n2;
211+       bool  is_comparable = (lhs_unit == rhs_unit);
212+       return  SASS_MEMORY_NEW (Boolean, pstate, is_comparable);
213+     }
214+ 
215+   }
216+ 
217+ }
0 commit comments