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