1// sass.hpp must go before all system headers to get the
2// __EXTENSIONS__ fix on Solaris.
3#include "sass.hpp"
4
5#include <cstdlib>
6#include <cstring>
7#include "util.hpp"
8#include "eval.hpp"
9#include "operators.hpp"
10#include "sass/values.h"
11#include "sass_values.hpp"
12
13extern "C" {
14 using namespace Sass;
15
16 // Return the sass tag for a generic sass value
17 enum Sass_Tag ADDCALL sass_value_get_tag(const union Sass_Value* v) { return v->unknown.tag; }
18
19 // Check value for specified type
20 bool ADDCALL sass_value_is_null(const union Sass_Value* v) { return v->unknown.tag == SASS_NULL; }
21 bool ADDCALL sass_value_is_number(const union Sass_Value* v) { return v->unknown.tag == SASS_NUMBER; }
22 bool ADDCALL sass_value_is_string(const union Sass_Value* v) { return v->unknown.tag == SASS_STRING; }
23 bool ADDCALL sass_value_is_boolean(const union Sass_Value* v) { return v->unknown.tag == SASS_BOOLEAN; }
24 bool ADDCALL sass_value_is_color(const union Sass_Value* v) { return v->unknown.tag == SASS_COLOR; }
25 bool ADDCALL sass_value_is_list(const union Sass_Value* v) { return v->unknown.tag == SASS_LIST; }
26 bool ADDCALL sass_value_is_map(const union Sass_Value* v) { return v->unknown.tag == SASS_MAP; }
27 bool ADDCALL sass_value_is_error(const union Sass_Value* v) { return v->unknown.tag == SASS_ERROR; }
28 bool ADDCALL sass_value_is_warning(const union Sass_Value* v) { return v->unknown.tag == SASS_WARNING; }
29
30 // Getters and setters for Sass_Number
31 double ADDCALL sass_number_get_value(const union Sass_Value* v) { return v->number.value; }
32 void ADDCALL sass_number_set_value(union Sass_Value* v, double value) { v->number.value = value; }
33 const char* ADDCALL sass_number_get_unit(const union Sass_Value* v) { return v->number.unit; }
34 void ADDCALL sass_number_set_unit(union Sass_Value* v, char* unit) { v->number.unit = unit; }
35
36 // Getters and setters for Sass_String
37 const char* ADDCALL sass_string_get_value(const union Sass_Value* v) { return v->string.value; }
38 void ADDCALL sass_string_set_value(union Sass_Value* v, char* value) { v->string.value = value; }
39 bool ADDCALL sass_string_is_quoted(const union Sass_Value* v) { return v->string.quoted; }
40 void ADDCALL sass_string_set_quoted(union Sass_Value* v, bool quoted) { v->string.quoted = quoted; }
41
42 // Getters and setters for Sass_Boolean
43 bool ADDCALL sass_boolean_get_value(const union Sass_Value* v) { return v->boolean.value; }
44 void ADDCALL sass_boolean_set_value(union Sass_Value* v, bool value) { v->boolean.value = value; }
45
46 // Getters and setters for Sass_Color
47 double ADDCALL sass_color_get_r(const union Sass_Value* v) { return v->color.r; }
48 void ADDCALL sass_color_set_r(union Sass_Value* v, double r) { v->color.r = r; }
49 double ADDCALL sass_color_get_g(const union Sass_Value* v) { return v->color.g; }
50 void ADDCALL sass_color_set_g(union Sass_Value* v, double g) { v->color.g = g; }
51 double ADDCALL sass_color_get_b(const union Sass_Value* v) { return v->color.b; }
52 void ADDCALL sass_color_set_b(union Sass_Value* v, double b) { v->color.b = b; }
53 double ADDCALL sass_color_get_a(const union Sass_Value* v) { return v->color.a; }
54 void ADDCALL sass_color_set_a(union Sass_Value* v, double a) { v->color.a = a; }
55
56 // Getters and setters for Sass_List
57 size_t ADDCALL sass_list_get_length(const union Sass_Value* v) { return v->list.length; }
58 enum Sass_Separator ADDCALL sass_list_get_separator(const union Sass_Value* v) { return v->list.separator; }
59 void ADDCALL sass_list_set_separator(union Sass_Value* v, enum Sass_Separator separator) { v->list.separator = separator; }
60 bool ADDCALL sass_list_get_is_bracketed(const union Sass_Value* v) { return v->list.is_bracketed; }
61 void ADDCALL sass_list_set_is_bracketed(union Sass_Value* v, bool is_bracketed) { v->list.is_bracketed = is_bracketed; }
62 // Getters and setters for Sass_List values
63 union Sass_Value* ADDCALL sass_list_get_value(const union Sass_Value* v, size_t i) { return v->list.values[i]; }
64 void ADDCALL sass_list_set_value(union Sass_Value* v, size_t i, union Sass_Value* value) { v->list.values[i] = value; }
65
66 // Getters and setters for Sass_Map
67 size_t ADDCALL sass_map_get_length(const union Sass_Value* v) { return v->map.length; }
68 // Getters and setters for Sass_List keys and values
69 union Sass_Value* ADDCALL sass_map_get_key(const union Sass_Value* v, size_t i) { return v->map.pairs[i].key; }
70 union Sass_Value* ADDCALL sass_map_get_value(const union Sass_Value* v, size_t i) { return v->map.pairs[i].value; }
71 void ADDCALL sass_map_set_key(union Sass_Value* v, size_t i, union Sass_Value* key) { v->map.pairs[i].key = key; }
72 void ADDCALL sass_map_set_value(union Sass_Value* v, size_t i, union Sass_Value* val) { v->map.pairs[i].value = val; }
73
74 // Getters and setters for Sass_Error
75 char* ADDCALL sass_error_get_message(const union Sass_Value* v) { return v->error.message; };
76 void ADDCALL sass_error_set_message(union Sass_Value* v, char* msg) { v->error.message = msg; };
77
78 // Getters and setters for Sass_Warning
79 char* ADDCALL sass_warning_get_message(const union Sass_Value* v) { return v->warning.message; };
80 void ADDCALL sass_warning_set_message(union Sass_Value* v, char* msg) { v->warning.message = msg; };
81
82 // Creator functions for all value types
83
84 union Sass_Value* ADDCALL sass_make_boolean(bool val)
85 {
86 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
87 if (v == 0) return 0;
88 v->boolean.tag = SASS_BOOLEAN;
89 v->boolean.value = val;
90 return v;
91 }
92
93 union Sass_Value* ADDCALL sass_make_number(double val, const char* unit)
94 {
95 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
96 if (v == 0) return 0;
97 v->number.tag = SASS_NUMBER;
98 v->number.value = val;
99 v->number.unit = unit ? sass_copy_c_string(str: unit) : 0;
100 if (v->number.unit == 0) { free(ptr: v); return 0; }
101 return v;
102 }
103
104 union Sass_Value* ADDCALL sass_make_color(double r, double g, double b, double a)
105 {
106 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
107 if (v == 0) return 0;
108 v->color.tag = SASS_COLOR;
109 v->color.r = r;
110 v->color.g = g;
111 v->color.b = b;
112 v->color.a = a;
113 return v;
114 }
115
116 union Sass_Value* ADDCALL sass_make_string(const char* val)
117 {
118 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
119 if (v == 0) return 0;
120 v->string.quoted = false;
121 v->string.tag = SASS_STRING;
122 v->string.value = val ? sass_copy_c_string(str: val) : 0;
123 if (v->string.value == 0) { free(ptr: v); return 0; }
124 return v;
125 }
126
127 union Sass_Value* ADDCALL sass_make_qstring(const char* val)
128 {
129 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
130 if (v == 0) return 0;
131 v->string.quoted = true;
132 v->string.tag = SASS_STRING;
133 v->string.value = val ? sass_copy_c_string(str: val) : 0;
134 if (v->string.value == 0) { free(ptr: v); return 0; }
135 return v;
136 }
137
138 union Sass_Value* ADDCALL sass_make_list(size_t len, enum Sass_Separator sep, bool is_bracketed)
139 {
140 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
141 if (v == 0) return 0;
142 v->list.tag = SASS_LIST;
143 v->list.length = len;
144 v->list.separator = sep;
145 v->list.is_bracketed = is_bracketed;
146 v->list.values = (union Sass_Value**) calloc(nmemb: len, size: sizeof(union Sass_Value*));
147 if (v->list.values == 0) { free(ptr: v); return 0; }
148 return v;
149 }
150
151 union Sass_Value* ADDCALL sass_make_map(size_t len)
152 {
153 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
154 if (v == 0) return 0;
155 v->map.tag = SASS_MAP;
156 v->map.length = len;
157 v->map.pairs = (struct Sass_MapPair*) calloc(nmemb: len, size: sizeof(struct Sass_MapPair));
158 if (v->map.pairs == 0) { free(ptr: v); return 0; }
159 return v;
160 }
161
162 union Sass_Value* ADDCALL sass_make_null(void)
163 {
164 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
165 if (v == 0) return 0;
166 v->null.tag = SASS_NULL;
167 return v;
168 }
169
170 union Sass_Value* ADDCALL sass_make_error(const char* msg)
171 {
172 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
173 if (v == 0) return 0;
174 v->error.tag = SASS_ERROR;
175 v->error.message = msg ? sass_copy_c_string(str: msg) : 0;
176 if (v->error.message == 0) { free(ptr: v); return 0; }
177 return v;
178 }
179
180 union Sass_Value* ADDCALL sass_make_warning(const char* msg)
181 {
182 union Sass_Value* v = (Sass_Value*) calloc(nmemb: 1, size: sizeof(Sass_Value));
183 if (v == 0) return 0;
184 v->warning.tag = SASS_WARNING;
185 v->warning.message = msg ? sass_copy_c_string(str: msg) : 0;
186 if (v->warning.message == 0) { free(ptr: v); return 0; }
187 return v;
188 }
189
190 // will free all associated sass values
191 void ADDCALL sass_delete_value(union Sass_Value* val) {
192
193 size_t i;
194 if (val == 0) return;
195 switch(val->unknown.tag) {
196 case SASS_NULL: {
197 } break;
198 case SASS_BOOLEAN: {
199 } break;
200 case SASS_NUMBER: {
201 free(ptr: val->number.unit);
202 } break;
203 case SASS_COLOR: {
204 } break;
205 case SASS_STRING: {
206 free(ptr: val->string.value);
207 } break;
208 case SASS_LIST: {
209 for (i=0; i<val->list.length; i++) {
210 sass_delete_value(val: val->list.values[i]);
211 }
212 free(ptr: val->list.values);
213 } break;
214 case SASS_MAP: {
215 for (i=0; i<val->map.length; i++) {
216 sass_delete_value(val: val->map.pairs[i].key);
217 sass_delete_value(val: val->map.pairs[i].value);
218 }
219 free(ptr: val->map.pairs);
220 } break;
221 case SASS_ERROR: {
222 free(ptr: val->error.message);
223 } break;
224 case SASS_WARNING: {
225 free(ptr: val->error.message);
226 } break;
227 default: break;
228 }
229
230 free(ptr: val);
231
232 }
233
234 // Make a deep cloned copy of the given sass value
235 union Sass_Value* ADDCALL sass_clone_value (const union Sass_Value* val)
236 {
237
238 size_t i;
239 if (val == 0) return 0;
240 switch(val->unknown.tag) {
241 case SASS_NULL: {
242 return sass_make_null();
243 }
244 case SASS_BOOLEAN: {
245 return sass_make_boolean(val: val->boolean.value);
246 }
247 case SASS_NUMBER: {
248 return sass_make_number(val: val->number.value, unit: val->number.unit);
249 }
250 case SASS_COLOR: {
251 return sass_make_color(r: val->color.r, g: val->color.g, b: val->color.b, a: val->color.a);
252 }
253 case SASS_STRING: {
254 return sass_string_is_quoted(v: val) ? sass_make_qstring(val: val->string.value) : sass_make_string(val: val->string.value);
255 }
256 case SASS_LIST: {
257 union Sass_Value* list = sass_make_list(len: val->list.length, sep: val->list.separator, is_bracketed: val->list.is_bracketed);
258 for (i = 0; i < list->list.length; i++) {
259 list->list.values[i] = sass_clone_value(val: val->list.values[i]);
260 }
261 return list;
262 }
263 case SASS_MAP: {
264 union Sass_Value* map = sass_make_map(len: val->map.length);
265 for (i = 0; i < val->map.length; i++) {
266 map->map.pairs[i].key = sass_clone_value(val: val->map.pairs[i].key);
267 map->map.pairs[i].value = sass_clone_value(val: val->map.pairs[i].value);
268 }
269 return map;
270 }
271 case SASS_ERROR: {
272 return sass_make_error(msg: val->error.message);
273 }
274 case SASS_WARNING: {
275 return sass_make_warning(msg: val->warning.message);
276 }
277 default: break;
278 }
279
280 return 0;
281
282 }
283
284 union Sass_Value* ADDCALL sass_value_stringify (const union Sass_Value* v, bool compressed, int precision)
285 {
286 ValueObj val = sass_value_to_ast_node(val: v);
287 Sass_Inspect_Options options(compressed ? COMPRESSED : NESTED, precision);
288 sass::string str(val->to_string(opt: options));
289 return sass_make_qstring(val: str.c_str());
290 }
291
292 union Sass_Value* ADDCALL sass_value_op (enum Sass_OP op, const union Sass_Value* a, const union Sass_Value* b)
293 {
294
295 Sass::ValueObj rv;
296
297 try {
298
299 ValueObj lhs = sass_value_to_ast_node(val: a);
300 ValueObj rhs = sass_value_to_ast_node(val: b);
301 struct Sass_Inspect_Options options(NESTED, 5);
302
303 // see if it's a relational expression
304 switch(op) {
305 case Sass_OP::EQ: return sass_make_boolean(val: Operators::eq(lhs, rhs));
306 case Sass_OP::NEQ: return sass_make_boolean(val: Operators::neq(lhs, rhs));
307 case Sass_OP::GT: return sass_make_boolean(val: Operators::gt(lhs, rhs));
308 case Sass_OP::GTE: return sass_make_boolean(val: Operators::gte(lhs, rhs));
309 case Sass_OP::LT: return sass_make_boolean(val: Operators::lt(lhs, rhs));
310 case Sass_OP::LTE: return sass_make_boolean(val: Operators::lte(lhs, rhs));
311 case Sass_OP::AND: return ast_node_to_sass_value(val: lhs->is_false() ? lhs : rhs);
312 case Sass_OP::OR: return ast_node_to_sass_value(val: lhs->is_false() ? rhs : lhs);
313 default: break;
314 }
315
316 if (sass_value_is_number(v: a) && sass_value_is_number(v: b)) {
317 const Number* l_n = Cast<Number>(ptr: lhs);
318 const Number* r_n = Cast<Number>(ptr: rhs);
319 rv = Operators::op_numbers(op, *l_n, *r_n, opt: options, pstate: l_n->pstate());
320 }
321 else if (sass_value_is_number(v: a) && sass_value_is_color(v: a)) {
322 const Number* l_n = Cast<Number>(ptr: lhs);
323 // Direct HSLA operations are not supported
324 // All color maths will be deprecated anyway
325 Color_RGBA_Obj r_c = Cast<Color>(ptr: rhs)->toRGBA();
326 rv = Operators::op_number_color(op, *l_n, *r_c, opt: options, pstate: l_n->pstate());
327 }
328 else if (sass_value_is_color(v: a) && sass_value_is_number(v: b)) {
329 // Direct HSLA operations are not supported
330 // All color maths will be deprecated anyway
331 Color_RGBA_Obj l_c = Cast<Color>(ptr: lhs)->toRGBA();
332 const Number* r_n = Cast<Number>(ptr: rhs);
333 rv = Operators::op_color_number(op, *l_c, *r_n, opt: options, pstate: l_c->pstate());
334 }
335 else if (sass_value_is_color(v: a) && sass_value_is_color(v: b)) {
336 // Direct HSLA operations are not supported
337 // All color maths will be deprecated anyway
338 Color_RGBA_Obj l_c = Cast<Color>(ptr: lhs)->toRGBA();
339 Color_RGBA_Obj r_c = Cast<Color>(ptr: rhs)->toRGBA();
340 rv = Operators::op_colors(op, *l_c, *r_c, opt: options, pstate: l_c->pstate());
341 }
342 else /* convert other stuff to string and apply operation */ {
343 rv = Operators::op_strings(op, *lhs, *rhs, opt: options, pstate: lhs->pstate());
344 }
345
346 // ToDo: maybe we should return null value?
347 if (!rv) return sass_make_error(msg: "invalid return value");
348
349 // convert result back to ast node
350 return ast_node_to_sass_value(val: rv.ptr());
351 }
352
353 // simply pass the error message back to the caller for now
354 catch (Exception::InvalidSass& e) { return sass_make_error(msg: e.what()); }
355 catch (std::bad_alloc&) { return sass_make_error(msg: "memory exhausted"); }
356 catch (std::exception& e) { return sass_make_error(msg: e.what()); }
357 catch (sass::string& e) { return sass_make_error(msg: e.c_str()); }
358 catch (const char* e) { return sass_make_error(msg: e); }
359 catch (...) { return sass_make_error(msg: "unknown"); }
360 }
361
362}
363

source code of gtk/subprojects/libsass/src/sass_values.cpp