sassc 2.0.1 → 2.1.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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
- }