Initial commit
[yaffs-website] / node_modules / node-sass / src / libsass / src / sass_context.cpp
1 #include "sass.hpp"
2 #include <cstring>
3 #include <stdexcept>
4 #include <sstream>
5 #include <string>
6 #include <vector>
7
8 #include "sass.h"
9 #include "ast.hpp"
10 #include "file.hpp"
11 #include "json.hpp"
12 #include "util.hpp"
13 #include "context.hpp"
14 #include "sass_context.hpp"
15 #include "sass_functions.hpp"
16 #include "ast_fwd_decl.hpp"
17 #include "error_handling.hpp"
18
19 #define LFEED "\n"
20
21 // C++ helper
22 namespace Sass {
23   // see sass_copy_c_string(std::string str)
24   static inline JsonNode* json_mkstream(const std::stringstream& stream)
25   {
26     // hold on to string on stack!
27     std::string str(stream.str());
28     return json_mkstring(str.c_str());
29   }
30
31   static int handle_error(Sass_Context* c_ctx) {
32     try {
33       throw;
34     }
35     catch (Exception::Base& e) {
36       std::stringstream msg_stream;
37       std::string cwd(Sass::File::get_cwd());
38
39       std::string msg_prefix(e.errtype());
40       bool got_newline = false;
41       msg_stream << msg_prefix << ": ";
42       const char* msg = e.what();
43       while (msg && *msg) {
44         if (*msg == '\r') {
45           got_newline = true;
46         }
47         else if (*msg == '\n') {
48           got_newline = true;
49         }
50         else if (got_newline) {
51           msg_stream << std::string(msg_prefix.size() + 2, ' ');
52           got_newline = false;
53         }
54         msg_stream << *msg;
55         ++msg;
56       }
57       if (!got_newline) msg_stream << "\n";
58       if (e.import_stack) {
59         for (size_t i = 1; i < e.import_stack->size() - 1; ++i) {
60           std::string path((*e.import_stack)[i]->imp_path);
61           std::string rel_path(Sass::File::abs2rel(path, cwd, cwd));
62           msg_stream << std::string(msg_prefix.size() + 2, ' ');
63           msg_stream << (i == 1 ? " on line " : " from line ");
64           msg_stream << e.pstate.line + 1 << " of " << rel_path << "\n";
65         }
66       }
67       else {
68         std::string rel_path(Sass::File::abs2rel(e.pstate.path, cwd, cwd));
69         msg_stream << std::string(msg_prefix.size() + 2, ' ');
70         msg_stream << " on line " << e.pstate.line + 1 << " of " << rel_path << "\n";
71       }
72
73       // now create the code trace (ToDo: maybe have util functions?)
74       if (e.pstate.line != std::string::npos && e.pstate.column != std::string::npos) {
75         size_t line = e.pstate.line;
76         const char* line_beg = e.pstate.src;
77         while (line_beg && *line_beg && line) {
78           if (*line_beg == '\n') --line;
79           ++line_beg;
80         }
81         const char* line_end = line_beg;
82         while (line_end && *line_end && *line_end != '\n') {
83           if (*line_end == '\n') break;
84           if (*line_end == '\r') break;
85           line_end++;
86         }
87         size_t max_left = 42; size_t max_right = 78;
88         size_t move_in = e.pstate.column > max_left ? e.pstate.column - max_left : 0;
89         size_t shorten = (line_end - line_beg) - move_in > max_right ?
90           (line_end - line_beg) - move_in - max_right : 0;
91         msg_stream << ">> " << std::string(line_beg + move_in, line_end - shorten) << "\n";
92         msg_stream << "   " << std::string(e.pstate.column - move_in, '-') << "^\n";
93       }
94
95       JsonNode* json_err = json_mkobject();
96       json_append_member(json_err, "status", json_mknumber(1));
97       json_append_member(json_err, "file", json_mkstring(e.pstate.path));
98       json_append_member(json_err, "line", json_mknumber((double)(e.pstate.line + 1)));
99       json_append_member(json_err, "column", json_mknumber((double)(e.pstate.column + 1)));
100       json_append_member(json_err, "message", json_mkstring(e.what()));
101       json_append_member(json_err, "formatted", json_mkstream(msg_stream));
102       try { c_ctx->error_json = json_stringify(json_err, "  "); }
103       catch (...) {}
104       c_ctx->error_message = sass_copy_string(msg_stream.str());
105       c_ctx->error_text = sass_copy_c_string(e.what());
106       c_ctx->error_status = 1;
107       c_ctx->error_file = sass_copy_c_string(e.pstate.path);
108       c_ctx->error_line = e.pstate.line + 1;
109       c_ctx->error_column = e.pstate.column + 1;
110       c_ctx->error_src = e.pstate.src;
111       c_ctx->output_string = 0;
112       c_ctx->source_map_string = 0;
113       json_delete(json_err);
114     }
115     catch (std::bad_alloc& ba) {
116       std::stringstream msg_stream;
117       JsonNode* json_err = json_mkobject();
118       msg_stream << "Unable to allocate memory: " << ba.what() << std::endl;
119       json_append_member(json_err, "status", json_mknumber(2));
120       json_append_member(json_err, "message", json_mkstring(ba.what()));
121       json_append_member(json_err, "formatted", json_mkstream(msg_stream));
122       try { c_ctx->error_json = json_stringify(json_err, "  "); }
123       catch (...) {}
124       c_ctx->error_message = sass_copy_string(msg_stream.str());
125       c_ctx->error_text = sass_copy_c_string(ba.what());
126       c_ctx->error_status = 2;
127       c_ctx->output_string = 0;
128       c_ctx->source_map_string = 0;
129       json_delete(json_err);
130     }
131     catch (std::exception& e) {
132       std::stringstream msg_stream;
133       JsonNode* json_err = json_mkobject();
134       msg_stream << "Internal Error: " << e.what() << std::endl;
135       json_append_member(json_err, "status", json_mknumber(3));
136       json_append_member(json_err, "message", json_mkstring(e.what()));
137       json_append_member(json_err, "formatted", json_mkstream(msg_stream));
138       try { c_ctx->error_json = json_stringify(json_err, "  "); }
139       catch (...) {}
140       c_ctx->error_message = sass_copy_string(msg_stream.str());
141       c_ctx->error_text = sass_copy_c_string(e.what());
142       c_ctx->error_status = 3;
143       c_ctx->output_string = 0;
144       c_ctx->source_map_string = 0;
145       json_delete(json_err);
146     }
147     catch (std::string& e) {
148       std::stringstream msg_stream;
149       JsonNode* json_err = json_mkobject();
150       msg_stream << "Internal Error: " << e << std::endl;
151       json_append_member(json_err, "status", json_mknumber(4));
152       json_append_member(json_err, "message", json_mkstring(e.c_str()));
153       json_append_member(json_err, "formatted", json_mkstream(msg_stream));
154       try { c_ctx->error_json = json_stringify(json_err, "  "); }
155       catch (...) {}
156       c_ctx->error_message = sass_copy_string(msg_stream.str());
157       c_ctx->error_text = sass_copy_c_string(e.c_str());
158       c_ctx->error_status = 4;
159       c_ctx->output_string = 0;
160       c_ctx->source_map_string = 0;
161       json_delete(json_err);
162     }
163     catch (const char* e) {
164       std::stringstream msg_stream;
165       JsonNode* json_err = json_mkobject();
166       msg_stream << "Internal Error: " << e << std::endl;
167       json_append_member(json_err, "status", json_mknumber(4));
168       json_append_member(json_err, "message", json_mkstring(e));
169       json_append_member(json_err, "formatted", json_mkstream(msg_stream));
170       try { c_ctx->error_json = json_stringify(json_err, "  "); }
171       catch (...) {}
172       c_ctx->error_message = sass_copy_string(msg_stream.str());
173       c_ctx->error_text = sass_copy_c_string(e);
174       c_ctx->error_status = 4;
175       c_ctx->output_string = 0;
176       c_ctx->source_map_string = 0;
177       json_delete(json_err);
178     }
179     catch (...) {
180       std::stringstream msg_stream;
181       JsonNode* json_err = json_mkobject();
182       msg_stream << "Unknown error occurred" << std::endl;
183       json_append_member(json_err, "status", json_mknumber(5));
184       json_append_member(json_err, "message", json_mkstring("unknown"));
185       try { c_ctx->error_json = json_stringify(json_err, "  "); }
186       catch (...) {}
187       c_ctx->error_message = sass_copy_string(msg_stream.str());
188       c_ctx->error_text = sass_copy_c_string("unknown");
189       c_ctx->error_status = 5;
190       c_ctx->output_string = 0;
191       c_ctx->source_map_string = 0;
192       json_delete(json_err);
193     }
194     return c_ctx->error_status;
195   }
196
197   // allow one error handler to throw another error
198   // this can happen with invalid utf8 and json lib
199   static int handle_errors(Sass_Context* c_ctx) {
200     try { return handle_error(c_ctx); }
201     catch (...) { return handle_error(c_ctx); }
202     return c_ctx->error_status;
203   }
204
205   static Block_Obj sass_parse_block(Sass_Compiler* compiler) throw()
206   {
207
208     // assert valid pointer
209     if (compiler == 0) return 0;
210     // The cpp context must be set by now
211     Context* cpp_ctx = compiler->cpp_ctx;
212     Sass_Context* c_ctx = compiler->c_ctx;
213     // We will take care to wire up the rest
214     compiler->cpp_ctx->c_compiler = compiler;
215     compiler->state = SASS_COMPILER_PARSED;
216
217     try {
218
219       // get input/output path from options
220       std::string input_path = safe_str(c_ctx->input_path);
221       std::string output_path = safe_str(c_ctx->output_path);
222
223       // maybe skip some entries of included files
224       // we do not include stdin for data contexts
225       bool skip = c_ctx->type == SASS_CONTEXT_DATA;
226
227       // dispatch parse call
228       Block_Obj root(cpp_ctx->parse());
229       // abort on errors
230       if (!root) return 0;
231
232       // skip all prefixed files? (ToDo: check srcmap)
233       // IMO source-maps should point to headers already
234       // therefore don't skip it for now. re-enable or
235       // remove completely once this is tested
236       size_t headers = cpp_ctx->head_imports;
237
238       // copy the included files on to the context (dont forget to free later)
239       if (copy_strings(cpp_ctx->get_included_files(skip, headers), &c_ctx->included_files) == NULL)
240         throw(std::bad_alloc());
241
242       // return parsed block
243       return root;
244
245     }
246     // pass errors to generic error handler
247     catch (...) { handle_errors(c_ctx); }
248
249     // error
250     return 0;
251
252   }
253
254 }
255
256 extern "C" {
257   using namespace Sass;
258
259   static void sass_clear_options (struct Sass_Options* options);
260   static void sass_reset_options (struct Sass_Options* options);
261   static void copy_options(struct Sass_Options* to, struct Sass_Options* from) {
262     // do not overwrite ourself
263     if (to == from) return;
264     // free assigned memory
265     sass_clear_options(to);
266     // move memory
267     *to = *from;
268     // Reset pointers on source
269     sass_reset_options(from);
270   }
271
272   #define IMPLEMENT_SASS_OPTION_ACCESSOR(type, option) \
273     type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return options->option; } \
274     void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) { options->option = option; }
275   #define IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \
276     type ADDCALL sass_option_get_##option (struct Sass_Options* options) { return safe_str(options->option, def); }
277   #define IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def) \
278     void ADDCALL sass_option_set_##option (struct Sass_Options* options, type option) \
279     { free(options->option); options->option = option || def ? sass_copy_c_string(option ? option : def) : 0; }
280   #define IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(type, option, def) \
281     IMPLEMENT_SASS_OPTION_STRING_GETTER(type, option, def) \
282     IMPLEMENT_SASS_OPTION_STRING_SETTER(type, option, def)
283
284   #define IMPLEMENT_SASS_CONTEXT_GETTER(type, option) \
285     type ADDCALL sass_context_get_##option (struct Sass_Context* ctx) { return ctx->option; }
286   #define IMPLEMENT_SASS_CONTEXT_TAKER(type, option) \
287     type sass_context_take_##option (struct Sass_Context* ctx) \
288     { type foo = ctx->option; ctx->option = 0; return foo; }
289
290
291   // generic compilation function (not exported, use file/data compile instead)
292   static Sass_Compiler* sass_prepare_context (Sass_Context* c_ctx, Context* cpp_ctx) throw()
293   {
294     try {
295       // register our custom functions
296       if (c_ctx->c_functions) {
297         auto this_func_data = c_ctx->c_functions;
298         while (this_func_data && *this_func_data) {
299           cpp_ctx->add_c_function(*this_func_data);
300           ++this_func_data;
301         }
302       }
303
304       // register our custom headers
305       if (c_ctx->c_headers) {
306         auto this_head_data = c_ctx->c_headers;
307         while (this_head_data && *this_head_data) {
308           cpp_ctx->add_c_header(*this_head_data);
309           ++this_head_data;
310         }
311       }
312
313       // register our custom importers
314       if (c_ctx->c_importers) {
315         auto this_imp_data = c_ctx->c_importers;
316         while (this_imp_data && *this_imp_data) {
317           cpp_ctx->add_c_importer(*this_imp_data);
318           ++this_imp_data;
319         }
320       }
321
322       // reset error status
323       c_ctx->error_json = 0;
324       c_ctx->error_text = 0;
325       c_ctx->error_message = 0;
326       c_ctx->error_status = 0;
327       // reset error position
328       c_ctx->error_src = 0;
329       c_ctx->error_file = 0;
330       c_ctx->error_line = std::string::npos;
331       c_ctx->error_column = std::string::npos;
332
333       // allocate a new compiler instance
334       Sass_Compiler* compiler = (struct Sass_Compiler*) calloc(1, sizeof(struct Sass_Compiler));
335       compiler->state = SASS_COMPILER_CREATED;
336
337       // store in sass compiler
338       compiler->c_ctx = c_ctx;
339       compiler->cpp_ctx = cpp_ctx;
340       cpp_ctx->c_compiler = compiler;
341
342       // use to parse block
343       return compiler;
344
345     }
346     // pass errors to generic error handler
347     catch (...) { handle_errors(c_ctx); }
348
349     // error
350     return 0;
351
352   }
353
354   // generic compilation function (not exported, use file/data compile instead)
355   static int sass_compile_context (Sass_Context* c_ctx, Context* cpp_ctx)
356   {
357
358     // prepare sass compiler with context and options
359     Sass_Compiler* compiler = sass_prepare_context(c_ctx, cpp_ctx);
360
361     try {
362       // call each compiler step
363       sass_compiler_parse(compiler);
364       sass_compiler_execute(compiler);
365     }
366     // pass errors to generic error handler
367     catch (...) { handle_errors(c_ctx); }
368
369     sass_delete_compiler(compiler);
370
371     return c_ctx->error_status;
372   }
373
374   inline void init_options (struct Sass_Options* options)
375   {
376     options->precision = 5;
377     options->indent = "  ";
378     options->linefeed = LFEED;
379   }
380
381   Sass_Options* ADDCALL sass_make_options (void)
382   {
383     struct Sass_Options* options = (struct Sass_Options*) calloc(1, sizeof(struct Sass_Options));
384     if (options == 0) { std::cerr << "Error allocating memory for options" << std::endl; return 0; }
385     init_options(options);
386     return options;
387   }
388
389   Sass_File_Context* ADDCALL sass_make_file_context(const char* input_path)
390   {
391     SharedObj::setTaint(true); // needed for static colors
392     struct Sass_File_Context* ctx = (struct Sass_File_Context*) calloc(1, sizeof(struct Sass_File_Context));
393     if (ctx == 0) { std::cerr << "Error allocating memory for file context" << std::endl; return 0; }
394     ctx->type = SASS_CONTEXT_FILE;
395     init_options(ctx);
396     try {
397       if (input_path == 0) { throw(std::runtime_error("File context created without an input path")); }
398       if (*input_path == 0) { throw(std::runtime_error("File context created with empty input path")); }
399       sass_option_set_input_path(ctx, input_path);
400     } catch (...) {
401       handle_errors(ctx);
402     }
403     return ctx;
404   }
405
406   Sass_Data_Context* ADDCALL sass_make_data_context(char* source_string)
407   {
408     struct Sass_Data_Context* ctx = (struct Sass_Data_Context*) calloc(1, sizeof(struct Sass_Data_Context));
409     if (ctx == 0) { std::cerr << "Error allocating memory for data context" << std::endl; return 0; }
410     ctx->type = SASS_CONTEXT_DATA;
411     init_options(ctx);
412     try {
413       if (source_string == 0) { throw(std::runtime_error("Data context created without a source string")); }
414       if (*source_string == 0) { throw(std::runtime_error("Data context created with empty source string")); }
415       ctx->source_string = source_string;
416     } catch (...) {
417       handle_errors(ctx);
418     }
419     return ctx;
420   }
421
422   struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx)
423   {
424     if (data_ctx == 0) return 0;
425     Context* cpp_ctx = new Data_Context(*data_ctx);
426     return sass_prepare_context(data_ctx, cpp_ctx);
427   }
428
429   struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx)
430   {
431     if (file_ctx == 0) return 0;
432     Context* cpp_ctx = new File_Context(*file_ctx);
433     return sass_prepare_context(file_ctx, cpp_ctx);
434   }
435
436   int ADDCALL sass_compile_data_context(Sass_Data_Context* data_ctx)
437   {
438     if (data_ctx == 0) return 1;
439     if (data_ctx->error_status)
440       return data_ctx->error_status;
441     try {
442       if (data_ctx->source_string == 0) { throw(std::runtime_error("Data context has no source string")); }
443       // empty source string is a valid case, even if not really usefull (different than with file context)
444       // if (*data_ctx->source_string == 0) { throw(std::runtime_error("Data context has empty source string")); }
445     }
446     catch (...) { return handle_errors(data_ctx) | 1; }
447     Context* cpp_ctx = new Data_Context(*data_ctx);
448     return sass_compile_context(data_ctx, cpp_ctx);
449   }
450
451   int ADDCALL sass_compile_file_context(Sass_File_Context* file_ctx)
452   {
453     if (file_ctx == 0) return 1;
454     if (file_ctx->error_status)
455       return file_ctx->error_status;
456     try {
457       if (file_ctx->input_path == 0) { throw(std::runtime_error("File context has no input path")); }
458       if (*file_ctx->input_path == 0) { throw(std::runtime_error("File context has empty input path")); }
459     }
460     catch (...) { return handle_errors(file_ctx) | 1; }
461     Context* cpp_ctx = new File_Context(*file_ctx);
462     return sass_compile_context(file_ctx, cpp_ctx);
463   }
464
465   int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler)
466   {
467     if (compiler == 0) return 1;
468     if (compiler->state == SASS_COMPILER_PARSED) return 0;
469     if (compiler->state != SASS_COMPILER_CREATED) return -1;
470     if (compiler->c_ctx == NULL) return 1;
471     if (compiler->cpp_ctx == NULL) return 1;
472     if (compiler->c_ctx->error_status)
473       return compiler->c_ctx->error_status;
474     // parse the context we have set up (file or data)
475     compiler->root = sass_parse_block(compiler);
476     // success
477     return 0;
478   }
479
480   int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler)
481   {
482     if (compiler == 0) return 1;
483     if (compiler->state == SASS_COMPILER_EXECUTED) return 0;
484     if (compiler->state != SASS_COMPILER_PARSED) return -1;
485     if (compiler->c_ctx == NULL) return 1;
486     if (compiler->cpp_ctx == NULL) return 1;
487     if (compiler->root.isNull()) return 1;
488     if (compiler->c_ctx->error_status)
489       return compiler->c_ctx->error_status;
490     compiler->state = SASS_COMPILER_EXECUTED;
491     Context* cpp_ctx = compiler->cpp_ctx;
492     Block_Obj root = compiler->root;
493     // compile the parsed root block
494     try { compiler->c_ctx->output_string = cpp_ctx->render(root); }
495     // pass catched errors to generic error handler
496     catch (...) { return handle_errors(compiler->c_ctx) | 1; }
497     // generate source map json and store on context
498     compiler->c_ctx->source_map_string = cpp_ctx->render_srcmap();
499     // success
500     return 0;
501   }
502
503   // helper function, not exported, only accessible locally
504   static void sass_reset_options (struct Sass_Options* options)
505   {
506     // free pointer before
507     // or copy/move them
508     options->input_path = 0;
509     options->output_path = 0;
510     options->plugin_path = 0;
511     options->include_path = 0;
512     options->source_map_file = 0;
513     options->source_map_root = 0;
514     options->c_functions = 0;
515     options->c_importers = 0;
516     options->c_headers = 0;
517     options->plugin_paths = 0;
518     options->include_paths = 0;
519   }
520
521   // helper function, not exported, only accessible locally
522   static void sass_clear_options (struct Sass_Options* options)
523   {
524     if (options == 0) return;
525     // Deallocate custom functions
526     if (options->c_functions) {
527       Sass_Function_List this_func_data = options->c_functions;
528       while (this_func_data && *this_func_data) {
529         free(*this_func_data);
530         ++this_func_data;
531       }
532     }
533     // Deallocate custom headers
534     if (options->c_headers) {
535       Sass_Importer_List this_head_data = options->c_headers;
536       while (this_head_data && *this_head_data) {
537         free(*this_head_data);
538         ++this_head_data;
539       }
540     }
541     // Deallocate custom importers
542     if (options->c_importers) {
543       Sass_Importer_List this_imp_data = options->c_importers;
544       while (this_imp_data && *this_imp_data) {
545         free(*this_imp_data);
546         ++this_imp_data;
547       }
548     }
549     // Deallocate inc paths
550     if (options->plugin_paths) {
551       struct string_list* cur;
552       struct string_list* next;
553       cur = options->plugin_paths;
554       while (cur) {
555         next = cur->next;
556         free(cur->string);
557         free(cur);
558         cur = next;
559       }
560     }
561     // Deallocate inc paths
562     if (options->include_paths) {
563       struct string_list* cur;
564       struct string_list* next;
565       cur = options->include_paths;
566       while (cur) {
567         next = cur->next;
568         free(cur->string);
569         free(cur);
570         cur = next;
571       }
572     }
573     // Free options strings
574     free(options->input_path);
575     free(options->output_path);
576     free(options->plugin_path);
577     free(options->include_path);
578     free(options->source_map_file);
579     free(options->source_map_root);
580     // Free custom functions
581     free(options->c_functions);
582     // Free custom importers
583     free(options->c_importers);
584     free(options->c_headers);
585     // Reset our pointers
586     options->input_path = 0;
587     options->output_path = 0;
588     options->plugin_path = 0;
589     options->include_path = 0;
590     options->source_map_file = 0;
591     options->source_map_root = 0;
592     options->c_functions = 0;
593     options->c_importers = 0;
594     options->c_headers = 0;
595     options->plugin_paths = 0;
596     options->include_paths = 0;
597   }
598
599   // helper function, not exported, only accessible locally
600   // sass_free_context is also defined in old sass_interface
601   static void sass_clear_context (struct Sass_Context* ctx)
602   {
603     if (ctx == 0) return;
604     // release the allocated memory (mostly via sass_copy_c_string)
605     if (ctx->output_string)     free(ctx->output_string);
606     if (ctx->source_map_string) free(ctx->source_map_string);
607     if (ctx->error_message)     free(ctx->error_message);
608     if (ctx->error_text)        free(ctx->error_text);
609     if (ctx->error_json)        free(ctx->error_json);
610     if (ctx->error_file)        free(ctx->error_file);
611     free_string_array(ctx->included_files);
612     // play safe and reset properties
613     ctx->output_string = 0;
614     ctx->source_map_string = 0;
615     ctx->error_message = 0;
616     ctx->error_text = 0;
617     ctx->error_json = 0;
618     ctx->error_file = 0;
619     ctx->included_files = 0;
620     // debug leaked memory
621     #ifdef DEBUG_SHARED_PTR
622       SharedObj::dumpMemLeaks();
623     #endif
624     // now clear the options
625     sass_clear_options(ctx);
626   }
627
628   void ADDCALL sass_delete_compiler (struct Sass_Compiler* compiler)
629   {
630     if (compiler == 0) {
631       return;
632     }
633     Context* cpp_ctx = compiler->cpp_ctx;
634     if (cpp_ctx) delete(cpp_ctx);
635     compiler->cpp_ctx = NULL;
636     compiler->c_ctx = NULL;
637     compiler->root = NULL;
638     free(compiler);
639   }
640
641   void ADDCALL sass_delete_options (struct Sass_Options* options)
642   {
643     sass_clear_options(options); free(options);
644   }
645
646   // Deallocate all associated memory with file context
647   void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx)
648   {
649     // clear the context and free it
650     sass_clear_context(ctx); free(ctx);
651   }
652   // Deallocate all associated memory with data context
653   void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx)
654   {
655     // clean the source string if it was not passed
656     // we reset this member once we start parsing
657     if (ctx->source_string) free(ctx->source_string);
658     // clear the context and free it
659     sass_clear_context(ctx); free(ctx);
660   }
661
662   // Getters for sass context from specific implementations
663   struct Sass_Context* ADDCALL sass_file_context_get_context(struct Sass_File_Context* ctx) { return ctx; }
664   struct Sass_Context* ADDCALL sass_data_context_get_context(struct Sass_Data_Context* ctx) { return ctx; }
665
666   // Getters for context options from Sass_Context
667   struct Sass_Options* ADDCALL sass_context_get_options(struct Sass_Context* ctx) { return ctx; }
668   struct Sass_Options* ADDCALL sass_file_context_get_options(struct Sass_File_Context* ctx) { return ctx; }
669   struct Sass_Options* ADDCALL sass_data_context_get_options(struct Sass_Data_Context* ctx) { return ctx; }
670   void ADDCALL sass_file_context_set_options (struct Sass_File_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
671   void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* ctx, struct Sass_Options* opt) { copy_options(ctx, opt); }
672
673   // Getters for Sass_Compiler options (get conected sass context)
674   enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler) { return compiler->state; }
675   struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
676   struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compiler* compiler) { return compiler->c_ctx; }
677   // Getters for Sass_Compiler options (query import stack)
678   size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.size(); }
679   Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->import_stack.back(); }
680   Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx) { return compiler->cpp_ctx->import_stack[idx]; }
681   // Getters for Sass_Compiler options (query function stack)
682   size_t ADDCALL sass_compiler_get_callee_stack_size(struct Sass_Compiler* compiler) { return compiler->cpp_ctx->callee_stack.size(); }
683   Sass_Callee_Entry ADDCALL sass_compiler_get_last_callee(struct Sass_Compiler* compiler) { return &compiler->cpp_ctx->callee_stack.back(); }
684   Sass_Callee_Entry ADDCALL sass_compiler_get_callee_entry(struct Sass_Compiler* compiler, size_t idx) { return &compiler->cpp_ctx->callee_stack[idx]; }
685
686   // Calculate the size of the stored null terminated array
687   size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx)
688   { size_t l = 0; auto i = ctx->included_files; while (i && *i) { ++i; ++l; } return l; }
689
690   // Create getter and setters for options
691   IMPLEMENT_SASS_OPTION_ACCESSOR(int, precision);
692   IMPLEMENT_SASS_OPTION_ACCESSOR(enum Sass_Output_Style, output_style);
693   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_comments);
694   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_embed);
695   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_contents);
696   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, source_map_file_urls);
697   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, omit_source_map_url);
698   IMPLEMENT_SASS_OPTION_ACCESSOR(bool, is_indented_syntax_src);
699   IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Function_List, c_functions);
700   IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_importers);
701   IMPLEMENT_SASS_OPTION_ACCESSOR(Sass_Importer_List, c_headers);
702   IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, indent);
703   IMPLEMENT_SASS_OPTION_ACCESSOR(const char*, linefeed);
704   IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, plugin_path, 0);
705   IMPLEMENT_SASS_OPTION_STRING_SETTER(const char*, include_path, 0);
706   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, input_path, 0);
707   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, output_path, 0);
708   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_file, 0);
709   IMPLEMENT_SASS_OPTION_STRING_ACCESSOR(const char*, source_map_root, 0);
710
711   // Create getter and setters for context
712   IMPLEMENT_SASS_CONTEXT_GETTER(int, error_status);
713   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_json);
714   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_message);
715   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_text);
716   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_file);
717   IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_line);
718   IMPLEMENT_SASS_CONTEXT_GETTER(size_t, error_column);
719   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, error_src);
720   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, output_string);
721   IMPLEMENT_SASS_CONTEXT_GETTER(const char*, source_map_string);
722   IMPLEMENT_SASS_CONTEXT_GETTER(char**, included_files);
723
724   // Take ownership of memory (value on context is set to 0)
725   IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_json);
726   IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_message);
727   IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_text);
728   IMPLEMENT_SASS_CONTEXT_TAKER(char*, error_file);
729   IMPLEMENT_SASS_CONTEXT_TAKER(char*, output_string);
730   IMPLEMENT_SASS_CONTEXT_TAKER(char*, source_map_string);
731   IMPLEMENT_SASS_CONTEXT_TAKER(char**, included_files);
732
733   // Push function for include paths (no manipulation support for now)
734   void ADDCALL sass_option_push_include_path(struct Sass_Options* options, const char* path)
735   {
736
737     struct string_list* include_path = (struct string_list*) calloc(1, sizeof(struct string_list));
738     if (include_path == 0) return;
739     include_path->string = path ? sass_copy_c_string(path) : 0;
740     struct string_list* last = options->include_paths;
741     if (!options->include_paths) {
742       options->include_paths = include_path;
743     } else {
744       while (last->next)
745         last = last->next;
746       last->next = include_path;
747     }
748
749   }
750
751   // Push function for include paths (no manipulation support for now)
752   size_t ADDCALL sass_option_get_include_path_size(struct Sass_Options* options)
753   {
754     size_t len = 0;
755     struct string_list* cur = options->include_paths;
756     while (cur) { len ++; cur = cur->next; }
757     return len;
758   }
759
760   // Push function for include paths (no manipulation support for now)
761   const char* ADDCALL sass_option_get_include_path(struct Sass_Options* options, size_t i)
762   {
763     struct string_list* cur = options->include_paths;
764     while (i) { i--; cur = cur->next; }
765     return cur->string;
766   }
767
768   // Push function for plugin paths (no manipulation support for now)
769   void ADDCALL sass_option_push_plugin_path(struct Sass_Options* options, const char* path)
770   {
771
772     struct string_list* plugin_path = (struct string_list*) calloc(1, sizeof(struct string_list));
773     if (plugin_path == 0) return;
774     plugin_path->string = path ? sass_copy_c_string(path) : 0;
775     struct string_list* last = options->plugin_paths;
776     if (!options->plugin_paths) {
777       options->plugin_paths = plugin_path;
778     } else {
779       while (last->next)
780         last = last->next;
781       last->next = plugin_path;
782     }
783
784   }
785
786 }