context.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. #ifdef _WIN32
  2. #define PATH_SEP ';'
  3. #else
  4. #define PATH_SEP ':'
  5. #endif
  6. #ifndef SASS_AST
  7. #include "ast.hpp"
  8. #endif
  9. #include "context.hpp"
  10. #include "constants.hpp"
  11. #include "parser.hpp"
  12. #include "file.hpp"
  13. #include "inspect.hpp"
  14. #include "output_nested.hpp"
  15. #include "output_compressed.hpp"
  16. #include "expand.hpp"
  17. #include "eval.hpp"
  18. #include "contextualize.hpp"
  19. #include "extend.hpp"
  20. #include "remove_placeholders.hpp"
  21. #include "copy_c_str.hpp"
  22. #include "color_names.hpp"
  23. #include "functions.hpp"
  24. #include "backtrace.hpp"
  25. #include "sass2scss.h"
  26. #ifndef SASS_PRELEXER
  27. #include "prelexer.hpp"
  28. #endif
  29. #include <iomanip>
  30. #include <iostream>
  31. #include <cstring>
  32. #include <sstream>
  33. namespace Sass {
  34. using namespace Constants;
  35. using namespace File;
  36. using std::cerr;
  37. using std::endl;
  38. Sass_Queued::Sass_Queued(const string& load_path, const string& abs_path, const char* source)
  39. {
  40. this->load_path = load_path;
  41. this->abs_path = abs_path;
  42. this->source = source;
  43. }
  44. Context::Context(Context::Data initializers)
  45. : mem(Memory_Manager<AST_Node>()),
  46. source_c_str (initializers.source_c_str()),
  47. sources (vector<const char*>()),
  48. include_paths (initializers.include_paths()),
  49. queue (vector<Sass_Queued>()),
  50. style_sheets (map<string, Block*>()),
  51. source_map (resolve_relative_path(initializers.output_path(), initializers.source_map_file(), get_cwd())),
  52. c_functions (vector<Sass_C_Function_Callback>()),
  53. image_path (initializers.image_path()),
  54. input_path (make_canonical_path(initializers.input_path())),
  55. output_path (make_canonical_path(initializers.output_path())),
  56. source_comments (initializers.source_comments()),
  57. output_style (initializers.output_style()),
  58. source_map_file (make_canonical_path(initializers.source_map_file())),
  59. source_map_embed (initializers.source_map_embed()),
  60. source_map_contents (initializers.source_map_contents()),
  61. omit_source_map_url (initializers.omit_source_map_url()),
  62. is_indented_syntax_src (initializers.is_indented_syntax_src()),
  63. importer (initializers.importer()),
  64. names_to_colors (map<string, Color*>()),
  65. colors_to_names (map<int, string>()),
  66. precision (initializers.precision()),
  67. _skip_source_map_update (initializers._skip_source_map_update()),
  68. subset_map (Subset_Map<string, pair<Complex_Selector*, Compound_Selector*> >())
  69. {
  70. cwd = get_cwd();
  71. // enforce some safe defaults
  72. // used to create relative file links
  73. if (input_path == "") input_path = "stdin";
  74. if (output_path == "") output_path = "stdout";
  75. include_paths.push_back(cwd);
  76. collect_include_paths(initializers.include_paths_c_str());
  77. collect_include_paths(initializers.include_paths_array());
  78. setup_color_map();
  79. string entry_point = initializers.entry_point();
  80. if (!entry_point.empty()) {
  81. string result(add_file(entry_point));
  82. if (result.empty()) {
  83. throw "File to read not found or unreadable: " + entry_point;
  84. }
  85. }
  86. }
  87. Context::~Context()
  88. {
  89. // everything that gets put into sources will be freed by us
  90. for (size_t i = 0; i < sources.size(); ++i) delete[] sources[i];
  91. for (size_t n = 0; n < import_stack.size(); ++n) sass_delete_import(import_stack[n]);
  92. sources.clear(); import_stack.clear();
  93. }
  94. void Context::setup_color_map()
  95. {
  96. size_t i = 0;
  97. while (color_names[i]) {
  98. string name(color_names[i]);
  99. Color* value = new (mem) Color("[COLOR TABLE]", Position(),
  100. color_values[i*4],
  101. color_values[i*4+1],
  102. color_values[i*4+2],
  103. color_values[i*4+3]);
  104. names_to_colors[name] = value;
  105. // only map fully opaque colors
  106. if (color_values[i*4+3] >= 1) {
  107. int numval = color_values[i*4]*0x10000;
  108. numval += color_values[i*4+1]*0x100;
  109. numval += color_values[i*4+2];
  110. colors_to_names[numval] = name;
  111. }
  112. ++i;
  113. }
  114. }
  115. void Context::collect_include_paths(const char* paths_str)
  116. {
  117. if (paths_str) {
  118. const char* beg = paths_str;
  119. const char* end = Prelexer::find_first<PATH_SEP>(beg);
  120. while (end) {
  121. string path(beg, end - beg);
  122. if (!path.empty()) {
  123. if (*path.rbegin() != '/') path += '/';
  124. include_paths.push_back(path);
  125. }
  126. beg = end + 1;
  127. end = Prelexer::find_first<PATH_SEP>(beg);
  128. }
  129. string path(beg);
  130. if (!path.empty()) {
  131. if (*path.rbegin() != '/') path += '/';
  132. include_paths.push_back(path);
  133. }
  134. }
  135. }
  136. void Context::collect_include_paths(const char** paths_array)
  137. {
  138. if (*include_paths.back().rbegin() != '/') include_paths.back() += '/';
  139. if (paths_array) {
  140. for (size_t i = 0; paths_array[i]; i++) {
  141. collect_include_paths(paths_array[i]);
  142. }
  143. }
  144. }
  145. void Context::add_source(string load_path, string abs_path, const char* contents)
  146. {
  147. sources.push_back(contents);
  148. included_files.push_back(abs_path);
  149. queue.push_back(Sass_Queued(load_path, abs_path, contents));
  150. source_map.source_index.push_back(sources.size() - 1);
  151. include_links.push_back(resolve_relative_path(abs_path, source_map_file, cwd));
  152. }
  153. string Context::add_file(string path)
  154. {
  155. using namespace File;
  156. char* contents = 0;
  157. string real_path;
  158. path = make_canonical_path(path);
  159. for (size_t i = 0, S = include_paths.size(); i < S; ++i) {
  160. string full_path(join_paths(include_paths[i], path));
  161. if (style_sheets.count(full_path)) return full_path;
  162. contents = resolve_and_load(full_path, real_path);
  163. if (contents) {
  164. add_source(full_path, real_path, contents);
  165. style_sheets[full_path] = 0;
  166. return full_path;
  167. }
  168. }
  169. return string();
  170. }
  171. string Context::add_file(string dir, string rel_filepath)
  172. {
  173. using namespace File;
  174. char* contents = 0;
  175. string real_path;
  176. rel_filepath = make_canonical_path(rel_filepath);
  177. string full_path(join_paths(dir, rel_filepath));
  178. if (style_sheets.count(full_path)) return full_path;
  179. contents = resolve_and_load(full_path, real_path);
  180. if (contents) {
  181. add_source(full_path, real_path, contents);
  182. style_sheets[full_path] = 0;
  183. return full_path;
  184. }
  185. for (size_t i = 0, S = include_paths.size(); i < S; ++i) {
  186. string full_path(join_paths(include_paths[i], rel_filepath));
  187. if (style_sheets.count(full_path)) return full_path;
  188. contents = resolve_and_load(full_path, real_path);
  189. if (contents) {
  190. add_source(full_path, real_path, contents);
  191. style_sheets[full_path] = 0;
  192. return full_path;
  193. }
  194. }
  195. return string();
  196. }
  197. void register_function(Context&, Signature sig, Native_Function f, Env* env);
  198. void register_function(Context&, Signature sig, Native_Function f, size_t arity, Env* env);
  199. void register_overload_stub(Context&, string name, Env* env);
  200. void register_built_in_functions(Context&, Env* env);
  201. void register_c_functions(Context&, Env* env, Sass_C_Function_List);
  202. void register_c_function(Context&, Env* env, Sass_C_Function_Callback);
  203. char* Context::compile_block(Block* root)
  204. {
  205. char* result = 0;
  206. if (!root) return 0;
  207. switch (output_style) {
  208. case COMPRESSED: {
  209. Output_Compressed output_compressed(this);
  210. root->perform(&output_compressed);
  211. string output = output_compressed.get_buffer();
  212. if (source_map_file != "" && !omit_source_map_url) {
  213. output += format_source_mapping_url(source_map_file);
  214. }
  215. result = copy_c_str(output.c_str());
  216. } break;
  217. default: {
  218. Output_Nested output_nested(source_comments, this);
  219. root->perform(&output_nested);
  220. string output = output_nested.get_buffer();
  221. if (source_map_file != "" && !omit_source_map_url) {
  222. output += "\n" + format_source_mapping_url(source_map_file);
  223. }
  224. result = copy_c_str(output.c_str());
  225. } break;
  226. }
  227. return result;
  228. }
  229. Block* Context::parse_file()
  230. {
  231. Block* root = 0;
  232. for (size_t i = 0; i < queue.size(); ++i) {
  233. struct Sass_Import* import = sass_make_import(
  234. queue[i].load_path.c_str(),
  235. queue[i].abs_path.c_str(),
  236. 0, 0
  237. );
  238. import_stack.push_back(import);
  239. Parser p(Parser::from_c_str(queue[i].source, *this, queue[i].abs_path, Position(1 + i, 1, 1)));
  240. Block* ast = p.parse();
  241. sass_delete_import(import_stack.back());
  242. import_stack.pop_back();
  243. if (i == 0) root = ast;
  244. style_sheets[queue[i].load_path] = ast;
  245. }
  246. if (root == 0) return 0;
  247. Env tge;
  248. Backtrace backtrace(0, "", Position(), "");
  249. register_built_in_functions(*this, &tge);
  250. for (size_t i = 0, S = c_functions.size(); i < S; ++i) {
  251. register_c_function(*this, &tge, c_functions[i]);
  252. }
  253. Eval eval(*this, &tge, &backtrace);
  254. Contextualize contextualize(*this, &eval, &tge, &backtrace);
  255. Expand expand(*this, &eval, &contextualize, &tge, &backtrace);
  256. // Inspect inspect(this);
  257. // Output_Nested output_nested(*this);
  258. root = root->perform(&expand)->block();
  259. if (!subset_map.empty()) {
  260. Extend extend(*this, subset_map);
  261. root->perform(&extend);
  262. }
  263. Remove_Placeholders remove_placeholders(*this);
  264. root->perform(&remove_placeholders);
  265. return root;
  266. }
  267. Block* Context::parse_string()
  268. {
  269. if (!source_c_str) return 0;
  270. queue.clear();
  271. if(is_indented_syntax_src) {
  272. char * contents = sass2scss(source_c_str, SASS2SCSS_PRETTIFY_1);
  273. add_source(input_path, input_path, contents);
  274. return parse_file();
  275. }
  276. add_source(input_path, input_path, strdup(source_c_str));
  277. return parse_file();
  278. }
  279. char* Context::compile_file()
  280. {
  281. // returns NULL if something fails
  282. return compile_block(parse_file());
  283. }
  284. char* Context::compile_string()
  285. {
  286. // returns NULL if something fails
  287. return compile_block(parse_string());
  288. }
  289. string Context::format_source_mapping_url(const string& file)
  290. {
  291. string url = resolve_relative_path(file, output_path, cwd);
  292. if (source_map_embed) {
  293. string map = source_map.generate_source_map(*this);
  294. istringstream is( map );
  295. ostringstream buffer;
  296. base64::encoder E;
  297. E.encode(is, buffer);
  298. url = "data:application/json;base64," + buffer.str();
  299. url.erase(url.size() - 1);
  300. }
  301. return "/*# sourceMappingURL=" + url + " */";
  302. }
  303. char* Context::generate_source_map()
  304. {
  305. if (source_map_file == "") return 0;
  306. char* result = 0;
  307. string map = source_map.generate_source_map(*this);
  308. result = copy_c_str(map.c_str());
  309. return result;
  310. }
  311. std::vector<std::string> Context::get_included_files(size_t skip)
  312. {
  313. vector<string> includes = included_files;
  314. std::sort( includes.begin() + skip, includes.end() );
  315. includes.erase( std::unique( includes.begin(), includes.end() ), includes.end() );
  316. // the skip solution seems more robust, as we may have real files named stdin
  317. // includes.erase( std::remove( includes.begin(), includes.end(), "stdin" ), includes.end() );
  318. return includes;
  319. }
  320. string Context::get_cwd()
  321. {
  322. return Sass::File::get_cwd();
  323. }
  324. void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
  325. {
  326. Definition* def = make_native_function(sig, f, ctx);
  327. def->environment(env);
  328. (*env)[def->name() + "[f]"] = def;
  329. }
  330. void register_function(Context& ctx, Signature sig, Native_Function f, size_t arity, Env* env)
  331. {
  332. Definition* def = make_native_function(sig, f, ctx);
  333. stringstream ss;
  334. ss << def->name() << "[f]" << arity;
  335. def->environment(env);
  336. (*env)[ss.str()] = def;
  337. }
  338. void register_overload_stub(Context& ctx, string name, Env* env)
  339. {
  340. Definition* stub = new (ctx.mem) Definition("[built-in function]",
  341. Position(),
  342. 0,
  343. name,
  344. 0,
  345. 0,
  346. true);
  347. (*env)[name + "[f]"] = stub;
  348. }
  349. void register_built_in_functions(Context& ctx, Env* env)
  350. {
  351. using namespace Functions;
  352. // RGB Functions
  353. register_function(ctx, rgb_sig, rgb, env);
  354. register_overload_stub(ctx, "rgba", env);
  355. register_function(ctx, rgba_4_sig, rgba_4, 4, env);
  356. register_function(ctx, rgba_2_sig, rgba_2, 2, env);
  357. register_function(ctx, red_sig, red, env);
  358. register_function(ctx, green_sig, green, env);
  359. register_function(ctx, blue_sig, blue, env);
  360. register_function(ctx, mix_sig, mix, env);
  361. // HSL Functions
  362. register_function(ctx, hsl_sig, hsl, env);
  363. register_function(ctx, hsla_sig, hsla, env);
  364. register_function(ctx, hue_sig, hue, env);
  365. register_function(ctx, saturation_sig, saturation, env);
  366. register_function(ctx, lightness_sig, lightness, env);
  367. register_function(ctx, adjust_hue_sig, adjust_hue, env);
  368. register_function(ctx, lighten_sig, lighten, env);
  369. register_function(ctx, darken_sig, darken, env);
  370. register_function(ctx, saturate_sig, saturate, env);
  371. register_function(ctx, desaturate_sig, desaturate, env);
  372. register_function(ctx, grayscale_sig, grayscale, env);
  373. register_function(ctx, complement_sig, complement, env);
  374. register_function(ctx, invert_sig, invert, env);
  375. // Opacity Functions
  376. register_function(ctx, alpha_sig, alpha, env);
  377. register_function(ctx, opacity_sig, alpha, env);
  378. register_function(ctx, opacify_sig, opacify, env);
  379. register_function(ctx, fade_in_sig, opacify, env);
  380. register_function(ctx, transparentize_sig, transparentize, env);
  381. register_function(ctx, fade_out_sig, transparentize, env);
  382. // Other Color Functions
  383. register_function(ctx, adjust_color_sig, adjust_color, env);
  384. register_function(ctx, scale_color_sig, scale_color, env);
  385. register_function(ctx, change_color_sig, change_color, env);
  386. register_function(ctx, ie_hex_str_sig, ie_hex_str, env);
  387. // String Functions
  388. register_function(ctx, unquote_sig, sass_unquote, env);
  389. register_function(ctx, quote_sig, sass_quote, env);
  390. register_function(ctx, str_length_sig, str_length, env);
  391. register_function(ctx, str_insert_sig, str_insert, env);
  392. register_function(ctx, str_index_sig, str_index, env);
  393. register_function(ctx, str_slice_sig, str_slice, env);
  394. register_function(ctx, to_upper_case_sig, to_upper_case, env);
  395. register_function(ctx, to_lower_case_sig, to_lower_case, env);
  396. // Number Functions
  397. register_function(ctx, percentage_sig, percentage, env);
  398. register_function(ctx, round_sig, round, env);
  399. register_function(ctx, ceil_sig, ceil, env);
  400. register_function(ctx, floor_sig, floor, env);
  401. register_function(ctx, abs_sig, abs, env);
  402. register_function(ctx, min_sig, min, env);
  403. register_function(ctx, max_sig, max, env);
  404. register_function(ctx, random_sig, random, env);
  405. // List Functions
  406. register_function(ctx, length_sig, length, env);
  407. register_function(ctx, nth_sig, nth, env);
  408. register_function(ctx, set_nth_sig, set_nth, env);
  409. register_function(ctx, index_sig, index, env);
  410. register_function(ctx, join_sig, join, env);
  411. register_function(ctx, append_sig, append, env);
  412. register_function(ctx, compact_sig, compact, env);
  413. register_function(ctx, zip_sig, zip, env);
  414. register_function(ctx, list_separator_sig, list_separator, env);
  415. // Map Functions
  416. register_function(ctx, map_get_sig, map_get, env);
  417. register_function(ctx, map_merge_sig, map_merge, env);
  418. register_function(ctx, map_remove_sig, map_remove, env);
  419. register_function(ctx, map_keys_sig, map_keys, env);
  420. register_function(ctx, map_values_sig, map_values, env);
  421. register_function(ctx, map_has_key_sig, map_has_key, env);
  422. register_function(ctx, keywords_sig, keywords, env);
  423. // Introspection Functions
  424. register_function(ctx, type_of_sig, type_of, env);
  425. register_function(ctx, unit_sig, unit, env);
  426. register_function(ctx, unitless_sig, unitless, env);
  427. register_function(ctx, comparable_sig, comparable, env);
  428. register_function(ctx, variable_exists_sig, variable_exists, env);
  429. register_function(ctx, global_variable_exists_sig, global_variable_exists, env);
  430. register_function(ctx, function_exists_sig, function_exists, env);
  431. register_function(ctx, mixin_exists_sig, mixin_exists, env);
  432. register_function(ctx, feature_exists_sig, feature_exists, env);
  433. register_function(ctx, call_sig, call, env);
  434. // Boolean Functions
  435. register_function(ctx, not_sig, sass_not, env);
  436. register_function(ctx, if_sig, sass_if, env);
  437. // Path Functions
  438. register_function(ctx, image_url_sig, image_url, env);
  439. // Misc Functions
  440. register_function(ctx, inspect_sig, inspect, env);
  441. register_function(ctx, unique_id_sig, unique_id, env);
  442. }
  443. void register_c_functions(Context& ctx, Env* env, Sass_C_Function_List descrs)
  444. {
  445. while (descrs && *descrs) {
  446. register_c_function(ctx, env, *descrs);
  447. ++descrs;
  448. }
  449. }
  450. void register_c_function(Context& ctx, Env* env, Sass_C_Function_Callback descr)
  451. {
  452. Definition* def = make_c_function(
  453. sass_function_get_signature(descr),
  454. sass_function_get_function(descr),
  455. sass_function_get_cookie(descr),
  456. ctx
  457. );
  458. def->environment(env);
  459. (*env)[def->name() + "[f]"] = def;
  460. }
  461. }