702 lines
24 KiB
C
702 lines
24 KiB
C
|
#include <Python.h>
|
||
|
#include <sass/context.h>
|
||
|
|
||
|
#if PY_MAJOR_VERSION >= 3
|
||
|
#define PySass_IF_PY3(three, two) (three)
|
||
|
#define PySass_Object_Bytes(o) PyUnicode_AsUTF8String(PyObject_Str(o))
|
||
|
#define COLLECTIONS_ABC_MOD "collections.abc"
|
||
|
#else
|
||
|
#define PySass_IF_PY3(three, two) (two)
|
||
|
#define PySass_Object_Bytes(o) PyObject_Str(o)
|
||
|
#define COLLECTIONS_ABC_MOD "collections"
|
||
|
#endif
|
||
|
|
||
|
static PyObject* _to_py_value(const union Sass_Value* value);
|
||
|
static union Sass_Value* _to_sass_value(PyObject* value);
|
||
|
|
||
|
static union Sass_Value* _color_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _number_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _list_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _mapping_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _unicode_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _warning_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _error_to_sass_value(PyObject* value);
|
||
|
static union Sass_Value* _unknown_type_to_sass_error(PyObject* value);
|
||
|
static union Sass_Value* _exception_to_sass_error();
|
||
|
|
||
|
|
||
|
static PyObject* _to_py_value(const union Sass_Value* value) {
|
||
|
PyObject* retv = NULL;
|
||
|
PyObject* types_mod = PyImport_ImportModule("sass");
|
||
|
PyObject* sass_comma = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_COMMA");
|
||
|
PyObject* sass_space = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_SPACE");
|
||
|
|
||
|
switch (sass_value_get_tag(value)) {
|
||
|
case SASS_NULL:
|
||
|
retv = Py_None;
|
||
|
Py_INCREF(retv);
|
||
|
break;
|
||
|
case SASS_BOOLEAN:
|
||
|
retv = PyBool_FromLong(sass_boolean_get_value(value));
|
||
|
break;
|
||
|
case SASS_STRING:
|
||
|
retv = PyUnicode_FromString(sass_string_get_value(value));
|
||
|
break;
|
||
|
case SASS_NUMBER:
|
||
|
retv = PyObject_CallMethod(
|
||
|
types_mod,
|
||
|
"SassNumber",
|
||
|
PySass_IF_PY3("dy", "ds"),
|
||
|
sass_number_get_value(value),
|
||
|
sass_number_get_unit(value)
|
||
|
);
|
||
|
break;
|
||
|
case SASS_COLOR:
|
||
|
retv = PyObject_CallMethod(
|
||
|
types_mod,
|
||
|
"SassColor",
|
||
|
"dddd",
|
||
|
sass_color_get_r(value),
|
||
|
sass_color_get_g(value),
|
||
|
sass_color_get_b(value),
|
||
|
sass_color_get_a(value)
|
||
|
);
|
||
|
break;
|
||
|
case SASS_LIST: {
|
||
|
size_t i = 0;
|
||
|
PyObject* items = PyTuple_New(sass_list_get_length(value));
|
||
|
PyObject* separator = sass_comma;
|
||
|
int is_bracketed = sass_list_get_is_bracketed(value);
|
||
|
PyObject* bracketed = PyBool_FromLong(is_bracketed);
|
||
|
switch (sass_list_get_separator(value)) {
|
||
|
case SASS_COMMA:
|
||
|
separator = sass_comma;
|
||
|
break;
|
||
|
case SASS_SPACE:
|
||
|
separator = sass_space;
|
||
|
break;
|
||
|
case SASS_HASH:
|
||
|
assert(0);
|
||
|
break;
|
||
|
}
|
||
|
for (i = 0; i < sass_list_get_length(value); i += 1) {
|
||
|
PyTuple_SetItem(
|
||
|
items,
|
||
|
i,
|
||
|
_to_py_value(sass_list_get_value(value, i))
|
||
|
);
|
||
|
}
|
||
|
retv = PyObject_CallMethod(
|
||
|
types_mod, "SassList", "OOO", items, separator, bracketed
|
||
|
);
|
||
|
break;
|
||
|
}
|
||
|
case SASS_MAP: {
|
||
|
size_t i = 0;
|
||
|
PyObject* items = PyTuple_New(sass_map_get_length(value));
|
||
|
for (i = 0; i < sass_map_get_length(value); i += 1) {
|
||
|
PyObject* kvp = PyTuple_New(2);
|
||
|
PyTuple_SetItem(
|
||
|
kvp, 0, _to_py_value(sass_map_get_key(value, i))
|
||
|
);
|
||
|
PyTuple_SetItem(
|
||
|
kvp, 1, _to_py_value(sass_map_get_value(value, i))
|
||
|
);
|
||
|
PyTuple_SetItem(items, i, kvp);
|
||
|
}
|
||
|
retv = PyObject_CallMethod(types_mod, "SassMap", "(O)", items);
|
||
|
Py_DECREF(items);
|
||
|
break;
|
||
|
}
|
||
|
case SASS_ERROR:
|
||
|
case SASS_WARNING:
|
||
|
/* @warning and @error cannot be passed */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (retv == NULL) {
|
||
|
PyErr_SetString(PyExc_TypeError, "Unexpected sass type");
|
||
|
}
|
||
|
|
||
|
Py_DECREF(types_mod);
|
||
|
Py_DECREF(sass_comma);
|
||
|
Py_DECREF(sass_space);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _color_to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* r_value = PyObject_GetAttrString(value, "r");
|
||
|
PyObject* g_value = PyObject_GetAttrString(value, "g");
|
||
|
PyObject* b_value = PyObject_GetAttrString(value, "b");
|
||
|
PyObject* a_value = PyObject_GetAttrString(value, "a");
|
||
|
retv = sass_make_color(
|
||
|
PyFloat_AsDouble(r_value),
|
||
|
PyFloat_AsDouble(g_value),
|
||
|
PyFloat_AsDouble(b_value),
|
||
|
PyFloat_AsDouble(a_value)
|
||
|
);
|
||
|
Py_DECREF(r_value);
|
||
|
Py_DECREF(g_value);
|
||
|
Py_DECREF(b_value);
|
||
|
Py_DECREF(a_value);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _list_to_sass_value(PyObject* value) {
|
||
|
PyObject* types_mod = PyImport_ImportModule("sass");
|
||
|
PyObject* sass_comma = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_COMMA");
|
||
|
PyObject* sass_space = PyObject_GetAttrString(types_mod, "SASS_SEPARATOR_SPACE");
|
||
|
union Sass_Value* retv = NULL;
|
||
|
Py_ssize_t i = 0;
|
||
|
PyObject* items = PyObject_GetAttrString(value, "items");
|
||
|
PyObject* separator = PyObject_GetAttrString(value, "separator");
|
||
|
PyObject* bracketed = PyObject_GetAttrString(value, "bracketed");
|
||
|
enum Sass_Separator sep = SASS_COMMA;
|
||
|
if (separator == sass_comma) {
|
||
|
sep = SASS_COMMA;
|
||
|
} else if (separator == sass_space) {
|
||
|
sep = SASS_SPACE;
|
||
|
} else {
|
||
|
assert(0);
|
||
|
}
|
||
|
int is_bracketed = bracketed == Py_True;
|
||
|
retv = sass_make_list(PyTuple_Size(items), sep, is_bracketed);
|
||
|
for (i = 0; i < PyTuple_Size(items); i += 1) {
|
||
|
sass_list_set_value(
|
||
|
retv, i, _to_sass_value(PyTuple_GetItem(items, i))
|
||
|
);
|
||
|
}
|
||
|
Py_DECREF(types_mod);
|
||
|
Py_DECREF(sass_comma);
|
||
|
Py_DECREF(sass_space);
|
||
|
Py_DECREF(items);
|
||
|
Py_DECREF(separator);
|
||
|
Py_DECREF(bracketed);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _mapping_to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
size_t i = 0;
|
||
|
Py_ssize_t pos = 0;
|
||
|
PyObject* d_key = NULL;
|
||
|
PyObject* d_value = NULL;
|
||
|
PyObject* dct = PyDict_New();
|
||
|
PyDict_Update(dct, value);
|
||
|
retv = sass_make_map(PyDict_Size(dct));
|
||
|
while (PyDict_Next(dct, &pos, &d_key, &d_value)) {
|
||
|
sass_map_set_key(retv, i, _to_sass_value(d_key));
|
||
|
sass_map_set_value(retv, i, _to_sass_value(d_value));
|
||
|
i += 1;
|
||
|
}
|
||
|
Py_DECREF(dct);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _number_to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* d_value = PyObject_GetAttrString(value, "value");
|
||
|
PyObject* unit = PyObject_GetAttrString(value, "unit");
|
||
|
PyObject* bytes = PyUnicode_AsEncodedString(unit, "UTF-8", "strict");
|
||
|
retv = sass_make_number(
|
||
|
PyFloat_AsDouble(d_value), PyBytes_AsString(bytes)
|
||
|
);
|
||
|
Py_DECREF(d_value);
|
||
|
Py_DECREF(unit);
|
||
|
Py_DECREF(bytes);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _unicode_to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* bytes = PyUnicode_AsEncodedString(value, "UTF-8", "strict");
|
||
|
retv = sass_make_string(PyBytes_AsString(bytes));
|
||
|
Py_DECREF(bytes);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _warning_to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* msg = PyObject_GetAttrString(value, "msg");
|
||
|
PyObject* bytes = PyUnicode_AsEncodedString(msg, "UTF-8", "strict");
|
||
|
retv = sass_make_warning(PyBytes_AsString(bytes));
|
||
|
Py_DECREF(msg);
|
||
|
Py_DECREF(bytes);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _error_to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* msg = PyObject_GetAttrString(value, "msg");
|
||
|
PyObject* bytes = PyUnicode_AsEncodedString(msg, "UTF-8", "strict");
|
||
|
retv = sass_make_error(PyBytes_AsString(bytes));
|
||
|
Py_DECREF(msg);
|
||
|
Py_DECREF(bytes);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _unknown_type_to_sass_error(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* type = PyObject_Type(value);
|
||
|
PyObject* type_name = PyObject_GetAttrString(type, "__name__");
|
||
|
PyObject* fmt = PyUnicode_FromString(
|
||
|
"Unexpected type: `{0}`.\n"
|
||
|
"Expected one of:\n"
|
||
|
"- None\n"
|
||
|
"- bool\n"
|
||
|
"- str\n"
|
||
|
"- SassNumber\n"
|
||
|
"- SassColor\n"
|
||
|
"- SassList\n"
|
||
|
"- dict\n"
|
||
|
"- SassMap\n"
|
||
|
"- SassWarning\n"
|
||
|
"- SassError\n"
|
||
|
);
|
||
|
PyObject* format_meth = PyObject_GetAttrString(fmt, "format");
|
||
|
PyObject* result = PyObject_CallFunctionObjArgs(
|
||
|
format_meth, type_name, NULL
|
||
|
);
|
||
|
PyObject* bytes = PyUnicode_AsEncodedString(result, "UTF-8", "strict");
|
||
|
retv = sass_make_error(PyBytes_AsString(bytes));
|
||
|
Py_DECREF(type);
|
||
|
Py_DECREF(type_name);
|
||
|
Py_DECREF(fmt);
|
||
|
Py_DECREF(format_meth);
|
||
|
Py_DECREF(result);
|
||
|
Py_DECREF(bytes);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static PyObject* _exception_to_bytes() {
|
||
|
PyObject* retv = NULL;
|
||
|
PyObject* etype = NULL;
|
||
|
PyObject* evalue = NULL;
|
||
|
PyObject* etb = NULL;
|
||
|
PyErr_Fetch(&etype, &evalue, &etb);
|
||
|
PyErr_NormalizeException(&etype, &evalue, &etb);
|
||
|
{
|
||
|
PyObject* traceback_mod = PyImport_ImportModule("traceback");
|
||
|
PyObject* traceback_parts = PyObject_CallMethod(
|
||
|
traceback_mod, "format_exception", "OOO", etype, evalue, etb
|
||
|
);
|
||
|
PyList_Insert(traceback_parts, 0, PyUnicode_FromString("\n"));
|
||
|
PyObject* joinstr = PyUnicode_FromString("");
|
||
|
PyObject* result = PyUnicode_Join(joinstr, traceback_parts);
|
||
|
retv = PyUnicode_AsEncodedString(result, "UTF-8", "strict");
|
||
|
Py_DECREF(traceback_mod);
|
||
|
Py_DECREF(traceback_parts);
|
||
|
Py_DECREF(joinstr);
|
||
|
Py_DECREF(result);
|
||
|
}
|
||
|
Py_DECREF(etype);
|
||
|
Py_DECREF(evalue);
|
||
|
Py_DECREF(etb);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _exception_to_sass_error() {
|
||
|
PyObject* bytes = _exception_to_bytes();
|
||
|
union Sass_Value* retv = sass_make_error(PyBytes_AsString(bytes));
|
||
|
Py_DECREF(bytes);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static Sass_Import_List _exception_to_sass_import_error(const char* path) {
|
||
|
PyObject* bytes = _exception_to_bytes();
|
||
|
Sass_Import_List import_list = sass_make_import_list(1);
|
||
|
import_list[0] = sass_make_import_entry(path, 0, 0);
|
||
|
sass_import_set_error(import_list[0], PyBytes_AsString(bytes), 0, 0);
|
||
|
Py_DECREF(bytes);
|
||
|
return import_list;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _to_sass_value(PyObject* value) {
|
||
|
union Sass_Value* retv = NULL;
|
||
|
PyObject* types_mod = PyImport_ImportModule("sass");
|
||
|
PyObject* sass_number_t = PyObject_GetAttrString(types_mod, "SassNumber");
|
||
|
PyObject* sass_color_t = PyObject_GetAttrString(types_mod, "SassColor");
|
||
|
PyObject* sass_list_t = PyObject_GetAttrString(types_mod, "SassList");
|
||
|
PyObject* sass_warning_t = PyObject_GetAttrString(types_mod, "SassWarning");
|
||
|
PyObject* sass_error_t = PyObject_GetAttrString(types_mod, "SassError");
|
||
|
PyObject* collections_mod = PyImport_ImportModule(COLLECTIONS_ABC_MOD);
|
||
|
PyObject* mapping_t = PyObject_GetAttrString(collections_mod, "Mapping");
|
||
|
|
||
|
if (value == Py_None) {
|
||
|
retv = sass_make_null();
|
||
|
} else if (PyBool_Check(value)) {
|
||
|
retv = sass_make_boolean(value == Py_True);
|
||
|
} else if (PyUnicode_Check(value)) {
|
||
|
retv = _unicode_to_sass_value(value);
|
||
|
} else if (PyBytes_Check(value)) {
|
||
|
retv = sass_make_string(PyBytes_AsString(value));
|
||
|
/* XXX: PyMapping_Check returns true for lists and tuples in python3 :( */
|
||
|
/* XXX: pypy derps on dicts: https://bitbucket.org/pypy/pypy/issue/1970 */
|
||
|
} else if (PyDict_Check(value) || PyObject_IsInstance(value, mapping_t)) {
|
||
|
retv = _mapping_to_sass_value(value);
|
||
|
} else if (PyObject_IsInstance(value, sass_number_t)) {
|
||
|
retv = _number_to_sass_value(value);
|
||
|
} else if (PyObject_IsInstance(value, sass_color_t)) {
|
||
|
retv = _color_to_sass_value(value);
|
||
|
} else if (PyObject_IsInstance(value, sass_list_t)) {
|
||
|
retv = _list_to_sass_value(value);
|
||
|
} else if (PyObject_IsInstance(value, sass_warning_t)) {
|
||
|
retv = _warning_to_sass_value(value);
|
||
|
} else if (PyObject_IsInstance(value, sass_error_t)) {
|
||
|
retv = _error_to_sass_value(value);
|
||
|
}
|
||
|
|
||
|
if (retv == NULL) {
|
||
|
retv = _unknown_type_to_sass_error(value);
|
||
|
}
|
||
|
|
||
|
Py_DECREF(types_mod);
|
||
|
Py_DECREF(sass_number_t);
|
||
|
Py_DECREF(sass_color_t);
|
||
|
Py_DECREF(sass_list_t);
|
||
|
Py_DECREF(sass_warning_t);
|
||
|
Py_DECREF(sass_error_t);
|
||
|
Py_DECREF(collections_mod);
|
||
|
Py_DECREF(mapping_t);
|
||
|
return retv;
|
||
|
}
|
||
|
|
||
|
static union Sass_Value* _call_py_f(
|
||
|
const union Sass_Value* sass_args,
|
||
|
Sass_Function_Entry cb,
|
||
|
struct Sass_Compiler* compiler
|
||
|
) {
|
||
|
size_t i;
|
||
|
PyObject* pyfunc = (PyObject*)sass_function_get_cookie(cb);
|
||
|
PyObject* py_args = PyTuple_New(sass_list_get_length(sass_args));
|
||
|
PyObject* py_result = NULL;
|
||
|
union Sass_Value* sass_result = NULL;
|
||
|
|
||
|
for (i = 0; i < sass_list_get_length(sass_args); i += 1) {
|
||
|
const union Sass_Value* sass_arg = sass_list_get_value(sass_args, i);
|
||
|
PyObject* py_arg = NULL;
|
||
|
if (!(py_arg = _to_py_value(sass_arg))) goto done;
|
||
|
PyTuple_SetItem(py_args, i, py_arg);
|
||
|
}
|
||
|
|
||
|
if (!(py_result = PyObject_CallObject(pyfunc, py_args))) goto done;
|
||
|
sass_result = _to_sass_value(py_result);
|
||
|
|
||
|
done:
|
||
|
if (sass_result == NULL) {
|
||
|
sass_result = _exception_to_sass_error();
|
||
|
}
|
||
|
Py_XDECREF(py_args);
|
||
|
Py_XDECREF(py_result);
|
||
|
return sass_result;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void _add_custom_functions(
|
||
|
struct Sass_Options* options, PyObject* custom_functions
|
||
|
) {
|
||
|
Py_ssize_t i;
|
||
|
Sass_Function_List fn_list = sass_make_function_list(
|
||
|
PyList_Size(custom_functions)
|
||
|
);
|
||
|
for (i = 0; i < PyList_Size(custom_functions); i += 1) {
|
||
|
PyObject* sass_function = PyList_GetItem(custom_functions, i);
|
||
|
PyObject* signature = PySass_Object_Bytes(sass_function);
|
||
|
Sass_Function_Entry fn = sass_make_function(
|
||
|
PyBytes_AsString(signature),
|
||
|
_call_py_f,
|
||
|
sass_function
|
||
|
);
|
||
|
sass_function_set_list_entry(fn_list, i, fn);
|
||
|
}
|
||
|
sass_option_set_c_functions(options, fn_list);
|
||
|
}
|
||
|
|
||
|
static Sass_Import_List _call_py_importer_f(
|
||
|
const char* path, Sass_Importer_Entry cb, struct Sass_Compiler* comp
|
||
|
) {
|
||
|
PyObject* pyfunc = (PyObject*)sass_importer_get_cookie(cb);
|
||
|
PyObject* py_result = NULL;
|
||
|
Sass_Import_List sass_imports = NULL;
|
||
|
struct Sass_Import* previous;
|
||
|
const char* prev_path;
|
||
|
Py_ssize_t i;
|
||
|
|
||
|
previous = sass_compiler_get_last_import(comp);
|
||
|
prev_path = sass_import_get_abs_path(previous);
|
||
|
|
||
|
py_result = PyObject_CallFunction(pyfunc, PySass_IF_PY3("yy", "ss"), path, prev_path);
|
||
|
|
||
|
/* Handle importer throwing an exception */
|
||
|
if (!py_result) goto done;
|
||
|
|
||
|
/* Could return None indicating it could not handle the import */
|
||
|
if (py_result == Py_None) {
|
||
|
Py_XDECREF(py_result);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* Otherwise, we know our importer is well formed (because we wrap it)
|
||
|
* The return value will be a tuple of 1, 2, or 3 tuples */
|
||
|
sass_imports = sass_make_import_list(PyTuple_Size(py_result));
|
||
|
for (i = 0; i < PyTuple_Size(py_result); i += 1) {
|
||
|
char* path_str = NULL; /* XXX: Memory leak? */
|
||
|
char* source_str = NULL;
|
||
|
char* sourcemap_str = NULL;
|
||
|
PyObject* tup = PyTuple_GetItem(py_result, i);
|
||
|
Py_ssize_t size = PyTuple_Size(tup);
|
||
|
|
||
|
if (size == 1) {
|
||
|
PyArg_ParseTuple(tup, PySass_IF_PY3("y", "s"), &path_str);
|
||
|
} else if (size == 2) {
|
||
|
PyArg_ParseTuple(
|
||
|
tup, PySass_IF_PY3("yy", "ss"), &path_str, &source_str
|
||
|
);
|
||
|
} else if (size == 3) {
|
||
|
PyArg_ParseTuple(
|
||
|
tup, PySass_IF_PY3("yyy", "sss"),
|
||
|
&path_str, &source_str, &sourcemap_str
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/* We need to give copies of these arguments; libsass handles
|
||
|
* deallocation of them later, whereas path_str is left flapping
|
||
|
* in the breeze -- it's treated const, so that's okay. */
|
||
|
if (source_str) source_str = sass_copy_c_string(source_str);
|
||
|
if (sourcemap_str) sourcemap_str = sass_copy_c_string(sourcemap_str);
|
||
|
|
||
|
sass_imports[i] = sass_make_import_entry(
|
||
|
path_str, source_str, sourcemap_str
|
||
|
);
|
||
|
}
|
||
|
|
||
|
done:
|
||
|
if (sass_imports == NULL) {
|
||
|
sass_imports = _exception_to_sass_import_error(path);
|
||
|
}
|
||
|
|
||
|
Py_XDECREF(py_result);
|
||
|
|
||
|
return sass_imports;
|
||
|
}
|
||
|
|
||
|
static void _add_custom_importers(
|
||
|
struct Sass_Options* options, PyObject* custom_importers
|
||
|
) {
|
||
|
Py_ssize_t i;
|
||
|
Sass_Importer_List importer_list;
|
||
|
|
||
|
if (custom_importers == Py_None) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
importer_list = sass_make_importer_list(PyTuple_Size(custom_importers));
|
||
|
|
||
|
for (i = 0; i < PyTuple_Size(custom_importers); i += 1) {
|
||
|
PyObject* item = PyTuple_GetItem(custom_importers, i);
|
||
|
int priority = 0;
|
||
|
PyObject* import_function = NULL;
|
||
|
|
||
|
PyArg_ParseTuple(item, "iO", &priority, &import_function);
|
||
|
|
||
|
importer_list[i] = sass_make_importer(
|
||
|
_call_py_importer_f, priority, import_function
|
||
|
);
|
||
|
}
|
||
|
|
||
|
sass_option_set_c_importers(options, importer_list);
|
||
|
}
|
||
|
|
||
|
static PyObject *
|
||
|
PySass_compile_string(PyObject *self, PyObject *args) {
|
||
|
struct Sass_Context *ctx;
|
||
|
struct Sass_Data_Context *context;
|
||
|
struct Sass_Options *options;
|
||
|
char *string, *include_paths;
|
||
|
const char *error_message, *output_string;
|
||
|
enum Sass_Output_Style output_style;
|
||
|
int source_comments, error_status, precision, indented,
|
||
|
source_map_embed, source_map_contents,
|
||
|
omit_source_map_url;
|
||
|
PyObject *custom_functions;
|
||
|
PyObject *custom_importers;
|
||
|
PyObject *source_map_root;
|
||
|
PyObject *result;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args,
|
||
|
PySass_IF_PY3("yiiyiOiOiiiO", "siisiOiOiiiO"),
|
||
|
&string, &output_style, &source_comments,
|
||
|
&include_paths, &precision,
|
||
|
&custom_functions, &indented, &custom_importers,
|
||
|
&source_map_contents, &source_map_embed,
|
||
|
&omit_source_map_url, &source_map_root)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
context = sass_make_data_context(sass_copy_c_string(string));
|
||
|
options = sass_data_context_get_options(context);
|
||
|
sass_option_set_output_style(options, output_style);
|
||
|
sass_option_set_source_comments(options, source_comments);
|
||
|
sass_option_set_include_path(options, include_paths);
|
||
|
sass_option_set_precision(options, precision);
|
||
|
sass_option_set_is_indented_syntax_src(options, indented);
|
||
|
sass_option_set_source_map_contents(options, source_map_contents);
|
||
|
sass_option_set_source_map_embed(options, source_map_embed);
|
||
|
sass_option_set_omit_source_map_url(options, omit_source_map_url);
|
||
|
|
||
|
if (PyBytes_Check(source_map_root) && PyBytes_Size(source_map_root)) {
|
||
|
sass_option_set_source_map_root(
|
||
|
options, PyBytes_AsString(source_map_root)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
_add_custom_functions(options, custom_functions);
|
||
|
_add_custom_importers(options, custom_importers);
|
||
|
sass_compile_data_context(context);
|
||
|
|
||
|
ctx = sass_data_context_get_context(context);
|
||
|
error_status = sass_context_get_error_status(ctx);
|
||
|
error_message = sass_context_get_error_message(ctx);
|
||
|
output_string = sass_context_get_output_string(ctx);
|
||
|
result = Py_BuildValue(
|
||
|
PySass_IF_PY3("hy", "hs"),
|
||
|
(short int) !error_status,
|
||
|
error_status ? error_message : output_string
|
||
|
);
|
||
|
sass_delete_data_context(context);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static PyObject *
|
||
|
PySass_compile_filename(PyObject *self, PyObject *args) {
|
||
|
struct Sass_Context *ctx;
|
||
|
struct Sass_File_Context *context;
|
||
|
struct Sass_Options *options;
|
||
|
char *filename, *include_paths;
|
||
|
const char *error_message, *output_string, *source_map_string;
|
||
|
enum Sass_Output_Style output_style;
|
||
|
int source_comments, error_status, precision, source_map_embed,
|
||
|
source_map_contents, omit_source_map_url;
|
||
|
PyObject *source_map_filename, *custom_functions, *custom_importers,
|
||
|
*result, *output_filename_hint, *source_map_root;
|
||
|
|
||
|
if (!PyArg_ParseTuple(args,
|
||
|
PySass_IF_PY3("yiiyiOOOOiiiO", "siisiOOOOiiiO"),
|
||
|
&filename, &output_style, &source_comments,
|
||
|
&include_paths, &precision,
|
||
|
&source_map_filename, &custom_functions,
|
||
|
&custom_importers, &output_filename_hint,
|
||
|
&source_map_contents, &source_map_embed,
|
||
|
&omit_source_map_url, &source_map_root)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
context = sass_make_file_context(filename);
|
||
|
options = sass_file_context_get_options(context);
|
||
|
|
||
|
if (PyBytes_Check(source_map_filename)) {
|
||
|
if (PyBytes_Size(source_map_filename)) {
|
||
|
sass_option_set_source_map_file(
|
||
|
options, PyBytes_AsString(source_map_filename)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
if (PyBytes_Check(output_filename_hint)) {
|
||
|
if (PyBytes_Size(output_filename_hint)) {
|
||
|
sass_option_set_output_path(
|
||
|
options, PyBytes_AsString(output_filename_hint)
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (PyBytes_Check(source_map_root) && PyBytes_Size(source_map_root)) {
|
||
|
sass_option_set_source_map_root(
|
||
|
options, PyBytes_AsString(source_map_root)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
sass_option_set_output_style(options, output_style);
|
||
|
sass_option_set_source_comments(options, source_comments);
|
||
|
sass_option_set_include_path(options, include_paths);
|
||
|
sass_option_set_precision(options, precision);
|
||
|
sass_option_set_source_map_contents(options, source_map_contents);
|
||
|
sass_option_set_source_map_embed(options, source_map_embed);
|
||
|
sass_option_set_omit_source_map_url(options, omit_source_map_url);
|
||
|
_add_custom_functions(options, custom_functions);
|
||
|
_add_custom_importers(options, custom_importers);
|
||
|
sass_compile_file_context(context);
|
||
|
|
||
|
ctx = sass_file_context_get_context(context);
|
||
|
error_status = sass_context_get_error_status(ctx);
|
||
|
error_message = sass_context_get_error_message(ctx);
|
||
|
output_string = sass_context_get_output_string(ctx);
|
||
|
source_map_string = sass_context_get_source_map_string(ctx);
|
||
|
result = Py_BuildValue(
|
||
|
PySass_IF_PY3("hyy", "hss"),
|
||
|
(short int) !error_status,
|
||
|
error_status ? error_message : output_string,
|
||
|
error_status || source_map_string == NULL ? "" : source_map_string
|
||
|
);
|
||
|
sass_delete_file_context(context);
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static PyMethodDef PySass_methods[] = {
|
||
|
{"compile_string", PySass_compile_string, METH_VARARGS,
|
||
|
"Compile a Sass string."},
|
||
|
{"compile_filename", PySass_compile_filename, METH_VARARGS,
|
||
|
"Compile a Sass file."},
|
||
|
{NULL, NULL, 0, NULL}
|
||
|
};
|
||
|
|
||
|
static char PySass_doc[] = "The thin binding of libsass for Python.";
|
||
|
|
||
|
PyObject* PySass_make_enum_dict() {
|
||
|
PyObject* dct = PyDict_New();
|
||
|
PyDict_SetItemString(dct, "nested", PyLong_FromLong(SASS_STYLE_NESTED));
|
||
|
PyDict_SetItemString(dct, "expanded", PyLong_FromLong(SASS_STYLE_EXPANDED));
|
||
|
PyDict_SetItemString(dct, "compact", PyLong_FromLong(SASS_STYLE_COMPACT));
|
||
|
PyDict_SetItemString(dct, "compressed", PyLong_FromLong(SASS_STYLE_COMPRESSED));
|
||
|
return dct;
|
||
|
}
|
||
|
|
||
|
void PySass_init_module(PyObject *module) {
|
||
|
PyModule_AddObject(module, "OUTPUT_STYLES", PySass_make_enum_dict());
|
||
|
PyModule_AddObject(module, "libsass_version", PyUnicode_FromString(libsass_version()));
|
||
|
}
|
||
|
|
||
|
#if PY_MAJOR_VERSION >= 3
|
||
|
|
||
|
static struct PyModuleDef sassmodule = {
|
||
|
PyModuleDef_HEAD_INIT,
|
||
|
"_sass",
|
||
|
PySass_doc,
|
||
|
-1,
|
||
|
PySass_methods
|
||
|
};
|
||
|
|
||
|
PyMODINIT_FUNC
|
||
|
PyInit__sass()
|
||
|
{
|
||
|
PyObject *module = PyModule_Create(&sassmodule);
|
||
|
if (module != NULL) {
|
||
|
PySass_init_module(module);
|
||
|
}
|
||
|
return module;
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
|
||
|
PyMODINIT_FUNC
|
||
|
init_sass()
|
||
|
{
|
||
|
PyObject *module;
|
||
|
module = Py_InitModule3("_sass", PySass_methods, PySass_doc);
|
||
|
if (module != NULL) {
|
||
|
PySass_init_module(module);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#endif
|