sassc 2.0.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/.gitmodules +1 -1
  4. data/.travis.yml +9 -3
  5. data/CHANGELOG.md +36 -0
  6. data/CODE_OF_CONDUCT.md +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +43 -7
  9. data/ext/depend +4 -0
  10. data/ext/extconf.rb +92 -0
  11. data/ext/libsass/VERSION +1 -0
  12. data/ext/libsass/include/sass/base.h +9 -1
  13. data/ext/libsass/include/sass/context.h +5 -1
  14. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  15. data/ext/libsass/src/ast.cpp +755 -2028
  16. data/ext/libsass/src/ast.hpp +492 -2477
  17. data/ext/libsass/src/{to_c.cpp → ast2c.cpp} +22 -16
  18. data/ext/libsass/src/ast2c.hpp +39 -0
  19. data/ext/libsass/src/ast_def_macros.hpp +70 -10
  20. data/ext/libsass/src/ast_fwd_decl.cpp +5 -3
  21. data/ext/libsass/src/ast_fwd_decl.hpp +107 -296
  22. data/ext/libsass/src/ast_helpers.hpp +292 -0
  23. data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
  24. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  25. data/ext/libsass/src/ast_sel_unify.cpp +275 -0
  26. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  27. data/ext/libsass/src/ast_selectors.cpp +1043 -0
  28. data/ext/libsass/src/ast_selectors.hpp +522 -0
  29. data/ext/libsass/src/ast_supports.cpp +114 -0
  30. data/ext/libsass/src/ast_supports.hpp +121 -0
  31. data/ext/libsass/src/ast_values.cpp +1154 -0
  32. data/ext/libsass/src/ast_values.hpp +498 -0
  33. data/ext/libsass/src/backtrace.cpp +11 -7
  34. data/ext/libsass/src/backtrace.hpp +5 -5
  35. data/ext/libsass/src/base64vlq.cpp +5 -2
  36. data/ext/libsass/src/base64vlq.hpp +1 -1
  37. data/ext/libsass/src/bind.cpp +35 -34
  38. data/ext/libsass/src/bind.hpp +3 -1
  39. data/ext/libsass/src/c2ast.cpp +64 -0
  40. data/ext/libsass/src/c2ast.hpp +14 -0
  41. data/ext/libsass/src/cencode.c +4 -6
  42. data/ext/libsass/src/check_nesting.cpp +83 -88
  43. data/ext/libsass/src/check_nesting.hpp +39 -34
  44. data/ext/libsass/src/color_maps.cpp +168 -164
  45. data/ext/libsass/src/color_maps.hpp +152 -160
  46. data/ext/libsass/src/constants.cpp +20 -0
  47. data/ext/libsass/src/constants.hpp +19 -0
  48. data/ext/libsass/src/context.cpp +104 -121
  49. data/ext/libsass/src/context.hpp +43 -55
  50. data/ext/libsass/src/cssize.cpp +103 -188
  51. data/ext/libsass/src/cssize.hpp +45 -51
  52. data/ext/libsass/src/dart_helpers.hpp +199 -0
  53. data/ext/libsass/src/debugger.hpp +524 -361
  54. data/ext/libsass/src/emitter.cpp +26 -26
  55. data/ext/libsass/src/emitter.hpp +20 -18
  56. data/ext/libsass/src/environment.cpp +41 -27
  57. data/ext/libsass/src/environment.hpp +33 -22
  58. data/ext/libsass/src/error_handling.cpp +92 -94
  59. data/ext/libsass/src/error_handling.hpp +73 -50
  60. data/ext/libsass/src/eval.cpp +380 -515
  61. data/ext/libsass/src/eval.hpp +64 -57
  62. data/ext/libsass/src/eval_selectors.cpp +75 -0
  63. data/ext/libsass/src/expand.cpp +322 -263
  64. data/ext/libsass/src/expand.hpp +55 -39
  65. data/ext/libsass/src/extender.cpp +1188 -0
  66. data/ext/libsass/src/extender.hpp +399 -0
  67. data/ext/libsass/src/extension.cpp +43 -0
  68. data/ext/libsass/src/extension.hpp +89 -0
  69. data/ext/libsass/src/file.cpp +134 -88
  70. data/ext/libsass/src/file.hpp +28 -37
  71. data/ext/libsass/src/fn_colors.cpp +596 -0
  72. data/ext/libsass/src/fn_colors.hpp +85 -0
  73. data/ext/libsass/src/fn_lists.cpp +285 -0
  74. data/ext/libsass/src/fn_lists.hpp +34 -0
  75. data/ext/libsass/src/fn_maps.cpp +94 -0
  76. data/ext/libsass/src/fn_maps.hpp +30 -0
  77. data/ext/libsass/src/fn_miscs.cpp +244 -0
  78. data/ext/libsass/src/fn_miscs.hpp +40 -0
  79. data/ext/libsass/src/fn_numbers.cpp +227 -0
  80. data/ext/libsass/src/fn_numbers.hpp +45 -0
  81. data/ext/libsass/src/fn_selectors.cpp +205 -0
  82. data/ext/libsass/src/fn_selectors.hpp +35 -0
  83. data/ext/libsass/src/fn_strings.cpp +268 -0
  84. data/ext/libsass/src/fn_strings.hpp +34 -0
  85. data/ext/libsass/src/fn_utils.cpp +158 -0
  86. data/ext/libsass/src/fn_utils.hpp +62 -0
  87. data/ext/libsass/src/inspect.cpp +253 -266
  88. data/ext/libsass/src/inspect.hpp +72 -74
  89. data/ext/libsass/src/json.cpp +2 -2
  90. data/ext/libsass/src/lexer.cpp +25 -84
  91. data/ext/libsass/src/lexer.hpp +5 -16
  92. data/ext/libsass/src/listize.cpp +27 -43
  93. data/ext/libsass/src/listize.hpp +14 -11
  94. data/ext/libsass/src/mapping.hpp +1 -0
  95. data/ext/libsass/src/memory.hpp +12 -0
  96. data/ext/libsass/src/memory/allocator.cpp +48 -0
  97. data/ext/libsass/src/memory/allocator.hpp +138 -0
  98. data/ext/libsass/src/memory/config.hpp +20 -0
  99. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  100. data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
  101. data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
  102. data/ext/libsass/src/operation.hpp +193 -143
  103. data/ext/libsass/src/operators.cpp +56 -29
  104. data/ext/libsass/src/operators.hpp +11 -11
  105. data/ext/libsass/src/ordered_map.hpp +112 -0
  106. data/ext/libsass/src/output.cpp +59 -75
  107. data/ext/libsass/src/output.hpp +15 -22
  108. data/ext/libsass/src/parser.cpp +662 -818
  109. data/ext/libsass/src/parser.hpp +96 -100
  110. data/ext/libsass/src/parser_selectors.cpp +189 -0
  111. data/ext/libsass/src/permutate.hpp +164 -0
  112. data/ext/libsass/src/plugins.cpp +12 -8
  113. data/ext/libsass/src/plugins.hpp +8 -8
  114. data/ext/libsass/src/position.cpp +10 -26
  115. data/ext/libsass/src/position.hpp +44 -21
  116. data/ext/libsass/src/prelexer.cpp +14 -8
  117. data/ext/libsass/src/prelexer.hpp +9 -9
  118. data/ext/libsass/src/remove_placeholders.cpp +59 -57
  119. data/ext/libsass/src/remove_placeholders.hpp +20 -18
  120. data/ext/libsass/src/sass.cpp +25 -18
  121. data/ext/libsass/src/sass.hpp +22 -14
  122. data/ext/libsass/src/sass2scss.cpp +49 -18
  123. data/ext/libsass/src/sass_context.cpp +104 -132
  124. data/ext/libsass/src/sass_context.hpp +2 -2
  125. data/ext/libsass/src/sass_functions.cpp +7 -4
  126. data/ext/libsass/src/sass_functions.hpp +1 -1
  127. data/ext/libsass/src/sass_values.cpp +26 -21
  128. data/ext/libsass/src/settings.hpp +19 -0
  129. data/ext/libsass/src/source.cpp +69 -0
  130. data/ext/libsass/src/source.hpp +95 -0
  131. data/ext/libsass/src/source_data.hpp +32 -0
  132. data/ext/libsass/src/source_map.cpp +27 -20
  133. data/ext/libsass/src/source_map.hpp +14 -11
  134. data/ext/libsass/src/stylesheet.cpp +22 -0
  135. data/ext/libsass/src/stylesheet.hpp +57 -0
  136. data/ext/libsass/src/to_value.cpp +24 -22
  137. data/ext/libsass/src/to_value.hpp +18 -22
  138. data/ext/libsass/src/units.cpp +28 -22
  139. data/ext/libsass/src/units.hpp +9 -8
  140. data/ext/libsass/src/utf8/checked.h +12 -10
  141. data/ext/libsass/src/utf8/core.h +3 -0
  142. data/ext/libsass/src/utf8_string.cpp +12 -10
  143. data/ext/libsass/src/utf8_string.hpp +7 -6
  144. data/ext/libsass/src/util.cpp +97 -107
  145. data/ext/libsass/src/util.hpp +74 -30
  146. data/ext/libsass/src/util_string.cpp +125 -0
  147. data/ext/libsass/src/util_string.hpp +73 -0
  148. data/ext/libsass/src/values.cpp +33 -24
  149. data/ext/libsass/src/values.hpp +2 -2
  150. data/lib/sassc.rb +24 -0
  151. data/lib/sassc/engine.rb +7 -5
  152. data/lib/sassc/functions_handler.rb +11 -13
  153. data/lib/sassc/native.rb +10 -9
  154. data/lib/sassc/native/native_functions_api.rb +0 -5
  155. data/lib/sassc/script.rb +4 -6
  156. data/lib/sassc/version.rb +1 -1
  157. data/sassc.gemspec +32 -12
  158. data/test/engine_test.rb +32 -2
  159. data/test/functions_test.rb +38 -1
  160. data/test/native_test.rb +4 -4
  161. metadata +95 -109
  162. data/ext/Rakefile +0 -3
  163. data/ext/libsass/.editorconfig +0 -15
  164. data/ext/libsass/.gitattributes +0 -2
  165. data/ext/libsass/.github/CONTRIBUTING.md +0 -65
  166. data/ext/libsass/.github/ISSUE_TEMPLATE.md +0 -54
  167. data/ext/libsass/.gitignore +0 -85
  168. data/ext/libsass/.travis.yml +0 -64
  169. data/ext/libsass/COPYING +0 -25
  170. data/ext/libsass/GNUmakefile.am +0 -88
  171. data/ext/libsass/INSTALL +0 -1
  172. data/ext/libsass/LICENSE +0 -25
  173. data/ext/libsass/Makefile +0 -351
  174. data/ext/libsass/Makefile.conf +0 -55
  175. data/ext/libsass/Readme.md +0 -104
  176. data/ext/libsass/SECURITY.md +0 -10
  177. data/ext/libsass/appveyor.yml +0 -91
  178. data/ext/libsass/configure.ac +0 -138
  179. data/ext/libsass/contrib/libsass.spec +0 -66
  180. data/ext/libsass/docs/README.md +0 -20
  181. data/ext/libsass/docs/api-context-example.md +0 -45
  182. data/ext/libsass/docs/api-context-internal.md +0 -163
  183. data/ext/libsass/docs/api-context.md +0 -295
  184. data/ext/libsass/docs/api-doc.md +0 -215
  185. data/ext/libsass/docs/api-function-example.md +0 -67
  186. data/ext/libsass/docs/api-function-internal.md +0 -8
  187. data/ext/libsass/docs/api-function.md +0 -74
  188. data/ext/libsass/docs/api-importer-example.md +0 -112
  189. data/ext/libsass/docs/api-importer-internal.md +0 -20
  190. data/ext/libsass/docs/api-importer.md +0 -86
  191. data/ext/libsass/docs/api-value-example.md +0 -55
  192. data/ext/libsass/docs/api-value-internal.md +0 -76
  193. data/ext/libsass/docs/api-value.md +0 -154
  194. data/ext/libsass/docs/build-on-darwin.md +0 -27
  195. data/ext/libsass/docs/build-on-gentoo.md +0 -55
  196. data/ext/libsass/docs/build-on-windows.md +0 -139
  197. data/ext/libsass/docs/build-shared-library.md +0 -35
  198. data/ext/libsass/docs/build-with-autotools.md +0 -78
  199. data/ext/libsass/docs/build-with-makefiles.md +0 -68
  200. data/ext/libsass/docs/build-with-mingw.md +0 -107
  201. data/ext/libsass/docs/build-with-visual-studio.md +0 -90
  202. data/ext/libsass/docs/build.md +0 -97
  203. data/ext/libsass/docs/compatibility-plan.md +0 -48
  204. data/ext/libsass/docs/contributing.md +0 -17
  205. data/ext/libsass/docs/custom-functions-internal.md +0 -122
  206. data/ext/libsass/docs/dev-ast-memory.md +0 -223
  207. data/ext/libsass/docs/implementations.md +0 -56
  208. data/ext/libsass/docs/plugins.md +0 -47
  209. data/ext/libsass/docs/setup-environment.md +0 -68
  210. data/ext/libsass/docs/source-map-internals.md +0 -51
  211. data/ext/libsass/docs/trace.md +0 -26
  212. data/ext/libsass/docs/triage.md +0 -17
  213. data/ext/libsass/docs/unicode.md +0 -39
  214. data/ext/libsass/extconf.rb +0 -6
  215. data/ext/libsass/include/sass/version.h.in +0 -12
  216. data/ext/libsass/m4/.gitkeep +0 -0
  217. data/ext/libsass/m4/m4-ax_cxx_compile_stdcxx_11.m4 +0 -167
  218. data/ext/libsass/res/resource.rc +0 -35
  219. data/ext/libsass/script/bootstrap +0 -13
  220. data/ext/libsass/script/branding +0 -10
  221. data/ext/libsass/script/ci-build-libsass +0 -134
  222. data/ext/libsass/script/ci-build-plugin +0 -62
  223. data/ext/libsass/script/ci-install-compiler +0 -6
  224. data/ext/libsass/script/ci-install-deps +0 -20
  225. data/ext/libsass/script/ci-report-coverage +0 -42
  226. data/ext/libsass/script/spec +0 -5
  227. data/ext/libsass/script/tap-driver +0 -652
  228. data/ext/libsass/script/tap-runner +0 -1
  229. data/ext/libsass/script/test-leaks.pl +0 -103
  230. data/ext/libsass/src/GNUmakefile.am +0 -54
  231. data/ext/libsass/src/extend.cpp +0 -2130
  232. data/ext/libsass/src/extend.hpp +0 -86
  233. data/ext/libsass/src/functions.cpp +0 -2234
  234. data/ext/libsass/src/functions.hpp +0 -198
  235. data/ext/libsass/src/memory/SharedPtr.cpp +0 -114
  236. data/ext/libsass/src/memory/SharedPtr.hpp +0 -206
  237. data/ext/libsass/src/node.cpp +0 -319
  238. data/ext/libsass/src/node.hpp +0 -118
  239. data/ext/libsass/src/paths.hpp +0 -71
  240. data/ext/libsass/src/sass_util.cpp +0 -149
  241. data/ext/libsass/src/sass_util.hpp +0 -256
  242. data/ext/libsass/src/subset_map.cpp +0 -55
  243. data/ext/libsass/src/subset_map.hpp +0 -76
  244. data/ext/libsass/src/support/libsass.pc.in +0 -11
  245. data/ext/libsass/src/to_c.hpp +0 -39
  246. data/ext/libsass/test/test_node.cpp +0 -94
  247. data/ext/libsass/test/test_paths.cpp +0 -28
  248. data/ext/libsass/test/test_selector_difference.cpp +0 -25
  249. data/ext/libsass/test/test_specificity.cpp +0 -25
  250. data/ext/libsass/test/test_subset_map.cpp +0 -472
  251. data/ext/libsass/test/test_superselector.cpp +0 -69
  252. data/ext/libsass/test/test_unification.cpp +0 -31
  253. data/ext/libsass/version.sh +0 -10
  254. data/ext/libsass/win/libsass.sln +0 -39
  255. data/ext/libsass/win/libsass.sln.DotSettings +0 -9
  256. data/ext/libsass/win/libsass.targets +0 -118
  257. data/ext/libsass/win/libsass.vcxproj +0 -188
  258. data/ext/libsass/win/libsass.vcxproj.filters +0 -357
  259. data/lib/sassc/native/lib_c.rb +0 -21
  260. data/lib/tasks/libsass.rb +0 -33
@@ -1,86 +0,0 @@
1
- #ifndef SASS_EXTEND_H
2
- #define SASS_EXTEND_H
3
-
4
- #include <string>
5
- #include <set>
6
-
7
- #include "ast.hpp"
8
- #include "node.hpp"
9
- #include "eval.hpp"
10
- #include "operation.hpp"
11
- #include "subset_map.hpp"
12
- #include "ast_fwd_decl.hpp"
13
-
14
- namespace Sass {
15
-
16
- Node subweave(Node& one, Node& two);
17
-
18
- class Extend : public Operation_CRTP<void, Extend> {
19
-
20
- Subset_Map& subset_map;
21
- Eval* eval;
22
-
23
- void fallback_impl(AST_Node_Ptr n) { }
24
-
25
- private:
26
-
27
- std::unordered_map<
28
- Selector_List_Obj, // key
29
- Selector_List_Obj, // value
30
- HashNodes, // hasher
31
- CompareNodes // compare
32
- > memoizeList;
33
-
34
- std::unordered_map<
35
- Complex_Selector_Obj, // key
36
- Node, // value
37
- HashNodes, // hasher
38
- CompareNodes // compare
39
- > memoizeComplex;
40
-
41
- /* this turned out to be too much overhead
42
- re-evaluate once we store an ast selector
43
- std::unordered_map<
44
- Compound_Selector_Obj, // key
45
- Node, // value
46
- HashNodes, // hasher
47
- CompareNodes // compare
48
- > memoizeCompound;
49
- */
50
-
51
- void extendObjectWithSelectorAndBlock(Ruleset_Ptr pObject);
52
- Node extendComplexSelector(Complex_Selector_Ptr sel, CompoundSelectorSet& seen, bool isReplace, bool isOriginal);
53
- Node extendCompoundSelector(Compound_Selector_Ptr sel, CompoundSelectorSet& seen, bool isReplace);
54
- bool complexSelectorHasExtension(Complex_Selector_Ptr selector, CompoundSelectorSet& seen);
55
- Node trim(Node& seqses, bool isReplace);
56
- Node weave(Node& path);
57
-
58
- public:
59
- void setEval(Eval& eval);
60
- Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, bool isReplace, bool& extendedSomething, CompoundSelectorSet& seen);
61
- Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, bool isReplace = false) {
62
- bool extendedSomething = false;
63
- CompoundSelectorSet seen;
64
- return extendSelectorList(pSelectorList, isReplace, extendedSomething, seen);
65
- }
66
- Selector_List_Ptr extendSelectorList(Selector_List_Obj pSelectorList, CompoundSelectorSet& seen) {
67
- bool isReplace = false;
68
- bool extendedSomething = false;
69
- return extendSelectorList(pSelectorList, isReplace, extendedSomething, seen);
70
- }
71
- Extend(Subset_Map&);
72
- ~Extend() { }
73
-
74
- void operator()(Block_Ptr);
75
- void operator()(Ruleset_Ptr);
76
- void operator()(Supports_Block_Ptr);
77
- void operator()(Media_Block_Ptr);
78
- void operator()(Directive_Ptr);
79
-
80
- template <typename U>
81
- void fallback(U x) { return fallback_impl(x); }
82
- };
83
-
84
- }
85
-
86
- #endif
@@ -1,2234 +0,0 @@
1
- #include "sass.hpp"
2
- #include "functions.hpp"
3
- #include "ast.hpp"
4
- #include "context.hpp"
5
- #include "backtrace.hpp"
6
- #include "parser.hpp"
7
- #include "constants.hpp"
8
- #include "inspect.hpp"
9
- #include "extend.hpp"
10
- #include "eval.hpp"
11
- #include "util.hpp"
12
- #include "expand.hpp"
13
- #include "operators.hpp"
14
- #include "utf8_string.hpp"
15
- #include "sass/base.h"
16
- #include "utf8.h"
17
-
18
- #include <cstdint>
19
- #include <cstdlib>
20
- #include <cmath>
21
- #include <cctype>
22
- #include <sstream>
23
- #include <string>
24
- #include <iomanip>
25
- #include <iostream>
26
- #include <random>
27
- #include <set>
28
-
29
- #ifdef __MINGW32__
30
- #include "windows.h"
31
- #include "wincrypt.h"
32
- #endif
33
-
34
- #define ARG(argname, argtype) get_arg<argtype>(argname, env, sig, pstate, traces)
35
- #define ARGM(argname, argtype, ctx) get_arg_m(argname, env, sig, pstate, traces, ctx)
36
-
37
- // return a number object (copied since we want to have reduced units)
38
- #define ARGN(argname) get_arg_n(argname, env, sig, pstate, traces) // Number copy
39
-
40
- // special function for weird hsla percent (10px == 10% == 10 != 0.1)
41
- #define ARGVAL(argname) get_arg_val(argname, env, sig, pstate, traces) // double
42
-
43
- // macros for common ranges (u mean unsigned or upper, r for full range)
44
- #define DARG_U_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 1.0) // double
45
- #define DARG_R_FACT(argname) get_arg_r(argname, env, sig, pstate, traces, - 1.0, 1.0) // double
46
- #define DARG_U_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 255.0) // double
47
- #define DARG_R_BYTE(argname) get_arg_r(argname, env, sig, pstate, traces, - 255.0, 255.0) // double
48
- #define DARG_U_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 0.0, 100.0) // double
49
- #define DARG_R_PRCT(argname) get_arg_r(argname, env, sig, pstate, traces, - 100.0, 100.0) // double
50
-
51
- // macros for color related inputs (rbg and alpha/opacity values)
52
- #define COLOR_NUM(argname) color_num(argname, env, sig, pstate, traces) // double
53
- #define ALPHA_NUM(argname) alpha_num(argname, env, sig, pstate, traces) // double
54
-
55
- namespace Sass {
56
- using std::stringstream;
57
- using std::endl;
58
-
59
- Definition_Ptr make_native_function(Signature sig, Native_Function func, Context& ctx)
60
- {
61
- Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[built-in function]"));
62
- sig_parser.lex<Prelexer::identifier>();
63
- std::string name(Util::normalize_underscores(sig_parser.lexed));
64
- Parameters_Obj params = sig_parser.parse_parameters();
65
- return SASS_MEMORY_NEW(Definition,
66
- ParserState("[built-in function]"),
67
- sig,
68
- name,
69
- params,
70
- func,
71
- false);
72
- }
73
-
74
- Definition_Ptr make_c_function(Sass_Function_Entry c_func, Context& ctx)
75
- {
76
- using namespace Prelexer;
77
-
78
- const char* sig = sass_function_get_signature(c_func);
79
- Parser sig_parser = Parser::from_c_str(sig, ctx, ctx.traces, ParserState("[c function]"));
80
- // allow to overload generic callback plus @warn, @error and @debug with custom functions
81
- sig_parser.lex < alternatives < identifier, exactly <'*'>,
82
- exactly < Constants::warn_kwd >,
83
- exactly < Constants::error_kwd >,
84
- exactly < Constants::debug_kwd >
85
- > >();
86
- std::string name(Util::normalize_underscores(sig_parser.lexed));
87
- Parameters_Obj params = sig_parser.parse_parameters();
88
- return SASS_MEMORY_NEW(Definition,
89
- ParserState("[c function]"),
90
- sig,
91
- name,
92
- params,
93
- c_func,
94
- false, true);
95
- }
96
-
97
- std::string function_name(Signature sig)
98
- {
99
- std::string str(sig);
100
- return str.substr(0, str.find('('));
101
- }
102
-
103
- namespace Functions {
104
-
105
- inline void handle_utf8_error (const ParserState& pstate, Backtraces traces)
106
- {
107
- try {
108
- throw;
109
- }
110
- catch (utf8::invalid_code_point) {
111
- std::string msg("utf8::invalid_code_point");
112
- error(msg, pstate, traces);
113
- }
114
- catch (utf8::not_enough_room) {
115
- std::string msg("utf8::not_enough_room");
116
- error(msg, pstate, traces);
117
- }
118
- catch (utf8::invalid_utf8) {
119
- std::string msg("utf8::invalid_utf8");
120
- error(msg, pstate, traces);
121
- }
122
- catch (...) { throw; }
123
- }
124
-
125
- template <typename T>
126
- T* get_arg(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
127
- {
128
- // Minimal error handling -- the expectation is that built-ins will be written correctly!
129
- T* val = Cast<T>(env[argname]);
130
- if (!val) {
131
- std::string msg("argument `");
132
- msg += argname;
133
- msg += "` of `";
134
- msg += sig;
135
- msg += "` must be a ";
136
- msg += T::type_name();
137
- error(msg, pstate, traces);
138
- }
139
- return val;
140
- }
141
-
142
- Map_Ptr get_arg_m(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx)
143
- {
144
- // Minimal error handling -- the expectation is that built-ins will be written correctly!
145
- Map_Ptr val = Cast<Map>(env[argname]);
146
- if (val) return val;
147
-
148
- List_Ptr lval = Cast<List>(env[argname]);
149
- if (lval && lval->length() == 0) return SASS_MEMORY_NEW(Map, pstate, 0);
150
-
151
- // fallback on get_arg for error handling
152
- val = get_arg<Map>(argname, env, sig, pstate, traces);
153
- return val;
154
- }
155
-
156
- double get_arg_r(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, double lo, double hi)
157
- {
158
- // Minimal error handling -- the expectation is that built-ins will be written correctly!
159
- Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
160
- Number tmpnr(val);
161
- tmpnr.reduce();
162
- double v = tmpnr.value();
163
- if (!(lo <= v && v <= hi)) {
164
- std::stringstream msg;
165
- msg << "argument `" << argname << "` of `" << sig << "` must be between ";
166
- msg << lo << " and " << hi;
167
- error(msg.str(), pstate, traces);
168
- }
169
- return v;
170
- }
171
-
172
- Number_Ptr get_arg_n(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
173
- {
174
- // Minimal error handling -- the expectation is that built-ins will be written correctly!
175
- Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
176
- val = SASS_MEMORY_COPY(val);
177
- val->reduce();
178
- return val;
179
- }
180
-
181
- double get_arg_v(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
182
- {
183
- // Minimal error handling -- the expectation is that built-ins will be written correctly!
184
- Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
185
- Number tmpnr(val);
186
- tmpnr.reduce();
187
- /*
188
- if (tmpnr.unit() == "%") {
189
- tmpnr.value(tmpnr.value() / 100);
190
- tmpnr.numerators.clear();
191
- } else {
192
- if (!tmpnr.is_unitless()) error("argument " + argname + " of `" + std::string(sig) + "` must be unitless", pstate);
193
- }
194
- */
195
- return tmpnr.value();
196
- }
197
-
198
- double get_arg_val(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
199
- {
200
- // Minimal error handling -- the expectation is that built-ins will be written correctly!
201
- Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
202
- Number tmpnr(val);
203
- tmpnr.reduce();
204
- return tmpnr.value();
205
- }
206
-
207
- double color_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces)
208
- {
209
- Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
210
- Number tmpnr(val);
211
- tmpnr.reduce();
212
- if (tmpnr.unit() == "%") {
213
- return std::min(std::max(tmpnr.value() * 255 / 100.0, 0.0), 255.0);
214
- } else {
215
- return std::min(std::max(tmpnr.value(), 0.0), 255.0);
216
- }
217
- }
218
-
219
-
220
- inline double alpha_num(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces) {
221
- Number_Ptr val = get_arg<Number>(argname, env, sig, pstate, traces);
222
- Number tmpnr(val);
223
- tmpnr.reduce();
224
- if (tmpnr.unit() == "%") {
225
- return std::min(std::max(tmpnr.value(), 0.0), 100.0);
226
- } else {
227
- return std::min(std::max(tmpnr.value(), 0.0), 1.0);
228
- }
229
- }
230
-
231
- #define ARGSEL(argname, seltype, contextualize) get_arg_sel<seltype>(argname, env, sig, pstate, traces, ctx)
232
-
233
- template <typename T>
234
- T get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx);
235
-
236
- template <>
237
- Selector_List_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) {
238
- Expression_Obj exp = ARG(argname, Expression);
239
- if (exp->concrete_type() == Expression::NULL_VAL) {
240
- std::stringstream msg;
241
- msg << argname << ": null is not a valid selector: it must be a string,\n";
242
- msg << "a list of strings, or a list of lists of strings for `" << function_name(sig) << "'";
243
- error(msg.str(), pstate, traces);
244
- }
245
- if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
246
- str->quote_mark(0);
247
- }
248
- std::string exp_src = exp->to_string(ctx.c_options);
249
- return Parser::parse_selector(exp_src.c_str(), ctx, traces);
250
- }
251
-
252
- template <>
253
- Compound_Selector_Obj get_arg_sel(const std::string& argname, Env& env, Signature sig, ParserState pstate, Backtraces traces, Context& ctx) {
254
- Expression_Obj exp = ARG(argname, Expression);
255
- if (exp->concrete_type() == Expression::NULL_VAL) {
256
- std::stringstream msg;
257
- msg << argname << ": null is not a string for `" << function_name(sig) << "'";
258
- error(msg.str(), pstate, traces);
259
- }
260
- if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
261
- str->quote_mark(0);
262
- }
263
- std::string exp_src = exp->to_string(ctx.c_options);
264
- Selector_List_Obj sel_list = Parser::parse_selector(exp_src.c_str(), ctx, traces);
265
- if (sel_list->length() == 0) return NULL;
266
- Complex_Selector_Obj first = sel_list->first();
267
- if (!first->tail()) return first->head();
268
- return first->tail()->head();
269
- }
270
-
271
- #ifdef __MINGW32__
272
- uint64_t GetSeed()
273
- {
274
- HCRYPTPROV hp = 0;
275
- BYTE rb[8];
276
- CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
277
- CryptGenRandom(hp, sizeof(rb), rb);
278
- CryptReleaseContext(hp, 0);
279
-
280
- uint64_t seed;
281
- memcpy(&seed, &rb[0], sizeof(seed));
282
-
283
- return seed;
284
- }
285
- #else
286
- uint64_t GetSeed()
287
- {
288
- std::random_device rd;
289
- return rd();
290
- }
291
- #endif
292
-
293
- // note: the performance of many implementations of
294
- // random_device degrades sharply once the entropy pool
295
- // is exhausted. For practical use, random_device is
296
- // generally only used to seed a PRNG such as mt19937.
297
- static std::mt19937 rand(static_cast<unsigned int>(GetSeed()));
298
-
299
- // features
300
- static std::set<std::string> features {
301
- "global-variable-shadowing",
302
- "extend-selector-pseudoclass",
303
- "at-error",
304
- "units-level-3",
305
- "custom-property"
306
- };
307
-
308
- ////////////////
309
- // RGB FUNCTIONS
310
- ////////////////
311
-
312
- inline bool special_number(String_Constant_Ptr s) {
313
- if (s) {
314
- std::string calc("calc(");
315
- std::string var("var(");
316
- std::string ss(s->value());
317
- return std::equal(calc.begin(), calc.end(), ss.begin()) ||
318
- std::equal(var.begin(), var.end(), ss.begin());
319
- }
320
- return false;
321
- }
322
-
323
- Signature rgb_sig = "rgb($red, $green, $blue)";
324
- BUILT_IN(rgb)
325
- {
326
- if (
327
- special_number(Cast<String_Constant>(env["$red"])) ||
328
- special_number(Cast<String_Constant>(env["$green"])) ||
329
- special_number(Cast<String_Constant>(env["$blue"]))
330
- ) {
331
- return SASS_MEMORY_NEW(String_Constant, pstate, "rgb("
332
- + env["$red"]->to_string()
333
- + ", "
334
- + env["$green"]->to_string()
335
- + ", "
336
- + env["$blue"]->to_string()
337
- + ")"
338
- );
339
- }
340
-
341
- return SASS_MEMORY_NEW(Color,
342
- pstate,
343
- COLOR_NUM("$red"),
344
- COLOR_NUM("$green"),
345
- COLOR_NUM("$blue"));
346
- }
347
-
348
- Signature rgba_4_sig = "rgba($red, $green, $blue, $alpha)";
349
- BUILT_IN(rgba_4)
350
- {
351
- if (
352
- special_number(Cast<String_Constant>(env["$red"])) ||
353
- special_number(Cast<String_Constant>(env["$green"])) ||
354
- special_number(Cast<String_Constant>(env["$blue"])) ||
355
- special_number(Cast<String_Constant>(env["$alpha"]))
356
- ) {
357
- return SASS_MEMORY_NEW(String_Constant, pstate, "rgba("
358
- + env["$red"]->to_string()
359
- + ", "
360
- + env["$green"]->to_string()
361
- + ", "
362
- + env["$blue"]->to_string()
363
- + ", "
364
- + env["$alpha"]->to_string()
365
- + ")"
366
- );
367
- }
368
-
369
- return SASS_MEMORY_NEW(Color,
370
- pstate,
371
- COLOR_NUM("$red"),
372
- COLOR_NUM("$green"),
373
- COLOR_NUM("$blue"),
374
- ALPHA_NUM("$alpha"));
375
- }
376
-
377
- Signature rgba_2_sig = "rgba($color, $alpha)";
378
- BUILT_IN(rgba_2)
379
- {
380
- if (
381
- special_number(Cast<String_Constant>(env["$color"]))
382
- ) {
383
- return SASS_MEMORY_NEW(String_Constant, pstate, "rgba("
384
- + env["$color"]->to_string()
385
- + ", "
386
- + env["$alpha"]->to_string()
387
- + ")"
388
- );
389
- }
390
-
391
- Color_Ptr c_arg = ARG("$color", Color);
392
-
393
- if (
394
- special_number(Cast<String_Constant>(env["$alpha"]))
395
- ) {
396
- std::stringstream strm;
397
- strm << "rgba("
398
- << (int)c_arg->r() << ", "
399
- << (int)c_arg->g() << ", "
400
- << (int)c_arg->b() << ", "
401
- << env["$alpha"]->to_string()
402
- << ")";
403
- return SASS_MEMORY_NEW(String_Constant, pstate, strm.str());
404
- }
405
-
406
- Color_Ptr new_c = SASS_MEMORY_COPY(c_arg);
407
- new_c->a(ALPHA_NUM("$alpha"));
408
- new_c->disp("");
409
- return new_c;
410
- }
411
-
412
- Signature red_sig = "red($color)";
413
- BUILT_IN(red)
414
- { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->r()); }
415
-
416
- Signature green_sig = "green($color)";
417
- BUILT_IN(green)
418
- { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->g()); }
419
-
420
- Signature blue_sig = "blue($color)";
421
- BUILT_IN(blue)
422
- { return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->b()); }
423
-
424
- Color* colormix(Context& ctx, ParserState& pstate, Color* color1, Color* color2, double weight) {
425
- double p = weight/100;
426
- double w = 2*p - 1;
427
- double a = color1->a() - color2->a();
428
-
429
- double w1 = (((w * a == -1) ? w : (w + a)/(1 + w*a)) + 1)/2.0;
430
- double w2 = 1 - w1;
431
-
432
- return SASS_MEMORY_NEW(Color,
433
- pstate,
434
- Sass::round(w1*color1->r() + w2*color2->r(), ctx.c_options.precision),
435
- Sass::round(w1*color1->g() + w2*color2->g(), ctx.c_options.precision),
436
- Sass::round(w1*color1->b() + w2*color2->b(), ctx.c_options.precision),
437
- color1->a()*p + color2->a()*(1-p));
438
- }
439
-
440
- Signature mix_sig = "mix($color-1, $color-2, $weight: 50%)";
441
- BUILT_IN(mix)
442
- {
443
- Color_Obj color1 = ARG("$color-1", Color);
444
- Color_Obj color2 = ARG("$color-2", Color);
445
- double weight = DARG_U_PRCT("$weight");
446
- return colormix(ctx, pstate, color1, color2, weight);
447
-
448
- }
449
-
450
- ////////////////
451
- // HSL FUNCTIONS
452
- ////////////////
453
-
454
- // RGB to HSL helper function
455
- struct HSL { double h; double s; double l; };
456
- HSL rgb_to_hsl(double r, double g, double b)
457
- {
458
-
459
- // Algorithm from http://en.wikipedia.org/wiki/wHSL_and_HSV#Conversion_from_RGB_to_HSL_or_HSV
460
- r /= 255.0; g /= 255.0; b /= 255.0;
461
-
462
- double max = std::max(r, std::max(g, b));
463
- double min = std::min(r, std::min(g, b));
464
- double delta = max - min;
465
-
466
- double h = 0;
467
- double s;
468
- double l = (max + min) / 2.0;
469
-
470
- if (max == min) {
471
- h = s = 0; // achromatic
472
- }
473
- else {
474
- if (l < 0.5) s = delta / (max + min);
475
- else s = delta / (2.0 - max - min);
476
-
477
- if (r == max) h = (g - b) / delta + (g < b ? 6 : 0);
478
- else if (g == max) h = (b - r) / delta + 2;
479
- else if (b == max) h = (r - g) / delta + 4;
480
- }
481
-
482
- HSL hsl_struct;
483
- hsl_struct.h = h / 6 * 360;
484
- hsl_struct.s = s * 100;
485
- hsl_struct.l = l * 100;
486
-
487
- return hsl_struct;
488
- }
489
-
490
- // hue to RGB helper function
491
- double h_to_rgb(double m1, double m2, double h) {
492
- while (h < 0) h += 1;
493
- while (h > 1) h -= 1;
494
- if (h*6.0 < 1) return m1 + (m2 - m1)*h*6;
495
- if (h*2.0 < 1) return m2;
496
- if (h*3.0 < 2) return m1 + (m2 - m1) * (2.0/3.0 - h)*6;
497
- return m1;
498
- }
499
-
500
- Color_Ptr hsla_impl(double h, double s, double l, double a, Context& ctx, ParserState pstate)
501
- {
502
- h /= 360.0;
503
- s /= 100.0;
504
- l /= 100.0;
505
-
506
- if (l < 0) l = 0;
507
- if (s < 0) s = 0;
508
- if (l > 1) l = 1;
509
- if (s > 1) s = 1;
510
- while (h < 0) h += 1;
511
- while (h > 1) h -= 1;
512
-
513
- // if saturation is exacly zero, we loose
514
- // information for hue, since it will evaluate
515
- // to zero if converted back from rgb. Setting
516
- // saturation to a very tiny number solves this.
517
- if (s == 0) s = 1e-10;
518
-
519
- // Algorithm from the CSS3 spec: http://www.w3.org/TR/css3-color/#hsl-color.
520
- double m2;
521
- if (l <= 0.5) m2 = l*(s+1.0);
522
- else m2 = (l+s)-(l*s);
523
- double m1 = (l*2.0)-m2;
524
- // round the results -- consider moving this into the Color constructor
525
- double r = (h_to_rgb(m1, m2, h + 1.0/3.0) * 255.0);
526
- double g = (h_to_rgb(m1, m2, h) * 255.0);
527
- double b = (h_to_rgb(m1, m2, h - 1.0/3.0) * 255.0);
528
-
529
- return SASS_MEMORY_NEW(Color, pstate, r, g, b, a);
530
- }
531
-
532
- Signature hsl_sig = "hsl($hue, $saturation, $lightness)";
533
- BUILT_IN(hsl)
534
- {
535
- if (
536
- special_number(Cast<String_Constant>(env["$hue"])) ||
537
- special_number(Cast<String_Constant>(env["$saturation"])) ||
538
- special_number(Cast<String_Constant>(env["$lightness"]))
539
- ) {
540
- return SASS_MEMORY_NEW(String_Constant, pstate, "hsl("
541
- + env["$hue"]->to_string()
542
- + ", "
543
- + env["$saturation"]->to_string()
544
- + ", "
545
- + env["$lightness"]->to_string()
546
- + ")"
547
- );
548
- }
549
-
550
- return hsla_impl(ARGVAL("$hue"),
551
- ARGVAL("$saturation"),
552
- ARGVAL("$lightness"),
553
- 1.0,
554
- ctx,
555
- pstate);
556
- }
557
-
558
- Signature hsla_sig = "hsla($hue, $saturation, $lightness, $alpha)";
559
- BUILT_IN(hsla)
560
- {
561
- if (
562
- special_number(Cast<String_Constant>(env["$hue"])) ||
563
- special_number(Cast<String_Constant>(env["$saturation"])) ||
564
- special_number(Cast<String_Constant>(env["$lightness"])) ||
565
- special_number(Cast<String_Constant>(env["$alpha"]))
566
- ) {
567
- return SASS_MEMORY_NEW(String_Constant, pstate, "hsla("
568
- + env["$hue"]->to_string()
569
- + ", "
570
- + env["$saturation"]->to_string()
571
- + ", "
572
- + env["$lightness"]->to_string()
573
- + ", "
574
- + env["$alpha"]->to_string()
575
- + ")"
576
- );
577
- }
578
-
579
- return hsla_impl(ARGVAL("$hue"),
580
- ARGVAL("$saturation"),
581
- ARGVAL("$lightness"),
582
- ARGVAL("$alpha"),
583
- ctx,
584
- pstate);
585
- }
586
-
587
- Signature hue_sig = "hue($color)";
588
- BUILT_IN(hue)
589
- {
590
- Color_Ptr rgb_color = ARG("$color", Color);
591
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
592
- rgb_color->g(),
593
- rgb_color->b());
594
- return SASS_MEMORY_NEW(Number, pstate, hsl_color.h, "deg");
595
- }
596
-
597
- Signature saturation_sig = "saturation($color)";
598
- BUILT_IN(saturation)
599
- {
600
- Color_Ptr rgb_color = ARG("$color", Color);
601
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
602
- rgb_color->g(),
603
- rgb_color->b());
604
- return SASS_MEMORY_NEW(Number, pstate, hsl_color.s, "%");
605
- }
606
-
607
- Signature lightness_sig = "lightness($color)";
608
- BUILT_IN(lightness)
609
- {
610
- Color_Ptr rgb_color = ARG("$color", Color);
611
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
612
- rgb_color->g(),
613
- rgb_color->b());
614
- return SASS_MEMORY_NEW(Number, pstate, hsl_color.l, "%");
615
- }
616
-
617
- Signature adjust_hue_sig = "adjust-hue($color, $degrees)";
618
- BUILT_IN(adjust_hue)
619
- {
620
- Color_Ptr rgb_color = ARG("$color", Color);
621
- double degrees = ARGVAL("$degrees");
622
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
623
- rgb_color->g(),
624
- rgb_color->b());
625
- return hsla_impl(hsl_color.h + degrees,
626
- hsl_color.s,
627
- hsl_color.l,
628
- rgb_color->a(),
629
- ctx,
630
- pstate);
631
- }
632
-
633
- Signature lighten_sig = "lighten($color, $amount)";
634
- BUILT_IN(lighten)
635
- {
636
- Color_Ptr rgb_color = ARG("$color", Color);
637
- double amount = DARG_U_PRCT("$amount");
638
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
639
- rgb_color->g(),
640
- rgb_color->b());
641
- //Check lightness is not negative before lighten it
642
- double hslcolorL = hsl_color.l;
643
- if (hslcolorL < 0) {
644
- hslcolorL = 0;
645
- }
646
-
647
- return hsla_impl(hsl_color.h,
648
- hsl_color.s,
649
- hslcolorL + amount,
650
- rgb_color->a(),
651
- ctx,
652
- pstate);
653
- }
654
-
655
- Signature darken_sig = "darken($color, $amount)";
656
- BUILT_IN(darken)
657
- {
658
- Color_Ptr rgb_color = ARG("$color", Color);
659
- double amount = DARG_U_PRCT("$amount");
660
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
661
- rgb_color->g(),
662
- rgb_color->b());
663
-
664
- //Check lightness if not over 100, before darken it
665
- double hslcolorL = hsl_color.l;
666
- if (hslcolorL > 100) {
667
- hslcolorL = 100;
668
- }
669
-
670
- return hsla_impl(hsl_color.h,
671
- hsl_color.s,
672
- hslcolorL - amount,
673
- rgb_color->a(),
674
- ctx,
675
- pstate);
676
- }
677
-
678
- Signature saturate_sig = "saturate($color, $amount: false)";
679
- BUILT_IN(saturate)
680
- {
681
- // CSS3 filter function overload: pass literal through directly
682
- if (!Cast<Number>(env["$amount"])) {
683
- return SASS_MEMORY_NEW(String_Quoted, pstate, "saturate(" + env["$color"]->to_string(ctx.c_options) + ")");
684
- }
685
-
686
- double amount = DARG_U_PRCT("$amount");
687
- Color_Ptr rgb_color = ARG("$color", Color);
688
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
689
- rgb_color->g(),
690
- rgb_color->b());
691
-
692
- double hslcolorS = hsl_color.s + amount;
693
-
694
- // Saturation cannot be below 0 or above 100
695
- if (hslcolorS < 0) {
696
- hslcolorS = 0;
697
- }
698
- if (hslcolorS > 100) {
699
- hslcolorS = 100;
700
- }
701
-
702
- return hsla_impl(hsl_color.h,
703
- hslcolorS,
704
- hsl_color.l,
705
- rgb_color->a(),
706
- ctx,
707
- pstate);
708
- }
709
-
710
- Signature desaturate_sig = "desaturate($color, $amount)";
711
- BUILT_IN(desaturate)
712
- {
713
- Color_Ptr rgb_color = ARG("$color", Color);
714
- double amount = DARG_U_PRCT("$amount");
715
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
716
- rgb_color->g(),
717
- rgb_color->b());
718
-
719
- double hslcolorS = hsl_color.s - amount;
720
-
721
- // Saturation cannot be below 0 or above 100
722
- if (hslcolorS <= 0) {
723
- hslcolorS = 0;
724
- }
725
- if (hslcolorS > 100) {
726
- hslcolorS = 100;
727
- }
728
-
729
- return hsla_impl(hsl_color.h,
730
- hslcolorS,
731
- hsl_color.l,
732
- rgb_color->a(),
733
- ctx,
734
- pstate);
735
- }
736
-
737
- Signature grayscale_sig = "grayscale($color)";
738
- BUILT_IN(grayscale)
739
- {
740
- // CSS3 filter function overload: pass literal through directly
741
- Number_Ptr amount = Cast<Number>(env["$color"]);
742
- if (amount) {
743
- return SASS_MEMORY_NEW(String_Quoted, pstate, "grayscale(" + amount->to_string(ctx.c_options) + ")");
744
- }
745
-
746
- Color_Ptr rgb_color = ARG("$color", Color);
747
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
748
- rgb_color->g(),
749
- rgb_color->b());
750
- return hsla_impl(hsl_color.h,
751
- 0.0,
752
- hsl_color.l,
753
- rgb_color->a(),
754
- ctx,
755
- pstate);
756
- }
757
-
758
- Signature complement_sig = "complement($color)";
759
- BUILT_IN(complement)
760
- {
761
- Color_Ptr rgb_color = ARG("$color", Color);
762
- HSL hsl_color = rgb_to_hsl(rgb_color->r(),
763
- rgb_color->g(),
764
- rgb_color->b());
765
- return hsla_impl(hsl_color.h - 180.0,
766
- hsl_color.s,
767
- hsl_color.l,
768
- rgb_color->a(),
769
- ctx,
770
- pstate);
771
- }
772
-
773
- Signature invert_sig = "invert($color, $weight: 100%)";
774
- BUILT_IN(invert)
775
- {
776
- // CSS3 filter function overload: pass literal through directly
777
- Number_Ptr amount = Cast<Number>(env["$color"]);
778
- if (amount) {
779
- return SASS_MEMORY_NEW(String_Quoted, pstate, "invert(" + amount->to_string(ctx.c_options) + ")");
780
- }
781
-
782
- double weight = DARG_U_PRCT("$weight");
783
- Color_Ptr rgb_color = ARG("$color", Color);
784
- Color_Obj inv = SASS_MEMORY_NEW(Color,
785
- pstate,
786
- 255 - rgb_color->r(),
787
- 255 - rgb_color->g(),
788
- 255 - rgb_color->b(),
789
- rgb_color->a());
790
- return colormix(ctx, pstate, inv, rgb_color, weight);
791
- }
792
-
793
- ////////////////////
794
- // OPACITY FUNCTIONS
795
- ////////////////////
796
- Signature alpha_sig = "alpha($color)";
797
- Signature opacity_sig = "opacity($color)";
798
- BUILT_IN(alpha)
799
- {
800
- String_Constant_Ptr ie_kwd = Cast<String_Constant>(env["$color"]);
801
- if (ie_kwd) {
802
- return SASS_MEMORY_NEW(String_Quoted, pstate, "alpha(" + ie_kwd->value() + ")");
803
- }
804
-
805
- // CSS3 filter function overload: pass literal through directly
806
- Number_Ptr amount = Cast<Number>(env["$color"]);
807
- if (amount) {
808
- return SASS_MEMORY_NEW(String_Quoted, pstate, "opacity(" + amount->to_string(ctx.c_options) + ")");
809
- }
810
-
811
- return SASS_MEMORY_NEW(Number, pstate, ARG("$color", Color)->a());
812
- }
813
-
814
- Signature opacify_sig = "opacify($color, $amount)";
815
- Signature fade_in_sig = "fade-in($color, $amount)";
816
- BUILT_IN(opacify)
817
- {
818
- Color_Ptr color = ARG("$color", Color);
819
- double amount = DARG_U_FACT("$amount");
820
- double alpha = std::min(color->a() + amount, 1.0);
821
- return SASS_MEMORY_NEW(Color,
822
- pstate,
823
- color->r(),
824
- color->g(),
825
- color->b(),
826
- alpha);
827
- }
828
-
829
- Signature transparentize_sig = "transparentize($color, $amount)";
830
- Signature fade_out_sig = "fade-out($color, $amount)";
831
- BUILT_IN(transparentize)
832
- {
833
- Color_Ptr color = ARG("$color", Color);
834
- double amount = DARG_U_FACT("$amount");
835
- double alpha = std::max(color->a() - amount, 0.0);
836
- return SASS_MEMORY_NEW(Color,
837
- pstate,
838
- color->r(),
839
- color->g(),
840
- color->b(),
841
- alpha);
842
- }
843
-
844
- ////////////////////////
845
- // OTHER COLOR FUNCTIONS
846
- ////////////////////////
847
-
848
- Signature adjust_color_sig = "adjust-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
849
- BUILT_IN(adjust_color)
850
- {
851
- Color_Ptr color = ARG("$color", Color);
852
- Number_Ptr r = Cast<Number>(env["$red"]);
853
- Number_Ptr g = Cast<Number>(env["$green"]);
854
- Number_Ptr b = Cast<Number>(env["$blue"]);
855
- Number_Ptr h = Cast<Number>(env["$hue"]);
856
- Number_Ptr s = Cast<Number>(env["$saturation"]);
857
- Number_Ptr l = Cast<Number>(env["$lightness"]);
858
- Number_Ptr a = Cast<Number>(env["$alpha"]);
859
-
860
- bool rgb = r || g || b;
861
- bool hsl = h || s || l;
862
-
863
- if (rgb && hsl) {
864
- error("Cannot specify HSL and RGB values for a color at the same time for `adjust-color'", pstate, traces);
865
- }
866
- if (rgb) {
867
- double rr = r ? DARG_R_BYTE("$red") : 0;
868
- double gg = g ? DARG_R_BYTE("$green") : 0;
869
- double bb = b ? DARG_R_BYTE("$blue") : 0;
870
- double aa = a ? DARG_R_FACT("$alpha") : 0;
871
- return SASS_MEMORY_NEW(Color,
872
- pstate,
873
- color->r() + rr,
874
- color->g() + gg,
875
- color->b() + bb,
876
- color->a() + aa);
877
- }
878
- if (hsl) {
879
- HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
880
- double ss = s ? DARG_R_PRCT("$saturation") : 0;
881
- double ll = l ? DARG_R_PRCT("$lightness") : 0;
882
- double aa = a ? DARG_R_FACT("$alpha") : 0;
883
- return hsla_impl(hsl_struct.h + (h ? h->value() : 0),
884
- hsl_struct.s + ss,
885
- hsl_struct.l + ll,
886
- color->a() + aa,
887
- ctx,
888
- pstate);
889
- }
890
- if (a) {
891
- return SASS_MEMORY_NEW(Color,
892
- pstate,
893
- color->r(),
894
- color->g(),
895
- color->b(),
896
- color->a() + (a ? a->value() : 0));
897
- }
898
- error("not enough arguments for `adjust-color'", pstate, traces);
899
- // unreachable
900
- return color;
901
- }
902
-
903
- Signature scale_color_sig = "scale-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
904
- BUILT_IN(scale_color)
905
- {
906
- Color_Ptr color = ARG("$color", Color);
907
- Number_Ptr r = Cast<Number>(env["$red"]);
908
- Number_Ptr g = Cast<Number>(env["$green"]);
909
- Number_Ptr b = Cast<Number>(env["$blue"]);
910
- Number_Ptr h = Cast<Number>(env["$hue"]);
911
- Number_Ptr s = Cast<Number>(env["$saturation"]);
912
- Number_Ptr l = Cast<Number>(env["$lightness"]);
913
- Number_Ptr a = Cast<Number>(env["$alpha"]);
914
-
915
- bool rgb = r || g || b;
916
- bool hsl = h || s || l;
917
-
918
- if (rgb && hsl) {
919
- error("Cannot specify HSL and RGB values for a color at the same time for `scale-color'", pstate, traces);
920
- }
921
- if (rgb) {
922
- double rscale = (r ? DARG_R_PRCT("$red") : 0.0) / 100.0;
923
- double gscale = (g ? DARG_R_PRCT("$green") : 0.0) / 100.0;
924
- double bscale = (b ? DARG_R_PRCT("$blue") : 0.0) / 100.0;
925
- double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0;
926
- return SASS_MEMORY_NEW(Color,
927
- pstate,
928
- color->r() + rscale * (rscale > 0.0 ? 255 - color->r() : color->r()),
929
- color->g() + gscale * (gscale > 0.0 ? 255 - color->g() : color->g()),
930
- color->b() + bscale * (bscale > 0.0 ? 255 - color->b() : color->b()),
931
- color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()));
932
- }
933
- if (hsl) {
934
- double hscale = (h ? DARG_R_PRCT("$hue") : 0.0) / 100.0;
935
- double sscale = (s ? DARG_R_PRCT("$saturation") : 0.0) / 100.0;
936
- double lscale = (l ? DARG_R_PRCT("$lightness") : 0.0) / 100.0;
937
- double ascale = (a ? DARG_R_PRCT("$alpha") : 0.0) / 100.0;
938
- HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
939
- hsl_struct.h += hscale * (hscale > 0.0 ? 360.0 - hsl_struct.h : hsl_struct.h);
940
- hsl_struct.s += sscale * (sscale > 0.0 ? 100.0 - hsl_struct.s : hsl_struct.s);
941
- hsl_struct.l += lscale * (lscale > 0.0 ? 100.0 - hsl_struct.l : hsl_struct.l);
942
- double alpha = color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a());
943
- return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
944
- }
945
- if (a) {
946
- double ascale = (DARG_R_PRCT("$alpha")) / 100.0;
947
- return SASS_MEMORY_NEW(Color,
948
- pstate,
949
- color->r(),
950
- color->g(),
951
- color->b(),
952
- color->a() + ascale * (ascale > 0.0 ? 1.0 - color->a() : color->a()));
953
- }
954
- error("not enough arguments for `scale-color'", pstate, traces);
955
- // unreachable
956
- return color;
957
- }
958
-
959
- Signature change_color_sig = "change-color($color, $red: false, $green: false, $blue: false, $hue: false, $saturation: false, $lightness: false, $alpha: false)";
960
- BUILT_IN(change_color)
961
- {
962
- Color_Ptr color = ARG("$color", Color);
963
- Number_Ptr r = Cast<Number>(env["$red"]);
964
- Number_Ptr g = Cast<Number>(env["$green"]);
965
- Number_Ptr b = Cast<Number>(env["$blue"]);
966
- Number_Ptr h = Cast<Number>(env["$hue"]);
967
- Number_Ptr s = Cast<Number>(env["$saturation"]);
968
- Number_Ptr l = Cast<Number>(env["$lightness"]);
969
- Number_Ptr a = Cast<Number>(env["$alpha"]);
970
-
971
- bool rgb = r || g || b;
972
- bool hsl = h || s || l;
973
-
974
- if (rgb && hsl) {
975
- error("Cannot specify HSL and RGB values for a color at the same time for `change-color'", pstate, traces);
976
- }
977
- if (rgb) {
978
- return SASS_MEMORY_NEW(Color,
979
- pstate,
980
- r ? DARG_U_BYTE("$red") : color->r(),
981
- g ? DARG_U_BYTE("$green") : color->g(),
982
- b ? DARG_U_BYTE("$blue") : color->b(),
983
- a ? DARG_U_BYTE("$alpha") : color->a());
984
- }
985
- if (hsl) {
986
- HSL hsl_struct = rgb_to_hsl(color->r(), color->g(), color->b());
987
- if (h) hsl_struct.h = std::fmod(h->value(), 360.0);
988
- if (s) hsl_struct.s = DARG_U_PRCT("$saturation");
989
- if (l) hsl_struct.l = DARG_U_PRCT("$lightness");
990
- double alpha = a ? DARG_U_FACT("$alpha") : color->a();
991
- return hsla_impl(hsl_struct.h, hsl_struct.s, hsl_struct.l, alpha, ctx, pstate);
992
- }
993
- if (a) {
994
- double alpha = DARG_U_FACT("$alpha");
995
- return SASS_MEMORY_NEW(Color,
996
- pstate,
997
- color->r(),
998
- color->g(),
999
- color->b(),
1000
- alpha);
1001
- }
1002
- error("not enough arguments for `change-color'", pstate, traces);
1003
- // unreachable
1004
- return color;
1005
- }
1006
-
1007
- template <size_t range>
1008
- static double cap_channel(double c) {
1009
- if (c > range) return range;
1010
- else if (c < 0) return 0;
1011
- else return c;
1012
- }
1013
-
1014
- Signature ie_hex_str_sig = "ie-hex-str($color)";
1015
- BUILT_IN(ie_hex_str)
1016
- {
1017
- Color_Ptr c = ARG("$color", Color);
1018
- double r = cap_channel<0xff>(c->r());
1019
- double g = cap_channel<0xff>(c->g());
1020
- double b = cap_channel<0xff>(c->b());
1021
- double a = cap_channel<1> (c->a()) * 255;
1022
-
1023
- std::stringstream ss;
1024
- ss << '#' << std::setw(2) << std::setfill('0');
1025
- ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(a, ctx.c_options.precision));
1026
- ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(r, ctx.c_options.precision));
1027
- ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(g, ctx.c_options.precision));
1028
- ss << std::hex << std::setw(2) << static_cast<unsigned long>(Sass::round(b, ctx.c_options.precision));
1029
-
1030
- std::string result(ss.str());
1031
- for (size_t i = 0, L = result.length(); i < L; ++i) {
1032
- result[i] = std::toupper(result[i]);
1033
- }
1034
- return SASS_MEMORY_NEW(String_Quoted, pstate, result);
1035
- }
1036
-
1037
- ///////////////////
1038
- // STRING FUNCTIONS
1039
- ///////////////////
1040
-
1041
- Signature unquote_sig = "unquote($string)";
1042
- BUILT_IN(sass_unquote)
1043
- {
1044
- AST_Node_Obj arg = env["$string"];
1045
- if (String_Quoted_Ptr string_quoted = Cast<String_Quoted>(arg)) {
1046
- String_Constant_Ptr result = SASS_MEMORY_NEW(String_Constant, pstate, string_quoted->value());
1047
- // remember if the string was quoted (color tokens)
1048
- result->is_delayed(true); // delay colors
1049
- return result;
1050
- }
1051
- else if (String_Constant_Ptr str = Cast<String_Constant>(arg)) {
1052
- return str;
1053
- }
1054
- else if (Expression_Ptr ex = Cast<Expression>(arg)) {
1055
- Sass_Output_Style oldstyle = ctx.c_options.output_style;
1056
- ctx.c_options.output_style = SASS_STYLE_NESTED;
1057
- std::string val(arg->to_string(ctx.c_options));
1058
- val = Cast<Null>(arg) ? "null" : val;
1059
- ctx.c_options.output_style = oldstyle;
1060
-
1061
- deprecated_function("Passing " + val + ", a non-string value, to unquote()", pstate);
1062
- return ex;
1063
- }
1064
- throw std::runtime_error("Invalid Data Type for unquote");
1065
- }
1066
-
1067
- Signature quote_sig = "quote($string)";
1068
- BUILT_IN(sass_quote)
1069
- {
1070
- AST_Node_Obj arg = env["$string"];
1071
- // only set quote mark to true if already a string
1072
- if (String_Quoted_Ptr qstr = Cast<String_Quoted>(arg)) {
1073
- qstr->quote_mark('*');
1074
- return qstr;
1075
- }
1076
- // all other nodes must be converted to a string node
1077
- std::string str(quote(arg->to_string(ctx.c_options), String_Constant::double_quote()));
1078
- String_Quoted_Ptr result = SASS_MEMORY_NEW(String_Quoted, pstate, str);
1079
- result->quote_mark('*');
1080
- return result;
1081
- }
1082
-
1083
-
1084
- Signature str_length_sig = "str-length($string)";
1085
- BUILT_IN(str_length)
1086
- {
1087
- size_t len = std::string::npos;
1088
- try {
1089
- String_Constant_Ptr s = ARG("$string", String_Constant);
1090
- len = UTF_8::code_point_count(s->value(), 0, s->value().size());
1091
-
1092
- }
1093
- // handle any invalid utf8 errors
1094
- // other errors will be re-thrown
1095
- catch (...) { handle_utf8_error(pstate, traces); }
1096
- // return something even if we had an error (-1)
1097
- return SASS_MEMORY_NEW(Number, pstate, (double)len);
1098
- }
1099
-
1100
- Signature str_insert_sig = "str-insert($string, $insert, $index)";
1101
- BUILT_IN(str_insert)
1102
- {
1103
- std::string str;
1104
- try {
1105
- String_Constant_Ptr s = ARG("$string", String_Constant);
1106
- str = s->value();
1107
- str = unquote(str);
1108
- String_Constant_Ptr i = ARG("$insert", String_Constant);
1109
- std::string ins = i->value();
1110
- ins = unquote(ins);
1111
- double index = ARGVAL("$index");
1112
- size_t len = UTF_8::code_point_count(str, 0, str.size());
1113
-
1114
- if (index > 0 && index <= len) {
1115
- // positive and within string length
1116
- str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index) - 1), ins);
1117
- }
1118
- else if (index > len) {
1119
- // positive and past string length
1120
- str += ins;
1121
- }
1122
- else if (index == 0) {
1123
- str = ins + str;
1124
- }
1125
- else if (std::abs(index) <= len) {
1126
- // negative and within string length
1127
- index += len + 1;
1128
- str.insert(UTF_8::offset_at_position(str, static_cast<size_t>(index)), ins);
1129
- }
1130
- else {
1131
- // negative and past string length
1132
- str = ins + str;
1133
- }
1134
-
1135
- if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
1136
- if (ss->quote_mark()) str = quote(str);
1137
- }
1138
- }
1139
- // handle any invalid utf8 errors
1140
- // other errors will be re-thrown
1141
- catch (...) { handle_utf8_error(pstate, traces); }
1142
- return SASS_MEMORY_NEW(String_Quoted, pstate, str);
1143
- }
1144
-
1145
- Signature str_index_sig = "str-index($string, $substring)";
1146
- BUILT_IN(str_index)
1147
- {
1148
- size_t index = std::string::npos;
1149
- try {
1150
- String_Constant_Ptr s = ARG("$string", String_Constant);
1151
- String_Constant_Ptr t = ARG("$substring", String_Constant);
1152
- std::string str = s->value();
1153
- str = unquote(str);
1154
- std::string substr = t->value();
1155
- substr = unquote(substr);
1156
-
1157
- size_t c_index = str.find(substr);
1158
- if(c_index == std::string::npos) {
1159
- return SASS_MEMORY_NEW(Null, pstate);
1160
- }
1161
- index = UTF_8::code_point_count(str, 0, c_index) + 1;
1162
- }
1163
- // handle any invalid utf8 errors
1164
- // other errors will be re-thrown
1165
- catch (...) { handle_utf8_error(pstate, traces); }
1166
- // return something even if we had an error (-1)
1167
- return SASS_MEMORY_NEW(Number, pstate, (double)index);
1168
- }
1169
-
1170
- Signature str_slice_sig = "str-slice($string, $start-at, $end-at:-1)";
1171
- BUILT_IN(str_slice)
1172
- {
1173
- std::string newstr;
1174
- try {
1175
- String_Constant_Ptr s = ARG("$string", String_Constant);
1176
- double start_at = ARGVAL("$start-at");
1177
- double end_at = ARGVAL("$end-at");
1178
- String_Quoted_Ptr ss = Cast<String_Quoted>(s);
1179
-
1180
- std::string str = unquote(s->value());
1181
-
1182
- size_t size = utf8::distance(str.begin(), str.end());
1183
-
1184
- if (!Cast<Number>(env["$end-at"])) {
1185
- end_at = -1;
1186
- }
1187
-
1188
- if (end_at == 0 || (end_at + size) < 0) {
1189
- if (ss && ss->quote_mark()) newstr = quote("");
1190
- return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
1191
- }
1192
-
1193
- if (end_at < 0) {
1194
- end_at += size + 1;
1195
- if (end_at == 0) end_at = 1;
1196
- }
1197
- if (end_at > size) { end_at = (double)size; }
1198
- if (start_at < 0) {
1199
- start_at += size + 1;
1200
- if (start_at < 0) start_at = 0;
1201
- }
1202
- else if (start_at == 0) { ++ start_at; }
1203
-
1204
- if (start_at <= end_at)
1205
- {
1206
- std::string::iterator start = str.begin();
1207
- utf8::advance(start, start_at - 1, str.end());
1208
- std::string::iterator end = start;
1209
- utf8::advance(end, end_at - start_at + 1, str.end());
1210
- newstr = std::string(start, end);
1211
- }
1212
- if (ss) {
1213
- if(ss->quote_mark()) newstr = quote(newstr);
1214
- }
1215
- }
1216
- // handle any invalid utf8 errors
1217
- // other errors will be re-thrown
1218
- catch (...) { handle_utf8_error(pstate, traces); }
1219
- return SASS_MEMORY_NEW(String_Quoted, pstate, newstr);
1220
- }
1221
-
1222
- Signature to_upper_case_sig = "to-upper-case($string)";
1223
- BUILT_IN(to_upper_case)
1224
- {
1225
- String_Constant_Ptr s = ARG("$string", String_Constant);
1226
- std::string str = s->value();
1227
-
1228
- for (size_t i = 0, L = str.length(); i < L; ++i) {
1229
- if (Sass::Util::isAscii(str[i])) {
1230
- str[i] = std::toupper(str[i]);
1231
- }
1232
- }
1233
-
1234
- if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
1235
- String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
1236
- cpy->value(str);
1237
- return cpy;
1238
- } else {
1239
- return SASS_MEMORY_NEW(String_Quoted, pstate, str);
1240
- }
1241
- }
1242
-
1243
- Signature to_lower_case_sig = "to-lower-case($string)";
1244
- BUILT_IN(to_lower_case)
1245
- {
1246
- String_Constant_Ptr s = ARG("$string", String_Constant);
1247
- std::string str = s->value();
1248
-
1249
- for (size_t i = 0, L = str.length(); i < L; ++i) {
1250
- if (Sass::Util::isAscii(str[i])) {
1251
- str[i] = std::tolower(str[i]);
1252
- }
1253
- }
1254
-
1255
- if (String_Quoted_Ptr ss = Cast<String_Quoted>(s)) {
1256
- String_Quoted_Ptr cpy = SASS_MEMORY_COPY(ss);
1257
- cpy->value(str);
1258
- return cpy;
1259
- } else {
1260
- return SASS_MEMORY_NEW(String_Quoted, pstate, str);
1261
- }
1262
- }
1263
-
1264
- ///////////////////
1265
- // NUMBER FUNCTIONS
1266
- ///////////////////
1267
-
1268
- Signature percentage_sig = "percentage($number)";
1269
- BUILT_IN(percentage)
1270
- {
1271
- Number_Obj n = ARGN("$number");
1272
- if (!n->is_unitless()) error("argument $number of `" + std::string(sig) + "` must be unitless", pstate, traces);
1273
- return SASS_MEMORY_NEW(Number, pstate, n->value() * 100, "%");
1274
- }
1275
-
1276
- Signature round_sig = "round($number)";
1277
- BUILT_IN(round)
1278
- {
1279
- Number_Obj r = ARGN("$number");
1280
- r->value(Sass::round(r->value(), ctx.c_options.precision));
1281
- r->pstate(pstate);
1282
- return r.detach();
1283
- }
1284
-
1285
- Signature ceil_sig = "ceil($number)";
1286
- BUILT_IN(ceil)
1287
- {
1288
- Number_Obj r = ARGN("$number");
1289
- r->value(std::ceil(r->value()));
1290
- r->pstate(pstate);
1291
- return r.detach();
1292
- }
1293
-
1294
- Signature floor_sig = "floor($number)";
1295
- BUILT_IN(floor)
1296
- {
1297
- Number_Obj r = ARGN("$number");
1298
- r->value(std::floor(r->value()));
1299
- r->pstate(pstate);
1300
- return r.detach();
1301
- }
1302
-
1303
- Signature abs_sig = "abs($number)";
1304
- BUILT_IN(abs)
1305
- {
1306
- Number_Obj r = ARGN("$number");
1307
- r->value(std::abs(r->value()));
1308
- r->pstate(pstate);
1309
- return r.detach();
1310
- }
1311
-
1312
- Signature min_sig = "min($numbers...)";
1313
- BUILT_IN(min)
1314
- {
1315
- List_Ptr arglist = ARG("$numbers", List);
1316
- Number_Obj least = NULL;
1317
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1318
- Expression_Obj val = arglist->value_at_index(i);
1319
- Number_Obj xi = Cast<Number>(val);
1320
- if (!xi) {
1321
- error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `min'", pstate, traces);
1322
- }
1323
- if (least) {
1324
- if (*xi < *least) least = xi;
1325
- } else least = xi;
1326
- }
1327
- return least.detach();
1328
- }
1329
-
1330
- Signature max_sig = "max($numbers...)";
1331
- BUILT_IN(max)
1332
- {
1333
- List_Ptr arglist = ARG("$numbers", List);
1334
- Number_Obj greatest = NULL;
1335
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1336
- Expression_Obj val = arglist->value_at_index(i);
1337
- Number_Obj xi = Cast<Number>(val);
1338
- if (!xi) {
1339
- error("\"" + val->to_string(ctx.c_options) + "\" is not a number for `max'", pstate, traces);
1340
- }
1341
- if (greatest) {
1342
- if (*greatest < *xi) greatest = xi;
1343
- } else greatest = xi;
1344
- }
1345
- return greatest.detach();
1346
- }
1347
-
1348
- Signature random_sig = "random($limit:false)";
1349
- BUILT_IN(random)
1350
- {
1351
- AST_Node_Obj arg = env["$limit"];
1352
- Value_Ptr v = Cast<Value>(arg);
1353
- Number_Ptr l = Cast<Number>(arg);
1354
- Boolean_Ptr b = Cast<Boolean>(arg);
1355
- if (l) {
1356
- double lv = l->value();
1357
- if (lv < 1) {
1358
- stringstream err;
1359
- err << "$limit " << lv << " must be greater than or equal to 1 for `random'";
1360
- error(err.str(), pstate, traces);
1361
- }
1362
- bool eq_int = std::fabs(trunc(lv) - lv) < NUMBER_EPSILON;
1363
- if (!eq_int) {
1364
- stringstream err;
1365
- err << "Expected $limit to be an integer but got " << lv << " for `random'";
1366
- error(err.str(), pstate, traces);
1367
- }
1368
- std::uniform_real_distribution<> distributor(1, lv + 1);
1369
- uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
1370
- return SASS_MEMORY_NEW(Number, pstate, (double)distributed);
1371
- }
1372
- else if (b) {
1373
- std::uniform_real_distribution<> distributor(0, 1);
1374
- double distributed = static_cast<double>(distributor(rand));
1375
- return SASS_MEMORY_NEW(Number, pstate, distributed);
1376
- } else if (v) {
1377
- traces.push_back(Backtrace(pstate));
1378
- throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number", v);
1379
- } else {
1380
- traces.push_back(Backtrace(pstate));
1381
- throw Exception::InvalidArgumentType(pstate, traces, "random", "$limit", "number");
1382
- }
1383
- }
1384
-
1385
- /////////////////
1386
- // LIST FUNCTIONS
1387
- /////////////////
1388
-
1389
- Signature length_sig = "length($list)";
1390
- BUILT_IN(length)
1391
- {
1392
- if (Selector_List_Ptr sl = Cast<Selector_List>(env["$list"])) {
1393
- return SASS_MEMORY_NEW(Number, pstate, (double)sl->length());
1394
- }
1395
- Expression_Ptr v = ARG("$list", Expression);
1396
- if (v->concrete_type() == Expression::MAP) {
1397
- Map_Ptr map = Cast<Map>(env["$list"]);
1398
- return SASS_MEMORY_NEW(Number, pstate, (double)(map ? map->length() : 1));
1399
- }
1400
- if (v->concrete_type() == Expression::SELECTOR) {
1401
- if (Compound_Selector_Ptr h = Cast<Compound_Selector>(v)) {
1402
- return SASS_MEMORY_NEW(Number, pstate, (double)h->length());
1403
- } else if (Selector_List_Ptr ls = Cast<Selector_List>(v)) {
1404
- return SASS_MEMORY_NEW(Number, pstate, (double)ls->length());
1405
- } else {
1406
- return SASS_MEMORY_NEW(Number, pstate, 1);
1407
- }
1408
- }
1409
-
1410
- List_Ptr list = Cast<List>(env["$list"]);
1411
- return SASS_MEMORY_NEW(Number,
1412
- pstate,
1413
- (double)(list ? list->size() : 1));
1414
- }
1415
-
1416
- Signature nth_sig = "nth($list, $n)";
1417
- BUILT_IN(nth)
1418
- {
1419
- double nr = ARGVAL("$n");
1420
- Map_Ptr m = Cast<Map>(env["$list"]);
1421
- if (Selector_List_Ptr sl = Cast<Selector_List>(env["$list"])) {
1422
- size_t len = m ? m->length() : sl->length();
1423
- bool empty = m ? m->empty() : sl->empty();
1424
- if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
1425
- double index = std::floor(nr < 0 ? len + nr : nr - 1);
1426
- if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
1427
- // return (*sl)[static_cast<int>(index)];
1428
- Listize listize;
1429
- return (*sl)[static_cast<int>(index)]->perform(&listize);
1430
- }
1431
- List_Obj l = Cast<List>(env["$list"]);
1432
- if (nr == 0) error("argument `$n` of `" + std::string(sig) + "` must be non-zero", pstate, traces);
1433
- // if the argument isn't a list, then wrap it in a singleton list
1434
- if (!m && !l) {
1435
- l = SASS_MEMORY_NEW(List, pstate, 1);
1436
- l->append(ARG("$list", Expression));
1437
- }
1438
- size_t len = m ? m->length() : l->length();
1439
- bool empty = m ? m->empty() : l->empty();
1440
- if (empty) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
1441
- double index = std::floor(nr < 0 ? len + nr : nr - 1);
1442
- if (index < 0 || index > len - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
1443
-
1444
- if (m) {
1445
- l = SASS_MEMORY_NEW(List, pstate, 1);
1446
- l->append(m->keys()[static_cast<unsigned int>(index)]);
1447
- l->append(m->at(m->keys()[static_cast<unsigned int>(index)]));
1448
- return l.detach();
1449
- }
1450
- else {
1451
- Expression_Obj rv = l->value_at_index(static_cast<int>(index));
1452
- rv->set_delayed(false);
1453
- return rv.detach();
1454
- }
1455
- }
1456
-
1457
- Signature set_nth_sig = "set-nth($list, $n, $value)";
1458
- BUILT_IN(set_nth)
1459
- {
1460
- Map_Obj m = Cast<Map>(env["$list"]);
1461
- List_Obj l = Cast<List>(env["$list"]);
1462
- Number_Obj n = ARG("$n", Number);
1463
- Expression_Obj v = ARG("$value", Expression);
1464
- if (!l) {
1465
- l = SASS_MEMORY_NEW(List, pstate, 1);
1466
- l->append(ARG("$list", Expression));
1467
- }
1468
- if (m) {
1469
- l = m->to_list(pstate);
1470
- }
1471
- if (l->empty()) error("argument `$list` of `" + std::string(sig) + "` must not be empty", pstate, traces);
1472
- double index = std::floor(n->value() < 0 ? l->length() + n->value() : n->value() - 1);
1473
- if (index < 0 || index > l->length() - 1) error("index out of bounds for `" + std::string(sig) + "`", pstate, traces);
1474
- List_Ptr result = SASS_MEMORY_NEW(List, pstate, l->length(), l->separator(), false, l->is_bracketed());
1475
- for (size_t i = 0, L = l->length(); i < L; ++i) {
1476
- result->append(((i == index) ? v : (*l)[i]));
1477
- }
1478
- return result;
1479
- }
1480
-
1481
- Signature index_sig = "index($list, $value)";
1482
- BUILT_IN(index)
1483
- {
1484
- Map_Obj m = Cast<Map>(env["$list"]);
1485
- List_Obj l = Cast<List>(env["$list"]);
1486
- Expression_Obj v = ARG("$value", Expression);
1487
- if (!l) {
1488
- l = SASS_MEMORY_NEW(List, pstate, 1);
1489
- l->append(ARG("$list", Expression));
1490
- }
1491
- if (m) {
1492
- l = m->to_list(pstate);
1493
- }
1494
- for (size_t i = 0, L = l->length(); i < L; ++i) {
1495
- if (Operators::eq(l->value_at_index(i), v)) return SASS_MEMORY_NEW(Number, pstate, (double)(i+1));
1496
- }
1497
- return SASS_MEMORY_NEW(Null, pstate);
1498
- }
1499
-
1500
- Signature join_sig = "join($list1, $list2, $separator: auto, $bracketed: auto)";
1501
- BUILT_IN(join)
1502
- {
1503
- Map_Obj m1 = Cast<Map>(env["$list1"]);
1504
- Map_Obj m2 = Cast<Map>(env["$list2"]);
1505
- List_Obj l1 = Cast<List>(env["$list1"]);
1506
- List_Obj l2 = Cast<List>(env["$list2"]);
1507
- String_Constant_Obj sep = ARG("$separator", String_Constant);
1508
- enum Sass_Separator sep_val = (l1 ? l1->separator() : SASS_SPACE);
1509
- Value* bracketed = ARG("$bracketed", Value);
1510
- bool is_bracketed = (l1 ? l1->is_bracketed() : false);
1511
- if (!l1) {
1512
- l1 = SASS_MEMORY_NEW(List, pstate, 1);
1513
- l1->append(ARG("$list1", Expression));
1514
- sep_val = (l2 ? l2->separator() : SASS_SPACE);
1515
- is_bracketed = (l2 ? l2->is_bracketed() : false);
1516
- }
1517
- if (!l2) {
1518
- l2 = SASS_MEMORY_NEW(List, pstate, 1);
1519
- l2->append(ARG("$list2", Expression));
1520
- }
1521
- if (m1) {
1522
- l1 = m1->to_list(pstate);
1523
- sep_val = SASS_COMMA;
1524
- }
1525
- if (m2) {
1526
- l2 = m2->to_list(pstate);
1527
- }
1528
- size_t len = l1->length() + l2->length();
1529
- std::string sep_str = unquote(sep->value());
1530
- if (sep_str == "space") sep_val = SASS_SPACE;
1531
- else if (sep_str == "comma") sep_val = SASS_COMMA;
1532
- else if (sep_str != "auto") error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces);
1533
- String_Constant_Obj bracketed_as_str = Cast<String_Constant>(bracketed);
1534
- bool bracketed_is_auto = bracketed_as_str && unquote(bracketed_as_str->value()) == "auto";
1535
- if (!bracketed_is_auto) {
1536
- is_bracketed = !bracketed->is_false();
1537
- }
1538
- List_Obj result = SASS_MEMORY_NEW(List, pstate, len, sep_val, false, is_bracketed);
1539
- result->concat(l1);
1540
- result->concat(l2);
1541
- return result.detach();
1542
- }
1543
-
1544
- Signature append_sig = "append($list, $val, $separator: auto)";
1545
- BUILT_IN(append)
1546
- {
1547
- Map_Obj m = Cast<Map>(env["$list"]);
1548
- List_Obj l = Cast<List>(env["$list"]);
1549
- Expression_Obj v = ARG("$val", Expression);
1550
- if (Selector_List_Ptr sl = Cast<Selector_List>(env["$list"])) {
1551
- Listize listize;
1552
- l = Cast<List>(sl->perform(&listize));
1553
- }
1554
- String_Constant_Obj sep = ARG("$separator", String_Constant);
1555
- if (!l) {
1556
- l = SASS_MEMORY_NEW(List, pstate, 1);
1557
- l->append(ARG("$list", Expression));
1558
- }
1559
- if (m) {
1560
- l = m->to_list(pstate);
1561
- }
1562
- List_Ptr result = SASS_MEMORY_COPY(l);
1563
- std::string sep_str(unquote(sep->value()));
1564
- if (sep_str != "auto") { // check default first
1565
- if (sep_str == "space") result->separator(SASS_SPACE);
1566
- else if (sep_str == "comma") result->separator(SASS_COMMA);
1567
- else error("argument `$separator` of `" + std::string(sig) + "` must be `space`, `comma`, or `auto`", pstate, traces);
1568
- }
1569
- if (l->is_arglist()) {
1570
- result->append(SASS_MEMORY_NEW(Argument,
1571
- v->pstate(),
1572
- v,
1573
- "",
1574
- false,
1575
- false));
1576
-
1577
- } else {
1578
- result->append(v);
1579
- }
1580
- return result;
1581
- }
1582
-
1583
- Signature zip_sig = "zip($lists...)";
1584
- BUILT_IN(zip)
1585
- {
1586
- List_Obj arglist = SASS_MEMORY_COPY(ARG("$lists", List));
1587
- size_t shortest = 0;
1588
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1589
- List_Obj ith = Cast<List>(arglist->value_at_index(i));
1590
- Map_Obj mith = Cast<Map>(arglist->value_at_index(i));
1591
- if (!ith) {
1592
- if (mith) {
1593
- ith = mith->to_list(pstate);
1594
- } else {
1595
- ith = SASS_MEMORY_NEW(List, pstate, 1);
1596
- ith->append(arglist->value_at_index(i));
1597
- }
1598
- if (arglist->is_arglist()) {
1599
- Argument_Obj arg = (Argument_Ptr)(arglist->at(i).ptr()); // XXX
1600
- arg->value(ith);
1601
- } else {
1602
- (*arglist)[i] = ith;
1603
- }
1604
- }
1605
- shortest = (i ? std::min(shortest, ith->length()) : ith->length());
1606
- }
1607
- List_Ptr zippers = SASS_MEMORY_NEW(List, pstate, shortest, SASS_COMMA);
1608
- size_t L = arglist->length();
1609
- for (size_t i = 0; i < shortest; ++i) {
1610
- List_Ptr zipper = SASS_MEMORY_NEW(List, pstate, L);
1611
- for (size_t j = 0; j < L; ++j) {
1612
- zipper->append(Cast<List>(arglist->value_at_index(j))->at(i));
1613
- }
1614
- zippers->append(zipper);
1615
- }
1616
- return zippers;
1617
- }
1618
-
1619
- Signature list_separator_sig = "list_separator($list)";
1620
- BUILT_IN(list_separator)
1621
- {
1622
- List_Obj l = Cast<List>(env["$list"]);
1623
- if (!l) {
1624
- l = SASS_MEMORY_NEW(List, pstate, 1);
1625
- l->append(ARG("$list", Expression));
1626
- }
1627
- return SASS_MEMORY_NEW(String_Quoted,
1628
- pstate,
1629
- l->separator() == SASS_COMMA ? "comma" : "space");
1630
- }
1631
-
1632
- /////////////////
1633
- // MAP FUNCTIONS
1634
- /////////////////
1635
-
1636
- Signature map_get_sig = "map-get($map, $key)";
1637
- BUILT_IN(map_get)
1638
- {
1639
- // leaks for "map-get((), foo)" if not Obj
1640
- // investigate why this is (unexpected)
1641
- Map_Obj m = ARGM("$map", Map, ctx);
1642
- Expression_Obj v = ARG("$key", Expression);
1643
- try {
1644
- Expression_Obj val = m->at(v);
1645
- if (!val) return SASS_MEMORY_NEW(Null, pstate);
1646
- val->set_delayed(false);
1647
- return val.detach();
1648
- } catch (const std::out_of_range&) {
1649
- return SASS_MEMORY_NEW(Null, pstate);
1650
- }
1651
- catch (...) { throw; }
1652
- }
1653
-
1654
- Signature map_has_key_sig = "map-has-key($map, $key)";
1655
- BUILT_IN(map_has_key)
1656
- {
1657
- Map_Obj m = ARGM("$map", Map, ctx);
1658
- Expression_Obj v = ARG("$key", Expression);
1659
- return SASS_MEMORY_NEW(Boolean, pstate, m->has(v));
1660
- }
1661
-
1662
- Signature map_keys_sig = "map-keys($map)";
1663
- BUILT_IN(map_keys)
1664
- {
1665
- Map_Obj m = ARGM("$map", Map, ctx);
1666
- List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA);
1667
- for ( auto key : m->keys()) {
1668
- result->append(key);
1669
- }
1670
- return result;
1671
- }
1672
-
1673
- Signature map_values_sig = "map-values($map)";
1674
- BUILT_IN(map_values)
1675
- {
1676
- Map_Obj m = ARGM("$map", Map, ctx);
1677
- List_Ptr result = SASS_MEMORY_NEW(List, pstate, m->length(), SASS_COMMA);
1678
- for ( auto key : m->keys()) {
1679
- result->append(m->at(key));
1680
- }
1681
- return result;
1682
- }
1683
-
1684
- Signature map_merge_sig = "map-merge($map1, $map2)";
1685
- BUILT_IN(map_merge)
1686
- {
1687
- Map_Obj m1 = ARGM("$map1", Map, ctx);
1688
- Map_Obj m2 = ARGM("$map2", Map, ctx);
1689
-
1690
- size_t len = m1->length() + m2->length();
1691
- Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, len);
1692
- // concat not implemented for maps
1693
- *result += m1;
1694
- *result += m2;
1695
- return result;
1696
- }
1697
-
1698
- Signature map_remove_sig = "map-remove($map, $keys...)";
1699
- BUILT_IN(map_remove)
1700
- {
1701
- bool remove;
1702
- Map_Obj m = ARGM("$map", Map, ctx);
1703
- List_Obj arglist = ARG("$keys", List);
1704
- Map_Ptr result = SASS_MEMORY_NEW(Map, pstate, 1);
1705
- for (auto key : m->keys()) {
1706
- remove = false;
1707
- for (size_t j = 0, K = arglist->length(); j < K && !remove; ++j) {
1708
- remove = Operators::eq(key, arglist->value_at_index(j));
1709
- }
1710
- if (!remove) *result << std::make_pair(key, m->at(key));
1711
- }
1712
- return result;
1713
- }
1714
-
1715
- Signature keywords_sig = "keywords($args)";
1716
- BUILT_IN(keywords)
1717
- {
1718
- List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List)); // copy
1719
- Map_Obj result = SASS_MEMORY_NEW(Map, pstate, 1);
1720
- for (size_t i = arglist->size(), L = arglist->length(); i < L; ++i) {
1721
- Expression_Obj obj = arglist->at(i);
1722
- Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX
1723
- std::string name = std::string(arg->name());
1724
- name = name.erase(0, 1); // sanitize name (remove dollar sign)
1725
- *result << std::make_pair(SASS_MEMORY_NEW(String_Quoted,
1726
- pstate, name),
1727
- arg->value());
1728
- }
1729
- return result.detach();
1730
- }
1731
-
1732
- //////////////////////////
1733
- // INTROSPECTION FUNCTIONS
1734
- //////////////////////////
1735
-
1736
- Signature type_of_sig = "type-of($value)";
1737
- BUILT_IN(type_of)
1738
- {
1739
- Expression_Ptr v = ARG("$value", Expression);
1740
- return SASS_MEMORY_NEW(String_Quoted, pstate, v->type());
1741
- }
1742
-
1743
- Signature unit_sig = "unit($number)";
1744
- BUILT_IN(unit)
1745
- {
1746
- Number_Obj arg = ARGN("$number");
1747
- std::string str(quote(arg->unit(), '"'));
1748
- return SASS_MEMORY_NEW(String_Quoted, pstate, str);
1749
- }
1750
-
1751
- Signature unitless_sig = "unitless($number)";
1752
- BUILT_IN(unitless)
1753
- {
1754
- Number_Obj arg = ARGN("$number");
1755
- bool unitless = arg->is_unitless();
1756
- return SASS_MEMORY_NEW(Boolean, pstate, unitless);
1757
- }
1758
-
1759
- Signature comparable_sig = "comparable($number-1, $number-2)";
1760
- BUILT_IN(comparable)
1761
- {
1762
- Number_Obj n1 = ARGN("$number-1");
1763
- Number_Obj n2 = ARGN("$number-2");
1764
- if (n1->is_unitless() || n2->is_unitless()) {
1765
- return SASS_MEMORY_NEW(Boolean, pstate, true);
1766
- }
1767
- // normalize into main units
1768
- n1->normalize(); n2->normalize();
1769
- Units &lhs_unit = *n1, &rhs_unit = *n2;
1770
- bool is_comparable = (lhs_unit == rhs_unit);
1771
- return SASS_MEMORY_NEW(Boolean, pstate, is_comparable);
1772
- }
1773
-
1774
- Signature variable_exists_sig = "variable-exists($name)";
1775
- BUILT_IN(variable_exists)
1776
- {
1777
- std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
1778
-
1779
- if(d_env.has("$"+s)) {
1780
- return SASS_MEMORY_NEW(Boolean, pstate, true);
1781
- }
1782
- else {
1783
- return SASS_MEMORY_NEW(Boolean, pstate, false);
1784
- }
1785
- }
1786
-
1787
- Signature global_variable_exists_sig = "global-variable-exists($name)";
1788
- BUILT_IN(global_variable_exists)
1789
- {
1790
- std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
1791
-
1792
- if(d_env.has_global("$"+s)) {
1793
- return SASS_MEMORY_NEW(Boolean, pstate, true);
1794
- }
1795
- else {
1796
- return SASS_MEMORY_NEW(Boolean, pstate, false);
1797
- }
1798
- }
1799
-
1800
- Signature function_exists_sig = "function-exists($name)";
1801
- BUILT_IN(function_exists)
1802
- {
1803
- String_Constant_Ptr ss = Cast<String_Constant>(env["$name"]);
1804
- if (!ss) {
1805
- error("$name: " + (env["$name"]->to_string()) + " is not a string for `function-exists'", pstate, traces);
1806
- }
1807
-
1808
- std::string name = Util::normalize_underscores(unquote(ss->value()));
1809
-
1810
- if(d_env.has_global(name+"[f]")) {
1811
- return SASS_MEMORY_NEW(Boolean, pstate, true);
1812
- }
1813
- else {
1814
- return SASS_MEMORY_NEW(Boolean, pstate, false);
1815
- }
1816
- }
1817
-
1818
- Signature mixin_exists_sig = "mixin-exists($name)";
1819
- BUILT_IN(mixin_exists)
1820
- {
1821
- std::string s = Util::normalize_underscores(unquote(ARG("$name", String_Constant)->value()));
1822
-
1823
- if(d_env.has_global(s+"[m]")) {
1824
- return SASS_MEMORY_NEW(Boolean, pstate, true);
1825
- }
1826
- else {
1827
- return SASS_MEMORY_NEW(Boolean, pstate, false);
1828
- }
1829
- }
1830
-
1831
- Signature feature_exists_sig = "feature-exists($name)";
1832
- BUILT_IN(feature_exists)
1833
- {
1834
- std::string s = unquote(ARG("$name", String_Constant)->value());
1835
-
1836
- if(features.find(s) == features.end()) {
1837
- return SASS_MEMORY_NEW(Boolean, pstate, false);
1838
- }
1839
- else {
1840
- return SASS_MEMORY_NEW(Boolean, pstate, true);
1841
- }
1842
- }
1843
-
1844
- Signature call_sig = "call($name, $args...)";
1845
- BUILT_IN(call)
1846
- {
1847
- std::string name;
1848
- Function_Ptr ff = Cast<Function>(env["$name"]);
1849
- String_Constant_Ptr ss = Cast<String_Constant>(env["$name"]);
1850
-
1851
- if (ss) {
1852
- name = Util::normalize_underscores(unquote(ss->value()));
1853
- std::cerr << "DEPRECATION WARNING: ";
1854
- std::cerr << "Passing a string to call() is deprecated and will be illegal" << std::endl;
1855
- std::cerr << "in Sass 4.0. Use call(get-function(" + quote(name) + ")) instead." << std::endl;
1856
- std::cerr << std::endl;
1857
- } else if (ff) {
1858
- name = ff->name();
1859
- }
1860
-
1861
- List_Obj arglist = SASS_MEMORY_COPY(ARG("$args", List));
1862
-
1863
- Arguments_Obj args = SASS_MEMORY_NEW(Arguments, pstate);
1864
- // std::string full_name(name + "[f]");
1865
- // Definition_Ptr def = d_env.has(full_name) ? Cast<Definition>((d_env)[full_name]) : 0;
1866
- // Parameters_Ptr params = def ? def->parameters() : 0;
1867
- // size_t param_size = params ? params->length() : 0;
1868
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1869
- Expression_Obj expr = arglist->value_at_index(i);
1870
- // if (params && params->has_rest_parameter()) {
1871
- // Parameter_Obj p = param_size > i ? (*params)[i] : 0;
1872
- // List_Ptr list = Cast<List>(expr);
1873
- // if (list && p && !p->is_rest_parameter()) expr = (*list)[0];
1874
- // }
1875
- if (arglist->is_arglist()) {
1876
- Expression_Obj obj = arglist->at(i);
1877
- Argument_Obj arg = (Argument_Ptr) obj.ptr(); // XXX
1878
- args->append(SASS_MEMORY_NEW(Argument,
1879
- pstate,
1880
- expr,
1881
- arg ? arg->name() : "",
1882
- arg ? arg->is_rest_argument() : false,
1883
- arg ? arg->is_keyword_argument() : false));
1884
- } else {
1885
- args->append(SASS_MEMORY_NEW(Argument, pstate, expr));
1886
- }
1887
- }
1888
- Function_Call_Obj func = SASS_MEMORY_NEW(Function_Call, pstate, name, args);
1889
- Expand expand(ctx, &d_env, &selector_stack);
1890
- func->via_call(true); // calc invoke is allowed
1891
- if (ff) func->func(ff);
1892
- return func->perform(&expand.eval);
1893
- }
1894
-
1895
- ////////////////////
1896
- // BOOLEAN FUNCTIONS
1897
- ////////////////////
1898
-
1899
- Signature not_sig = "not($value)";
1900
- BUILT_IN(sass_not)
1901
- {
1902
- return SASS_MEMORY_NEW(Boolean, pstate, ARG("$value", Expression)->is_false());
1903
- }
1904
-
1905
- Signature if_sig = "if($condition, $if-true, $if-false)";
1906
- // BUILT_IN(sass_if)
1907
- // { return ARG("$condition", Expression)->is_false() ? ARG("$if-false", Expression) : ARG("$if-true", Expression); }
1908
- BUILT_IN(sass_if)
1909
- {
1910
- Expand expand(ctx, &d_env, &selector_stack);
1911
- Expression_Obj cond = ARG("$condition", Expression)->perform(&expand.eval);
1912
- bool is_true = !cond->is_false();
1913
- Expression_Obj res = ARG(is_true ? "$if-true" : "$if-false", Expression);
1914
- res = res->perform(&expand.eval);
1915
- res->set_delayed(false); // clone?
1916
- return res.detach();
1917
- }
1918
-
1919
- //////////////////////////
1920
- // MISCELLANEOUS FUNCTIONS
1921
- //////////////////////////
1922
-
1923
- // value.check_deprecated_interp if value.is_a?(Sass::Script::Value::String)
1924
- // unquoted_string(value.to_sass)
1925
-
1926
- Signature inspect_sig = "inspect($value)";
1927
- BUILT_IN(inspect)
1928
- {
1929
- Expression_Ptr v = ARG("$value", Expression);
1930
- if (v->concrete_type() == Expression::NULL_VAL) {
1931
- return SASS_MEMORY_NEW(String_Quoted, pstate, "null");
1932
- } else if (v->concrete_type() == Expression::BOOLEAN && v->is_false()) {
1933
- return SASS_MEMORY_NEW(String_Quoted, pstate, "false");
1934
- } else if (v->concrete_type() == Expression::STRING) {
1935
- return v;
1936
- } else {
1937
- // ToDo: fix to_sass for nested parentheses
1938
- Sass_Output_Style old_style;
1939
- old_style = ctx.c_options.output_style;
1940
- ctx.c_options.output_style = TO_SASS;
1941
- Emitter emitter(ctx.c_options);
1942
- Inspect i(emitter);
1943
- i.in_declaration = false;
1944
- v->perform(&i);
1945
- ctx.c_options.output_style = old_style;
1946
- return SASS_MEMORY_NEW(String_Quoted, pstate, i.get_buffer());
1947
- }
1948
- // return v;
1949
- }
1950
- Signature selector_nest_sig = "selector-nest($selectors...)";
1951
- BUILT_IN(selector_nest)
1952
- {
1953
- List_Ptr arglist = ARG("$selectors", List);
1954
-
1955
- // Not enough parameters
1956
- if( arglist->length() == 0 )
1957
- error("$selectors: At least one selector must be passed for `selector-nest'", pstate, traces);
1958
-
1959
- // Parse args into vector of selectors
1960
- std::vector<Selector_List_Obj> parsedSelectors;
1961
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
1962
- Expression_Obj exp = Cast<Expression>(arglist->value_at_index(i));
1963
- if (exp->concrete_type() == Expression::NULL_VAL) {
1964
- std::stringstream msg;
1965
- msg << "$selectors: null is not a valid selector: it must be a string,\n";
1966
- msg << "a list of strings, or a list of lists of strings for 'selector-nest'";
1967
- error(msg.str(), pstate, traces);
1968
- }
1969
- if (String_Constant_Obj str = Cast<String_Constant>(exp)) {
1970
- str->quote_mark(0);
1971
- }
1972
- std::string exp_src = exp->to_string(ctx.c_options);
1973
- Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces);
1974
- parsedSelectors.push_back(sel);
1975
- }
1976
-
1977
- // Nothing to do
1978
- if( parsedSelectors.empty() ) {
1979
- return SASS_MEMORY_NEW(Null, pstate);
1980
- }
1981
-
1982
- // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
1983
- std::vector<Selector_List_Obj>::iterator itr = parsedSelectors.begin();
1984
- Selector_List_Obj result = *itr;
1985
- ++itr;
1986
-
1987
- for(;itr != parsedSelectors.end(); ++itr) {
1988
- Selector_List_Obj child = *itr;
1989
- std::vector<Complex_Selector_Obj> exploded;
1990
- selector_stack.push_back(result);
1991
- Selector_List_Obj rv = child->resolve_parent_refs(selector_stack, traces);
1992
- selector_stack.pop_back();
1993
- for (size_t m = 0, mLen = rv->length(); m < mLen; ++m) {
1994
- exploded.push_back((*rv)[m]);
1995
- }
1996
- result->elements(exploded);
1997
- }
1998
-
1999
- Listize listize;
2000
- return result->perform(&listize);
2001
- }
2002
-
2003
- Signature selector_append_sig = "selector-append($selectors...)";
2004
- BUILT_IN(selector_append)
2005
- {
2006
- List_Ptr arglist = ARG("$selectors", List);
2007
-
2008
- // Not enough parameters
2009
- if( arglist->length() == 0 )
2010
- error("$selectors: At least one selector must be passed for `selector-append'", pstate, traces);
2011
-
2012
- // Parse args into vector of selectors
2013
- std::vector<Selector_List_Obj> parsedSelectors;
2014
- for (size_t i = 0, L = arglist->length(); i < L; ++i) {
2015
- Expression_Obj exp = Cast<Expression>(arglist->value_at_index(i));
2016
- if (exp->concrete_type() == Expression::NULL_VAL) {
2017
- std::stringstream msg;
2018
- msg << "$selectors: null is not a valid selector: it must be a string,\n";
2019
- msg << "a list of strings, or a list of lists of strings for 'selector-append'";
2020
- error(msg.str(), pstate, traces);
2021
- }
2022
- if (String_Constant_Ptr str = Cast<String_Constant>(exp)) {
2023
- str->quote_mark(0);
2024
- }
2025
- std::string exp_src = exp->to_string();
2026
- Selector_List_Obj sel = Parser::parse_selector(exp_src.c_str(), ctx, traces);
2027
- parsedSelectors.push_back(sel);
2028
- }
2029
-
2030
- // Nothing to do
2031
- if( parsedSelectors.empty() ) {
2032
- return SASS_MEMORY_NEW(Null, pstate);
2033
- }
2034
-
2035
- // Set the first element as the `result`, keep appending to as we go down the parsedSelector vector.
2036
- std::vector<Selector_List_Obj>::iterator itr = parsedSelectors.begin();
2037
- Selector_List_Obj result = *itr;
2038
- ++itr;
2039
-
2040
- for(;itr != parsedSelectors.end(); ++itr) {
2041
- Selector_List_Obj child = *itr;
2042
- std::vector<Complex_Selector_Obj> newElements;
2043
-
2044
- // For every COMPLEX_SELECTOR in `result`
2045
- // For every COMPLEX_SELECTOR in `child`
2046
- // let parentSeqClone equal a copy of result->elements[i]
2047
- // let childSeq equal child->elements[j]
2048
- // Append all of childSeq head elements into parentSeqClone
2049
- // Set the innermost tail of parentSeqClone, to childSeq's tail
2050
- // Replace result->elements with newElements
2051
- for (size_t i = 0, resultLen = result->length(); i < resultLen; ++i) {
2052
- for (size_t j = 0, childLen = child->length(); j < childLen; ++j) {
2053
- Complex_Selector_Obj parentSeqClone = SASS_MEMORY_CLONE((*result)[i]);
2054
- Complex_Selector_Obj childSeq = (*child)[j];
2055
- Complex_Selector_Obj base = childSeq->tail();
2056
-
2057
- // Must be a simple sequence
2058
- if( childSeq->combinator() != Complex_Selector::Combinator::ANCESTOR_OF ) {
2059
- std::string msg("Can't append \"");
2060
- msg += childSeq->to_string();
2061
- msg += "\" to \"";
2062
- msg += parentSeqClone->to_string();
2063
- msg += "\" for `selector-append'";
2064
- error(msg, pstate, traces);
2065
- }
2066
-
2067
- // Cannot be a Universal selector
2068
- Element_Selector_Obj pType = Cast<Element_Selector>(childSeq->head()->first());
2069
- if(pType && pType->name() == "*") {
2070
- std::string msg("Can't append \"");
2071
- msg += childSeq->to_string();
2072
- msg += "\" to \"";
2073
- msg += parentSeqClone->to_string();
2074
- msg += "\" for `selector-append'";
2075
- error(msg, pstate, traces);
2076
- }
2077
-
2078
- // TODO: Add check for namespace stuff
2079
-
2080
- // append any selectors in childSeq's head
2081
- parentSeqClone->innermost()->head()->concat(base->head());
2082
-
2083
- // Set parentSeqClone new tail
2084
- parentSeqClone->innermost()->tail( base->tail() );
2085
-
2086
- newElements.push_back(parentSeqClone);
2087
- }
2088
- }
2089
-
2090
- result->elements(newElements);
2091
- }
2092
-
2093
- Listize listize;
2094
- return result->perform(&listize);
2095
- }
2096
-
2097
- Signature selector_unify_sig = "selector-unify($selector1, $selector2)";
2098
- BUILT_IN(selector_unify)
2099
- {
2100
- Selector_List_Obj selector1 = ARGSEL("$selector1", Selector_List_Obj, p_contextualize);
2101
- Selector_List_Obj selector2 = ARGSEL("$selector2", Selector_List_Obj, p_contextualize);
2102
-
2103
- Selector_List_Obj result = selector1->unify_with(selector2);
2104
- Listize listize;
2105
- return result->perform(&listize);
2106
- }
2107
-
2108
- Signature simple_selectors_sig = "simple-selectors($selector)";
2109
- BUILT_IN(simple_selectors)
2110
- {
2111
- Compound_Selector_Obj sel = ARGSEL("$selector", Compound_Selector_Obj, p_contextualize);
2112
-
2113
- List_Ptr l = SASS_MEMORY_NEW(List, sel->pstate(), sel->length(), SASS_COMMA);
2114
-
2115
- for (size_t i = 0, L = sel->length(); i < L; ++i) {
2116
- Simple_Selector_Obj ss = (*sel)[i];
2117
- std::string ss_string = ss->to_string() ;
2118
-
2119
- l->append(SASS_MEMORY_NEW(String_Quoted, ss->pstate(), ss_string));
2120
- }
2121
-
2122
- return l;
2123
- }
2124
-
2125
- Signature selector_extend_sig = "selector-extend($selector, $extendee, $extender)";
2126
- BUILT_IN(selector_extend)
2127
- {
2128
- Selector_List_Obj selector = ARGSEL("$selector", Selector_List_Obj, p_contextualize);
2129
- Selector_List_Obj extendee = ARGSEL("$extendee", Selector_List_Obj, p_contextualize);
2130
- Selector_List_Obj extender = ARGSEL("$extender", Selector_List_Obj, p_contextualize);
2131
-
2132
- Subset_Map subset_map;
2133
- extender->populate_extends(extendee, subset_map);
2134
- Extend extend(subset_map);
2135
-
2136
- Selector_List_Obj result = extend.extendSelectorList(selector, false);
2137
-
2138
- Listize listize;
2139
- return result->perform(&listize);
2140
- }
2141
-
2142
- Signature selector_replace_sig = "selector-replace($selector, $original, $replacement)";
2143
- BUILT_IN(selector_replace)
2144
- {
2145
- Selector_List_Obj selector = ARGSEL("$selector", Selector_List_Obj, p_contextualize);
2146
- Selector_List_Obj original = ARGSEL("$original", Selector_List_Obj, p_contextualize);
2147
- Selector_List_Obj replacement = ARGSEL("$replacement", Selector_List_Obj, p_contextualize);
2148
- Subset_Map subset_map;
2149
- replacement->populate_extends(original, subset_map);
2150
- Extend extend(subset_map);
2151
-
2152
- Selector_List_Obj result = extend.extendSelectorList(selector, true);
2153
-
2154
- Listize listize;
2155
- return result->perform(&listize);
2156
- }
2157
-
2158
- Signature selector_parse_sig = "selector-parse($selector)";
2159
- BUILT_IN(selector_parse)
2160
- {
2161
- Selector_List_Obj sel = ARGSEL("$selector", Selector_List_Obj, p_contextualize);
2162
-
2163
- Listize listize;
2164
- return sel->perform(&listize);
2165
- }
2166
-
2167
- Signature is_superselector_sig = "is-superselector($super, $sub)";
2168
- BUILT_IN(is_superselector)
2169
- {
2170
- Selector_List_Obj sel_sup = ARGSEL("$super", Selector_List_Obj, p_contextualize);
2171
- Selector_List_Obj sel_sub = ARGSEL("$sub", Selector_List_Obj, p_contextualize);
2172
- bool result = sel_sup->is_superselector_of(sel_sub);
2173
- return SASS_MEMORY_NEW(Boolean, pstate, result);
2174
- }
2175
-
2176
- Signature unique_id_sig = "unique-id()";
2177
- BUILT_IN(unique_id)
2178
- {
2179
- std::stringstream ss;
2180
- std::uniform_real_distribution<> distributor(0, 4294967296); // 16^8
2181
- uint_fast32_t distributed = static_cast<uint_fast32_t>(distributor(rand));
2182
- ss << "u" << std::setfill('0') << std::setw(8) << std::hex << distributed;
2183
- return SASS_MEMORY_NEW(String_Quoted, pstate, ss.str());
2184
- }
2185
-
2186
- Signature is_bracketed_sig = "is-bracketed($list)";
2187
- BUILT_IN(is_bracketed)
2188
- {
2189
- Value_Obj value = ARG("$list", Value);
2190
- List_Obj list = Cast<List>(value);
2191
- return SASS_MEMORY_NEW(Boolean, pstate, list && list->is_bracketed());
2192
- }
2193
-
2194
- Signature content_exists_sig = "content-exists()";
2195
- BUILT_IN(content_exists)
2196
- {
2197
- if (!d_env.has_global("is_in_mixin")) {
2198
- error("Cannot call content-exists() except within a mixin.", pstate, traces);
2199
- }
2200
- return SASS_MEMORY_NEW(Boolean, pstate, d_env.has_lexical("@content[m]"));
2201
- }
2202
-
2203
- Signature get_function_sig = "get-function($name, $css: false)";
2204
- BUILT_IN(get_function)
2205
- {
2206
- String_Constant_Ptr ss = Cast<String_Constant>(env["$name"]);
2207
- if (!ss) {
2208
- error("$name: " + (env["$name"]->to_string()) + " is not a string for `get-function'", pstate, traces);
2209
- }
2210
-
2211
- std::string name = Util::normalize_underscores(unquote(ss->value()));
2212
- std::string full_name = name + "[f]";
2213
-
2214
- Boolean_Obj css = ARG("$css", Boolean);
2215
- if (!css->is_false()) {
2216
- Definition_Ptr def = SASS_MEMORY_NEW(Definition,
2217
- pstate,
2218
- name,
2219
- SASS_MEMORY_NEW(Parameters, pstate),
2220
- SASS_MEMORY_NEW(Block, pstate, 0, false),
2221
- Definition::FUNCTION);
2222
- return SASS_MEMORY_NEW(Function, pstate, def, true);
2223
- }
2224
-
2225
-
2226
- if (!d_env.has_global(full_name)) {
2227
- error("Function not found: " + name, pstate, traces);
2228
- }
2229
-
2230
- Definition_Ptr def = Cast<Definition>(d_env[full_name]);
2231
- return SASS_MEMORY_NEW(Function, pstate, def, false);
2232
- }
2233
- }
2234
- }