@@ -35,6 +35,305 @@ static struct PySass_Pair PySass_output_style_enum[] = {
35
35
{NULL }
36
36
};
37
37
38
+ static PyObject* _to_py_value (const union Sass_Value* value) {
39
+ PyObject* retv = NULL ;
40
+ PyObject* types_mod = PyImport_ImportModule (" sassutils.sass_types" );
41
+ PyObject* sass_comma = PyObject_GetAttrString (types_mod, " SASS_SEPARATOR_COMMA" );
42
+ PyObject* sass_space = PyObject_GetAttrString (types_mod, " SASS_SEPARATOR_SPACE" );
43
+
44
+ switch (sass_value_get_tag (value)) {
45
+ case SASS_NULL:
46
+ retv = Py_None;
47
+ Py_INCREF (retv);
48
+ break ;
49
+ case SASS_BOOLEAN:
50
+ retv = PyBool_FromLong (sass_boolean_get_value (value));
51
+ break ;
52
+ case SASS_STRING:
53
+ retv = PyUnicode_FromString (sass_string_get_value (value));
54
+ break ;
55
+ case SASS_NUMBER:
56
+ retv = PyObject_CallMethod (
57
+ types_mod,
58
+ " SassNumber" ,
59
+ PySass_IF_PY3 (" dy" , " ds" ),
60
+ sass_number_get_value (value),
61
+ sass_number_get_unit (value)
62
+ );
63
+ break ;
64
+ case SASS_COLOR:
65
+ retv = PyObject_CallMethod (
66
+ types_mod,
67
+ " SassColor" ,
68
+ " dddd" ,
69
+ sass_color_get_r (value),
70
+ sass_color_get_g (value),
71
+ sass_color_get_b (value),
72
+ sass_color_get_a (value)
73
+ );
74
+ break ;
75
+ case SASS_LIST: {
76
+ size_t i = 0 ;
77
+ PyObject* items = PyTuple_New (sass_list_get_length (value));
78
+ PyObject* separator = sass_comma;
79
+ switch (sass_list_get_separator (value)) {
80
+ case SASS_COMMA:
81
+ separator = sass_comma;
82
+ break ;
83
+ case SASS_SPACE:
84
+ separator = sass_space;
85
+ break ;
86
+ }
87
+ for (i = 0 ; i < sass_list_get_length (value); i += 1 ) {
88
+ PyTuple_SetItem (
89
+ items,
90
+ i,
91
+ _to_py_value (sass_list_get_value (value, i))
92
+ );
93
+ }
94
+ retv = PyObject_CallMethod (
95
+ types_mod, " SassList" , " OO" , items, separator
96
+ );
97
+ break ;
98
+ }
99
+ case SASS_MAP: {
100
+ size_t i = 0 ;
101
+ PyObject* items = PyTuple_New (sass_map_get_length (value));
102
+ for (i = 0 ; i < sass_map_get_length (value); i += 1 ) {
103
+ PyObject* kvp = PyTuple_New (2 );
104
+ PyTuple_SetItem (
105
+ kvp, 0 , _to_py_value (sass_map_get_key (value, i))
106
+ );
107
+ PyTuple_SetItem (
108
+ kvp, 1 , _to_py_value (sass_map_get_value (value, i))
109
+ );
110
+ PyTuple_SetItem (items, i, kvp);
111
+ }
112
+ retv = PyObject_CallMethod (types_mod, " SassMap" , " (O)" , items);
113
+ Py_DECREF (items);
114
+ break ;
115
+ }
116
+ case SASS_ERROR:
117
+ case SASS_WARNING:
118
+ /* @warning and @error cannot be passed */
119
+ break ;
120
+ }
121
+
122
+ if (retv == NULL ) {
123
+ PyErr_SetString (PyExc_TypeError, " Unexpected sass type" );
124
+ }
125
+
126
+ Py_DECREF (types_mod);
127
+ Py_DECREF (sass_comma);
128
+ Py_DECREF (sass_space);
129
+ return retv;
130
+ }
131
+
132
+ static union Sass_Value* _to_sass_value (PyObject* value) {
133
+ union Sass_Value* retv = NULL ;
134
+ PyObject* types_mod = PyImport_ImportModule (" sassutils.sass_types" );
135
+ PyObject* sass_number_t = PyObject_GetAttrString (types_mod, " SassNumber" );
136
+ PyObject* sass_color_t = PyObject_GetAttrString (types_mod, " SassColor" );
137
+ PyObject* sass_list_t = PyObject_GetAttrString (types_mod, " SassList" );
138
+ PyObject* sass_warning_t = PyObject_GetAttrString (types_mod, " SassWarning" );
139
+ PyObject* sass_error_t = PyObject_GetAttrString (types_mod, " SassError" );
140
+ PyObject* sass_comma = PyObject_GetAttrString (types_mod, " SASS_SEPARATOR_COMMA" );
141
+ PyObject* sass_space = PyObject_GetAttrString (types_mod, " SASS_SEPARATOR_SPACE" );
142
+
143
+ if (value == Py_None) {
144
+ retv = sass_make_null ();
145
+ } else if (PyBool_Check (value)) {
146
+ retv = sass_make_boolean (value == Py_True);
147
+ } else if (PyUnicode_Check (value)) {
148
+ PyObject* bytes = PyUnicode_AsEncodedString (value, " UTF-8" , " strict" );
149
+ retv = sass_make_string (PySass_Bytes_AS_STRING (bytes));
150
+ Py_DECREF (bytes);
151
+ } else if (PySass_Bytes_Check (value)) {
152
+ retv = sass_make_string (PySass_Bytes_AS_STRING (value));
153
+ } else if (PyDict_Check (value)) {
154
+ size_t i = 0 ;
155
+ Py_ssize_t pos = 0 ;
156
+ PyObject* d_key = NULL ;
157
+ PyObject* d_value = NULL ;
158
+ retv = sass_make_map (PyDict_Size (value));
159
+ while (PyDict_Next (value, &pos, &d_key, &d_value)) {
160
+ sass_map_set_key (retv, i, _to_sass_value (d_key));
161
+ sass_map_set_value (retv, i, _to_sass_value (d_value));
162
+ i += 1 ;
163
+ }
164
+ } else if (PyObject_IsInstance (value, sass_number_t )) {
165
+ PyObject* d_value = PyObject_GetAttrString (value, " value" );
166
+ PyObject* unit = PyObject_GetAttrString (value, " unit" );
167
+ PyObject* bytes = PyUnicode_AsEncodedString (unit, " UTF-8" , " strict" );
168
+ retv = sass_make_number (
169
+ PyFloat_AsDouble (d_value), PySass_Bytes_AS_STRING (bytes)
170
+ );
171
+ Py_DECREF (d_value);
172
+ Py_DECREF (unit);
173
+ Py_DECREF (bytes);
174
+ } else if (PyObject_IsInstance (value, sass_color_t )) {
175
+ PyObject* r_value = PyObject_GetAttrString (value, " r" );
176
+ PyObject* g_value = PyObject_GetAttrString (value, " g" );
177
+ PyObject* b_value = PyObject_GetAttrString (value, " b" );
178
+ PyObject* a_value = PyObject_GetAttrString (value, " a" );
179
+ retv = sass_make_color (
180
+ PyFloat_AsDouble (r_value),
181
+ PyFloat_AsDouble (g_value),
182
+ PyFloat_AsDouble (b_value),
183
+ PyFloat_AsDouble (a_value)
184
+ );
185
+ Py_DECREF (r_value);
186
+ Py_DECREF (g_value);
187
+ Py_DECREF (b_value);
188
+ Py_DECREF (a_value);
189
+ } else if (PyObject_IsInstance (value, sass_list_t )) {
190
+ Py_ssize_t i = 0 ;
191
+ PyObject* items = PyObject_GetAttrString (value, " items" );
192
+ PyObject* separator = PyObject_GetAttrString (value, " separator" );
193
+ /* TODO: I don't really like this, maybe move types to C */
194
+ Sass_Separator sep = SASS_COMMA;
195
+ if (separator == sass_comma) {
196
+ sep = SASS_COMMA;
197
+ } else if (separator == sass_space) {
198
+ sep = SASS_SPACE;
199
+ } else {
200
+ assert (0 );
201
+ }
202
+ retv = sass_make_list (PyTuple_Size (items), sep);
203
+ for (i = 0 ; i < PyTuple_Size (items); i += 1 ) {
204
+ sass_list_set_value (
205
+ retv, i, _to_sass_value (PyTuple_GET_ITEM (items, i))
206
+ );
207
+ }
208
+ Py_DECREF (items);
209
+ Py_DECREF (separator);
210
+ } else if (PyObject_IsInstance (value, sass_warning_t )) {
211
+ PyObject* msg = PyObject_GetAttrString (value, " msg" );
212
+ PyObject* bytes = PyUnicode_AsEncodedString (msg, " UTF-8" , " strict" );
213
+ retv = sass_make_warning (PySass_Bytes_AS_STRING (bytes));
214
+ Py_DECREF (msg);
215
+ Py_DECREF (bytes);
216
+ } else if (PyObject_IsInstance (value, sass_error_t )) {
217
+ PyObject* msg = PyObject_GetAttrString (value, " msg" );
218
+ PyObject* bytes = PyUnicode_AsEncodedString (msg, " UTF-8" , " strict" );
219
+ retv = sass_make_error (PySass_Bytes_AS_STRING (bytes));
220
+ Py_DECREF (msg);
221
+ Py_DECREF (bytes);
222
+ }
223
+
224
+ if (retv == NULL ) {
225
+ PyObject* type = PyObject_Type (value);
226
+ PyObject* type_name = PyObject_GetAttrString (type, " __name__" );
227
+ PyObject* fmt = PyUnicode_FromString (
228
+ " Unexpected type: `{0}`.\n "
229
+ " Expected one of:\n "
230
+ " - None\n "
231
+ " - bool\n "
232
+ " - str\n "
233
+ " - SassNumber\n "
234
+ " - SassColor\n "
235
+ " - SassList\n "
236
+ " - dict\n "
237
+ " - SassMap\n "
238
+ " - SassWarning\n "
239
+ " - SassError\n "
240
+ );
241
+ PyObject* format_meth = PyObject_GetAttrString (fmt, " format" );
242
+ PyObject* result = PyObject_CallFunctionObjArgs (
243
+ format_meth, type_name, NULL
244
+ );
245
+ PyObject* bytes = PyUnicode_AsEncodedString (result, " UTF-8" , " strict" );
246
+ retv = sass_make_error (PySass_Bytes_AS_STRING (bytes));
247
+ Py_DECREF (type);
248
+ Py_DECREF (type_name);
249
+ Py_DECREF (fmt);
250
+ Py_DECREF (format_meth);
251
+ Py_DECREF (result);
252
+ Py_DECREF (bytes);
253
+ }
254
+
255
+ Py_DECREF (types_mod);
256
+ Py_DECREF (sass_number_t );
257
+ Py_DECREF (sass_color_t );
258
+ Py_DECREF (sass_list_t );
259
+ Py_DECREF (sass_warning_t );
260
+ Py_DECREF (sass_error_t );
261
+ Py_DECREF (sass_comma);
262
+ Py_DECREF (sass_space);
263
+ return retv;
264
+ }
265
+
266
+ static union Sass_Value* _call_py_f (
267
+ const union Sass_Value* sass_args, void * cookie
268
+ ) {
269
+ size_t i;
270
+ PyObject* pyfunc = (PyObject*)cookie;
271
+ PyObject* py_args = PyTuple_New (sass_list_get_length (sass_args));
272
+ PyObject* py_result = NULL ;
273
+ union Sass_Value* sass_result = NULL ;
274
+
275
+ for (i = 0 ; i < sass_list_get_length (sass_args); i += 1 ) {
276
+ union Sass_Value* sass_arg = sass_list_get_value (sass_args, i);
277
+ PyObject* py_arg = NULL ;
278
+ if (!(py_arg = _to_py_value (sass_arg))) goto done;
279
+ PyTuple_SetItem (py_args, i, py_arg);
280
+ }
281
+
282
+ if (!(py_result = PyObject_CallObject (pyfunc, py_args))) goto done;
283
+ sass_result = _to_sass_value (py_result);
284
+
285
+ done:
286
+ if (sass_result == NULL ) {
287
+ PyObject* etype = NULL ;
288
+ PyObject* evalue = NULL ;
289
+ PyObject* etb = NULL ;
290
+ {
291
+ PyErr_Fetch (&etype, &evalue, &etb);
292
+ PyObject* traceback_mod = PyImport_ImportModule (" traceback" );
293
+ PyObject* traceback_parts = PyObject_CallMethod (
294
+ traceback_mod, " format_exception" , " OOO" , etype, evalue, etb
295
+ );
296
+ PyList_Insert (traceback_parts, 0 , PyUnicode_FromString (" \n " ));
297
+ PyObject* joinstr = PyUnicode_FromString (" " );
298
+ PyObject* result = PyUnicode_Join (joinstr, traceback_parts);
299
+ PyObject* bytes = PyUnicode_AsEncodedString (
300
+ result, " UTF-8" , " strict"
301
+ );
302
+ sass_result = sass_make_error (PySass_Bytes_AS_STRING (bytes));
303
+ Py_DECREF (traceback_mod);
304
+ Py_DECREF (traceback_parts);
305
+ Py_DECREF (joinstr);
306
+ Py_DECREF (result);
307
+ Py_DECREF (bytes);
308
+ }
309
+ }
310
+ Py_XDECREF (py_args);
311
+ Py_XDECREF (py_result);
312
+ return sass_result;
313
+ }
314
+
315
+
316
+ static void _add_custom_functions (
317
+ struct Sass_Options * options, PyObject* custom_functions
318
+ ) {
319
+ Py_ssize_t i;
320
+ Sass_C_Function_List fn_list = sass_make_function_list (
321
+ PyList_Size (custom_functions)
322
+ );
323
+ for (i = 0 ; i < PyList_GET_SIZE (custom_functions); i += 1 ) {
324
+ PyObject* signature_and_func = PyList_GET_ITEM (custom_functions, i);
325
+ PyObject* signature = PyTuple_GET_ITEM (signature_and_func, 0 );
326
+ PyObject* func = PyTuple_GET_ITEM (signature_and_func, 1 );
327
+ Sass_C_Function_Callback fn = sass_make_function (
328
+ PySass_Bytes_AS_STRING (signature),
329
+ _call_py_f,
330
+ func
331
+ );
332
+ sass_function_set_list_entry (fn_list, i, fn);
333
+ }
334
+ sass_option_set_c_functions (options, fn_list);
335
+ }
336
+
38
337
static PyObject *
39
338
PySass_compile_string (PyObject *self, PyObject *args) {
40
339
struct Sass_Context *ctx;
@@ -44,12 +343,14 @@ PySass_compile_string(PyObject *self, PyObject *args) {
44
343
const char *error_message, *output_string;
45
344
Sass_Output_Style output_style;
46
345
int source_comments, error_status, precision;
346
+ PyObject *custom_functions;
47
347
PyObject *result;
48
348
49
349
if (!PyArg_ParseTuple (args,
50
- PySass_IF_PY3 (" yiiyyi " , " siissi " ),
350
+ PySass_IF_PY3 (" yiiyyiO " , " siissiO " ),
51
351
&string, &output_style, &source_comments,
52
- &include_paths, &image_path, &precision)) {
352
+ &include_paths, &image_path, &precision,
353
+ &custom_functions)) {
53
354
return NULL ;
54
355
}
55
356
@@ -60,6 +361,7 @@ PySass_compile_string(PyObject *self, PyObject *args) {
60
361
sass_option_set_include_path (options, include_paths);
61
362
sass_option_set_image_path (options, image_path);
62
363
sass_option_set_precision (options, precision);
364
+ _add_custom_functions (options, custom_functions);
63
365
64
366
sass_compile_data_context (context);
65
367
@@ -85,12 +387,13 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
85
387
const char *error_message, *output_string, *source_map_string;
86
388
Sass_Output_Style output_style;
87
389
int source_comments, error_status, precision;
88
- PyObject *source_map_filename, *result;
390
+ PyObject *source_map_filename, *custom_functions, * result;
89
391
90
392
if (!PyArg_ParseTuple (args,
91
- PySass_IF_PY3 (" yiiyyiO " , " siissiO " ),
393
+ PySass_IF_PY3 (" yiiyyiOO " , " siissiOO " ),
92
394
&filename, &output_style, &source_comments,
93
- &include_paths, &image_path, &precision, &source_map_filename)) {
395
+ &include_paths, &image_path, &precision,
396
+ &source_map_filename, &custom_functions)) {
94
397
return NULL ;
95
398
}
96
399
@@ -114,6 +417,7 @@ PySass_compile_filename(PyObject *self, PyObject *args) {
114
417
sass_option_set_include_path (options, include_paths);
115
418
sass_option_set_image_path (options, image_path);
116
419
sass_option_set_precision (options, precision);
420
+ _add_custom_functions (options, custom_functions);
117
421
118
422
sass_compile_file_context (context);
119
423
0 commit comments