sassc4 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/.gitmodules +3 -0
  4. data/.travis.yml +16 -0
  5. data/CHANGELOG.md +97 -0
  6. data/CODE_OF_CONDUCT.md +10 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE.txt +22 -0
  9. data/README.md +80 -0
  10. data/Rakefile +51 -0
  11. data/ext/depend +4 -0
  12. data/ext/extconf.rb +92 -0
  13. data/ext/libsass/VERSION +1 -0
  14. data/ext/libsass/contrib/plugin.cpp +60 -0
  15. data/ext/libsass/include/sass/base.h +97 -0
  16. data/ext/libsass/include/sass/context.h +174 -0
  17. data/ext/libsass/include/sass/functions.h +139 -0
  18. data/ext/libsass/include/sass/values.h +145 -0
  19. data/ext/libsass/include/sass/version.h +12 -0
  20. data/ext/libsass/include/sass.h +15 -0
  21. data/ext/libsass/include/sass2scss.h +120 -0
  22. data/ext/libsass/src/MurmurHash2.hpp +91 -0
  23. data/ext/libsass/src/ast.cpp +953 -0
  24. data/ext/libsass/src/ast.hpp +1064 -0
  25. data/ext/libsass/src/ast2c.cpp +80 -0
  26. data/ext/libsass/src/ast2c.hpp +39 -0
  27. data/ext/libsass/src/ast_def_macros.hpp +140 -0
  28. data/ext/libsass/src/ast_fwd_decl.cpp +31 -0
  29. data/ext/libsass/src/ast_fwd_decl.hpp +274 -0
  30. data/ext/libsass/src/ast_helpers.hpp +316 -0
  31. data/ext/libsass/src/ast_sel_cmp.cpp +396 -0
  32. data/ext/libsass/src/ast_sel_super.cpp +539 -0
  33. data/ext/libsass/src/ast_sel_unify.cpp +275 -0
  34. data/ext/libsass/src/ast_sel_weave.cpp +616 -0
  35. data/ext/libsass/src/ast_selectors.cpp +1070 -0
  36. data/ext/libsass/src/ast_selectors.hpp +523 -0
  37. data/ext/libsass/src/ast_supports.cpp +114 -0
  38. data/ext/libsass/src/ast_supports.hpp +121 -0
  39. data/ext/libsass/src/ast_values.cpp +1154 -0
  40. data/ext/libsass/src/ast_values.hpp +498 -0
  41. data/ext/libsass/src/b64/cencode.h +32 -0
  42. data/ext/libsass/src/b64/encode.h +79 -0
  43. data/ext/libsass/src/backtrace.cpp +50 -0
  44. data/ext/libsass/src/backtrace.hpp +29 -0
  45. data/ext/libsass/src/base64vlq.cpp +47 -0
  46. data/ext/libsass/src/base64vlq.hpp +30 -0
  47. data/ext/libsass/src/bind.cpp +312 -0
  48. data/ext/libsass/src/bind.hpp +15 -0
  49. data/ext/libsass/src/c2ast.cpp +64 -0
  50. data/ext/libsass/src/c2ast.hpp +14 -0
  51. data/ext/libsass/src/c99func.c +54 -0
  52. data/ext/libsass/src/cencode.c +106 -0
  53. data/ext/libsass/src/check_nesting.cpp +393 -0
  54. data/ext/libsass/src/check_nesting.hpp +70 -0
  55. data/ext/libsass/src/color_maps.cpp +652 -0
  56. data/ext/libsass/src/color_maps.hpp +323 -0
  57. data/ext/libsass/src/color_spaces.cpp +241 -0
  58. data/ext/libsass/src/color_spaces.hpp +227 -0
  59. data/ext/libsass/src/constants.cpp +199 -0
  60. data/ext/libsass/src/constants.hpp +200 -0
  61. data/ext/libsass/src/context.cpp +870 -0
  62. data/ext/libsass/src/context.hpp +140 -0
  63. data/ext/libsass/src/cssize.cpp +521 -0
  64. data/ext/libsass/src/cssize.hpp +71 -0
  65. data/ext/libsass/src/dart_helpers.hpp +199 -0
  66. data/ext/libsass/src/debug.hpp +43 -0
  67. data/ext/libsass/src/debugger.hpp +964 -0
  68. data/ext/libsass/src/emitter.cpp +297 -0
  69. data/ext/libsass/src/emitter.hpp +101 -0
  70. data/ext/libsass/src/environment.cpp +260 -0
  71. data/ext/libsass/src/environment.hpp +124 -0
  72. data/ext/libsass/src/error_handling.cpp +239 -0
  73. data/ext/libsass/src/error_handling.hpp +248 -0
  74. data/ext/libsass/src/eval.cpp +1543 -0
  75. data/ext/libsass/src/eval.hpp +110 -0
  76. data/ext/libsass/src/eval_selectors.cpp +75 -0
  77. data/ext/libsass/src/expand.cpp +875 -0
  78. data/ext/libsass/src/expand.hpp +98 -0
  79. data/ext/libsass/src/extender.cpp +1226 -0
  80. data/ext/libsass/src/extender.hpp +399 -0
  81. data/ext/libsass/src/extension.cpp +43 -0
  82. data/ext/libsass/src/extension.hpp +89 -0
  83. data/ext/libsass/src/file.cpp +531 -0
  84. data/ext/libsass/src/file.hpp +124 -0
  85. data/ext/libsass/src/fn_colors.cpp +836 -0
  86. data/ext/libsass/src/fn_colors.hpp +99 -0
  87. data/ext/libsass/src/fn_lists.cpp +285 -0
  88. data/ext/libsass/src/fn_lists.hpp +34 -0
  89. data/ext/libsass/src/fn_maps.cpp +94 -0
  90. data/ext/libsass/src/fn_maps.hpp +30 -0
  91. data/ext/libsass/src/fn_miscs.cpp +248 -0
  92. data/ext/libsass/src/fn_miscs.hpp +40 -0
  93. data/ext/libsass/src/fn_numbers.cpp +246 -0
  94. data/ext/libsass/src/fn_numbers.hpp +45 -0
  95. data/ext/libsass/src/fn_selectors.cpp +205 -0
  96. data/ext/libsass/src/fn_selectors.hpp +35 -0
  97. data/ext/libsass/src/fn_strings.cpp +268 -0
  98. data/ext/libsass/src/fn_strings.hpp +34 -0
  99. data/ext/libsass/src/fn_utils.cpp +159 -0
  100. data/ext/libsass/src/fn_utils.hpp +62 -0
  101. data/ext/libsass/src/inspect.cpp +1126 -0
  102. data/ext/libsass/src/inspect.hpp +101 -0
  103. data/ext/libsass/src/json.cpp +1436 -0
  104. data/ext/libsass/src/json.hpp +117 -0
  105. data/ext/libsass/src/kwd_arg_macros.hpp +28 -0
  106. data/ext/libsass/src/lexer.cpp +122 -0
  107. data/ext/libsass/src/lexer.hpp +304 -0
  108. data/ext/libsass/src/listize.cpp +70 -0
  109. data/ext/libsass/src/listize.hpp +37 -0
  110. data/ext/libsass/src/mapping.hpp +19 -0
  111. data/ext/libsass/src/memory/allocator.cpp +48 -0
  112. data/ext/libsass/src/memory/allocator.hpp +138 -0
  113. data/ext/libsass/src/memory/config.hpp +20 -0
  114. data/ext/libsass/src/memory/memory_pool.hpp +186 -0
  115. data/ext/libsass/src/memory/shared_ptr.cpp +33 -0
  116. data/ext/libsass/src/memory/shared_ptr.hpp +332 -0
  117. data/ext/libsass/src/memory.hpp +12 -0
  118. data/ext/libsass/src/operation.hpp +223 -0
  119. data/ext/libsass/src/operators.cpp +267 -0
  120. data/ext/libsass/src/operators.hpp +30 -0
  121. data/ext/libsass/src/ordered_map.hpp +112 -0
  122. data/ext/libsass/src/output.cpp +320 -0
  123. data/ext/libsass/src/output.hpp +47 -0
  124. data/ext/libsass/src/parser.cpp +3059 -0
  125. data/ext/libsass/src/parser.hpp +395 -0
  126. data/ext/libsass/src/parser_selectors.cpp +189 -0
  127. data/ext/libsass/src/permutate.hpp +164 -0
  128. data/ext/libsass/src/plugins.cpp +188 -0
  129. data/ext/libsass/src/plugins.hpp +57 -0
  130. data/ext/libsass/src/position.cpp +163 -0
  131. data/ext/libsass/src/position.hpp +147 -0
  132. data/ext/libsass/src/prelexer.cpp +1780 -0
  133. data/ext/libsass/src/prelexer.hpp +484 -0
  134. data/ext/libsass/src/remove_placeholders.cpp +86 -0
  135. data/ext/libsass/src/remove_placeholders.hpp +37 -0
  136. data/ext/libsass/src/sass.cpp +156 -0
  137. data/ext/libsass/src/sass.hpp +147 -0
  138. data/ext/libsass/src/sass2scss.cpp +895 -0
  139. data/ext/libsass/src/sass_context.cpp +742 -0
  140. data/ext/libsass/src/sass_context.hpp +129 -0
  141. data/ext/libsass/src/sass_functions.cpp +210 -0
  142. data/ext/libsass/src/sass_functions.hpp +50 -0
  143. data/ext/libsass/src/sass_values.cpp +362 -0
  144. data/ext/libsass/src/sass_values.hpp +82 -0
  145. data/ext/libsass/src/settings.hpp +19 -0
  146. data/ext/libsass/src/source.cpp +69 -0
  147. data/ext/libsass/src/source.hpp +95 -0
  148. data/ext/libsass/src/source_data.hpp +32 -0
  149. data/ext/libsass/src/source_map.cpp +202 -0
  150. data/ext/libsass/src/source_map.hpp +65 -0
  151. data/ext/libsass/src/stylesheet.cpp +22 -0
  152. data/ext/libsass/src/stylesheet.hpp +57 -0
  153. data/ext/libsass/src/to_value.cpp +114 -0
  154. data/ext/libsass/src/to_value.hpp +46 -0
  155. data/ext/libsass/src/units.cpp +507 -0
  156. data/ext/libsass/src/units.hpp +110 -0
  157. data/ext/libsass/src/utf8/checked.h +336 -0
  158. data/ext/libsass/src/utf8/core.h +332 -0
  159. data/ext/libsass/src/utf8/unchecked.h +235 -0
  160. data/ext/libsass/src/utf8.h +34 -0
  161. data/ext/libsass/src/utf8_string.cpp +104 -0
  162. data/ext/libsass/src/utf8_string.hpp +38 -0
  163. data/ext/libsass/src/util.cpp +723 -0
  164. data/ext/libsass/src/util.hpp +105 -0
  165. data/ext/libsass/src/util_string.cpp +125 -0
  166. data/ext/libsass/src/util_string.hpp +73 -0
  167. data/ext/libsass/src/values.cpp +140 -0
  168. data/ext/libsass/src/values.hpp +12 -0
  169. data/lib/sassc/dependency.rb +17 -0
  170. data/lib/sassc/engine.rb +141 -0
  171. data/lib/sassc/error.rb +37 -0
  172. data/lib/sassc/functions_handler.rb +73 -0
  173. data/lib/sassc/import_handler.rb +50 -0
  174. data/lib/sassc/importer.rb +31 -0
  175. data/lib/sassc/native/native_context_api.rb +147 -0
  176. data/lib/sassc/native/native_functions_api.rb +159 -0
  177. data/lib/sassc/native/sass2scss_api.rb +10 -0
  178. data/lib/sassc/native/sass_input_style.rb +13 -0
  179. data/lib/sassc/native/sass_output_style.rb +12 -0
  180. data/lib/sassc/native/sass_value.rb +97 -0
  181. data/lib/sassc/native/string_list.rb +10 -0
  182. data/lib/sassc/native.rb +64 -0
  183. data/lib/sassc/sass_2_scss.rb +9 -0
  184. data/lib/sassc/script/functions.rb +8 -0
  185. data/lib/sassc/script/value/bool.rb +32 -0
  186. data/lib/sassc/script/value/color.rb +95 -0
  187. data/lib/sassc/script/value/list.rb +136 -0
  188. data/lib/sassc/script/value/map.rb +69 -0
  189. data/lib/sassc/script/value/number.rb +389 -0
  190. data/lib/sassc/script/value/string.rb +96 -0
  191. data/lib/sassc/script/value.rb +137 -0
  192. data/lib/sassc/script/value_conversion/base.rb +13 -0
  193. data/lib/sassc/script/value_conversion/bool.rb +13 -0
  194. data/lib/sassc/script/value_conversion/color.rb +18 -0
  195. data/lib/sassc/script/value_conversion/list.rb +25 -0
  196. data/lib/sassc/script/value_conversion/map.rb +21 -0
  197. data/lib/sassc/script/value_conversion/number.rb +13 -0
  198. data/lib/sassc/script/value_conversion/string.rb +17 -0
  199. data/lib/sassc/script/value_conversion.rb +69 -0
  200. data/lib/sassc/script.rb +17 -0
  201. data/lib/sassc/util/normalized_map.rb +117 -0
  202. data/lib/sassc/util.rb +231 -0
  203. data/lib/sassc/version.rb +5 -0
  204. data/lib/sassc.rb +57 -0
  205. data/sassc.gemspec +69 -0
  206. data/test/css_color_level4_test.rb +168 -0
  207. data/test/custom_importer_test.rb +127 -0
  208. data/test/engine_test.rb +314 -0
  209. data/test/error_test.rb +29 -0
  210. data/test/fixtures/paths.scss +10 -0
  211. data/test/functions_test.rb +340 -0
  212. data/test/native_test.rb +213 -0
  213. data/test/output_style_test.rb +107 -0
  214. data/test/sass_2_scss_test.rb +14 -0
  215. data/test/test_helper.rb +45 -0
  216. metadata +396 -0
@@ -0,0 +1,870 @@
1
+ // sass.hpp must go before all system headers to get the
2
+ // __EXTENSIONS__ fix on Solaris.
3
+ #include "sass.hpp"
4
+ #include "ast.hpp"
5
+
6
+ #include "remove_placeholders.hpp"
7
+ #include "sass_functions.hpp"
8
+ #include "check_nesting.hpp"
9
+ #include "fn_selectors.hpp"
10
+ #include "fn_strings.hpp"
11
+ #include "fn_numbers.hpp"
12
+ #include "fn_colors.hpp"
13
+ #include "fn_miscs.hpp"
14
+ #include "fn_lists.hpp"
15
+ #include "fn_maps.hpp"
16
+ #include "context.hpp"
17
+ #include "expand.hpp"
18
+ #include "parser.hpp"
19
+ #include "cssize.hpp"
20
+ #include "source.hpp"
21
+
22
+ namespace Sass {
23
+ using namespace Constants;
24
+ using namespace File;
25
+ using namespace Sass;
26
+
27
+ inline bool sort_importers (const Sass_Importer_Entry& i, const Sass_Importer_Entry& j)
28
+ { return sass_importer_get_priority(i) > sass_importer_get_priority(j); }
29
+
30
+ static sass::string safe_input(const char* in_path)
31
+ {
32
+ if (in_path == nullptr || in_path[0] == '\0') return "stdin";
33
+ return in_path;
34
+ }
35
+
36
+ static sass::string safe_output(const char* out_path, sass::string input_path)
37
+ {
38
+ if (out_path == nullptr || out_path[0] == '\0') {
39
+ if (input_path.empty()) return "stdout";
40
+ return input_path.substr(0, input_path.find_last_of(".")) + ".css";
41
+ }
42
+ return out_path;
43
+ }
44
+
45
+ Context::Context(struct Sass_Context& c_ctx)
46
+ : CWD(File::get_cwd()),
47
+ c_options(c_ctx),
48
+ entry_path(""),
49
+ head_imports(0),
50
+ plugins(),
51
+ emitter(c_options),
52
+
53
+ ast_gc(),
54
+ strings(),
55
+ resources(),
56
+ sheets(),
57
+ import_stack(),
58
+ callee_stack(),
59
+ traces(),
60
+ extender(Extender::NORMAL, traces),
61
+ c_compiler(NULL),
62
+
63
+ c_headers (sass::vector<Sass_Importer_Entry>()),
64
+ c_importers (sass::vector<Sass_Importer_Entry>()),
65
+ c_functions (sass::vector<Sass_Function_Entry>()),
66
+
67
+ indent (safe_str(c_options.indent, " ")),
68
+ linefeed (safe_str(c_options.linefeed, "\n")),
69
+
70
+ input_path (make_canonical_path(safe_input(c_options.input_path))),
71
+ output_path (make_canonical_path(safe_output(c_options.output_path, input_path))),
72
+ source_map_file (make_canonical_path(safe_str(c_options.source_map_file, ""))),
73
+ source_map_root (make_canonical_path(safe_str(c_options.source_map_root, "")))
74
+
75
+ {
76
+
77
+ // Sass 3.4: The current working directory will no longer be placed onto the Sass load path by default.
78
+ // If you need the current working directory to be available, set SASS_PATH=. in your shell's environment.
79
+ // include_paths.push_back(CWD);
80
+
81
+ // collect more paths from different options
82
+ collect_include_paths(c_options.include_path);
83
+ collect_include_paths(c_options.include_paths);
84
+ collect_plugin_paths(c_options.plugin_path);
85
+ collect_plugin_paths(c_options.plugin_paths);
86
+
87
+ // load plugins and register custom behaviors
88
+ for(auto plug : plugin_paths) plugins.load_plugins(plug);
89
+ for(auto fn : plugins.get_headers()) c_headers.push_back(fn);
90
+ for(auto fn : plugins.get_importers()) c_importers.push_back(fn);
91
+ for(auto fn : plugins.get_functions()) c_functions.push_back(fn);
92
+
93
+ // sort the items by priority (lowest first)
94
+ sort (c_headers.begin(), c_headers.end(), sort_importers);
95
+ sort (c_importers.begin(), c_importers.end(), sort_importers);
96
+
97
+ emitter.set_filename(abs2rel(output_path, source_map_file, CWD));
98
+
99
+ }
100
+
101
+ void Context::add_c_function(Sass_Function_Entry function)
102
+ {
103
+ c_functions.push_back(function);
104
+ }
105
+ void Context::add_c_header(Sass_Importer_Entry header)
106
+ {
107
+ c_headers.push_back(header);
108
+ // need to sort the array afterwards (no big deal)
109
+ sort (c_headers.begin(), c_headers.end(), sort_importers);
110
+ }
111
+ void Context::add_c_importer(Sass_Importer_Entry importer)
112
+ {
113
+ c_importers.push_back(importer);
114
+ // need to sort the array afterwards (no big deal)
115
+ sort (c_importers.begin(), c_importers.end(), sort_importers);
116
+ }
117
+
118
+ Context::~Context()
119
+ {
120
+ // resources were allocated by malloc
121
+ for (size_t i = 0; i < resources.size(); ++i) {
122
+ free(resources[i].contents);
123
+ free(resources[i].srcmap);
124
+ }
125
+ // free all strings we kept alive during compiler execution
126
+ for (size_t n = 0; n < strings.size(); ++n) free(strings[n]);
127
+ // everything that gets put into sources will be freed by us
128
+ // this shouldn't have anything in it anyway!?
129
+ for (size_t m = 0; m < import_stack.size(); ++m) {
130
+ sass_import_take_source(import_stack[m]);
131
+ sass_import_take_srcmap(import_stack[m]);
132
+ sass_delete_import(import_stack[m]);
133
+ }
134
+ // clear inner structures (vectors) and input source
135
+ resources.clear(); import_stack.clear();
136
+ sheets.clear();
137
+ }
138
+
139
+ Data_Context::~Data_Context()
140
+ {
141
+ // --> this will be freed by resources
142
+ // make sure we free the source even if not processed!
143
+ // if (resources.size() == 0 && source_c_str) free(source_c_str);
144
+ // if (resources.size() == 0 && srcmap_c_str) free(srcmap_c_str);
145
+ // source_c_str = 0; srcmap_c_str = 0;
146
+ }
147
+
148
+ File_Context::~File_Context()
149
+ {
150
+ }
151
+
152
+ void Context::collect_include_paths(const char* paths_str)
153
+ {
154
+ if (paths_str) {
155
+ const char* beg = paths_str;
156
+ const char* end = Prelexer::find_first<PATH_SEP>(beg);
157
+
158
+ while (end) {
159
+ sass::string path(beg, end - beg);
160
+ if (!path.empty()) {
161
+ if (*path.rbegin() != '/') path += '/';
162
+ include_paths.push_back(path);
163
+ }
164
+ beg = end + 1;
165
+ end = Prelexer::find_first<PATH_SEP>(beg);
166
+ }
167
+
168
+ sass::string path(beg);
169
+ if (!path.empty()) {
170
+ if (*path.rbegin() != '/') path += '/';
171
+ include_paths.push_back(path);
172
+ }
173
+ }
174
+ }
175
+
176
+ void Context::collect_include_paths(string_list* paths_array)
177
+ {
178
+ while (paths_array)
179
+ {
180
+ collect_include_paths(paths_array->string);
181
+ paths_array = paths_array->next;
182
+ }
183
+ }
184
+
185
+ void Context::collect_plugin_paths(const char* paths_str)
186
+ {
187
+ if (paths_str) {
188
+ const char* beg = paths_str;
189
+ const char* end = Prelexer::find_first<PATH_SEP>(beg);
190
+
191
+ while (end) {
192
+ sass::string path(beg, end - beg);
193
+ if (!path.empty()) {
194
+ if (*path.rbegin() != '/') path += '/';
195
+ plugin_paths.push_back(path);
196
+ }
197
+ beg = end + 1;
198
+ end = Prelexer::find_first<PATH_SEP>(beg);
199
+ }
200
+
201
+ sass::string path(beg);
202
+ if (!path.empty()) {
203
+ if (*path.rbegin() != '/') path += '/';
204
+ plugin_paths.push_back(path);
205
+ }
206
+ }
207
+ }
208
+
209
+ void Context::collect_plugin_paths(string_list* paths_array)
210
+ {
211
+ while (paths_array)
212
+ {
213
+ collect_plugin_paths(paths_array->string);
214
+ paths_array = paths_array->next;
215
+ }
216
+ }
217
+
218
+ // resolve the imp_path in base_path or include_paths
219
+ // looks for alternatives and returns a list from one directory
220
+ sass::vector<Include> Context::find_includes(const Importer& import)
221
+ {
222
+ // make sure we resolve against an absolute path
223
+ sass::string base_path(rel2abs(import.base_path));
224
+ // first try to resolve the load path relative to the base path
225
+ sass::vector<Include> vec(resolve_includes(base_path, import.imp_path));
226
+ // then search in every include path (but only if nothing found yet)
227
+ for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
228
+ {
229
+ // call resolve_includes and individual base path and append all results
230
+ sass::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path));
231
+ if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
232
+ }
233
+ // return vector
234
+ return vec;
235
+ }
236
+
237
+ // register include with resolved path and its content
238
+ // memory of the resources will be freed by us on exit
239
+ void Context::register_resource(const Include& inc, const Resource& res)
240
+ {
241
+
242
+ // do not parse same resource twice
243
+ // maybe raise an error in this case
244
+ // if (sheets.count(inc.abs_path)) {
245
+ // free(res.contents); free(res.srcmap);
246
+ // throw std::runtime_error("duplicate resource registered");
247
+ // return;
248
+ // }
249
+
250
+ // get index for this resource
251
+ size_t idx = resources.size();
252
+
253
+ // tell emitter about new resource
254
+ emitter.add_source_index(idx);
255
+
256
+ // put resources under our control
257
+ // the memory will be freed later
258
+ resources.push_back(res);
259
+
260
+ // add a relative link to the working directory
261
+ included_files.push_back(inc.abs_path);
262
+ // add a relative link to the source map output file
263
+ srcmap_links.push_back(abs2rel(inc.abs_path, source_map_file, CWD));
264
+
265
+ // get pointer to the loaded content
266
+ Sass_Import_Entry import = sass_make_import(
267
+ inc.imp_path.c_str(),
268
+ inc.abs_path.c_str(),
269
+ res.contents,
270
+ res.srcmap
271
+ );
272
+ // add the entry to the stack
273
+ import_stack.push_back(import);
274
+
275
+ // get pointer to the loaded content
276
+ const char* contents = resources[idx].contents;
277
+ SourceFileObj source = SASS_MEMORY_NEW(SourceFile,
278
+ inc.abs_path.c_str(), contents, idx);
279
+
280
+ // create the initial parser state from resource
281
+ SourceSpan pstate(source);
282
+
283
+ // check existing import stack for possible recursion
284
+ for (size_t i = 0; i < import_stack.size() - 2; ++i) {
285
+ auto parent = import_stack[i];
286
+ if (std::strcmp(parent->abs_path, import->abs_path) == 0) {
287
+ sass::string cwd(File::get_cwd());
288
+ // make path relative to the current directory
289
+ sass::string stack("An @import loop has been found:");
290
+ for (size_t n = 1; n < i + 2; ++n) {
291
+ stack += "\n " + sass::string(File::abs2rel(import_stack[n]->abs_path, cwd, cwd)) +
292
+ " imports " + sass::string(File::abs2rel(import_stack[n+1]->abs_path, cwd, cwd));
293
+ }
294
+ // implement error throw directly until we
295
+ // decided how to handle full stack traces
296
+ throw Exception::InvalidSyntax(pstate, traces, stack);
297
+ // error(stack, prstate ? *prstate : pstate, import_stack);
298
+ }
299
+ }
300
+
301
+ // create a parser instance from the given c_str buffer
302
+ Parser p(source, *this, traces);
303
+ // do not yet dispose these buffers
304
+ sass_import_take_source(import);
305
+ sass_import_take_srcmap(import);
306
+ // then parse the root block
307
+ Block_Obj root = p.parse();
308
+ // delete memory of current stack frame
309
+ sass_delete_import(import_stack.back());
310
+ // remove current stack frame
311
+ import_stack.pop_back();
312
+ // create key/value pair for ast node
313
+ std::pair<const sass::string, StyleSheet>
314
+ ast_pair(inc.abs_path, { res, root });
315
+ // register resulting resource
316
+ sheets.insert(ast_pair);
317
+ }
318
+
319
+ // register include with resolved path and its content
320
+ // memory of the resources will be freed by us on exit
321
+ void Context::register_resource(const Include& inc, const Resource& res, SourceSpan& prstate)
322
+ {
323
+ traces.push_back(Backtrace(prstate));
324
+ register_resource(inc, res);
325
+ traces.pop_back();
326
+ }
327
+
328
+ // Add a new import to the context (called from `import_url`)
329
+ Include Context::load_import(const Importer& imp, SourceSpan pstate)
330
+ {
331
+
332
+ // search for valid imports (ie. partials) on the filesystem
333
+ // this may return more than one valid result (ambiguous imp_path)
334
+ const sass::vector<Include> resolved(find_includes(imp));
335
+
336
+ // error nicely on ambiguous imp_path
337
+ if (resolved.size() > 1) {
338
+ sass::ostream msg_stream;
339
+ msg_stream << "It's not clear which file to import for ";
340
+ msg_stream << "'@import \"" << imp.imp_path << "\"'." << "\n";
341
+ msg_stream << "Candidates:" << "\n";
342
+ for (size_t i = 0, L = resolved.size(); i < L; ++i)
343
+ { msg_stream << " " << resolved[i].imp_path << "\n"; }
344
+ msg_stream << "Please delete or rename all but one of these files." << "\n";
345
+ error(msg_stream.str(), pstate, traces);
346
+ }
347
+
348
+ // process the resolved entry
349
+ else if (resolved.size() == 1) {
350
+ bool use_cache = c_importers.size() == 0;
351
+ // use cache for the resource loading
352
+ if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0];
353
+ // try to read the content of the resolved file entry
354
+ // the memory buffer returned must be freed by us!
355
+ if (char* contents = read_file(resolved[0].abs_path)) {
356
+ // register the newly resolved file resource
357
+ register_resource(resolved[0], { contents, 0 }, pstate);
358
+ // return resolved entry
359
+ return resolved[0];
360
+ }
361
+ }
362
+
363
+ // nothing found
364
+ return { imp, "" };
365
+
366
+ }
367
+
368
+ void Context::import_url (Import* imp, sass::string load_path, const sass::string& ctx_path) {
369
+
370
+ SourceSpan pstate(imp->pstate());
371
+ sass::string imp_path(unquote(load_path));
372
+ sass::string protocol("file");
373
+
374
+ using namespace Prelexer;
375
+ if (const char* proto = sequence< identifier, exactly<':'>, exactly<'/'>, exactly<'/'> >(imp_path.c_str())) {
376
+
377
+ protocol = sass::string(imp_path.c_str(), proto - 3);
378
+ // if (protocol.compare("file") && true) { }
379
+ }
380
+
381
+ // add urls (protocol other than file) and urls without protocol to `urls` member
382
+ // ToDo: if ctx_path is already a file resource, we should not add it here?
383
+ if (imp->import_queries() || protocol != "file" || imp_path.substr(0, 2) == "//") {
384
+ imp->urls().push_back(SASS_MEMORY_NEW(String_Quoted, imp->pstate(), load_path));
385
+ }
386
+ else if (imp_path.length() > 4 && imp_path.substr(imp_path.length() - 4, 4) == ".css") {
387
+ String_Constant* loc = SASS_MEMORY_NEW(String_Constant, pstate, unquote(load_path));
388
+ Argument_Obj loc_arg = SASS_MEMORY_NEW(Argument, pstate, loc);
389
+ Arguments_Obj loc_args = SASS_MEMORY_NEW(Arguments, pstate);
390
+ loc_args->append(loc_arg);
391
+ Function_Call* new_url = SASS_MEMORY_NEW(Function_Call, pstate, sass::string("url"), loc_args);
392
+ imp->urls().push_back(new_url);
393
+ }
394
+ else {
395
+ const Importer importer(imp_path, ctx_path);
396
+ Include include(load_import(importer, pstate));
397
+ if (include.abs_path.empty()) {
398
+ error("File to import not found or unreadable: " + imp_path + ".", pstate, traces);
399
+ }
400
+ imp->incs().push_back(include);
401
+ }
402
+
403
+ }
404
+
405
+
406
+ // call custom importers on the given (unquoted) load_path and eventually parse the resulting style_sheet
407
+ bool Context::call_loader(const sass::string& load_path, const char* ctx_path, SourceSpan& pstate, Import* imp, sass::vector<Sass_Importer_Entry> importers, bool only_one)
408
+ {
409
+ // unique counter
410
+ size_t count = 0;
411
+ // need one correct import
412
+ bool has_import = false;
413
+ // process all custom importers (or custom headers)
414
+ for (Sass_Importer_Entry& importer_ent : importers) {
415
+ // int priority = sass_importer_get_priority(importer);
416
+ Sass_Importer_Fn fn = sass_importer_get_function(importer_ent);
417
+ // skip importer if it returns NULL
418
+ if (Sass_Import_List includes =
419
+ fn(load_path.c_str(), importer_ent, c_compiler)
420
+ ) {
421
+ // get c pointer copy to iterate over
422
+ Sass_Import_List it_includes = includes;
423
+ while (*it_includes) { ++count;
424
+ // create unique path to use as key
425
+ sass::string uniq_path = load_path;
426
+ if (!only_one && count) {
427
+ sass::ostream path_strm;
428
+ path_strm << uniq_path << ":" << count;
429
+ uniq_path = path_strm.str();
430
+ }
431
+ // create the importer struct
432
+ Importer importer(uniq_path, ctx_path);
433
+ // query data from the current include
434
+ Sass_Import_Entry include_ent = *it_includes;
435
+ char* source = sass_import_take_source(include_ent);
436
+ char* srcmap = sass_import_take_srcmap(include_ent);
437
+ size_t line = sass_import_get_error_line(include_ent);
438
+ size_t column = sass_import_get_error_column(include_ent);
439
+ const char *abs_path = sass_import_get_abs_path(include_ent);
440
+ // handle error message passed back from custom importer
441
+ // it may (or may not) override the line and column info
442
+ if (const char* err_message = sass_import_get_error_message(include_ent)) {
443
+ if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, pstate);
444
+ if (line == sass::string::npos && column == sass::string::npos) error(err_message, pstate, traces);
445
+ else { error(err_message, { pstate.source, { line, column } }, traces); }
446
+ }
447
+ // content for import was set
448
+ else if (source) {
449
+ // resolved abs_path should be set by custom importer
450
+ // use the created uniq_path as fallback (maybe enforce)
451
+ sass::string path_key(abs_path ? abs_path : uniq_path);
452
+ // create the importer struct
453
+ Include include(importer, path_key);
454
+ // attach information to AST node
455
+ imp->incs().push_back(include);
456
+ // register the resource buffers
457
+ register_resource(include, { source, srcmap }, pstate);
458
+ }
459
+ // only a path was retuned
460
+ // try to load it like normal
461
+ else if(abs_path) {
462
+ // checks some urls to preserve
463
+ // `http://`, `https://` and `//`
464
+ // or dispatchs to `import_file`
465
+ // which will check for a `.css` extension
466
+ // or resolves the file on the filesystem
467
+ // added and resolved via `add_file`
468
+ // finally stores everything on `imp`
469
+ import_url(imp, abs_path, ctx_path);
470
+ }
471
+ // move to next
472
+ ++it_includes;
473
+ }
474
+ // deallocate the returned memory
475
+ sass_delete_import_list(includes);
476
+ // set success flag
477
+ has_import = true;
478
+ // break out of loop
479
+ if (only_one) break;
480
+ }
481
+ }
482
+ // return result
483
+ return has_import;
484
+ }
485
+
486
+ void register_function(Context&, Signature sig, Native_Function f, Env* env);
487
+ void register_function(Context&, Signature sig, Native_Function f, size_t arity, Env* env);
488
+ void register_overload_stub(Context&, sass::string name, Env* env);
489
+ void register_built_in_functions(Context&, Env* env);
490
+ void register_c_functions(Context&, Env* env, Sass_Function_List);
491
+ void register_c_function(Context&, Env* env, Sass_Function_Entry);
492
+
493
+ char* Context::render(Block_Obj root)
494
+ {
495
+ // check for valid block
496
+ if (!root) return 0;
497
+ // start the render process
498
+ root->perform(&emitter);
499
+ // finish emitter stream
500
+ emitter.finalize();
501
+ // get the resulting buffer from stream
502
+ OutputBuffer emitted = emitter.get_buffer();
503
+ // should we append a source map url?
504
+ if (!c_options.omit_source_map_url) {
505
+ // generate an embedded source map
506
+ if (c_options.source_map_embed) {
507
+ emitted.buffer += linefeed;
508
+ emitted.buffer += format_embedded_source_map();
509
+ }
510
+ // or just link the generated one
511
+ else if (source_map_file != "") {
512
+ emitted.buffer += linefeed;
513
+ emitted.buffer += format_source_mapping_url(source_map_file);
514
+ }
515
+ }
516
+ // create a copy of the resulting buffer string
517
+ // this must be freed or taken over by implementor
518
+ return sass_copy_c_string(emitted.buffer.c_str());
519
+ }
520
+
521
+ void Context::apply_custom_headers(Block_Obj root, const char* ctx_path, SourceSpan pstate)
522
+ {
523
+ // create a custom import to resolve headers
524
+ Import_Obj imp = SASS_MEMORY_NEW(Import, pstate);
525
+ // dispatch headers which will add custom functions
526
+ // custom headers are added to the import instance
527
+ call_headers(entry_path, ctx_path, pstate, imp);
528
+ // increase head count to skip later
529
+ head_imports += resources.size() - 1;
530
+ // add the statement if we have urls
531
+ if (!imp->urls().empty()) root->append(imp);
532
+ // process all other resources (add Import_Stub nodes)
533
+ for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
534
+ root->append(SASS_MEMORY_NEW(Import_Stub, pstate, imp->incs()[i]));
535
+ }
536
+ }
537
+
538
+ Block_Obj File_Context::parse()
539
+ {
540
+
541
+ // check if entry file is given
542
+ if (input_path.empty()) return {};
543
+
544
+ // create absolute path from input filename
545
+ // ToDo: this should be resolved via custom importers
546
+ sass::string abs_path(rel2abs(input_path, CWD));
547
+
548
+ // try to load the entry file
549
+ char* contents = read_file(abs_path);
550
+
551
+ // alternatively also look inside each include path folder
552
+ // I think this differs from ruby sass (IMO too late to remove)
553
+ for (size_t i = 0, S = include_paths.size(); contents == 0 && i < S; ++i) {
554
+ // build absolute path for this include path entry
555
+ abs_path = rel2abs(input_path, include_paths[i]);
556
+ // try to load the resulting path
557
+ contents = read_file(abs_path);
558
+ }
559
+
560
+ // abort early if no content could be loaded (various reasons)
561
+ if (!contents) throw std::runtime_error(
562
+ "File to read not found or unreadable: "
563
+ + std::string(input_path.c_str()));
564
+
565
+ // store entry path
566
+ entry_path = abs_path;
567
+
568
+ // create entry only for import stack
569
+ Sass_Import_Entry import = sass_make_import(
570
+ input_path.c_str(),
571
+ entry_path.c_str(),
572
+ contents,
573
+ 0
574
+ );
575
+ // add the entry to the stack
576
+ import_stack.push_back(import);
577
+
578
+ // create the source entry for file entry
579
+ register_resource({{ input_path, "." }, abs_path }, { contents, 0 });
580
+
581
+ // create root ast tree node
582
+ return compile();
583
+
584
+ }
585
+
586
+ Block_Obj Data_Context::parse()
587
+ {
588
+
589
+ // check if source string is given
590
+ if (!source_c_str) return {};
591
+
592
+ // convert indented sass syntax
593
+ if(c_options.is_indented_syntax_src) {
594
+ // call sass2scss to convert the string
595
+ char * converted = sass2scss(source_c_str,
596
+ // preserve the structure as much as possible
597
+ SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
598
+ // replace old source_c_str with converted
599
+ free(source_c_str); source_c_str = converted;
600
+ }
601
+
602
+ // remember entry path (defaults to stdin for string)
603
+ entry_path = input_path.empty() ? "stdin" : input_path;
604
+
605
+ // ToDo: this may be resolved via custom importers
606
+ sass::string abs_path(rel2abs(entry_path));
607
+ char* abs_path_c_str = sass_copy_c_string(abs_path.c_str());
608
+ strings.push_back(abs_path_c_str);
609
+
610
+ // create entry only for the import stack
611
+ Sass_Import_Entry import = sass_make_import(
612
+ entry_path.c_str(),
613
+ abs_path_c_str,
614
+ source_c_str,
615
+ srcmap_c_str
616
+ );
617
+ // add the entry to the stack
618
+ import_stack.push_back(import);
619
+
620
+ // register a synthetic resource (path does not really exist, skip in includes)
621
+ register_resource({{ input_path, "." }, input_path }, { source_c_str, srcmap_c_str });
622
+
623
+ // create root ast tree node
624
+ return compile();
625
+ }
626
+
627
+ // parse root block from includes
628
+ Block_Obj Context::compile()
629
+ {
630
+ // abort if there is no data
631
+ if (resources.size() == 0) return {};
632
+ // get root block from the first style sheet
633
+ Block_Obj root = sheets.at(entry_path).root;
634
+ // abort on invalid root
635
+ if (root.isNull()) return {};
636
+ Env global; // create root environment
637
+ // register built-in functions on env
638
+ register_built_in_functions(*this, &global);
639
+ // register custom functions (defined via C-API)
640
+ for (size_t i = 0, S = c_functions.size(); i < S; ++i)
641
+ { register_c_function(*this, &global, c_functions[i]); }
642
+ // create initial backtrace entry
643
+ // create crtp visitor objects
644
+ Expand expand(*this, &global);
645
+ Cssize cssize(*this);
646
+ CheckNesting check_nesting;
647
+ // check nesting in all files
648
+ for (auto sheet : sheets) {
649
+ auto styles = sheet.second;
650
+ check_nesting(styles.root);
651
+ }
652
+ // expand and eval the tree
653
+ root = expand(root);
654
+
655
+ Extension unsatisfied;
656
+ // check that all extends were used
657
+ if (extender.checkForUnsatisfiedExtends(unsatisfied)) {
658
+ throw Exception::UnsatisfiedExtend(traces, unsatisfied);
659
+ }
660
+
661
+ // check nesting
662
+ check_nesting(root);
663
+ // merge and bubble certain rules
664
+ root = cssize(root);
665
+
666
+ // clean up by removing empty placeholders
667
+ // ToDo: maybe we can do this somewhere else?
668
+ Remove_Placeholders remove_placeholders;
669
+ root->perform(&remove_placeholders);
670
+
671
+ // return processed tree
672
+ return root;
673
+ }
674
+ // EO compile
675
+
676
+ sass::string Context::format_embedded_source_map()
677
+ {
678
+ sass::string map = emitter.render_srcmap(*this);
679
+ sass::istream is( map.c_str() );
680
+ sass::ostream buffer;
681
+ base64::encoder E;
682
+ E.encode(is, buffer);
683
+ sass::string url = "data:application/json;base64," + buffer.str();
684
+ url.erase(url.size() - 1);
685
+ return "/*# sourceMappingURL=" + url + " */";
686
+ }
687
+
688
+ sass::string Context::format_source_mapping_url(const sass::string& file)
689
+ {
690
+ sass::string url = abs2rel(file, output_path, CWD);
691
+ return "/*# sourceMappingURL=" + url + " */";
692
+ }
693
+
694
+ char* Context::render_srcmap()
695
+ {
696
+ if (source_map_file == "") return 0;
697
+ sass::string map = emitter.render_srcmap(*this);
698
+ return sass_copy_c_string(map.c_str());
699
+ }
700
+
701
+
702
+ // for data context we want to start after "stdin"
703
+ // we probably always want to skip the header includes?
704
+ sass::vector<sass::string> Context::get_included_files(bool skip, size_t headers)
705
+ {
706
+ // create a copy of the vector for manipulations
707
+ sass::vector<sass::string> includes = included_files;
708
+ if (includes.size() == 0) return includes;
709
+ if (skip) { includes.erase( includes.begin(), includes.begin() + 1 + headers); }
710
+ else { includes.erase( includes.begin() + 1, includes.begin() + 1 + headers); }
711
+ includes.erase( std::unique( includes.begin(), includes.end() ), includes.end() );
712
+ std::sort( includes.begin() + (skip ? 0 : 1), includes.end() );
713
+ return includes;
714
+ }
715
+
716
+ void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
717
+ {
718
+ Definition* def = make_native_function(sig, f, ctx);
719
+ def->environment(env);
720
+ (*env)[def->name() + "[f]"] = def;
721
+ }
722
+
723
+ void register_function(Context& ctx, Signature sig, Native_Function f, size_t arity, Env* env)
724
+ {
725
+ Definition* def = make_native_function(sig, f, ctx);
726
+ sass::ostream ss;
727
+ ss << def->name() << "[f]" << arity;
728
+ def->environment(env);
729
+ (*env)[ss.str()] = def;
730
+ }
731
+
732
+ void register_overload_stub(Context& ctx, sass::string name, Env* env)
733
+ {
734
+ Definition* stub = SASS_MEMORY_NEW(Definition,
735
+ SourceSpan{ "[built-in function]" },
736
+ nullptr,
737
+ name,
738
+ Parameters_Obj{},
739
+ nullptr,
740
+ true);
741
+ (*env)[name + "[f]"] = stub;
742
+ }
743
+
744
+
745
+ void register_built_in_functions(Context& ctx, Env* env)
746
+ {
747
+ using namespace Functions;
748
+ // RGB Functions (CSS Colors Level 4: rgb() now supports optional alpha)
749
+ register_function(ctx, rgb_sig, rgb, env);
750
+ register_overload_stub(ctx, "rgba", env);
751
+ register_function(ctx, rgba_4_sig, rgba_4, 4, env);
752
+ register_function(ctx, rgba_2_sig, rgba_2, 2, env);
753
+ register_function(ctx, red_sig, red, env);
754
+ register_function(ctx, green_sig, green, env);
755
+ register_function(ctx, blue_sig, blue, env);
756
+ register_function(ctx, mix_sig, mix, env);
757
+ // HSL Functions (CSS Colors Level 4: hsl() now supports optional alpha)
758
+ register_function(ctx, hsl_sig, hsl, env);
759
+ register_function(ctx, hsla_sig, hsla, env);
760
+ register_function(ctx, hue_sig, hue, env);
761
+ register_function(ctx, saturation_sig, saturation, env);
762
+ register_function(ctx, lightness_sig, lightness, env);
763
+ register_function(ctx, adjust_hue_sig, adjust_hue, env);
764
+ register_function(ctx, lighten_sig, lighten, env);
765
+ register_function(ctx, darken_sig, darken, env);
766
+ register_function(ctx, saturate_sig, saturate, env);
767
+ register_function(ctx, desaturate_sig, desaturate, env);
768
+ register_function(ctx, grayscale_sig, grayscale, env);
769
+ register_function(ctx, complement_sig, complement, env);
770
+ register_function(ctx, invert_sig, invert, env);
771
+ // Opacity Functions
772
+ register_function(ctx, alpha_sig, alpha, env);
773
+ register_function(ctx, opacity_sig, alpha, env);
774
+ register_function(ctx, opacify_sig, opacify, env);
775
+ register_function(ctx, fade_in_sig, opacify, env);
776
+ register_function(ctx, transparentize_sig, transparentize, env);
777
+ register_function(ctx, fade_out_sig, transparentize, env);
778
+ // Other Color Functions
779
+ register_function(ctx, adjust_color_sig, adjust_color, env);
780
+ register_function(ctx, scale_color_sig, scale_color, env);
781
+ register_function(ctx, change_color_sig, change_color, env);
782
+ register_function(ctx, ie_hex_str_sig, ie_hex_str, env);
783
+ // CSS Colors Level 4 Functions
784
+ register_function(ctx, hwb_sig, hwb, env);
785
+ register_function(ctx, lab_sig, lab, env);
786
+ register_function(ctx, lch_sig, lch, env);
787
+ register_function(ctx, oklab_sig, oklab, env);
788
+ register_function(ctx, oklch_sig, oklch, env);
789
+ register_function(ctx, color_sig, color, env);
790
+ // String Functions
791
+ register_function(ctx, unquote_sig, sass_unquote, env);
792
+ register_function(ctx, quote_sig, sass_quote, env);
793
+ register_function(ctx, str_length_sig, str_length, env);
794
+ register_function(ctx, str_insert_sig, str_insert, env);
795
+ register_function(ctx, str_index_sig, str_index, env);
796
+ register_function(ctx, str_slice_sig, str_slice, env);
797
+ register_function(ctx, to_upper_case_sig, to_upper_case, env);
798
+ register_function(ctx, to_lower_case_sig, to_lower_case, env);
799
+ // Number Functions
800
+ register_function(ctx, percentage_sig, percentage, env);
801
+ register_function(ctx, round_sig, round, env);
802
+ register_function(ctx, ceil_sig, ceil, env);
803
+ register_function(ctx, floor_sig, floor, env);
804
+ register_function(ctx, abs_sig, abs, env);
805
+ register_function(ctx, min_sig, min, env);
806
+ register_function(ctx, max_sig, max, env);
807
+ register_function(ctx, random_sig, random, env);
808
+ // List Functions
809
+ register_function(ctx, length_sig, length, env);
810
+ register_function(ctx, nth_sig, nth, env);
811
+ register_function(ctx, set_nth_sig, set_nth, env);
812
+ register_function(ctx, index_sig, index, env);
813
+ register_function(ctx, join_sig, join, env);
814
+ register_function(ctx, append_sig, append, env);
815
+ register_function(ctx, zip_sig, zip, env);
816
+ register_function(ctx, list_separator_sig, list_separator, env);
817
+ register_function(ctx, is_bracketed_sig, is_bracketed, env);
818
+ // Map Functions
819
+ register_function(ctx, map_get_sig, map_get, env);
820
+ register_function(ctx, map_merge_sig, map_merge, env);
821
+ register_function(ctx, map_remove_sig, map_remove, env);
822
+ register_function(ctx, map_keys_sig, map_keys, env);
823
+ register_function(ctx, map_values_sig, map_values, env);
824
+ register_function(ctx, map_has_key_sig, map_has_key, env);
825
+ register_function(ctx, keywords_sig, keywords, env);
826
+ // Introspection Functions
827
+ register_function(ctx, type_of_sig, type_of, env);
828
+ register_function(ctx, unit_sig, unit, env);
829
+ register_function(ctx, unitless_sig, unitless, env);
830
+ register_function(ctx, comparable_sig, comparable, env);
831
+ register_function(ctx, variable_exists_sig, variable_exists, env);
832
+ register_function(ctx, global_variable_exists_sig, global_variable_exists, env);
833
+ register_function(ctx, function_exists_sig, function_exists, env);
834
+ register_function(ctx, mixin_exists_sig, mixin_exists, env);
835
+ register_function(ctx, feature_exists_sig, feature_exists, env);
836
+ register_function(ctx, call_sig, call, env);
837
+ register_function(ctx, content_exists_sig, content_exists, env);
838
+ register_function(ctx, get_function_sig, get_function, env);
839
+ // Boolean Functions
840
+ register_function(ctx, not_sig, sass_not, env);
841
+ register_function(ctx, if_sig, sass_if, env);
842
+ // Misc Functions
843
+ register_function(ctx, inspect_sig, inspect, env);
844
+ register_function(ctx, unique_id_sig, unique_id, env);
845
+ // Selector functions
846
+ register_function(ctx, selector_nest_sig, selector_nest, env);
847
+ register_function(ctx, selector_append_sig, selector_append, env);
848
+ register_function(ctx, selector_extend_sig, selector_extend, env);
849
+ register_function(ctx, selector_replace_sig, selector_replace, env);
850
+ register_function(ctx, selector_unify_sig, selector_unify, env);
851
+ register_function(ctx, is_superselector_sig, is_superselector, env);
852
+ register_function(ctx, simple_selectors_sig, simple_selectors, env);
853
+ register_function(ctx, selector_parse_sig, selector_parse, env);
854
+ }
855
+
856
+ void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
857
+ {
858
+ while (descrs && *descrs) {
859
+ register_c_function(ctx, env, *descrs);
860
+ ++descrs;
861
+ }
862
+ }
863
+ void register_c_function(Context& ctx, Env* env, Sass_Function_Entry descr)
864
+ {
865
+ Definition* def = make_c_function(descr, ctx);
866
+ def->environment(env);
867
+ (*env)[def->name() + "[f]"] = def;
868
+ }
869
+
870
+ }