added whole system from ola4doc
This commit is contained in:
+343
@@ -0,0 +1,343 @@
|
||||
#include <nan.h>
|
||||
#include <vector>
|
||||
#include "sass_context_wrapper.h"
|
||||
#include "custom_function_bridge.h"
|
||||
#include "create_string.h"
|
||||
#include "sass_types/factory.h"
|
||||
|
||||
Sass_Import_List sass_importer(const char* cur_path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
|
||||
{
|
||||
void* cookie = sass_importer_get_cookie(cb);
|
||||
struct Sass_Import* previous = sass_compiler_get_last_import(comp);
|
||||
const char* prev_path = sass_import_get_abs_path(previous);
|
||||
CustomImporterBridge& bridge = *(static_cast<CustomImporterBridge*>(cookie));
|
||||
|
||||
std::vector<void*> argv;
|
||||
argv.push_back((void*)cur_path);
|
||||
argv.push_back((void*)prev_path);
|
||||
|
||||
return bridge(argv);
|
||||
}
|
||||
|
||||
union Sass_Value* sass_custom_function(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp)
|
||||
{
|
||||
void* cookie = sass_function_get_cookie(cb);
|
||||
CustomFunctionBridge& bridge = *(static_cast<CustomFunctionBridge*>(cookie));
|
||||
|
||||
std::vector<void*> argv;
|
||||
for (unsigned l = sass_list_get_length(s_args), i = 0; i < l; i++) {
|
||||
argv.push_back((void*)sass_list_get_value(s_args, i));
|
||||
}
|
||||
|
||||
return bridge(argv);
|
||||
}
|
||||
|
||||
int ExtractOptions(v8::Local<v8::Object> options, void* cptr, sass_context_wrapper* ctx_w, bool is_file, bool is_sync) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
struct Sass_Context* ctx;
|
||||
|
||||
v8::Local<v8::Value> result_ = Nan::Get(
|
||||
options,
|
||||
Nan::New("result").ToLocalChecked()
|
||||
).ToLocalChecked();
|
||||
if (!result_->IsObject()) {
|
||||
Nan::ThrowTypeError("\"result\" element is not an object");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx_w->result.Reset(result_.As<v8::Object>());
|
||||
|
||||
if (is_file) {
|
||||
ctx_w->fctx = (struct Sass_File_Context*) cptr;
|
||||
ctx = sass_file_context_get_context(ctx_w->fctx);
|
||||
}
|
||||
else {
|
||||
ctx_w->dctx = (struct Sass_Data_Context*) cptr;
|
||||
ctx = sass_data_context_get_context(ctx_w->dctx);
|
||||
}
|
||||
|
||||
struct Sass_Options* sass_options = sass_context_get_options(ctx);
|
||||
|
||||
ctx_w->is_sync = is_sync;
|
||||
|
||||
if (!is_sync) {
|
||||
ctx_w->request.data = ctx_w;
|
||||
|
||||
// async (callback) style
|
||||
v8::Local<v8::Function> success_callback = v8::Local<v8::Function>::Cast(Nan::Get(options, Nan::New("success").ToLocalChecked()).ToLocalChecked());
|
||||
v8::Local<v8::Function> error_callback = v8::Local<v8::Function>::Cast(Nan::Get(options, Nan::New("error").ToLocalChecked()).ToLocalChecked());
|
||||
|
||||
ctx_w->success_callback = new Nan::Callback(success_callback);
|
||||
ctx_w->error_callback = new Nan::Callback(error_callback);
|
||||
}
|
||||
|
||||
if (!is_file) {
|
||||
ctx_w->file = create_string(Nan::Get(options, Nan::New("file").ToLocalChecked()));
|
||||
sass_option_set_input_path(sass_options, ctx_w->file);
|
||||
}
|
||||
|
||||
int indent_len = Nan::To<int32_t>(
|
||||
Nan::Get(
|
||||
options,
|
||||
Nan::New("indentWidth").ToLocalChecked()
|
||||
).ToLocalChecked()).FromJust();
|
||||
|
||||
ctx_w->indent = (char*)malloc(indent_len + 1);
|
||||
|
||||
strcpy(ctx_w->indent, std::string(
|
||||
indent_len,
|
||||
Nan::To<int32_t>(
|
||||
Nan::Get(
|
||||
options,
|
||||
Nan::New("indentType").ToLocalChecked()
|
||||
).ToLocalChecked()).FromJust() == 1 ? '\t' : ' '
|
||||
).c_str());
|
||||
|
||||
ctx_w->linefeed = create_string(Nan::Get(options, Nan::New("linefeed").ToLocalChecked()));
|
||||
ctx_w->include_path = create_string(Nan::Get(options, Nan::New("includePaths").ToLocalChecked()));
|
||||
ctx_w->out_file = create_string(Nan::Get(options, Nan::New("outFile").ToLocalChecked()));
|
||||
ctx_w->source_map = create_string(Nan::Get(options, Nan::New("sourceMap").ToLocalChecked()));
|
||||
ctx_w->source_map_root = create_string(Nan::Get(options, Nan::New("sourceMapRoot").ToLocalChecked()));
|
||||
|
||||
sass_option_set_output_path(sass_options, ctx_w->out_file);
|
||||
sass_option_set_output_style(sass_options, (Sass_Output_Style)Nan::To<int32_t>(Nan::Get(options, Nan::New("style").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_is_indented_syntax_src(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("indentedSyntax").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_source_comments(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("sourceComments").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_omit_source_map_url(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("omitSourceMapUrl").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_source_map_embed(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("sourceMapEmbed").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_source_map_contents(sass_options, Nan::To<bool>(Nan::Get(options, Nan::New("sourceMapContents").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_source_map_file(sass_options, ctx_w->source_map);
|
||||
sass_option_set_source_map_root(sass_options, ctx_w->source_map_root);
|
||||
sass_option_set_include_path(sass_options, ctx_w->include_path);
|
||||
sass_option_set_precision(sass_options, Nan::To<int32_t>(Nan::Get(options, Nan::New("precision").ToLocalChecked()).ToLocalChecked()).FromJust());
|
||||
sass_option_set_indent(sass_options, ctx_w->indent);
|
||||
sass_option_set_linefeed(sass_options, ctx_w->linefeed);
|
||||
|
||||
v8::Local<v8::Value> importer_callback = Nan::Get(options, Nan::New("importer").ToLocalChecked()).ToLocalChecked();
|
||||
|
||||
if (importer_callback->IsFunction()) {
|
||||
v8::Local<v8::Function> importer = importer_callback.As<v8::Function>();
|
||||
|
||||
CustomImporterBridge *bridge = new CustomImporterBridge(importer, ctx_w->is_sync);
|
||||
ctx_w->importer_bridges.push_back(bridge);
|
||||
|
||||
Sass_Importer_List c_importers = sass_make_importer_list(1);
|
||||
c_importers[0] = sass_make_importer(sass_importer, 0, bridge);
|
||||
|
||||
sass_option_set_c_importers(sass_options, c_importers);
|
||||
}
|
||||
else if (importer_callback->IsArray()) {
|
||||
v8::Local<v8::Array> importers = importer_callback.As<v8::Array>();
|
||||
Sass_Importer_List c_importers = sass_make_importer_list(importers->Length());
|
||||
|
||||
for (size_t i = 0; i < importers->Length(); ++i) {
|
||||
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(Nan::Get(importers, static_cast<uint32_t>(i)).ToLocalChecked());
|
||||
|
||||
CustomImporterBridge *bridge = new CustomImporterBridge(callback, ctx_w->is_sync);
|
||||
ctx_w->importer_bridges.push_back(bridge);
|
||||
|
||||
c_importers[i] = sass_make_importer(sass_importer, importers->Length() - i - 1, bridge);
|
||||
}
|
||||
|
||||
sass_option_set_c_importers(sass_options, c_importers);
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> custom_functions = Nan::Get(options, Nan::New("functions").ToLocalChecked()).ToLocalChecked();
|
||||
|
||||
if (custom_functions->IsObject()) {
|
||||
v8::Local<v8::Object> functions = custom_functions.As<v8::Object>();
|
||||
v8::Local<v8::Array> signatures = Nan::GetOwnPropertyNames(functions).ToLocalChecked();
|
||||
unsigned num_signatures = signatures->Length();
|
||||
Sass_Function_List fn_list = sass_make_function_list(num_signatures);
|
||||
|
||||
for (unsigned i = 0; i < num_signatures; i++) {
|
||||
v8::Local<v8::String> signature = v8::Local<v8::String>::Cast(Nan::Get(signatures, Nan::New(i)).ToLocalChecked());
|
||||
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(Nan::Get(functions, signature).ToLocalChecked());
|
||||
|
||||
CustomFunctionBridge *bridge = new CustomFunctionBridge(callback, ctx_w->is_sync);
|
||||
ctx_w->function_bridges.push_back(bridge);
|
||||
|
||||
Sass_Function_Entry fn = sass_make_function(create_string(signature), sass_custom_function, bridge);
|
||||
sass_function_set_list_entry(fn_list, i, fn);
|
||||
}
|
||||
|
||||
sass_option_set_c_functions(sass_options, fn_list);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void GetStats(sass_context_wrapper* ctx_w, Sass_Context* ctx) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
char** included_files = sass_context_get_included_files(ctx);
|
||||
v8::Local<v8::Array> arr = Nan::New<v8::Array>();
|
||||
|
||||
if (included_files) {
|
||||
for (int i = 0; included_files[i] != nullptr; ++i) {
|
||||
Nan::Set(arr, i, Nan::New<v8::String>(included_files[i]).ToLocalChecked());
|
||||
}
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> result = Nan::New(ctx_w->result);
|
||||
assert(result->IsObject());
|
||||
|
||||
v8::Local<v8::Value> stats = Nan::Get(
|
||||
result,
|
||||
Nan::New("stats").ToLocalChecked()
|
||||
).ToLocalChecked();
|
||||
if (stats->IsObject()) {
|
||||
Nan::Set(
|
||||
stats.As<v8::Object>(),
|
||||
Nan::New("includedFiles").ToLocalChecked(),
|
||||
arr
|
||||
);
|
||||
} else {
|
||||
Nan::ThrowTypeError("\"result.stats\" element is not an object");
|
||||
}
|
||||
}
|
||||
|
||||
int GetResult(sass_context_wrapper* ctx_w, Sass_Context* ctx, bool is_sync = false) {
|
||||
Nan::HandleScope scope;
|
||||
v8::Local<v8::Object> result;
|
||||
|
||||
int status = sass_context_get_error_status(ctx);
|
||||
|
||||
result = Nan::New(ctx_w->result);
|
||||
assert(result->IsObject());
|
||||
|
||||
if (status == 0) {
|
||||
const char* css = sass_context_get_output_string(ctx);
|
||||
const char* map = sass_context_get_source_map_string(ctx);
|
||||
|
||||
Nan::Set(result, Nan::New("css").ToLocalChecked(), Nan::CopyBuffer(css, static_cast<uint32_t>(strlen(css))).ToLocalChecked());
|
||||
|
||||
GetStats(ctx_w, ctx);
|
||||
|
||||
if (map) {
|
||||
Nan::Set(result, Nan::New("map").ToLocalChecked(), Nan::CopyBuffer(map, static_cast<uint32_t>(strlen(map))).ToLocalChecked());
|
||||
}
|
||||
}
|
||||
else if (is_sync) {
|
||||
Nan::Set(result, Nan::New("error").ToLocalChecked(), Nan::New<v8::String>(sass_context_get_error_json(ctx)).ToLocalChecked());
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void MakeCallback(uv_work_t* req) {
|
||||
Nan::HandleScope scope;
|
||||
|
||||
Nan::TryCatch try_catch;
|
||||
sass_context_wrapper* ctx_w = static_cast<sass_context_wrapper*>(req->data);
|
||||
struct Sass_Context* ctx;
|
||||
|
||||
if (ctx_w->dctx) {
|
||||
ctx = sass_data_context_get_context(ctx_w->dctx);
|
||||
}
|
||||
else {
|
||||
ctx = sass_file_context_get_context(ctx_w->fctx);
|
||||
}
|
||||
|
||||
int status = GetResult(ctx_w, ctx);
|
||||
|
||||
if (status == 0 && ctx_w->success_callback) {
|
||||
// if no error, do callback(null, result)
|
||||
ctx_w->success_callback->Call(0, 0);
|
||||
}
|
||||
else if (ctx_w->error_callback) {
|
||||
// if error, do callback(error)
|
||||
const char* err = sass_context_get_error_json(ctx);
|
||||
v8::Local<v8::Value> argv[] = {
|
||||
Nan::New<v8::String>(err).ToLocalChecked()
|
||||
};
|
||||
ctx_w->error_callback->Call(1, argv);
|
||||
}
|
||||
if (try_catch.HasCaught()) {
|
||||
Nan::FatalException(try_catch);
|
||||
}
|
||||
|
||||
sass_free_context_wrapper(ctx_w);
|
||||
}
|
||||
|
||||
NAN_METHOD(render) {
|
||||
|
||||
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
|
||||
char* source_string = create_string(Nan::Get(options, Nan::New("data").ToLocalChecked()));
|
||||
struct Sass_Data_Context* dctx = sass_make_data_context(source_string);
|
||||
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
|
||||
|
||||
if (ExtractOptions(options, dctx, ctx_w, false, false) >= 0) {
|
||||
|
||||
int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
|
||||
|
||||
assert(status == 0);
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(render_sync) {
|
||||
|
||||
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
|
||||
char* source_string = create_string(Nan::Get(options, Nan::New("data").ToLocalChecked()));
|
||||
struct Sass_Data_Context* dctx = sass_make_data_context(source_string);
|
||||
struct Sass_Context* ctx = sass_data_context_get_context(dctx);
|
||||
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
|
||||
int result = -1;
|
||||
|
||||
if ((result = ExtractOptions(options, dctx, ctx_w, false, true)) >= 0) {
|
||||
compile_data(dctx);
|
||||
result = GetResult(ctx_w, ctx, true);
|
||||
}
|
||||
|
||||
sass_free_context_wrapper(ctx_w);
|
||||
info.GetReturnValue().Set(result == 0);
|
||||
}
|
||||
|
||||
NAN_METHOD(render_file) {
|
||||
|
||||
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
|
||||
char* input_path = create_string(Nan::Get(options, Nan::New("file").ToLocalChecked()));
|
||||
struct Sass_File_Context* fctx = sass_make_file_context(input_path);
|
||||
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
|
||||
|
||||
if (ExtractOptions(options, fctx, ctx_w, true, false) >= 0) {
|
||||
|
||||
int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback);
|
||||
assert(status == 0);
|
||||
}
|
||||
}
|
||||
|
||||
NAN_METHOD(render_file_sync) {
|
||||
|
||||
v8::Local<v8::Object> options = Nan::To<v8::Object>(info[0]).ToLocalChecked();
|
||||
char* input_path = create_string(Nan::Get(options, Nan::New("file").ToLocalChecked()));
|
||||
struct Sass_File_Context* fctx = sass_make_file_context(input_path);
|
||||
struct Sass_Context* ctx = sass_file_context_get_context(fctx);
|
||||
sass_context_wrapper* ctx_w = sass_make_context_wrapper();
|
||||
int result = -1;
|
||||
|
||||
if ((result = ExtractOptions(options, fctx, ctx_w, true, true)) >= 0) {
|
||||
compile_file(fctx);
|
||||
result = GetResult(ctx_w, ctx, true);
|
||||
};
|
||||
|
||||
free(input_path);
|
||||
sass_free_context_wrapper(ctx_w);
|
||||
|
||||
info.GetReturnValue().Set(result == 0);
|
||||
}
|
||||
|
||||
NAN_METHOD(libsass_version) {
|
||||
info.GetReturnValue().Set(Nan::New<v8::String>(libsass_version()).ToLocalChecked());
|
||||
}
|
||||
|
||||
NAN_MODULE_INIT(RegisterModule) {
|
||||
Nan::SetMethod(target, "render", render);
|
||||
Nan::SetMethod(target, "renderSync", render_sync);
|
||||
Nan::SetMethod(target, "renderFile", render_file);
|
||||
Nan::SetMethod(target, "renderFileSync", render_file_sync);
|
||||
Nan::SetMethod(target, "libsassVersion", libsass_version);
|
||||
SassTypes::Factory::initExports(target);
|
||||
}
|
||||
|
||||
NODE_MODULE(binding, RegisterModule);
|
||||
+225
@@ -0,0 +1,225 @@
|
||||
#ifndef CALLBACK_BRIDGE_H
|
||||
#define CALLBACK_BRIDGE_H
|
||||
|
||||
#include <vector>
|
||||
#include <nan.h>
|
||||
#include <algorithm>
|
||||
#include <uv.h>
|
||||
|
||||
#define COMMA ,
|
||||
|
||||
template <typename T, typename L = void*>
|
||||
class CallbackBridge {
|
||||
public:
|
||||
CallbackBridge(v8::Local<v8::Function>, bool);
|
||||
virtual ~CallbackBridge();
|
||||
|
||||
// Executes the callback
|
||||
T operator()(std::vector<void*>);
|
||||
|
||||
protected:
|
||||
// We will expose a bridge object to the JS callback that wraps this instance so we don't loose context.
|
||||
// This is the V8 constructor for such objects.
|
||||
static Nan::MaybeLocal<v8::Function> get_wrapper_constructor();
|
||||
static void async_gone(uv_handle_t *handle);
|
||||
static NAN_METHOD(New);
|
||||
static NAN_METHOD(ReturnCallback);
|
||||
static Nan::Persistent<v8::Function> wrapper_constructor;
|
||||
Nan::Persistent<v8::Object> wrapper;
|
||||
|
||||
// The callback that will get called in the main thread after the worker thread used for the sass
|
||||
// compilation step makes a call to uv_async_send()
|
||||
static void dispatched_async_uv_callback(uv_async_t*);
|
||||
|
||||
// The V8 values sent to our ReturnCallback must be read on the main thread not the sass worker thread.
|
||||
// This gives a chance to specialized subclasses to transform those values into whatever makes sense to
|
||||
// sass before we resume the worker thread.
|
||||
virtual T post_process_return_value(v8::Local<v8::Value>) const =0;
|
||||
|
||||
|
||||
virtual std::vector<v8::Local<v8::Value>> pre_process_args(std::vector<L>) const =0;
|
||||
|
||||
Nan::Callback* callback;
|
||||
bool is_sync;
|
||||
|
||||
uv_mutex_t cv_mutex;
|
||||
uv_cond_t condition_variable;
|
||||
uv_async_t *async;
|
||||
std::vector<L> argv;
|
||||
bool has_returned;
|
||||
T return_value;
|
||||
};
|
||||
|
||||
template <typename T, typename L>
|
||||
Nan::Persistent<v8::Function> CallbackBridge<T, L>::wrapper_constructor;
|
||||
|
||||
template <typename T, typename L>
|
||||
CallbackBridge<T, L>::CallbackBridge(v8::Local<v8::Function> callback, bool is_sync) : callback(new Nan::Callback(callback)), is_sync(is_sync) {
|
||||
/*
|
||||
* This is invoked from the main JavaScript thread.
|
||||
* V8 context is available.
|
||||
*/
|
||||
Nan::HandleScope scope;
|
||||
uv_mutex_init(&this->cv_mutex);
|
||||
uv_cond_init(&this->condition_variable);
|
||||
if (!is_sync) {
|
||||
this->async = new uv_async_t;
|
||||
this->async->data = (void*) this;
|
||||
uv_async_init(uv_default_loop(), this->async, (uv_async_cb) dispatched_async_uv_callback);
|
||||
}
|
||||
|
||||
v8::Local<v8::Function> func = CallbackBridge<T, L>::get_wrapper_constructor().ToLocalChecked();
|
||||
wrapper.Reset(Nan::NewInstance(func).ToLocalChecked());
|
||||
Nan::SetInternalFieldPointer(Nan::New(wrapper), 0, this);
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
CallbackBridge<T, L>::~CallbackBridge() {
|
||||
delete this->callback;
|
||||
this->wrapper.Reset();
|
||||
uv_cond_destroy(&this->condition_variable);
|
||||
uv_mutex_destroy(&this->cv_mutex);
|
||||
|
||||
if (!is_sync) {
|
||||
uv_close((uv_handle_t*)this->async, &async_gone);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
T CallbackBridge<T, L>::operator()(std::vector<void*> argv) {
|
||||
// argv.push_back(wrapper);
|
||||
if (this->is_sync) {
|
||||
/*
|
||||
* This is invoked from the main JavaScript thread.
|
||||
* V8 context is available.
|
||||
*
|
||||
* Establish Local<> scope for all functions
|
||||
* from types invoked by pre_process_args() and
|
||||
* post_process_args().
|
||||
*/
|
||||
Nan::HandleScope scope;
|
||||
Nan::TryCatch try_catch;
|
||||
std::vector<v8::Local<v8::Value>> argv_v8 = pre_process_args(argv);
|
||||
if (try_catch.HasCaught()) {
|
||||
Nan::FatalException(try_catch);
|
||||
}
|
||||
|
||||
argv_v8.push_back(Nan::New(wrapper));
|
||||
|
||||
return this->post_process_return_value(
|
||||
this->callback->Call(argv_v8.size(), &argv_v8[0])
|
||||
);
|
||||
} else {
|
||||
/*
|
||||
* This is invoked from the worker thread.
|
||||
* No V8 context and functions available.
|
||||
* Just wait for response from asynchronously
|
||||
* scheduled JavaScript code
|
||||
*
|
||||
* XXX Issue #1048: We block here even if the
|
||||
* event loop stops and the callback
|
||||
* would never be executed.
|
||||
* XXX Issue #857: By waiting here we occupy
|
||||
* one of the threads taken from the
|
||||
* uv threadpool. Might deadlock if
|
||||
* async I/O executed from JavaScript callbacks.
|
||||
*/
|
||||
this->argv = argv;
|
||||
|
||||
uv_mutex_lock(&this->cv_mutex);
|
||||
this->has_returned = false;
|
||||
uv_async_send(this->async);
|
||||
while (!this->has_returned) {
|
||||
uv_cond_wait(&this->condition_variable, &this->cv_mutex);
|
||||
}
|
||||
uv_mutex_unlock(&this->cv_mutex);
|
||||
return this->return_value;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
void CallbackBridge<T, L>::dispatched_async_uv_callback(uv_async_t *req) {
|
||||
CallbackBridge* bridge = static_cast<CallbackBridge*>(req->data);
|
||||
|
||||
/*
|
||||
* Function scheduled via uv_async mechanism, therefore
|
||||
* it is invoked from the main JavaScript thread.
|
||||
* V8 context is available.
|
||||
*
|
||||
* Establish Local<> scope for all functions
|
||||
* from types invoked by pre_process_args() and
|
||||
* post_process_args().
|
||||
*/
|
||||
Nan::HandleScope scope;
|
||||
Nan::TryCatch try_catch;
|
||||
|
||||
std::vector<v8::Local<v8::Value>> argv_v8 = bridge->pre_process_args(bridge->argv);
|
||||
if (try_catch.HasCaught()) {
|
||||
Nan::FatalException(try_catch);
|
||||
}
|
||||
argv_v8.push_back(Nan::New(bridge->wrapper));
|
||||
|
||||
bridge->callback->Call(argv_v8.size(), &argv_v8[0]);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
Nan::FatalException(try_catch);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
NAN_METHOD(CallbackBridge<T COMMA L>::ReturnCallback) {
|
||||
|
||||
/*
|
||||
* Callback function invoked by the user code.
|
||||
* It is invoked from the main JavaScript thread.
|
||||
* V8 context is available.
|
||||
*
|
||||
* Implicit Local<> handle scope created by NAN_METHOD(.)
|
||||
*/
|
||||
CallbackBridge<T, L>* bridge = static_cast<CallbackBridge<T, L>*>(Nan::GetInternalFieldPointer(info.This(), 0));
|
||||
Nan::TryCatch try_catch;
|
||||
|
||||
bridge->return_value = bridge->post_process_return_value(info[0]);
|
||||
|
||||
{
|
||||
uv_mutex_lock(&bridge->cv_mutex);
|
||||
bridge->has_returned = true;
|
||||
uv_mutex_unlock(&bridge->cv_mutex);
|
||||
}
|
||||
|
||||
uv_cond_broadcast(&bridge->condition_variable);
|
||||
|
||||
if (try_catch.HasCaught()) {
|
||||
Nan::FatalException(try_catch);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
Nan::MaybeLocal<v8::Function> CallbackBridge<T, L>::get_wrapper_constructor() {
|
||||
/* Uses handle scope created in the CallbackBridge<T, L> constructor */
|
||||
if (wrapper_constructor.IsEmpty()) {
|
||||
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
|
||||
tpl->SetClassName(Nan::New("CallbackBridge").ToLocalChecked());
|
||||
tpl->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
|
||||
Nan::SetPrototypeTemplate(tpl, "success",
|
||||
Nan::New<v8::FunctionTemplate>(ReturnCallback)
|
||||
);
|
||||
|
||||
wrapper_constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
|
||||
}
|
||||
|
||||
return Nan::New(wrapper_constructor);
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
NAN_METHOD(CallbackBridge<T COMMA L>::New) {
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
template <typename T, typename L>
|
||||
void CallbackBridge<T, L>::async_gone(uv_handle_t *handle) {
|
||||
delete (uv_async_t *)handle;
|
||||
}
|
||||
|
||||
#endif
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
#include <nan.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "create_string.h"
|
||||
|
||||
char* create_string(Nan::MaybeLocal<v8::Value> maybevalue) {
|
||||
v8::Local<v8::Value> value;
|
||||
|
||||
if (maybevalue.ToLocal(&value)) {
|
||||
if (value->IsNull() || !value->IsString()) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
v8::String::Utf8Value string(value);
|
||||
char *str = (char *)malloc(string.length() + 1);
|
||||
strcpy(str, *string);
|
||||
return str;
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#ifndef CREATE_STRING_H
|
||||
#define CREATE_STRING_H
|
||||
|
||||
#include <nan.h>
|
||||
|
||||
char* create_string(Nan::MaybeLocal<v8::Value>);
|
||||
|
||||
#endif
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
#include <nan.h>
|
||||
#include <stdexcept>
|
||||
#include "custom_function_bridge.h"
|
||||
#include "sass_types/factory.h"
|
||||
#include "sass_types/value.h"
|
||||
|
||||
Sass_Value* CustomFunctionBridge::post_process_return_value(v8::Local<v8::Value> val) const {
|
||||
SassTypes::Value *v_;
|
||||
if ((v_ = SassTypes::Factory::unwrap(val))) {
|
||||
return v_->get_sass_value();
|
||||
} else {
|
||||
return sass_make_error("A SassValue object was expected.");
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<v8::Local<v8::Value>> CustomFunctionBridge::pre_process_args(std::vector<void*> in) const {
|
||||
std::vector<v8::Local<v8::Value>> argv = std::vector<v8::Local<v8::Value>>();
|
||||
|
||||
for (void* value : in) {
|
||||
argv.push_back(SassTypes::Factory::create(static_cast<Sass_Value*>(value))->get_js_object());
|
||||
}
|
||||
|
||||
return argv;
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
#ifndef CUSTOM_FUNCTION_BRIDGE_H
|
||||
#define CUSTOM_FUNCTION_BRIDGE_H
|
||||
|
||||
#include <nan.h>
|
||||
#include <sass/values.h>
|
||||
#include <sass/functions.h>
|
||||
#include "callback_bridge.h"
|
||||
|
||||
class CustomFunctionBridge : public CallbackBridge<Sass_Value*> {
|
||||
public:
|
||||
CustomFunctionBridge(v8::Local<v8::Function> cb, bool is_sync) : CallbackBridge<Sass_Value*>(cb, is_sync) {}
|
||||
|
||||
private:
|
||||
Sass_Value* post_process_return_value(v8::Local<v8::Value>) const;
|
||||
std::vector<v8::Local<v8::Value>> pre_process_args(std::vector<void*>) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
#include <nan.h>
|
||||
#include <stdexcept>
|
||||
#include "custom_importer_bridge.h"
|
||||
#include "create_string.h"
|
||||
|
||||
SassImportList CustomImporterBridge::post_process_return_value(v8::Local<v8::Value> returned_value) const {
|
||||
SassImportList imports = 0;
|
||||
Nan::HandleScope scope;
|
||||
|
||||
if (returned_value->IsArray()) {
|
||||
v8::Local<v8::Array> array = returned_value.As<v8::Array>();
|
||||
|
||||
imports = sass_make_import_list(array->Length());
|
||||
|
||||
for (size_t i = 0; i < array->Length(); ++i) {
|
||||
v8::Local<v8::Value> value = Nan::Get(array, static_cast<uint32_t>(i)).ToLocalChecked();
|
||||
|
||||
if (!value->IsObject()) {
|
||||
auto entry = sass_make_import_entry(0, 0, 0);
|
||||
sass_import_set_error(entry, "returned array must only contain object literals", -1, -1);
|
||||
continue;
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> object = value.As<v8::Object>();
|
||||
|
||||
if (value->IsNativeError()) {
|
||||
char* message = create_string(Nan::Get(object, Nan::New<v8::String>("message").ToLocalChecked()));
|
||||
|
||||
imports[i] = sass_make_import_entry(0, 0, 0);
|
||||
|
||||
sass_import_set_error(imports[i], message, -1, -1);
|
||||
}
|
||||
else {
|
||||
imports[i] = get_importer_entry(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (returned_value->IsNativeError()) {
|
||||
imports = sass_make_import_list(1);
|
||||
v8::Local<v8::Object> object = returned_value.As<v8::Object>();
|
||||
char* message = create_string(Nan::Get(object, Nan::New<v8::String>("message").ToLocalChecked()));
|
||||
|
||||
imports[0] = sass_make_import_entry(0, 0, 0);
|
||||
|
||||
sass_import_set_error(imports[0], message, -1, -1);
|
||||
}
|
||||
else if (returned_value->IsObject()) {
|
||||
imports = sass_make_import_list(1);
|
||||
imports[0] = get_importer_entry(returned_value.As<v8::Object>());
|
||||
}
|
||||
|
||||
return imports;
|
||||
}
|
||||
|
||||
Sass_Import* CustomImporterBridge::check_returned_string(Nan::MaybeLocal<v8::Value> value, const char *msg) const
|
||||
{
|
||||
v8::Local<v8::Value> checked;
|
||||
if (value.ToLocal(&checked)) {
|
||||
if (!checked->IsUndefined() && !checked->IsString()) {
|
||||
goto err;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
err:
|
||||
auto entry = sass_make_import_entry(0, 0, 0);
|
||||
sass_import_set_error(entry, msg, -1, -1);
|
||||
return entry;
|
||||
}
|
||||
|
||||
Sass_Import* CustomImporterBridge::get_importer_entry(const v8::Local<v8::Object>& object) const {
|
||||
auto returned_file = Nan::Get(object, Nan::New<v8::String>("file").ToLocalChecked());
|
||||
auto returned_contents = Nan::Get(object, Nan::New<v8::String>("contents").ToLocalChecked()).ToLocalChecked();
|
||||
auto returned_map = Nan::Get(object, Nan::New<v8::String>("map").ToLocalChecked());
|
||||
Sass_Import *err;
|
||||
|
||||
if ((err = check_returned_string(returned_file, "returned value of `file` must be a string")))
|
||||
return err;
|
||||
|
||||
if ((err = check_returned_string(returned_contents, "returned value of `contents` must be a string")))
|
||||
return err;
|
||||
|
||||
if ((err = check_returned_string(returned_map, "returned value of `returned_map` must be a string")))
|
||||
return err;
|
||||
|
||||
char* path = create_string(returned_file);
|
||||
char* contents = create_string(returned_contents);
|
||||
char* srcmap = create_string(returned_map);
|
||||
|
||||
return sass_make_import_entry(path, contents, srcmap);
|
||||
}
|
||||
|
||||
std::vector<v8::Local<v8::Value>> CustomImporterBridge::pre_process_args(std::vector<void*> in) const {
|
||||
std::vector<v8::Local<v8::Value>> out;
|
||||
|
||||
for (void* ptr : in) {
|
||||
out.push_back(Nan::New<v8::String>((char const*)ptr).ToLocalChecked());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
#ifndef CUSTOM_IMPORTER_BRIDGE_H
|
||||
#define CUSTOM_IMPORTER_BRIDGE_H
|
||||
|
||||
#include <nan.h>
|
||||
#include <sass/functions.h>
|
||||
#include <sass/values.h>
|
||||
#include "callback_bridge.h"
|
||||
|
||||
typedef Sass_Import_List SassImportList;
|
||||
|
||||
class CustomImporterBridge : public CallbackBridge<SassImportList> {
|
||||
public:
|
||||
CustomImporterBridge(v8::Local<v8::Function> cb, bool is_sync) : CallbackBridge<SassImportList>(cb, is_sync) {}
|
||||
|
||||
private:
|
||||
SassImportList post_process_return_value(v8::Local<v8::Value>) const;
|
||||
Sass_Import* check_returned_string(Nan::MaybeLocal<v8::Value> value, const char *msg) const;
|
||||
Sass_Import* get_importer_entry(const v8::Local<v8::Object>&) const;
|
||||
std::vector<v8::Local<v8::Value>> pre_process_args(std::vector<void*>) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
{
|
||||
'targets': [
|
||||
{
|
||||
'target_name': 'libsass',
|
||||
'win_delay_load_hook': 'false',
|
||||
'type': 'static_library',
|
||||
'defines': [
|
||||
'LIBSASS_VERSION="<!(node -e "process.stdout.write(require(\'../package.json\').libsass)")"'
|
||||
],
|
||||
'defines!': [
|
||||
'DEBUG'
|
||||
],
|
||||
'sources': [
|
||||
'libsass/src/ast.cpp',
|
||||
'libsass/src/base64vlq.cpp',
|
||||
'libsass/src/bind.cpp',
|
||||
'libsass/src/cencode.c',
|
||||
'libsass/src/color_maps.cpp',
|
||||
'libsass/src/constants.cpp',
|
||||
'libsass/src/context.cpp',
|
||||
'libsass/src/cssize.cpp',
|
||||
'libsass/src/emitter.cpp',
|
||||
'libsass/src/environment.cpp',
|
||||
'libsass/src/error_handling.cpp',
|
||||
'libsass/src/eval.cpp',
|
||||
'libsass/src/expand.cpp',
|
||||
'libsass/src/extend.cpp',
|
||||
'libsass/src/file.cpp',
|
||||
'libsass/src/functions.cpp',
|
||||
'libsass/src/inspect.cpp',
|
||||
'libsass/src/json.cpp',
|
||||
'libsass/src/lexer.cpp',
|
||||
'libsass/src/listize.cpp',
|
||||
'libsass/src/memory_manager.cpp',
|
||||
'libsass/src/node.cpp',
|
||||
'libsass/src/output.cpp',
|
||||
'libsass/src/parser.cpp',
|
||||
'libsass/src/plugins.cpp',
|
||||
'libsass/src/position.cpp',
|
||||
'libsass/src/prelexer.cpp',
|
||||
'libsass/src/remove_placeholders.cpp',
|
||||
'libsass/src/sass.cpp',
|
||||
'libsass/src/sass2scss.cpp',
|
||||
'libsass/src/sass_context.cpp',
|
||||
'libsass/src/sass_functions.cpp',
|
||||
'libsass/src/sass_util.cpp',
|
||||
'libsass/src/sass_values.cpp',
|
||||
'libsass/src/source_map.cpp',
|
||||
'libsass/src/to_c.cpp',
|
||||
'libsass/src/to_value.cpp',
|
||||
'libsass/src/units.cpp',
|
||||
'libsass/src/utf8_string.cpp',
|
||||
'libsass/src/util.cpp',
|
||||
'libsass/src/values.cpp'
|
||||
],
|
||||
'cflags!': [
|
||||
'-fno-rtti',
|
||||
'-fno-exceptions'
|
||||
],
|
||||
'cflags_cc!': [
|
||||
'-fno-rtti',
|
||||
'-fno-exceptions'
|
||||
],
|
||||
'cflags_cc': [
|
||||
'-fexceptions',
|
||||
'-frtti',
|
||||
],
|
||||
'include_dirs': [ 'libsass/include' ],
|
||||
'direct_dependent_settings': {
|
||||
'include_dirs': [ 'libsass/include' ],
|
||||
},
|
||||
'conditions': [
|
||||
['OS=="mac"', {
|
||||
'xcode_settings': {
|
||||
'CLANG_CXX_LANGUAGE_STANDARD': 'c++11',
|
||||
'CLANG_CXX_LIBRARY': 'libc++',
|
||||
'OTHER_LDFLAGS': [],
|
||||
'GCC_ENABLE_CPP_EXCEPTIONS': 'YES',
|
||||
'GCC_ENABLE_CPP_RTTI': 'YES',
|
||||
'MACOSX_DEPLOYMENT_TARGET': '10.7'
|
||||
}
|
||||
}],
|
||||
['OS=="win"', {
|
||||
'msvs_settings': {
|
||||
'VCCLCompilerTool': {
|
||||
'AdditionalOptions': [
|
||||
'/GR',
|
||||
'/EHsc'
|
||||
]
|
||||
}
|
||||
},
|
||||
'conditions': [
|
||||
['MSVS_VERSION < "2015"', {
|
||||
'sources': [
|
||||
'libsass/src/c99func.c'
|
||||
]
|
||||
}]
|
||||
]
|
||||
}],
|
||||
['OS!="win"', {
|
||||
'cflags_cc+': [
|
||||
'-std=c++0x'
|
||||
]
|
||||
}]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# This file is for unifying the coding style for different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = spaces
|
||||
indent_size = 2
|
||||
|
||||
[{Makefile, GNUmakefile.am}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
@@ -0,0 +1,2 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
# Miscellaneous stuff
|
||||
|
||||
/sassc
|
||||
/sass-spec
|
||||
|
||||
VERSION
|
||||
.DS_Store
|
||||
.sass-cache
|
||||
*.gem
|
||||
*.gcno
|
||||
.svn/*
|
||||
.cproject
|
||||
.project
|
||||
.settings/
|
||||
|
||||
# Configuration stuff
|
||||
|
||||
GNUmakefile.in
|
||||
GNUmakefile
|
||||
/aclocal.m4
|
||||
/autom4te.cache/
|
||||
/src/config.h
|
||||
/config.h.in
|
||||
/config.log
|
||||
/config.status
|
||||
/configure
|
||||
/libtool
|
||||
/m4/libtool.m4
|
||||
/m4/ltoptions.m4
|
||||
/m4/ltsugar.m4
|
||||
/m4/ltversion.m4
|
||||
/m4/lt~obsolete.m4
|
||||
/script/ar-lib
|
||||
/script/compile
|
||||
/script/config.guess
|
||||
/script/config.sub
|
||||
/script/depcomp
|
||||
/script/install-sh
|
||||
/script/ltmain.sh
|
||||
/script/missing
|
||||
/script/test-driver
|
||||
/src/stamp-h1
|
||||
/src/Makefile.in
|
||||
/src/Makefile
|
||||
libsass/*
|
||||
|
||||
# Build stuff
|
||||
|
||||
*.o
|
||||
*.lo
|
||||
*.so
|
||||
*.dll
|
||||
*.a
|
||||
*.suo
|
||||
*.sdf
|
||||
*.opendb
|
||||
*.opensdf
|
||||
a.out
|
||||
libsass.js
|
||||
tester
|
||||
tester.exe
|
||||
build/
|
||||
config.h.in*
|
||||
lib/pkgconfig/
|
||||
|
||||
bin/*
|
||||
.deps/
|
||||
.libs/
|
||||
win/bin
|
||||
*.user
|
||||
|
||||
# Final results
|
||||
|
||||
sassc++
|
||||
libsass.la
|
||||
src/support/libsass.pc
|
||||
|
||||
# Cloned testing dirs
|
||||
sassc/
|
||||
sass-spec/
|
||||
|
||||
installer/
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
language: cpp
|
||||
sudo: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
|
||||
compiler:
|
||||
- gcc
|
||||
- clang
|
||||
|
||||
# don't create redundant code coverage reports
|
||||
# - AUTOTOOLS=yes COVERAGE=yes BUILD=static
|
||||
# - AUTOTOOLS=no COVERAGE=yes BUILD=shared
|
||||
# - AUTOTOOLS=no COVERAGE=no BUILD=static
|
||||
|
||||
# further speed up day by day travis-ci builds
|
||||
# re-enable this if you change the makefiles
|
||||
# this will still catch all coding errors!
|
||||
# - AUTOTOOLS=yes COVERAGE=no BUILD=static
|
||||
|
||||
env:
|
||||
- AUTOTOOLS=no COVERAGE=no BUILD=shared
|
||||
- AUTOTOOLS=no COVERAGE=yes BUILD=static
|
||||
- AUTOTOOLS=yes COVERAGE=no BUILD=shared
|
||||
|
||||
# currenty there are various issues when
|
||||
# built with coverage, clang and autotools
|
||||
# - AUTOTOOLS=yes COVERAGE=yes BUILD=shared
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- compiler: clang
|
||||
env: AUTOTOOLS=yes COVERAGE=yes BUILD=static
|
||||
- os: linux
|
||||
env: AUTOTOOLS=no COVERAGE=no BUILD=shared
|
||||
- os: osx
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
env: AUTOTOOLS=no BUILD=static
|
||||
|
||||
script: ./script/ci-build-libsass
|
||||
before_install: ./script/ci-install-deps
|
||||
install: ./script/ci-install-compiler
|
||||
after_success: ./script/ci-report-coverage
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
Copyright (C) 2012 by Hampton Catlin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
The following files in the spec were taken from the original Ruby Sass project which
|
||||
is copyright Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein and under
|
||||
the same license.
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -I script
|
||||
|
||||
AM_COPT = -Wall -O2
|
||||
AM_COVLDFLAGS =
|
||||
|
||||
if ENABLE_COVERAGE
|
||||
AM_COPT = -O0 --coverage
|
||||
AM_COVLDFLAGS += -lgcov
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_CFLAGS = $(AM_COPT)
|
||||
AM_CXXFLAGS = $(AM_COPT)
|
||||
AM_LDFLAGS = $(AM_COPT) $(AM_COVLDFLAGS)
|
||||
|
||||
# only needed to support old source tree
|
||||
# we have moved the files to src folder
|
||||
AM_CPPFLAGS += -I$(top_srcdir)
|
||||
|
||||
RESOURCES =
|
||||
if COMPILER_IS_MINGW32
|
||||
RESOURCES += res/libsass.rc
|
||||
AM_CXXFLAGS += -std=gnu++0x
|
||||
else
|
||||
AM_CXXFLAGS += -std=c++0x
|
||||
endif
|
||||
|
||||
if ENABLE_TESTS
|
||||
|
||||
noinst_PROGRAMS = tester
|
||||
|
||||
tester_LDADD = src/libsass.la
|
||||
tester_SOURCES = $(SASS_SASSC_PATH)/sassc.c
|
||||
tester_VERSION ?= `cd "$(SASS_SASSC_PATH)" && ./version.sh`
|
||||
tester_CFLAGS = $(AM_CFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
|
||||
tester_CXXFLAGS = $(AM_CXXFLAGS) -DSASSC_VERSION="\"$(tester_VERSION)\""
|
||||
tester_LDFLAGS = $(AM_LDFLAGS)
|
||||
|
||||
if ENABLE_COVERAGE
|
||||
nodist_EXTRA_tester_SOURCES = non-existent-file-to-force-CXX-linking.cxx
|
||||
endif
|
||||
|
||||
SASS_SASSC_PATH ?= $(top_srcdir)/sassc
|
||||
SASS_SPEC_PATH ?= $(top_srcdir)/sass-spec
|
||||
|
||||
TESTS = \
|
||||
$(SASS_SPEC_PATH)/spec/basic \
|
||||
$(SASS_SPEC_PATH)/spec/css \
|
||||
$(SASS_SPEC_PATH)/spec/extend-tests \
|
||||
$(SASS_SPEC_PATH)/spec/extends \
|
||||
$(SASS_SPEC_PATH)/spec/libsass \
|
||||
$(SASS_SPEC_PATH)/spec/libsass-closed-issues \
|
||||
$(SASS_SPEC_PATH)/spec/maps \
|
||||
$(SASS_SPEC_PATH)/spec/misc \
|
||||
$(SASS_SPEC_PATH)/spec/regressions \
|
||||
$(SASS_SPEC_PATH)/spec/scss \
|
||||
$(SASS_SPEC_PATH)/spec/scss-tests \
|
||||
$(SASS_SPEC_PATH)/spec/types
|
||||
|
||||
SASS_TEST_FLAGS = -V 3.4 --impl libsass
|
||||
LOG_DRIVER = env AM_TAP_AWK='$(AWK)' $(SHELL) ./script/tap-driver
|
||||
AM_LOG_FLAGS = -c ./tester $(LOG_FLAGS)
|
||||
if USE_TAP
|
||||
AM_LOG_FLAGS += -t
|
||||
SASS_TEST_FLAGS += -t | tapout
|
||||
LOG_COMPILER = ./script/tap-runner $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
|
||||
else
|
||||
LOG_COMPILER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
|
||||
endif
|
||||
|
||||
SASS_TESTER = $(RUBY) $(SASS_SPEC_PATH)/sass-spec.rb
|
||||
SASS_TESTER += -c $(SASS_LIBSASS_PATH)/tester$(EXEEXT)
|
||||
|
||||
test:
|
||||
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
|
||||
|
||||
test_build:
|
||||
$(SASS_TESTER) $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
|
||||
|
||||
test_full:
|
||||
$(SASS_TESTER) --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
|
||||
|
||||
test_probe:
|
||||
$(SASS_TESTER) --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH) $(SASS_TEST_FLAGS)
|
||||
|
||||
endif
|
||||
|
||||
SUBDIRS = src
|
||||
+1
@@ -0,0 +1 @@
|
||||
// Autotools requires us to have this file. Boo.
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
|
||||
Copyright (C) 2012-2016 by the Sass Open Source Foundation
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
The following files in the spec were taken from the original Ruby Sass project which
|
||||
is copyright Hampton Catlin, Nathan Weizenbaum, and Chris Eppstein and under
|
||||
the same license.
|
||||
+342
@@ -0,0 +1,342 @@
|
||||
OS ?= $(shell uname -s)
|
||||
CC ?= gcc
|
||||
CXX ?= g++
|
||||
RM ?= rm -f
|
||||
CP ?= cp -a
|
||||
MKDIR ?= mkdir
|
||||
RMDIR ?= rmdir
|
||||
WINDRES ?= windres
|
||||
# Solaris/Illumos flavors
|
||||
# ginstall from coreutils
|
||||
ifeq ($(OS),SunOS)
|
||||
INSTALL ?= ginstall
|
||||
endif
|
||||
INSTALL ?= install
|
||||
CFLAGS ?= -Wall
|
||||
CXXFLAGS ?= -Wall
|
||||
LDFLAGS ?= -Wall
|
||||
ifneq "$(COVERAGE)" "yes"
|
||||
CFLAGS += -O2
|
||||
CXXFLAGS += -O2
|
||||
LDFLAGS += -O2
|
||||
endif
|
||||
LDFLAGS += -Wl,-undefined,error
|
||||
CAT ?= $(if $(filter $(OS),Windows_NT),type,cat)
|
||||
|
||||
ifneq (,$(findstring /cygdrive/,$(PATH)))
|
||||
UNAME := Cygwin
|
||||
else
|
||||
ifneq (,$(findstring Windows_NT,$(OS)))
|
||||
UNAME := Windows
|
||||
else
|
||||
ifneq (,$(findstring mingw32,$(MAKE)))
|
||||
UNAME := Windows
|
||||
else
|
||||
ifneq (,$(findstring MINGW32,$(shell uname -s)))
|
||||
UNAME = Windows
|
||||
else
|
||||
UNAME := $(shell uname -s)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(SASS_LIBSASS_PATH),)
|
||||
SASS_LIBSASS_PATH = $(abspath $(CURDIR))
|
||||
endif
|
||||
|
||||
ifeq ($(LIBSASS_VERSION),)
|
||||
ifneq ($(wildcard ./.git/ ),)
|
||||
LIBSASS_VERSION ?= $(shell git describe --abbrev=4 --dirty --always --tags)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(LIBSASS_VERSION),)
|
||||
ifneq ($(wildcard VERSION),)
|
||||
LIBSASS_VERSION ?= $(shell $(CAT) VERSION)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(LIBSASS_VERSION),)
|
||||
CFLAGS += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
|
||||
CXXFLAGS += -DLIBSASS_VERSION="\"$(LIBSASS_VERSION)\""
|
||||
endif
|
||||
|
||||
# enable mandatory flag
|
||||
ifeq (Windows,$(UNAME))
|
||||
ifneq ($(BUILD),shared)
|
||||
STATIC_ALL ?= 1
|
||||
endif
|
||||
STATIC_LIBGCC ?= 1
|
||||
STATIC_LIBSTDCPP ?= 1
|
||||
CXXFLAGS += -std=gnu++0x
|
||||
LDFLAGS += -std=gnu++0x
|
||||
else
|
||||
STATIC_ALL ?= 0
|
||||
STATIC_LIBGCC ?= 0
|
||||
STATIC_LIBSTDCPP ?= 0
|
||||
CXXFLAGS += -std=c++0x
|
||||
LDFLAGS += -std=c++0x
|
||||
endif
|
||||
|
||||
ifneq ($(SASS_LIBSASS_PATH),)
|
||||
CFLAGS += -I $(SASS_LIBSASS_PATH)/include
|
||||
CXXFLAGS += -I $(SASS_LIBSASS_PATH)/include
|
||||
else
|
||||
# this is needed for mingw
|
||||
CFLAGS += -I include
|
||||
CXXFLAGS += -I include
|
||||
endif
|
||||
|
||||
ifneq ($(EXTRA_CFLAGS),)
|
||||
CFLAGS += $(EXTRA_CFLAGS)
|
||||
endif
|
||||
ifneq ($(EXTRA_CXXFLAGS),)
|
||||
CXXFLAGS += $(EXTRA_CXXFLAGS)
|
||||
endif
|
||||
ifneq ($(EXTRA_LDFLAGS),)
|
||||
LDFLAGS += $(EXTRA_LDFLAGS)
|
||||
endif
|
||||
|
||||
LDLIBS = -lm
|
||||
|
||||
ifneq ($(BUILD),shared)
|
||||
LDLIBS += -lstdc++
|
||||
endif
|
||||
|
||||
# link statically into lib
|
||||
# makes it a lot more portable
|
||||
# increases size by about 50KB
|
||||
ifeq ($(STATIC_ALL),1)
|
||||
LDFLAGS += -static
|
||||
endif
|
||||
ifeq ($(STATIC_LIBGCC),1)
|
||||
LDFLAGS += -static-libgcc
|
||||
endif
|
||||
ifeq ($(STATIC_LIBSTDCPP),1)
|
||||
LDFLAGS += -static-libstdc++
|
||||
endif
|
||||
|
||||
ifeq ($(UNAME),Darwin)
|
||||
CFLAGS += -stdlib=libc++
|
||||
CXXFLAGS += -stdlib=libc++
|
||||
LDFLAGS += -stdlib=libc++
|
||||
endif
|
||||
|
||||
ifneq (Windows,$(UNAME))
|
||||
ifneq (FreeBSD,$(UNAME))
|
||||
LDFLAGS += -ldl
|
||||
LDLIBS += -ldl
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(BUILD),shared)
|
||||
BUILD = static
|
||||
endif
|
||||
|
||||
ifeq (,$(TRAVIS_BUILD_DIR))
|
||||
ifeq ($(OS),SunOS)
|
||||
PREFIX ?= /opt/local
|
||||
else
|
||||
PREFIX ?= /usr/local
|
||||
endif
|
||||
else
|
||||
PREFIX ?= $(TRAVIS_BUILD_DIR)
|
||||
endif
|
||||
|
||||
|
||||
SASS_SASSC_PATH ?= sassc
|
||||
SASS_SPEC_PATH ?= sass-spec
|
||||
SASS_SPEC_SPEC_DIR ?= spec
|
||||
SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc
|
||||
RUBY_BIN = ruby
|
||||
|
||||
LIB_STATIC = $(SASS_LIBSASS_PATH)/lib/libsass.a
|
||||
LIB_SHARED = $(SASS_LIBSASS_PATH)/lib/libsass.so
|
||||
|
||||
ifeq (Windows,$(UNAME))
|
||||
ifeq (shared,$(BUILD))
|
||||
CFLAGS += -D ADD_EXPORTS
|
||||
CXXFLAGS += -D ADD_EXPORTS
|
||||
LIB_SHARED = $(SASS_LIBSASS_PATH)/lib/libsass.dll
|
||||
endif
|
||||
else
|
||||
ifneq (Cygwin,$(UNAME))
|
||||
CFLAGS += -fPIC
|
||||
CXXFLAGS += -fPIC
|
||||
LDFLAGS += -fPIC
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq (Windows,$(UNAME))
|
||||
SASSC_BIN = $(SASS_SASSC_PATH)/bin/sassc.exe
|
||||
endif
|
||||
|
||||
include Makefile.conf
|
||||
|
||||
RESOURCES =
|
||||
STATICLIB = lib/libsass.a
|
||||
SHAREDLIB = lib/libsass.so
|
||||
ifeq (Windows,$(UNAME))
|
||||
RESOURCES += res/resource.rc
|
||||
SHAREDLIB = lib/libsass.dll
|
||||
ifeq (shared,$(BUILD))
|
||||
CFLAGS += -D ADD_EXPORTS
|
||||
CXXFLAGS += -D ADD_EXPORTS
|
||||
endif
|
||||
else
|
||||
ifneq (Cygwin,$(UNAME))
|
||||
CFLAGS += -fPIC
|
||||
CXXFLAGS += -fPIC
|
||||
LDFLAGS += -fPIC
|
||||
endif
|
||||
endif
|
||||
|
||||
OBJECTS = $(addprefix src/,$(SOURCES:.cpp=.o))
|
||||
COBJECTS = $(addprefix src/,$(CSOURCES:.c=.o))
|
||||
RCOBJECTS = $(RESOURCES:.rc=.o)
|
||||
|
||||
DEBUG_LVL ?= NONE
|
||||
|
||||
CLEANUPS ?=
|
||||
CLEANUPS += $(RCOBJECTS)
|
||||
CLEANUPS += $(COBJECTS)
|
||||
CLEANUPS += $(OBJECTS)
|
||||
CLEANUPS += $(LIBSASS_LIB)
|
||||
|
||||
all: $(BUILD)
|
||||
|
||||
debug: $(BUILD)
|
||||
|
||||
debug-static: LDFLAGS := -g $(filter-out -O2,$(LDFLAGS))
|
||||
debug-static: CFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CFLAGS))
|
||||
debug-static: CXXFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CXXFLAGS))
|
||||
debug-static: static
|
||||
|
||||
debug-shared: LDFLAGS := -g $(filter-out -O2,$(LDFLAGS))
|
||||
debug-shared: CFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CFLAGS))
|
||||
debug-shared: CXXFLAGS := -g -DDEBUG -DDEBUG_LVL="$(DEBUG_LVL)" $(filter-out -O2,$(CXXFLAGS))
|
||||
debug-shared: shared
|
||||
|
||||
lib:
|
||||
$(MKDIR) lib
|
||||
|
||||
lib/libsass.a: lib $(COBJECTS) $(OBJECTS)
|
||||
$(AR) rcvs $@ $(COBJECTS) $(OBJECTS)
|
||||
|
||||
lib/libsass.so: lib $(COBJECTS) $(OBJECTS)
|
||||
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(LDLIBS)
|
||||
|
||||
lib/libsass.dll: lib $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
|
||||
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -Wl,--subsystem,windows,--out-implib,lib/libsass.a
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
%.o: %.rc
|
||||
$(WINDRES) -i $< -o $@
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
%: %.o static
|
||||
$(CXX) $(CXXFLAGS) -o $@ $+ $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
install: install-$(BUILD)
|
||||
|
||||
static: $(STATICLIB)
|
||||
shared: $(SHAREDLIB)
|
||||
|
||||
$(DESTDIR)$(PREFIX):
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)
|
||||
|
||||
$(DESTDIR)$(PREFIX)/lib: $(DESTDIR)$(PREFIX)
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/lib
|
||||
|
||||
$(DESTDIR)$(PREFIX)/include: $(DESTDIR)$(PREFIX)
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include
|
||||
|
||||
$(DESTDIR)$(PREFIX)/include/sass: $(DESTDIR)$(PREFIX)/include
|
||||
$(MKDIR) $(DESTDIR)$(PREFIX)/include/sass
|
||||
|
||||
$(DESTDIR)$(PREFIX)/include/%.h: include/%.h \
|
||||
$(DESTDIR)$(PREFIX)/include \
|
||||
$(DESTDIR)$(PREFIX)/include/sass
|
||||
$(INSTALL) -v -m0644 "$<" "$@"
|
||||
|
||||
install-headers: $(DESTDIR)$(PREFIX)/include/sass.h \
|
||||
$(DESTDIR)$(PREFIX)/include/sass2scss.h \
|
||||
$(DESTDIR)$(PREFIX)/include/sass/base.h \
|
||||
$(DESTDIR)$(PREFIX)/include/sass/version.h \
|
||||
$(DESTDIR)$(PREFIX)/include/sass/values.h \
|
||||
$(DESTDIR)$(PREFIX)/include/sass/context.h \
|
||||
$(DESTDIR)$(PREFIX)/include/sass/functions.h
|
||||
|
||||
$(DESTDIR)$(PREFIX)/lib/%.a: lib/%.a \
|
||||
$(DESTDIR)$(PREFIX)/lib
|
||||
@$(INSTALL) -v -m0755 "$<" "$@"
|
||||
|
||||
$(DESTDIR)$(PREFIX)/lib/%.so: lib/%.so \
|
||||
$(DESTDIR)$(PREFIX)/lib
|
||||
@$(INSTALL) -v -m0755 "$<" "$@"
|
||||
|
||||
$(DESTDIR)$(PREFIX)/lib/%.dll: lib/%.dll \
|
||||
$(DESTDIR)$(PREFIX)/lib
|
||||
@$(INSTALL) -v -m0755 "$<" "$@"
|
||||
|
||||
install-static: $(DESTDIR)$(PREFIX)/lib/libsass.a
|
||||
|
||||
install-shared: $(DESTDIR)$(PREFIX)/lib/libsass.so \
|
||||
install-headers
|
||||
|
||||
$(SASSC_BIN): $(BUILD)
|
||||
$(MAKE) -C $(SASS_SASSC_PATH)
|
||||
|
||||
sassc: $(SASSC_BIN)
|
||||
$(SASSC_BIN) -v
|
||||
|
||||
version: $(SASSC_BIN)
|
||||
$(SASSC_BIN) -h
|
||||
$(SASSC_BIN) -v
|
||||
|
||||
test: $(SASSC_BIN)
|
||||
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
|
||||
|
||||
test_build: $(SASSC_BIN)
|
||||
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
|
||||
|
||||
test_full: $(SASSC_BIN)
|
||||
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --run-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
|
||||
|
||||
test_probe: $(SASSC_BIN)
|
||||
$(RUBY_BIN) $(SASS_SPEC_PATH)/sass-spec.rb -V 3.4 -c $(SASSC_BIN) --impl libsass --probe-todo $(LOG_FLAGS) $(SASS_SPEC_PATH)/$(SASS_SPEC_SPEC_DIR)
|
||||
|
||||
clean-objects: lib
|
||||
-$(RM) lib/*.a lib/*.so lib/*.dll lib/*.la
|
||||
-$(RMDIR) lib
|
||||
clean: clean-objects
|
||||
$(RM) $(CLEANUPS)
|
||||
|
||||
clean-all:
|
||||
$(MAKE) -C $(SASS_SASSC_PATH) clean
|
||||
|
||||
lib-file: lib-file-$(BUILD)
|
||||
lib-opts: lib-opts-$(BUILD)
|
||||
|
||||
lib-file-static:
|
||||
@echo $(LIB_STATIC)
|
||||
lib-file-shared:
|
||||
@echo $(LIB_SHARED)
|
||||
lib-opts-static:
|
||||
@echo -L"$(SASS_LIBSASS_PATH)/lib"
|
||||
lib-opts-shared:
|
||||
@echo -L"$(SASS_LIBSASS_PATH)/lib -lsass"
|
||||
|
||||
.PHONY: all static shared sassc \
|
||||
version install-headers \
|
||||
clean clean-all clean-objects \
|
||||
debug debug-static debug-shared \
|
||||
install install-static install-shared \
|
||||
lib-opts lib-opts-shared lib-opts-static \
|
||||
lib-file lib-file-shared lib-file-static
|
||||
.DELETE_ON_ERROR:
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
# this is merely a common Makefile multiple implementers can use
|
||||
|
||||
SOURCES = \
|
||||
ast.cpp \
|
||||
base64vlq.cpp \
|
||||
bind.cpp \
|
||||
color_maps.cpp \
|
||||
constants.cpp \
|
||||
context.cpp \
|
||||
cssize.cpp \
|
||||
emitter.cpp \
|
||||
environment.cpp \
|
||||
error_handling.cpp \
|
||||
eval.cpp \
|
||||
expand.cpp \
|
||||
extend.cpp \
|
||||
file.cpp \
|
||||
functions.cpp \
|
||||
inspect.cpp \
|
||||
json.cpp \
|
||||
lexer.cpp \
|
||||
listize.cpp \
|
||||
memory_manager.cpp \
|
||||
node.cpp \
|
||||
output.cpp \
|
||||
parser.cpp \
|
||||
plugins.cpp \
|
||||
position.cpp \
|
||||
prelexer.cpp \
|
||||
remove_placeholders.cpp \
|
||||
sass.cpp \
|
||||
sass_util.cpp \
|
||||
sass_values.cpp \
|
||||
sass_context.cpp \
|
||||
sass_functions.cpp \
|
||||
sass2scss.cpp \
|
||||
source_map.cpp \
|
||||
to_c.cpp \
|
||||
to_value.cpp \
|
||||
units.cpp \
|
||||
utf8_string.cpp \
|
||||
values.cpp \
|
||||
util.cpp
|
||||
|
||||
CSOURCES = cencode.c
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
LibSass
|
||||
=======
|
||||
|
||||
by Aaron Leung ([@akhleung]), Hampton Catlin ([@hcatlin]), Marcel Greter ([@mgreter]) and Michael Mifsud ([@xzyfer])
|
||||
|
||||
[](https://travis-ci.org/sass/libsass)
|
||||
[](https://ci.appveyor.com/project/sass/libsass/branch/master)
|
||||
[](https://www.bountysource.com/trackers/283068-libsass?utm_source=283068&utm_medium=shield&utm_campaign=TRACKER_BADGE)
|
||||
[](https://coveralls.io/r/sass/libsass?branch=feature%2Ftest-travis-ci-3)
|
||||
[](https://libsass-slack.herokuapp.com/)
|
||||
|
||||
https://github.com/sass/libsass
|
||||
|
||||
LibSass is just a library, but if you want to RUN LibSass,
|
||||
then go to https://github.com/sass/sassc or
|
||||
https://github.com/sass/sassc-ruby or
|
||||
[find your local implementer](docs/implementations.md).
|
||||
|
||||
LibSass requires GCC 4.6+ or Clang/LLVM. If your OS is older, this version may not compile.
|
||||
|
||||
On Windows, you need MinGW with GCC 4.6+ or VS 2013 Update 4+. It is also possible to build LibSass with Clang/LLVM on Windows.
|
||||
|
||||
About
|
||||
-----
|
||||
|
||||
LibSass is a C/C++ port of the Sass CSS precompiler. The original version was written in Ruby, but this version is meant for efficiency and portability.
|
||||
|
||||
This library strives to be light, simple, and easy to build and integrate with a variety of platforms and languages.
|
||||
|
||||
Developing
|
||||
----------
|
||||
|
||||
As you may have noticed, the LibSass repo itself has
|
||||
no executables and no tests. Oh noes! How can you develop???
|
||||
|
||||
Well, luckily, [SassC](http://github.com/sass/sassc) is the official binary wrapper for
|
||||
LibSass and is *always* kept in sync. SassC uses a git submodule
|
||||
to include LibSass. When developing LibSass, its best to actually
|
||||
check out SassC and develop in that directory with the SassC spec
|
||||
and tests there.
|
||||
|
||||
We even run Travis tests for SassC!
|
||||
|
||||
Tests
|
||||
-------
|
||||
|
||||
Since LibSass is a pure library, tests are run through the [SassSpec](https://github.com/sass/sass-spec) project using the [SassC](http://github.com/sass/sassc) driver.
|
||||
|
||||
To run tests against LibSass while developing, you can run `./script/spec`. This will clone SassC and Sass-Spec under the project folder and then run the Sass-Spec test suite. You may want to update the clones to ensure you have the latest version.
|
||||
|
||||
Library Usage
|
||||
-------------
|
||||
|
||||
While LibSass is a library primarily written in C++, it provides a simple
|
||||
C interface which should be used by most implementers. LibSass does not do
|
||||
much on its own without an implementer. This can be a command line tool, like
|
||||
[sassc](https://github.com/sass/sassc) or a [binding](docs/implementations.md)
|
||||
to your favorite programing language.
|
||||
|
||||
If you want to build or interface with LibSass, we recommend to check out the
|
||||
documentation pages about [building LibSass](docs/build.md) and
|
||||
the [C-API documentation](docs/api-doc.md).
|
||||
|
||||
About Sass
|
||||
----------
|
||||
|
||||
Sass is a CSS pre-processor language to add on exciting, new,
|
||||
awesome features to CSS. Sass was the first language of its kind
|
||||
and by far the most mature and up to date codebase.
|
||||
|
||||
Sass was originally concieved of by the co-creator of this library,
|
||||
Hampton Catlin ([@hcatlin]). Most of the language has been the result of years
|
||||
of work by Natalie Weizenbaum ([@nex3]) and Chris Eppstein ([@chriseppstein]).
|
||||
|
||||
For more information about Sass itself, please visit http://sass-lang.com
|
||||
|
||||
Initial development of libsass by Aaron Leung and Hampton Catlin was supported by [Moovweb](http://www.moovweb.com).
|
||||
|
||||
Licensing
|
||||
---------
|
||||
|
||||
Our MIT license is designed to be as simple, and liberal as possible.
|
||||
|
||||
[@hcatlin]: https://github.com/hcatlin
|
||||
[@akhleung]: https://github.com/akhleung
|
||||
[@chriseppstein]: https://github.com/chriseppstein
|
||||
[@nex3]: https://github.com/nex3
|
||||
[@mgreter]: https://github.com/mgreter
|
||||
[@xzyfer]: https://github.com/xzyfer
|
||||
|
||||
sass2scss was originally written by [Marcel Greter](@mgreter)
|
||||
and he happily agreed to have it merged into the project.
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
Serious about security
|
||||
======================
|
||||
|
||||
The LibSass team recognizes the important contributions the security research
|
||||
community can make. We therefore encourage reporting security issues with the
|
||||
code contained in this repository.
|
||||
|
||||
If you believe you have discovered a security vulnerability, please report it at
|
||||
https://hackerone.com/libsass instead of GitHub.
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
os: Visual Studio 2013
|
||||
|
||||
environment:
|
||||
CTEST_OUTPUT_ON_FAILURE: 1
|
||||
ruby_version: 22-x64
|
||||
TargetPath: sassc/bin/sassc
|
||||
matrix:
|
||||
- Compiler: msvc
|
||||
Config: Release
|
||||
- Compiler: msvc
|
||||
Config: Debug
|
||||
- Compiler: mingw
|
||||
Build: static
|
||||
- Compiler: mingw
|
||||
Build: shared
|
||||
|
||||
cache:
|
||||
- C:\Ruby%ruby_version%\lib\ruby\gems
|
||||
- C:\mingw64
|
||||
|
||||
install:
|
||||
- git clone https://github.com/sass/sassc.git
|
||||
- git clone https://github.com/sass/sass-spec.git
|
||||
- set PATH=C:\Ruby%ruby_version%\bin;%PATH%
|
||||
- ps: |
|
||||
if(!(gem which minitest 2>$nul)) { gem install minitest --no-ri --no-rdoc }
|
||||
if ($env:Compiler -eq "mingw" -AND -Not (Test-Path "C:\mingw64")) {
|
||||
# Install MinGW.
|
||||
$file = "x86_64-4.9.2-release-win32-seh-rt_v4-rev3.7z"
|
||||
wget https://bintray.com/artifact/download/drewwells/generic/$file -OutFile $file
|
||||
&7z x -oC:\ $file > $null
|
||||
}
|
||||
- set PATH=C:\mingw64\bin;%PATH%
|
||||
- set CC=gcc
|
||||
|
||||
build_script:
|
||||
- ps: |
|
||||
if ($env:Compiler -eq "mingw") {
|
||||
mingw32-make -j4 sassc
|
||||
} else {
|
||||
msbuild /m:4 /p:Configuration=$env:Config sassc\win\sassc.sln
|
||||
}
|
||||
|
||||
# print the branding art
|
||||
mv script/branding script/branding.ps1
|
||||
script/branding.ps1
|
||||
|
||||
# print the version info
|
||||
&$env:TargetPath -v
|
||||
ruby -v
|
||||
|
||||
test_script:
|
||||
- ps: |
|
||||
$PRNR = $env:APPVEYOR_PULL_REQUEST_NUMBER
|
||||
if ($PRNR) {
|
||||
echo "Fetching info for PR $PRNR"
|
||||
wget https://api.github.com/repos/sass/libsass/pulls/$PRNR -OutFile pr.json
|
||||
$json = cat pr.json -Raw
|
||||
$SPEC_PR = [regex]::match($json,'sass\/sass-spec(#|\/pull\/)([0-9]+)').Groups[2].Value
|
||||
if ($SPEC_PR) {
|
||||
echo "Checkout sass spec PR $SPEC_PR"
|
||||
git -C sass-spec fetch -q -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
|
||||
git -C sass-spec checkout -q --force ci-spec-pr-$SPEC_PR
|
||||
}
|
||||
}
|
||||
ruby sass-spec/sass-spec.rb -V 3.4 --probe-todo --impl libsass -c $env:TargetPath -s sass-spec/spec
|
||||
if(-not($?)) {
|
||||
echo "sass-spec tests failed"
|
||||
exit 1
|
||||
}
|
||||
Write-Host "Explicitly testing the case when cwd has Cyrillic characters: " -nonewline
|
||||
# See comments in gh-1774 for details.
|
||||
$env:TargetPath = Join-Path $pwd.Path $env:TargetPath
|
||||
cd sass-spec/spec/libsass/Sáss-UŢF8/
|
||||
&$env:TargetPath ./input.scss 2>&1>$null
|
||||
if(-not($?)) {
|
||||
echo "Failed!"
|
||||
exit 1
|
||||
} else {
|
||||
echo "Success!"
|
||||
}
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
# -*- Autoconf -*-
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.61])
|
||||
|
||||
AC_INIT([libsass], m4_esyscmd_s([./version.sh]), [support@moovweb.com])
|
||||
AC_CONFIG_SRCDIR([src/ast.hpp])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([src/config.h])
|
||||
AC_CONFIG_FILES([include/sass/version.h])
|
||||
AC_CONFIG_AUX_DIR([script])
|
||||
# These are flags passed to automake
|
||||
# Though they look like gcc flags!
|
||||
AM_INIT_AUTOMAKE([foreign parallel-tests -Wall])
|
||||
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])])
|
||||
# would fail with mingw otherwise
|
||||
# m4_pattern_allow([AM_PROG_AR])
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_LANG_PUSH([C])
|
||||
AC_LANG_PUSH([C++])
|
||||
AC_GNU_SOURCE
|
||||
# Check fails on Travis, but it works fine
|
||||
# AX_CXX_COMPILE_STDCXX_11([ext],[optional])
|
||||
AC_CHECK_TOOL([AR], [ar], [false])
|
||||
if test "x$is_mingw32" != "xyes"; then
|
||||
AC_CHECK_TOOL([DLLTOOL], [dlltool], [false])
|
||||
AC_CHECK_TOOL([DLLWRAP], [dllwrap], [false])
|
||||
AC_CHECK_TOOL([WINDRES], [windres], [false])
|
||||
fi
|
||||
LT_INIT([dlopen])
|
||||
|
||||
# Checks for header files.
|
||||
AC_CHECK_HEADERS([unistd.h])
|
||||
|
||||
# Checks for typedefs, structures, and compiler characteristics.
|
||||
AC_TYPE_SIZE_T
|
||||
|
||||
# Checks for library functions.
|
||||
AC_FUNC_MALLOC
|
||||
AC_CHECK_FUNCS([floor getcwd strtol])
|
||||
|
||||
# Checks for testing.
|
||||
AC_ARG_ENABLE(tests, AS_HELP_STRING([--enable-tests], [enable testing the build]),
|
||||
[enable_tests="$enableval"], [enable_tests=no])
|
||||
|
||||
AS_CASE([$target], [*-*-mingw32], [is_mingw32=yes], [is_mingw32=no])
|
||||
AM_CONDITIONAL(COMPILER_IS_MINGW32, test "x$is_mingw32" = "xyes")
|
||||
|
||||
dnl The dlopen() function is in the C library for *BSD and in
|
||||
dnl libdl on GLIBC-based systems
|
||||
if test "x$is_mingw32" != "xyes"; then
|
||||
AC_SEARCH_LIBS([dlopen], [dl dld], [], [
|
||||
AC_MSG_ERROR([unable to find the dlopen() function])
|
||||
])
|
||||
fi
|
||||
|
||||
if test "x$enable_tests" = "xyes"; then
|
||||
AC_PROG_CC
|
||||
AC_PROG_AWK
|
||||
# test need minitest gem
|
||||
AC_PATH_PROG(RUBY, [ruby])
|
||||
AC_PATH_PROG(TAPOUT, [tapout])
|
||||
AC_REQUIRE_AUX_FILE([tap-driver])
|
||||
AC_REQUIRE_AUX_FILE([tap-runner])
|
||||
AC_ARG_WITH(sassc-dir,
|
||||
AS_HELP_STRING([--with-sassc-dir=<dir>], [specify directory of sassc sources for testing (default: sassc)]),
|
||||
[sassc_dir="$withval"], [sassc_dir="sassc"])
|
||||
AC_CHECK_FILE([$sassc_dir/sassc.c], [], [
|
||||
AC_MSG_ERROR([Unable to find sassc directory.
|
||||
You must clone the sassc repository in this directory or specify
|
||||
the --with-sassc-dir=<dir> argument.
|
||||
])
|
||||
])
|
||||
SASS_SASSC_PATH=$sassc_dir
|
||||
AC_SUBST(SASS_SASSC_PATH)
|
||||
|
||||
AC_ARG_WITH(sass-spec-dir,
|
||||
AS_HELP_STRING([--with-sass-spec-dir=<dir>], [specify directory of sass-spec for testing (default: sass-spec)]),
|
||||
[sass_spec_dir="$withval"], [sass_spec_dir="sass-spec"])
|
||||
AC_CHECK_FILE([$sass_spec_dir/sass-spec.rb], [], [
|
||||
AC_MSG_ERROR([Unable to find sass-spec directory.
|
||||
You must clone the sass-spec repository in this directory or specify
|
||||
the --with-sass-spec-dir=<dir> argument.
|
||||
])
|
||||
])
|
||||
# Automake doesn't like its tests in an absolute path, so we make it relative.
|
||||
case $sass_spec_dir in
|
||||
/*)
|
||||
SASS_SPEC_PATH=`$RUBY -e "require 'pathname'; puts Pathname.new('$sass_spec_dir').relative_path_from(Pathname.new('$PWD')).to_s"`
|
||||
;;
|
||||
*)
|
||||
SASS_SPEC_PATH="$sass_spec_dir"
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(SASS_SPEC_PATH)
|
||||
|
||||
# TODO: Remove this when automake requirements are 1.12+
|
||||
AC_MSG_CHECKING([whether we can use TAP mode])
|
||||
tmp=`$AWK '/TEST_LOG_DRIVER/' $srcdir/GNUmakefile.in`
|
||||
if test "x$tmp" != "x"; then
|
||||
use_tap=yes
|
||||
else
|
||||
use_tap=no
|
||||
fi
|
||||
AC_MSG_RESULT([$use_tap])
|
||||
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(ENABLE_TESTS, test "x$enable_tests" = "xyes")
|
||||
AM_CONDITIONAL(USE_TAP, test "x$use_tap" = "xyes")
|
||||
|
||||
AC_ARG_ENABLE([coverage],
|
||||
[AS_HELP_STRING([--enable-coverage],
|
||||
[enable coverage report for test suite])],
|
||||
[enable_cov=$enableval],
|
||||
[enable_cov=no])
|
||||
|
||||
if test "x$enable_cov" = "xyes"; then
|
||||
|
||||
AC_CHECK_PROG(GCOV, gcov, gcov)
|
||||
|
||||
# Remove all optimization flags from C[XX]FLAGS
|
||||
changequote({,})
|
||||
CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
|
||||
CXXFLAGS=`echo "$CXXFLAGS" | $SED -e 's/-O[0-9]*//g'`
|
||||
changequote([,])
|
||||
|
||||
AC_SUBST(GCOV)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(ENABLE_COVERAGE, test "x$enable_cov" = "xyes")
|
||||
|
||||
AC_SUBST(PACKAGE_VERSION)
|
||||
|
||||
AC_MSG_NOTICE([Building libsass ($VERSION)])
|
||||
|
||||
AC_CONFIG_FILES([GNUmakefile src/GNUmakefile src/support/libsass.pc])
|
||||
AC_OUTPUT
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
Name: libsass
|
||||
Version: %{version}
|
||||
Release: 1%{?dist}
|
||||
Summary: A C/C++ implementation of a Sass compiler
|
||||
|
||||
License: MIT
|
||||
URL: http://libsass.org
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
BuildRequires: gcc-c++ >= 4.7
|
||||
BuildRequires: autoconf
|
||||
BuildRequires: automake
|
||||
BuildRequires: libtool
|
||||
|
||||
|
||||
%description
|
||||
LibSass is a C/C++ port of the Sass engine. The point is to be simple, fast, and easy to integrate.
|
||||
|
||||
%package devel
|
||||
Summary: Development files for %{name}
|
||||
Requires: %{name}%{?_isa} = %{version}-%{release}
|
||||
|
||||
|
||||
%description devel
|
||||
The %{name}-devel package contains libraries and header files for
|
||||
developing applications that use %{name}.
|
||||
|
||||
|
||||
%prep
|
||||
%setup -q
|
||||
autoreconf --force --install
|
||||
|
||||
|
||||
%build
|
||||
%configure --disable-static \
|
||||
--disable-tests \
|
||||
--enable-shared
|
||||
|
||||
make %{?_smp_mflags}
|
||||
|
||||
|
||||
%install
|
||||
%make_install
|
||||
find $RPM_BUILD_ROOT -name '*.la' -exec rm -f {} ';'
|
||||
|
||||
|
||||
%post -p /sbin/ldconfig
|
||||
|
||||
%postun -p /sbin/ldconfig
|
||||
|
||||
|
||||
%files
|
||||
%doc Readme.md LICENSE
|
||||
%{_libdir}/*.so.*
|
||||
|
||||
%files devel
|
||||
%doc
|
||||
%{_includedir}/*
|
||||
%{_libdir}/*.so
|
||||
%{_libdir}/pkgconfig/*.pc
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Feb 10 2015 Gawain Lynch <gawain.lynch@gmail.com> - 3.1.0-1
|
||||
- Initial SPEC file
|
||||
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include <sass.h>
|
||||
|
||||
// gcc: g++ -shared plugin.cpp -o plugin.so -fPIC -Llib -lsass
|
||||
// mingw: g++ -shared plugin.cpp -o plugin.dll -Llib -lsass
|
||||
|
||||
extern "C" const char* ADDCALL libsass_get_version() {
|
||||
return libsass_version();
|
||||
}
|
||||
|
||||
union Sass_Value* custom_function(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp)
|
||||
{
|
||||
// get context/option struct associated with this compiler
|
||||
struct Sass_Context* ctx = sass_compiler_get_context(comp);
|
||||
struct Sass_Options* opts = sass_compiler_get_options(comp);
|
||||
// get the cookie from function descriptor
|
||||
void* cookie = sass_function_get_cookie(cb);
|
||||
// we actually abuse the void* to store an "int"
|
||||
return sass_make_number((intptr_t)cookie, "px");
|
||||
}
|
||||
|
||||
extern "C" Sass_Function_List ADDCALL libsass_load_functions()
|
||||
{
|
||||
// allocate a custom function caller
|
||||
Sass_Function_Entry c_func =
|
||||
sass_make_function("foo()", custom_function, (void*)42);
|
||||
// create list of all custom functions
|
||||
Sass_Function_List fn_list = sass_make_function_list(1);
|
||||
// put the only function in this plugin to the list
|
||||
sass_function_set_list_entry(fn_list, 0, c_func);
|
||||
// return the list
|
||||
return fn_list;
|
||||
}
|
||||
|
||||
Sass_Import_List custom_importer(const char* cur_path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
|
||||
{
|
||||
// get the cookie from importer descriptor
|
||||
void* cookie = sass_importer_get_cookie(cb);
|
||||
// create a list to hold our import entries
|
||||
Sass_Import_List incs = sass_make_import_list(1);
|
||||
// create our only import entry (route path back)
|
||||
incs[0] = sass_make_import_entry(cur_path, 0, 0);
|
||||
// return imports
|
||||
return incs;
|
||||
}
|
||||
|
||||
extern "C" Sass_Importer_List ADDCALL libsass_load_importers()
|
||||
{
|
||||
// allocate a custom function caller
|
||||
Sass_Importer_Entry c_imp =
|
||||
sass_make_importer(custom_importer, - 99, (void*)42);
|
||||
// create list of all custom functions
|
||||
Sass_Importer_List imp_list = sass_make_importer_list(1);
|
||||
// put the only function in this plugin to the list
|
||||
sass_importer_set_list_entry(imp_list, 0, c_imp);
|
||||
// return the list
|
||||
return imp_list;
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
Welcome to the LibSass documentation!
|
||||
|
||||
## First Off
|
||||
LibSass is just a library. To run the code locally (i.e. to compile your stylesheets), you need an implementer. SassC (get it?) is an implementer written in C. There are a number of other implementations of LibSass - for example Node. We encourage you to write your own port - the whole point of LibSass is that we want to bring Sass to many other languages, not just Ruby!
|
||||
|
||||
We're working hard on moving to full parity with Ruby Sass... learn more at the [The-LibSass-Compatibility-Plan](compatibility-plan.md)!
|
||||
|
||||
### Implementing LibSass
|
||||
|
||||
If you're interested in implementing LibSass in your own project see the [API Documentation](api-doc.md) which now includes implementing
|
||||
your own [Sass functions](api-function.md). You may wish to [look at other implementations](implementations.md) for your language of choice.
|
||||
Or make your own!
|
||||
|
||||
### Contributing to LibSass
|
||||
|
||||
| Issue Tracker | Issue Triage | Community Guidelines |
|
||||
|-------------------|----------------------------------|-----------------------------|
|
||||
| We're always needing help, so check out our issue tracker, help some people out, and read our article on [Contributing](contributing.md)! It's got all the details on what to do! | To help understand the process of triaging bugs, have a look at our [Issue-Triage](triage.md) document. | Oh, and don't forget we always follow [[Sass Community Guidelines|http://sass-lang.com/community-guidelines]]. Be nice and everyone else will be nice too! |
|
||||
|
||||
Please refer to the steps on [Building LibSass](build.md)
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
## Example main.c
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include "sass/context.h"
|
||||
|
||||
int main( int argc, const char* argv[] )
|
||||
{
|
||||
|
||||
// get the input file from first argument or use default
|
||||
const char* input = argc > 1 ? argv[1] : "styles.scss";
|
||||
|
||||
// create the file context and get all related structs
|
||||
struct Sass_File_Context* file_ctx = sass_make_file_context(input);
|
||||
struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
|
||||
struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
|
||||
|
||||
// configure some options ...
|
||||
sass_option_set_precision(ctx_opt, 10);
|
||||
|
||||
// context is set up, call the compile step now
|
||||
int status = sass_compile_file_context(file_ctx);
|
||||
|
||||
// print the result or the error to the stdout
|
||||
if (status == 0) puts(sass_context_get_output_string(ctx));
|
||||
else puts(sass_context_get_error_message(ctx));
|
||||
|
||||
// release allocated memory
|
||||
sass_delete_file_context(file_ctx);
|
||||
|
||||
// exit status
|
||||
return status;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Compile main.c
|
||||
|
||||
```bash
|
||||
gcc -c main.c -o main.o
|
||||
gcc -o sample main.o -lsass
|
||||
echo "foo { margin: 21px * 2; }" > foo.scss
|
||||
./sample foo.scss => "foo { margin: 42px }"
|
||||
```
|
||||
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
```C
|
||||
// Input behaviours
|
||||
enum Sass_Input_Style {
|
||||
SASS_CONTEXT_NULL,
|
||||
SASS_CONTEXT_FILE,
|
||||
SASS_CONTEXT_DATA,
|
||||
SASS_CONTEXT_FOLDER
|
||||
};
|
||||
|
||||
// simple linked list
|
||||
struct string_list {
|
||||
string_list* next;
|
||||
char* string;
|
||||
};
|
||||
|
||||
// sass config options structure
|
||||
struct Sass_Options {
|
||||
|
||||
// Precision for fractional numbers
|
||||
int precision;
|
||||
|
||||
// Output style for the generated css code
|
||||
// A value from above SASS_STYLE_* constants
|
||||
enum Sass_Output_Style output_style;
|
||||
|
||||
// Emit comments in the generated CSS indicating
|
||||
// the corresponding source line.
|
||||
bool source_comments;
|
||||
|
||||
// embed sourceMappingUrl as data uri
|
||||
bool source_map_embed;
|
||||
|
||||
// embed include contents in maps
|
||||
bool source_map_contents;
|
||||
|
||||
// Disable sourceMappingUrl in css output
|
||||
bool omit_source_map_url;
|
||||
|
||||
// Treat source_string as sass (as opposed to scss)
|
||||
bool is_indented_syntax_src;
|
||||
|
||||
// The input path is used for source map
|
||||
// generation. It can be used to define
|
||||
// something with string compilation or to
|
||||
// overload the input file path. It is
|
||||
// set to "stdin" for data contexts and
|
||||
// to the input file on file contexts.
|
||||
char* input_path;
|
||||
|
||||
// The output path is used for source map
|
||||
// generation. LibSass will not write to
|
||||
// this file, it is just used to create
|
||||
// information in source-maps etc.
|
||||
char* output_path;
|
||||
|
||||
// String to be used for indentation
|
||||
const char* indent;
|
||||
// String to be used to for line feeds
|
||||
const char* linefeed;
|
||||
|
||||
// Colon-separated list of paths
|
||||
// Semicolon-separated on Windows
|
||||
// Note: It may be better to use
|
||||
// array interface instead
|
||||
char* include_path;
|
||||
char* plugin_path;
|
||||
|
||||
// Include paths (linked string list)
|
||||
struct string_list* include_paths;
|
||||
// Plugin paths (linked string list)
|
||||
struct string_list* plugin_paths;
|
||||
|
||||
// Path to source map file
|
||||
// Enables source map generation
|
||||
// Used to create sourceMappingUrl
|
||||
char* source_map_file;
|
||||
|
||||
// Directly inserted in source maps
|
||||
char* source_map_root;
|
||||
|
||||
// Custom functions that can be called from sccs code
|
||||
Sass_C_Function_List c_functions;
|
||||
|
||||
// Callback to overload imports
|
||||
Sass_C_Import_Callback importer;
|
||||
|
||||
};
|
||||
|
||||
// base for all contexts
|
||||
struct Sass_Context : Sass_Options
|
||||
{
|
||||
|
||||
// store context type info
|
||||
enum Sass_Input_Style type;
|
||||
|
||||
// generated output data
|
||||
char* output_string;
|
||||
|
||||
// generated source map json
|
||||
char* source_map_string;
|
||||
|
||||
// error status
|
||||
int error_status;
|
||||
char* error_json;
|
||||
char* error_text;
|
||||
char* error_message;
|
||||
// error position
|
||||
char* error_file;
|
||||
size_t error_line;
|
||||
size_t error_column;
|
||||
|
||||
// report imported files
|
||||
char** included_files;
|
||||
|
||||
};
|
||||
|
||||
// struct for file compilation
|
||||
struct Sass_File_Context : Sass_Context {
|
||||
|
||||
// no additional fields required
|
||||
// input_path is already on options
|
||||
|
||||
};
|
||||
|
||||
// struct for data compilation
|
||||
struct Sass_Data_Context : Sass_Context {
|
||||
|
||||
// provided source string
|
||||
char* source_string;
|
||||
|
||||
};
|
||||
|
||||
// Compiler states
|
||||
enum Sass_Compiler_State {
|
||||
SASS_COMPILER_CREATED,
|
||||
SASS_COMPILER_PARSED,
|
||||
SASS_COMPILER_EXECUTED
|
||||
};
|
||||
|
||||
// link c and cpp context
|
||||
struct Sass_Compiler {
|
||||
// progress status
|
||||
Sass_Compiler_State state;
|
||||
// original c context
|
||||
Sass_Context* c_ctx;
|
||||
// Sass::Context
|
||||
void* cpp_ctx;
|
||||
// Sass::Block
|
||||
void* root;
|
||||
};
|
||||
```
|
||||
|
||||
+268
@@ -0,0 +1,268 @@
|
||||
Sass Contexts come in two flavors:
|
||||
|
||||
- `Sass_File_Context`
|
||||
- `Sass_Data_Context`
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```C
|
||||
#include "sass/context.h"
|
||||
```
|
||||
|
||||
***Sass_Options***
|
||||
|
||||
```C
|
||||
// Precision for fractional numbers
|
||||
int precision;
|
||||
```
|
||||
```C
|
||||
// Output style for the generated css code
|
||||
// A value from above SASS_STYLE_* constants
|
||||
int output_style;
|
||||
```
|
||||
```C
|
||||
// Emit comments in the generated CSS indicating
|
||||
// the corresponding source line.
|
||||
bool source_comments;
|
||||
```
|
||||
```C
|
||||
// embed sourceMappingUrl as data uri
|
||||
bool source_map_embed;
|
||||
```
|
||||
```C
|
||||
// embed include contents in maps
|
||||
bool source_map_contents;
|
||||
```
|
||||
```C
|
||||
// Disable sourceMappingUrl in css output
|
||||
bool omit_source_map_url;
|
||||
```
|
||||
```C
|
||||
// Treat source_string as sass (as opposed to scss)
|
||||
bool is_indented_syntax_src;
|
||||
```
|
||||
```C
|
||||
// The input path is used for source map
|
||||
// generating. It can be used to define
|
||||
// something with string compilation or to
|
||||
// overload the input file path. It is
|
||||
// set to "stdin" for data contexts and
|
||||
// to the input file on file contexts.
|
||||
char* input_path;
|
||||
```
|
||||
```C
|
||||
// The output path is used for source map
|
||||
// generating. LibSass will not write to
|
||||
// this file, it is just used to create
|
||||
// information in source-maps etc.
|
||||
char* output_path;
|
||||
```
|
||||
```C
|
||||
// String to be used for indentation
|
||||
const char* indent;
|
||||
```
|
||||
```C
|
||||
// String to be used to for line feeds
|
||||
const char* linefeed;
|
||||
```
|
||||
```C
|
||||
// Colon-separated list of paths
|
||||
// Semicolon-separated on Windows
|
||||
char* include_path;
|
||||
char* plugin_path;
|
||||
```
|
||||
```C
|
||||
// Additional include paths
|
||||
// Must be null delimited
|
||||
char** include_paths;
|
||||
char** plugin_paths;
|
||||
```
|
||||
```C
|
||||
// Path to source map file
|
||||
// Enables the source map generating
|
||||
// Used to create sourceMappingUrl
|
||||
char* source_map_file;
|
||||
```
|
||||
```C
|
||||
// Directly inserted in source maps
|
||||
char* source_map_root;
|
||||
```
|
||||
```C
|
||||
// Custom functions that can be called from Sass code
|
||||
Sass_C_Function_List c_functions;
|
||||
```
|
||||
```C
|
||||
// Callback to overload imports
|
||||
Sass_C_Import_Callback importer;
|
||||
```
|
||||
|
||||
***Sass_Context***
|
||||
|
||||
```C
|
||||
// store context type info
|
||||
enum Sass_Input_Style type;
|
||||
````
|
||||
```C
|
||||
// generated output data
|
||||
char* output_string;
|
||||
```
|
||||
```C
|
||||
// generated source map json
|
||||
char* source_map_string;
|
||||
```
|
||||
```C
|
||||
// error status
|
||||
int error_status;
|
||||
char* error_json;
|
||||
char* error_text;
|
||||
char* error_message;
|
||||
// error position
|
||||
char* error_file;
|
||||
size_t error_line;
|
||||
size_t error_column;
|
||||
```
|
||||
```C
|
||||
// report imported files
|
||||
char** included_files;
|
||||
```
|
||||
|
||||
***Sass_File_Context***
|
||||
|
||||
```C
|
||||
// no additional fields required
|
||||
// input_path is already on options
|
||||
```
|
||||
|
||||
***Sass_Data_Context***
|
||||
|
||||
```C
|
||||
// provided source string
|
||||
char* source_string;
|
||||
```
|
||||
|
||||
### Sass Context API
|
||||
|
||||
```C
|
||||
// Forward declaration
|
||||
struct Sass_Compiler;
|
||||
|
||||
// Forward declaration
|
||||
struct Sass_Options;
|
||||
struct Sass_Context; // : Sass_Options
|
||||
struct Sass_File_Context; // : Sass_Context
|
||||
struct Sass_Data_Context; // : Sass_Context
|
||||
|
||||
// Create and initialize an option struct
|
||||
struct Sass_Options* sass_make_options (void);
|
||||
// Create and initialize a specific context
|
||||
struct Sass_File_Context* sass_make_file_context (const char* input_path);
|
||||
struct Sass_Data_Context* sass_make_data_context (char* source_string);
|
||||
|
||||
// Call the compilation step for the specific context
|
||||
int sass_compile_file_context (struct Sass_File_Context* ctx);
|
||||
int sass_compile_data_context (struct Sass_Data_Context* ctx);
|
||||
|
||||
// Create a sass compiler instance for more control
|
||||
struct Sass_Compiler* sass_make_file_compiler (struct Sass_File_Context* file_ctx);
|
||||
struct Sass_Compiler* sass_make_data_compiler (struct Sass_Data_Context* data_ctx);
|
||||
|
||||
// Execute the different compilation steps individually
|
||||
// Usefull if you only want to query the included files
|
||||
int sass_compiler_parse (struct Sass_Compiler* compiler);
|
||||
int sass_compiler_execute (struct Sass_Compiler* compiler);
|
||||
|
||||
// Release all memory allocated with the compiler
|
||||
// This does _not_ include any contexts or options
|
||||
void sass_delete_compiler (struct Sass_Compiler* compiler);
|
||||
|
||||
// Release all memory allocated and also ourself
|
||||
void sass_delete_file_context (struct Sass_File_Context* ctx);
|
||||
void sass_delete_data_context (struct Sass_Data_Context* ctx);
|
||||
|
||||
// Getters for Context from specific implementation
|
||||
struct Sass_Context* sass_file_context_get_context (struct Sass_File_Context* file_ctx);
|
||||
struct Sass_Context* sass_data_context_get_context (struct Sass_Data_Context* data_ctx);
|
||||
|
||||
// Getters for Context_Options from Sass_Context
|
||||
struct Sass_Options* sass_context_get_options (struct Sass_Context* ctx);
|
||||
struct Sass_Options* sass_file_context_get_options (struct Sass_File_Context* file_ctx);
|
||||
struct Sass_Options* sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
|
||||
void sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
|
||||
void sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);
|
||||
|
||||
// Getters for Sass_Context values
|
||||
const char* sass_context_get_output_string (struct Sass_Context* ctx);
|
||||
int sass_context_get_error_status (struct Sass_Context* ctx);
|
||||
const char* sass_context_get_error_json (struct Sass_Context* ctx);
|
||||
const char* sass_context_get_error_text (struct Sass_Context* ctx);
|
||||
const char* sass_context_get_error_message (struct Sass_Context* ctx);
|
||||
const char* sass_context_get_error_file (struct Sass_Context* ctx);
|
||||
size_t sass_context_get_error_line (struct Sass_Context* ctx);
|
||||
size_t sass_context_get_error_column (struct Sass_Context* ctx);
|
||||
const char* sass_context_get_source_map_string (struct Sass_Context* ctx);
|
||||
char** sass_context_get_included_files (struct Sass_Context* ctx);
|
||||
|
||||
// Take ownership of memory (value on context is set to 0)
|
||||
char* sass_context_take_error_json (struct Sass_Context* ctx);
|
||||
char* sass_context_take_error_text (struct Sass_Context* ctx);
|
||||
char* sass_context_take_error_message (struct Sass_Context* ctx);
|
||||
char* sass_context_take_error_file (struct Sass_Context* ctx);
|
||||
char* sass_context_take_output_string (struct Sass_Context* ctx);
|
||||
char* sass_context_take_source_map_string (struct Sass_Context* ctx);
|
||||
|
||||
// Push function for plugin/include paths (no manipulation support for now)
|
||||
void sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
|
||||
void sass_option_push_include_path (struct Sass_Options* options, const char* path);
|
||||
```
|
||||
|
||||
### Sass Options API
|
||||
|
||||
```C
|
||||
// Getters for Context_Option values
|
||||
int sass_option_get_precision (struct Sass_Options* options);
|
||||
enum Sass_Output_Style sass_option_get_output_style (struct Sass_Options* options);
|
||||
bool sass_option_get_source_comments (struct Sass_Options* options);
|
||||
bool sass_option_get_source_map_embed (struct Sass_Options* options);
|
||||
bool sass_option_get_source_map_contents (struct Sass_Options* options);
|
||||
bool sass_option_get_omit_source_map_url (struct Sass_Options* options);
|
||||
bool sass_option_get_is_indented_syntax_src (struct Sass_Options* options);
|
||||
const char* sass_option_get_indent (struct Sass_Options* options);
|
||||
const char* sass_option_get_linefeed (struct Sass_Options* options);
|
||||
const char* sass_option_get_input_path (struct Sass_Options* options);
|
||||
const char* sass_option_get_output_path (struct Sass_Options* options);
|
||||
const char* sass_option_get_plugin_path (struct Sass_Options* options);
|
||||
const char* sass_option_get_include_path (struct Sass_Options* options);
|
||||
const char* sass_option_get_source_map_file (struct Sass_Options* options);
|
||||
const char* sass_option_get_source_map_root (struct Sass_Options* options);
|
||||
Sass_C_Function_List sass_option_get_c_functions (struct Sass_Options* options);
|
||||
Sass_C_Import_Callback sass_option_get_importer (struct Sass_Options* options);
|
||||
|
||||
// Setters for Context_Option values
|
||||
void sass_option_set_precision (struct Sass_Options* options, int precision);
|
||||
void sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
|
||||
void sass_option_set_source_comments (struct Sass_Options* options, bool source_comments);
|
||||
void sass_option_set_source_map_embed (struct Sass_Options* options, bool source_map_embed);
|
||||
void sass_option_set_source_map_contents (struct Sass_Options* options, bool source_map_contents);
|
||||
void sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url);
|
||||
void sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src);
|
||||
void sass_option_set_indent (struct Sass_Options* options, const char* indent);
|
||||
void sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed);
|
||||
void sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
|
||||
void sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
|
||||
void sass_option_set_plugin_path (struct Sass_Options* options, const char* plugin_path);
|
||||
void sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
|
||||
void sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
|
||||
void sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
|
||||
void sass_option_set_c_functions (struct Sass_Options* options, Sass_C_Function_List c_functions);
|
||||
void sass_option_set_importer (struct Sass_Options* options, Sass_C_Import_Callback importer);
|
||||
|
||||
// Push function for paths (no manipulation support for now)
|
||||
void sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
|
||||
void sass_option_push_include_path (struct Sass_Options* options, const char* path);
|
||||
```
|
||||
|
||||
### More links
|
||||
|
||||
- [Sass Context Example](api-context-example.md)
|
||||
- [Sass Context Internal](api-context-internal.md)
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
## Introduction
|
||||
|
||||
LibSass wouldn't be much good without a way to interface with it. These interface documentations describe the various functions and data structures available to implementers. They are split up over three major components, which have all their own source files (plus some common functionality).
|
||||
|
||||
- [Sass Context](api-context.md) - Trigger and handle the main Sass compilation
|
||||
- [Sass Value](api-value.md) - Exchange values and its format with LibSass
|
||||
- [Sass Function](api-function.md) - Get invoked by LibSass for function statments
|
||||
- [Sass Importer](api-importer.md) - Get invoked by LibSass for @import statments
|
||||
|
||||
### Basic usage
|
||||
|
||||
First you will need to include the header file!
|
||||
This will automatically load all other headers too!
|
||||
|
||||
```C
|
||||
#include "sass/context.h"
|
||||
```
|
||||
|
||||
## Basic C Example
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include "sass/context.h"
|
||||
|
||||
int main() {
|
||||
puts(libsass_version());
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
```bash
|
||||
gcc -Wall version.c -lsass -o version && ./version
|
||||
```
|
||||
|
||||
## More C Examples
|
||||
|
||||
- [Sample code for Sass Context](api-context-example.md)
|
||||
- [Sample code for Sass Value](api-value-example.md)
|
||||
- [Sample code for Sass Function](api-function-example.md)
|
||||
- [Sample code for Sass Importer](api-importer-example.md)
|
||||
|
||||
## Compiling your code
|
||||
|
||||
The most important is your sass file (or string of sass code). With this, you will want to start a LibSass compiler. Here is some pseudocode describing the process. The compiler has two different modes: direct input as a string with `Sass_Data_Context` or LibSass will do file reading for you by using `Sass_File_Context`. See the code for a list of options available [Sass_Options](https://github.com/sass/libsass/blob/36feef0/include/sass/interface.h#L18)
|
||||
|
||||
**Building a file compiler**
|
||||
|
||||
context = sass_make_file_context("file.scss")
|
||||
options = sass_file_context_get_options(context)
|
||||
sass_option_set_precision(options, 1)
|
||||
sass_option_set_source_comments(options, true)
|
||||
|
||||
sass_file_context_set_options(context, options)
|
||||
|
||||
compiler = sass_make_file_compiler(sass_context)
|
||||
sass_compiler_parse(compiler)
|
||||
sass_compiler_execute(compiler)
|
||||
|
||||
output = sass_context_get_output_string(context)
|
||||
// Retrieve errors during compilation
|
||||
error_status = sass_context_get_error_status(context)
|
||||
json_error = sass_context_get_error_json(context)
|
||||
// Release memory dedicated to the C compiler
|
||||
sass_delete_compiler(compiler)
|
||||
|
||||
**Building a data compiler**
|
||||
|
||||
context = sass_make_data_context("div { a { color: blue; } }")
|
||||
options = sass_data_context_get_options(context)
|
||||
sass_option_set_precision(options, 1)
|
||||
sass_option_set_source_comments(options, true)
|
||||
|
||||
sass_data_context_set_options(context, options)
|
||||
|
||||
compiler = sass_make_data_compiler(context)
|
||||
sass_compiler_parse(compiler)
|
||||
sass_compiler_execute(compiler)
|
||||
|
||||
output = sass_context_get_output_string(context)
|
||||
// div a { color: blue; }
|
||||
// Retrieve errors during compilation
|
||||
error_status = sass_context_get_error_status(context)
|
||||
json_error = sass_context_get_error_json(context)
|
||||
// Release memory dedicated to the C compiler
|
||||
sass_delete_compiler(compiler)
|
||||
|
||||
## Sass Context Internals
|
||||
|
||||
Everything is stored in structs:
|
||||
|
||||
```C
|
||||
struct Sass_Options;
|
||||
struct Sass_Context : Sass_Options;
|
||||
struct Sass_File_context : Sass_Context;
|
||||
struct Sass_Data_context : Sass_Context;
|
||||
```
|
||||
|
||||
This mirrors very well how `libsass` uses these structures.
|
||||
|
||||
- `Sass_Options` holds everything you feed in before the compilation. It also hosts `input_path` and `output_path` options, because they are used to generate/calculate relative links in source-maps. The `input_path` is shared with `Sass_File_Context`.
|
||||
- `Sass_Context` holds all the data returned by the compilation step.
|
||||
- `Sass_File_Context` is a specific implementation that requires no additional fields
|
||||
- `Sass_Data_Context` is a specific implementation that adds the `input_source` field
|
||||
|
||||
Structs can be down-casted to access `context` or `options`!
|
||||
|
||||
## Memory handling and life-cycles
|
||||
|
||||
We keep memory around for as long as the main [context](api-context.md) object is not destroyed (`sass_delete_context`). LibSass will create copies of most inputs/options beside the main sass code.
|
||||
You need to allocate and fill that buffer before passing it to LibSass. You may also overtake memory management from libsass for certain return values (i.e. `sass_context_take_output_string`).
|
||||
|
||||
```C
|
||||
// to allocate buffer to be filled
|
||||
void* sass_alloc_memory(size_t size);
|
||||
// to allocate a buffer from existing string
|
||||
char* sass_copy_c_string(const char* str);
|
||||
// to free overtaken memory when done
|
||||
void sass_free_memory(void* ptr);
|
||||
```
|
||||
|
||||
## Miscellaneous API functions
|
||||
|
||||
```C
|
||||
// Some convenient string helper function
|
||||
char* sass_string_unquote (const char* str);
|
||||
char* sass_string_quote (const char* str, const char quote_mark);
|
||||
|
||||
// Resolve a file via the given include paths in the include char* array
|
||||
char* sass_resolve_file (const char* path, const char* incs[]);
|
||||
|
||||
// Get compiled libsass version
|
||||
const char* libsass_version(void);
|
||||
```
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
**input_path**
|
||||
|
||||
The `input_path` is part of `Sass_Options`, but it also is the main option for `Sass_File_Context`. It is also used to generate relative file links in source-maps. Therefore it is pretty usefull to pass this information if you have a `Sass_Data_Context` and know the original path.
|
||||
|
||||
**output_path**
|
||||
|
||||
Be aware that `libsass` does not write the output file itself. This option merely exists to give `libsass` the proper information to generate links in source-maps. The file has to be written to the disk by the binding/implementation. If the `output_path` is omitted, `libsass` tries to extrapolate one from the `input_path` by replacing (or adding) the file ending with `.css`.
|
||||
|
||||
## Error Codes
|
||||
|
||||
The `error_code` is integer value which indicates the type of error that occurred inside the LibSass process. Following is the list of error codes along with the short description:
|
||||
|
||||
* 1: normal errors like parsing or `eval` errors
|
||||
* 2: bad allocation error (memory error)
|
||||
* 3: "untranslated" C++ exception (`throw std::exception`)
|
||||
* 4: legacy string exceptions ( `throw const char*` or `std::string` )
|
||||
* 5: Some other unknown exception
|
||||
|
||||
Although for the API consumer, error codes do not offer much value except indicating whether *any* error occurred during the compilation, it helps debugging the LibSass internal code paths.
|
||||
|
||||
## Real-World Implementations
|
||||
|
||||
The proof is in the pudding, so we have highlighted a few implementations that should be on par with the latest LibSass interface version. Some of them may not have all features implemented!
|
||||
|
||||
1. [Perl Example](https://github.com/sass/perl-libsass/blob/master/lib/CSS/Sass.xs)
|
||||
2. [Go Example](http://godoc.org/github.com/wellington/go-libsass#example-Context-Compile)
|
||||
3. [Node Example](https://github.com/sass/node-sass/blob/master/src/binding.cpp)
|
||||
|
||||
## ABI forward compatibility
|
||||
|
||||
We use a functional API to make dynamic linking more robust and future compatible. The API is not yet 100% stable, so we do not yet guarantee [ABI](https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html) forward compatibility. We will do so, once we increase the shared library version above 1.0.
|
||||
|
||||
## Plugins (experimental)
|
||||
|
||||
LibSass can load plugins from directories. Just define `plugin_path` on context options to load all plugins from the given directories. To implement plugins, please consult the [[Wiki-Page for plugins|API-Plugins]].
|
||||
|
||||
## Internal Structs
|
||||
|
||||
- [Sass Context Internals](api-context-internal.md)
|
||||
- [Sass Value Internals](api-value-internal.md)
|
||||
- [Sass Function Internals](api-function-internal.md)
|
||||
- [Sass Importer Internals](api-importer-internal.md)
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
## Example main.c
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "sass/context.h"
|
||||
|
||||
union Sass_Value* call_fn_foo(const union Sass_Value* s_args, Sass_Function_Entry cb, struct Sass_Compiler* comp)
|
||||
{
|
||||
// get context/option struct associated with this compiler
|
||||
struct Sass_Context* ctx = sass_compiler_get_context(comp);
|
||||
struct Sass_Options* opts = sass_compiler_get_options(comp);
|
||||
// get information about previous importer entry from the stack
|
||||
struct Sass_Import* import = sass_compiler_get_last_import(comp);
|
||||
const char* prev_abs_path = sass_import_get_abs_path(import);
|
||||
const char* prev_imp_path = sass_import_get_imp_path(import);
|
||||
// get the cookie from function descriptor
|
||||
void* cookie = sass_function_get_cookie(cb);
|
||||
// we actually abuse the void* to store an "int"
|
||||
return sass_make_number((intptr_t)cookie, "px");
|
||||
}
|
||||
|
||||
int main( int argc, const char* argv[] )
|
||||
{
|
||||
|
||||
// get the input file from first argument or use default
|
||||
const char* input = argc > 1 ? argv[1] : "styles.scss";
|
||||
|
||||
// create the file context and get all related structs
|
||||
struct Sass_File_Context* file_ctx = sass_make_file_context(input);
|
||||
struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
|
||||
struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
|
||||
|
||||
// allocate a custom function caller
|
||||
Sass_Function_Entry fn_foo =
|
||||
sass_make_function("foo()", call_fn_foo, (void*)42);
|
||||
|
||||
// create list of all custom functions
|
||||
Sass_Function_List fn_list = sass_make_function_list(1);
|
||||
sass_function_set_list_entry(fn_list, 0, fn_foo);
|
||||
sass_option_set_c_functions(ctx_opt, fn_list);
|
||||
|
||||
// context is set up, call the compile step now
|
||||
int status = sass_compile_file_context(file_ctx);
|
||||
|
||||
// print the result or the error to the stdout
|
||||
if (status == 0) puts(sass_context_get_output_string(ctx));
|
||||
else puts(sass_context_get_error_message(ctx));
|
||||
|
||||
// release allocated memory
|
||||
sass_delete_file_context(file_ctx);
|
||||
|
||||
// exit status
|
||||
return status;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Compile main.c
|
||||
|
||||
```bash
|
||||
gcc -c main.c -o main.o
|
||||
gcc -o sample main.o -lsass
|
||||
echo "foo { margin: foo(); }" > foo.scss
|
||||
./sample foo.scss => "foo { margin: 42px }"
|
||||
```
|
||||
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
```C
|
||||
// Struct to hold custom function callback
|
||||
struct Sass_Function {
|
||||
const char* signature;
|
||||
Sass_Function_Fn function;
|
||||
void* cookie;
|
||||
};
|
||||
```
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
Sass functions are used to define new custom functions callable by Sass code. They are also used to overload debug or error statements. You can also define a fallback function, which is called for every unknown function found in the Sass code. Functions get passed zero or more `Sass_Values` (a `Sass_List` value) and they must also return a `Sass_Value`. Return a `Sass_Error` if you want to signal an error.
|
||||
|
||||
## Special signatures
|
||||
|
||||
- `*` - Fallback implementation
|
||||
- `@warn` - Overload warn statements
|
||||
- `@error` - Overload error statements
|
||||
- `@debug` - Overload debug statements
|
||||
|
||||
Note: The fallback implementation will be given the name of the called function as the first argument, before all the original function arguments. These features are pretty new and should be considered experimental.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```C
|
||||
#include "sass/functions.h"
|
||||
```
|
||||
|
||||
## Sass Function API
|
||||
|
||||
```C
|
||||
// Forward declaration
|
||||
struct Sass_Compiler;
|
||||
struct Sass_Function;
|
||||
|
||||
// Typedef helpers for custom functions lists
|
||||
typedef struct Sass_Function (*Sass_Function_Entry);
|
||||
typedef struct Sass_Function* (*Sass_Function_List);
|
||||
// Typedef defining function signature and return type
|
||||
typedef union Sass_Value* (*Sass_Function_Fn)
|
||||
(const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Compiler* compiler);
|
||||
|
||||
// Creators for sass function list and function descriptors
|
||||
ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length);
|
||||
ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie);
|
||||
|
||||
// Setters and getters for callbacks on function lists
|
||||
ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos);
|
||||
ADDAPI void ADDCALL sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb);
|
||||
|
||||
// Getters for custom function descriptors
|
||||
ADDAPI const char* ADDCALL sass_function_get_signature (Sass_Function_Entry cb);
|
||||
ADDAPI Sass_Function_Fn ADDCALL sass_function_get_function (Sass_Function_Entry cb);
|
||||
ADDAPI void* ADDCALL sass_function_get_cookie (Sass_Function_Entry cb);
|
||||
```
|
||||
|
||||
### More links
|
||||
|
||||
- [Sass Function Example](api-function-example.md)
|
||||
- [Sass Function Internal](api-function-internal.md)
|
||||
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
## Example importer.c
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "sass/context.h"
|
||||
|
||||
Sass_Import_List sass_importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp)
|
||||
{
|
||||
// get the cookie from importer descriptor
|
||||
void* cookie = sass_importer_get_cookie(cb);
|
||||
Sass_Import_List list = sass_make_import_list(2);
|
||||
char* local = sass_copy_c_string("local { color: green; }");
|
||||
char* remote = sass_copy_c_string("remote { color: red; }");
|
||||
list[0] = sass_make_import_entry("/tmp/styles.scss", local, 0);
|
||||
list[1] = sass_make_import_entry("http://www.example.com", remote, 0);
|
||||
return list;
|
||||
}
|
||||
|
||||
int main( int argc, const char* argv[] )
|
||||
{
|
||||
|
||||
// get the input file from first argument or use default
|
||||
const char* input = argc > 1 ? argv[1] : "styles.scss";
|
||||
|
||||
// create the file context and get all related structs
|
||||
struct Sass_File_Context* file_ctx = sass_make_file_context(input);
|
||||
struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
|
||||
struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
|
||||
|
||||
// allocate custom importer
|
||||
Sass_Importer_Entry c_imp =
|
||||
sass_make_importer(sass_importer, 0, 0);
|
||||
// create list for all custom importers
|
||||
Sass_Importer_List imp_list = sass_make_importer_list(1);
|
||||
// put only the importer on to the list
|
||||
sass_importer_set_list_entry(imp_list, 0, c_imp);
|
||||
// register list on to the context options
|
||||
sass_option_set_c_importers(ctx_opt, imp_list);
|
||||
// context is set up, call the compile step now
|
||||
int status = sass_compile_file_context(file_ctx);
|
||||
|
||||
// print the result or the error to the stdout
|
||||
if (status == 0) puts(sass_context_get_output_string(ctx));
|
||||
else puts(sass_context_get_error_message(ctx));
|
||||
|
||||
// release allocated memory
|
||||
sass_delete_file_context(file_ctx);
|
||||
|
||||
// exit status
|
||||
return status;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Compile importer.c
|
||||
|
||||
```bash
|
||||
gcc -c importer.c -o importer.o
|
||||
gcc -o importer importer.o -lsass
|
||||
echo "@import 'foobar';" > importer.scss
|
||||
./importer importer.scss
|
||||
```
|
||||
|
||||
## Importer Behavior Examples
|
||||
|
||||
```C
|
||||
Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
|
||||
// let LibSass handle the import request
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
|
||||
// let LibSass handle the request
|
||||
// swallows »@import "http://…"« pass-through
|
||||
// (arguably a bug)
|
||||
Sass_Import_List list = sass_make_import_list(1);
|
||||
list[0] = sass_make_import_entry(path, 0, 0);
|
||||
return list;
|
||||
}
|
||||
|
||||
Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
|
||||
// return an error to halt execution
|
||||
Sass_Import_List list = sass_make_import_list(1);
|
||||
const char* message = "some error message";
|
||||
list[0] = sass_make_import_entry(path, 0, 0);
|
||||
sass_import_set_error(list[0], sass_copy_c_string(message), 0, 0);
|
||||
return list;
|
||||
}
|
||||
|
||||
Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
|
||||
// let LibSass load the file identifed by the importer
|
||||
Sass_Import_List list = sass_make_import_list(1);
|
||||
list[0] = sass_make_import_entry("/tmp/file.scss", 0, 0);
|
||||
return list;
|
||||
}
|
||||
|
||||
Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
|
||||
// completely hide the import
|
||||
// (arguably a bug)
|
||||
Sass_Import_List list = sass_make_import_list(0);
|
||||
return list;
|
||||
}
|
||||
|
||||
Sass_Import_List importer(const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp) {
|
||||
// completely hide the import
|
||||
// (arguably a bug)
|
||||
Sass_Import_List list = sass_make_import_list(1);
|
||||
list[0] = sass_make_import_entry(0, 0, 0);
|
||||
return list;
|
||||
}
|
||||
```
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
```C
|
||||
// External import entry
|
||||
struct Sass_Import {
|
||||
char* imp_path; // path as found in the import statement
|
||||
char *abs_path; // path after importer has resolved it
|
||||
char* source;
|
||||
char* srcmap;
|
||||
// error handling
|
||||
char* error;
|
||||
size_t line;
|
||||
size_t column;
|
||||
};
|
||||
|
||||
// Struct to hold importer callback
|
||||
struct Sass_Importer {
|
||||
Sass_Importer_Fn importer;
|
||||
double priority;
|
||||
void* cookie;
|
||||
};
|
||||
```
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
By using custom importers, Sass stylesheets can be implemented in any possible way, such as by being loaded via a remote server. Please note: this feature is experimental and is implemented differently than importers in Ruby Sass. Imports must be relative to the parent import context and therefore we need to pass this information to the importer callback. This is currently done by passing the complete import string/path of the previous import context.
|
||||
|
||||
## Return Imports
|
||||
|
||||
You actually have to return a list of imports, since some importers may want to import multiple files from one import statement (ie. a glob/star importer). The memory you pass with source and srcmap is taken over by LibSass and freed automatically when the import is done. You are also allowed to return `0` instead of a list, which will tell LibSass to handle the import by itself (as if no custom importer was in use).
|
||||
|
||||
```C
|
||||
struct Sass_Import** rv = sass_make_import_list(1);
|
||||
rv[0] = sass_make_import(rel, abs, source, srcmap);
|
||||
```
|
||||
|
||||
Every import will then be included in LibSass. You are allowed to only return a file path without any loaded source. This way you can ie. implement rewrite rules for import paths and leave the loading part for LibSass.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```C
|
||||
#include "sass/functions.h"
|
||||
```
|
||||
|
||||
## Sass Importer API
|
||||
|
||||
```C
|
||||
// Forward declaration
|
||||
struct Sass_Import;
|
||||
|
||||
// Forward declaration
|
||||
struct Sass_C_Import_Descriptor;
|
||||
|
||||
// Typedef defining the custom importer callback
|
||||
typedef struct Sass_C_Import_Descriptor (*Sass_C_Import_Callback);
|
||||
// Typedef defining the importer c function prototype
|
||||
typedef struct Sass_Import** (*Sass_C_Import_Fn) (const char* url, const char* prev, void* cookie);
|
||||
|
||||
// Creators for custom importer callback (with some additional pointer)
|
||||
// The pointer is mostly used to store the callback into the actual function
|
||||
Sass_C_Import_Callback sass_make_importer (Sass_C_Import_Fn, void* cookie);
|
||||
|
||||
// Getters for import function descriptors
|
||||
Sass_C_Import_Fn sass_import_get_function (Sass_C_Import_Callback fn);
|
||||
void* sass_import_get_cookie (Sass_C_Import_Callback fn);
|
||||
|
||||
// Deallocator for associated memory
|
||||
void sass_delete_importer (Sass_C_Import_Callback fn);
|
||||
|
||||
// Creator for sass custom importer return argument list
|
||||
struct Sass_Import** sass_make_import_list (size_t length);
|
||||
// Creator for a single import entry returned by the custom importer inside the list
|
||||
struct Sass_Import* sass_make_import_entry (const char* path, char* source, char* srcmap);
|
||||
struct Sass_Import* sass_make_import (const char* rel, const char* abs, char* source, char* srcmap);
|
||||
|
||||
// set error message to abort import and to print out a message (path from existing object is used in output)
|
||||
struct Sass_Import* sass_import_set_error(struct Sass_Import* import, const char* message, size_t line, size_t col);
|
||||
|
||||
// Setters to insert an entry into the import list (you may also use [] access directly)
|
||||
// Since we are dealing with pointers they should have a guaranteed and fixed size
|
||||
void sass_import_set_list_entry (struct Sass_Import** list, size_t idx, struct Sass_Import* entry);
|
||||
struct Sass_Import* sass_import_get_list_entry (struct Sass_Import** list, size_t idx);
|
||||
|
||||
// Getters for import entry
|
||||
const char* sass_import_get_rel_path (struct Sass_Import*);
|
||||
const char* sass_import_get_abs_path (struct Sass_Import*);
|
||||
const char* sass_import_get_source (struct Sass_Import*);
|
||||
const char* sass_import_get_srcmap (struct Sass_Import*);
|
||||
// Explicit functions to take ownership of these items
|
||||
// The property on our struct will be reset to NULL
|
||||
char* sass_import_take_source (struct Sass_Import*);
|
||||
char* sass_import_take_srcmap (struct Sass_Import*);
|
||||
|
||||
// Getters for import error entries
|
||||
size_t sass_import_get_error_line (struct Sass_Import*);
|
||||
size_t sass_import_get_error_column (struct Sass_Import*);
|
||||
const char* sass_import_get_error_message (struct Sass_Import*);
|
||||
|
||||
// Deallocator for associated memory (incl. entries)
|
||||
void sass_delete_import_list (struct Sass_Import**);
|
||||
// Just in case we have some stray import structs
|
||||
void sass_delete_import (struct Sass_Import*);
|
||||
```
|
||||
|
||||
### More links
|
||||
|
||||
- [Sass Importer Example](api-importer-example.md)
|
||||
- [Sass Importer Internal](api-importer-internal.md)
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
```C
|
||||
struct Sass_Unknown {
|
||||
enum Sass_Tag tag;
|
||||
};
|
||||
|
||||
struct Sass_Boolean {
|
||||
enum Sass_Tag tag;
|
||||
bool value;
|
||||
};
|
||||
|
||||
struct Sass_Number {
|
||||
enum Sass_Tag tag;
|
||||
double value;
|
||||
char* unit;
|
||||
};
|
||||
|
||||
struct Sass_Color {
|
||||
enum Sass_Tag tag;
|
||||
double r;
|
||||
double g;
|
||||
double b;
|
||||
double a;
|
||||
};
|
||||
|
||||
struct Sass_String {
|
||||
enum Sass_Tag tag;
|
||||
char* value;
|
||||
};
|
||||
|
||||
struct Sass_List {
|
||||
enum Sass_Tag tag;
|
||||
enum Sass_Separator separator;
|
||||
size_t length;
|
||||
// null terminated "array"
|
||||
union Sass_Value** values;
|
||||
};
|
||||
|
||||
struct Sass_Map {
|
||||
enum Sass_Tag tag;
|
||||
size_t length;
|
||||
struct Sass_MapPair* pairs;
|
||||
};
|
||||
|
||||
struct Sass_Null {
|
||||
enum Sass_Tag tag;
|
||||
};
|
||||
|
||||
struct Sass_Error {
|
||||
enum Sass_Tag tag;
|
||||
char* message;
|
||||
};
|
||||
|
||||
struct Sass_Warning {
|
||||
enum Sass_Tag tag;
|
||||
char* message;
|
||||
};
|
||||
|
||||
union Sass_Value {
|
||||
struct Sass_Unknown unknown;
|
||||
struct Sass_Boolean boolean;
|
||||
struct Sass_Number number;
|
||||
struct Sass_Color color;
|
||||
struct Sass_String string;
|
||||
struct Sass_List list;
|
||||
struct Sass_Map map;
|
||||
struct Sass_Null null;
|
||||
struct Sass_Error error;
|
||||
struct Sass_Warning warning;
|
||||
};
|
||||
|
||||
struct Sass_MapPair {
|
||||
union Sass_Value* key;
|
||||
union Sass_Value* value;
|
||||
};
|
||||
```
|
||||
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
`Sass_Values` are used to pass values and their types between the implementer and LibSass. Sass knows various different value types (including nested arrays and hash-maps). If you implement a binding to another programming language, you have to find a way to convert `Sass_Values` between the targeted language and C. `Sass_Values` are currently only used by custom functions.
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```C
|
||||
#include "sass/values.h"
|
||||
```
|
||||
|
||||
```C
|
||||
// Type for Sass values
|
||||
enum Sass_Tag {
|
||||
SASS_BOOLEAN,
|
||||
SASS_NUMBER,
|
||||
SASS_COLOR,
|
||||
SASS_STRING,
|
||||
SASS_LIST,
|
||||
SASS_MAP,
|
||||
SASS_NULL,
|
||||
SASS_ERROR,
|
||||
SASS_WARNING
|
||||
};
|
||||
|
||||
// Tags for denoting Sass list separators
|
||||
enum Sass_Separator {
|
||||
SASS_COMMA,
|
||||
SASS_SPACE
|
||||
};
|
||||
```
|
||||
|
||||
### Sass Value API
|
||||
|
||||
```C
|
||||
// Forward declaration
|
||||
union Sass_Value;
|
||||
|
||||
// Return the sass tag for a generic sass value
|
||||
// Check is needed before accessing specific values!
|
||||
enum Sass_Tag sass_value_get_tag (const union Sass_Value* v);
|
||||
|
||||
// Check value to be of a specific type
|
||||
// Can also be used before accessing properties!
|
||||
bool sass_value_is_null (const union Sass_Value* v);
|
||||
bool sass_value_is_number (const union Sass_Value* v);
|
||||
bool sass_value_is_string (const union Sass_Value* v);
|
||||
bool sass_value_is_boolean (const union Sass_Value* v);
|
||||
bool sass_value_is_color (const union Sass_Value* v);
|
||||
bool sass_value_is_list (const union Sass_Value* v);
|
||||
bool sass_value_is_map (const union Sass_Value* v);
|
||||
bool sass_value_is_error (const union Sass_Value* v);
|
||||
bool sass_value_is_warning (const union Sass_Value* v);
|
||||
|
||||
// Getters and setters for Sass_Number
|
||||
double sass_number_get_value (const union Sass_Value* v);
|
||||
void sass_number_set_value (union Sass_Value* v, double value);
|
||||
const char* sass_number_get_unit (const union Sass_Value* v);
|
||||
void sass_number_set_unit (union Sass_Value* v, char* unit);
|
||||
|
||||
// Getters and setters for Sass_String
|
||||
const char* sass_string_get_value (const union Sass_Value* v);
|
||||
void sass_string_set_value (union Sass_Value* v, char* value);
|
||||
|
||||
// Getters and setters for Sass_Boolean
|
||||
bool sass_boolean_get_value (const union Sass_Value* v);
|
||||
void sass_boolean_set_value (union Sass_Value* v, bool value);
|
||||
|
||||
// Getters and setters for Sass_Color
|
||||
double sass_color_get_r (const union Sass_Value* v);
|
||||
void sass_color_set_r (union Sass_Value* v, double r);
|
||||
double sass_color_get_g (const union Sass_Value* v);
|
||||
void sass_color_set_g (union Sass_Value* v, double g);
|
||||
double sass_color_get_b (const union Sass_Value* v);
|
||||
void sass_color_set_b (union Sass_Value* v, double b);
|
||||
double sass_color_get_a (const union Sass_Value* v);
|
||||
void sass_color_set_a (union Sass_Value* v, double a);
|
||||
|
||||
// Getter for the number of items in list
|
||||
size_t sass_list_get_length (const union Sass_Value* v);
|
||||
// Getters and setters for Sass_List
|
||||
enum Sass_Separator sass_list_get_separator (const union Sass_Value* v);
|
||||
void sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
|
||||
// Getters and setters for Sass_List values
|
||||
union Sass_Value* sass_list_get_value (const union Sass_Value* v, size_t i);
|
||||
void sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
|
||||
|
||||
// Getter for the number of items in map
|
||||
size_t sass_map_get_length (const union Sass_Value* v);
|
||||
// Getters and setters for Sass_List keys and values
|
||||
union Sass_Value* sass_map_get_key (const union Sass_Value* v, size_t i);
|
||||
void sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
|
||||
union Sass_Value* sass_map_get_value (const union Sass_Value* v, size_t i);
|
||||
void sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);
|
||||
|
||||
// Getters and setters for Sass_Error
|
||||
char* sass_error_get_message (const union Sass_Value* v);
|
||||
void sass_error_set_message (union Sass_Value* v, char* msg);
|
||||
|
||||
// Getters and setters for Sass_Warning
|
||||
char* sass_warning_get_message (const union Sass_Value* v);
|
||||
void sass_warning_set_message (union Sass_Value* v, char* msg);
|
||||
|
||||
// Creator functions for all value types
|
||||
union Sass_Value* sass_make_null (void);
|
||||
union Sass_Value* sass_make_boolean (bool val);
|
||||
union Sass_Value* sass_make_string (const char* val);
|
||||
union Sass_Value* sass_make_number (double val, const char* unit);
|
||||
union Sass_Value* sass_make_color (double r, double g, double b, double a);
|
||||
union Sass_Value* sass_make_list (size_t len, enum Sass_Separator sep);
|
||||
union Sass_Value* sass_make_map (size_t len);
|
||||
union Sass_Value* sass_make_error (const char* msg);
|
||||
union Sass_Value* sass_make_warning (const char* msg);
|
||||
|
||||
// Generic destructor function for all types
|
||||
// Will release memory of all associated Sass_Values
|
||||
// Means we will delete recursively for lists and maps
|
||||
void sass_delete_value (union Sass_Value* val);
|
||||
|
||||
// Make a deep cloned copy of the given sass value
|
||||
union Sass_Value* sass_clone_value (const union Sass_Value* val);
|
||||
```
|
||||
|
||||
### More links
|
||||
|
||||
- [Sass Value Example](api-value-example.md)
|
||||
- [Sass Value Internal](api-value-internal.md)
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
To install LibSass, make sure the OS X build tools are installed:
|
||||
|
||||
xcode-select --install
|
||||
|
||||
## Homebrew
|
||||
|
||||
To install homebrew, see [http://brew.sh](http://brew.sh)
|
||||
|
||||
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
|
||||
|
||||
You can install the latest version of LibSass quite easily with brew.
|
||||
|
||||
brew install --HEAD libsass
|
||||
|
||||
To update this, do:
|
||||
|
||||
brew reinstall --HEAD libsass
|
||||
|
||||
Brew will build static and shared libraries, and a `libsass.pc` file in `/usr/local/lib/pkgconfig`.
|
||||
|
||||
To use `libsass.pc`, make sure this path is in your `PKG_CONFIG_PATH`
|
||||
|
||||
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
|
||||
|
||||
## Manually
|
||||
|
||||
See the linux instructions [Building-with-autotools](build-with-autotools.md) or [Building-with-makefiles](build-with-makefiles.md)
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
Here are two ebuilds to compile LibSass and sassc on gentoo linux. If you do not know how to use these ebuilds, you should probably read the gentoo wiki page about [portage overlays](http://wiki.gentoo.org/wiki/Overlay).
|
||||
|
||||
## www-misc/libsass/libsass-9999.ebuild
|
||||
```ebuild
|
||||
EAPI=4
|
||||
|
||||
inherit eutils git-2 autotools
|
||||
|
||||
DESCRIPTION="A C/C++ implementation of a Sass compiler."
|
||||
HOMEPAGE="http://libsass.org/"
|
||||
EGIT_PROJECT='libsass'
|
||||
EGIT_REPO_URI="https://github.com/sass/libsass.git"
|
||||
LICENSE="MIT"
|
||||
SLOT="0"
|
||||
KEYWORDS=""
|
||||
IUSE=""
|
||||
DEPEND=""
|
||||
RDEPEND="${DEPEND}"
|
||||
DEPEND="${DEPEND}"
|
||||
|
||||
pkg_pretend() {
|
||||
# older gcc is not supported
|
||||
local major=$(gcc-major-version)
|
||||
local minor=$(gcc-minor-version)
|
||||
[[ "${MERGE_TYPE}" != "binary" && ( $major > 4 || ( $major == 4 && $minor < 5 ) ) ]] && \
|
||||
die "Sorry, but gcc earlier than 4.5 will not work for LibSass."
|
||||
}
|
||||
|
||||
src_prepare() {
|
||||
eautoreconf
|
||||
}
|
||||
```
|
||||
|
||||
## www-misc/sassc/sassc-9999.ebuild
|
||||
```ebuild
|
||||
EAPI=4
|
||||
|
||||
inherit eutils git-2 autotools
|
||||
|
||||
DESCRIPTION="Command Line Tool for LibSass."
|
||||
HOMEPAGE="http://libsass.org/"
|
||||
EGIT_PROJECT='sassc'
|
||||
EGIT_REPO_URI="https://github.com/sass/sassc.git"
|
||||
LICENSE="MIT"
|
||||
SLOT="0"
|
||||
KEYWORDS=""
|
||||
IUSE=""
|
||||
DEPEND="www-misc/libsass"
|
||||
RDEPEND="${DEPEND}"
|
||||
DEPEND="${DEPEND}"
|
||||
|
||||
src_prepare() {
|
||||
eautoreconf
|
||||
}
|
||||
```
|
||||
+139
@@ -0,0 +1,139 @@
|
||||
We support builds via MingGW and via Visual Studio Community 2013.
|
||||
Both should be considered experimental (MinGW was better tested)!
|
||||
|
||||
## Building via MingGW (makefiles)
|
||||
|
||||
First grab the latest [MinGW for windows] [1] installer. Once it is installed, you can click on continue or open the Installation Manager via `bin\mingw-get.exe`.
|
||||
|
||||
You need to have the following components installed:
|
||||

|
||||
|
||||
Next we need to install [git for windows] [2]. You probably want to check the option to add it to the global path, but you do not need to install the unix tools.
|
||||
|
||||
If you want to run the spec test-suite you also need [ruby] [3] and a few gems available. Grab the [latest installer] [3] and make sure to add it the global path. Then install the missing gems:
|
||||
|
||||
```bash
|
||||
gem install minitest
|
||||
```
|
||||
|
||||
### Mount the mingw root directory
|
||||
|
||||
As mentioned in the [MinGW Getting Started](http://www.mingw.org/wiki/Getting_Started#toc5) guide, you should edit `C:\MinGW\msys\1.0\etc\fstab` to contain the following line:
|
||||
|
||||
```
|
||||
C:\MinGW /mingw
|
||||
```
|
||||
|
||||
### Starting a "MingGW" console
|
||||
|
||||
Create a batch file with this content:
|
||||
```bat
|
||||
@echo off
|
||||
set PATH=C:\MinGW\bin;%PATH%
|
||||
REM only needed if not already available
|
||||
set PATH=%PROGRAMFILES%\git\bin;%PATH%
|
||||
REM C:\MinGW\msys\1.0\msys.bat
|
||||
cmd
|
||||
```
|
||||
|
||||
Execute it and make sure these commands can be called: `git`, `mingw32-make`, `rm` and `gcc`! Once this is all set, you should be ready to compile `libsass`!
|
||||
|
||||
### Get the sources
|
||||
|
||||
```bash
|
||||
# using git is preferred
|
||||
git clone https://github.com/sass/libsass.git
|
||||
# only needed for sassc and/or testsuite
|
||||
git clone https://github.com/sass/sassc.git libsass/sassc
|
||||
git clone https://github.com/sass/sass-spec.git libsass/sass-spec
|
||||
```
|
||||
|
||||
### Decide for static or shared library
|
||||
|
||||
`libsass` can be built and linked as a `static` or as a `shared` library. The default is `static`. To change it you can set the `BUILD` environment variable:
|
||||
|
||||
```bat
|
||||
set BUILD="shared"
|
||||
```
|
||||
|
||||
### Compile the library
|
||||
```bash
|
||||
mingw32-make -C libsass
|
||||
```
|
||||
|
||||
### Results can be found in
|
||||
```bash
|
||||
$ ls libsass/lib
|
||||
libsass.a libsass.dll libsass.so
|
||||
```
|
||||
|
||||
### Run the spec test-suite
|
||||
```bash
|
||||
mingw32-make -C libsass test_build
|
||||
```
|
||||
|
||||
## Building via MingGW 64bit (makefiles)
|
||||
Building libass to dll on window 64bit.
|
||||
|
||||
+ downloads [MinGW64 for windows7 64bit](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v3-rev0.7z/download) , and unzip to "C:\mingw64".
|
||||
|
||||
+ Create a batch file with this content:
|
||||
|
||||
```bat
|
||||
@echo off
|
||||
set PATH=C:\mingw64\bin;%PATH%
|
||||
set CC=gcc
|
||||
REM only needed if not already available
|
||||
set PATH=%PROGRAMFILES%\Git\bin;%PATH%
|
||||
REM C:\MinGW\msys\1.0\msys.bat
|
||||
cmd
|
||||
```
|
||||
|
||||
+ By default , mingw64 dll will depends on "mingwm10.dll、 libgcc_s_dw2-1.dll" , we can modify Makefile to fix this:(add "-static")
|
||||
|
||||
``` bash
|
||||
lib/libsass.dll: $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
|
||||
$(MKDIR) lib
|
||||
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -static -Wl,--subsystem,windows,--out-implib,lib/libsass.a
|
||||
```
|
||||
|
||||
+ Compile the library
|
||||
|
||||
```bash
|
||||
mingw32-make -C libsass
|
||||
```
|
||||
|
||||
By the way , if you are using java jna , [JNAerator](http://jnaerator.googlecode.com/) is a good tool.
|
||||
|
||||
## Building via Visual Studio Community 2013
|
||||
|
||||
Open a Visual Studio 2013 command prompt:
|
||||
- `VS2013 x86 Native Tools Command Prompt`
|
||||
|
||||
Note: When I installed the community edition, I only got the 2012 command prompts. I copied them from the Startmenu to the Desktop and adjusted the paths from `Visual Studio 11.0` to `Visual Studio 12.0`. Since `libsass` uses some `C++11` features, you need at least a MSVC 2013 compiler (v120).
|
||||
|
||||
### Get the source
|
||||
```bash
|
||||
# using git is preferred
|
||||
git clone https://github.com/sass/libsass.git
|
||||
git clone https://github.com/sass/sassc.git libsass/sassc
|
||||
# only needed if you want to run the testsuite
|
||||
git clone https://github.com/sass/sass-spec.git libsass/sass-spec
|
||||
```
|
||||
|
||||
### Compile sassc
|
||||
|
||||
Sometimes `msbuild` seems not available from the command prompt. Just search for it and add it to the global path. It seems to be included in the .net folders too.
|
||||
|
||||
```bat
|
||||
cd libsass
|
||||
REM set PATH=%PATH%;%PROGRAMFILES%\MSBuild\12.0\Bin
|
||||
msbuild /m:4 /p:Configuration=Release win\libsass.sln
|
||||
REM running the spec test-suite manually (needs ruby and minitest gem)
|
||||
ruby sass-spec\sass-spec.rb -V 3.4 -c win\bin\sassc.exe -s --impl libsass sass-spec/spec
|
||||
cd ..
|
||||
```
|
||||
|
||||
[1]: http://sourceforge.net/projects/mingw/files/latest/download?source=files
|
||||
[2]: https://msysgit.github.io/
|
||||
[3]: http://rubyinstaller.org/
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
This page is mostly intended for people that want to build a system library that gets distributed via RPMs or other means. This is currently in a experimental phase, as we currently do not really guarantee any ABI forward compatibility. The C API was rewritten to make this possible in the future, but we want to wait some more time till we can call this final and stable.
|
||||
|
||||
Building via autotools
|
||||
--
|
||||
|
||||
You want to build a system library only via autotools, since it will create the proper `libtool` files to make it loadable on multiple systems. We hope this works correctly, but nobody of the `libsass` core team has much knowledge in this area. Therefore we are open for comments or improvements by people that have more experience in that matter (like package maintainers from various linux distributions).
|
||||
|
||||
```bash
|
||||
apt-get install autoconf libtool
|
||||
git clone https://github.com/sass/libsass.git
|
||||
cd libsass
|
||||
autoreconf --force --install
|
||||
./configure \
|
||||
--disable-tests \
|
||||
--disable-static \
|
||||
--enable-shared \
|
||||
--prefix=/usr
|
||||
make -j5 install
|
||||
cd ..
|
||||
```
|
||||
|
||||
This should install these files
|
||||
```bash
|
||||
# $ ls -la /usr/lib/libsass.*
|
||||
/usr/lib/libsass.la
|
||||
/usr/lib/libsass.so -> libsass.so.0.0.9
|
||||
/usr/lib/libsass.so.0 -> libsass.so.0.0.9
|
||||
/usr/lib/libsass.so.0.0.9
|
||||
# $ ls -la /usr/include/sass*
|
||||
/usr/include/sass.h
|
||||
/usr/include/sass2scss.h
|
||||
/usr/include/sass/context.h
|
||||
/usr/include/sass/functions.h
|
||||
/usr/include/sass/values.h
|
||||
```
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
### Get the sources
|
||||
```bash
|
||||
# using git is preferred
|
||||
git clone https://github.com/sass/libsass.git
|
||||
# only needed for sassc and/or testsuite
|
||||
git clone https://github.com/sass/sassc.git libsass/sassc
|
||||
git clone https://github.com/sass/sass-spec.git libsass/sass-spec
|
||||
```
|
||||
|
||||
### Prerequisites
|
||||
|
||||
In order to run autotools you need a few tools installed on your system.
|
||||
```bash
|
||||
yum install automake libtool # RedHat Linux
|
||||
emerge -a automake libtool # Gentoo Linux
|
||||
pkgin install automake libtool # SmartOS
|
||||
```
|
||||
|
||||
|
||||
### Create configure script
|
||||
```bash
|
||||
cd libsass
|
||||
autoreconf --force --install
|
||||
cd ..
|
||||
```
|
||||
|
||||
### Create custom makefiles
|
||||
```bash
|
||||
cd libsass
|
||||
./configure \
|
||||
--disable-tests \
|
||||
--disable-shared \
|
||||
--prefix=/usr
|
||||
cd ..
|
||||
```
|
||||
|
||||
### Build the library
|
||||
```bash
|
||||
make -C libsass -j5
|
||||
```
|
||||
|
||||
### Install the library
|
||||
The library will be installed to the location given as `prefix` to `configure`. This is standard behavior for autotools and not `libsass` specific.
|
||||
```bash
|
||||
make -C libsass -j5 install
|
||||
```
|
||||
|
||||
### Configure options
|
||||
The `configure` script is created by autotools. To get an overview of available options you can call `./configure --help`. When you execute this script, it will create specific makefiles, which you then use via the regular make command.
|
||||
|
||||
There are some `libsass` specific options:
|
||||
|
||||
```
|
||||
Optional Features:
|
||||
--enable-tests enable testing the build
|
||||
--enable-coverage enable coverage report for test suite
|
||||
--enable-shared build shared libraries [default=yes]
|
||||
--enable-static build static libraries [default=yes]
|
||||
|
||||
Optional Packages:
|
||||
--with-sassc-dir=<dir> specify directory of sassc sources for
|
||||
testing (default: sassc)
|
||||
--with-sass-spec-dir=<dir> specify directory of sass-spec for testing
|
||||
(default: sass-spec)
|
||||
```
|
||||
|
||||
### Build sassc and run spec test-suite
|
||||
|
||||
```bash
|
||||
cd libsass
|
||||
autoreconf --force --install
|
||||
./configure \
|
||||
--enable-tests \
|
||||
--enable-shared \
|
||||
--prefix=/usr
|
||||
make -j5 test_build
|
||||
cd ..
|
||||
```
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
### Get the sources
|
||||
```bash
|
||||
# using git is preferred
|
||||
git clone https://github.com/sass/libsass.git
|
||||
# only needed for sassc and/or testsuite
|
||||
git clone https://github.com/sass/sassc.git libsass/sassc
|
||||
git clone https://github.com/sass/sass-spec.git libsass/sass-spec
|
||||
```
|
||||
|
||||
### Decide for static or shared library
|
||||
|
||||
`libsass` can be built and linked as a `static` or as a `shared` library. The default is `static`. To change it you can set the `BUILD` environment variable:
|
||||
|
||||
```bash
|
||||
export BUILD="shared"
|
||||
```
|
||||
|
||||
Alternatively you can also define it directly when calling make:
|
||||
|
||||
```bash
|
||||
BUILD="shared" make ...
|
||||
```
|
||||
|
||||
### Compile the library
|
||||
```bash
|
||||
make -C libsass -j5
|
||||
```
|
||||
|
||||
### Results can be found in
|
||||
```bash
|
||||
$ ls libsass/lib
|
||||
libsass.a libsass.so
|
||||
```
|
||||
|
||||
### Install onto the system
|
||||
|
||||
We recommend to use [autotools to install](build-with-autotools.md) libsass onto the
|
||||
system, since that brings all the benefits of using libtools as the main install method.
|
||||
If you still want to install libsass via the makefile, you need to make sure that gnu
|
||||
`install` utility (or compatible) is installed on your system.
|
||||
```bash
|
||||
yum install coreutils # RedHat Linux
|
||||
emerge -a coreutils # Gentoo Linux
|
||||
pkgin install coreutils # SmartOS
|
||||
```
|
||||
|
||||
You can set the install location by setting `PREFIX`
|
||||
```bash
|
||||
PREFIX="/opt/local" make install
|
||||
```
|
||||
|
||||
|
||||
### Compling sassc
|
||||
|
||||
```bash
|
||||
# Let build know library location
|
||||
export SASS_LIBSASS_PATH="`pwd`/libsass"
|
||||
# Invokes the sassc makefile
|
||||
make -C libsass -j5 sassc
|
||||
```
|
||||
|
||||
### Run the spec test-suite
|
||||
|
||||
```bash
|
||||
# needs ruby available
|
||||
# also gem install minitest
|
||||
make -C libsass -j5 test_build
|
||||
```
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
## Building LibSass with MingGW (makefiles)
|
||||
|
||||
First grab the latest [MinGW for windows] [1] installer. Once it is installed, you can click on continue or open the Installation Manager via `bin\mingw-get.exe`.
|
||||
|
||||
You need to have the following components installed:
|
||||

|
||||
|
||||
Next we need to install [git for windows] [2]. You probably want to check the option to add it to the global path, but you do not need to install the unix tools.
|
||||
|
||||
If you want to run the spec test-suite you also need [ruby] [3] and a few gems available. Grab the [latest installer] [3] and make sure to add it the global path. Then install the missing gems:
|
||||
|
||||
```bash
|
||||
gem install minitest
|
||||
```
|
||||
|
||||
### Mount the mingw root directory
|
||||
|
||||
As mentioned in the [MinGW Getting Started](http://www.mingw.org/wiki/Getting_Started#toc5) guide, you should edit `C:\MinGW\msys\1.0\etc\fstab` to contain the following line:
|
||||
|
||||
```
|
||||
C:\MinGW /mingw
|
||||
```
|
||||
|
||||
### Starting a "MingGW" console
|
||||
|
||||
Create a batch file with this content:
|
||||
```bat
|
||||
@echo off
|
||||
set PATH=C:\MinGW\bin;%PATH%
|
||||
REM only needed if not already available
|
||||
set PATH=%PROGRAMFILES%\git\bin;%PATH%
|
||||
REM C:\MinGW\msys\1.0\msys.bat
|
||||
cmd
|
||||
```
|
||||
|
||||
Execute it and make sure these commands can be called: `git`, `mingw32-make`, `rm` and `gcc`! Once this is all set, you should be ready to compile `libsass`!
|
||||
|
||||
### Get the sources
|
||||
|
||||
```bash
|
||||
# using git is preferred
|
||||
git clone https://github.com/sass/libsass.git
|
||||
# only needed for sassc and/or testsuite
|
||||
git clone https://github.com/sass/sassc.git libsass/sassc
|
||||
git clone https://github.com/sass/sass-spec.git libsass/sass-spec
|
||||
```
|
||||
|
||||
### Decide for static or shared library
|
||||
|
||||
`libsass` can be built and linked as a `static` or as a `shared` library. The default is `static`. To change it you can set the `BUILD` environment variable:
|
||||
|
||||
```bat
|
||||
set BUILD="shared"
|
||||
```
|
||||
|
||||
### Compile the library
|
||||
```bash
|
||||
mingw32-make -C libsass
|
||||
```
|
||||
|
||||
### Results can be found in
|
||||
```bash
|
||||
$ ls libsass/lib
|
||||
libsass.a libsass.dll libsass.so
|
||||
```
|
||||
|
||||
### Run the spec test-suite
|
||||
```bash
|
||||
mingw32-make -C libsass test_build
|
||||
```
|
||||
|
||||
## Building via MingGW 64bit (makefiles)
|
||||
Building libass to dll on window 64bit.
|
||||
|
||||
Download [MinGW64 for windows7 64bit](http://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/4.9.2/threads-win32/seh/x86_64-4.9.2-release-win32-seh-rt_v3-rev0.7z/download) and unzip to "C:\mingw64".
|
||||
|
||||
Create a batch file with this content:
|
||||
|
||||
```bat
|
||||
@echo off
|
||||
set PATH=C:\mingw64\bin;%PATH%
|
||||
set CC=gcc
|
||||
REM only needed if not already available
|
||||
set PATH=%PROGRAMFILES%\Git\bin;%PATH%
|
||||
REM C:\MinGW\msys\1.0\msys.bat
|
||||
cmd
|
||||
```
|
||||
|
||||
By default, mingw64 dll will depends on "mingwm10.dll、 libgcc_s_dw2-1.dll", we can modify Makefile to fix this:(add "-static")
|
||||
|
||||
``` bash
|
||||
lib/libsass.dll: $(COBJECTS) $(OBJECTS) $(RCOBJECTS)
|
||||
$(MKDIR) lib
|
||||
$(CXX) -shared $(LDFLAGS) -o $@ $(COBJECTS) $(OBJECTS) $(RCOBJECTS) $(LDLIBS) -s -static -Wl,--subsystem,windows,--out-implib,lib/libsass.a
|
||||
```
|
||||
|
||||
Compile the library
|
||||
|
||||
```bash
|
||||
mingw32-make -C libsass
|
||||
```
|
||||
|
||||
By the way, if you are using java jna, [JNAerator](http://jnaerator.googlecode.com/) is a good tool.
|
||||
|
||||
[1]: http://sourceforge.net/projects/mingw/files/latest/download?source=files
|
||||
[2]: https://msysgit.github.io/
|
||||
[3]: http://rubyinstaller.org/
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
## Building LibSass with Visual Studio
|
||||
|
||||
### Requirements:
|
||||
|
||||
The minimum requirement to build LibSass with Visual Studio is "Visual Studio 2013 Express for Desktop".
|
||||
|
||||
Additionally, it is recommended to have `git` installed and available in `PATH`, so to deduce the `libsass` version information. For instance, if GitHub for Windows (https://windows.github.com/) is installed, the `PATH` will have an entry resembling: `X:\Users\<YOUR_NAME>\AppData\Local\GitHub\PortableGit_<SOME_GUID>\cmd\` (where `X` is the drive letter of system drive). If `git` is not available, inquiring the LibSass version will result in `[NA]`.
|
||||
|
||||
### Build Steps:
|
||||
|
||||
#### From Visual Studio:
|
||||
|
||||
On opening the `win\libsass.sln` solution and build (Ctrl+Shift+B) to build `libsass.dll`.
|
||||
|
||||
To Build LibSass as a static Library, it is recommended to set an environment variable `LIBSASS_STATIC_LIB` before launching the project:
|
||||
|
||||
```cmd
|
||||
cd path\to\libsass
|
||||
SET LIBSASS_STATIC_LIB=1
|
||||
::
|
||||
:: or in PowerShell:
|
||||
:: $env:LIBSASS_STATIC_LIB=1
|
||||
::
|
||||
win\libsass.sln
|
||||
```
|
||||
|
||||
Visual Studio will form the filtered source tree as shown below:
|
||||
|
||||

|
||||
|
||||
`Header Files` contains the .h and .hpp files, while `Source Files` covers `.c` and `.cpp`. The other used headers/sources will appear under `External Dependencies`.
|
||||
|
||||
If there is a LibSass code file appearing under External Dependencies, it can be changed by altering the `win\libsass.vcxproj.filters` file or dragging in Solution Explorer.
|
||||
|
||||
#### From Command Prompt:
|
||||
|
||||
Notice that in the following commands:
|
||||
|
||||
* If the platform is 32-bit Windows, replace `ProgramFiles(x86)` with `ProgramFiles`.
|
||||
* To build with Visual Studio 2015, replace `12.0` with `14.0` in the aforementioned command.
|
||||
|
||||
Open a command prompt:
|
||||
|
||||
To build dynamic/shared library (`libsass.dll`):
|
||||
|
||||
```cmd
|
||||
:: debug build:
|
||||
"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln
|
||||
|
||||
:: release build:
|
||||
"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln ^
|
||||
/p:Configuration=Release
|
||||
```
|
||||
|
||||
To build static library (`libsass.lib`):
|
||||
|
||||
```cmd
|
||||
:: debug build:
|
||||
"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln ^
|
||||
/p:LIBSASS_STATIC_LIB=1
|
||||
|
||||
:: release build:
|
||||
"%ProgramFiles(x86)%\MSBuild\12.0\Bin\MSBuild" win\libsass.sln ^
|
||||
/p:LIBSASS_STATIC_LIB=1 /p:Configuration=Release
|
||||
```
|
||||
|
||||
#### From PowerShell:
|
||||
|
||||
To build dynamic/shared library (`libsass.dll`):
|
||||
|
||||
```powershell
|
||||
# debug build:
|
||||
&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln
|
||||
|
||||
# release build:
|
||||
&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln `
|
||||
/p:Configuration=Release
|
||||
```
|
||||
|
||||
To build static library (`libsass.lib`):
|
||||
|
||||
```powershell
|
||||
# build:
|
||||
&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln `
|
||||
/p:LIBSASS_STATIC_LIB=1
|
||||
|
||||
# release build:
|
||||
&"${env:ProgramFiles(x86)}\MSBuild\12.0\Bin\MSBuild" win\libsass.sln `
|
||||
/p:LIBSASS_STATIC_LIB=1 /p:Configuration=Release
|
||||
```
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
`libsass` is only a library and does not do much on its own. You need an implementation that you can use from the [command line] [6]. Or some [[bindings|Implementations]] to use it within your favorite programming language. You should be able to get [`sassc`] [6] running by following the instructions in this guide.
|
||||
|
||||
Before starting, see [setup dev environment](setup-environment.md).
|
||||
|
||||
Building on different Operating Systems
|
||||
--
|
||||
|
||||
We try to keep the code as OS independent and standard compliant as possible. Reading files from the file-system has some OS depending code, but will ultimately fall back to a posix compatible implementation. We do use some `C++11` features, but are so far only committed to use `unordered_map`. This means you will need a pretty recent compiler on most systems (gcc 4.5 seems to be the minimum).
|
||||
|
||||
### Building on Linux (and other *nix flavors)
|
||||
|
||||
Linux is the main target for `libsass` and we support two ways to build `libsass` here. The old plain makefiles should still work on most systems (including MinGW), while the autotools build is preferred if you want to create a [system library] (experimental).
|
||||
|
||||
- [Building with makefiles] [1]
|
||||
- [Building with autotools] [2]
|
||||
|
||||
### Building on Windows (experimental)
|
||||
|
||||
Windows build support was added very recently and should be considered experimental. Credits go to @darrenkopp and @am11 for their work on getting `libsass` and `sassc` to compile with visual studio!
|
||||
|
||||
- [Building with MinGW] [3]
|
||||
- [Building with Visual Studio] [11]
|
||||
|
||||
### Building on Max OS X (untested)
|
||||
|
||||
Works the same as on linux, but you can also install LibSass via `homebrew`.
|
||||
|
||||
- [Building on Mac OS X] [10]
|
||||
|
||||
### Building a system library (experimental)
|
||||
|
||||
Since `libsass` is a library, it makes sense to install it as a shared library on your system. On linux this means creating a `.so` library via autotools. This should work pretty well already, but we are not yet committed to keep the ABI 100% stable. This should be the case once we increase the version number for the library to 1.0.0 or higher. On Windows you should be able get a `dll` by creating a shared build with MinGW. There is currently no target in the MSVC project files to do this.
|
||||
|
||||
- [Building shared system library] [4]
|
||||
|
||||
Compiling with clang instead of gcc
|
||||
--
|
||||
|
||||
To use clang you just need to set the appropriate environment variables:
|
||||
|
||||
```bash
|
||||
export CC=/usr/bin/clang
|
||||
export CXX=/usr/bin/clang++
|
||||
```
|
||||
|
||||
Running the spec test-suite
|
||||
--
|
||||
|
||||
We constantly and automatically test `libsass` against the official [spec test-suite] [5]. To do this we need to have a test-runner (which is written in ruby) and a command-line tool ([`sassc`] [6]) to run the tests. Therefore we need to additionally compile `sassc`. To do this, the build files of all three projects need to work together. This may not have the same quality for all build flavors. You definitely need to have ruby (2.1?) installed (version 1.9 seems to cause problems at least on windows). You also need some gems installed:
|
||||
|
||||
```bash
|
||||
ruby -v
|
||||
gem install minitest
|
||||
# should be optional
|
||||
gem install minitap
|
||||
```
|
||||
|
||||
Including the LibSass version
|
||||
--
|
||||
|
||||
There is a function in `libsass` to query the current version. This has to be defined at compile time. We use a C macro for this, which can be defined by calling `g++ -DLIBSASS_VERSION="\"x.y.z.\""`. The two quotes are necessary, since it needs to end up as a valid C string. Normally you do not need to do anything if you use the makefiles or autotools. They will try to fetch the version via git directly. If you only have the sources without the git repo, you can pass the version as an environment variable to `make` or `configure`:
|
||||
|
||||
```
|
||||
export LIBSASS_VERSION="x.y.z."
|
||||
```
|
||||
|
||||
Continuous Integration
|
||||
--
|
||||
|
||||
We use two CI services to automatically test all commits against the latest [spec test-suite] [5].
|
||||
|
||||
- [LibSass on Travis-CI (linux)][7]
|
||||
[](https://travis-ci.org/sass/libsass)
|
||||
- [LibSass on AppVeyor (windows)][8]
|
||||
[](https://ci.appveyor.com/project/mgreter/libsass-513/branch/master)
|
||||
|
||||
Why not using CMake?
|
||||
--
|
||||
|
||||
There were some efforts to get `libsass` to compile with CMake, which should make it easier to create build files for linux and windows. Unfortunately this was not completed. But we are certainly open for PRs!
|
||||
|
||||
Miscellaneous
|
||||
--
|
||||
|
||||
- [Ebuilds for Gentoo Linux](build-on-gentoo.md)
|
||||
|
||||
[1]: build-with-makefiles.md
|
||||
[2]: build-with-autotools.md
|
||||
[3]: build-with-mingw.md
|
||||
[4]: build-shared-library.md
|
||||
[5]: https://github.com/sass/sass-spec
|
||||
[6]: https://github.com/sass/sassc
|
||||
[7]: https://github.com/sass/libsass/blob/master/.travis.yml
|
||||
[8]: https://github.com/sass/libsass/blob/master/appveyor.yml
|
||||
[9]: implementations.md
|
||||
[10]: build-on-darwin.md
|
||||
[11]: build-with-visual-studio.md
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
This document is to serve as a living, changing plan for getting LibSass caught up with Ruby Sass.
|
||||
|
||||
_Note: an "s" preceeding a version number is specifying a Ruby Sass version. Without an s, it's a version of LibSass._
|
||||
|
||||
# Goal
|
||||
**Our goal is to reach full s3.4 compatibility as soon as possible. LibSass version 3.4 will behave just like Ruby Sass 3.4**
|
||||
|
||||
I highlight the goal, because there are some things that are *not* currently priorities. To be clear, they WILL be priorities, but they are not at the moment:
|
||||
|
||||
* Performance Improvements
|
||||
* Extensibility
|
||||
|
||||
The overriding goal is correctness.
|
||||
|
||||
## Verifying Correctness
|
||||
LibSass uses the spec for its testing. The spec was originally based off s3.2 tests. Many things have changed in Ruby Sass since then and some of the tests need to be updated and changed in order to get them to match both LibSass and Ruby Sass.
|
||||
|
||||
Until this project is complete, the spec will be primarily a place to test LibSass. By the time LibSass reaches 3.4, it is our goal that sass-spec will be fully usable as an official testing source for ALL implementations of Sass.
|
||||
|
||||
## Version Naming
|
||||
Until LibSass reaches parity with Ruby Sass, we will be aggressively bumping versions, and LibSass 3.4 will be the peer to Ruby Sass 3.4 in every way.
|
||||
|
||||
# Release Plan
|
||||
|
||||
## 3.0
|
||||
The goal of 3.0 is to introduce some of the most demanded features for LibSass. That is, we are focusing on issues and features that have kept adoption down. This is a mongrel release wrt which version of Sass it's targeting. It's often a mixture of 3.2 / 3.3 / 3.4 behaviours. This is not ideal, but it's favourable to not existing. Targeting 3.4 strictly during this release would mean we never actually release.
|
||||
|
||||
# 3.1
|
||||
The goal of 3.1 is to update all the passing specs to agree with 3.4. This will not be a complete representation of s3.4 (aka, there will me missing features), but the goal is to change existing features and implemented features to match 3.4 behaviour.
|
||||
|
||||
By the end of this, the sass-spec must pass against 3.4.
|
||||
|
||||
Major issues:
|
||||
* Variable Scoping
|
||||
* Color Handling
|
||||
* Precision
|
||||
|
||||
# 3.2
|
||||
This version will focus on edge case fixes. There are a LOT of edge cases in the _todo_ tests and this is the release where we hunt those down like dogs (not that we want to hurt dogs, it's just a figure of speech in English).
|
||||
|
||||
# 3.3
|
||||
Dress rehearsal. When we are 99% sure that we've fixed the main issues keeping us from saying we are compliant in s3.4 behaviour.
|
||||
|
||||
# 3.4
|
||||
Compass Compatibility. We need to be able to work with Compass and all the other libraries out there. At this point, we are calling LibSass "mature"
|
||||
|
||||
# Beyond 3.4
|
||||
Obviously, there is matching Sass 3.5 behaviour. But, beyond that, we'll want to focus on performance, stability, and error handling. These can always be improved upon and are the life's work of an open source project. We'll have to work closely with Sass in the future.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
First of all, welcome! Thanks for even reading this page. If you're here, you're probably wondering what you can do to help make the LibSass project even more awesome. And, even having that feeling means you are awesome!
|
||||
|
||||
## I'm a programmer
|
||||
|
||||
Awesome! We need your help. The best thing to do is go find issues that are tagged with both "bug" and "test written". We do spec driven development here and these issues have a test that's written already in the sass-spec project. Go find the test by going to sass-spec/spec/LibSass-todo-issues/issue_XXX/ where XXX is the issue number. Write the code, and compile, and then issue a pull request referencing the issue. We'll quickly verify it and get it merged in!
|
||||
|
||||
To get your dev environment setup, check out our article on [Setup-Dev-Environment](setup-environment.md).
|
||||
|
||||
## I'm not a backend programmer
|
||||
|
||||
COOL! We also need your help. Doing [Issue-Triage](triage.md) is a big deal and something we need constant help with. That means helping to verify issues, write tests for them, and make sure they are getting fixed. It's being part of the smiling face of the project.
|
||||
|
||||
Also, we need help with the Sass-Spec project itself. Just people to organize, refactor, and understand the tests in there.
|
||||
|
||||
## I don't know what a computer is?
|
||||
|
||||
Hmm.... well, it's the thing you are looking at right now. Ummm... check out training courses! Then, come back and join us!
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
# Developer Documentation
|
||||
|
||||
Custom functions are internally represented by `struct Sass_C_Function_Descriptor`.
|
||||
|
||||
## Sass_C_Function_Descriptor
|
||||
|
||||
```C
|
||||
struct Sass_C_Function_Descriptor {
|
||||
const char* signature;
|
||||
Sass_C_Function function;
|
||||
void* cookie;
|
||||
};
|
||||
```
|
||||
|
||||
- `signature`: The function declaration, like `foo($bar, $baz:1)`
|
||||
- `function`: Reference to the C function callback
|
||||
- `cookie`: any pointer you want to attach
|
||||
|
||||
### signature
|
||||
|
||||
The signature defines how the function can be invoked. It also declares which arguments are required and which are optional. Required arguments will be enforced by LibSass and a Sass error is thrown in the event a call as missing an argument. Optional arguments only need to be present when you want to overwrite the default value.
|
||||
|
||||
foo($bar, $baz: 2)
|
||||
|
||||
In this example, `$bar` is required and will error if not passed. `$baz` is optional and the default value of it is 2. A call like `foo(10)` is therefore equal to `foo(10, 2)`, while `foo()` will produce an error.
|
||||
|
||||
### function
|
||||
|
||||
The callback function needs to be of the following form:
|
||||
|
||||
```C
|
||||
union Sass_Value* call_sass_function(
|
||||
const union Sass_Value* s_args,
|
||||
void* cookie
|
||||
) {
|
||||
return sass_clone_value(s_args);
|
||||
}
|
||||
```
|
||||
|
||||
### cookie
|
||||
|
||||
The cookie can hold any pointer you want. In the `perl-libsass` implementation it holds the structure with the reference of the actual registered callback into the perl interpreter. Before that call `perl-libsass` will convert all `Sass_Values` to corresponding perl data types (so they can be used natively inside the perl interpretor). The callback can also return a `Sass_Value`. In `perl-libsass` the actual function returns a perl value, which has to be converted before `libsass` can work with it again!
|
||||
|
||||
## Sass_Values
|
||||
|
||||
```C
|
||||
// allocate memory (copies passed strings)
|
||||
union Sass_Value* make_sass_boolean (int val);
|
||||
union Sass_Value* make_sass_number (double val, const char* unit);
|
||||
union Sass_Value* make_sass_color (double r, double g, double b, double a);
|
||||
union Sass_Value* make_sass_string (const char* val);
|
||||
union Sass_Value* make_sass_list (size_t len, enum Sass_Separator sep);
|
||||
union Sass_Value* make_sass_map (size_t len);
|
||||
union Sass_Value* make_sass_null ();
|
||||
union Sass_Value* make_sass_error (const char* msg);
|
||||
|
||||
// Make a deep cloned copy of the given sass value
|
||||
union Sass_Value* sass_clone_value (const union Sass_Value* val);
|
||||
|
||||
// deallocate memory (incl. all copied memory)
|
||||
void sass_delete_value (const union Sass_Value* val);
|
||||
```
|
||||
|
||||
## Example main.c
|
||||
|
||||
```C
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "sass/context.h"
|
||||
|
||||
union Sass_Value* call_fn_foo(const union Sass_Value* s_args, void* cookie)
|
||||
{
|
||||
// we actually abuse the void* to store an "int"
|
||||
return sass_make_number((size_t)cookie, "px");
|
||||
}
|
||||
|
||||
int main( int argc, const char* argv[] )
|
||||
{
|
||||
|
||||
// get the input file from first argument or use default
|
||||
const char* input = argc > 1 ? argv[1] : "styles.scss";
|
||||
|
||||
// create the file context and get all related structs
|
||||
struct Sass_File_Context* file_ctx = sass_make_file_context(input);
|
||||
struct Sass_Context* ctx = sass_file_context_get_context(file_ctx);
|
||||
struct Sass_Options* ctx_opt = sass_context_get_options(ctx);
|
||||
|
||||
// allocate a custom function caller
|
||||
Sass_C_Function_Callback fn_foo =
|
||||
sass_make_function("foo()", call_fn_foo, (void*)42);
|
||||
|
||||
// create list of all custom functions
|
||||
Sass_C_Function_List fn_list = sass_make_function_list(1);
|
||||
sass_function_set_list_entry(fn_list, 0, fn_foo);
|
||||
sass_option_set_c_functions(ctx_opt, fn_list);
|
||||
|
||||
// context is set up, call the compile step now
|
||||
int status = sass_compile_file_context(file_ctx);
|
||||
|
||||
// print the result or the error to the stdout
|
||||
if (status == 0) puts(sass_context_get_output_string(ctx));
|
||||
else puts(sass_context_get_error_message(ctx));
|
||||
|
||||
// release allocated memory
|
||||
sass_delete_file_context(file_ctx);
|
||||
|
||||
// exit status
|
||||
return status;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## Compile main.c
|
||||
|
||||
```bash
|
||||
gcc -c main.c -o main.o
|
||||
gcc -o sample main.o -lsass
|
||||
echo "foo { margin: foo(); }" > foo.scss
|
||||
./sample foo.scss => "foo { margin: 42px }"
|
||||
```
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
There are several implementations of `libsass` for a variety of languages. Here are just a few of them. Note, some implementations may or may not be up to date. We have not verified whether they work.
|
||||
|
||||
### C
|
||||
* [sassc](https://github.com/hcatlin/sassc)
|
||||
|
||||
### Go
|
||||
* [go-libsass](https://github.com/wellington/go-libsass)
|
||||
* [go_sass](https://github.com/suapapa/go_sass)
|
||||
* [go-sass](https://github.com/SamWhited/go-sass)
|
||||
|
||||
### Lua
|
||||
* [lua-sass](https://github.com/craigbarnes/lua-sass)
|
||||
|
||||
### .NET
|
||||
* [libsass-net](https://github.com/darrenkopp/libsass-net)
|
||||
* [NSass](https://github.com/TBAPI-0KA/NSass)
|
||||
* [Sass.Net](https://github.com/andyalm/Sass.Net)
|
||||
|
||||
### node.js
|
||||
* [node-sass](https://github.com/andrew/node-sass)
|
||||
|
||||
### Java
|
||||
* [libsass-maven-plugin](https://github.com/warmuuh/libsass-maven-plugin)
|
||||
* [jsass](https://github.com/bit3/jsass)
|
||||
|
||||
### JavaScript
|
||||
* [sass.js](https://github.com/medialize/sass.js)
|
||||
|
||||
### Perl
|
||||
* [CSS::Sass](https://github.com/caldwell/CSS-Sass)
|
||||
* [Text::Sass::XS](https://github.com/ysasaki/Text-Sass-XS)
|
||||
|
||||
### PHP
|
||||
* [sassphp](https://github.com/sensational/sassphp)
|
||||
|
||||
### Python
|
||||
* [libsass-python](https://github.com/dahlia/libsass-python)
|
||||
* [SassPython](https://github.com/marianoguerra/SassPython)
|
||||
* [pylibsass](https://github.com/rsenk330/pylibsass)
|
||||
* [python-scss](https://github.com/pistolero/python-scss)
|
||||
|
||||
### Ruby
|
||||
* [sassruby](https://github.com/hcatlin/sassruby)
|
||||
|
||||
### Scala
|
||||
* [Sass-Scala](https://github.com/kkung/Sass-Scala)
|
||||
|
||||
### Tcl
|
||||
* [tclsass](https://github.com/flightaware/tclsass)
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
Plugins are shared object files (.so on *nix and .dll on win) that can be loaded by LibSass on runtime. Currently we only provide a way to load internal/custom functions from plugins. In the future we probably will also add a way to provide custom importers via plugins (needs more refactoring to [support multiple importers with some kind of priority system](https://github.com/sass/libsass/issues/962)).
|
||||
|
||||
## plugin.cpp
|
||||
|
||||
```C++
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <stdint.h>
|
||||
#include "sass_values.h"
|
||||
|
||||
union Sass_Value* ADDCALL call_fn_foo(const union Sass_Value* s_args, void* cookie)
|
||||
{
|
||||
// we actually abuse the void* to store an "int"
|
||||
return sass_make_number((intptr_t)cookie, "px");
|
||||
}
|
||||
|
||||
extern "C" const char* ADDCALL libsass_get_version() {
|
||||
return libsass_version();
|
||||
}
|
||||
|
||||
extern "C" Sass_C_Function_List ADDCALL libsass_load_functions()
|
||||
{
|
||||
// allocate a custom function caller
|
||||
Sass_C_Function_Callback fn_foo =
|
||||
sass_make_function("foo()", call_fn_foo, (void*)42);
|
||||
// create list of all custom functions
|
||||
Sass_C_Function_List fn_list = sass_make_function_list(1);
|
||||
// put the only function in this plugin to the list
|
||||
sass_function_set_list_entry(fn_list, 0, fn_foo);
|
||||
// return the list
|
||||
return fn_list;
|
||||
}
|
||||
```
|
||||
|
||||
To compile the plugin you need to have LibSass already built as a shared library (to link against it). The commands below expect the shared library in the `lib` sub-directory (`-Llib`). The plugin and the main LibSass process should "consume" the same shared LibSass library on runtime. It will propably also work if they use different LibSass versions. In this case we check if the major versions are compatible (i.e. 3.1.3 and 3.1.1 would be considered compatible).
|
||||
|
||||
## Compile with gcc on linux
|
||||
|
||||
```bash
|
||||
g++ -O2 -shared plugin.cpp -o plugin.so -fPIC -Llib -lsass
|
||||
```
|
||||
|
||||
## Compile with mingw on windows
|
||||
|
||||
```bash
|
||||
g++ -O2 -shared plugin.cpp -o plugin.dll -Llib -lsass
|
||||
```
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
## Requirements
|
||||
In order to install and setup your local development environment, there are some prerequisites:
|
||||
|
||||
* git
|
||||
* gcc/clang/llvm (Linux: build tools, Mac OS X: XCode w/ Command Line Tools)
|
||||
* ruby w/ bundler
|
||||
|
||||
OS X:
|
||||
First you'll need to install XCode which you can now get from the AppStore installed on your mac. After you download that and run it, then run this on the command line:
|
||||
|
||||
````
|
||||
xcode-select --install
|
||||
````
|
||||
|
||||
## Cloning the Projects
|
||||
|
||||
First, clone the project and then add a line to your `~/.bash_profile` that will let other programs know where the LibSass dev files are.
|
||||
|
||||
````
|
||||
git clone git@github.com:sass/libsass.git
|
||||
cd libsass
|
||||
echo "export SASS_LIBSASS_PATH=$(pwd)" >> ~/.bash_profile
|
||||
|
||||
````
|
||||
|
||||
Then, if you run the "bootstrap" script, it should clone all the other required projects.
|
||||
|
||||
````
|
||||
./script/bootstrap
|
||||
````
|
||||
|
||||
You should now have a `sass-spec` and `sassc` folder within the libsass folder. Both of these are clones of their respective git projects. If you want to do a pull request, remember to work in those folders. For instance, if you want to add a test (see other documentation for how to do that), make sure to commit it to your *fork* of the sass-spec github project. Also, whenever you are running tests, make sure to `pull` from the origin! We want to make sure we are testing against the newest libsass, sassc, and sass-spec!
|
||||
|
||||
Now, try and see if you can build the project. We do that with the `make` command.
|
||||
|
||||
````
|
||||
make
|
||||
````
|
||||
|
||||
At this point, if you get an error, something is most likely wrong with your compiler installation. Yikes. It's hard to cover how to fix this in an article. Feel free to open an issue and we'll try and help! But, remember, before you do that, googling the error message is your friend! Many problems are solved quickly that way.
|
||||
|
||||
## Running The Spec Against LibSass
|
||||
|
||||
Then, to run the spec against LibSass, just run:
|
||||
|
||||
````
|
||||
./script/spec
|
||||
````
|
||||
|
||||
If you get an error about `SASS_LIBSASS_PATH`, you may still need to set a variable pointing to the libsass folder, like this:
|
||||
|
||||
````
|
||||
export SASS_LIBSASS_PATH=/Users/you/path/libsass
|
||||
````
|
||||
|
||||
...where the latter part is to the `libsass` directory you've cloned. You can get this path by typing `pwd` in the Terminal
|
||||
|
||||
## Running the Spec Against Ruby Sass
|
||||
|
||||
Go into the sass-spec folder that should have been cloned earlier with the "bootstrap" command. Run the following.
|
||||
|
||||
````
|
||||
bundle install
|
||||
./sass-spec.rb
|
||||
````
|
||||
|
||||
Voila! Now you are testing against Sass too!
|
||||
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
This document is mainly intended for developers!
|
||||
|
||||
# Documenting some of the source map internals
|
||||
|
||||
Since source maps are somewhat a black box to all LibSass maintainers, [I](@mgreter) will try to document my findings with source maps in LibSass, as I come across them. This document will also brievely explain how LibSass parses the source and how it outputs the result.
|
||||
|
||||
The main storage for SourceMap mappings is the `mappings` vector:
|
||||
|
||||
```
|
||||
# in source_map.hpp
|
||||
vector<Mapping> mappings
|
||||
# in mappings.hpp
|
||||
struct Mapping ...
|
||||
Position original_position;
|
||||
Position generated_position;
|
||||
```
|
||||
|
||||
## Every parsed token has its source associated
|
||||
|
||||
LibSass uses a lexical parser. Whenever LibSass finds a token of interest, it creates a specific `AST_Node`, which will hold a reference to the input source with line/column information. `AST_Node` is the base class for all parsed items. They are declared in `ast.hpp` and are used in `parser.hpp`. Here a simple example:
|
||||
|
||||
```
|
||||
if (lex< custom_property_name >()) {
|
||||
Sass::String* prop = new (ctx.mem) String_Constant(path, source_position, lexed);
|
||||
return new (ctx.mem) Declaration(path, prop->position(), prop, ...);
|
||||
}
|
||||
```
|
||||
|
||||
## How is the `source_position` calculated
|
||||
|
||||
This is automatically done with `lex` in `parser.hpp`. Whenever something is lexed, the `source_position` is updated. But be aware that `source_position` points to the begining of the parsed text. If you need a mapping for the position where the parsing ended, you need to add another call to `lex` (to match nothing)!
|
||||
|
||||
```
|
||||
lex< exactly < empty_str > >();
|
||||
end = new (ctx.mem) String_Constant(path, source_position, lexed);
|
||||
```
|
||||
|
||||
## How are mappings for the output created
|
||||
|
||||
So far we have collected all needed data for all tokens in the input stream. We can now use this information to create mappings when we put things into the output stream. Mappings are created via the `add_mappings` method:
|
||||
|
||||
```
|
||||
# in source_map.hpp
|
||||
void add_mapping(AST_Node* node);
|
||||
```
|
||||
|
||||
This method is called in two places:
|
||||
- `Inspect::append_to_buffer`
|
||||
- `Output_[Nested|Compressed]::append_to_buffer`
|
||||
|
||||
Mappings can only be created for things that have been parsed into a `AST_Node`. Otherwise we do not have the information to create the mappings, which is the reason why LibSass currently only maps the most important tokens in source maps.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
## This is proposed interface in https://github.com/sass/libsass/pull/1288
|
||||
|
||||
Additional debugging macros with low overhead are available, `TRACE()` and `TRACEINST()`.
|
||||
|
||||
Both macros simulate a string stream, so they can be used like this:
|
||||
|
||||
TRACE() << "Reached.";
|
||||
|
||||
produces:
|
||||
|
||||
[LibSass] parse_value parser.cpp:1384 Reached.
|
||||
|
||||
`TRACE()`
|
||||
logs function name, source filename, source file name to the standard error and the attached
|
||||
stream to the standard error.
|
||||
|
||||
`TRACEINST(obj)`
|
||||
logs object instance address, function name, source filename, source file name to the standard error and the attached stream to the standard error, for example:
|
||||
|
||||
TRACEINST(this) << "String_Constant created " << this;
|
||||
|
||||
produces:
|
||||
|
||||
[LibSass] 0x8031ba980:String_Constant ./ast.hpp:1371 String_Constant created (0,"auto")
|
||||
|
||||
The macros generate output only of `LibSass_TRACE` is set in the environment.
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
This is an article about how to help with LibSass issues. Issue triage is a fancy word for explaining how we deal with incoming issues and make sure that the right problems get worked on. The lifecycle of an issue goes like this:
|
||||
|
||||
1. Issue is reported by a user.
|
||||
2. If the issue seems like a bug, then the "bug" tag is added.
|
||||
3. If the reporting user didn't also create a spec test over at sass/sass-spec, the "needs test" tag is added.
|
||||
4. Verify that Ruby Sass *does not* have the same bug. LibSass strives to be an exact replica of how Ruby Sass works. If it's an issue that neither project has solved, please close the ticket with the "not in sass" label.
|
||||
5. The smallest possible breaking test is created in sass-spec. Cut away any extra information or non-breaking code until the core issue is made clear.
|
||||
6. Again, verify that the expected output matches the latest Ruby Sass release. Do this by using your own tool OR by running ./sass-spec.rb in the spec folder and making sure that your test passes!
|
||||
7. Create the test cases in sass-spec with the name spec/LibSass-todo-issues/issue_XXX/input.scss and expected_output.css where the XXX is the issue number here.
|
||||
8. Commit that test to sass-spec, making sure to reference the issue in the comment message like "Test to demonstrate sass/LibSass#XXX".
|
||||
9. Once the spec test exists, remove the "needs test" tag and replace it with "test written".
|
||||
10. A C++ developer will then work on the issue and issue a pull request to fix the issue.
|
||||
11. A core member verifies that the fix does actually fix the spec tests.
|
||||
12. The fix is merged into the project.
|
||||
13. The spec is moved from the LibSass-todo-issues folder into LibSass-closed-issues
|
||||
14. The issue is closed
|
||||
15. Have a soda pop or enjoyable beverage of your choice
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
LibSass currently expects all input to be utf8 encoded (and outputs only utf8), if you actually have any unicode characters at all. We do not support conversion between encodings, even if you declare it with a `@charset` rule. The text below was originally posted as an [issue](https://github.com/sass/libsass/issues/381) on the LibSass tracker.
|
||||
|
||||
### [Declaring character encodings in CSS](http://www.w3.org/International/questions/qa-css-charset.en)
|
||||
|
||||
This [explains](http://www.w3.org/International/questions/qa-css-charset.en) how the character encoding of a css file is determined. Since we are only dealing with local files, we never have a HTTP header. So the precedence should be 'charset' rule, byte-order mark (BOM) or auto-detection (finally falling back to system default/UTF-8). This may not sound too hard to implement, but what about import rules? The CSS specs do not forbid the mixing of different encodings! I solved that by converting all files to UTF-8 internally. On writing there is an option to tell the tool what encoding it should be (UTF-8 by default). One can also define if it should write a BOM or not and if it should add the charset declaration.
|
||||
|
||||
Since my tool is written in perl, I have a lot of utilities at hand to deal with different unicode charsets. I'm pretty sure that most OSS uses [libiconv](https://www.gnu.org/software/libiconv/) to convert between different encodings. But I have now idea how easy/hard this would be to integrate platform independent (it seems doable).
|
||||
|
||||
### Current status on LibSass unicode support
|
||||
|
||||
Currently LibSass seems to handle the common UTF-8 case pretty well. I believe it should correctly support all ASCII compatible encodings (like UTF-8 or Latin-1). If all includes use the same encoding, the output should be correct (in the same encoding). It should also handle unicode chars in [selectors, variable names and other identifiers](https://github.com/hcatlin/libsass/issues/244#issuecomment-34681227). This is true for all ASCII compatible encodings. So the main incompatible encodings (I'm aware of) are UTF-16/UTF-32 (which could be converted to UTF-8 with libiconv).
|
||||
|
||||
### Current encoding auto detection
|
||||
|
||||
LibSass currently reads all kind of BOMs and will error out if it finds something it doesn't know how to handle! It seems that it throws away the optional UTF-8 BOM (if any is found). IMO it would be nice if users could configure that (also if a charset rule should be added to the output).
|
||||
|
||||
### What is currently not supported
|
||||
|
||||
- Using non ASCII compatible encodings (like UTF-16)
|
||||
- Using non ASCII characters in different encodings in different includes
|
||||
|
||||
### What is missing to support the above cases
|
||||
|
||||
- A way to convert between encodings (like libiconv)
|
||||
- Sniffing the charset inside the file (source is available)
|
||||
- Handling the conversion on import (and export)
|
||||
- Optional: Make output encoding configurable
|
||||
- Optional: Add optional/mandatory BOM (configurable)
|
||||
|
||||
### Low priority feature
|
||||
|
||||
I guess the current implementation should handle more than 99% of all real world use cases.
|
||||
A) Unicode characters are still seldomly seen (as they can be written escaped)
|
||||
B) It will still work if it's UTF-8 or in any of the most common known western ISO codepages.
|
||||
Although I'm not sure how this applies to asian and other "exotic" codepages!
|
||||
|
||||
I guess the biggest Problem is to have libiconv (or some other) library as a dependency. Since it contains a lot of rules for the conversions, I see it as the only way to handle this correctly. Once that is sorted out it should be pretty much straight forward to implement the missing pieces (in parser.cpp - Parser::parse should return encoding and add Parser::sniff_charset, then convert the source byte stream to UTF-8).
|
||||
|
||||
I hope the statements above all hold true. Unicode is really not the easiest topic to wrap your head around. But since I did all the above recently in Perl, I wanted to document it here. Feel free to extend or criticize.
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
require 'mkmf'
|
||||
# .. more stuff
|
||||
#$LIBPATH.push(Config::CONFIG['libdir'])
|
||||
$CFLAGS << " #{ENV["CFLAGS"]}"
|
||||
$LIBS << " #{ENV["LIBS"]}"
|
||||
create_makefile("libsass")
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#ifndef SASS_H
|
||||
#define SASS_H
|
||||
|
||||
// #define DEBUG 1
|
||||
|
||||
// include API headers
|
||||
#include <sass/base.h>
|
||||
#include <sass/version.h>
|
||||
#include <sass/values.h>
|
||||
#include <sass/functions.h>
|
||||
#include <sass/context.h>
|
||||
#include <sass2scss.h>
|
||||
|
||||
#endif
|
||||
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
#ifndef SASS_BASE_H
|
||||
#define SASS_BASE_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable : 4503)
|
||||
#ifndef _SCL_SECURE_NO_WARNINGS
|
||||
#define _SCL_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#ifndef _CRT_SECURE_NO_WARNINGS
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif
|
||||
#ifndef _CRT_NONSTDC_NO_DEPRECATE
|
||||
#define _CRT_NONSTDC_NO_DEPRECATE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define DEPRECATED(func) func __attribute__ ((deprecated))
|
||||
#elif defined(_MSC_VER)
|
||||
#define DEPRECATED(func) __declspec(deprecated) func
|
||||
#else
|
||||
#pragma message("WARNING: You need to implement DEPRECATED for this compiler")
|
||||
#define DEPRECATED(func) func
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* You should define ADD_EXPORTS *only* when building the DLL. */
|
||||
#ifdef ADD_EXPORTS
|
||||
#define ADDAPI __declspec(dllexport)
|
||||
#define ADDCALL __cdecl
|
||||
#else
|
||||
#define ADDAPI
|
||||
#define ADDCALL
|
||||
#endif
|
||||
|
||||
#else /* _WIN32 not defined. */
|
||||
|
||||
/* Define with no value on non-Windows OSes. */
|
||||
#define ADDAPI
|
||||
#define ADDCALL
|
||||
|
||||
#endif
|
||||
|
||||
/* Make sure functions are exported with C linkage under C++ compilers. */
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Different render styles
|
||||
enum Sass_Output_Style {
|
||||
SASS_STYLE_NESTED,
|
||||
SASS_STYLE_EXPANDED,
|
||||
SASS_STYLE_COMPACT,
|
||||
SASS_STYLE_COMPRESSED,
|
||||
// only used internaly
|
||||
SASS_STYLE_INSPECT,
|
||||
SASS_STYLE_TO_SASS
|
||||
};
|
||||
|
||||
// to allocate buffer to be filled
|
||||
void* sass_alloc_memory(size_t size);
|
||||
// to allocate a buffer from existing string
|
||||
char* sass_copy_c_string(const char* str);
|
||||
// to free overtaken memory when done
|
||||
void sass_free_memory(void* ptr);
|
||||
|
||||
// Some convenient string helper function
|
||||
ADDAPI char* ADDCALL sass_string_quote (const char* str, const char quote_mark);
|
||||
ADDAPI char* ADDCALL sass_string_unquote (const char* str);
|
||||
|
||||
// Resolve a file via the given include paths in the include char* array
|
||||
ADDAPI char* ADDCALL sass_resolve_file (const char* path, const char* incs[]);
|
||||
|
||||
// Get compiled libsass version
|
||||
ADDAPI const char* ADDCALL libsass_version(void);
|
||||
|
||||
// Get compiled libsass language
|
||||
ADDAPI const char* ADDCALL libsass_language_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+152
@@ -0,0 +1,152 @@
|
||||
#ifndef SASS_C_CONTEXT_H
|
||||
#define SASS_C_CONTEXT_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <sass/base.h>
|
||||
#include <sass/values.h>
|
||||
#include <sass/functions.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Forward declaration
|
||||
struct Sass_Compiler;
|
||||
|
||||
// Forward declaration
|
||||
struct Sass_Options; // base struct
|
||||
struct Sass_Context; // : Sass_Options
|
||||
struct Sass_File_Context; // : Sass_Context
|
||||
struct Sass_Data_Context; // : Sass_Context
|
||||
|
||||
// Compiler states
|
||||
enum Sass_Compiler_State {
|
||||
SASS_COMPILER_CREATED,
|
||||
SASS_COMPILER_PARSED,
|
||||
SASS_COMPILER_EXECUTED
|
||||
};
|
||||
|
||||
// Create and initialize an option struct
|
||||
ADDAPI struct Sass_Options* ADDCALL sass_make_options (void);
|
||||
// Create and initialize a specific context
|
||||
ADDAPI struct Sass_File_Context* ADDCALL sass_make_file_context (const char* input_path);
|
||||
ADDAPI struct Sass_Data_Context* ADDCALL sass_make_data_context (char* source_string);
|
||||
|
||||
// Call the compilation step for the specific context
|
||||
ADDAPI int ADDCALL sass_compile_file_context (struct Sass_File_Context* ctx);
|
||||
ADDAPI int ADDCALL sass_compile_data_context (struct Sass_Data_Context* ctx);
|
||||
|
||||
// Create a sass compiler instance for more control
|
||||
ADDAPI struct Sass_Compiler* ADDCALL sass_make_file_compiler (struct Sass_File_Context* file_ctx);
|
||||
ADDAPI struct Sass_Compiler* ADDCALL sass_make_data_compiler (struct Sass_Data_Context* data_ctx);
|
||||
|
||||
// Execute the different compilation steps individually
|
||||
// Usefull if you only want to query the included files
|
||||
ADDAPI int ADDCALL sass_compiler_parse(struct Sass_Compiler* compiler);
|
||||
ADDAPI int ADDCALL sass_compiler_execute(struct Sass_Compiler* compiler);
|
||||
|
||||
// Release all memory allocated with the compiler
|
||||
// This does _not_ include any contexts or options
|
||||
ADDAPI void ADDCALL sass_delete_compiler(struct Sass_Compiler* compiler);
|
||||
|
||||
// Release all memory allocated and also ourself
|
||||
ADDAPI void ADDCALL sass_delete_file_context (struct Sass_File_Context* ctx);
|
||||
ADDAPI void ADDCALL sass_delete_data_context (struct Sass_Data_Context* ctx);
|
||||
|
||||
// Getters for context from specific implementation
|
||||
ADDAPI struct Sass_Context* ADDCALL sass_file_context_get_context (struct Sass_File_Context* file_ctx);
|
||||
ADDAPI struct Sass_Context* ADDCALL sass_data_context_get_context (struct Sass_Data_Context* data_ctx);
|
||||
|
||||
// Getters for Context_Options from Sass_Context
|
||||
ADDAPI struct Sass_Options* ADDCALL sass_context_get_options (struct Sass_Context* ctx);
|
||||
ADDAPI struct Sass_Options* ADDCALL sass_file_context_get_options (struct Sass_File_Context* file_ctx);
|
||||
ADDAPI struct Sass_Options* ADDCALL sass_data_context_get_options (struct Sass_Data_Context* data_ctx);
|
||||
ADDAPI void ADDCALL sass_file_context_set_options (struct Sass_File_Context* file_ctx, struct Sass_Options* opt);
|
||||
ADDAPI void ADDCALL sass_data_context_set_options (struct Sass_Data_Context* data_ctx, struct Sass_Options* opt);
|
||||
|
||||
|
||||
// Getters for Context_Option values
|
||||
ADDAPI int ADDCALL sass_option_get_precision (struct Sass_Options* options);
|
||||
ADDAPI enum Sass_Output_Style ADDCALL sass_option_get_output_style (struct Sass_Options* options);
|
||||
ADDAPI bool ADDCALL sass_option_get_source_comments (struct Sass_Options* options);
|
||||
ADDAPI bool ADDCALL sass_option_get_source_map_embed (struct Sass_Options* options);
|
||||
ADDAPI bool ADDCALL sass_option_get_source_map_contents (struct Sass_Options* options);
|
||||
ADDAPI bool ADDCALL sass_option_get_omit_source_map_url (struct Sass_Options* options);
|
||||
ADDAPI bool ADDCALL sass_option_get_is_indented_syntax_src (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_indent (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_linefeed (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_input_path (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_output_path (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_plugin_path (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_include_path (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_source_map_file (struct Sass_Options* options);
|
||||
ADDAPI const char* ADDCALL sass_option_get_source_map_root (struct Sass_Options* options);
|
||||
ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_headers (struct Sass_Options* options);
|
||||
ADDAPI Sass_Importer_List ADDCALL sass_option_get_c_importers (struct Sass_Options* options);
|
||||
ADDAPI Sass_Function_List ADDCALL sass_option_get_c_functions (struct Sass_Options* options);
|
||||
|
||||
// Setters for Context_Option values
|
||||
ADDAPI void ADDCALL sass_option_set_precision (struct Sass_Options* options, int precision);
|
||||
ADDAPI void ADDCALL sass_option_set_output_style (struct Sass_Options* options, enum Sass_Output_Style output_style);
|
||||
ADDAPI void ADDCALL sass_option_set_source_comments (struct Sass_Options* options, bool source_comments);
|
||||
ADDAPI void ADDCALL sass_option_set_source_map_embed (struct Sass_Options* options, bool source_map_embed);
|
||||
ADDAPI void ADDCALL sass_option_set_source_map_contents (struct Sass_Options* options, bool source_map_contents);
|
||||
ADDAPI void ADDCALL sass_option_set_omit_source_map_url (struct Sass_Options* options, bool omit_source_map_url);
|
||||
ADDAPI void ADDCALL sass_option_set_is_indented_syntax_src (struct Sass_Options* options, bool is_indented_syntax_src);
|
||||
ADDAPI void ADDCALL sass_option_set_indent (struct Sass_Options* options, const char* indent);
|
||||
ADDAPI void ADDCALL sass_option_set_linefeed (struct Sass_Options* options, const char* linefeed);
|
||||
ADDAPI void ADDCALL sass_option_set_input_path (struct Sass_Options* options, const char* input_path);
|
||||
ADDAPI void ADDCALL sass_option_set_output_path (struct Sass_Options* options, const char* output_path);
|
||||
ADDAPI void ADDCALL sass_option_set_plugin_path (struct Sass_Options* options, const char* plugin_path);
|
||||
ADDAPI void ADDCALL sass_option_set_include_path (struct Sass_Options* options, const char* include_path);
|
||||
ADDAPI void ADDCALL sass_option_set_source_map_file (struct Sass_Options* options, const char* source_map_file);
|
||||
ADDAPI void ADDCALL sass_option_set_source_map_root (struct Sass_Options* options, const char* source_map_root);
|
||||
ADDAPI void ADDCALL sass_option_set_c_headers (struct Sass_Options* options, Sass_Importer_List c_headers);
|
||||
ADDAPI void ADDCALL sass_option_set_c_importers (struct Sass_Options* options, Sass_Importer_List c_importers);
|
||||
ADDAPI void ADDCALL sass_option_set_c_functions (struct Sass_Options* options, Sass_Function_List c_functions);
|
||||
|
||||
|
||||
// Getters for Sass_Context values
|
||||
ADDAPI const char* ADDCALL sass_context_get_output_string (struct Sass_Context* ctx);
|
||||
ADDAPI int ADDCALL sass_context_get_error_status (struct Sass_Context* ctx);
|
||||
ADDAPI const char* ADDCALL sass_context_get_error_json (struct Sass_Context* ctx);
|
||||
ADDAPI const char* ADDCALL sass_context_get_error_text (struct Sass_Context* ctx);
|
||||
ADDAPI const char* ADDCALL sass_context_get_error_message (struct Sass_Context* ctx);
|
||||
ADDAPI const char* ADDCALL sass_context_get_error_file (struct Sass_Context* ctx);
|
||||
ADDAPI const char* ADDCALL sass_context_get_error_src (struct Sass_Context* ctx);
|
||||
ADDAPI size_t ADDCALL sass_context_get_error_line (struct Sass_Context* ctx);
|
||||
ADDAPI size_t ADDCALL sass_context_get_error_column (struct Sass_Context* ctx);
|
||||
ADDAPI const char* ADDCALL sass_context_get_source_map_string (struct Sass_Context* ctx);
|
||||
ADDAPI char** ADDCALL sass_context_get_included_files (struct Sass_Context* ctx);
|
||||
|
||||
// Calculate the size of the stored null terminated array
|
||||
ADDAPI size_t ADDCALL sass_context_get_included_files_size (struct Sass_Context* ctx);
|
||||
|
||||
// Take ownership of memory (value on context is set to 0)
|
||||
ADDAPI char* ADDCALL sass_context_take_error_json (struct Sass_Context* ctx);
|
||||
ADDAPI char* ADDCALL sass_context_take_error_text (struct Sass_Context* ctx);
|
||||
ADDAPI char* ADDCALL sass_context_take_error_message (struct Sass_Context* ctx);
|
||||
ADDAPI char* ADDCALL sass_context_take_error_file (struct Sass_Context* ctx);
|
||||
ADDAPI char* ADDCALL sass_context_take_output_string (struct Sass_Context* ctx);
|
||||
ADDAPI char* ADDCALL sass_context_take_source_map_string (struct Sass_Context* ctx);
|
||||
ADDAPI char** ADDCALL sass_context_take_included_files (struct Sass_Context* ctx);
|
||||
|
||||
// Getters for Sass_Compiler options
|
||||
ADDAPI enum Sass_Compiler_State ADDCALL sass_compiler_get_state(struct Sass_Compiler* compiler);
|
||||
ADDAPI struct Sass_Context* ADDCALL sass_compiler_get_context(struct Sass_Compiler* compiler);
|
||||
ADDAPI struct Sass_Options* ADDCALL sass_compiler_get_options(struct Sass_Compiler* compiler);
|
||||
ADDAPI size_t ADDCALL sass_compiler_get_import_stack_size(struct Sass_Compiler* compiler);
|
||||
ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_last_import(struct Sass_Compiler* compiler);
|
||||
ADDAPI Sass_Import_Entry ADDCALL sass_compiler_get_import_entry(struct Sass_Compiler* compiler, size_t idx);
|
||||
|
||||
// Push function for paths (no manipulation support for now)
|
||||
ADDAPI void ADDCALL sass_option_push_plugin_path (struct Sass_Options* options, const char* path);
|
||||
ADDAPI void ADDCALL sass_option_push_include_path (struct Sass_Options* options, const char* path);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
#ifndef SASS_C_FUNCTIONS_H
|
||||
#define SASS_C_FUNCTIONS_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <sass/base.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Forward declaration
|
||||
struct Sass_Import;
|
||||
struct Sass_Options;
|
||||
struct Sass_Compiler;
|
||||
struct Sass_Importer;
|
||||
struct Sass_Function;
|
||||
|
||||
// Typedef helpers for import lists
|
||||
typedef struct Sass_Import (*Sass_Import_Entry);
|
||||
typedef struct Sass_Import* (*Sass_Import_List);
|
||||
// Typedef helpers for custom importer lists
|
||||
typedef struct Sass_Importer (*Sass_Importer_Entry);
|
||||
typedef struct Sass_Importer* (*Sass_Importer_List);
|
||||
// Typedef defining importer signature and return type
|
||||
typedef Sass_Import_List (*Sass_Importer_Fn)
|
||||
(const char* url, Sass_Importer_Entry cb, struct Sass_Compiler* compiler);
|
||||
|
||||
// Typedef helpers for custom functions lists
|
||||
typedef struct Sass_Function (*Sass_Function_Entry);
|
||||
typedef struct Sass_Function* (*Sass_Function_List);
|
||||
// Typedef defining function signature and return type
|
||||
typedef union Sass_Value* (*Sass_Function_Fn)
|
||||
(const union Sass_Value*, Sass_Function_Entry cb, struct Sass_Compiler* compiler);
|
||||
|
||||
|
||||
// Creator for sass custom importer return argument list
|
||||
ADDAPI Sass_Importer_List ADDCALL sass_make_importer_list (size_t length);
|
||||
ADDAPI Sass_Importer_Entry ADDCALL sass_importer_get_list_entry (Sass_Importer_List list, size_t idx);
|
||||
ADDAPI void ADDCALL sass_importer_set_list_entry (Sass_Importer_List list, size_t idx, Sass_Importer_Entry entry);
|
||||
|
||||
|
||||
// Creators for custom importer callback (with some additional pointer)
|
||||
// The pointer is mostly used to store the callback into the actual binding
|
||||
ADDAPI Sass_Importer_Entry ADDCALL sass_make_importer (Sass_Importer_Fn importer, double priority, void* cookie);
|
||||
|
||||
// Getters for import function descriptors
|
||||
ADDAPI Sass_Importer_Fn ADDCALL sass_importer_get_function (Sass_Importer_Entry cb);
|
||||
ADDAPI double ADDCALL sass_importer_get_priority (Sass_Importer_Entry cb);
|
||||
ADDAPI void* ADDCALL sass_importer_get_cookie (Sass_Importer_Entry cb);
|
||||
|
||||
// Deallocator for associated memory
|
||||
ADDAPI void ADDCALL sass_delete_importer (Sass_Importer_Entry cb);
|
||||
|
||||
// Creator for sass custom importer return argument list
|
||||
ADDAPI Sass_Import_List ADDCALL sass_make_import_list (size_t length);
|
||||
// Creator for a single import entry returned by the custom importer inside the list
|
||||
ADDAPI Sass_Import_Entry ADDCALL sass_make_import_entry (const char* path, char* source, char* srcmap);
|
||||
ADDAPI Sass_Import_Entry ADDCALL sass_make_import (const char* imp_path, const char* abs_base, char* source, char* srcmap);
|
||||
// set error message to abort import and to print out a message (path from existing object is used in output)
|
||||
ADDAPI Sass_Import_Entry ADDCALL sass_import_set_error(Sass_Import_Entry import, const char* message, size_t line, size_t col);
|
||||
|
||||
// Setters to insert an entry into the import list (you may also use [] access directly)
|
||||
// Since we are dealing with pointers they should have a guaranteed and fixed size
|
||||
ADDAPI void ADDCALL sass_import_set_list_entry (Sass_Import_List list, size_t idx, Sass_Import_Entry entry);
|
||||
ADDAPI Sass_Import_Entry ADDCALL sass_import_get_list_entry (Sass_Import_List list, size_t idx);
|
||||
|
||||
// Getters for import entry
|
||||
ADDAPI const char* ADDCALL sass_import_get_imp_path (Sass_Import_Entry);
|
||||
ADDAPI const char* ADDCALL sass_import_get_abs_path (Sass_Import_Entry);
|
||||
ADDAPI const char* ADDCALL sass_import_get_source (Sass_Import_Entry);
|
||||
ADDAPI const char* ADDCALL sass_import_get_srcmap (Sass_Import_Entry);
|
||||
// Explicit functions to take ownership of these items
|
||||
// The property on our struct will be reset to NULL
|
||||
ADDAPI char* ADDCALL sass_import_take_source (Sass_Import_Entry);
|
||||
ADDAPI char* ADDCALL sass_import_take_srcmap (Sass_Import_Entry);
|
||||
// Getters from import error entry
|
||||
ADDAPI size_t ADDCALL sass_import_get_error_line (Sass_Import_Entry);
|
||||
ADDAPI size_t ADDCALL sass_import_get_error_column (Sass_Import_Entry);
|
||||
ADDAPI const char* ADDCALL sass_import_get_error_message (Sass_Import_Entry);
|
||||
|
||||
// Deallocator for associated memory (incl. entries)
|
||||
ADDAPI void ADDCALL sass_delete_import_list (Sass_Import_List);
|
||||
// Just in case we have some stray import structs
|
||||
ADDAPI void ADDCALL sass_delete_import (Sass_Import_Entry);
|
||||
|
||||
|
||||
|
||||
// Creators for sass function list and function descriptors
|
||||
ADDAPI Sass_Function_List ADDCALL sass_make_function_list (size_t length);
|
||||
ADDAPI Sass_Function_Entry ADDCALL sass_make_function (const char* signature, Sass_Function_Fn cb, void* cookie);
|
||||
|
||||
// Setters and getters for callbacks on function lists
|
||||
ADDAPI Sass_Function_Entry ADDCALL sass_function_get_list_entry(Sass_Function_List list, size_t pos);
|
||||
ADDAPI void ADDCALL sass_function_set_list_entry(Sass_Function_List list, size_t pos, Sass_Function_Entry cb);
|
||||
|
||||
// Getters for custom function descriptors
|
||||
ADDAPI const char* ADDCALL sass_function_get_signature (Sass_Function_Entry cb);
|
||||
ADDAPI Sass_Function_Fn ADDCALL sass_function_get_function (Sass_Function_Entry cb);
|
||||
ADDAPI void* ADDCALL sass_function_get_cookie (Sass_Function_Entry cb);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
#ifndef SASS_C_VALUES_H
|
||||
#define SASS_C_VALUES_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#include <sass/base.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
// Forward declaration
|
||||
union Sass_Value;
|
||||
|
||||
// Type for Sass values
|
||||
enum Sass_Tag {
|
||||
SASS_BOOLEAN,
|
||||
SASS_NUMBER,
|
||||
SASS_COLOR,
|
||||
SASS_STRING,
|
||||
SASS_LIST,
|
||||
SASS_MAP,
|
||||
SASS_NULL,
|
||||
SASS_ERROR,
|
||||
SASS_WARNING
|
||||
};
|
||||
|
||||
// Tags for denoting Sass list separators
|
||||
enum Sass_Separator {
|
||||
SASS_COMMA,
|
||||
SASS_SPACE,
|
||||
SASS_HASH
|
||||
};
|
||||
|
||||
// Value Operators
|
||||
enum Sass_OP {
|
||||
AND, OR, // logical connectives
|
||||
EQ, NEQ, GT, GTE, LT, LTE, // arithmetic relations
|
||||
ADD, SUB, MUL, DIV, MOD, // arithmetic functions
|
||||
NUM_OPS // so we know how big to make the op table
|
||||
};
|
||||
|
||||
// Return the sass tag for a generic sass value
|
||||
// Check is needed before accessing specific values!
|
||||
ADDAPI enum Sass_Tag ADDCALL sass_value_get_tag (const union Sass_Value* v);
|
||||
|
||||
// Check value to be of a specific type
|
||||
// Can also be used before accessing properties!
|
||||
ADDAPI bool ADDCALL sass_value_is_null (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_number (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_string (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_boolean (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_color (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_list (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_map (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_error (const union Sass_Value* v);
|
||||
ADDAPI bool ADDCALL sass_value_is_warning (const union Sass_Value* v);
|
||||
|
||||
// Getters and setters for Sass_Number
|
||||
ADDAPI double ADDCALL sass_number_get_value (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_number_set_value (union Sass_Value* v, double value);
|
||||
ADDAPI const char* ADDCALL sass_number_get_unit (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_number_set_unit (union Sass_Value* v, char* unit);
|
||||
|
||||
// Getters and setters for Sass_String
|
||||
ADDAPI const char* ADDCALL sass_string_get_value (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_string_set_value (union Sass_Value* v, char* value);
|
||||
ADDAPI bool ADDCALL sass_string_is_quoted(const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted);
|
||||
|
||||
// Getters and setters for Sass_Boolean
|
||||
ADDAPI bool ADDCALL sass_boolean_get_value (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_boolean_set_value (union Sass_Value* v, bool value);
|
||||
|
||||
// Getters and setters for Sass_Color
|
||||
ADDAPI double ADDCALL sass_color_get_r (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_color_set_r (union Sass_Value* v, double r);
|
||||
ADDAPI double ADDCALL sass_color_get_g (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_color_set_g (union Sass_Value* v, double g);
|
||||
ADDAPI double ADDCALL sass_color_get_b (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_color_set_b (union Sass_Value* v, double b);
|
||||
ADDAPI double ADDCALL sass_color_get_a (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_color_set_a (union Sass_Value* v, double a);
|
||||
|
||||
// Getter for the number of items in list
|
||||
ADDAPI size_t ADDCALL sass_list_get_length (const union Sass_Value* v);
|
||||
// Getters and setters for Sass_List
|
||||
ADDAPI enum Sass_Separator ADDCALL sass_list_get_separator (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_list_set_separator (union Sass_Value* v, enum Sass_Separator value);
|
||||
// Getters and setters for Sass_List values
|
||||
ADDAPI union Sass_Value* ADDCALL sass_list_get_value (const union Sass_Value* v, size_t i);
|
||||
ADDAPI void ADDCALL sass_list_set_value (union Sass_Value* v, size_t i, union Sass_Value* value);
|
||||
|
||||
// Getter for the number of items in map
|
||||
ADDAPI size_t ADDCALL sass_map_get_length (const union Sass_Value* v);
|
||||
// Getters and setters for Sass_Map keys and values
|
||||
ADDAPI union Sass_Value* ADDCALL sass_map_get_key (const union Sass_Value* v, size_t i);
|
||||
ADDAPI void ADDCALL sass_map_set_key (union Sass_Value* v, size_t i, union Sass_Value*);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_map_get_value (const union Sass_Value* v, size_t i);
|
||||
ADDAPI void ADDCALL sass_map_set_value (union Sass_Value* v, size_t i, union Sass_Value*);
|
||||
|
||||
// Getters and setters for Sass_Error
|
||||
ADDAPI char* ADDCALL sass_error_get_message (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_error_set_message (union Sass_Value* v, char* msg);
|
||||
|
||||
// Getters and setters for Sass_Warning
|
||||
ADDAPI char* ADDCALL sass_warning_get_message (const union Sass_Value* v);
|
||||
ADDAPI void ADDCALL sass_warning_set_message (union Sass_Value* v, char* msg);
|
||||
|
||||
// Creator functions for all value types
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_null (void);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_boolean (bool val);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_string (const char* val);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_qstring (const char* val);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_number (double val, const char* unit);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_color (double r, double g, double b, double a);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_list (size_t len, enum Sass_Separator sep);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_map (size_t len);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_error (const char* msg);
|
||||
ADDAPI union Sass_Value* ADDCALL sass_make_warning (const char* msg);
|
||||
|
||||
// Generic destructor function for all types
|
||||
// Will release memory of all associated Sass_Values
|
||||
// Means we will delete recursively for lists and maps
|
||||
ADDAPI void ADDCALL sass_delete_value (union Sass_Value* val);
|
||||
|
||||
// Make a deep cloned copy of the given sass value
|
||||
ADDAPI union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val);
|
||||
|
||||
// Stringify a Sass_Values and also return the result as a Sass_Value (of type STRING)
|
||||
ADDAPI union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* a, bool compressed, int precision);
|
||||
|
||||
// Execute an operation for two Sass_Values and return the result as a Sass_Value too
|
||||
ADDAPI union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#ifndef SASS_VERSION_H
|
||||
#define SASS_VERSION_H
|
||||
|
||||
#ifndef LIBSASS_VERSION
|
||||
#define LIBSASS_VERSION "[NA]"
|
||||
#endif
|
||||
|
||||
#ifndef LIBSASS_LANGUAGE_VERSION
|
||||
#define LIBSASS_LANGUAGE_VERSION "[NA]"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
#ifndef SASS_VERSION_H
|
||||
#define SASS_VERSION_H
|
||||
|
||||
#ifndef LIBSASS_VERSION
|
||||
#define LIBSASS_VERSION "@PACKAGE_VERSION@"
|
||||
#endif
|
||||
|
||||
#ifndef LIBSASS_LANGUAGE_VERSION
|
||||
#define LIBSASS_LANGUAGE_VERSION "3.4"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+120
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* sass2scss
|
||||
* Licensed under the MIT License
|
||||
* Copyright (c) Marcel Greter
|
||||
*/
|
||||
|
||||
#ifndef SASS2SCSS_H
|
||||
#define SASS2SCSS_H
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
/* You should define ADD_EXPORTS *only* when building the DLL. */
|
||||
#ifdef ADD_EXPORTS
|
||||
#define ADDAPI __declspec(dllexport)
|
||||
#define ADDCALL __cdecl
|
||||
#else
|
||||
#define ADDAPI
|
||||
#define ADDCALL
|
||||
#endif
|
||||
|
||||
#else /* _WIN32 not defined. */
|
||||
|
||||
/* Define with no value on non-Windows OSes. */
|
||||
#define ADDAPI
|
||||
#define ADDCALL
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#ifndef SASS2SCSS_VERSION
|
||||
// Hardcode once the file is copied from
|
||||
// https://github.com/mgreter/sass2scss
|
||||
#define SASS2SCSS_VERSION "1.0.6"
|
||||
#endif
|
||||
|
||||
// add namespace for c++
|
||||
namespace Sass
|
||||
{
|
||||
|
||||
// pretty print options
|
||||
const int SASS2SCSS_PRETTIFY_0 = 0;
|
||||
const int SASS2SCSS_PRETTIFY_1 = 1;
|
||||
const int SASS2SCSS_PRETTIFY_2 = 2;
|
||||
const int SASS2SCSS_PRETTIFY_3 = 3;
|
||||
|
||||
// remove one-line comment
|
||||
const int SASS2SCSS_KEEP_COMMENT = 32;
|
||||
// remove multi-line comments
|
||||
const int SASS2SCSS_STRIP_COMMENT = 64;
|
||||
// convert one-line to multi-line
|
||||
const int SASS2SCSS_CONVERT_COMMENT = 128;
|
||||
|
||||
// String for finding something interesting
|
||||
const std::string SASS2SCSS_FIND_WHITESPACE = " \t\n\v\f\r";
|
||||
|
||||
// converter struct
|
||||
// holding all states
|
||||
struct converter
|
||||
{
|
||||
// bit options
|
||||
int options;
|
||||
// is selector
|
||||
bool selector;
|
||||
// concat lists
|
||||
bool comma;
|
||||
// has property
|
||||
bool property;
|
||||
// has semicolon
|
||||
bool semicolon;
|
||||
// comment context
|
||||
std::string comment;
|
||||
// flag end of file
|
||||
bool end_of_file;
|
||||
// whitespace buffer
|
||||
std::string whitespace;
|
||||
// context/block stack
|
||||
std::stack<std::string> indents;
|
||||
};
|
||||
|
||||
// function only available in c++ code
|
||||
char* sass2scss (const std::string& sass, const int options);
|
||||
|
||||
}
|
||||
// EO namespace
|
||||
|
||||
// declare for c
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// prettyfy print options
|
||||
#define SASS2SCSS_PRETTIFY_0 0
|
||||
#define SASS2SCSS_PRETTIFY_1 1
|
||||
#define SASS2SCSS_PRETTIFY_2 2
|
||||
#define SASS2SCSS_PRETTIFY_3 3
|
||||
|
||||
// keep one-line comments
|
||||
#define SASS2SCSS_KEEP_COMMENT 32
|
||||
// remove multi-line comments
|
||||
#define SASS2SCSS_STRIP_COMMENT 64
|
||||
// convert one-line to multi-line
|
||||
#define SASS2SCSS_CONVERT_COMMENT 128
|
||||
|
||||
// available to c and c++ code
|
||||
ADDAPI char* ADDCALL sass2scss (const char* sass, const int options);
|
||||
|
||||
// Get compiled sass2scss version
|
||||
ADDAPI const char* ADDCALL sass2scss_version(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // __cplusplus defined.
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
# ============================================================================
|
||||
# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
|
||||
# ============================================================================
|
||||
#
|
||||
# SYNOPSIS
|
||||
#
|
||||
# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
|
||||
#
|
||||
# DESCRIPTION
|
||||
#
|
||||
# Check for baseline language coverage in the compiler for the C++11
|
||||
# standard; if necessary, add switches to CXXFLAGS to enable support.
|
||||
#
|
||||
# The first argument, if specified, indicates whether you insist on an
|
||||
# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
|
||||
# -std=c++11). If neither is specified, you get whatever works, with
|
||||
# preference for an extended mode.
|
||||
#
|
||||
# The second argument, if specified 'mandatory' or if left unspecified,
|
||||
# indicates that baseline C++11 support is required and that the macro
|
||||
# should error out if no mode with that support is found. If specified
|
||||
# 'optional', then configuration proceeds regardless, after defining
|
||||
# HAVE_CXX11 if and only if a supporting mode is found.
|
||||
#
|
||||
# LICENSE
|
||||
#
|
||||
# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
|
||||
# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
|
||||
# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
|
||||
# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
|
||||
#
|
||||
# Copying and distribution of this file, with or without modification, are
|
||||
# permitted in any medium without royalty provided the copyright notice
|
||||
# and this notice are preserved. This file is offered as-is, without any
|
||||
# warranty.
|
||||
|
||||
#serial 11
|
||||
|
||||
m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
|
||||
template <typename T>
|
||||
struct check
|
||||
{
|
||||
static_assert(sizeof(int) <= sizeof(T), "not big enough");
|
||||
};
|
||||
|
||||
struct Base {
|
||||
virtual void f() {}
|
||||
};
|
||||
struct Child : public Base {
|
||||
virtual void f() override {}
|
||||
};
|
||||
|
||||
typedef check<check<bool>> right_angle_brackets;
|
||||
|
||||
int a;
|
||||
decltype(a) b;
|
||||
|
||||
typedef check<int> check_type;
|
||||
check_type c;
|
||||
check_type&& cr = static_cast<check_type&&>(c);
|
||||
|
||||
auto d = a;
|
||||
auto l = [](){};
|
||||
// Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
|
||||
struct use_l { use_l() { l(); } };
|
||||
|
||||
// http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
|
||||
// Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
|
||||
namespace test_template_alias_sfinae {
|
||||
struct foo {};
|
||||
|
||||
template<typename T>
|
||||
using member = typename T::member_type;
|
||||
|
||||
template<typename T>
|
||||
void func(...) {}
|
||||
|
||||
template<typename T>
|
||||
void func(member<T>*) {}
|
||||
|
||||
void test();
|
||||
|
||||
void test() {
|
||||
func<foo>(0);
|
||||
}
|
||||
}
|
||||
]])
|
||||
|
||||
AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
|
||||
m4_if([$1], [], [],
|
||||
[$1], [ext], [],
|
||||
[$1], [noext], [],
|
||||
[m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
|
||||
m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
|
||||
[$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
|
||||
[$2], [optional], [ax_cxx_compile_cxx11_required=false],
|
||||
[m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
|
||||
AC_LANG_PUSH([C++])dnl
|
||||
ac_success=no
|
||||
AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
|
||||
ax_cv_cxx_compile_cxx11,
|
||||
[AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
|
||||
[ax_cv_cxx_compile_cxx11=yes],
|
||||
[ax_cv_cxx_compile_cxx11=no])])
|
||||
if test x$ax_cv_cxx_compile_cxx11 = xyes; then
|
||||
ac_success=yes
|
||||
fi
|
||||
|
||||
m4_if([$1], [noext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
for switch in -std=gnu++11 -std=gnu++0x; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
|
||||
m4_if([$1], [ext], [], [dnl
|
||||
if test x$ac_success = xno; then
|
||||
dnl HP's aCC needs +std=c++11 according to:
|
||||
dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
|
||||
for switch in -std=c++11 -std=c++0x +std=c++11; do
|
||||
cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
|
||||
AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
|
||||
$cachevar,
|
||||
[ac_save_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
|
||||
[eval $cachevar=yes],
|
||||
[eval $cachevar=no])
|
||||
CXXFLAGS="$ac_save_CXXFLAGS"])
|
||||
if eval test x\$$cachevar = xyes; then
|
||||
CXXFLAGS="$CXXFLAGS $switch"
|
||||
ac_success=yes
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi])
|
||||
AC_LANG_POP([C++])
|
||||
if test x$ax_cxx_compile_cxx11_required = xtrue; then
|
||||
if test x$ac_success = xno; then
|
||||
AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
|
||||
fi
|
||||
else
|
||||
if test x$ac_success = xno; then
|
||||
HAVE_CXX11=0
|
||||
AC_MSG_NOTICE([No compiler with C++11 support was found])
|
||||
else
|
||||
HAVE_CXX11=1
|
||||
AC_DEFINE(HAVE_CXX11,1,
|
||||
[define if the compiler supports basic C++11 syntax])
|
||||
fi
|
||||
|
||||
AC_SUBST(HAVE_CXX11)
|
||||
fi
|
||||
])
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
#include <windows.h>
|
||||
|
||||
// DLL version information.
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG | VS_FF_PRERELEASE
|
||||
#else
|
||||
FILEFLAGS 0
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_DLL
|
||||
FILESUBTYPE VFT2_UNKNOWN
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "080904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Libsass Organization"
|
||||
VALUE "FileDescription", "A C/C++ implementation of a Sass compiler"
|
||||
VALUE "FileVersion", "0.9.0.0"
|
||||
VALUE "InternalName", "libsass"
|
||||
VALUE "LegalCopyright", "©2014 libsass.org"
|
||||
VALUE "OriginalFilename", "libsass.dll"
|
||||
VALUE "ProductName", "Libsass Library"
|
||||
VALUE "ProductVersion", "0.9.0.0"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x809, 1200
|
||||
END
|
||||
END
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
|
||||
script/branding
|
||||
|
||||
if [ ! -d "sass-spec" ]; then
|
||||
git clone https://github.com/sass/sass-spec.git
|
||||
fi
|
||||
if [ ! -d "sassc" ]; then
|
||||
git clone https://github.com/sass/sassc.git
|
||||
fi
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
#! /bin/bash
|
||||
|
||||
echo " "
|
||||
echo " _ ___ ____ ____ _ ____ ____ "
|
||||
echo "| | |_ _| __ ) ___| / \ / ___/ ___| "
|
||||
echo "| | | || _ \___ \ / _ \ \___ \___ \ "
|
||||
echo "| |___ | || |_) |__) / ___ \ ___) |__) |"
|
||||
echo "|_____|___|____/____/_/ \_\____/____/ "
|
||||
echo " "
|
||||
|
||||
+129
@@ -0,0 +1,129 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
script/bootstrap
|
||||
|
||||
# export this path right here (was in script/spec before)
|
||||
export SASS_LIBSASS_PATH="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/../ && pwd )"
|
||||
|
||||
# use some defaults if not running under travis ci
|
||||
if [ "x$CONTINUOUS_INTEGRATION" == "x" ]; then export CONTINUOUS_INTEGRATION=true; fi
|
||||
if [ "x$TRAVIS_BUILD_DIR" == "x" ]; then export TRAVIS_BUILD_DIR=$(pwd); fi
|
||||
if [ "x$SASS_SASSC_PATH" == "x" ]; then export SASS_SASSC_PATH=$(pwd)/sassc; fi
|
||||
if [ "x$SASS_SPEC_PATH" == "x" ]; then export SASS_SPEC_PATH=$(pwd)/sass-spec; fi
|
||||
|
||||
# try to get the os name from uname (and filter via perl - probably not the most portable way?)
|
||||
if [ "x$TRAVIS_OS_NAME" == "x" ]; then export TRAVIS_OS_NAME=`uname -s | perl -ne 'print lc \$1 if\(/^([a-zA-Z]+)/'\)`; fi
|
||||
|
||||
if [ "x$COVERAGE" == "xyes" ]; then
|
||||
COVERAGE_OPT="--enable-coverage"
|
||||
export EXTRA_CFLAGS="--coverage"
|
||||
export EXTRA_CXXFLAGS="--coverage"
|
||||
export EXTRA_LDFLAGS="--coverage"
|
||||
else
|
||||
COVERAGE_OPT="--disable-coverage"
|
||||
fi
|
||||
|
||||
if [ "x$BUILD" == "xstatic" ]; then
|
||||
SHARED_OPT="--disable-shared --enable-static"
|
||||
MAKE_TARGET="static"
|
||||
else
|
||||
# Makefile of sassc wants to link to static
|
||||
SHARED_OPT="--enable-shared --enable-static"
|
||||
MAKE_TARGET="shared"
|
||||
fi
|
||||
|
||||
if [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
|
||||
MAKE_OPTS="$MAKE_OPTS -j1 V=1"
|
||||
else
|
||||
MAKE_OPTS="$MAKE_OPTS -j3 V=1"
|
||||
fi
|
||||
|
||||
if [ "x$PREFIX" == "x" ]; then
|
||||
if [ "x$TRAVIS_BUILD_DIR" == "x" ]; then
|
||||
PREFIX=$SASS_LIBSASS_PATH/build
|
||||
else
|
||||
PREFIX=$TRAVIS_BUILD_DIR/build
|
||||
fi
|
||||
fi
|
||||
|
||||
# enable address sanitation
|
||||
# https://en.wikipedia.org/wiki/AddressSanitizer
|
||||
if [ "x$CC" == "xclang" ]; then
|
||||
if [ "x$COVERAGE" != "xyes" ]; then
|
||||
if [ "$TRAVIS_OS_NAME" == "linux" ]; then
|
||||
export EXTRA_CFLAGS="$EXTRA_CFLAGS -fsanitize=address"
|
||||
export EXTRA_CXXFLAGS="$EXTRA_CXXFLAGS -fsanitize=address"
|
||||
export EXTRA_LDFLAGS="$EXTRA_LDFLAGS -fsanitize=address"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo SASS_LIBSASS_PATH: $SASS_LIBSASS_PATH
|
||||
echo TRAVIS_BUILD_DIR: $TRAVIS_BUILD_DIR
|
||||
echo SASS_SASSC_PATH: $SASS_SASSC_PATH
|
||||
echo SASS_SPEC_PATH: $SASS_SPEC_PATH
|
||||
echo INSTALL_LOCATION: $PREFIX
|
||||
|
||||
if [ "x$AUTOTOOLS" == "xyes" ]; then
|
||||
|
||||
echo -en 'travis_fold:start:configure\r'
|
||||
autoreconf --force --install
|
||||
./configure --enable-tests $COVERAGE_OPT \
|
||||
--disable-silent-rules \
|
||||
--with-sassc-dir=$SASS_SASSC_PATH \
|
||||
--with-sass-spec-dir=$SASS_SPEC_PATH \
|
||||
--prefix=$PREFIX \
|
||||
${SHARED_OPT}
|
||||
echo -en 'travis_fold:end:configure\r'
|
||||
|
||||
make $MAKE_OPTS clean
|
||||
|
||||
# install to prefix directory
|
||||
PREFIX="$PREFIX" make $MAKE_OPTS install
|
||||
|
||||
else
|
||||
|
||||
make $MAKE_OPTS clean
|
||||
|
||||
fi
|
||||
|
||||
# install to prefix directory
|
||||
PREFIX="$PREFIX" make $MAKE_OPTS install
|
||||
|
||||
ls -la $PREFIX/*
|
||||
|
||||
echo successfully compiled libsass
|
||||
echo AUTOTOOLS=$AUTOTOOLS COVERAGE=$COVERAGE BUILD=$BUILD
|
||||
|
||||
if [ "$CONTINUOUS_INTEGRATION" == "true" ] && [ "$TRAVIS_PULL_REQUEST" != "false" ] && [ "x$TRAVIS_PULL_REQUEST" != "x" ] &&
|
||||
([ "$TRAVIS_OS_NAME" == "linux" ] || [ "$TRAVIS_OS_NAME" == "osx" ] || [ "$TRAVIS_OS_NAME" == "cygwin" ]);
|
||||
then
|
||||
|
||||
echo "Fetching PR $TRAVIS_PULL_REQUEST"
|
||||
|
||||
JSON=$(curl -L -sS https://api.github.com/repos/sass/libsass/pulls/$TRAVIS_PULL_REQUEST)
|
||||
|
||||
if [[ $JSON =~ "API rate limit exceeded" ]];
|
||||
then
|
||||
echo "Travis rate limit on github exceeded"
|
||||
echo "Retrying via 'special purpose proxy'"
|
||||
JSON=$(curl -L -sS http://libsass.ocbnet.ch/libsass-spec-pr.psgi/$TRAVIS_PULL_REQUEST)
|
||||
fi
|
||||
|
||||
RE_SPEC_PR="sass\/sass-spec(#|\/pull\/)([0-9]+)"
|
||||
|
||||
if [[ $JSON =~ $RE_SPEC_PR ]];
|
||||
then
|
||||
SPEC_PR="${BASH_REMATCH[2]}"
|
||||
echo "Fetching Sass Spec PR $SPEC_PR"
|
||||
git -C sass-spec fetch -u origin pull/$SPEC_PR/head:ci-spec-pr-$SPEC_PR
|
||||
git -C sass-spec checkout --force ci-spec-pr-$SPEC_PR
|
||||
LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_probe
|
||||
else
|
||||
LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_probe
|
||||
fi
|
||||
else
|
||||
LD_LIBRARY_PATH="$PREFIX/lib/" make $MAKE_OPTS test_probe
|
||||
fi
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
|
||||
gem install minitest
|
||||
gem install minitap
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
if [ "x$COVERAGE" == "xyes" ]; then
|
||||
pip install --user gcovr
|
||||
pip install --user cpp-coveralls
|
||||
else
|
||||
echo "no dependencies to install"
|
||||
fi
|
||||
|
||||
if [ "x$AUTOTOOLS" == "xyes" ]; then
|
||||
sudo add-apt-repository -y ppa:rbose-debianizer/automake &> /dev/null
|
||||
sudo apt-get -qq update
|
||||
sudo apt-get -qq install automake
|
||||
AUTOTOOLS=yes
|
||||
fi
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
#!/bin/bash
|
||||
|
||||
if [ "x$COVERAGE" = "xyes" ]; then
|
||||
|
||||
# exclude some directories from profiling (.libs is from autotools)
|
||||
export EXCLUDE_COVERAGE="--exclude src/sassc
|
||||
--exclude src/sass-spec
|
||||
--exclude src/.libs
|
||||
--exclude src/debug.hpp
|
||||
--exclude src/json.cpp
|
||||
--exclude src/json.hpp
|
||||
--exclude src/cencode.c
|
||||
--exclude src/b64
|
||||
--exclude src/utf8
|
||||
--exclude src/utf8_string.hpp
|
||||
--exclude src/utf8.h
|
||||
--exclude src/utf8_string.cpp
|
||||
--exclude src/sass2scss.h
|
||||
--exclude src/sass2scss.cpp
|
||||
--exclude src/test
|
||||
--exclude src/posix
|
||||
--exclude src/debugger.hpp"
|
||||
# debug via gcovr
|
||||
gcov -v
|
||||
gcovr -r .
|
||||
# generate and submit report to coveralls.io
|
||||
coveralls $EXCLUDE_COVERAGE --gcov-options '\-lp'
|
||||
|
||||
else
|
||||
echo "skip coverage reporting"
|
||||
fi
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
script/bootstrap
|
||||
|
||||
make $MAKE_OPTS test_build
|
||||
+652
@@ -0,0 +1,652 @@
|
||||
#! /bin/sh
|
||||
# Copyright (C) 2011-2013 Free Software Foundation, Inc.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
scriptversion=2011-12-27.17; # UTC
|
||||
|
||||
# Make unconditional expansion of undefined variables an error. This
|
||||
# helps a lot in preventing typo-related bugs.
|
||||
set -u
|
||||
|
||||
me=tap-driver.sh
|
||||
|
||||
fatal ()
|
||||
{
|
||||
echo "$me: fatal: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
usage_error ()
|
||||
{
|
||||
echo "$me: $*" >&2
|
||||
print_usage >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
print_usage ()
|
||||
{
|
||||
cat <<END
|
||||
Usage:
|
||||
tap-driver.sh --test-name=NAME --log-file=PATH --trs-file=PATH
|
||||
[--expect-failure={yes|no}] [--color-tests={yes|no}]
|
||||
[--enable-hard-errors={yes|no}] [--ignore-exit]
|
||||
[--diagnostic-string=STRING] [--merge|--no-merge]
|
||||
[--comments|--no-comments] [--] TEST-COMMAND
|
||||
The \`--test-name', \`--log-file' and \`--trs-file' options are mandatory.
|
||||
END
|
||||
}
|
||||
|
||||
# TODO: better error handling in option parsing (in particular, ensure
|
||||
# TODO: $log_file, $trs_file and $test_name are defined).
|
||||
test_name= # Used for reporting.
|
||||
log_file= # Where to save the result and output of the test script.
|
||||
trs_file= # Where to save the metadata of the test run.
|
||||
expect_failure=0
|
||||
color_tests=0
|
||||
merge=0
|
||||
ignore_exit=0
|
||||
comments=0
|
||||
diag_string='#'
|
||||
while test $# -gt 0; do
|
||||
case $1 in
|
||||
--help) print_usage; exit $?;;
|
||||
--version) echo "$me $scriptversion"; exit $?;;
|
||||
--test-name) test_name=$2; shift;;
|
||||
--log-file) log_file=$2; shift;;
|
||||
--trs-file) trs_file=$2; shift;;
|
||||
--color-tests) color_tests=$2; shift;;
|
||||
--expect-failure) expect_failure=$2; shift;;
|
||||
--enable-hard-errors) shift;; # No-op.
|
||||
--merge) merge=1;;
|
||||
--no-merge) merge=0;;
|
||||
--ignore-exit) ignore_exit=1;;
|
||||
--comments) comments=1;;
|
||||
--no-comments) comments=0;;
|
||||
--diagnostic-string) diag_string=$2; shift;;
|
||||
--) shift; break;;
|
||||
-*) usage_error "invalid option: '$1'";;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
test $# -gt 0 || usage_error "missing test command"
|
||||
|
||||
case $expect_failure in
|
||||
yes) expect_failure=1;;
|
||||
*) expect_failure=0;;
|
||||
esac
|
||||
|
||||
if test $color_tests = yes; then
|
||||
init_colors='
|
||||
color_map["red"]="[0;31m" # Red.
|
||||
color_map["grn"]="[0;32m" # Green.
|
||||
color_map["lgn"]="[1;32m" # Light green.
|
||||
color_map["blu"]="[1;34m" # Blue.
|
||||
color_map["mgn"]="[0;35m" # Magenta.
|
||||
color_map["std"]="[m" # No color.
|
||||
color_for_result["ERROR"] = "mgn"
|
||||
color_for_result["PASS"] = "grn"
|
||||
color_for_result["XPASS"] = "red"
|
||||
color_for_result["FAIL"] = "red"
|
||||
color_for_result["XFAIL"] = "lgn"
|
||||
color_for_result["SKIP"] = "blu"'
|
||||
else
|
||||
init_colors=''
|
||||
fi
|
||||
|
||||
# :; is there to work around a bug in bash 3.2 (and earlier) which
|
||||
# does not always set '$?' properly on redirection failure.
|
||||
# See the Autoconf manual for more details.
|
||||
:;{
|
||||
(
|
||||
# Ignore common signals (in this subshell only!), to avoid potential
|
||||
# problems with Korn shells. Some Korn shells are known to propagate
|
||||
# to themselves signals that have killed a child process they were
|
||||
# waiting for; this is done at least for SIGINT (and usually only for
|
||||
# it, in truth). Without the `trap' below, such a behaviour could
|
||||
# cause a premature exit in the current subshell, e.g., in case the
|
||||
# test command it runs gets terminated by a SIGINT. Thus, the awk
|
||||
# script we are piping into would never seen the exit status it
|
||||
# expects on its last input line (which is displayed below by the
|
||||
# last `echo $?' statement), and would thus die reporting an internal
|
||||
# error.
|
||||
# For more information, see the Autoconf manual and the threads:
|
||||
# <http://lists.gnu.org/archive/html/bug-autoconf/2011-09/msg00004.html>
|
||||
# <http://mail.opensolaris.org/pipermail/ksh93-integration-discuss/2009-February/004121.html>
|
||||
trap : 1 3 2 13 15
|
||||
if test $merge -gt 0; then
|
||||
exec 2>&1
|
||||
else
|
||||
exec 2>&3
|
||||
fi
|
||||
"$@"
|
||||
echo $?
|
||||
) | LC_ALL=C ${AM_TAP_AWK-awk} \
|
||||
-v me="$me" \
|
||||
-v test_script_name="$test_name" \
|
||||
-v log_file="$log_file" \
|
||||
-v trs_file="$trs_file" \
|
||||
-v expect_failure="$expect_failure" \
|
||||
-v merge="$merge" \
|
||||
-v ignore_exit="$ignore_exit" \
|
||||
-v comments="$comments" \
|
||||
-v diag_string="$diag_string" \
|
||||
'
|
||||
# FIXME: the usages of "cat >&3" below could be optimized when using
|
||||
# FIXME: GNU awk, and/on on systems that supports /dev/fd/.
|
||||
|
||||
# Implementation note: in what follows, `result_obj` will be an
|
||||
# associative array that (partly) simulates a TAP result object
|
||||
# from the `TAP::Parser` perl module.
|
||||
|
||||
## ----------- ##
|
||||
## FUNCTIONS ##
|
||||
## ----------- ##
|
||||
|
||||
function fatal(msg)
|
||||
{
|
||||
print me ": " msg | "cat >&2"
|
||||
exit 1
|
||||
}
|
||||
|
||||
function abort(where)
|
||||
{
|
||||
fatal("internal error " where)
|
||||
}
|
||||
|
||||
# Convert a boolean to a "yes"/"no" string.
|
||||
function yn(bool)
|
||||
{
|
||||
return bool ? "yes" : "no";
|
||||
}
|
||||
|
||||
function add_test_result(result)
|
||||
{
|
||||
if (!test_results_index)
|
||||
test_results_index = 0
|
||||
test_results_list[test_results_index] = result
|
||||
test_results_index += 1
|
||||
test_results_seen[result] = 1;
|
||||
}
|
||||
|
||||
# Whether the test script should be re-run by "make recheck".
|
||||
function must_recheck()
|
||||
{
|
||||
for (k in test_results_seen)
|
||||
if (k != "XFAIL" && k != "PASS" && k != "SKIP")
|
||||
return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# Whether the content of the log file associated to this test should
|
||||
# be copied into the "global" test-suite.log.
|
||||
function copy_in_global_log()
|
||||
{
|
||||
for (k in test_results_seen)
|
||||
if (k != "PASS")
|
||||
return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
# FIXME: this can certainly be improved ...
|
||||
function get_global_test_result()
|
||||
{
|
||||
if ("ERROR" in test_results_seen)
|
||||
return "ERROR"
|
||||
if ("FAIL" in test_results_seen || "XPASS" in test_results_seen)
|
||||
return "FAIL"
|
||||
all_skipped = 1
|
||||
for (k in test_results_seen)
|
||||
if (k != "SKIP")
|
||||
all_skipped = 0
|
||||
if (all_skipped)
|
||||
return "SKIP"
|
||||
return "PASS";
|
||||
}
|
||||
|
||||
function stringify_result_obj(result_obj)
|
||||
{
|
||||
if (result_obj["is_unplanned"] || result_obj["number"] != testno)
|
||||
return "ERROR"
|
||||
|
||||
if (plan_seen == LATE_PLAN)
|
||||
return "ERROR"
|
||||
|
||||
if (result_obj["directive"] == "TODO")
|
||||
return result_obj["is_ok"] ? "XPASS" : "XFAIL"
|
||||
|
||||
if (result_obj["directive"] == "SKIP")
|
||||
return result_obj["is_ok"] ? "SKIP" : COOKED_FAIL;
|
||||
|
||||
if (length(result_obj["directive"]))
|
||||
abort("in function stringify_result_obj()")
|
||||
|
||||
return result_obj["is_ok"] ? COOKED_PASS : COOKED_FAIL
|
||||
}
|
||||
|
||||
function decorate_result(result)
|
||||
{
|
||||
color_name = color_for_result[result]
|
||||
if (color_name)
|
||||
return color_map[color_name] "" result "" color_map["std"]
|
||||
# If we are not using colorized output, or if we do not know how
|
||||
# to colorize the given result, we should return it unchanged.
|
||||
return result
|
||||
}
|
||||
|
||||
function report(result, details)
|
||||
{
|
||||
if (result ~ /^(X?(PASS|FAIL)|SKIP|ERROR)/)
|
||||
{
|
||||
msg = ": " test_script_name
|
||||
add_test_result(result)
|
||||
}
|
||||
else if (result == "#")
|
||||
{
|
||||
msg = " " test_script_name ":"
|
||||
}
|
||||
else
|
||||
{
|
||||
abort("in function report()")
|
||||
}
|
||||
if (length(details))
|
||||
msg = msg " " details
|
||||
# Output on console might be colorized.
|
||||
print decorate_result(result) msg
|
||||
# Log the result in the log file too, to help debugging (this is
|
||||
# especially true when said result is a TAP error or "Bail out!").
|
||||
print result msg | "cat >&3";
|
||||
}
|
||||
|
||||
function testsuite_error(error_message)
|
||||
{
|
||||
report("ERROR", "- " error_message)
|
||||
}
|
||||
|
||||
function handle_tap_result()
|
||||
{
|
||||
details = result_obj["number"];
|
||||
if (length(result_obj["description"]))
|
||||
details = details " " result_obj["description"]
|
||||
|
||||
if (plan_seen == LATE_PLAN)
|
||||
{
|
||||
details = details " # AFTER LATE PLAN";
|
||||
}
|
||||
else if (result_obj["is_unplanned"])
|
||||
{
|
||||
details = details " # UNPLANNED";
|
||||
}
|
||||
else if (result_obj["number"] != testno)
|
||||
{
|
||||
details = sprintf("%s # OUT-OF-ORDER (expecting %d)",
|
||||
details, testno);
|
||||
}
|
||||
else if (result_obj["directive"])
|
||||
{
|
||||
details = details " # " result_obj["directive"];
|
||||
if (length(result_obj["explanation"]))
|
||||
details = details " " result_obj["explanation"]
|
||||
}
|
||||
|
||||
report(stringify_result_obj(result_obj), details)
|
||||
}
|
||||
|
||||
# `skip_reason` should be empty whenever planned > 0.
|
||||
function handle_tap_plan(planned, skip_reason)
|
||||
{
|
||||
planned += 0 # Avoid getting confused if, say, `planned` is "00"
|
||||
if (length(skip_reason) && planned > 0)
|
||||
abort("in function handle_tap_plan()")
|
||||
if (plan_seen)
|
||||
{
|
||||
# Error, only one plan per stream is acceptable.
|
||||
testsuite_error("multiple test plans")
|
||||
return;
|
||||
}
|
||||
planned_tests = planned
|
||||
# The TAP plan can come before or after *all* the TAP results; we speak
|
||||
# respectively of an "early" or a "late" plan. If we see the plan line
|
||||
# after at least one TAP result has been seen, assume we have a late
|
||||
# plan; in this case, any further test result seen after the plan will
|
||||
# be flagged as an error.
|
||||
plan_seen = (testno >= 1 ? LATE_PLAN : EARLY_PLAN)
|
||||
# If testno > 0, we have an error ("too many tests run") that will be
|
||||
# automatically dealt with later, so do not worry about it here. If
|
||||
# $plan_seen is true, we have an error due to a repeated plan, and that
|
||||
# has already been dealt with above. Otherwise, we have a valid "plan
|
||||
# with SKIP" specification, and should report it as a particular kind
|
||||
# of SKIP result.
|
||||
if (planned == 0 && testno == 0)
|
||||
{
|
||||
if (length(skip_reason))
|
||||
skip_reason = "- " skip_reason;
|
||||
report("SKIP", skip_reason);
|
||||
}
|
||||
}
|
||||
|
||||
function extract_tap_comment(line)
|
||||
{
|
||||
if (index(line, diag_string) == 1)
|
||||
{
|
||||
# Strip leading `diag_string` from `line`.
|
||||
line = substr(line, length(diag_string) + 1)
|
||||
# And strip any leading and trailing whitespace left.
|
||||
sub("^[ \t]*", "", line)
|
||||
sub("[ \t]*$", "", line)
|
||||
# Return what is left (if any).
|
||||
return line;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
# When this function is called, we know that line is a TAP result line,
|
||||
# so that it matches the (perl) RE "^(not )?ok\b".
|
||||
function setup_result_obj(line)
|
||||
{
|
||||
# Get the result, and remove it from the line.
|
||||
result_obj["is_ok"] = (substr(line, 1, 2) == "ok" ? 1 : 0)
|
||||
sub("^(not )?ok[ \t]*", "", line)
|
||||
|
||||
# If the result has an explicit number, get it and strip it; otherwise,
|
||||
# automatically assing the next progresive number to it.
|
||||
if (line ~ /^[0-9]+$/ || line ~ /^[0-9]+[^a-zA-Z0-9_]/)
|
||||
{
|
||||
match(line, "^[0-9]+")
|
||||
# The final `+ 0` is to normalize numbers with leading zeros.
|
||||
result_obj["number"] = substr(line, 1, RLENGTH) + 0
|
||||
line = substr(line, RLENGTH + 1)
|
||||
}
|
||||
else
|
||||
{
|
||||
result_obj["number"] = testno
|
||||
}
|
||||
|
||||
if (plan_seen == LATE_PLAN)
|
||||
# No further test results are acceptable after a "late" TAP plan
|
||||
# has been seen.
|
||||
result_obj["is_unplanned"] = 1
|
||||
else if (plan_seen && testno > planned_tests)
|
||||
result_obj["is_unplanned"] = 1
|
||||
else
|
||||
result_obj["is_unplanned"] = 0
|
||||
|
||||
# Strip trailing and leading whitespace.
|
||||
sub("^[ \t]*", "", line)
|
||||
sub("[ \t]*$", "", line)
|
||||
|
||||
# This will have to be corrected if we have a "TODO"/"SKIP" directive.
|
||||
result_obj["description"] = line
|
||||
result_obj["directive"] = ""
|
||||
result_obj["explanation"] = ""
|
||||
|
||||
if (index(line, "#") == 0)
|
||||
return # No possible directive, nothing more to do.
|
||||
|
||||
# Directives are case-insensitive.
|
||||
rx = "[ \t]*#[ \t]*([tT][oO][dD][oO]|[sS][kK][iI][pP])[ \t]*"
|
||||
|
||||
# See whether we have the directive, and if yes, where.
|
||||
pos = match(line, rx "$")
|
||||
if (!pos)
|
||||
pos = match(line, rx "[^a-zA-Z0-9_]")
|
||||
|
||||
# If there was no TAP directive, we have nothing more to do.
|
||||
if (!pos)
|
||||
return
|
||||
|
||||
# Let`s now see if the TAP directive has been escaped. For example:
|
||||
# escaped: ok \# SKIP
|
||||
# not escaped: ok \\# SKIP
|
||||
# escaped: ok \\\\\# SKIP
|
||||
# not escaped: ok \ # SKIP
|
||||
if (substr(line, pos, 1) == "#")
|
||||
{
|
||||
bslash_count = 0
|
||||
for (i = pos; i > 1 && substr(line, i - 1, 1) == "\\"; i--)
|
||||
bslash_count += 1
|
||||
if (bslash_count % 2)
|
||||
return # Directive was escaped.
|
||||
}
|
||||
|
||||
# Strip the directive and its explanation (if any) from the test
|
||||
# description.
|
||||
result_obj["description"] = substr(line, 1, pos - 1)
|
||||
# Now remove the test description from the line, that has been dealt
|
||||
# with already.
|
||||
line = substr(line, pos)
|
||||
# Strip the directive, and save its value (normalized to upper case).
|
||||
sub("^[ \t]*#[ \t]*", "", line)
|
||||
result_obj["directive"] = toupper(substr(line, 1, 4))
|
||||
line = substr(line, 5)
|
||||
# Now get the explanation for the directive (if any), with leading
|
||||
# and trailing whitespace removed.
|
||||
sub("^[ \t]*", "", line)
|
||||
sub("[ \t]*$", "", line)
|
||||
result_obj["explanation"] = line
|
||||
}
|
||||
|
||||
function get_test_exit_message(status)
|
||||
{
|
||||
if (status == 0)
|
||||
return ""
|
||||
if (status !~ /^[1-9][0-9]*$/)
|
||||
abort("getting exit status")
|
||||
if (status < 127)
|
||||
exit_details = ""
|
||||
else if (status == 127)
|
||||
exit_details = " (command not found?)"
|
||||
else if (status >= 128 && status <= 255)
|
||||
exit_details = sprintf(" (terminated by signal %d?)", status - 128)
|
||||
else if (status > 256 && status <= 384)
|
||||
# We used to report an "abnormal termination" here, but some Korn
|
||||
# shells, when a child process die due to signal number n, can leave
|
||||
# in $? an exit status of 256+n instead of the more standard 128+n.
|
||||
# Apparently, both behaviours are allowed by POSIX (2008), so be
|
||||
# prepared to handle them both. See also Austing Group report ID
|
||||
# 0000051 <http://www.austingroupbugs.net/view.php?id=51>
|
||||
exit_details = sprintf(" (terminated by signal %d?)", status - 256)
|
||||
else
|
||||
# Never seen in practice.
|
||||
exit_details = " (abnormal termination)"
|
||||
return sprintf("exited with status %d%s", status, exit_details)
|
||||
}
|
||||
|
||||
function write_test_results()
|
||||
{
|
||||
print ":global-test-result: " get_global_test_result() > trs_file
|
||||
print ":recheck: " yn(must_recheck()) > trs_file
|
||||
print ":copy-in-global-log: " yn(copy_in_global_log()) > trs_file
|
||||
for (i = 0; i < test_results_index; i += 1)
|
||||
print ":test-result: " test_results_list[i] > trs_file
|
||||
close(trs_file);
|
||||
}
|
||||
|
||||
BEGIN {
|
||||
|
||||
## ------- ##
|
||||
## SETUP ##
|
||||
## ------- ##
|
||||
|
||||
'"$init_colors"'
|
||||
|
||||
# Properly initialized once the TAP plan is seen.
|
||||
planned_tests = 0
|
||||
|
||||
COOKED_PASS = expect_failure ? "XPASS": "PASS";
|
||||
COOKED_FAIL = expect_failure ? "XFAIL": "FAIL";
|
||||
|
||||
# Enumeration-like constants to remember which kind of plan (if any)
|
||||
# has been seen. It is important that NO_PLAN evaluates "false" as
|
||||
# a boolean.
|
||||
NO_PLAN = 0
|
||||
EARLY_PLAN = 1
|
||||
LATE_PLAN = 2
|
||||
|
||||
testno = 0 # Number of test results seen so far.
|
||||
bailed_out = 0 # Whether a "Bail out!" directive has been seen.
|
||||
|
||||
# Whether the TAP plan has been seen or not, and if yes, which kind
|
||||
# it is ("early" is seen before any test result, "late" otherwise).
|
||||
plan_seen = NO_PLAN
|
||||
|
||||
## --------- ##
|
||||
## PARSING ##
|
||||
## --------- ##
|
||||
|
||||
is_first_read = 1
|
||||
|
||||
while (1)
|
||||
{
|
||||
# Involutions required so that we are able to read the exit status
|
||||
# from the last input line.
|
||||
st = getline
|
||||
if (st < 0) # I/O error.
|
||||
fatal("I/O error while reading from input stream")
|
||||
else if (st == 0) # End-of-input
|
||||
{
|
||||
if (is_first_read)
|
||||
abort("in input loop: only one input line")
|
||||
break
|
||||
}
|
||||
if (is_first_read)
|
||||
{
|
||||
is_first_read = 0
|
||||
nextline = $0
|
||||
continue
|
||||
}
|
||||
else
|
||||
{
|
||||
curline = nextline
|
||||
nextline = $0
|
||||
$0 = curline
|
||||
}
|
||||
# Copy any input line verbatim into the log file.
|
||||
print | "cat >&3"
|
||||
# Parsing of TAP input should stop after a "Bail out!" directive.
|
||||
if (bailed_out)
|
||||
continue
|
||||
|
||||
# TAP test result.
|
||||
if ($0 ~ /^(not )?ok$/ || $0 ~ /^(not )?ok[^a-zA-Z0-9_]/)
|
||||
{
|
||||
testno += 1
|
||||
setup_result_obj($0)
|
||||
handle_tap_result()
|
||||
}
|
||||
# TAP plan (normal or "SKIP" without explanation).
|
||||
else if ($0 ~ /^1\.\.[0-9]+[ \t]*$/)
|
||||
{
|
||||
# The next two lines will put the number of planned tests in $0.
|
||||
sub("^1\\.\\.", "")
|
||||
sub("[^0-9]*$", "")
|
||||
handle_tap_plan($0, "")
|
||||
continue
|
||||
}
|
||||
# TAP "SKIP" plan, with an explanation.
|
||||
else if ($0 ~ /^1\.\.0+[ \t]*#/)
|
||||
{
|
||||
# The next lines will put the skip explanation in $0, stripping
|
||||
# any leading and trailing whitespace. This is a little more
|
||||
# tricky in truth, since we want to also strip a potential leading
|
||||
# "SKIP" string from the message.
|
||||
sub("^[^#]*#[ \t]*(SKIP[: \t][ \t]*)?", "")
|
||||
sub("[ \t]*$", "");
|
||||
handle_tap_plan(0, $0)
|
||||
}
|
||||
# "Bail out!" magic.
|
||||
# Older versions of prove and TAP::Harness (e.g., 3.17) did not
|
||||
# recognize a "Bail out!" directive when preceded by leading
|
||||
# whitespace, but more modern versions (e.g., 3.23) do. So we
|
||||
# emulate the latter, "more modern" behaviour.
|
||||
else if ($0 ~ /^[ \t]*Bail out!/)
|
||||
{
|
||||
bailed_out = 1
|
||||
# Get the bailout message (if any), with leading and trailing
|
||||
# whitespace stripped. The message remains stored in `$0`.
|
||||
sub("^[ \t]*Bail out![ \t]*", "");
|
||||
sub("[ \t]*$", "");
|
||||
# Format the error message for the
|
||||
bailout_message = "Bail out!"
|
||||
if (length($0))
|
||||
bailout_message = bailout_message " " $0
|
||||
testsuite_error(bailout_message)
|
||||
}
|
||||
# Maybe we have too look for dianogtic comments too.
|
||||
else if (comments != 0)
|
||||
{
|
||||
comment = extract_tap_comment($0);
|
||||
if (length(comment))
|
||||
report("#", comment);
|
||||
}
|
||||
}
|
||||
|
||||
## -------- ##
|
||||
## FINISH ##
|
||||
## -------- ##
|
||||
|
||||
# A "Bail out!" directive should cause us to ignore any following TAP
|
||||
# error, as well as a non-zero exit status from the TAP producer.
|
||||
if (!bailed_out)
|
||||
{
|
||||
if (!plan_seen)
|
||||
{
|
||||
testsuite_error("missing test plan")
|
||||
}
|
||||
else if (planned_tests != testno)
|
||||
{
|
||||
bad_amount = testno > planned_tests ? "many" : "few"
|
||||
testsuite_error(sprintf("too %s tests run (expected %d, got %d)",
|
||||
bad_amount, planned_tests, testno))
|
||||
}
|
||||
if (!ignore_exit)
|
||||
{
|
||||
# Fetch exit status from the last line.
|
||||
exit_message = get_test_exit_message(nextline)
|
||||
if (exit_message)
|
||||
testsuite_error(exit_message)
|
||||
}
|
||||
}
|
||||
|
||||
write_test_results()
|
||||
|
||||
exit 0
|
||||
|
||||
} # End of "BEGIN" block.
|
||||
'
|
||||
|
||||
# TODO: document that we consume the file descriptor 3 :-(
|
||||
} 3>"$log_file"
|
||||
|
||||
test $? -eq 0 || fatal "I/O or internal error"
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-time-zone: "UTC"
|
||||
# time-stamp-end: "; # UTC"
|
||||
# End:
|
||||
+1
@@ -0,0 +1 @@
|
||||
$@ | tapout tap
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
ACLOCAL_AMFLAGS = ${ACLOCAL_FLAGS} -I m4 -I script
|
||||
|
||||
AM_COPT = -Wall -O2
|
||||
AM_COVLDFLAGS =
|
||||
|
||||
if ENABLE_COVERAGE
|
||||
AM_COPT = -O0 --coverage
|
||||
AM_COVLDFLAGS += -lgcov
|
||||
endif
|
||||
|
||||
AM_CPPFLAGS = -I$(top_srcdir)/include
|
||||
AM_CFLAGS = $(AM_COPT)
|
||||
AM_CXXFLAGS = $(AM_COPT)
|
||||
AM_LDFLAGS = $(AM_COPT) $(AM_COVLDFLAGS)
|
||||
|
||||
if COMPILER_IS_MINGW32
|
||||
AM_CXXFLAGS += -std=gnu++0x
|
||||
else
|
||||
AM_CXXFLAGS += -std=c++0x
|
||||
endif
|
||||
|
||||
EXTRA_DIST = \
|
||||
COPYING \
|
||||
INSTALL \
|
||||
LICENSE \
|
||||
Readme.md
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = support/libsass.pc
|
||||
|
||||
lib_LTLIBRARIES = libsass.la
|
||||
|
||||
include $(top_srcdir)/Makefile.conf
|
||||
|
||||
libsass_la_SOURCES = ${CSOURCES} ${SOURCES}
|
||||
|
||||
libsass_la_LDFLAGS = $(AM_LDFLAGS) -no-undefined -version-info 0:9:0
|
||||
|
||||
if ENABLE_TESTS
|
||||
if ENABLE_COVERAGE
|
||||
nodist_EXTRA_libsass_la_SOURCES = non-existent-file-to-force-CXX-linking.cxx
|
||||
endif
|
||||
endif
|
||||
|
||||
include_HEADERS = $(top_srcdir)/include/sass.h \
|
||||
$(top_srcdir)/include/sass2scss.h
|
||||
|
||||
sass_includedir = $(includedir)/sass
|
||||
|
||||
sass_include_HEADERS = $(top_srcdir)/include/sass/base.h \
|
||||
$(top_srcdir)/include/sass/values.h \
|
||||
$(top_srcdir)/include/sass/version.h \
|
||||
$(top_srcdir)/include/sass/context.h \
|
||||
$(top_srcdir)/include/sass/functions.h
|
||||
+2216
File diff suppressed because it is too large
Load Diff
+2549
File diff suppressed because it is too large
Load Diff
+55
@@ -0,0 +1,55 @@
|
||||
#ifndef SASS_AST_DEF_MACROS_H
|
||||
#define SASS_AST_DEF_MACROS_H
|
||||
|
||||
// Helper class to switch a flag and revert once we go out of scope
|
||||
template <class T>
|
||||
class LocalOption {
|
||||
private:
|
||||
T* var; // pointer to original variable
|
||||
T orig; // copy of the original option
|
||||
public:
|
||||
LocalOption(T& var)
|
||||
{
|
||||
this->var = &var;
|
||||
this->orig = var;
|
||||
}
|
||||
LocalOption(T& var, T orig)
|
||||
{
|
||||
this->var = &var;
|
||||
this->orig = var;
|
||||
*(this->var) = orig;
|
||||
}
|
||||
~LocalOption() {
|
||||
*(this->var) = this->orig;
|
||||
}
|
||||
};
|
||||
|
||||
#define LOCAL_FLAG(name,opt) LocalOption<bool> flag_##name(name, opt)
|
||||
|
||||
#define ATTACH_OPERATIONS()\
|
||||
virtual void perform(Operation<void>* op) { (*op)(this); }\
|
||||
virtual AST_Node* perform(Operation<AST_Node*>* op) { return (*op)(this); }\
|
||||
virtual Statement* perform(Operation<Statement*>* op) { return (*op)(this); }\
|
||||
virtual Expression* perform(Operation<Expression*>* op) { return (*op)(this); }\
|
||||
virtual Selector* perform(Operation<Selector*>* op) { return (*op)(this); }\
|
||||
virtual std::string perform(Operation<std::string>* op) { return (*op)(this); }\
|
||||
virtual union Sass_Value* perform(Operation<union Sass_Value*>* op) { return (*op)(this); }\
|
||||
virtual Value* perform(Operation<Value*>* op) { return (*op)(this); }
|
||||
|
||||
#define ADD_PROPERTY(type, name)\
|
||||
protected:\
|
||||
type name##_;\
|
||||
public:\
|
||||
type name() const { return name##_; }\
|
||||
type name(type name##__) { return name##_ = name##__; }\
|
||||
private:
|
||||
|
||||
#define ADD_HASHED(type, name)\
|
||||
protected:\
|
||||
type name##_;\
|
||||
public:\
|
||||
type name() const { return name##_; }\
|
||||
type name(type name##__) { hash_ = 0; return name##_ = name##__; }\
|
||||
private:
|
||||
|
||||
#endif
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
#ifndef SASS_AST_FACTORY_H
|
||||
#define SASS_AST_FACTORY_H
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "ast.hpp"
|
||||
|
||||
namespace Sass {
|
||||
|
||||
class AST_Factory {
|
||||
std::vector<AST_Node*> nodes;
|
||||
public:
|
||||
// statements
|
||||
Block* new_Block(std::string p, size_t l, size_t s = 0, bool r = false);
|
||||
Ruleset* new_Ruleset(std::string p, size_t l, Selector* s, Block* b);
|
||||
Propset* new_Propset(std::string p, size_t l, String* pf, Block* b);
|
||||
Supports_Query* new_Supports_Query(std::string p, size_t l, Supports_Query* f, Block* b);
|
||||
Media_Query* new_Media_Query(std::string p, size_t l, List* q, Block* b);
|
||||
At_Root_Block* new_At_Root_Block(std::string p, size_t l, Selector* sel, Block* b);
|
||||
Directive* new_At_Rule(std::string p, size_t l, std::string kwd, Selector* sel, Block* b);
|
||||
Keyframe_Rule* new_Keyframe_Rule(std::string p, size_t l, Block* b);
|
||||
Declaration* new_Declaration(std::string p, size_t l, String* prop, List* vals);
|
||||
Assignment* new_Assignment(std::string p, size_t l, std::string var, Expression* val, bool guarded = false);
|
||||
Import<Function_Call*>* new_CSS_Import(std::string p, size_t l, Function_Call* loc);
|
||||
Import<String*>* new_SASS_Import(std::string p, size_t l, String* loc);
|
||||
Custom_Warning* new_Custom_Warning(std::string msg, size_t l, std::string msg);
|
||||
Custom_Error* new_Custom_Error(std::string p, size_t l, std::string msg);
|
||||
Warning* new_Warning(std::string p, size_t l, Expression* msg);
|
||||
Error* new_Error(std::string p, size_t l, Expression* msg);
|
||||
Debug* new_Debug(std::string p, size_t l, Expression* val);
|
||||
Comment* new_Comment(std::string p, size_t l, String* txt);
|
||||
If* new_If(std::string p, size_t l, Expression* pred, Block* con, Block* alt = 0);
|
||||
For* new_For(std::string p, size_t l, std::string var, Expression* lo, Expression* hi, Block* b, bool inc);
|
||||
Each* new_Each(std::string p, size_t l, std::vector<std::string> vars, Expression* lst, Block* b);
|
||||
While* new_While(std::string p, size_t l, Expression* pred, Block* b);
|
||||
Extension* new_Extension(std::string p, size_t l, Selector* s);
|
||||
Definition<MIXIN>* new_Mixin_Definition(std::string p, size_t l, std::string n, Parameters* params, Block* b);
|
||||
Definition<FUNCTION>* new_Function_Definition(std::string p, size_t l, std::string n, Parameters* params, Block* b);
|
||||
Mixin_Call* new_Mixin_Call(std::string p, size_t l, std::string n, Arguments* args, Block* b = 0);
|
||||
// expressions
|
||||
List* new_List(std::string p, size_t l, size_t size = 0, enum Sass_Separator sep = List::space, bool argl = false);
|
||||
Map* new_Map(std::string p, size_t l, size_t size = 0);
|
||||
Binary_Expression<AND>* new_And(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<OR>* new_Or(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<EQ>* new_Eq(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<NEQ>* new_Neq(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<GT>* new_Gt(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<GTE>* new_Gte(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<LT>* new_Lt(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<LTE>* new_Lte(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<ADD>* new_Add(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<SUB>* new_Sub(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<MUL>* new_Mul(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Binary_Expression<DIV>* new_Div(std::string p, size_t l, Expression* lhs, Expression* rhs);
|
||||
Negation* new_Negation(std::string p, size_t l, Expression* o);
|
||||
Function_Call* new_Function_Call(std::string p, size_t l, String* n, Arguments* args);
|
||||
Variable* new_Variable(std::string p, size_t l, std::string n);
|
||||
Textual<NUMBER>* new_Textual_Number(std::string p, size_t l, std::string val);
|
||||
Textual<PERCENTAGE>* new_Textual_Percentage(std::string p, size_t l, std::string val);
|
||||
Textual<DIMENSION>* new_Textual_Dimension(std::string p, size_t l, std::string val);
|
||||
Textual<HEX>* new_Textual_Hex(std::string p, size_t l, std::string val);
|
||||
Number* new_Number(std::string p, size_t l, double val);
|
||||
Percentage* new_Percentage(std::string p, size_t l, double val);
|
||||
Dimension* new_Dimension(std::string p, size_t l, double val, std::string unit);
|
||||
Color* new_Color(std::string p, size_t l, double r, double g, double b, double a = 1, std::string disp = "");
|
||||
Boolean* new_Boolean(std::string p, size_t l, bool val);
|
||||
String_Schema* new_String_Schema(std::string p, size_t l, size_t size = 0);
|
||||
String_Constant* new_String_Constant(std::string p, size_t l, std::string val);
|
||||
String_Constant* new_String_Constant(std::string p, size_t l, const char* beg);
|
||||
String_Constant* new_String_Constant(std::string p, size_t l, const char* beg, const char* end);
|
||||
Supports_Condition* new_Supports_Condition(std::string p, size_t l, String* f, Expression* v);
|
||||
Media_Expression* new_Media_Expression(std::string p, size_t l, String* f, Expression* v);
|
||||
Parent_Selector* new_Parent_Selector(std::string p, size_t l, Selector* s);
|
||||
// parameters and arguments
|
||||
Parameter* new_Parameter(std::string p, size_t l, std::string n, Expression* def = 0, bool rest = false);
|
||||
Parameters* new_Parameters(std::string p, size_t l);
|
||||
Argument* new_Argument(std::string p, size_t l, Expression* val, std::string n = "", bool rest = false);
|
||||
Arguments* new_Arguments(std::string p, size_t l);
|
||||
// selectors
|
||||
Selector_Schema* new_Selector_Schema(std::string p, size_t l, String* c);
|
||||
Attribute_Selector* new_Attribute_Selector(std::string p, size_t l, std::string n, std::string m, String* v);
|
||||
Simple_Selector* new_Simple_Selector(std::string p, size_t l, std::string c);
|
||||
Reference_Selector* new_Reference_Selector(std::string p, size_t l);
|
||||
Placeholder_Selector* new_Placeholder_Selector(std::string p, size_t l, std::string n);
|
||||
Pseudo_Selector* new_Pseudo_Selector(std::string p, size_t l, std::string n, Expression* expr = 0);
|
||||
Wrapped_Selector* new_Wrapped_Selector(std::string p, size_t l, std::string n, Simple_Base* sel);
|
||||
Compound_Selector* new_Compound_Selector(std::string p, size_t l, size_t s = 0);
|
||||
Complex_Selector* new_Complex_Selector(std::string p, size_t l, Complex_Selector::Combinator c, Complex_Selector* ctx, Compound_Selector* sel);
|
||||
Selector_List* new_Selector_List(std::string p, size_t l, size_t s = 0);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
#ifndef SASS_AST_FWD_DECL_H
|
||||
#define SASS_AST_FWD_DECL_H
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// Forward declarations for the AST visitors.
|
||||
/////////////////////////////////////////////
|
||||
namespace Sass {
|
||||
|
||||
class AST_Node;
|
||||
// statements
|
||||
class Statement;
|
||||
class Block;
|
||||
class Ruleset;
|
||||
class Propset;
|
||||
class Bubble;
|
||||
class Media_Block;
|
||||
class Supports_Block;
|
||||
class Directive;
|
||||
class Keyframe_Rule;
|
||||
class At_Root_Block;
|
||||
class Declaration;
|
||||
class Assignment;
|
||||
class Import;
|
||||
class Import_Stub;
|
||||
class Warning;
|
||||
class Error;
|
||||
class Debug;
|
||||
class Comment;
|
||||
class If;
|
||||
class For;
|
||||
class Each;
|
||||
class While;
|
||||
class Return;
|
||||
class Content;
|
||||
class Extension;
|
||||
class Definition;
|
||||
class Mixin_Call;
|
||||
// expressions
|
||||
class Value;
|
||||
class Expression;
|
||||
class List;
|
||||
class Map;
|
||||
class Binary_Expression;
|
||||
class Unary_Expression;
|
||||
class Function_Call;
|
||||
class Function_Call_Schema;
|
||||
class Custom_Warning;
|
||||
class Custom_Error;
|
||||
class Variable;
|
||||
class Textual;
|
||||
class Number;
|
||||
class Color;
|
||||
class Boolean;
|
||||
class String_Schema;
|
||||
class String;
|
||||
class String_Constant;
|
||||
class String_Quoted;
|
||||
class Media_Query;
|
||||
class Media_Query_Expression;
|
||||
class Supports_Condition;
|
||||
class Supports_Operator;
|
||||
class Supports_Negation;
|
||||
class Supports_Declaration;
|
||||
class Supports_Interpolation;
|
||||
class At_Root_Query;
|
||||
class Null;
|
||||
class Parent_Selector;
|
||||
// parameters and arguments
|
||||
class Parameter;
|
||||
class Parameters;
|
||||
class Argument;
|
||||
class Arguments;
|
||||
// selectors
|
||||
class Selector;
|
||||
class Selector_Schema;
|
||||
class Selector_Placeholder;
|
||||
class Type_Selector;
|
||||
class Selector_Qualifier;
|
||||
class Attribute_Selector;
|
||||
class Pseudo_Selector;
|
||||
class Wrapped_Selector;
|
||||
class Compound_Selector;
|
||||
class Complex_Selector;
|
||||
class Selector_List;
|
||||
|
||||
// common classes
|
||||
class Context;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
cencode.h - c header for a base64 encoding algorithm
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#ifndef BASE64_CENCODE_H
|
||||
#define BASE64_CENCODE_H
|
||||
|
||||
typedef enum
|
||||
{
|
||||
step_A, step_B, step_C
|
||||
} base64_encodestep;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
base64_encodestep step;
|
||||
char result;
|
||||
int stepcount;
|
||||
} base64_encodestate;
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in);
|
||||
|
||||
char base64_encode_value(char value_in);
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in);
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in);
|
||||
|
||||
#endif /* BASE64_CENCODE_H */
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
// :mode=c++:
|
||||
/*
|
||||
encode.h - c++ wrapper for a base64 encoding algorithm
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
#ifndef BASE64_ENCODE_H
|
||||
#define BASE64_ENCODE_H
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace base64
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
#include "cencode.h"
|
||||
}
|
||||
|
||||
struct encoder
|
||||
{
|
||||
base64_encodestate _state;
|
||||
int _buffersize;
|
||||
|
||||
encoder(int buffersize_in = BUFFERSIZE)
|
||||
: _buffersize(buffersize_in)
|
||||
{}
|
||||
|
||||
int encode(char value_in)
|
||||
{
|
||||
return base64_encode_value(value_in);
|
||||
}
|
||||
|
||||
int encode(const char* code_in, const int length_in, char* plaintext_out)
|
||||
{
|
||||
return base64_encode_block(code_in, length_in, plaintext_out, &_state);
|
||||
}
|
||||
|
||||
int encode_end(char* plaintext_out)
|
||||
{
|
||||
return base64_encode_blockend(plaintext_out, &_state);
|
||||
}
|
||||
|
||||
void encode(std::istream& istream_in, std::ostream& ostream_in)
|
||||
{
|
||||
base64_init_encodestate(&_state);
|
||||
//
|
||||
const int N = _buffersize;
|
||||
char* plaintext = new char[N];
|
||||
char* code = new char[2*N];
|
||||
int plainlength;
|
||||
int codelength;
|
||||
|
||||
do
|
||||
{
|
||||
istream_in.read(plaintext, N);
|
||||
plainlength = static_cast<int>(istream_in.gcount());
|
||||
//
|
||||
codelength = encode(plaintext, plainlength, code);
|
||||
ostream_in.write(code, codelength);
|
||||
}
|
||||
while (istream_in.good() && plainlength > 0);
|
||||
|
||||
codelength = encode_end(code);
|
||||
ostream_in.write(code, codelength);
|
||||
//
|
||||
base64_init_encodestate(&_state);
|
||||
|
||||
delete [] code;
|
||||
delete [] plaintext;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace base64
|
||||
|
||||
#endif // BASE64_ENCODE_H
|
||||
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
#ifndef SASS_BACKTRACE_H
|
||||
#define SASS_BACKTRACE_H
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "file.hpp"
|
||||
#include "position.hpp"
|
||||
|
||||
namespace Sass {
|
||||
|
||||
|
||||
struct Backtrace {
|
||||
|
||||
Backtrace* parent;
|
||||
ParserState pstate;
|
||||
std::string caller;
|
||||
|
||||
Backtrace(Backtrace* prn, ParserState pstate, std::string c)
|
||||
: parent(prn),
|
||||
pstate(pstate),
|
||||
caller(c)
|
||||
{ }
|
||||
|
||||
std::string to_string(bool warning = false)
|
||||
{
|
||||
size_t i = -1;
|
||||
std::stringstream ss;
|
||||
std::string cwd(Sass::File::get_cwd());
|
||||
Backtrace* this_point = this;
|
||||
|
||||
if (!warning) ss << std::endl << "Backtrace:";
|
||||
// the first tracepoint (which is parent-less) is an empty placeholder
|
||||
while (this_point->parent) {
|
||||
|
||||
// make path relative to the current directory
|
||||
std::string rel_path(Sass::File::abs2rel(this_point->pstate.path, cwd, cwd));
|
||||
|
||||
if (warning) {
|
||||
ss << std::endl
|
||||
<< "\t"
|
||||
<< (++i == 0 ? "on" : "from")
|
||||
<< " line "
|
||||
<< this_point->pstate.line + 1
|
||||
<< " of "
|
||||
<< rel_path;
|
||||
} else {
|
||||
ss << std::endl
|
||||
<< "\t"
|
||||
<< rel_path
|
||||
<< ":"
|
||||
<< this_point->pstate.line + 1
|
||||
<< this_point->parent->caller;
|
||||
}
|
||||
|
||||
this_point = this_point->parent;
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
size_t depth()
|
||||
{
|
||||
size_t d = 0;
|
||||
Backtrace* p = parent;
|
||||
while (p) {
|
||||
++d;
|
||||
p = p->parent;
|
||||
}
|
||||
return d-1;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
#include "sass.hpp"
|
||||
#include "base64vlq.hpp"
|
||||
|
||||
namespace Sass {
|
||||
|
||||
std::string Base64VLQ::encode(const int number) const
|
||||
{
|
||||
std::string encoded = "";
|
||||
|
||||
int vlq = to_vlq_signed(number);
|
||||
|
||||
do {
|
||||
int digit = vlq & VLQ_BASE_MASK;
|
||||
vlq >>= VLQ_BASE_SHIFT;
|
||||
if (vlq > 0) {
|
||||
digit |= VLQ_CONTINUATION_BIT;
|
||||
}
|
||||
encoded += base64_encode(digit);
|
||||
} while (vlq > 0);
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
char Base64VLQ::base64_encode(const int number) const
|
||||
{
|
||||
int index = number;
|
||||
if (index < 0) index = 0;
|
||||
if (index > 63) index = 63;
|
||||
return CHARACTERS[index];
|
||||
}
|
||||
|
||||
int Base64VLQ::to_vlq_signed(const int number) const
|
||||
{
|
||||
return (number < 0) ? ((-number) << 1) + 1 : (number << 1) + 0;
|
||||
}
|
||||
|
||||
const char* Base64VLQ::CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
const int Base64VLQ::VLQ_BASE_SHIFT = 5;
|
||||
const int Base64VLQ::VLQ_BASE = 1 << VLQ_BASE_SHIFT;
|
||||
const int Base64VLQ::VLQ_BASE_MASK = VLQ_BASE - 1;
|
||||
const int Base64VLQ::VLQ_CONTINUATION_BIT = VLQ_BASE;
|
||||
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
#ifndef SASS_BASE64VLQ_H
|
||||
#define SASS_BASE64VLQ_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Sass {
|
||||
|
||||
class Base64VLQ {
|
||||
|
||||
public:
|
||||
|
||||
std::string encode(const int number) const;
|
||||
|
||||
private:
|
||||
|
||||
char base64_encode(const int number) const;
|
||||
|
||||
int to_vlq_signed(const int number) const;
|
||||
|
||||
static const char* CHARACTERS;
|
||||
|
||||
static const int VLQ_BASE_SHIFT;
|
||||
static const int VLQ_BASE;
|
||||
static const int VLQ_BASE_MASK;
|
||||
static const int VLQ_CONTINUATION_BIT;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
#include "sass.hpp"
|
||||
#include "bind.hpp"
|
||||
#include "ast.hpp"
|
||||
#include "context.hpp"
|
||||
#include "eval.hpp"
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
namespace Sass {
|
||||
|
||||
void bind(std::string type, std::string name, Parameters* ps, Arguments* as, Context* ctx, Env* env, Eval* eval)
|
||||
{
|
||||
std::string callee(type + " " + name);
|
||||
|
||||
Listize listize(ctx->mem);
|
||||
std::map<std::string, Parameter*> param_map;
|
||||
|
||||
for (size_t i = 0, L = as->length(); i < L; ++i) {
|
||||
if (auto str = dynamic_cast<String_Quoted*>((*as)[i]->value())) {
|
||||
// force optional quotes (only if needed)
|
||||
if (str->quote_mark()) {
|
||||
str->quote_mark('*');
|
||||
str->is_delayed(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up a map to ensure named arguments refer to actual parameters. Also
|
||||
// eval each default value left-to-right, wrt env, populating env as we go.
|
||||
for (size_t i = 0, L = ps->length(); i < L; ++i) {
|
||||
Parameter* p = (*ps)[i];
|
||||
param_map[p->name()] = p;
|
||||
// if (p->default_value()) {
|
||||
// env->local_frame()[p->name()] = p->default_value()->perform(eval->with(env));
|
||||
// }
|
||||
}
|
||||
|
||||
// plug in all args; if we have leftover params, deal with it later
|
||||
size_t ip = 0, LP = ps->length();
|
||||
size_t ia = 0, LA = as->length();
|
||||
while (ia < LA) {
|
||||
Argument* a = (*as)[ia];
|
||||
if (ip >= LP) {
|
||||
// skip empty rest arguments
|
||||
if (a->is_rest_argument()) {
|
||||
if (List* l = dynamic_cast<List*>(a->value())) {
|
||||
if (l->length() == 0) {
|
||||
++ ia; continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::stringstream msg;
|
||||
msg << "wrong number of arguments (" << LA << " for " << LP << ")";
|
||||
msg << " for `" << name << "'";
|
||||
return error(msg.str(), as->pstate());
|
||||
}
|
||||
Parameter* p = (*ps)[ip];
|
||||
|
||||
// If the current parameter is the rest parameter, process and break the loop
|
||||
if (p->is_rest_parameter()) {
|
||||
// The next argument by coincidence provides a rest argument
|
||||
if (a->is_rest_argument()) {
|
||||
|
||||
// We should always get a list for rest arguments
|
||||
if (List* rest = dynamic_cast<List*>(a->value())) {
|
||||
// create a new list object for wrapped items
|
||||
List* arglist = SASS_MEMORY_NEW(ctx->mem, List,
|
||||
p->pstate(),
|
||||
0,
|
||||
rest->separator(),
|
||||
true);
|
||||
// wrap each item from list as an argument
|
||||
for (Expression* item : rest->elements()) {
|
||||
if (Argument* arg = dynamic_cast<Argument*>(item)) {
|
||||
(*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg);
|
||||
} else {
|
||||
(*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
|
||||
item->pstate(),
|
||||
item,
|
||||
"",
|
||||
false,
|
||||
false);
|
||||
}
|
||||
}
|
||||
// assign new arglist to environment
|
||||
env->local_frame()[p->name()] = arglist;
|
||||
}
|
||||
// invalid state
|
||||
else {
|
||||
throw std::runtime_error("invalid state");
|
||||
}
|
||||
} else if (a->is_keyword_argument()) {
|
||||
|
||||
// expand keyword arguments into their parameters
|
||||
List* arglist = SASS_MEMORY_NEW(ctx->mem, List, p->pstate(), 0, SASS_COMMA, true);
|
||||
env->local_frame()[p->name()] = arglist;
|
||||
Map* argmap = static_cast<Map*>(a->value());
|
||||
for (auto key : argmap->keys()) {
|
||||
std::string name = unquote(static_cast<String_Constant*>(key)->value());
|
||||
(*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
|
||||
key->pstate(),
|
||||
argmap->at(key),
|
||||
"$" + name,
|
||||
false,
|
||||
false);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
// create a new list object for wrapped items
|
||||
List* arglist = SASS_MEMORY_NEW(ctx->mem, List,
|
||||
p->pstate(),
|
||||
0,
|
||||
SASS_COMMA,
|
||||
true);
|
||||
// consume the next args
|
||||
while (ia < LA) {
|
||||
// get and post inc
|
||||
a = (*as)[ia++];
|
||||
// maybe we have another list as argument
|
||||
List* ls = dynamic_cast<List*>(a->value());
|
||||
// skip any list completely if empty
|
||||
if (ls && ls->empty() && a->is_rest_argument()) continue;
|
||||
|
||||
if (Argument* arg = dynamic_cast<Argument*>(a->value())) {
|
||||
(*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument, *arg);
|
||||
}
|
||||
// check if we have rest argument
|
||||
else if (a->is_rest_argument()) {
|
||||
// preserve the list separator from rest args
|
||||
if (List* rest = dynamic_cast<List*>(a->value())) {
|
||||
arglist->separator(rest->separator());
|
||||
|
||||
for (size_t i = 0, L = rest->size(); i < L; ++i) {
|
||||
(*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
|
||||
(*rest)[i]->pstate(),
|
||||
(*rest)[i],
|
||||
"",
|
||||
false,
|
||||
false);
|
||||
}
|
||||
}
|
||||
// no more arguments
|
||||
break;
|
||||
}
|
||||
// wrap all other value types into Argument
|
||||
else {
|
||||
(*arglist) << SASS_MEMORY_NEW(ctx->mem, Argument,
|
||||
a->pstate(),
|
||||
a->value(),
|
||||
a->name(),
|
||||
false,
|
||||
false);
|
||||
}
|
||||
}
|
||||
// assign new arglist to environment
|
||||
env->local_frame()[p->name()] = arglist;
|
||||
}
|
||||
// consumed parameter
|
||||
++ip;
|
||||
// no more paramaters
|
||||
break;
|
||||
}
|
||||
|
||||
// If the current argument is the rest argument, extract a value for processing
|
||||
else if (a->is_rest_argument()) {
|
||||
// normal param and rest arg
|
||||
List* arglist = static_cast<List*>(a->value());
|
||||
// empty rest arg - treat all args as default values
|
||||
if (!arglist->length()) {
|
||||
break;
|
||||
} else {
|
||||
if (arglist->length() > LP - ip && !ps->has_rest_parameter()) {
|
||||
int arg_count = (arglist->length() + LA - 1);
|
||||
std::stringstream msg;
|
||||
msg << callee << " takes " << LP;
|
||||
msg << (LP == 1 ? " argument" : " arguments");
|
||||
msg << " but " << arg_count;
|
||||
msg << (arg_count == 1 ? " was passed" : " were passed.");
|
||||
deprecated_bind(msg.str(), as->pstate());
|
||||
|
||||
while (arglist->length() > LP - ip) {
|
||||
arglist->elements().erase(arglist->elements().end() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
// otherwise move one of the rest args into the param, converting to argument if necessary
|
||||
if (!(a = dynamic_cast<Argument*>((*arglist)[0]))) {
|
||||
Expression* a_to_convert = (*arglist)[0];
|
||||
a = SASS_MEMORY_NEW(ctx->mem, Argument,
|
||||
a_to_convert->pstate(),
|
||||
a_to_convert,
|
||||
"",
|
||||
false,
|
||||
false);
|
||||
}
|
||||
arglist->elements().erase(arglist->elements().begin());
|
||||
if (!arglist->length() || (!arglist->is_arglist() && ip + 1 == LP)) {
|
||||
++ia;
|
||||
}
|
||||
|
||||
} else if (a->is_keyword_argument()) {
|
||||
Map* argmap = static_cast<Map*>(a->value());
|
||||
|
||||
for (auto key : argmap->keys()) {
|
||||
std::string name = "$" + unquote(static_cast<String_Constant*>(key)->value());
|
||||
|
||||
if (!param_map.count(name)) {
|
||||
std::stringstream msg;
|
||||
msg << callee << " has no parameter named " << name;
|
||||
error(msg.str(), a->pstate());
|
||||
}
|
||||
env->local_frame()[name] = argmap->at(key);
|
||||
}
|
||||
++ia;
|
||||
continue;
|
||||
} else {
|
||||
++ia;
|
||||
}
|
||||
|
||||
if (a->name().empty()) {
|
||||
if (env->has_local(p->name())) {
|
||||
std::stringstream msg;
|
||||
msg << "parameter " << p->name()
|
||||
<< " provided more than once in call to " << callee;
|
||||
error(msg.str(), a->pstate());
|
||||
}
|
||||
// ordinal arg -- bind it to the next param
|
||||
env->local_frame()[p->name()] = a->value();
|
||||
++ip;
|
||||
}
|
||||
else {
|
||||
// named arg -- bind it to the appropriately named param
|
||||
if (!param_map.count(a->name())) {
|
||||
std::stringstream msg;
|
||||
msg << callee << " has no parameter named " << a->name();
|
||||
error(msg.str(), a->pstate());
|
||||
}
|
||||
if (param_map[a->name()]->is_rest_parameter()) {
|
||||
std::stringstream msg;
|
||||
msg << "argument " << a->name() << " of " << callee
|
||||
<< "cannot be used as named argument";
|
||||
error(msg.str(), a->pstate());
|
||||
}
|
||||
if (env->has_local(a->name())) {
|
||||
std::stringstream msg;
|
||||
msg << "parameter " << p->name()
|
||||
<< "provided more than once in call to " << callee;
|
||||
error(msg.str(), a->pstate());
|
||||
}
|
||||
env->local_frame()[a->name()] = a->value();
|
||||
}
|
||||
}
|
||||
// EO while ia
|
||||
|
||||
// If we make it here, we're out of args but may have leftover params.
|
||||
// That's only okay if they have default values, or were already bound by
|
||||
// named arguments, or if it's a single rest-param.
|
||||
for (size_t i = ip; i < LP; ++i) {
|
||||
Parameter* leftover = (*ps)[i];
|
||||
// cerr << "env for default params:" << endl;
|
||||
// env->print();
|
||||
// cerr << "********" << endl;
|
||||
if (!env->has_local(leftover->name())) {
|
||||
if (leftover->is_rest_parameter()) {
|
||||
env->local_frame()[leftover->name()] = SASS_MEMORY_NEW(ctx->mem, List,
|
||||
leftover->pstate(),
|
||||
0,
|
||||
SASS_COMMA,
|
||||
true);
|
||||
}
|
||||
else if (leftover->default_value()) {
|
||||
Expression* dv = leftover->default_value()->perform(eval);
|
||||
env->local_frame()[leftover->name()] = dv;
|
||||
}
|
||||
else {
|
||||
// param is unbound and has no default value -- error
|
||||
std::stringstream msg;
|
||||
msg << "required parameter " << leftover->name()
|
||||
<< " is missing in call to " << callee;
|
||||
error(msg.str(), as->pstate());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#ifndef SASS_BIND_H
|
||||
#define SASS_BIND_H
|
||||
|
||||
#include <string>
|
||||
#include "listize.hpp"
|
||||
#include "environment.hpp"
|
||||
|
||||
namespace Sass {
|
||||
class AST_Node;
|
||||
class Parameters;
|
||||
class Arguments;
|
||||
class Context;
|
||||
class Eval;
|
||||
typedef Environment<AST_Node*> Env;
|
||||
|
||||
void bind(std::string type, std::string name, Parameters*, Arguments*, Context*, Env*, Eval*);
|
||||
}
|
||||
|
||||
#endif
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright (C) 2011 Joseph A. Adams (joeyadams3.14159@gmail.com)
|
||||
All rights reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER < 1900
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
static int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
|
||||
{
|
||||
int count = -1;
|
||||
|
||||
if (size != 0)
|
||||
count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
|
||||
if (count == -1)
|
||||
count = _vscprintf(format, ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int snprintf(char* str, size_t size, const char* format, ...)
|
||||
{
|
||||
int count;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
count = c99_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
cencoder.c - c source to a base64 encoding algorithm implementation
|
||||
|
||||
This is part of the libb64 project, and has been placed in the public domain.
|
||||
For details, see http://sourceforge.net/projects/libb64
|
||||
*/
|
||||
|
||||
#include "b64/cencode.h"
|
||||
|
||||
void base64_init_encodestate(base64_encodestate* state_in)
|
||||
{
|
||||
state_in->step = step_A;
|
||||
state_in->result = 0;
|
||||
state_in->stepcount = 0;
|
||||
}
|
||||
|
||||
char base64_encode_value(char value_in)
|
||||
{
|
||||
static const char* encoding = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
if (value_in > 63) return '=';
|
||||
return encoding[(int)value_in];
|
||||
}
|
||||
|
||||
int base64_encode_block(const char* plaintext_in, int length_in, char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
const char* plainchar = plaintext_in;
|
||||
const char* const plaintextend = plaintext_in + length_in;
|
||||
char* codechar = code_out;
|
||||
char result;
|
||||
char fragment;
|
||||
|
||||
result = state_in->result;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
case step_A:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_A;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result = (fragment & 0x0fc) >> 2;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x003) << 4;
|
||||
case step_B:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_B;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0f0) >> 4;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x00f) << 2;
|
||||
case step_C:
|
||||
if (plainchar == plaintextend)
|
||||
{
|
||||
state_in->result = result;
|
||||
state_in->step = step_C;
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
fragment = *plainchar++;
|
||||
result |= (fragment & 0x0c0) >> 6;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
result = (fragment & 0x03f) >> 0;
|
||||
*codechar++ = base64_encode_value(result);
|
||||
|
||||
++(state_in->stepcount);
|
||||
}
|
||||
}
|
||||
/* control should not reach here */
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
|
||||
int base64_encode_blockend(char* code_out, base64_encodestate* state_in)
|
||||
{
|
||||
char* codechar = code_out;
|
||||
|
||||
switch (state_in->step)
|
||||
{
|
||||
case step_B:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_C:
|
||||
*codechar++ = base64_encode_value(state_in->result);
|
||||
*codechar++ = '=';
|
||||
break;
|
||||
case step_A:
|
||||
break;
|
||||
}
|
||||
*codechar++ = '\n';
|
||||
|
||||
return (int)(codechar - code_out);
|
||||
}
|
||||
|
||||
+644
@@ -0,0 +1,644 @@
|
||||
#include "sass.hpp"
|
||||
#include "ast.hpp"
|
||||
#include "color_maps.hpp"
|
||||
|
||||
namespace Sass {
|
||||
|
||||
namespace ColorNames
|
||||
{
|
||||
const char aliceblue [] = "aliceblue";
|
||||
const char antiquewhite [] = "antiquewhite";
|
||||
const char cyan [] = "cyan";
|
||||
const char aqua [] = "aqua";
|
||||
const char aquamarine [] = "aquamarine";
|
||||
const char azure [] = "azure";
|
||||
const char beige [] = "beige";
|
||||
const char bisque [] = "bisque";
|
||||
const char black [] = "black";
|
||||
const char blanchedalmond [] = "blanchedalmond";
|
||||
const char blue [] = "blue";
|
||||
const char blueviolet [] = "blueviolet";
|
||||
const char brown [] = "brown";
|
||||
const char burlywood [] = "burlywood";
|
||||
const char cadetblue [] = "cadetblue";
|
||||
const char chartreuse [] = "chartreuse";
|
||||
const char chocolate [] = "chocolate";
|
||||
const char coral [] = "coral";
|
||||
const char cornflowerblue [] = "cornflowerblue";
|
||||
const char cornsilk [] = "cornsilk";
|
||||
const char crimson [] = "crimson";
|
||||
const char darkblue [] = "darkblue";
|
||||
const char darkcyan [] = "darkcyan";
|
||||
const char darkgoldenrod [] = "darkgoldenrod";
|
||||
const char darkgray [] = "darkgray";
|
||||
const char darkgrey [] = "darkgrey";
|
||||
const char darkgreen [] = "darkgreen";
|
||||
const char darkkhaki [] = "darkkhaki";
|
||||
const char darkmagenta [] = "darkmagenta";
|
||||
const char darkolivegreen [] = "darkolivegreen";
|
||||
const char darkorange [] = "darkorange";
|
||||
const char darkorchid [] = "darkorchid";
|
||||
const char darkred [] = "darkred";
|
||||
const char darksalmon [] = "darksalmon";
|
||||
const char darkseagreen [] = "darkseagreen";
|
||||
const char darkslateblue [] = "darkslateblue";
|
||||
const char darkslategray [] = "darkslategray";
|
||||
const char darkslategrey [] = "darkslategrey";
|
||||
const char darkturquoise [] = "darkturquoise";
|
||||
const char darkviolet [] = "darkviolet";
|
||||
const char deeppink [] = "deeppink";
|
||||
const char deepskyblue [] = "deepskyblue";
|
||||
const char dimgray [] = "dimgray";
|
||||
const char dimgrey [] = "dimgrey";
|
||||
const char dodgerblue [] = "dodgerblue";
|
||||
const char firebrick [] = "firebrick";
|
||||
const char floralwhite [] = "floralwhite";
|
||||
const char forestgreen [] = "forestgreen";
|
||||
const char magenta [] = "magenta";
|
||||
const char fuchsia [] = "fuchsia";
|
||||
const char gainsboro [] = "gainsboro";
|
||||
const char ghostwhite [] = "ghostwhite";
|
||||
const char gold [] = "gold";
|
||||
const char goldenrod [] = "goldenrod";
|
||||
const char gray [] = "gray";
|
||||
const char grey [] = "grey";
|
||||
const char green [] = "green";
|
||||
const char greenyellow [] = "greenyellow";
|
||||
const char honeydew [] = "honeydew";
|
||||
const char hotpink [] = "hotpink";
|
||||
const char indianred [] = "indianred";
|
||||
const char indigo [] = "indigo";
|
||||
const char ivory [] = "ivory";
|
||||
const char khaki [] = "khaki";
|
||||
const char lavender [] = "lavender";
|
||||
const char lavenderblush [] = "lavenderblush";
|
||||
const char lawngreen [] = "lawngreen";
|
||||
const char lemonchiffon [] = "lemonchiffon";
|
||||
const char lightblue [] = "lightblue";
|
||||
const char lightcoral [] = "lightcoral";
|
||||
const char lightcyan [] = "lightcyan";
|
||||
const char lightgoldenrodyellow [] = "lightgoldenrodyellow";
|
||||
const char lightgray [] = "lightgray";
|
||||
const char lightgrey [] = "lightgrey";
|
||||
const char lightgreen [] = "lightgreen";
|
||||
const char lightpink [] = "lightpink";
|
||||
const char lightsalmon [] = "lightsalmon";
|
||||
const char lightseagreen [] = "lightseagreen";
|
||||
const char lightskyblue [] = "lightskyblue";
|
||||
const char lightslategray [] = "lightslategray";
|
||||
const char lightslategrey [] = "lightslategrey";
|
||||
const char lightsteelblue [] = "lightsteelblue";
|
||||
const char lightyellow [] = "lightyellow";
|
||||
const char lime [] = "lime";
|
||||
const char limegreen [] = "limegreen";
|
||||
const char linen [] = "linen";
|
||||
const char maroon [] = "maroon";
|
||||
const char mediumaquamarine [] = "mediumaquamarine";
|
||||
const char mediumblue [] = "mediumblue";
|
||||
const char mediumorchid [] = "mediumorchid";
|
||||
const char mediumpurple [] = "mediumpurple";
|
||||
const char mediumseagreen [] = "mediumseagreen";
|
||||
const char mediumslateblue [] = "mediumslateblue";
|
||||
const char mediumspringgreen [] = "mediumspringgreen";
|
||||
const char mediumturquoise [] = "mediumturquoise";
|
||||
const char mediumvioletred [] = "mediumvioletred";
|
||||
const char midnightblue [] = "midnightblue";
|
||||
const char mintcream [] = "mintcream";
|
||||
const char mistyrose [] = "mistyrose";
|
||||
const char moccasin [] = "moccasin";
|
||||
const char navajowhite [] = "navajowhite";
|
||||
const char navy [] = "navy";
|
||||
const char oldlace [] = "oldlace";
|
||||
const char olive [] = "olive";
|
||||
const char olivedrab [] = "olivedrab";
|
||||
const char orange [] = "orange";
|
||||
const char orangered [] = "orangered";
|
||||
const char orchid [] = "orchid";
|
||||
const char palegoldenrod [] = "palegoldenrod";
|
||||
const char palegreen [] = "palegreen";
|
||||
const char paleturquoise [] = "paleturquoise";
|
||||
const char palevioletred [] = "palevioletred";
|
||||
const char papayawhip [] = "papayawhip";
|
||||
const char peachpuff [] = "peachpuff";
|
||||
const char peru [] = "peru";
|
||||
const char pink [] = "pink";
|
||||
const char plum [] = "plum";
|
||||
const char powderblue [] = "powderblue";
|
||||
const char purple [] = "purple";
|
||||
const char red [] = "red";
|
||||
const char rosybrown [] = "rosybrown";
|
||||
const char royalblue [] = "royalblue";
|
||||
const char saddlebrown [] = "saddlebrown";
|
||||
const char salmon [] = "salmon";
|
||||
const char sandybrown [] = "sandybrown";
|
||||
const char seagreen [] = "seagreen";
|
||||
const char seashell [] = "seashell";
|
||||
const char sienna [] = "sienna";
|
||||
const char silver [] = "silver";
|
||||
const char skyblue [] = "skyblue";
|
||||
const char slateblue [] = "slateblue";
|
||||
const char slategray [] = "slategray";
|
||||
const char slategrey [] = "slategrey";
|
||||
const char snow [] = "snow";
|
||||
const char springgreen [] = "springgreen";
|
||||
const char steelblue [] = "steelblue";
|
||||
const char tan [] = "tan";
|
||||
const char teal [] = "teal";
|
||||
const char thistle [] = "thistle";
|
||||
const char tomato [] = "tomato";
|
||||
const char turquoise [] = "turquoise";
|
||||
const char violet [] = "violet";
|
||||
const char wheat [] = "wheat";
|
||||
const char white [] = "white";
|
||||
const char whitesmoke [] = "whitesmoke";
|
||||
const char yellow [] = "yellow";
|
||||
const char yellowgreen [] = "yellowgreen";
|
||||
const char rebeccapurple [] = "rebeccapurple";
|
||||
const char transparent [] = "transparent";
|
||||
}
|
||||
|
||||
namespace Colors {
|
||||
const ParserState color_table("[COLOR TABLE]");
|
||||
const Color aliceblue(color_table, 240, 248, 255, 1);
|
||||
const Color antiquewhite(color_table, 250, 235, 215, 1);
|
||||
const Color cyan(color_table, 0, 255, 255, 1);
|
||||
const Color aqua(color_table, 0, 255, 255, 1);
|
||||
const Color aquamarine(color_table, 127, 255, 212, 1);
|
||||
const Color azure(color_table, 240, 255, 255, 1);
|
||||
const Color beige(color_table, 245, 245, 220, 1);
|
||||
const Color bisque(color_table, 255, 228, 196, 1);
|
||||
const Color black(color_table, 0, 0, 0, 1);
|
||||
const Color blanchedalmond(color_table, 255, 235, 205, 1);
|
||||
const Color blue(color_table, 0, 0, 255, 1);
|
||||
const Color blueviolet(color_table, 138, 43, 226, 1);
|
||||
const Color brown(color_table, 165, 42, 42, 1);
|
||||
const Color burlywood(color_table, 222, 184, 135, 1);
|
||||
const Color cadetblue(color_table, 95, 158, 160, 1);
|
||||
const Color chartreuse(color_table, 127, 255, 0, 1);
|
||||
const Color chocolate(color_table, 210, 105, 30, 1);
|
||||
const Color coral(color_table, 255, 127, 80, 1);
|
||||
const Color cornflowerblue(color_table, 100, 149, 237, 1);
|
||||
const Color cornsilk(color_table, 255, 248, 220, 1);
|
||||
const Color crimson(color_table, 220, 20, 60, 1);
|
||||
const Color darkblue(color_table, 0, 0, 139, 1);
|
||||
const Color darkcyan(color_table, 0, 139, 139, 1);
|
||||
const Color darkgoldenrod(color_table, 184, 134, 11, 1);
|
||||
const Color darkgray(color_table, 169, 169, 169, 1);
|
||||
const Color darkgrey(color_table, 169, 169, 169, 1);
|
||||
const Color darkgreen(color_table, 0, 100, 0, 1);
|
||||
const Color darkkhaki(color_table, 189, 183, 107, 1);
|
||||
const Color darkmagenta(color_table, 139, 0, 139, 1);
|
||||
const Color darkolivegreen(color_table, 85, 107, 47, 1);
|
||||
const Color darkorange(color_table, 255, 140, 0, 1);
|
||||
const Color darkorchid(color_table, 153, 50, 204, 1);
|
||||
const Color darkred(color_table, 139, 0, 0, 1);
|
||||
const Color darksalmon(color_table, 233, 150, 122, 1);
|
||||
const Color darkseagreen(color_table, 143, 188, 143, 1);
|
||||
const Color darkslateblue(color_table, 72, 61, 139, 1);
|
||||
const Color darkslategray(color_table, 47, 79, 79, 1);
|
||||
const Color darkslategrey(color_table, 47, 79, 79, 1);
|
||||
const Color darkturquoise(color_table, 0, 206, 209, 1);
|
||||
const Color darkviolet(color_table, 148, 0, 211, 1);
|
||||
const Color deeppink(color_table, 255, 20, 147, 1);
|
||||
const Color deepskyblue(color_table, 0, 191, 255, 1);
|
||||
const Color dimgray(color_table, 105, 105, 105, 1);
|
||||
const Color dimgrey(color_table, 105, 105, 105, 1);
|
||||
const Color dodgerblue(color_table, 30, 144, 255, 1);
|
||||
const Color firebrick(color_table, 178, 34, 34, 1);
|
||||
const Color floralwhite(color_table, 255, 250, 240, 1);
|
||||
const Color forestgreen(color_table, 34, 139, 34, 1);
|
||||
const Color magenta(color_table, 255, 0, 255, 1);
|
||||
const Color fuchsia(color_table, 255, 0, 255, 1);
|
||||
const Color gainsboro(color_table, 220, 220, 220, 1);
|
||||
const Color ghostwhite(color_table, 248, 248, 255, 1);
|
||||
const Color gold(color_table, 255, 215, 0, 1);
|
||||
const Color goldenrod(color_table, 218, 165, 32, 1);
|
||||
const Color gray(color_table, 128, 128, 128, 1);
|
||||
const Color grey(color_table, 128, 128, 128, 1);
|
||||
const Color green(color_table, 0, 128, 0, 1);
|
||||
const Color greenyellow(color_table, 173, 255, 47, 1);
|
||||
const Color honeydew(color_table, 240, 255, 240, 1);
|
||||
const Color hotpink(color_table, 255, 105, 180, 1);
|
||||
const Color indianred(color_table, 205, 92, 92, 1);
|
||||
const Color indigo(color_table, 75, 0, 130, 1);
|
||||
const Color ivory(color_table, 255, 255, 240, 1);
|
||||
const Color khaki(color_table, 240, 230, 140, 1);
|
||||
const Color lavender(color_table, 230, 230, 250, 1);
|
||||
const Color lavenderblush(color_table, 255, 240, 245, 1);
|
||||
const Color lawngreen(color_table, 124, 252, 0, 1);
|
||||
const Color lemonchiffon(color_table, 255, 250, 205, 1);
|
||||
const Color lightblue(color_table, 173, 216, 230, 1);
|
||||
const Color lightcoral(color_table, 240, 128, 128, 1);
|
||||
const Color lightcyan(color_table, 224, 255, 255, 1);
|
||||
const Color lightgoldenrodyellow(color_table, 250, 250, 210, 1);
|
||||
const Color lightgray(color_table, 211, 211, 211, 1);
|
||||
const Color lightgrey(color_table, 211, 211, 211, 1);
|
||||
const Color lightgreen(color_table, 144, 238, 144, 1);
|
||||
const Color lightpink(color_table, 255, 182, 193, 1);
|
||||
const Color lightsalmon(color_table, 255, 160, 122, 1);
|
||||
const Color lightseagreen(color_table, 32, 178, 170, 1);
|
||||
const Color lightskyblue(color_table, 135, 206, 250, 1);
|
||||
const Color lightslategray(color_table, 119, 136, 153, 1);
|
||||
const Color lightslategrey(color_table, 119, 136, 153, 1);
|
||||
const Color lightsteelblue(color_table, 176, 196, 222, 1);
|
||||
const Color lightyellow(color_table, 255, 255, 224, 1);
|
||||
const Color lime(color_table, 0, 255, 0, 1);
|
||||
const Color limegreen(color_table, 50, 205, 50, 1);
|
||||
const Color linen(color_table, 250, 240, 230, 1);
|
||||
const Color maroon(color_table, 128, 0, 0, 1);
|
||||
const Color mediumaquamarine(color_table, 102, 205, 170, 1);
|
||||
const Color mediumblue(color_table, 0, 0, 205, 1);
|
||||
const Color mediumorchid(color_table, 186, 85, 211, 1);
|
||||
const Color mediumpurple(color_table, 147, 112, 219, 1);
|
||||
const Color mediumseagreen(color_table, 60, 179, 113, 1);
|
||||
const Color mediumslateblue(color_table, 123, 104, 238, 1);
|
||||
const Color mediumspringgreen(color_table, 0, 250, 154, 1);
|
||||
const Color mediumturquoise(color_table, 72, 209, 204, 1);
|
||||
const Color mediumvioletred(color_table, 199, 21, 133, 1);
|
||||
const Color midnightblue(color_table, 25, 25, 112, 1);
|
||||
const Color mintcream(color_table, 245, 255, 250, 1);
|
||||
const Color mistyrose(color_table, 255, 228, 225, 1);
|
||||
const Color moccasin(color_table, 255, 228, 181, 1);
|
||||
const Color navajowhite(color_table, 255, 222, 173, 1);
|
||||
const Color navy(color_table, 0, 0, 128, 1);
|
||||
const Color oldlace(color_table, 253, 245, 230, 1);
|
||||
const Color olive(color_table, 128, 128, 0, 1);
|
||||
const Color olivedrab(color_table, 107, 142, 35, 1);
|
||||
const Color orange(color_table, 255, 165, 0, 1);
|
||||
const Color orangered(color_table, 255, 69, 0, 1);
|
||||
const Color orchid(color_table, 218, 112, 214, 1);
|
||||
const Color palegoldenrod(color_table, 238, 232, 170, 1);
|
||||
const Color palegreen(color_table, 152, 251, 152, 1);
|
||||
const Color paleturquoise(color_table, 175, 238, 238, 1);
|
||||
const Color palevioletred(color_table, 219, 112, 147, 1);
|
||||
const Color papayawhip(color_table, 255, 239, 213, 1);
|
||||
const Color peachpuff(color_table, 255, 218, 185, 1);
|
||||
const Color peru(color_table, 205, 133, 63, 1);
|
||||
const Color pink(color_table, 255, 192, 203, 1);
|
||||
const Color plum(color_table, 221, 160, 221, 1);
|
||||
const Color powderblue(color_table, 176, 224, 230, 1);
|
||||
const Color purple(color_table, 128, 0, 128, 1);
|
||||
const Color red(color_table, 255, 0, 0, 1);
|
||||
const Color rosybrown(color_table, 188, 143, 143, 1);
|
||||
const Color royalblue(color_table, 65, 105, 225, 1);
|
||||
const Color saddlebrown(color_table, 139, 69, 19, 1);
|
||||
const Color salmon(color_table, 250, 128, 114, 1);
|
||||
const Color sandybrown(color_table, 244, 164, 96, 1);
|
||||
const Color seagreen(color_table, 46, 139, 87, 1);
|
||||
const Color seashell(color_table, 255, 245, 238, 1);
|
||||
const Color sienna(color_table, 160, 82, 45, 1);
|
||||
const Color silver(color_table, 192, 192, 192, 1);
|
||||
const Color skyblue(color_table, 135, 206, 235, 1);
|
||||
const Color slateblue(color_table, 106, 90, 205, 1);
|
||||
const Color slategray(color_table, 112, 128, 144, 1);
|
||||
const Color slategrey(color_table, 112, 128, 144, 1);
|
||||
const Color snow(color_table, 255, 250, 250, 1);
|
||||
const Color springgreen(color_table, 0, 255, 127, 1);
|
||||
const Color steelblue(color_table, 70, 130, 180, 1);
|
||||
const Color tan(color_table, 210, 180, 140, 1);
|
||||
const Color teal(color_table, 0, 128, 128, 1);
|
||||
const Color thistle(color_table, 216, 191, 216, 1);
|
||||
const Color tomato(color_table, 255, 99, 71, 1);
|
||||
const Color turquoise(color_table, 64, 224, 208, 1);
|
||||
const Color violet(color_table, 238, 130, 238, 1);
|
||||
const Color wheat(color_table, 245, 222, 179, 1);
|
||||
const Color white(color_table, 255, 255, 255, 1);
|
||||
const Color whitesmoke(color_table, 245, 245, 245, 1);
|
||||
const Color yellow(color_table, 255, 255, 0, 1);
|
||||
const Color yellowgreen(color_table, 154, 205, 50, 1);
|
||||
const Color rebeccapurple(color_table, 102, 51, 153, 1);
|
||||
const Color transparent(color_table, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
const std::map<const int, const char*> colors_to_names {
|
||||
{ 240 * 0x10000 + 248 * 0x100 + 255, ColorNames::aliceblue },
|
||||
{ 250 * 0x10000 + 235 * 0x100 + 215, ColorNames::antiquewhite },
|
||||
{ 0 * 0x10000 + 255 * 0x100 + 255, ColorNames::cyan },
|
||||
{ 127 * 0x10000 + 255 * 0x100 + 212, ColorNames::aquamarine },
|
||||
{ 240 * 0x10000 + 255 * 0x100 + 255, ColorNames::azure },
|
||||
{ 245 * 0x10000 + 245 * 0x100 + 220, ColorNames::beige },
|
||||
{ 255 * 0x10000 + 228 * 0x100 + 196, ColorNames::bisque },
|
||||
{ 0 * 0x10000 + 0 * 0x100 + 0, ColorNames::black },
|
||||
{ 255 * 0x10000 + 235 * 0x100 + 205, ColorNames::blanchedalmond },
|
||||
{ 0 * 0x10000 + 0 * 0x100 + 255, ColorNames::blue },
|
||||
{ 138 * 0x10000 + 43 * 0x100 + 226, ColorNames::blueviolet },
|
||||
{ 165 * 0x10000 + 42 * 0x100 + 42, ColorNames::brown },
|
||||
{ 222 * 0x10000 + 184 * 0x100 + 135, ColorNames::burlywood },
|
||||
{ 95 * 0x10000 + 158 * 0x100 + 160, ColorNames::cadetblue },
|
||||
{ 127 * 0x10000 + 255 * 0x100 + 0, ColorNames::chartreuse },
|
||||
{ 210 * 0x10000 + 105 * 0x100 + 30, ColorNames::chocolate },
|
||||
{ 255 * 0x10000 + 127 * 0x100 + 80, ColorNames::coral },
|
||||
{ 100 * 0x10000 + 149 * 0x100 + 237, ColorNames::cornflowerblue },
|
||||
{ 255 * 0x10000 + 248 * 0x100 + 220, ColorNames::cornsilk },
|
||||
{ 220 * 0x10000 + 20 * 0x100 + 60, ColorNames::crimson },
|
||||
{ 0 * 0x10000 + 0 * 0x100 + 139, ColorNames::darkblue },
|
||||
{ 0 * 0x10000 + 139 * 0x100 + 139, ColorNames::darkcyan },
|
||||
{ 184 * 0x10000 + 134 * 0x100 + 11, ColorNames::darkgoldenrod },
|
||||
{ 169 * 0x10000 + 169 * 0x100 + 169, ColorNames::darkgray },
|
||||
{ 0 * 0x10000 + 100 * 0x100 + 0, ColorNames::darkgreen },
|
||||
{ 189 * 0x10000 + 183 * 0x100 + 107, ColorNames::darkkhaki },
|
||||
{ 139 * 0x10000 + 0 * 0x100 + 139, ColorNames::darkmagenta },
|
||||
{ 85 * 0x10000 + 107 * 0x100 + 47, ColorNames::darkolivegreen },
|
||||
{ 255 * 0x10000 + 140 * 0x100 + 0, ColorNames::darkorange },
|
||||
{ 153 * 0x10000 + 50 * 0x100 + 204, ColorNames::darkorchid },
|
||||
{ 139 * 0x10000 + 0 * 0x100 + 0, ColorNames::darkred },
|
||||
{ 233 * 0x10000 + 150 * 0x100 + 122, ColorNames::darksalmon },
|
||||
{ 143 * 0x10000 + 188 * 0x100 + 143, ColorNames::darkseagreen },
|
||||
{ 72 * 0x10000 + 61 * 0x100 + 139, ColorNames::darkslateblue },
|
||||
{ 47 * 0x10000 + 79 * 0x100 + 79, ColorNames::darkslategray },
|
||||
{ 0 * 0x10000 + 206 * 0x100 + 209, ColorNames::darkturquoise },
|
||||
{ 148 * 0x10000 + 0 * 0x100 + 211, ColorNames::darkviolet },
|
||||
{ 255 * 0x10000 + 20 * 0x100 + 147, ColorNames::deeppink },
|
||||
{ 0 * 0x10000 + 191 * 0x100 + 255, ColorNames::deepskyblue },
|
||||
{ 105 * 0x10000 + 105 * 0x100 + 105, ColorNames::dimgray },
|
||||
{ 30 * 0x10000 + 144 * 0x100 + 255, ColorNames::dodgerblue },
|
||||
{ 178 * 0x10000 + 34 * 0x100 + 34, ColorNames::firebrick },
|
||||
{ 255 * 0x10000 + 250 * 0x100 + 240, ColorNames::floralwhite },
|
||||
{ 34 * 0x10000 + 139 * 0x100 + 34, ColorNames::forestgreen },
|
||||
{ 255 * 0x10000 + 0 * 0x100 + 255, ColorNames::magenta },
|
||||
{ 220 * 0x10000 + 220 * 0x100 + 220, ColorNames::gainsboro },
|
||||
{ 248 * 0x10000 + 248 * 0x100 + 255, ColorNames::ghostwhite },
|
||||
{ 255 * 0x10000 + 215 * 0x100 + 0, ColorNames::gold },
|
||||
{ 218 * 0x10000 + 165 * 0x100 + 32, ColorNames::goldenrod },
|
||||
{ 128 * 0x10000 + 128 * 0x100 + 128, ColorNames::gray },
|
||||
{ 0 * 0x10000 + 128 * 0x100 + 0, ColorNames::green },
|
||||
{ 173 * 0x10000 + 255 * 0x100 + 47, ColorNames::greenyellow },
|
||||
{ 240 * 0x10000 + 255 * 0x100 + 240, ColorNames::honeydew },
|
||||
{ 255 * 0x10000 + 105 * 0x100 + 180, ColorNames::hotpink },
|
||||
{ 205 * 0x10000 + 92 * 0x100 + 92, ColorNames::indianred },
|
||||
{ 75 * 0x10000 + 0 * 0x100 + 130, ColorNames::indigo },
|
||||
{ 255 * 0x10000 + 255 * 0x100 + 240, ColorNames::ivory },
|
||||
{ 240 * 0x10000 + 230 * 0x100 + 140, ColorNames::khaki },
|
||||
{ 230 * 0x10000 + 230 * 0x100 + 250, ColorNames::lavender },
|
||||
{ 255 * 0x10000 + 240 * 0x100 + 245, ColorNames::lavenderblush },
|
||||
{ 124 * 0x10000 + 252 * 0x100 + 0, ColorNames::lawngreen },
|
||||
{ 255 * 0x10000 + 250 * 0x100 + 205, ColorNames::lemonchiffon },
|
||||
{ 173 * 0x10000 + 216 * 0x100 + 230, ColorNames::lightblue },
|
||||
{ 240 * 0x10000 + 128 * 0x100 + 128, ColorNames::lightcoral },
|
||||
{ 224 * 0x10000 + 255 * 0x100 + 255, ColorNames::lightcyan },
|
||||
{ 250 * 0x10000 + 250 * 0x100 + 210, ColorNames::lightgoldenrodyellow },
|
||||
{ 211 * 0x10000 + 211 * 0x100 + 211, ColorNames::lightgray },
|
||||
{ 144 * 0x10000 + 238 * 0x100 + 144, ColorNames::lightgreen },
|
||||
{ 255 * 0x10000 + 182 * 0x100 + 193, ColorNames::lightpink },
|
||||
{ 255 * 0x10000 + 160 * 0x100 + 122, ColorNames::lightsalmon },
|
||||
{ 32 * 0x10000 + 178 * 0x100 + 170, ColorNames::lightseagreen },
|
||||
{ 135 * 0x10000 + 206 * 0x100 + 250, ColorNames::lightskyblue },
|
||||
{ 119 * 0x10000 + 136 * 0x100 + 153, ColorNames::lightslategray },
|
||||
{ 176 * 0x10000 + 196 * 0x100 + 222, ColorNames::lightsteelblue },
|
||||
{ 255 * 0x10000 + 255 * 0x100 + 224, ColorNames::lightyellow },
|
||||
{ 0 * 0x10000 + 255 * 0x100 + 0, ColorNames::lime },
|
||||
{ 50 * 0x10000 + 205 * 0x100 + 50, ColorNames::limegreen },
|
||||
{ 250 * 0x10000 + 240 * 0x100 + 230, ColorNames::linen },
|
||||
{ 128 * 0x10000 + 0 * 0x100 + 0, ColorNames::maroon },
|
||||
{ 102 * 0x10000 + 205 * 0x100 + 170, ColorNames::mediumaquamarine },
|
||||
{ 0 * 0x10000 + 0 * 0x100 + 205, ColorNames::mediumblue },
|
||||
{ 186 * 0x10000 + 85 * 0x100 + 211, ColorNames::mediumorchid },
|
||||
{ 147 * 0x10000 + 112 * 0x100 + 219, ColorNames::mediumpurple },
|
||||
{ 60 * 0x10000 + 179 * 0x100 + 113, ColorNames::mediumseagreen },
|
||||
{ 123 * 0x10000 + 104 * 0x100 + 238, ColorNames::mediumslateblue },
|
||||
{ 0 * 0x10000 + 250 * 0x100 + 154, ColorNames::mediumspringgreen },
|
||||
{ 72 * 0x10000 + 209 * 0x100 + 204, ColorNames::mediumturquoise },
|
||||
{ 199 * 0x10000 + 21 * 0x100 + 133, ColorNames::mediumvioletred },
|
||||
{ 25 * 0x10000 + 25 * 0x100 + 112, ColorNames::midnightblue },
|
||||
{ 245 * 0x10000 + 255 * 0x100 + 250, ColorNames::mintcream },
|
||||
{ 255 * 0x10000 + 228 * 0x100 + 225, ColorNames::mistyrose },
|
||||
{ 255 * 0x10000 + 228 * 0x100 + 181, ColorNames::moccasin },
|
||||
{ 255 * 0x10000 + 222 * 0x100 + 173, ColorNames::navajowhite },
|
||||
{ 0 * 0x10000 + 0 * 0x100 + 128, ColorNames::navy },
|
||||
{ 253 * 0x10000 + 245 * 0x100 + 230, ColorNames::oldlace },
|
||||
{ 128 * 0x10000 + 128 * 0x100 + 0, ColorNames::olive },
|
||||
{ 107 * 0x10000 + 142 * 0x100 + 35, ColorNames::olivedrab },
|
||||
{ 255 * 0x10000 + 165 * 0x100 + 0, ColorNames::orange },
|
||||
{ 255 * 0x10000 + 69 * 0x100 + 0, ColorNames::orangered },
|
||||
{ 218 * 0x10000 + 112 * 0x100 + 214, ColorNames::orchid },
|
||||
{ 238 * 0x10000 + 232 * 0x100 + 170, ColorNames::palegoldenrod },
|
||||
{ 152 * 0x10000 + 251 * 0x100 + 152, ColorNames::palegreen },
|
||||
{ 175 * 0x10000 + 238 * 0x100 + 238, ColorNames::paleturquoise },
|
||||
{ 219 * 0x10000 + 112 * 0x100 + 147, ColorNames::palevioletred },
|
||||
{ 255 * 0x10000 + 239 * 0x100 + 213, ColorNames::papayawhip },
|
||||
{ 255 * 0x10000 + 218 * 0x100 + 185, ColorNames::peachpuff },
|
||||
{ 205 * 0x10000 + 133 * 0x100 + 63, ColorNames::peru },
|
||||
{ 255 * 0x10000 + 192 * 0x100 + 203, ColorNames::pink },
|
||||
{ 221 * 0x10000 + 160 * 0x100 + 221, ColorNames::plum },
|
||||
{ 176 * 0x10000 + 224 * 0x100 + 230, ColorNames::powderblue },
|
||||
{ 128 * 0x10000 + 0 * 0x100 + 128, ColorNames::purple },
|
||||
{ 255 * 0x10000 + 0 * 0x100 + 0, ColorNames::red },
|
||||
{ 188 * 0x10000 + 143 * 0x100 + 143, ColorNames::rosybrown },
|
||||
{ 65 * 0x10000 + 105 * 0x100 + 225, ColorNames::royalblue },
|
||||
{ 139 * 0x10000 + 69 * 0x100 + 19, ColorNames::saddlebrown },
|
||||
{ 250 * 0x10000 + 128 * 0x100 + 114, ColorNames::salmon },
|
||||
{ 244 * 0x10000 + 164 * 0x100 + 96, ColorNames::sandybrown },
|
||||
{ 46 * 0x10000 + 139 * 0x100 + 87, ColorNames::seagreen },
|
||||
{ 255 * 0x10000 + 245 * 0x100 + 238, ColorNames::seashell },
|
||||
{ 160 * 0x10000 + 82 * 0x100 + 45, ColorNames::sienna },
|
||||
{ 192 * 0x10000 + 192 * 0x100 + 192, ColorNames::silver },
|
||||
{ 135 * 0x10000 + 206 * 0x100 + 235, ColorNames::skyblue },
|
||||
{ 106 * 0x10000 + 90 * 0x100 + 205, ColorNames::slateblue },
|
||||
{ 112 * 0x10000 + 128 * 0x100 + 144, ColorNames::slategray },
|
||||
{ 255 * 0x10000 + 250 * 0x100 + 250, ColorNames::snow },
|
||||
{ 0 * 0x10000 + 255 * 0x100 + 127, ColorNames::springgreen },
|
||||
{ 70 * 0x10000 + 130 * 0x100 + 180, ColorNames::steelblue },
|
||||
{ 210 * 0x10000 + 180 * 0x100 + 140, ColorNames::tan },
|
||||
{ 0 * 0x10000 + 128 * 0x100 + 128, ColorNames::teal },
|
||||
{ 216 * 0x10000 + 191 * 0x100 + 216, ColorNames::thistle },
|
||||
{ 255 * 0x10000 + 99 * 0x100 + 71, ColorNames::tomato },
|
||||
{ 64 * 0x10000 + 224 * 0x100 + 208, ColorNames::turquoise },
|
||||
{ 238 * 0x10000 + 130 * 0x100 + 238, ColorNames::violet },
|
||||
{ 245 * 0x10000 + 222 * 0x100 + 179, ColorNames::wheat },
|
||||
{ 255 * 0x10000 + 255 * 0x100 + 255, ColorNames::white },
|
||||
{ 245 * 0x10000 + 245 * 0x100 + 245, ColorNames::whitesmoke },
|
||||
{ 255 * 0x10000 + 255 * 0x100 + 0, ColorNames::yellow },
|
||||
{ 154 * 0x10000 + 205 * 0x100 + 50, ColorNames::yellowgreen },
|
||||
{ 102 * 0x10000 + 51 * 0x100 + 153, ColorNames::rebeccapurple }
|
||||
};
|
||||
|
||||
const std::map<const char*, const Color*, map_cmp_str> names_to_colors
|
||||
{
|
||||
{ ColorNames::aliceblue, &Colors::aliceblue },
|
||||
{ ColorNames::antiquewhite, &Colors::antiquewhite },
|
||||
{ ColorNames::cyan, &Colors::cyan },
|
||||
{ ColorNames::aqua, &Colors::aqua },
|
||||
{ ColorNames::aquamarine, &Colors::aquamarine },
|
||||
{ ColorNames::azure, &Colors::azure },
|
||||
{ ColorNames::beige, &Colors::beige },
|
||||
{ ColorNames::bisque, &Colors::bisque },
|
||||
{ ColorNames::black, &Colors::black },
|
||||
{ ColorNames::blanchedalmond, &Colors::blanchedalmond },
|
||||
{ ColorNames::blue, &Colors::blue },
|
||||
{ ColorNames::blueviolet, &Colors::blueviolet },
|
||||
{ ColorNames::brown, &Colors::brown },
|
||||
{ ColorNames::burlywood, &Colors::burlywood },
|
||||
{ ColorNames::cadetblue, &Colors::cadetblue },
|
||||
{ ColorNames::chartreuse, &Colors::chartreuse },
|
||||
{ ColorNames::chocolate, &Colors::chocolate },
|
||||
{ ColorNames::coral, &Colors::coral },
|
||||
{ ColorNames::cornflowerblue, &Colors::cornflowerblue },
|
||||
{ ColorNames::cornsilk, &Colors::cornsilk },
|
||||
{ ColorNames::crimson, &Colors::crimson },
|
||||
{ ColorNames::darkblue, &Colors::darkblue },
|
||||
{ ColorNames::darkcyan, &Colors::darkcyan },
|
||||
{ ColorNames::darkgoldenrod, &Colors::darkgoldenrod },
|
||||
{ ColorNames::darkgray, &Colors::darkgray },
|
||||
{ ColorNames::darkgrey, &Colors::darkgrey },
|
||||
{ ColorNames::darkgreen, &Colors::darkgreen },
|
||||
{ ColorNames::darkkhaki, &Colors::darkkhaki },
|
||||
{ ColorNames::darkmagenta, &Colors::darkmagenta },
|
||||
{ ColorNames::darkolivegreen, &Colors::darkolivegreen },
|
||||
{ ColorNames::darkorange, &Colors::darkorange },
|
||||
{ ColorNames::darkorchid, &Colors::darkorchid },
|
||||
{ ColorNames::darkred, &Colors::darkred },
|
||||
{ ColorNames::darksalmon, &Colors::darksalmon },
|
||||
{ ColorNames::darkseagreen, &Colors::darkseagreen },
|
||||
{ ColorNames::darkslateblue, &Colors::darkslateblue },
|
||||
{ ColorNames::darkslategray, &Colors::darkslategray },
|
||||
{ ColorNames::darkslategrey, &Colors::darkslategrey },
|
||||
{ ColorNames::darkturquoise, &Colors::darkturquoise },
|
||||
{ ColorNames::darkviolet, &Colors::darkviolet },
|
||||
{ ColorNames::deeppink, &Colors::deeppink },
|
||||
{ ColorNames::deepskyblue, &Colors::deepskyblue },
|
||||
{ ColorNames::dimgray, &Colors::dimgray },
|
||||
{ ColorNames::dimgrey, &Colors::dimgrey },
|
||||
{ ColorNames::dodgerblue, &Colors::dodgerblue },
|
||||
{ ColorNames::firebrick, &Colors::firebrick },
|
||||
{ ColorNames::floralwhite, &Colors::floralwhite },
|
||||
{ ColorNames::forestgreen, &Colors::forestgreen },
|
||||
{ ColorNames::magenta, &Colors::magenta },
|
||||
{ ColorNames::fuchsia, &Colors::fuchsia },
|
||||
{ ColorNames::gainsboro, &Colors::gainsboro },
|
||||
{ ColorNames::ghostwhite, &Colors::ghostwhite },
|
||||
{ ColorNames::gold, &Colors::gold },
|
||||
{ ColorNames::goldenrod, &Colors::goldenrod },
|
||||
{ ColorNames::gray, &Colors::gray },
|
||||
{ ColorNames::grey, &Colors::grey },
|
||||
{ ColorNames::green, &Colors::green },
|
||||
{ ColorNames::greenyellow, &Colors::greenyellow },
|
||||
{ ColorNames::honeydew, &Colors::honeydew },
|
||||
{ ColorNames::hotpink, &Colors::hotpink },
|
||||
{ ColorNames::indianred, &Colors::indianred },
|
||||
{ ColorNames::indigo, &Colors::indigo },
|
||||
{ ColorNames::ivory, &Colors::ivory },
|
||||
{ ColorNames::khaki, &Colors::khaki },
|
||||
{ ColorNames::lavender, &Colors::lavender },
|
||||
{ ColorNames::lavenderblush, &Colors::lavenderblush },
|
||||
{ ColorNames::lawngreen, &Colors::lawngreen },
|
||||
{ ColorNames::lemonchiffon, &Colors::lemonchiffon },
|
||||
{ ColorNames::lightblue, &Colors::lightblue },
|
||||
{ ColorNames::lightcoral, &Colors::lightcoral },
|
||||
{ ColorNames::lightcyan, &Colors::lightcyan },
|
||||
{ ColorNames::lightgoldenrodyellow, &Colors::lightgoldenrodyellow },
|
||||
{ ColorNames::lightgray, &Colors::lightgray },
|
||||
{ ColorNames::lightgrey, &Colors::lightgrey },
|
||||
{ ColorNames::lightgreen, &Colors::lightgreen },
|
||||
{ ColorNames::lightpink, &Colors::lightpink },
|
||||
{ ColorNames::lightsalmon, &Colors::lightsalmon },
|
||||
{ ColorNames::lightseagreen, &Colors::lightseagreen },
|
||||
{ ColorNames::lightskyblue, &Colors::lightskyblue },
|
||||
{ ColorNames::lightslategray, &Colors::lightslategray },
|
||||
{ ColorNames::lightslategrey, &Colors::lightslategrey },
|
||||
{ ColorNames::lightsteelblue, &Colors::lightsteelblue },
|
||||
{ ColorNames::lightyellow, &Colors::lightyellow },
|
||||
{ ColorNames::lime, &Colors::lime },
|
||||
{ ColorNames::limegreen, &Colors::limegreen },
|
||||
{ ColorNames::linen, &Colors::linen },
|
||||
{ ColorNames::maroon, &Colors::maroon },
|
||||
{ ColorNames::mediumaquamarine, &Colors::mediumaquamarine },
|
||||
{ ColorNames::mediumblue, &Colors::mediumblue },
|
||||
{ ColorNames::mediumorchid, &Colors::mediumorchid },
|
||||
{ ColorNames::mediumpurple, &Colors::mediumpurple },
|
||||
{ ColorNames::mediumseagreen, &Colors::mediumseagreen },
|
||||
{ ColorNames::mediumslateblue, &Colors::mediumslateblue },
|
||||
{ ColorNames::mediumspringgreen, &Colors::mediumspringgreen },
|
||||
{ ColorNames::mediumturquoise, &Colors::mediumturquoise },
|
||||
{ ColorNames::mediumvioletred, &Colors::mediumvioletred },
|
||||
{ ColorNames::midnightblue, &Colors::midnightblue },
|
||||
{ ColorNames::mintcream, &Colors::mintcream },
|
||||
{ ColorNames::mistyrose, &Colors::mistyrose },
|
||||
{ ColorNames::moccasin, &Colors::moccasin },
|
||||
{ ColorNames::navajowhite, &Colors::navajowhite },
|
||||
{ ColorNames::navy, &Colors::navy },
|
||||
{ ColorNames::oldlace, &Colors::oldlace },
|
||||
{ ColorNames::olive, &Colors::olive },
|
||||
{ ColorNames::olivedrab, &Colors::olivedrab },
|
||||
{ ColorNames::orange, &Colors::orange },
|
||||
{ ColorNames::orangered, &Colors::orangered },
|
||||
{ ColorNames::orchid, &Colors::orchid },
|
||||
{ ColorNames::palegoldenrod, &Colors::palegoldenrod },
|
||||
{ ColorNames::palegreen, &Colors::palegreen },
|
||||
{ ColorNames::paleturquoise, &Colors::paleturquoise },
|
||||
{ ColorNames::palevioletred, &Colors::palevioletred },
|
||||
{ ColorNames::papayawhip, &Colors::papayawhip },
|
||||
{ ColorNames::peachpuff, &Colors::peachpuff },
|
||||
{ ColorNames::peru, &Colors::peru },
|
||||
{ ColorNames::pink, &Colors::pink },
|
||||
{ ColorNames::plum, &Colors::plum },
|
||||
{ ColorNames::powderblue, &Colors::powderblue },
|
||||
{ ColorNames::purple, &Colors::purple },
|
||||
{ ColorNames::red, &Colors::red },
|
||||
{ ColorNames::rosybrown, &Colors::rosybrown },
|
||||
{ ColorNames::royalblue, &Colors::royalblue },
|
||||
{ ColorNames::saddlebrown, &Colors::saddlebrown },
|
||||
{ ColorNames::salmon, &Colors::salmon },
|
||||
{ ColorNames::sandybrown, &Colors::sandybrown },
|
||||
{ ColorNames::seagreen, &Colors::seagreen },
|
||||
{ ColorNames::seashell, &Colors::seashell },
|
||||
{ ColorNames::sienna, &Colors::sienna },
|
||||
{ ColorNames::silver, &Colors::silver },
|
||||
{ ColorNames::skyblue, &Colors::skyblue },
|
||||
{ ColorNames::slateblue, &Colors::slateblue },
|
||||
{ ColorNames::slategray, &Colors::slategray },
|
||||
{ ColorNames::slategrey, &Colors::slategrey },
|
||||
{ ColorNames::snow, &Colors::snow },
|
||||
{ ColorNames::springgreen, &Colors::springgreen },
|
||||
{ ColorNames::steelblue, &Colors::steelblue },
|
||||
{ ColorNames::tan, &Colors::tan },
|
||||
{ ColorNames::teal, &Colors::teal },
|
||||
{ ColorNames::thistle, &Colors::thistle },
|
||||
{ ColorNames::tomato, &Colors::tomato },
|
||||
{ ColorNames::turquoise, &Colors::turquoise },
|
||||
{ ColorNames::violet, &Colors::violet },
|
||||
{ ColorNames::wheat, &Colors::wheat },
|
||||
{ ColorNames::white, &Colors::white },
|
||||
{ ColorNames::whitesmoke, &Colors::whitesmoke },
|
||||
{ ColorNames::yellow, &Colors::yellow },
|
||||
{ ColorNames::yellowgreen, &Colors::yellowgreen },
|
||||
{ ColorNames::rebeccapurple, &Colors::rebeccapurple },
|
||||
{ ColorNames::transparent, &Colors::transparent }
|
||||
};
|
||||
|
||||
const Color* name_to_color(const char* key)
|
||||
{
|
||||
auto p = names_to_colors.find(key);
|
||||
if (p != names_to_colors.end()) {
|
||||
return p->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const Color* name_to_color(const std::string& key)
|
||||
{
|
||||
return name_to_color(key.c_str());
|
||||
}
|
||||
|
||||
const char* color_to_name(const int key)
|
||||
{
|
||||
auto p = colors_to_names.find(key);
|
||||
if (p != colors_to_names.end()) {
|
||||
return p->second;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char* color_to_name(const double key)
|
||||
{
|
||||
return color_to_name((int)key);
|
||||
}
|
||||
|
||||
const char* color_to_name(const Color& c)
|
||||
{
|
||||
double key = c.r() * 0x10000
|
||||
+ c.g() * 0x100
|
||||
+ c.b();
|
||||
return color_to_name(key);
|
||||
}
|
||||
|
||||
}
|
||||
+333
@@ -0,0 +1,333 @@
|
||||
#ifndef SASS_COLOR_MAPS_H
|
||||
#define SASS_COLOR_MAPS_H
|
||||
|
||||
#include <map>
|
||||
#include "ast.hpp"
|
||||
|
||||
namespace Sass {
|
||||
|
||||
struct map_cmp_str
|
||||
{
|
||||
bool operator()(char const *a, char const *b) const
|
||||
{
|
||||
return std::strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace ColorNames
|
||||
{
|
||||
extern const char aliceblue[];
|
||||
extern const char antiquewhite[];
|
||||
extern const char cyan[];
|
||||
extern const char aqua[];
|
||||
extern const char aquamarine[];
|
||||
extern const char azure[];
|
||||
extern const char beige[];
|
||||
extern const char bisque[];
|
||||
extern const char black[];
|
||||
extern const char blanchedalmond[];
|
||||
extern const char blue[];
|
||||
extern const char blueviolet[];
|
||||
extern const char brown[];
|
||||
extern const char burlywood[];
|
||||
extern const char cadetblue[];
|
||||
extern const char chartreuse[];
|
||||
extern const char chocolate[];
|
||||
extern const char coral[];
|
||||
extern const char cornflowerblue[];
|
||||
extern const char cornsilk[];
|
||||
extern const char crimson[];
|
||||
extern const char darkblue[];
|
||||
extern const char darkcyan[];
|
||||
extern const char darkgoldenrod[];
|
||||
extern const char darkgray[];
|
||||
extern const char darkgrey[];
|
||||
extern const char darkgreen[];
|
||||
extern const char darkkhaki[];
|
||||
extern const char darkmagenta[];
|
||||
extern const char darkolivegreen[];
|
||||
extern const char darkorange[];
|
||||
extern const char darkorchid[];
|
||||
extern const char darkred[];
|
||||
extern const char darksalmon[];
|
||||
extern const char darkseagreen[];
|
||||
extern const char darkslateblue[];
|
||||
extern const char darkslategray[];
|
||||
extern const char darkslategrey[];
|
||||
extern const char darkturquoise[];
|
||||
extern const char darkviolet[];
|
||||
extern const char deeppink[];
|
||||
extern const char deepskyblue[];
|
||||
extern const char dimgray[];
|
||||
extern const char dimgrey[];
|
||||
extern const char dodgerblue[];
|
||||
extern const char firebrick[];
|
||||
extern const char floralwhite[];
|
||||
extern const char forestgreen[];
|
||||
extern const char magenta[];
|
||||
extern const char fuchsia[];
|
||||
extern const char gainsboro[];
|
||||
extern const char ghostwhite[];
|
||||
extern const char gold[];
|
||||
extern const char goldenrod[];
|
||||
extern const char gray[];
|
||||
extern const char grey[];
|
||||
extern const char green[];
|
||||
extern const char greenyellow[];
|
||||
extern const char honeydew[];
|
||||
extern const char hotpink[];
|
||||
extern const char indianred[];
|
||||
extern const char indigo[];
|
||||
extern const char ivory[];
|
||||
extern const char khaki[];
|
||||
extern const char lavender[];
|
||||
extern const char lavenderblush[];
|
||||
extern const char lawngreen[];
|
||||
extern const char lemonchiffon[];
|
||||
extern const char lightblue[];
|
||||
extern const char lightcoral[];
|
||||
extern const char lightcyan[];
|
||||
extern const char lightgoldenrodyellow[];
|
||||
extern const char lightgray[];
|
||||
extern const char lightgrey[];
|
||||
extern const char lightgreen[];
|
||||
extern const char lightpink[];
|
||||
extern const char lightsalmon[];
|
||||
extern const char lightseagreen[];
|
||||
extern const char lightskyblue[];
|
||||
extern const char lightslategray[];
|
||||
extern const char lightslategrey[];
|
||||
extern const char lightsteelblue[];
|
||||
extern const char lightyellow[];
|
||||
extern const char lime[];
|
||||
extern const char limegreen[];
|
||||
extern const char linen[];
|
||||
extern const char maroon[];
|
||||
extern const char mediumaquamarine[];
|
||||
extern const char mediumblue[];
|
||||
extern const char mediumorchid[];
|
||||
extern const char mediumpurple[];
|
||||
extern const char mediumseagreen[];
|
||||
extern const char mediumslateblue[];
|
||||
extern const char mediumspringgreen[];
|
||||
extern const char mediumturquoise[];
|
||||
extern const char mediumvioletred[];
|
||||
extern const char midnightblue[];
|
||||
extern const char mintcream[];
|
||||
extern const char mistyrose[];
|
||||
extern const char moccasin[];
|
||||
extern const char navajowhite[];
|
||||
extern const char navy[];
|
||||
extern const char oldlace[];
|
||||
extern const char olive[];
|
||||
extern const char olivedrab[];
|
||||
extern const char orange[];
|
||||
extern const char orangered[];
|
||||
extern const char orchid[];
|
||||
extern const char palegoldenrod[];
|
||||
extern const char palegreen[];
|
||||
extern const char paleturquoise[];
|
||||
extern const char palevioletred[];
|
||||
extern const char papayawhip[];
|
||||
extern const char peachpuff[];
|
||||
extern const char peru[];
|
||||
extern const char pink[];
|
||||
extern const char plum[];
|
||||
extern const char powderblue[];
|
||||
extern const char purple[];
|
||||
extern const char red[];
|
||||
extern const char rosybrown[];
|
||||
extern const char royalblue[];
|
||||
extern const char saddlebrown[];
|
||||
extern const char salmon[];
|
||||
extern const char sandybrown[];
|
||||
extern const char seagreen[];
|
||||
extern const char seashell[];
|
||||
extern const char sienna[];
|
||||
extern const char silver[];
|
||||
extern const char skyblue[];
|
||||
extern const char slateblue[];
|
||||
extern const char slategray[];
|
||||
extern const char slategrey[];
|
||||
extern const char snow[];
|
||||
extern const char springgreen[];
|
||||
extern const char steelblue[];
|
||||
extern const char tan[];
|
||||
extern const char teal[];
|
||||
extern const char thistle[];
|
||||
extern const char tomato[];
|
||||
extern const char turquoise[];
|
||||
extern const char violet[];
|
||||
extern const char wheat[];
|
||||
extern const char white[];
|
||||
extern const char whitesmoke[];
|
||||
extern const char yellow[];
|
||||
extern const char yellowgreen[];
|
||||
extern const char rebeccapurple[];
|
||||
extern const char transparent[];
|
||||
}
|
||||
|
||||
namespace Colors {
|
||||
extern const Color aliceblue;
|
||||
extern const Color antiquewhite;
|
||||
extern const Color cyan;
|
||||
extern const Color aqua;
|
||||
extern const Color aquamarine;
|
||||
extern const Color azure;
|
||||
extern const Color beige;
|
||||
extern const Color bisque;
|
||||
extern const Color black;
|
||||
extern const Color blanchedalmond;
|
||||
extern const Color blue;
|
||||
extern const Color blueviolet;
|
||||
extern const Color brown;
|
||||
extern const Color burlywood;
|
||||
extern const Color cadetblue;
|
||||
extern const Color chartreuse;
|
||||
extern const Color chocolate;
|
||||
extern const Color coral;
|
||||
extern const Color cornflowerblue;
|
||||
extern const Color cornsilk;
|
||||
extern const Color crimson;
|
||||
extern const Color darkblue;
|
||||
extern const Color darkcyan;
|
||||
extern const Color darkgoldenrod;
|
||||
extern const Color darkgray;
|
||||
extern const Color darkgrey;
|
||||
extern const Color darkgreen;
|
||||
extern const Color darkkhaki;
|
||||
extern const Color darkmagenta;
|
||||
extern const Color darkolivegreen;
|
||||
extern const Color darkorange;
|
||||
extern const Color darkorchid;
|
||||
extern const Color darkred;
|
||||
extern const Color darksalmon;
|
||||
extern const Color darkseagreen;
|
||||
extern const Color darkslateblue;
|
||||
extern const Color darkslategray;
|
||||
extern const Color darkslategrey;
|
||||
extern const Color darkturquoise;
|
||||
extern const Color darkviolet;
|
||||
extern const Color deeppink;
|
||||
extern const Color deepskyblue;
|
||||
extern const Color dimgray;
|
||||
extern const Color dimgrey;
|
||||
extern const Color dodgerblue;
|
||||
extern const Color firebrick;
|
||||
extern const Color floralwhite;
|
||||
extern const Color forestgreen;
|
||||
extern const Color magenta;
|
||||
extern const Color fuchsia;
|
||||
extern const Color gainsboro;
|
||||
extern const Color ghostwhite;
|
||||
extern const Color gold;
|
||||
extern const Color goldenrod;
|
||||
extern const Color gray;
|
||||
extern const Color grey;
|
||||
extern const Color green;
|
||||
extern const Color greenyellow;
|
||||
extern const Color honeydew;
|
||||
extern const Color hotpink;
|
||||
extern const Color indianred;
|
||||
extern const Color indigo;
|
||||
extern const Color ivory;
|
||||
extern const Color khaki;
|
||||
extern const Color lavender;
|
||||
extern const Color lavenderblush;
|
||||
extern const Color lawngreen;
|
||||
extern const Color lemonchiffon;
|
||||
extern const Color lightblue;
|
||||
extern const Color lightcoral;
|
||||
extern const Color lightcyan;
|
||||
extern const Color lightgoldenrodyellow;
|
||||
extern const Color lightgray;
|
||||
extern const Color lightgrey;
|
||||
extern const Color lightgreen;
|
||||
extern const Color lightpink;
|
||||
extern const Color lightsalmon;
|
||||
extern const Color lightseagreen;
|
||||
extern const Color lightskyblue;
|
||||
extern const Color lightslategray;
|
||||
extern const Color lightslategrey;
|
||||
extern const Color lightsteelblue;
|
||||
extern const Color lightyellow;
|
||||
extern const Color lime;
|
||||
extern const Color limegreen;
|
||||
extern const Color linen;
|
||||
extern const Color maroon;
|
||||
extern const Color mediumaquamarine;
|
||||
extern const Color mediumblue;
|
||||
extern const Color mediumorchid;
|
||||
extern const Color mediumpurple;
|
||||
extern const Color mediumseagreen;
|
||||
extern const Color mediumslateblue;
|
||||
extern const Color mediumspringgreen;
|
||||
extern const Color mediumturquoise;
|
||||
extern const Color mediumvioletred;
|
||||
extern const Color midnightblue;
|
||||
extern const Color mintcream;
|
||||
extern const Color mistyrose;
|
||||
extern const Color moccasin;
|
||||
extern const Color navajowhite;
|
||||
extern const Color navy;
|
||||
extern const Color oldlace;
|
||||
extern const Color olive;
|
||||
extern const Color olivedrab;
|
||||
extern const Color orange;
|
||||
extern const Color orangered;
|
||||
extern const Color orchid;
|
||||
extern const Color palegoldenrod;
|
||||
extern const Color palegreen;
|
||||
extern const Color paleturquoise;
|
||||
extern const Color palevioletred;
|
||||
extern const Color papayawhip;
|
||||
extern const Color peachpuff;
|
||||
extern const Color peru;
|
||||
extern const Color pink;
|
||||
extern const Color plum;
|
||||
extern const Color powderblue;
|
||||
extern const Color purple;
|
||||
extern const Color red;
|
||||
extern const Color rosybrown;
|
||||
extern const Color royalblue;
|
||||
extern const Color saddlebrown;
|
||||
extern const Color salmon;
|
||||
extern const Color sandybrown;
|
||||
extern const Color seagreen;
|
||||
extern const Color seashell;
|
||||
extern const Color sienna;
|
||||
extern const Color silver;
|
||||
extern const Color skyblue;
|
||||
extern const Color slateblue;
|
||||
extern const Color slategray;
|
||||
extern const Color slategrey;
|
||||
extern const Color snow;
|
||||
extern const Color springgreen;
|
||||
extern const Color steelblue;
|
||||
extern const Color tan;
|
||||
extern const Color teal;
|
||||
extern const Color thistle;
|
||||
extern const Color tomato;
|
||||
extern const Color turquoise;
|
||||
extern const Color violet;
|
||||
extern const Color wheat;
|
||||
extern const Color white;
|
||||
extern const Color whitesmoke;
|
||||
extern const Color yellow;
|
||||
extern const Color yellowgreen;
|
||||
extern const Color rebeccapurple;
|
||||
extern const Color transparent;
|
||||
}
|
||||
|
||||
extern const std::map<const int, const char*> colors_to_names;
|
||||
extern const std::map<const char*, const Color*, map_cmp_str> names_to_colors;
|
||||
|
||||
extern const Color* name_to_color(const char*);
|
||||
extern const Color* name_to_color(const std::string&);
|
||||
extern const char* color_to_name(const int);
|
||||
extern const char* color_to_name(const Color&);
|
||||
extern const char* color_to_name(const double);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
#include "sass.hpp"
|
||||
#include "constants.hpp"
|
||||
|
||||
namespace Sass {
|
||||
namespace Constants {
|
||||
|
||||
extern const unsigned long MaxCallStack = 1024;
|
||||
|
||||
// https://github.com/sass/libsass/issues/592
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
|
||||
// https://github.com/sass/sass/issues/1495#issuecomment-61189114
|
||||
extern const unsigned long Specificity_Star = 0;
|
||||
extern const unsigned long Specificity_Universal = 1 << 0;
|
||||
extern const unsigned long Specificity_Type = 1 << 8;
|
||||
extern const unsigned long Specificity_Class = 1 << 16;
|
||||
extern const unsigned long Specificity_Attr = 1 << 16;
|
||||
extern const unsigned long Specificity_Pseudo = 1 << 16;
|
||||
extern const unsigned long Specificity_ID = 1 << 24;
|
||||
|
||||
// sass keywords
|
||||
extern const char at_root_kwd[] = "@at-root";
|
||||
extern const char import_kwd[] = "@import";
|
||||
extern const char mixin_kwd[] = "@mixin";
|
||||
extern const char function_kwd[] = "@function";
|
||||
extern const char return_kwd[] = "@return";
|
||||
extern const char include_kwd[] = "@include";
|
||||
extern const char content_kwd[] = "@content";
|
||||
extern const char extend_kwd[] = "@extend";
|
||||
extern const char if_kwd[] = "@if";
|
||||
extern const char else_kwd[] = "@else";
|
||||
extern const char if_after_else_kwd[] = "if";
|
||||
extern const char for_kwd[] = "@for";
|
||||
extern const char from_kwd[] = "from";
|
||||
extern const char to_kwd[] = "to";
|
||||
extern const char through_kwd[] = "through";
|
||||
extern const char each_kwd[] = "@each";
|
||||
extern const char in_kwd[] = "in";
|
||||
extern const char while_kwd[] = "@while";
|
||||
extern const char warn_kwd[] = "@warn";
|
||||
extern const char error_kwd[] = "@error";
|
||||
extern const char debug_kwd[] = "@debug";
|
||||
extern const char default_kwd[] = "default";
|
||||
extern const char global_kwd[] = "global";
|
||||
extern const char null_kwd[] = "null";
|
||||
extern const char optional_kwd[] = "optional";
|
||||
extern const char with_kwd[] = "with";
|
||||
extern const char without_kwd[] = "without";
|
||||
extern const char all_kwd[] = "all";
|
||||
extern const char rule_kwd[] = "rule";
|
||||
|
||||
// css standard units
|
||||
extern const char em_kwd[] = "em";
|
||||
extern const char ex_kwd[] = "ex";
|
||||
extern const char px_kwd[] = "px";
|
||||
extern const char cm_kwd[] = "cm";
|
||||
extern const char mm_kwd[] = "mm";
|
||||
extern const char pt_kwd[] = "pt";
|
||||
extern const char pc_kwd[] = "pc";
|
||||
extern const char deg_kwd[] = "deg";
|
||||
extern const char rad_kwd[] = "rad";
|
||||
extern const char grad_kwd[] = "grad";
|
||||
extern const char turn_kwd[] = "turn";
|
||||
extern const char ms_kwd[] = "ms";
|
||||
extern const char s_kwd[] = "s";
|
||||
extern const char Hz_kwd[] = "Hz";
|
||||
extern const char kHz_kwd[] = "kHz";
|
||||
|
||||
// vendor prefixes
|
||||
extern const char vendor_opera_kwd[] = "-o-";
|
||||
extern const char vendor_webkit_kwd[] = "-webkit-";
|
||||
extern const char vendor_mozilla_kwd[] = "-moz-";
|
||||
extern const char vendor_ms_kwd[] = "-ms-";
|
||||
extern const char vendor_khtml_kwd[] = "-khtml-";
|
||||
|
||||
// css functions and keywords
|
||||
extern const char charset_kwd[] = "@charset";
|
||||
extern const char media_kwd[] = "@media";
|
||||
extern const char supports_kwd[] = "@supports";
|
||||
extern const char keyframes_kwd[] = "keyframes";
|
||||
extern const char only_kwd[] = "only";
|
||||
extern const char rgb_kwd[] = "rgb(";
|
||||
extern const char url_kwd[] = "url";
|
||||
// extern const char url_prefix_kwd[] = "url-prefix(";
|
||||
extern const char important_kwd[] = "important";
|
||||
extern const char pseudo_not_kwd[] = ":not(";
|
||||
extern const char even_kwd[] = "even";
|
||||
extern const char odd_kwd[] = "odd";
|
||||
extern const char progid_kwd[] = "progid";
|
||||
extern const char expression_kwd[] = "expression";
|
||||
extern const char calc_fn_kwd[] = "calc";
|
||||
|
||||
extern const char almost_any_value_class[] = "\"'#!;{}";
|
||||
|
||||
// css selector keywords
|
||||
extern const char sel_deep_kwd[] = "/deep/";
|
||||
|
||||
// css attribute-matching operators
|
||||
extern const char tilde_equal[] = "~=";
|
||||
extern const char pipe_equal[] = "|=";
|
||||
extern const char caret_equal[] = "^=";
|
||||
extern const char dollar_equal[] = "$=";
|
||||
extern const char star_equal[] = "*=";
|
||||
|
||||
// relational & logical operators and constants
|
||||
extern const char and_kwd[] = "and";
|
||||
extern const char or_kwd[] = "or";
|
||||
extern const char not_kwd[] = "not";
|
||||
extern const char gt[] = ">";
|
||||
extern const char gte[] = ">=";
|
||||
extern const char lt[] = "<";
|
||||
extern const char lte[] = "<=";
|
||||
extern const char eq[] = "==";
|
||||
extern const char neq[] = "!=";
|
||||
extern const char true_kwd[] = "true";
|
||||
extern const char false_kwd[] = "false";
|
||||
|
||||
// miscellaneous punctuation and delimiters
|
||||
extern const char percent_str[] = "%";
|
||||
extern const char empty_str[] = "";
|
||||
extern const char slash_slash[] = "//";
|
||||
extern const char slash_star[] = "/*";
|
||||
extern const char star_slash[] = "*/";
|
||||
extern const char hash_lbrace[] = "#{";
|
||||
extern const char rbrace[] = "}";
|
||||
extern const char rparen[] = ")";
|
||||
extern const char sign_chars[] = "-+";
|
||||
extern const char op_chars[] = "-+";
|
||||
extern const char hyphen[] = "-";
|
||||
extern const char ellipsis[] = "...";
|
||||
// extern const char url_space_chars[] = " \t\r\n\f";
|
||||
// type names
|
||||
extern const char numeric_name[] = "numeric value";
|
||||
extern const char number_name[] = "number";
|
||||
extern const char percentage_name[] = "percentage";
|
||||
extern const char dimension_name[] = "numeric dimension";
|
||||
extern const char string_name[] = "string";
|
||||
extern const char bool_name[] = "bool";
|
||||
extern const char color_name[] = "color";
|
||||
extern const char list_name[] = "list";
|
||||
extern const char map_name[] = "map";
|
||||
extern const char arglist_name[] = "arglist";
|
||||
|
||||
// constants for uri parsing (RFC 3986 Appendix A.)
|
||||
extern const char uri_chars[] = ":;/?!%&#@|[]{}'`^\"*+-.,_=~";
|
||||
extern const char real_uri_chars[] = "#%&";
|
||||
|
||||
// some specific constant character classes
|
||||
// they must be static to be useable by lexer
|
||||
extern const char static_ops[] = "*/%";
|
||||
// some character classes for the parser
|
||||
extern const char selector_list_delims[] = "){};!";
|
||||
extern const char complex_selector_delims[] = ",){};!";
|
||||
extern const char selector_combinator_ops[] = "+~>";
|
||||
// optional modifiers for alternative compare context
|
||||
extern const char attribute_compare_modifiers[] = "~|^$*";
|
||||
extern const char selector_lookahead_ops[] = "*&%,()[]";
|
||||
|
||||
// byte order marks
|
||||
// (taken from http://en.wikipedia.org/wiki/Byte_order_mark)
|
||||
extern const unsigned char utf_8_bom[] = { 0xEF, 0xBB, 0xBF };
|
||||
extern const unsigned char utf_16_bom_be[] = { 0xFE, 0xFF };
|
||||
extern const unsigned char utf_16_bom_le[] = { 0xFF, 0xFE };
|
||||
extern const unsigned char utf_32_bom_be[] = { 0x00, 0x00, 0xFE, 0xFF };
|
||||
extern const unsigned char utf_32_bom_le[] = { 0xFF, 0xFE, 0x00, 0x00 };
|
||||
extern const unsigned char utf_7_bom_1[] = { 0x2B, 0x2F, 0x76, 0x38 };
|
||||
extern const unsigned char utf_7_bom_2[] = { 0x2B, 0x2F, 0x76, 0x39 };
|
||||
extern const unsigned char utf_7_bom_3[] = { 0x2B, 0x2F, 0x76, 0x2B };
|
||||
extern const unsigned char utf_7_bom_4[] = { 0x2B, 0x2F, 0x76, 0x2F };
|
||||
extern const unsigned char utf_7_bom_5[] = { 0x2B, 0x2F, 0x76, 0x38, 0x2D };
|
||||
extern const unsigned char utf_1_bom[] = { 0xF7, 0x64, 0x4C };
|
||||
extern const unsigned char utf_ebcdic_bom[] = { 0xDD, 0x73, 0x66, 0x73 };
|
||||
extern const unsigned char scsu_bom[] = { 0x0E, 0xFE, 0xFF };
|
||||
extern const unsigned char bocu_1_bom[] = { 0xFB, 0xEE, 0x28 };
|
||||
extern const unsigned char gb_18030_bom[] = { 0x84, 0x31, 0x95, 0x33 };
|
||||
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
#ifndef SASS_CONSTANTS_H
|
||||
#define SASS_CONSTANTS_H
|
||||
|
||||
namespace Sass {
|
||||
namespace Constants {
|
||||
|
||||
// The maximum call stack that can be created
|
||||
extern const unsigned long MaxCallStack;
|
||||
|
||||
// https://developer.mozilla.org/en-US/docs/Web/CSS/Specificity
|
||||
// The following list of selectors is by increasing specificity:
|
||||
extern const unsigned long Specificity_Star;
|
||||
extern const unsigned long Specificity_Universal;
|
||||
extern const unsigned long Specificity_Type;
|
||||
extern const unsigned long Specificity_Class;
|
||||
extern const unsigned long Specificity_Attr;
|
||||
extern const unsigned long Specificity_Pseudo;
|
||||
extern const unsigned long Specificity_ID;
|
||||
|
||||
// sass keywords
|
||||
extern const char at_root_kwd[];
|
||||
extern const char import_kwd[];
|
||||
extern const char mixin_kwd[];
|
||||
extern const char function_kwd[];
|
||||
extern const char return_kwd[];
|
||||
extern const char include_kwd[];
|
||||
extern const char content_kwd[];
|
||||
extern const char extend_kwd[];
|
||||
extern const char if_kwd[];
|
||||
extern const char else_kwd[];
|
||||
extern const char if_after_else_kwd[];
|
||||
extern const char for_kwd[];
|
||||
extern const char from_kwd[];
|
||||
extern const char to_kwd[];
|
||||
extern const char through_kwd[];
|
||||
extern const char each_kwd[];
|
||||
extern const char in_kwd[];
|
||||
extern const char while_kwd[];
|
||||
extern const char warn_kwd[];
|
||||
extern const char error_kwd[];
|
||||
extern const char debug_kwd[];
|
||||
extern const char default_kwd[];
|
||||
extern const char global_kwd[];
|
||||
extern const char null_kwd[];
|
||||
extern const char optional_kwd[];
|
||||
extern const char with_kwd[];
|
||||
extern const char without_kwd[];
|
||||
extern const char all_kwd[];
|
||||
extern const char rule_kwd[];
|
||||
|
||||
// css standard units
|
||||
extern const char em_kwd[];
|
||||
extern const char ex_kwd[];
|
||||
extern const char px_kwd[];
|
||||
extern const char cm_kwd[];
|
||||
extern const char mm_kwd[];
|
||||
extern const char pt_kwd[];
|
||||
extern const char pc_kwd[];
|
||||
extern const char deg_kwd[];
|
||||
extern const char rad_kwd[];
|
||||
extern const char grad_kwd[];
|
||||
extern const char turn_kwd[];
|
||||
extern const char ms_kwd[];
|
||||
extern const char s_kwd[];
|
||||
extern const char Hz_kwd[];
|
||||
extern const char kHz_kwd[];
|
||||
|
||||
// vendor prefixes
|
||||
extern const char vendor_opera_kwd[];
|
||||
extern const char vendor_webkit_kwd[];
|
||||
extern const char vendor_mozilla_kwd[];
|
||||
extern const char vendor_ms_kwd[];
|
||||
extern const char vendor_khtml_kwd[];
|
||||
|
||||
// css functions and keywords
|
||||
extern const char charset_kwd[];
|
||||
extern const char media_kwd[];
|
||||
extern const char supports_kwd[];
|
||||
extern const char keyframes_kwd[];
|
||||
extern const char only_kwd[];
|
||||
extern const char rgb_kwd[];
|
||||
extern const char url_kwd[];
|
||||
// extern const char url_prefix_kwd[];
|
||||
extern const char important_kwd[];
|
||||
extern const char pseudo_not_kwd[];
|
||||
extern const char even_kwd[];
|
||||
extern const char odd_kwd[];
|
||||
extern const char progid_kwd[];
|
||||
extern const char expression_kwd[];
|
||||
extern const char calc_fn_kwd[];
|
||||
|
||||
// char classes for "regular expressions"
|
||||
extern const char almost_any_value_class[];
|
||||
|
||||
// css selector keywords
|
||||
extern const char sel_deep_kwd[];
|
||||
|
||||
// css attribute-matching operators
|
||||
extern const char tilde_equal[];
|
||||
extern const char pipe_equal[];
|
||||
extern const char caret_equal[];
|
||||
extern const char dollar_equal[];
|
||||
extern const char star_equal[];
|
||||
|
||||
// relational & logical operators and constants
|
||||
extern const char and_kwd[];
|
||||
extern const char or_kwd[];
|
||||
extern const char not_kwd[];
|
||||
extern const char gt[];
|
||||
extern const char gte[];
|
||||
extern const char lt[];
|
||||
extern const char lte[];
|
||||
extern const char eq[];
|
||||
extern const char neq[];
|
||||
extern const char true_kwd[];
|
||||
extern const char false_kwd[];
|
||||
|
||||
// miscellaneous punctuation and delimiters
|
||||
extern const char percent_str[];
|
||||
extern const char empty_str[];
|
||||
extern const char slash_slash[];
|
||||
extern const char slash_star[];
|
||||
extern const char star_slash[];
|
||||
extern const char hash_lbrace[];
|
||||
extern const char rbrace[];
|
||||
extern const char rparen[];
|
||||
extern const char sign_chars[];
|
||||
extern const char op_chars[];
|
||||
extern const char hyphen[];
|
||||
extern const char ellipsis[];
|
||||
// extern const char url_space_chars[];
|
||||
|
||||
// type names
|
||||
extern const char numeric_name[];
|
||||
extern const char number_name[];
|
||||
extern const char percentage_name[];
|
||||
extern const char dimension_name[];
|
||||
extern const char string_name[];
|
||||
extern const char bool_name[];
|
||||
extern const char color_name[];
|
||||
extern const char list_name[];
|
||||
extern const char map_name[];
|
||||
extern const char arglist_name[];
|
||||
|
||||
// constants for uri parsing (RFC 3986 Appendix A.)
|
||||
extern const char uri_chars[];
|
||||
extern const char real_uri_chars[];
|
||||
|
||||
// some specific constant character classes
|
||||
// they must be static to be useable by lexer
|
||||
extern const char static_ops[];
|
||||
extern const char selector_list_delims[];
|
||||
extern const char complex_selector_delims[];
|
||||
extern const char selector_combinator_ops[];
|
||||
extern const char attribute_compare_modifiers[];
|
||||
extern const char selector_lookahead_ops[];
|
||||
|
||||
// byte order marks
|
||||
// (taken from http://en.wikipedia.org/wiki/Byte_order_mark)
|
||||
extern const unsigned char utf_8_bom[];
|
||||
extern const unsigned char utf_16_bom_be[];
|
||||
extern const unsigned char utf_16_bom_le[];
|
||||
extern const unsigned char utf_32_bom_be[];
|
||||
extern const unsigned char utf_32_bom_le[];
|
||||
extern const unsigned char utf_7_bom_1[];
|
||||
extern const unsigned char utf_7_bom_2[];
|
||||
extern const unsigned char utf_7_bom_3[];
|
||||
extern const unsigned char utf_7_bom_4[];
|
||||
extern const unsigned char utf_7_bom_5[];
|
||||
extern const unsigned char utf_1_bom[];
|
||||
extern const unsigned char utf_ebcdic_bom[];
|
||||
extern const unsigned char scsu_bom[];
|
||||
extern const unsigned char bocu_1_bom[];
|
||||
extern const unsigned char gb_18030_bom[];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
+858
@@ -0,0 +1,858 @@
|
||||
#include "sass.hpp"
|
||||
#include <string>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
#include "ast.hpp"
|
||||
#include "util.hpp"
|
||||
#include "sass.h"
|
||||
#include "context.hpp"
|
||||
#include "plugins.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "parser.hpp"
|
||||
#include "file.hpp"
|
||||
#include "inspect.hpp"
|
||||
#include "output.hpp"
|
||||
#include "expand.hpp"
|
||||
#include "eval.hpp"
|
||||
#include "cssize.hpp"
|
||||
#include "listize.hpp"
|
||||
#include "extend.hpp"
|
||||
#include "remove_placeholders.hpp"
|
||||
#include "functions.hpp"
|
||||
#include "sass_functions.hpp"
|
||||
#include "backtrace.hpp"
|
||||
#include "sass2scss.h"
|
||||
#include "prelexer.hpp"
|
||||
#include "emitter.hpp"
|
||||
|
||||
namespace Sass {
|
||||
using namespace Constants;
|
||||
using namespace File;
|
||||
using namespace Sass;
|
||||
|
||||
inline bool sort_importers (const Sass_Importer_Entry& i, const Sass_Importer_Entry& j)
|
||||
{ return sass_importer_get_priority(i) > sass_importer_get_priority(j); }
|
||||
|
||||
static std::string safe_input(const char* in_path)
|
||||
{
|
||||
// enforce some safe defaults
|
||||
// used to create relative file links
|
||||
std::string safe_path(in_path ? in_path : "");
|
||||
return safe_path == "" ? "stdin" : safe_path;
|
||||
}
|
||||
|
||||
static std::string safe_output(const char* out_path, const std::string& input_path = "")
|
||||
{
|
||||
std::string safe_path(out_path ? out_path : "");
|
||||
// maybe we can extract an output path from input path
|
||||
if (safe_path == "" && input_path != "") {
|
||||
int lastindex = static_cast<int>(input_path.find_last_of("."));
|
||||
return (lastindex > -1 ? input_path.substr(0, lastindex) : input_path) + ".css";
|
||||
}
|
||||
// enforce some safe defaults
|
||||
// used to create relative file links
|
||||
return safe_path == "" ? "stdout" : safe_path;
|
||||
}
|
||||
|
||||
Context::Context(struct Sass_Context& c_ctx)
|
||||
: CWD(File::get_cwd()),
|
||||
c_options(c_ctx),
|
||||
entry_path(""),
|
||||
head_imports(0),
|
||||
mem(Memory_Manager()),
|
||||
plugins(),
|
||||
emitter(c_options),
|
||||
|
||||
strings(),
|
||||
resources(),
|
||||
sheets(),
|
||||
subset_map(),
|
||||
import_stack(),
|
||||
|
||||
c_headers (std::vector<Sass_Importer_Entry>()),
|
||||
c_importers (std::vector<Sass_Importer_Entry>()),
|
||||
c_functions (std::vector<Sass_Function_Entry>()),
|
||||
|
||||
indent (safe_str(c_options.indent, " ")),
|
||||
linefeed (safe_str(c_options.linefeed, "\n")),
|
||||
|
||||
input_path (make_canonical_path(safe_input(c_options.input_path))),
|
||||
output_path (make_canonical_path(safe_output(c_options.output_path, input_path))),
|
||||
source_map_file (make_canonical_path(safe_str(c_options.source_map_file, ""))),
|
||||
source_map_root (make_canonical_path(safe_str(c_options.source_map_root, "")))
|
||||
|
||||
{
|
||||
|
||||
// add cwd to include paths
|
||||
include_paths.push_back(CWD);
|
||||
|
||||
// collect more paths from different options
|
||||
collect_include_paths(c_options.include_path);
|
||||
collect_include_paths(c_options.include_paths);
|
||||
collect_plugin_paths(c_options.plugin_path);
|
||||
collect_plugin_paths(c_options.plugin_paths);
|
||||
|
||||
// load plugins and register custom behaviors
|
||||
for(auto plug : plugin_paths) plugins.load_plugins(plug);
|
||||
for(auto fn : plugins.get_headers()) c_headers.push_back(fn);
|
||||
for(auto fn : plugins.get_importers()) c_importers.push_back(fn);
|
||||
for(auto fn : plugins.get_functions()) c_functions.push_back(fn);
|
||||
|
||||
// sort the items by priority (lowest first)
|
||||
sort (c_headers.begin(), c_headers.end(), sort_importers);
|
||||
sort (c_importers.begin(), c_importers.end(), sort_importers);
|
||||
|
||||
emitter.set_filename(abs2rel(output_path, source_map_file, CWD));
|
||||
|
||||
}
|
||||
|
||||
void Context::add_c_function(Sass_Function_Entry function)
|
||||
{
|
||||
c_functions.push_back(function);
|
||||
}
|
||||
void Context::add_c_header(Sass_Importer_Entry header)
|
||||
{
|
||||
c_headers.push_back(header);
|
||||
// need to sort the array afterwards (no big deal)
|
||||
sort (c_headers.begin(), c_headers.end(), sort_importers);
|
||||
}
|
||||
void Context::add_c_importer(Sass_Importer_Entry importer)
|
||||
{
|
||||
c_importers.push_back(importer);
|
||||
// need to sort the array afterwards (no big deal)
|
||||
sort (c_importers.begin(), c_importers.end(), sort_importers);
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
// resources were allocated by strdup or malloc
|
||||
for (size_t i = 0; i < resources.size(); ++i) {
|
||||
free(resources[i].contents);
|
||||
free(resources[i].srcmap);
|
||||
}
|
||||
// free all strings we kept alive during compiler execution
|
||||
for (size_t n = 0; n < strings.size(); ++n) free(strings[n]);
|
||||
// everything that gets put into sources will be freed by us
|
||||
// this shouldn't have anything in it anyway!?
|
||||
for (size_t m = 0; m < import_stack.size(); ++m) {
|
||||
sass_import_take_source(import_stack[m]);
|
||||
sass_import_take_srcmap(import_stack[m]);
|
||||
sass_delete_import(import_stack[m]);
|
||||
}
|
||||
// clear inner structures (vectors) and input source
|
||||
resources.clear(); import_stack.clear();
|
||||
}
|
||||
|
||||
Data_Context::~Data_Context()
|
||||
{
|
||||
// --> this will be freed by resources
|
||||
// make sure we free the source even if not processed!
|
||||
// if (resources.size() == 0 && source_c_str) free(source_c_str);
|
||||
// if (resources.size() == 0 && srcmap_c_str) free(srcmap_c_str);
|
||||
// source_c_str = 0; srcmap_c_str = 0;
|
||||
}
|
||||
|
||||
File_Context::~File_Context()
|
||||
{
|
||||
}
|
||||
|
||||
void Context::collect_include_paths(const char* paths_str)
|
||||
{
|
||||
if (paths_str) {
|
||||
const char* beg = paths_str;
|
||||
const char* end = Prelexer::find_first<PATH_SEP>(beg);
|
||||
|
||||
while (end) {
|
||||
std::string path(beg, end - beg);
|
||||
if (!path.empty()) {
|
||||
if (*path.rbegin() != '/') path += '/';
|
||||
include_paths.push_back(path);
|
||||
}
|
||||
beg = end + 1;
|
||||
end = Prelexer::find_first<PATH_SEP>(beg);
|
||||
}
|
||||
|
||||
std::string path(beg);
|
||||
if (!path.empty()) {
|
||||
if (*path.rbegin() != '/') path += '/';
|
||||
include_paths.push_back(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::collect_include_paths(string_list* paths_array)
|
||||
{
|
||||
while (paths_array)
|
||||
{
|
||||
collect_include_paths(paths_array->string);
|
||||
paths_array = paths_array->next;
|
||||
}
|
||||
}
|
||||
|
||||
void Context::collect_plugin_paths(const char* paths_str)
|
||||
{
|
||||
if (paths_str) {
|
||||
const char* beg = paths_str;
|
||||
const char* end = Prelexer::find_first<PATH_SEP>(beg);
|
||||
|
||||
while (end) {
|
||||
std::string path(beg, end - beg);
|
||||
if (!path.empty()) {
|
||||
if (*path.rbegin() != '/') path += '/';
|
||||
plugin_paths.push_back(path);
|
||||
}
|
||||
beg = end + 1;
|
||||
end = Prelexer::find_first<PATH_SEP>(beg);
|
||||
}
|
||||
|
||||
std::string path(beg);
|
||||
if (!path.empty()) {
|
||||
if (*path.rbegin() != '/') path += '/';
|
||||
plugin_paths.push_back(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Context::collect_plugin_paths(string_list* paths_array)
|
||||
{
|
||||
while (paths_array)
|
||||
{
|
||||
collect_plugin_paths(paths_array->string);
|
||||
paths_array = paths_array->next;
|
||||
}
|
||||
}
|
||||
|
||||
// resolve the imp_path in base_path or include_paths
|
||||
// looks for alternatives and returns a list from one directory
|
||||
std::vector<Include> Context::find_includes(const Importer& import)
|
||||
{
|
||||
// make sure we resolve against an absolute path
|
||||
std::string base_path(rel2abs(import.base_path));
|
||||
// first try to resolve the load path relative to the base path
|
||||
std::vector<Include> vec(resolve_includes(base_path, import.imp_path));
|
||||
// then search in every include path (but only if nothing found yet)
|
||||
for (size_t i = 0, S = include_paths.size(); vec.size() == 0 && i < S; ++i)
|
||||
{
|
||||
// call resolve_includes and individual base path and append all results
|
||||
std::vector<Include> resolved(resolve_includes(include_paths[i], import.imp_path));
|
||||
if (resolved.size()) vec.insert(vec.end(), resolved.begin(), resolved.end());
|
||||
}
|
||||
// return vector
|
||||
return vec;
|
||||
}
|
||||
|
||||
|
||||
// register include with resolved path and its content
|
||||
// memory of the resources will be freed by us on exit
|
||||
void Context::register_resource(const Include& inc, const Resource& res, ParserState* prstate)
|
||||
{
|
||||
|
||||
// do not parse same resource twice
|
||||
// maybe raise an error in this case
|
||||
// if (sheets.count(inc.abs_path)) {
|
||||
// free(res.contents); free(res.srcmap);
|
||||
// throw std::runtime_error("duplicate resource registered");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// get index for this resource
|
||||
size_t idx = resources.size();
|
||||
|
||||
// tell emitter about new resource
|
||||
emitter.add_source_index(idx);
|
||||
|
||||
// put resources under our control
|
||||
// the memory will be freed later
|
||||
resources.push_back(res);
|
||||
|
||||
// add a relative link to the working directory
|
||||
included_files.push_back(inc.abs_path);
|
||||
// add a relative link to the source map output file
|
||||
srcmap_links.push_back(abs2rel(inc.abs_path, source_map_file, CWD));
|
||||
|
||||
// get pointer to the loaded content
|
||||
Sass_Import_Entry import = sass_make_import(
|
||||
inc.imp_path.c_str(),
|
||||
inc.abs_path.c_str(),
|
||||
res.contents,
|
||||
res.srcmap
|
||||
);
|
||||
// add the entry to the stack
|
||||
import_stack.push_back(import);
|
||||
|
||||
// get pointer to the loaded content
|
||||
const char* contents = resources[idx].contents;
|
||||
// keep a copy of the path around (for parserstates)
|
||||
// ToDo: we clean it, but still not very elegant!?
|
||||
strings.push_back(sass_copy_c_string(inc.abs_path.c_str()));
|
||||
// create the initial parser state from resource
|
||||
ParserState pstate(strings.back(), contents, idx);
|
||||
|
||||
// check existing import stack for possible recursion
|
||||
for (size_t i = 0; i < import_stack.size() - 2; ++i) {
|
||||
auto parent = import_stack[i];
|
||||
if (std::strcmp(parent->abs_path, import->abs_path) == 0) {
|
||||
std::string stack("An @import loop has been found:");
|
||||
for (size_t n = 1; n < i + 2; ++n) {
|
||||
stack += "\n " + std::string(import_stack[n]->imp_path) +
|
||||
" imports " + std::string(import_stack[n+1]->imp_path);
|
||||
}
|
||||
// implement error throw directly until we
|
||||
// decided how to handle full stack traces
|
||||
ParserState state = prstate ? *prstate : pstate;
|
||||
throw Exception::InvalidSyntax(state, stack, &import_stack);
|
||||
// error(stack, prstate ? *prstate : pstate, import_stack);
|
||||
}
|
||||
}
|
||||
|
||||
// create a parser instance from the given c_str buffer
|
||||
Parser p(Parser::from_c_str(contents, *this, pstate));
|
||||
// do not yet dispose these buffers
|
||||
sass_import_take_source(import);
|
||||
sass_import_take_srcmap(import);
|
||||
// then parse the root block
|
||||
Block* root = p.parse();
|
||||
// delete memory of current stack frame
|
||||
sass_delete_import(import_stack.back());
|
||||
// remove current stack frame
|
||||
import_stack.pop_back();
|
||||
// create key/value pair for ast node
|
||||
std::pair<const std::string, const StyleSheet>
|
||||
ast_pair(inc.abs_path, { res, root });
|
||||
// register resulting resource
|
||||
sheets.insert(ast_pair);
|
||||
|
||||
}
|
||||
|
||||
// Add a new import to the context (called from `import_url`)
|
||||
Include Context::load_import(const Importer& imp, ParserState pstate)
|
||||
{
|
||||
|
||||
// search for valid imports (ie. partials) on the filesystem
|
||||
// this may return more than one valid result (ambiguous imp_path)
|
||||
const std::vector<Include> resolved(find_includes(imp));
|
||||
|
||||
// error nicely on ambiguous imp_path
|
||||
if (resolved.size() > 1) {
|
||||
std::stringstream msg_stream;
|
||||
msg_stream << "It's not clear which file to import for ";
|
||||
msg_stream << "'@import \"" << imp.imp_path << "\"'." << "\n";
|
||||
msg_stream << "Candidates:" << "\n";
|
||||
for (size_t i = 0, L = resolved.size(); i < L; ++i)
|
||||
{ msg_stream << " " << resolved[i].imp_path << "\n"; }
|
||||
msg_stream << "Please delete or rename all but one of these files." << "\n";
|
||||
error(msg_stream.str(), pstate);
|
||||
}
|
||||
|
||||
// process the resolved entry
|
||||
else if (resolved.size() == 1) {
|
||||
bool use_cache = c_importers.size() == 0;
|
||||
// use cache for the resource loading
|
||||
if (use_cache && sheets.count(resolved[0].abs_path)) return resolved[0];
|
||||
// try to read the content of the resolved file entry
|
||||
// the memory buffer returned must be freed by us!
|
||||
if (char* contents = read_file(resolved[0].abs_path)) {
|
||||
// register the newly resolved file resource
|
||||
register_resource(resolved[0], { contents, 0 }, &pstate);
|
||||
// return resolved entry
|
||||
return resolved[0];
|
||||
}
|
||||
}
|
||||
|
||||
// nothing found
|
||||
return { imp, "" };
|
||||
|
||||
}
|
||||
|
||||
void Context::import_url (Import* imp, std::string load_path, const std::string& ctx_path) {
|
||||
|
||||
ParserState pstate(imp->pstate());
|
||||
std::string imp_path(unquote(load_path));
|
||||
std::string protocol("file");
|
||||
|
||||
using namespace Prelexer;
|
||||
if (const char* proto = sequence< identifier, exactly<':'>, exactly<'/'>, exactly<'/'> >(imp_path.c_str())) {
|
||||
|
||||
protocol = std::string(imp_path.c_str(), proto - 3);
|
||||
// if (protocol.compare("file") && true) { }
|
||||
}
|
||||
|
||||
// add urls (protocol other than file) and urls without procotol to `urls` member
|
||||
// ToDo: if ctx_path is already a file resource, we should not add it here?
|
||||
if (imp->media_queries() || protocol != "file" || imp_path.substr(0, 2) == "//") {
|
||||
imp->urls().push_back(SASS_MEMORY_NEW(mem, String_Quoted, imp->pstate(), load_path));
|
||||
}
|
||||
else if (imp_path.length() > 4 && imp_path.substr(imp_path.length() - 4, 4) == ".css") {
|
||||
String_Constant* loc = SASS_MEMORY_NEW(mem, String_Constant, pstate, unquote(load_path));
|
||||
Argument* loc_arg = SASS_MEMORY_NEW(mem, Argument, pstate, loc);
|
||||
Arguments* loc_args = SASS_MEMORY_NEW(mem, Arguments, pstate);
|
||||
(*loc_args) << loc_arg;
|
||||
Function_Call* new_url = SASS_MEMORY_NEW(mem, Function_Call, pstate, "url", loc_args);
|
||||
imp->urls().push_back(new_url);
|
||||
}
|
||||
else {
|
||||
const Importer importer(imp_path, ctx_path);
|
||||
Include include(load_import(importer, pstate));
|
||||
if (include.abs_path.empty()) {
|
||||
error("File to import not found or unreadable: " + imp_path + "\nParent style sheet: " + ctx_path, pstate);
|
||||
}
|
||||
imp->incs().push_back(include);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// call custom importers on the given (unquoted) load_path and eventually parse the resulting style_sheet
|
||||
bool Context::call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one)
|
||||
{
|
||||
// unique counter
|
||||
size_t count = 0;
|
||||
// need one correct import
|
||||
bool has_import = false;
|
||||
// process all custom importers (or custom headers)
|
||||
for (Sass_Importer_Entry& importer : importers) {
|
||||
// int priority = sass_importer_get_priority(importer);
|
||||
Sass_Importer_Fn fn = sass_importer_get_function(importer);
|
||||
// skip importer if it returns NULL
|
||||
if (Sass_Import_List includes =
|
||||
fn(load_path.c_str(), importer, c_compiler)
|
||||
) {
|
||||
// get c pointer copy to iterate over
|
||||
Sass_Import_List it_includes = includes;
|
||||
while (*it_includes) { ++count;
|
||||
// create unique path to use as key
|
||||
std::string uniq_path = load_path;
|
||||
if (!only_one && count) {
|
||||
std::stringstream path_strm;
|
||||
path_strm << uniq_path << ":" << count;
|
||||
uniq_path = path_strm.str();
|
||||
}
|
||||
// create the importer struct
|
||||
Importer importer(uniq_path, ctx_path);
|
||||
// query data from the current include
|
||||
Sass_Import_Entry include = *it_includes;
|
||||
char* source = sass_import_take_source(include);
|
||||
char* srcmap = sass_import_take_srcmap(include);
|
||||
size_t line = sass_import_get_error_line(include);
|
||||
size_t column = sass_import_get_error_column(include);
|
||||
const char *abs_path = sass_import_get_abs_path(include);
|
||||
// handle error message passed back from custom importer
|
||||
// it may (or may not) override the line and column info
|
||||
if (const char* err_message = sass_import_get_error_message(include)) {
|
||||
if (source || srcmap) register_resource({ importer, uniq_path }, { source, srcmap }, &pstate);
|
||||
if (line == std::string::npos && column == std::string::npos) error(err_message, pstate);
|
||||
else error(err_message, ParserState(ctx_path, source, Position(line, column)));
|
||||
}
|
||||
// content for import was set
|
||||
else if (source) {
|
||||
// resolved abs_path should be set by custom importer
|
||||
// use the created uniq_path as fallback (maybe enforce)
|
||||
std::string path_key(abs_path ? abs_path : uniq_path);
|
||||
// create the importer struct
|
||||
Include include(importer, path_key);
|
||||
// attach information to AST node
|
||||
imp->incs().push_back(include);
|
||||
// register the resource buffers
|
||||
register_resource(include, { source, srcmap }, &pstate);
|
||||
}
|
||||
// only a path was retuned
|
||||
// try to load it like normal
|
||||
else if(abs_path) {
|
||||
// checks some urls to preserve
|
||||
// `http://`, `https://` and `//`
|
||||
// or dispatchs to `import_file`
|
||||
// which will check for a `.css` extension
|
||||
// or resolves the file on the filesystem
|
||||
// added and resolved via `add_file`
|
||||
// finally stores everything on `imp`
|
||||
import_url(imp, abs_path, ctx_path);
|
||||
}
|
||||
// move to next
|
||||
++it_includes;
|
||||
}
|
||||
// deallocate the returned memory
|
||||
sass_delete_import_list(includes);
|
||||
// set success flag
|
||||
has_import = true;
|
||||
// break out of loop
|
||||
if (only_one) break;
|
||||
}
|
||||
}
|
||||
// return result
|
||||
return has_import;
|
||||
}
|
||||
|
||||
void register_function(Context&, Signature sig, Native_Function f, Env* env);
|
||||
void register_function(Context&, Signature sig, Native_Function f, size_t arity, Env* env);
|
||||
void register_overload_stub(Context&, std::string name, Env* env);
|
||||
void register_built_in_functions(Context&, Env* env);
|
||||
void register_c_functions(Context&, Env* env, Sass_Function_List);
|
||||
void register_c_function(Context&, Env* env, Sass_Function_Entry);
|
||||
|
||||
char* Context::render(Block* root)
|
||||
{
|
||||
// check for valid block
|
||||
if (!root) return 0;
|
||||
// start the render process
|
||||
root->perform(&emitter);
|
||||
// finish emitter stream
|
||||
emitter.finalize();
|
||||
// get the resulting buffer from stream
|
||||
OutputBuffer emitted = emitter.get_buffer();
|
||||
// should we append a source map url?
|
||||
if (!c_options.omit_source_map_url) {
|
||||
// generate an embeded source map
|
||||
if (c_options.source_map_embed) {
|
||||
emitted.buffer += linefeed;
|
||||
emitted.buffer += format_embedded_source_map();
|
||||
}
|
||||
// or just link the generated one
|
||||
else if (source_map_file != "") {
|
||||
emitted.buffer += linefeed;
|
||||
emitted.buffer += format_source_mapping_url(source_map_file);
|
||||
}
|
||||
}
|
||||
// create a copy of the resulting buffer string
|
||||
// this must be freed or taken over by implementor
|
||||
return sass_copy_c_string(emitted.buffer.c_str());
|
||||
}
|
||||
|
||||
void Context::apply_custom_headers(Block* root, const char* ctx_path, ParserState pstate)
|
||||
{
|
||||
// create a custom import to resolve headers
|
||||
Import* imp = SASS_MEMORY_NEW(mem, Import, pstate);
|
||||
// dispatch headers which will add custom functions
|
||||
// custom headers are added to the import instance
|
||||
call_headers(entry_path, ctx_path, pstate, imp);
|
||||
// increase head count to skip later
|
||||
head_imports += resources.size() - 1;
|
||||
// add the statement if we have urls
|
||||
if (!imp->urls().empty()) (*root) << imp;
|
||||
// process all other resources (add Import_Stub nodes)
|
||||
for (size_t i = 0, S = imp->incs().size(); i < S; ++i) {
|
||||
(*root) << SASS_MEMORY_NEW(mem, Import_Stub, pstate, imp->incs()[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Block* File_Context::parse()
|
||||
{
|
||||
|
||||
// check if entry file is given
|
||||
if (input_path.empty()) return 0;
|
||||
|
||||
// create absolute path from input filename
|
||||
// ToDo: this should be resolved via custom importers
|
||||
std::string abs_path(rel2abs(input_path, CWD));
|
||||
|
||||
// try to load the entry file
|
||||
char* contents = read_file(abs_path);
|
||||
|
||||
// alternatively also look inside each include path folder
|
||||
// I think this differs from ruby sass (IMO too late to remove)
|
||||
for (size_t i = 0, S = include_paths.size(); contents == 0 && i < S; ++i) {
|
||||
// build absolute path for this include path entry
|
||||
abs_path = rel2abs(input_path, include_paths[i]);
|
||||
// try to load the resulting path
|
||||
contents = read_file(abs_path);
|
||||
}
|
||||
|
||||
// abort early if no content could be loaded (various reasons)
|
||||
if (!contents) throw "File to read not found or unreadable: " + input_path;
|
||||
|
||||
// store entry path
|
||||
entry_path = abs_path;
|
||||
|
||||
// create entry only for import stack
|
||||
Sass_Import_Entry import = sass_make_import(
|
||||
input_path.c_str(),
|
||||
entry_path.c_str(),
|
||||
contents,
|
||||
0
|
||||
);
|
||||
// add the entry to the stack
|
||||
import_stack.push_back(import);
|
||||
|
||||
// create the source entry for file entry
|
||||
register_resource({{ input_path, "." }, abs_path }, { contents, 0 });
|
||||
|
||||
// create root ast tree node
|
||||
return compile();
|
||||
|
||||
}
|
||||
|
||||
Block* Data_Context::parse()
|
||||
{
|
||||
|
||||
// check if source string is given
|
||||
if (!source_c_str) return 0;
|
||||
|
||||
// convert indented sass syntax
|
||||
if(c_options.is_indented_syntax_src) {
|
||||
// call sass2scss to convert the string
|
||||
char * converted = sass2scss(source_c_str,
|
||||
// preserve the structure as much as possible
|
||||
SASS2SCSS_PRETTIFY_1 | SASS2SCSS_KEEP_COMMENT);
|
||||
// replace old source_c_str with converted
|
||||
free(source_c_str); source_c_str = converted;
|
||||
}
|
||||
|
||||
// remember entry path (defaults to stdin for string)
|
||||
entry_path = input_path.empty() ? "stdin" : input_path;
|
||||
|
||||
// ToDo: this may be resolved via custom importers
|
||||
std::string abs_path(rel2abs(entry_path));
|
||||
char* abs_path_c_str = sass_copy_c_string(abs_path.c_str());
|
||||
strings.push_back(abs_path_c_str);
|
||||
|
||||
// create entry only for the import stack
|
||||
Sass_Import_Entry import = sass_make_import(
|
||||
entry_path.c_str(),
|
||||
abs_path_c_str,
|
||||
source_c_str,
|
||||
srcmap_c_str
|
||||
);
|
||||
// add the entry to the stack
|
||||
import_stack.push_back(import);
|
||||
|
||||
// register a synthetic resource (path does not really exist, skip in includes)
|
||||
register_resource({{ input_path, "." }, input_path }, { source_c_str, srcmap_c_str });
|
||||
|
||||
// create root ast tree node
|
||||
return compile();
|
||||
}
|
||||
|
||||
|
||||
|
||||
// parse root block from includes
|
||||
Block* Context::compile()
|
||||
{
|
||||
// abort if there is no data
|
||||
if (resources.size() == 0) return 0;
|
||||
// get root block from the first style sheet
|
||||
Block* root = sheets.at(entry_path).root;
|
||||
// abort on invalid root
|
||||
if (root == 0) return 0;
|
||||
|
||||
Env global; // create root environment
|
||||
// register built-in functions on env
|
||||
register_built_in_functions(*this, &global);
|
||||
// register custom functions (defined via C-API)
|
||||
for (size_t i = 0, S = c_functions.size(); i < S; ++i)
|
||||
{ register_c_function(*this, &global, c_functions[i]); }
|
||||
// create initial backtrace entry
|
||||
Backtrace backtrace(0, ParserState("", 0), "");
|
||||
// create crtp visitor objects
|
||||
Expand expand(*this, &global, &backtrace);
|
||||
Cssize cssize(*this, &backtrace);
|
||||
// expand and eval the tree
|
||||
root = root->perform(&expand)->block();
|
||||
// merge and bubble certain rules
|
||||
root = root->perform(&cssize)->block();
|
||||
// should we extend something?
|
||||
if (!subset_map.empty()) {
|
||||
// create crtp visitor object
|
||||
Extend extend(*this, subset_map);
|
||||
// extend tree nodes
|
||||
root->perform(&extend);
|
||||
}
|
||||
|
||||
// clean up by removing empty placeholders
|
||||
// ToDo: maybe we can do this somewhere else?
|
||||
Remove_Placeholders remove_placeholders(*this);
|
||||
root->perform(&remove_placeholders);
|
||||
// return processed tree
|
||||
return root;
|
||||
}
|
||||
// EO compile
|
||||
|
||||
std::string Context::format_embedded_source_map()
|
||||
{
|
||||
std::string map = emitter.render_srcmap(*this);
|
||||
std::istringstream is( map );
|
||||
std::ostringstream buffer;
|
||||
base64::encoder E;
|
||||
E.encode(is, buffer);
|
||||
std::string url = "data:application/json;base64," + buffer.str();
|
||||
url.erase(url.size() - 1);
|
||||
return "/*# sourceMappingURL=" + url + " */";
|
||||
}
|
||||
|
||||
std::string Context::format_source_mapping_url(const std::string& file)
|
||||
{
|
||||
std::string url = abs2rel(file, output_path, CWD);
|
||||
return "/*# sourceMappingURL=" + url + " */";
|
||||
}
|
||||
|
||||
char* Context::render_srcmap()
|
||||
{
|
||||
if (source_map_file == "") return 0;
|
||||
char* result = 0;
|
||||
std::string map = emitter.render_srcmap(*this);
|
||||
result = sass_copy_c_string(map.c_str());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// for data context we want to start after "stdin"
|
||||
// we probably always want to skip the header includes?
|
||||
std::vector<std::string> Context::get_included_files(bool skip, size_t headers)
|
||||
{
|
||||
// create a copy of the vector for manipulations
|
||||
std::vector<std::string> includes = included_files;
|
||||
if (includes.size() == 0) return includes;
|
||||
if (skip) { includes.erase( includes.begin(), includes.begin() + 1 + headers); }
|
||||
else { includes.erase( includes.begin() + 1, includes.begin() + 1 + headers); }
|
||||
includes.erase( std::unique( includes.begin(), includes.end() ), includes.end() );
|
||||
std::sort( includes.begin() + (skip ? 0 : 1), includes.end() );
|
||||
return includes;
|
||||
}
|
||||
|
||||
void register_function(Context& ctx, Signature sig, Native_Function f, Env* env)
|
||||
{
|
||||
Definition* def = make_native_function(sig, f, ctx);
|
||||
def->environment(env);
|
||||
(*env)[def->name() + "[f]"] = def;
|
||||
}
|
||||
|
||||
void register_function(Context& ctx, Signature sig, Native_Function f, size_t arity, Env* env)
|
||||
{
|
||||
Definition* def = make_native_function(sig, f, ctx);
|
||||
std::stringstream ss;
|
||||
ss << def->name() << "[f]" << arity;
|
||||
def->environment(env);
|
||||
(*env)[ss.str()] = def;
|
||||
}
|
||||
|
||||
void register_overload_stub(Context& ctx, std::string name, Env* env)
|
||||
{
|
||||
Definition* stub = SASS_MEMORY_NEW(ctx.mem, Definition,
|
||||
ParserState("[built-in function]"),
|
||||
0,
|
||||
name,
|
||||
0,
|
||||
0,
|
||||
true);
|
||||
(*env)[name + "[f]"] = stub;
|
||||
}
|
||||
|
||||
|
||||
void register_built_in_functions(Context& ctx, Env* env)
|
||||
{
|
||||
using namespace Functions;
|
||||
// RGB Functions
|
||||
register_function(ctx, rgb_sig, rgb, env);
|
||||
register_overload_stub(ctx, "rgba", env);
|
||||
register_function(ctx, rgba_4_sig, rgba_4, 4, env);
|
||||
register_function(ctx, rgba_2_sig, rgba_2, 2, env);
|
||||
register_function(ctx, red_sig, red, env);
|
||||
register_function(ctx, green_sig, green, env);
|
||||
register_function(ctx, blue_sig, blue, env);
|
||||
register_function(ctx, mix_sig, mix, env);
|
||||
// HSL Functions
|
||||
register_function(ctx, hsl_sig, hsl, env);
|
||||
register_function(ctx, hsla_sig, hsla, env);
|
||||
register_function(ctx, hue_sig, hue, env);
|
||||
register_function(ctx, saturation_sig, saturation, env);
|
||||
register_function(ctx, lightness_sig, lightness, env);
|
||||
register_function(ctx, adjust_hue_sig, adjust_hue, env);
|
||||
register_function(ctx, lighten_sig, lighten, env);
|
||||
register_function(ctx, darken_sig, darken, env);
|
||||
register_function(ctx, saturate_sig, saturate, env);
|
||||
register_function(ctx, desaturate_sig, desaturate, env);
|
||||
register_function(ctx, grayscale_sig, grayscale, env);
|
||||
register_function(ctx, complement_sig, complement, env);
|
||||
register_function(ctx, invert_sig, invert, env);
|
||||
// Opacity Functions
|
||||
register_function(ctx, alpha_sig, alpha, env);
|
||||
register_function(ctx, opacity_sig, alpha, env);
|
||||
register_function(ctx, opacify_sig, opacify, env);
|
||||
register_function(ctx, fade_in_sig, opacify, env);
|
||||
register_function(ctx, transparentize_sig, transparentize, env);
|
||||
register_function(ctx, fade_out_sig, transparentize, env);
|
||||
// Other Color Functions
|
||||
register_function(ctx, adjust_color_sig, adjust_color, env);
|
||||
register_function(ctx, scale_color_sig, scale_color, env);
|
||||
register_function(ctx, change_color_sig, change_color, env);
|
||||
register_function(ctx, ie_hex_str_sig, ie_hex_str, env);
|
||||
// String Functions
|
||||
register_function(ctx, unquote_sig, sass_unquote, env);
|
||||
register_function(ctx, quote_sig, sass_quote, env);
|
||||
register_function(ctx, str_length_sig, str_length, env);
|
||||
register_function(ctx, str_insert_sig, str_insert, env);
|
||||
register_function(ctx, str_index_sig, str_index, env);
|
||||
register_function(ctx, str_slice_sig, str_slice, env);
|
||||
register_function(ctx, to_upper_case_sig, to_upper_case, env);
|
||||
register_function(ctx, to_lower_case_sig, to_lower_case, env);
|
||||
// Number Functions
|
||||
register_function(ctx, percentage_sig, percentage, env);
|
||||
register_function(ctx, round_sig, round, env);
|
||||
register_function(ctx, ceil_sig, ceil, env);
|
||||
register_function(ctx, floor_sig, floor, env);
|
||||
register_function(ctx, abs_sig, abs, env);
|
||||
register_function(ctx, min_sig, min, env);
|
||||
register_function(ctx, max_sig, max, env);
|
||||
register_function(ctx, random_sig, random, env);
|
||||
// List Functions
|
||||
register_function(ctx, length_sig, length, env);
|
||||
register_function(ctx, nth_sig, nth, env);
|
||||
register_function(ctx, set_nth_sig, set_nth, env);
|
||||
register_function(ctx, index_sig, index, env);
|
||||
register_function(ctx, join_sig, join, env);
|
||||
register_function(ctx, append_sig, append, env);
|
||||
register_function(ctx, zip_sig, zip, env);
|
||||
register_function(ctx, list_separator_sig, list_separator, env);
|
||||
// Map Functions
|
||||
register_function(ctx, map_get_sig, map_get, env);
|
||||
register_function(ctx, map_merge_sig, map_merge, env);
|
||||
register_function(ctx, map_remove_sig, map_remove, env);
|
||||
register_function(ctx, map_keys_sig, map_keys, env);
|
||||
register_function(ctx, map_values_sig, map_values, env);
|
||||
register_function(ctx, map_has_key_sig, map_has_key, env);
|
||||
register_function(ctx, keywords_sig, keywords, env);
|
||||
// Introspection Functions
|
||||
register_function(ctx, type_of_sig, type_of, env);
|
||||
register_function(ctx, unit_sig, unit, env);
|
||||
register_function(ctx, unitless_sig, unitless, env);
|
||||
register_function(ctx, comparable_sig, comparable, env);
|
||||
register_function(ctx, variable_exists_sig, variable_exists, env);
|
||||
register_function(ctx, global_variable_exists_sig, global_variable_exists, env);
|
||||
register_function(ctx, function_exists_sig, function_exists, env);
|
||||
register_function(ctx, mixin_exists_sig, mixin_exists, env);
|
||||
register_function(ctx, feature_exists_sig, feature_exists, env);
|
||||
register_function(ctx, call_sig, call, env);
|
||||
// Boolean Functions
|
||||
register_function(ctx, not_sig, sass_not, env);
|
||||
register_function(ctx, if_sig, sass_if, env);
|
||||
// Misc Functions
|
||||
register_function(ctx, inspect_sig, inspect, env);
|
||||
register_function(ctx, unique_id_sig, unique_id, env);
|
||||
// Selector functions
|
||||
register_function(ctx, selector_nest_sig, selector_nest, env);
|
||||
register_function(ctx, selector_append_sig, selector_append, env);
|
||||
register_function(ctx, selector_extend_sig, selector_extend, env);
|
||||
register_function(ctx, selector_replace_sig, selector_replace, env);
|
||||
register_function(ctx, selector_unify_sig, selector_unify, env);
|
||||
register_function(ctx, is_superselector_sig, is_superselector, env);
|
||||
register_function(ctx, simple_selectors_sig, simple_selectors, env);
|
||||
register_function(ctx, selector_parse_sig, selector_parse, env);
|
||||
}
|
||||
|
||||
void register_c_functions(Context& ctx, Env* env, Sass_Function_List descrs)
|
||||
{
|
||||
while (descrs && *descrs) {
|
||||
register_c_function(ctx, env, *descrs);
|
||||
++descrs;
|
||||
}
|
||||
}
|
||||
void register_c_function(Context& ctx, Env* env, Sass_Function_Entry descr)
|
||||
{
|
||||
Definition* def = make_c_function(descr, ctx);
|
||||
def->environment(env);
|
||||
(*env)[def->name() + "[f]"] = def;
|
||||
}
|
||||
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
#ifndef SASS_CONTEXT_H
|
||||
#define SASS_CONTEXT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#define BUFFERSIZE 255
|
||||
#include "b64/encode.h"
|
||||
|
||||
#include "ast_fwd_decl.hpp"
|
||||
#include "kwd_arg_macros.hpp"
|
||||
#include "memory_manager.hpp"
|
||||
#include "ast_fwd_decl.hpp"
|
||||
#include "sass_context.hpp"
|
||||
#include "environment.hpp"
|
||||
#include "source_map.hpp"
|
||||
#include "subset_map.hpp"
|
||||
#include "output.hpp"
|
||||
#include "plugins.hpp"
|
||||
#include "file.hpp"
|
||||
|
||||
|
||||
struct Sass_Function;
|
||||
|
||||
namespace Sass {
|
||||
|
||||
class Context {
|
||||
public:
|
||||
void import_url (Import* imp, std::string load_path, const std::string& ctx_path);
|
||||
bool call_headers(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp)
|
||||
{ return call_loader(load_path, ctx_path, pstate, imp, c_headers, false); };
|
||||
bool call_importers(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp)
|
||||
{ return call_loader(load_path, ctx_path, pstate, imp, c_importers, true); };
|
||||
|
||||
private:
|
||||
bool call_loader(const std::string& load_path, const char* ctx_path, ParserState& pstate, Import* imp, std::vector<Sass_Importer_Entry> importers, bool only_one = true);
|
||||
|
||||
public:
|
||||
const std::string CWD;
|
||||
struct Sass_Options& c_options;
|
||||
std::string entry_path;
|
||||
size_t head_imports;
|
||||
Memory_Manager mem;
|
||||
Plugins plugins;
|
||||
Output emitter;
|
||||
|
||||
// resources add under our control
|
||||
// these are guaranteed to be freed
|
||||
std::vector<char*> strings;
|
||||
std::vector<Resource> resources;
|
||||
std::map<const std::string, const StyleSheet> sheets;
|
||||
Subset_Map<std::string, std::pair<Complex_Selector*, Compound_Selector*> > subset_map;
|
||||
std::vector<Sass_Import_Entry> import_stack;
|
||||
|
||||
struct Sass_Compiler* c_compiler;
|
||||
|
||||
// absolute paths to includes
|
||||
std::vector<std::string> included_files;
|
||||
// relative includes for sourcemap
|
||||
std::vector<std::string> srcmap_links;
|
||||
// vectors above have same size
|
||||
|
||||
std::vector<std::string> plugin_paths; // relative paths to load plugins
|
||||
std::vector<std::string> include_paths; // lookup paths for includes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void apply_custom_headers(Block* root, const char* path, ParserState pstate);
|
||||
|
||||
std::vector<Sass_Importer_Entry> c_headers;
|
||||
std::vector<Sass_Importer_Entry> c_importers;
|
||||
std::vector<Sass_Function_Entry> c_functions;
|
||||
|
||||
void add_c_header(Sass_Importer_Entry header);
|
||||
void add_c_importer(Sass_Importer_Entry importer);
|
||||
void add_c_function(Sass_Function_Entry function);
|
||||
|
||||
const std::string indent; // String to be used for indentation
|
||||
const std::string linefeed; // String to be used for line feeds
|
||||
const std::string input_path; // for relative paths in src-map
|
||||
const std::string output_path; // for relative paths to the output
|
||||
const std::string source_map_file; // path to source map file (enables feature)
|
||||
const std::string source_map_root; // path for sourceRoot property (pass-through)
|
||||
|
||||
virtual ~Context();
|
||||
Context(struct Sass_Context&);
|
||||
virtual Block* parse() = 0;
|
||||
virtual Block* compile();
|
||||
virtual char* render(Block* root);
|
||||
virtual char* render_srcmap();
|
||||
|
||||
void register_resource(const Include&, const Resource&, ParserState* = 0);
|
||||
std::vector<Include> find_includes(const Importer& import);
|
||||
Include load_import(const Importer&, ParserState pstate);
|
||||
|
||||
Sass_Output_Style output_style() { return c_options.output_style; };
|
||||
std::vector<std::string> get_included_files(bool skip = false, size_t headers = 0);
|
||||
|
||||
private:
|
||||
void collect_plugin_paths(const char* paths_str);
|
||||
void collect_plugin_paths(string_list* paths_array);
|
||||
void collect_include_paths(const char* paths_str);
|
||||
void collect_include_paths(string_list* paths_array);
|
||||
std::string format_embedded_source_map();
|
||||
std::string format_source_mapping_url(const std::string& out_path);
|
||||
|
||||
|
||||
// void register_built_in_functions(Env* env);
|
||||
// void register_function(Signature sig, Native_Function f, Env* env);
|
||||
// void register_function(Signature sig, Native_Function f, size_t arity, Env* env);
|
||||
// void register_overload_stub(std::string name, Env* env);
|
||||
|
||||
public:
|
||||
const std::string& cwd() { return CWD; };
|
||||
};
|
||||
|
||||
class File_Context : public Context {
|
||||
public:
|
||||
File_Context(struct Sass_File_Context& ctx)
|
||||
: Context(ctx)
|
||||
{ }
|
||||
virtual ~File_Context();
|
||||
virtual Block* parse();
|
||||
};
|
||||
|
||||
class Data_Context : public Context {
|
||||
public:
|
||||
char* source_c_str;
|
||||
char* srcmap_c_str;
|
||||
Data_Context(struct Sass_Data_Context& ctx)
|
||||
: Context(ctx)
|
||||
{
|
||||
source_c_str = ctx.source_string;
|
||||
srcmap_c_str = ctx.srcmap_string;
|
||||
ctx.source_string = 0; // passed away
|
||||
ctx.srcmap_string = 0; // passed away
|
||||
}
|
||||
virtual ~Data_Context();
|
||||
virtual Block* parse();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user