sassc 2.0.1 → 2.1.0.pre1

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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.gitmodules +1 -1
  4. data/.travis.yml +7 -3
  5. data/CHANGELOG.md +3 -0
  6. data/CODE_OF_CONDUCT.md +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +23 -8
  9. data/ext/extconf.rb +39 -0
  10. data/ext/libsass/.gitignore +1 -0
  11. data/ext/libsass/GNUmakefile.am +23 -39
  12. data/ext/libsass/Makefile +56 -91
  13. data/ext/libsass/Makefile.conf +16 -2
  14. data/ext/libsass/configure.ac +8 -12
  15. data/ext/libsass/include/sass/base.h +1 -0
  16. data/ext/libsass/include/sass/context.h +1 -1
  17. data/ext/libsass/src/GNUmakefile.am +1 -5
  18. data/ext/libsass/src/ast.cpp +747 -2010
  19. data/ext/libsass/src/ast.hpp +239 -2383
  20. data/ext/libsass/src/{to_c.cpp → ast2c.cpp} +22 -16
  21. data/ext/libsass/src/ast2c.hpp +39 -0
  22. data/ext/libsass/src/ast_def_macros.hpp +62 -10
  23. data/ext/libsass/src/ast_fwd_decl.cpp +1 -0
  24. data/ext/libsass/src/ast_fwd_decl.hpp +43 -165
  25. data/ext/libsass/src/ast_sel_cmp.cpp +909 -0
  26. data/ext/libsass/src/ast_sel_unify.cpp +280 -0
  27. data/ext/libsass/src/ast_selectors.cpp +1475 -0
  28. data/ext/libsass/src/ast_selectors.hpp +568 -0
  29. data/ext/libsass/src/ast_supports.cpp +130 -0
  30. data/ext/libsass/src/ast_supports.hpp +121 -0
  31. data/ext/libsass/src/ast_values.cpp +967 -0
  32. data/ext/libsass/src/ast_values.hpp +489 -0
  33. data/ext/libsass/src/backtrace.cpp +4 -0
  34. data/ext/libsass/src/base64vlq.cpp +3 -0
  35. data/ext/libsass/src/bind.cpp +18 -17
  36. data/ext/libsass/src/bind.hpp +3 -1
  37. data/ext/libsass/src/c2ast.cpp +64 -0
  38. data/ext/libsass/src/c2ast.hpp +14 -0
  39. data/ext/libsass/src/cencode.c +2 -2
  40. data/ext/libsass/src/check_nesting.cpp +52 -56
  41. data/ext/libsass/src/check_nesting.hpp +35 -34
  42. data/ext/libsass/src/color_maps.cpp +156 -153
  43. data/ext/libsass/src/color_maps.hpp +152 -152
  44. data/ext/libsass/src/constants.cpp +15 -0
  45. data/ext/libsass/src/constants.hpp +13 -0
  46. data/ext/libsass/src/context.cpp +24 -14
  47. data/ext/libsass/src/context.hpp +6 -6
  48. data/ext/libsass/src/cssize.cpp +69 -71
  49. data/ext/libsass/src/cssize.hpp +50 -50
  50. data/ext/libsass/src/debugger.hpp +117 -110
  51. data/ext/libsass/src/emitter.cpp +13 -12
  52. data/ext/libsass/src/emitter.hpp +13 -9
  53. data/ext/libsass/src/environment.cpp +15 -1
  54. data/ext/libsass/src/environment.hpp +6 -0
  55. data/ext/libsass/src/error_handling.cpp +36 -59
  56. data/ext/libsass/src/error_handling.hpp +29 -16
  57. data/ext/libsass/src/eval.cpp +302 -323
  58. data/ext/libsass/src/eval.hpp +64 -55
  59. data/ext/libsass/src/expand.cpp +94 -88
  60. data/ext/libsass/src/expand.hpp +33 -37
  61. data/ext/libsass/src/extend.cpp +38 -36
  62. data/ext/libsass/src/extend.hpp +15 -15
  63. data/ext/libsass/src/file.cpp +34 -2
  64. data/ext/libsass/src/fn_colors.cpp +594 -0
  65. data/ext/libsass/src/fn_colors.hpp +85 -0
  66. data/ext/libsass/src/fn_lists.cpp +284 -0
  67. data/ext/libsass/src/fn_lists.hpp +34 -0
  68. data/ext/libsass/src/fn_maps.cpp +94 -0
  69. data/ext/libsass/src/fn_maps.hpp +30 -0
  70. data/ext/libsass/src/fn_miscs.cpp +256 -0
  71. data/ext/libsass/src/fn_miscs.hpp +40 -0
  72. data/ext/libsass/src/fn_numbers.cpp +220 -0
  73. data/ext/libsass/src/fn_numbers.hpp +45 -0
  74. data/ext/libsass/src/fn_selectors.cpp +235 -0
  75. data/ext/libsass/src/fn_selectors.hpp +35 -0
  76. data/ext/libsass/src/fn_strings.cpp +254 -0
  77. data/ext/libsass/src/fn_strings.hpp +34 -0
  78. data/ext/libsass/src/fn_utils.cpp +156 -0
  79. data/ext/libsass/src/fn_utils.hpp +56 -0
  80. data/ext/libsass/src/inspect.cpp +101 -152
  81. data/ext/libsass/src/inspect.hpp +69 -73
  82. data/ext/libsass/src/json.cpp +2 -2
  83. data/ext/libsass/src/lexer.cpp +6 -3
  84. data/ext/libsass/src/listize.cpp +9 -11
  85. data/ext/libsass/src/listize.hpp +11 -7
  86. data/ext/libsass/src/memory/SharedPtr.cpp +2 -83
  87. data/ext/libsass/src/memory/SharedPtr.hpp +127 -143
  88. data/ext/libsass/src/node.cpp +13 -10
  89. data/ext/libsass/src/node.hpp +3 -3
  90. data/ext/libsass/src/operation.hpp +184 -144
  91. data/ext/libsass/src/operators.cpp +43 -17
  92. data/ext/libsass/src/operators.hpp +5 -5
  93. data/ext/libsass/src/output.cpp +21 -18
  94. data/ext/libsass/src/output.hpp +14 -21
  95. data/ext/libsass/src/parser.cpp +215 -183
  96. data/ext/libsass/src/parser.hpp +28 -24
  97. data/ext/libsass/src/plugins.cpp +5 -1
  98. data/ext/libsass/src/position.cpp +3 -0
  99. data/ext/libsass/src/prelexer.cpp +9 -3
  100. data/ext/libsass/src/prelexer.hpp +9 -9
  101. data/ext/libsass/src/remove_placeholders.cpp +14 -11
  102. data/ext/libsass/src/remove_placeholders.hpp +8 -9
  103. data/ext/libsass/src/sass.cpp +9 -3
  104. data/ext/libsass/src/sass.hpp +12 -9
  105. data/ext/libsass/src/sass2scss.cpp +45 -14
  106. data/ext/libsass/src/sass_context.cpp +18 -15
  107. data/ext/libsass/src/sass_functions.cpp +6 -3
  108. data/ext/libsass/src/sass_functions.hpp +1 -1
  109. data/ext/libsass/src/sass_util.cpp +3 -0
  110. data/ext/libsass/src/sass_values.cpp +21 -13
  111. data/ext/libsass/src/source_map.cpp +5 -2
  112. data/ext/libsass/src/source_map.hpp +2 -2
  113. data/ext/libsass/src/subset_map.cpp +4 -1
  114. data/ext/libsass/src/to_value.cpp +23 -21
  115. data/ext/libsass/src/to_value.hpp +18 -22
  116. data/ext/libsass/src/units.cpp +4 -0
  117. data/ext/libsass/src/units.hpp +1 -0
  118. data/ext/libsass/src/utf8/checked.h +12 -10
  119. data/ext/libsass/src/utf8/core.h +3 -0
  120. data/ext/libsass/src/utf8_string.cpp +3 -0
  121. data/ext/libsass/src/util.cpp +67 -75
  122. data/ext/libsass/src/util.hpp +64 -19
  123. data/ext/libsass/src/util_string.cpp +75 -0
  124. data/ext/libsass/src/util_string.hpp +19 -0
  125. data/ext/libsass/src/values.cpp +22 -13
  126. data/ext/libsass/src/values.hpp +2 -2
  127. data/ext/libsass/win/libsass.targets +30 -4
  128. data/ext/libsass/win/libsass.vcxproj.filters +82 -4
  129. data/lib/sassc.rb +24 -0
  130. data/lib/sassc/engine.rb +2 -2
  131. data/lib/sassc/native.rb +8 -1
  132. data/lib/sassc/version.rb +1 -1
  133. data/sassc.gemspec +19 -11
  134. data/test/engine_test.rb +26 -1
  135. data/test/native_test.rb +1 -1
  136. metadata +66 -72
  137. data/ext/Rakefile +0 -3
  138. data/ext/libsass/.github/CONTRIBUTING.md +0 -65
  139. data/ext/libsass/.github/ISSUE_TEMPLATE.md +0 -54
  140. data/ext/libsass/.travis.yml +0 -64
  141. data/ext/libsass/Readme.md +0 -104
  142. data/ext/libsass/SECURITY.md +0 -10
  143. data/ext/libsass/appveyor.yml +0 -91
  144. data/ext/libsass/docs/README.md +0 -20
  145. data/ext/libsass/docs/api-context-example.md +0 -45
  146. data/ext/libsass/docs/api-context-internal.md +0 -163
  147. data/ext/libsass/docs/api-context.md +0 -295
  148. data/ext/libsass/docs/api-doc.md +0 -215
  149. data/ext/libsass/docs/api-function-example.md +0 -67
  150. data/ext/libsass/docs/api-function-internal.md +0 -8
  151. data/ext/libsass/docs/api-function.md +0 -74
  152. data/ext/libsass/docs/api-importer-example.md +0 -112
  153. data/ext/libsass/docs/api-importer-internal.md +0 -20
  154. data/ext/libsass/docs/api-importer.md +0 -86
  155. data/ext/libsass/docs/api-value-example.md +0 -55
  156. data/ext/libsass/docs/api-value-internal.md +0 -76
  157. data/ext/libsass/docs/api-value.md +0 -154
  158. data/ext/libsass/docs/build-on-darwin.md +0 -27
  159. data/ext/libsass/docs/build-on-gentoo.md +0 -55
  160. data/ext/libsass/docs/build-on-windows.md +0 -139
  161. data/ext/libsass/docs/build-shared-library.md +0 -35
  162. data/ext/libsass/docs/build-with-autotools.md +0 -78
  163. data/ext/libsass/docs/build-with-makefiles.md +0 -68
  164. data/ext/libsass/docs/build-with-mingw.md +0 -107
  165. data/ext/libsass/docs/build-with-visual-studio.md +0 -90
  166. data/ext/libsass/docs/build.md +0 -97
  167. data/ext/libsass/docs/compatibility-plan.md +0 -48
  168. data/ext/libsass/docs/contributing.md +0 -17
  169. data/ext/libsass/docs/custom-functions-internal.md +0 -122
  170. data/ext/libsass/docs/dev-ast-memory.md +0 -223
  171. data/ext/libsass/docs/implementations.md +0 -56
  172. data/ext/libsass/docs/plugins.md +0 -47
  173. data/ext/libsass/docs/setup-environment.md +0 -68
  174. data/ext/libsass/docs/source-map-internals.md +0 -51
  175. data/ext/libsass/docs/trace.md +0 -26
  176. data/ext/libsass/docs/triage.md +0 -17
  177. data/ext/libsass/docs/unicode.md +0 -39
  178. data/ext/libsass/extconf.rb +0 -6
  179. data/ext/libsass/script/bootstrap +0 -13
  180. data/ext/libsass/script/branding +0 -10
  181. data/ext/libsass/script/ci-build-libsass +0 -134
  182. data/ext/libsass/script/ci-build-plugin +0 -62
  183. data/ext/libsass/script/ci-install-compiler +0 -6
  184. data/ext/libsass/script/ci-install-deps +0 -20
  185. data/ext/libsass/script/ci-report-coverage +0 -42
  186. data/ext/libsass/script/spec +0 -5
  187. data/ext/libsass/script/tap-driver +0 -652
  188. data/ext/libsass/script/tap-runner +0 -1
  189. data/ext/libsass/script/test-leaks.pl +0 -103
  190. data/ext/libsass/src/functions.cpp +0 -2234
  191. data/ext/libsass/src/functions.hpp +0 -198
  192. data/ext/libsass/src/to_c.hpp +0 -39
  193. data/ext/libsass/test/test_node.cpp +0 -94
  194. data/ext/libsass/test/test_paths.cpp +0 -28
  195. data/ext/libsass/test/test_selector_difference.cpp +0 -25
  196. data/ext/libsass/test/test_specificity.cpp +0 -25
  197. data/ext/libsass/test/test_subset_map.cpp +0 -472
  198. data/ext/libsass/test/test_superselector.cpp +0 -69
  199. data/ext/libsass/test/test_unification.cpp +0 -31
  200. data/lib/tasks/libsass.rb +0 -33
@@ -1 +0,0 @@
1
- $@ | tapout tap
@@ -1,103 +0,0 @@
1
- #!/usr/bin/perl
2
- ############################################################
3
- # this perl script is meant for developers only!
4
- # it will run all spec-tests (without verifying the
5
- # results) via valgrind to detect possible leaks.
6
- # expect that it takes 1h or more to finish!
7
- ############################################################
8
- # Prerequisite install: `cpan Parallel::Runner`
9
- # You may also need to install `cpan File::Find`
10
- # You may also need to install `cpan IPC::Run3`
11
- ############################################################
12
- # usage: `perl test-leaks.pl [threads]`
13
- # example: `time perl test-leaks.pl 4`
14
- ############################################################
15
- # leaks will be reported in "mem-leaks.log"
16
- ############################################################
17
-
18
- use strict;
19
- use warnings;
20
-
21
- ############################################################
22
- # configurations (you may adjust)
23
- ############################################################
24
-
25
- # number of threads to use
26
- my $threads = $ARGV[0] || 8;
27
-
28
- # the github repositories to checkout
29
- # if you need other branch, clone manually!
30
- my $sassc = "https://www.github.com/sass/sassc";
31
- my $specs = "https://www.github.com/sass/sass-spec";
32
-
33
- ############################################################
34
- # load modules
35
- ############################################################
36
-
37
- use IPC::Run3;
38
- use IO::Handle;
39
- use Fcntl qw(:flock);
40
- use File::Find::Rule;
41
- use Parallel::Runner;
42
- use List::Util qw(shuffle);
43
-
44
- ############################################################
45
- # check prerequisites
46
- ############################################################
47
-
48
- unless (-d "../sassc") {
49
- warn "sassc folder not found\n";
50
- warn "trying to checkout via git\n";
51
- system("git", "clone", $sassc, "../sassc");
52
- die "git command did not exit gracefully" if $?;
53
- }
54
-
55
- unless (-d "../sass-spec") {
56
- warn "sass-spec folder not found\n";
57
- warn "trying to checkout via git\n";
58
- system("git", "clone", $specs, "../sass-spec");
59
- die "git command did not exit gracefully" if $?;
60
- }
61
-
62
- unless (-f "../sassc/bin/sassc") {
63
- warn "sassc executable not found\n";
64
- warn "trying to compile via make\n";
65
- system("make", "-C", "../sassc", "-j", $threads);
66
- die "make command did not exit gracefully" if $?;
67
- }
68
-
69
- ############################################################
70
- # main runner code
71
- ############################################################
72
-
73
- my $root = "../sass-spec/spec";
74
- my @files = File::Find::Rule->file()
75
- ->name('input.scss')->in($root);
76
-
77
- open(my $leaks, ">", "mem-leaks.log");
78
- die "Cannot open log" unless $leaks;
79
- my $runner = Parallel::Runner->new($threads);
80
- die "Cannot start runner" unless $runner;
81
-
82
- print "##########################\n";
83
- print "Testing $#files spec files\n";
84
- print "##########################\n";
85
-
86
- foreach my $file (shuffle @files) {
87
- $runner->run(sub {
88
- $| = 1; select STDOUT;
89
- my $cmd = sprintf('../sassc/bin/sassc %s', $file);
90
- my $check = sprintf('valgrind --leak-check=yes %s', $cmd);
91
- run3($check, undef, \ my $out, \ my $err);
92
- if ($err =~ m/in use at exit: 0 bytes in 0 blocks/) {
93
- print "."; # print success indicator
94
- } else {
95
- print "F"; # print error indicator
96
- flock($leaks, LOCK_EX) or die "Cannot lock log";
97
- $leaks->printflush("#" x 80, "\n", $err, "\n");
98
- flock($leaks, LOCK_UN) or die "Cannot unlock log";
99
- }
100
- });
101
- }
102
-
103
- $runner->finish;
@@ -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
- }