sassc 1.7.1 → 1.8.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/ext/libsass/.gitignore +10 -6
  4. data/ext/libsass/.travis.yml +4 -1
  5. data/ext/libsass/GNUmakefile.am +88 -0
  6. data/ext/libsass/Makefile +157 -76
  7. data/ext/libsass/Makefile.conf +47 -0
  8. data/ext/libsass/Readme.md +13 -14
  9. data/ext/libsass/appveyor.yml +25 -41
  10. data/ext/libsass/configure.ac +20 -7
  11. data/ext/libsass/contrib/plugin.cpp +1 -1
  12. data/ext/libsass/include/sass.h +15 -0
  13. data/ext/libsass/{sass.h → include/sass/base.h} +17 -9
  14. data/ext/libsass/{sass_context.h → include/sass/context.h} +3 -1
  15. data/ext/libsass/{sass_functions.h → include/sass/functions.h} +4 -4
  16. data/ext/libsass/{sass_interface.h → include/sass/interface.h} +5 -2
  17. data/ext/libsass/{sass_values.h → include/sass/values.h} +15 -1
  18. data/ext/libsass/{sass_version.h → include/sass/version.h} +0 -0
  19. data/ext/libsass/{sass_version.h.in → include/sass/version.h.in} +0 -0
  20. data/ext/libsass/{sass2scss.h → include/sass2scss.h} +6 -7
  21. data/ext/libsass/m4/m4-ax_cxx_compile_stdcxx_11.m4 +167 -0
  22. data/ext/libsass/script/ci-build-libsass +67 -23
  23. data/ext/libsass/src/GNUmakefile.am +54 -0
  24. data/ext/libsass/src/ast.cpp +2029 -0
  25. data/ext/libsass/{ast.hpp → src/ast.hpp} +832 -660
  26. data/ext/libsass/src/ast_def_macros.hpp +47 -0
  27. data/ext/libsass/src/ast_factory.hpp +93 -0
  28. data/ext/libsass/{ast_fwd_decl.hpp → src/ast_fwd_decl.hpp} +9 -4
  29. data/ext/libsass/{b64 → src/b64}/cencode.h +1 -1
  30. data/ext/libsass/{b64 → src/b64}/encode.h +0 -0
  31. data/ext/libsass/{backtrace.hpp → src/backtrace.hpp} +9 -10
  32. data/ext/libsass/{base64vlq.cpp → src/base64vlq.cpp} +2 -2
  33. data/ext/libsass/{base64vlq.hpp → src/base64vlq.hpp} +1 -2
  34. data/ext/libsass/{bind.cpp → src/bind.cpp} +96 -59
  35. data/ext/libsass/{bind.hpp → src/bind.hpp} +1 -1
  36. data/ext/libsass/src/c99func.c +54 -0
  37. data/ext/libsass/{cencode.c → src/cencode.c} +5 -5
  38. data/ext/libsass/src/color_maps.cpp +643 -0
  39. data/ext/libsass/src/color_maps.hpp +333 -0
  40. data/ext/libsass/{constants.cpp → src/constants.cpp} +10 -1
  41. data/ext/libsass/{constants.hpp → src/constants.hpp} +7 -0
  42. data/ext/libsass/{context.cpp → src/context.cpp} +152 -122
  43. data/ext/libsass/src/context.hpp +150 -0
  44. data/ext/libsass/{cssize.cpp → src/cssize.cpp} +123 -109
  45. data/ext/libsass/{cssize.hpp → src/cssize.hpp} +9 -13
  46. data/ext/libsass/{debug.hpp → src/debug.hpp} +9 -9
  47. data/ext/libsass/src/debugger.hpp +683 -0
  48. data/ext/libsass/{emitter.cpp → src/emitter.cpp} +13 -13
  49. data/ext/libsass/{emitter.hpp → src/emitter.hpp} +10 -11
  50. data/ext/libsass/src/environment.cpp +184 -0
  51. data/ext/libsass/src/environment.hpp +92 -0
  52. data/ext/libsass/src/error_handling.cpp +46 -0
  53. data/ext/libsass/src/error_handling.hpp +34 -0
  54. data/ext/libsass/src/eval.cpp +1462 -0
  55. data/ext/libsass/src/eval.hpp +107 -0
  56. data/ext/libsass/src/expand.cpp +653 -0
  57. data/ext/libsass/{expand.hpp → src/expand.hpp} +17 -16
  58. data/ext/libsass/{extend.cpp → src/extend.cpp} +198 -139
  59. data/ext/libsass/{extend.hpp → src/extend.hpp} +7 -8
  60. data/ext/libsass/{file.cpp → src/file.cpp} +103 -57
  61. data/ext/libsass/{file.hpp → src/file.hpp} +23 -14
  62. data/ext/libsass/{functions.cpp → src/functions.cpp} +642 -333
  63. data/ext/libsass/{functions.hpp → src/functions.hpp} +17 -4
  64. data/ext/libsass/{inspect.cpp → src/inspect.cpp} +147 -260
  65. data/ext/libsass/{inspect.hpp → src/inspect.hpp} +7 -7
  66. data/ext/libsass/{json.cpp → src/json.cpp} +33 -43
  67. data/ext/libsass/{json.hpp → src/json.hpp} +1 -1
  68. data/ext/libsass/{kwd_arg_macros.hpp → src/kwd_arg_macros.hpp} +0 -0
  69. data/ext/libsass/{lexer.cpp → src/lexer.cpp} +28 -0
  70. data/ext/libsass/{lexer.hpp → src/lexer.hpp} +25 -10
  71. data/ext/libsass/{listize.cpp → src/listize.cpp} +17 -13
  72. data/ext/libsass/{listize.hpp → src/listize.hpp} +0 -2
  73. data/ext/libsass/{mapping.hpp → src/mapping.hpp} +0 -0
  74. data/ext/libsass/src/memory_manager.cpp +76 -0
  75. data/ext/libsass/src/memory_manager.hpp +48 -0
  76. data/ext/libsass/{node.cpp → src/node.cpp} +89 -18
  77. data/ext/libsass/{node.hpp → src/node.hpp} +5 -6
  78. data/ext/libsass/{operation.hpp → src/operation.hpp} +18 -12
  79. data/ext/libsass/{output.cpp → src/output.cpp} +47 -55
  80. data/ext/libsass/{output.hpp → src/output.hpp} +5 -4
  81. data/ext/libsass/src/parser.cpp +2529 -0
  82. data/ext/libsass/{parser.hpp → src/parser.hpp} +84 -60
  83. data/ext/libsass/{paths.hpp → src/paths.hpp} +10 -13
  84. data/ext/libsass/{plugins.cpp → src/plugins.cpp} +14 -17
  85. data/ext/libsass/{plugins.hpp → src/plugins.hpp} +10 -11
  86. data/ext/libsass/{position.cpp → src/position.cpp} +5 -6
  87. data/ext/libsass/{position.hpp → src/position.hpp} +19 -22
  88. data/ext/libsass/{prelexer.cpp → src/prelexer.cpp} +401 -53
  89. data/ext/libsass/{prelexer.hpp → src/prelexer.hpp} +50 -10
  90. data/ext/libsass/{remove_placeholders.cpp → src/remove_placeholders.cpp} +12 -16
  91. data/ext/libsass/{remove_placeholders.hpp → src/remove_placeholders.hpp} +1 -7
  92. data/ext/libsass/{sass.cpp → src/sass.cpp} +3 -5
  93. data/ext/libsass/{sass2scss.cpp → src/sass2scss.cpp} +51 -46
  94. data/ext/libsass/{sass_context.cpp → src/sass_context.cpp} +114 -112
  95. data/ext/libsass/{sass_functions.cpp → src/sass_functions.cpp} +11 -18
  96. data/ext/libsass/{sass_interface.cpp → src/sass_interface.cpp} +44 -81
  97. data/ext/libsass/{sass_util.cpp → src/sass_util.cpp} +26 -8
  98. data/ext/libsass/{sass_util.hpp → src/sass_util.hpp} +14 -18
  99. data/ext/libsass/{sass_values.cpp → src/sass_values.cpp} +91 -20
  100. data/ext/libsass/{source_map.cpp → src/source_map.cpp} +13 -13
  101. data/ext/libsass/{source_map.hpp → src/source_map.hpp} +9 -9
  102. data/ext/libsass/{subset_map.hpp → src/subset_map.hpp} +29 -31
  103. data/ext/libsass/{support → src/support}/libsass.pc.in +0 -0
  104. data/ext/libsass/src/to_c.cpp +73 -0
  105. data/ext/libsass/src/to_c.hpp +41 -0
  106. data/ext/libsass/src/to_string.cpp +47 -0
  107. data/ext/libsass/{to_string.hpp → src/to_string.hpp} +9 -7
  108. data/ext/libsass/src/to_value.cpp +109 -0
  109. data/ext/libsass/src/to_value.hpp +50 -0
  110. data/ext/libsass/{units.cpp → src/units.cpp} +56 -51
  111. data/ext/libsass/{units.hpp → src/units.hpp} +8 -9
  112. data/ext/libsass/{utf8.h → src/utf8.h} +0 -0
  113. data/ext/libsass/{utf8 → src/utf8}/checked.h +0 -0
  114. data/ext/libsass/{utf8 → src/utf8}/core.h +12 -12
  115. data/ext/libsass/{utf8 → src/utf8}/unchecked.h +0 -0
  116. data/ext/libsass/{utf8_string.cpp → src/utf8_string.cpp} +0 -0
  117. data/ext/libsass/{utf8_string.hpp → src/utf8_string.hpp} +6 -6
  118. data/ext/libsass/{util.cpp → src/util.cpp} +144 -86
  119. data/ext/libsass/src/util.hpp +59 -0
  120. data/ext/libsass/src/values.cpp +137 -0
  121. data/ext/libsass/src/values.hpp +12 -0
  122. data/ext/libsass/test/test_node.cpp +33 -33
  123. data/ext/libsass/test/test_paths.cpp +5 -6
  124. data/ext/libsass/test/test_selector_difference.cpp +4 -5
  125. data/ext/libsass/test/test_specificity.cpp +4 -5
  126. data/ext/libsass/test/test_subset_map.cpp +91 -91
  127. data/ext/libsass/test/test_superselector.cpp +11 -11
  128. data/ext/libsass/test/test_unification.cpp +4 -4
  129. data/ext/libsass/win/libsass.targets +101 -0
  130. data/ext/libsass/win/libsass.vcxproj +45 -127
  131. data/ext/libsass/win/libsass.vcxproj.filters +303 -0
  132. data/lib/sassc/import_handler.rb +1 -1
  133. data/lib/sassc/native/native_functions_api.rb +3 -3
  134. data/lib/sassc/version.rb +1 -1
  135. data/test/custom_importer_test.rb +1 -4
  136. data/test/functions_test.rb +3 -2
  137. data/test/native_test.rb +4 -3
  138. metadata +117 -110
  139. data/ext/libsass/Makefile.am +0 -146
  140. data/ext/libsass/ast.cpp +0 -945
  141. data/ext/libsass/ast_def_macros.hpp +0 -21
  142. data/ext/libsass/ast_factory.hpp +0 -92
  143. data/ext/libsass/color_names.hpp +0 -327
  144. data/ext/libsass/context.hpp +0 -157
  145. data/ext/libsass/contextualize.cpp +0 -148
  146. data/ext/libsass/contextualize.hpp +0 -46
  147. data/ext/libsass/contextualize_eval.cpp +0 -93
  148. data/ext/libsass/contextualize_eval.hpp +0 -44
  149. data/ext/libsass/debugger.hpp +0 -558
  150. data/ext/libsass/environment.hpp +0 -163
  151. data/ext/libsass/error_handling.cpp +0 -35
  152. data/ext/libsass/error_handling.hpp +0 -32
  153. data/ext/libsass/eval.cpp +0 -1392
  154. data/ext/libsass/eval.hpp +0 -88
  155. data/ext/libsass/expand.cpp +0 -575
  156. data/ext/libsass/memory_manager.hpp +0 -57
  157. data/ext/libsass/parser.cpp +0 -2403
  158. data/ext/libsass/posix/getopt.c +0 -562
  159. data/ext/libsass/posix/getopt.h +0 -95
  160. data/ext/libsass/to_c.cpp +0 -61
  161. data/ext/libsass/to_c.hpp +0 -44
  162. data/ext/libsass/to_string.cpp +0 -34
  163. data/ext/libsass/util.hpp +0 -54
  164. data/ext/libsass/win/libsass.filters +0 -312
@@ -0,0 +1,46 @@
1
+ #include "prelexer.hpp"
2
+ #include "backtrace.hpp"
3
+ #include "error_handling.hpp"
4
+
5
+ #include <iostream>
6
+
7
+ namespace Sass {
8
+
9
+ Error_Invalid::Error_Invalid(Type type, ParserState pstate, std::string message)
10
+ : type(type), pstate(pstate), message(message)
11
+ { }
12
+
13
+ void warn(std::string msg, ParserState pstate)
14
+ {
15
+ std::cerr << "Warning: " << msg<< std::endl;
16
+ }
17
+
18
+ void warn(std::string msg, ParserState pstate, Backtrace* bt)
19
+ {
20
+ Backtrace top(bt, pstate, "");
21
+ msg += top.to_string();
22
+ warn(msg, pstate);
23
+ }
24
+
25
+ void deprecated(std::string msg, ParserState pstate)
26
+ {
27
+ std::string cwd(Sass::File::get_cwd());
28
+ std::cerr << "DEPRECATION WARNING: " << msg << std::endl;
29
+ std::cerr << "will be an error in future versions of Sass." << std::endl;
30
+ std::string rel_path(Sass::File::resolve_relative_path(pstate.path, cwd, cwd));
31
+ std::cerr << " on line " << pstate.line+1 << " of " << rel_path << std::endl;
32
+ }
33
+
34
+ void error(std::string msg, ParserState pstate)
35
+ {
36
+ throw Error_Invalid(Error_Invalid::syntax, pstate, msg);
37
+ }
38
+
39
+ void error(std::string msg, ParserState pstate, Backtrace* bt)
40
+ {
41
+ Backtrace top(bt, pstate, "");
42
+ msg += "\n" + top.to_string();
43
+ error(msg, pstate);
44
+ }
45
+
46
+ }
@@ -0,0 +1,34 @@
1
+ #ifndef SASS_ERROR_HANDLING_H
2
+ #define SASS_ERROR_HANDLING_H
3
+
4
+ #include <string>
5
+
6
+ #include "position.hpp"
7
+
8
+ namespace Sass {
9
+
10
+ struct Backtrace;
11
+
12
+ struct Error_Invalid {
13
+ enum Type { read, write, syntax, evaluation };
14
+
15
+ Type type;
16
+ ParserState pstate;
17
+ std::string message;
18
+
19
+ Error_Invalid(Type type, ParserState pstate, std::string message);
20
+
21
+ };
22
+
23
+ void warn(std::string msg, ParserState pstate);
24
+ void warn(std::string msg, ParserState pstate, Backtrace* bt);
25
+
26
+ void deprecated(std::string msg, ParserState pstate);
27
+ // void deprecated(std::string msg, ParserState pstate, Backtrace* bt);
28
+
29
+ void error(std::string msg, ParserState pstate);
30
+ void error(std::string msg, ParserState pstate, Backtrace* bt);
31
+
32
+ }
33
+
34
+ #endif
@@ -0,0 +1,1462 @@
1
+ #include <cstdlib>
2
+ #include <cmath>
3
+ #include <iostream>
4
+ #include <sstream>
5
+ #include <iomanip>
6
+ #include <typeinfo>
7
+
8
+ #include "file.hpp"
9
+ #include "eval.hpp"
10
+ #include "ast.hpp"
11
+ #include "bind.hpp"
12
+ #include "util.hpp"
13
+ #include "to_string.hpp"
14
+ #include "inspect.hpp"
15
+ #include "environment.hpp"
16
+ #include "position.hpp"
17
+ #include "sass/values.h"
18
+ #include "to_value.hpp"
19
+ #include "to_c.hpp"
20
+ #include "context.hpp"
21
+ #include "backtrace.hpp"
22
+ #include "lexer.hpp"
23
+ #include "prelexer.hpp"
24
+ #include "parser.hpp"
25
+ #include "expand.hpp"
26
+ #include "color_maps.hpp"
27
+
28
+ namespace Sass {
29
+
30
+ inline double add(double x, double y) { return x + y; }
31
+ inline double sub(double x, double y) { return x - y; }
32
+ inline double mul(double x, double y) { return x * y; }
33
+ inline double div(double x, double y) { return x / y; } // x/0 checked by caller
34
+ inline double mod(double x, double y) { return std::abs(std::fmod(x, y)); } // x/0 checked by caller
35
+ typedef double (*bop)(double, double);
36
+ bop ops[Sass_OP::NUM_OPS] = {
37
+ 0, 0, // and, or
38
+ 0, 0, 0, 0, 0, 0, // eq, neq, gt, gte, lt, lte
39
+ add, sub, mul, div, mod
40
+ };
41
+
42
+ Eval::Eval(Expand& exp)
43
+ : exp(exp),
44
+ ctx(exp.ctx),
45
+ listize(exp.ctx)
46
+ { }
47
+ Eval::~Eval() { }
48
+
49
+ Context& Eval::context()
50
+ {
51
+ return ctx;
52
+ }
53
+
54
+ Env* Eval::environment()
55
+ {
56
+ return exp.environment();
57
+ }
58
+
59
+ Selector_List* Eval::selector()
60
+ {
61
+ return exp.selector();
62
+ }
63
+
64
+ Backtrace* Eval::backtrace()
65
+ {
66
+ return exp.backtrace();
67
+ }
68
+
69
+ Expression* Eval::operator()(Block* b)
70
+ {
71
+ Expression* val = 0;
72
+ for (size_t i = 0, L = b->length(); i < L; ++i) {
73
+ val = (*b)[i]->perform(this);
74
+ if (val) return val;
75
+ }
76
+ return val;
77
+ }
78
+
79
+ Expression* Eval::operator()(Assignment* a)
80
+ {
81
+ Env* env = exp.environment();
82
+ std::string var(a->variable());
83
+ if (a->is_global()) {
84
+ if (a->is_default()) {
85
+ if (env->has_global(var)) {
86
+ Expression* e = dynamic_cast<Expression*>(env->get_global(var));
87
+ if (!e || e->concrete_type() == Expression::NULL_VAL) {
88
+ env->set_global(var, a->value()->perform(this));
89
+ }
90
+ }
91
+ else {
92
+ env->set_global(var, a->value()->perform(this));
93
+ }
94
+ }
95
+ else {
96
+ env->set_global(var, a->value()->perform(this));
97
+ }
98
+ }
99
+ else if (a->is_default()) {
100
+ if (env->has_lexical(var)) {
101
+ auto cur = env;
102
+ while (cur && cur->is_lexical()) {
103
+ if (cur->has_local(var)) {
104
+ if (AST_Node* node = cur->get_local(var)) {
105
+ Expression* e = dynamic_cast<Expression*>(node);
106
+ if (!e || e->concrete_type() == Expression::NULL_VAL) {
107
+ cur->set_local(var, a->value()->perform(this));
108
+ }
109
+ }
110
+ else {
111
+ throw std::runtime_error("Env not in sync");
112
+ }
113
+ return 0;
114
+ }
115
+ cur = cur->parent();
116
+ }
117
+ throw std::runtime_error("Env not in sync");
118
+ }
119
+ else if (env->has_global(var)) {
120
+ if (AST_Node* node = env->get_global(var)) {
121
+ Expression* e = dynamic_cast<Expression*>(node);
122
+ if (!e || e->concrete_type() == Expression::NULL_VAL) {
123
+ env->set_global(var, a->value()->perform(this));
124
+ }
125
+ }
126
+ }
127
+ else if (env->is_lexical()) {
128
+ env->set_local(var, a->value()->perform(this));
129
+ }
130
+ else {
131
+ env->set_local(var, a->value()->perform(this));
132
+ }
133
+ }
134
+ else {
135
+ env->set_lexical(var, a->value()->perform(this));
136
+ }
137
+ return 0;
138
+ }
139
+
140
+ Expression* Eval::operator()(If* i)
141
+ {
142
+ Expression* rv = 0;
143
+ Env env(exp.environment());
144
+ exp.env_stack.push_back(&env);
145
+ if (*i->predicate()->perform(this)) {
146
+ rv = i->block()->perform(this);
147
+ }
148
+ else {
149
+ Block* alt = i->alternative();
150
+ if (alt) rv = alt->perform(this);
151
+ }
152
+ exp.env_stack.pop_back();
153
+ return rv;
154
+ }
155
+
156
+ // For does not create a new env scope
157
+ // But iteration vars are reset afterwards
158
+ Expression* Eval::operator()(For* f)
159
+ {
160
+ std::string variable(f->variable());
161
+ Expression* low = f->lower_bound()->perform(this);
162
+ if (low->concrete_type() != Expression::NUMBER) {
163
+ error("lower bound of `@for` directive must be numeric", low->pstate());
164
+ }
165
+ Expression* high = f->upper_bound()->perform(this);
166
+ if (high->concrete_type() != Expression::NUMBER) {
167
+ error("upper bound of `@for` directive must be numeric", high->pstate());
168
+ }
169
+ Number* sass_start = static_cast<Number*>(low);
170
+ Number* sass_end = static_cast<Number*>(high);
171
+ // check if units are valid for sequence
172
+ if (sass_start->unit() != sass_end->unit()) {
173
+ std::stringstream msg; msg << "Incompatible units: '"
174
+ << sass_start->unit() << "' and '"
175
+ << sass_end->unit() << "'.";
176
+ error(msg.str(), low->pstate(), backtrace());
177
+ }
178
+ double start = sass_start->value();
179
+ double end = sass_end->value();
180
+ // only create iterator once in this environment
181
+ Env* env = exp.environment();
182
+ Number* it = SASS_MEMORY_NEW(env->mem, Number, low->pstate(), start, sass_end->unit());
183
+ AST_Node* old_var = env->has_local(variable) ? env->get_local(variable) : 0;
184
+ env->set_local(variable, it);
185
+ Block* body = f->block();
186
+ Expression* val = 0;
187
+ if (start < end) {
188
+ if (f->is_inclusive()) ++end;
189
+ for (double i = start;
190
+ i < end;
191
+ ++i) {
192
+ it->value(i);
193
+ env->set_local(variable, it);
194
+ val = body->perform(this);
195
+ if (val) break;
196
+ }
197
+ } else {
198
+ if (f->is_inclusive()) --end;
199
+ for (double i = start;
200
+ i > end;
201
+ --i) {
202
+ it->value(i);
203
+ env->set_local(variable, it);
204
+ val = body->perform(this);
205
+ if (val) break;
206
+ }
207
+ }
208
+ // restore original environment
209
+ if (!old_var) env->del_local(variable);
210
+ else env->set_local(variable, old_var);
211
+ return val;
212
+ }
213
+
214
+ // Eval does not create a new env scope
215
+ // But iteration vars are reset afterwards
216
+ Expression* Eval::operator()(Each* e)
217
+ {
218
+ std::vector<std::string> variables(e->variables());
219
+ Expression* expr = e->list()->perform(this);
220
+ Env* env = exp.environment();
221
+ List* list = 0;
222
+ Map* map = 0;
223
+ if (expr->concrete_type() == Expression::MAP) {
224
+ map = static_cast<Map*>(expr);
225
+ }
226
+ else if (expr->concrete_type() != Expression::LIST) {
227
+ list = SASS_MEMORY_NEW(ctx.mem, List, expr->pstate(), 1, SASS_COMMA);
228
+ *list << expr;
229
+ }
230
+ else {
231
+ list = static_cast<List*>(expr);
232
+ }
233
+ // remember variables and then reset them
234
+ std::vector<AST_Node*> old_vars(variables.size());
235
+ for (size_t i = 0, L = variables.size(); i < L; ++i) {
236
+ old_vars[i] = env->has_local(variables[i]) ? env->get_local(variables[i]) : 0;
237
+ env->set_local(variables[i], 0);
238
+ }
239
+ Block* body = e->block();
240
+ Expression* val = 0;
241
+
242
+ if (map) {
243
+ for (auto key : map->keys()) {
244
+ Expression* value = map->at(key);
245
+
246
+ if (variables.size() == 1) {
247
+ List* variable = SASS_MEMORY_NEW(ctx.mem, List, map->pstate(), 2, SASS_SPACE);
248
+ *variable << key;
249
+ *variable << value;
250
+ env->set_local(variables[0], variable);
251
+ } else {
252
+ env->set_local(variables[0], key);
253
+ env->set_local(variables[1], value);
254
+ }
255
+
256
+ val = body->perform(this);
257
+ if (val) break;
258
+ }
259
+ }
260
+ else {
261
+ bool arglist = list->is_arglist();
262
+ for (size_t i = 0, L = list->length(); i < L; ++i) {
263
+ Expression* e = (*list)[i];
264
+ // unwrap value if the expression is an argument
265
+ if (Argument* arg = dynamic_cast<Argument*>(e)) e = arg->value();
266
+ // check if we got passed a list of args (investigate)
267
+ if (List* scalars = dynamic_cast<List*>(e)) {
268
+ if (variables.size() == 1) {
269
+ Expression* var = scalars;
270
+ if (arglist) var = (*scalars)[0];
271
+ env->set_local(variables[0], var);
272
+ } else {
273
+ for (size_t j = 0, K = variables.size(); j < K; ++j) {
274
+ Expression* res = j >= scalars->length()
275
+ ? SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate())
276
+ : (*scalars)[j];
277
+ env->set_local(variables[j], res);
278
+ }
279
+ }
280
+ } else {
281
+ if (variables.size() > 0) {
282
+ env->set_local(variables[0], e);
283
+ for (size_t j = 1, K = variables.size(); j < K; ++j) {
284
+ Expression* res = SASS_MEMORY_NEW(ctx.mem, Null, expr->pstate());
285
+ env->set_local(variables[j], res);
286
+ }
287
+ }
288
+ }
289
+ val = body->perform(this);
290
+ if (val) break;
291
+ }
292
+ }
293
+ // restore original environment
294
+ for (size_t j = 0, K = variables.size(); j < K; ++j) {
295
+ if(!old_vars[j]) env->del_local(variables[j]);
296
+ else env->set_local(variables[j], old_vars[j]);
297
+ }
298
+ return val;
299
+ }
300
+
301
+ Expression* Eval::operator()(While* w)
302
+ {
303
+ Expression* pred = w->predicate();
304
+ Block* body = w->block();
305
+ while (*pred->perform(this)) {
306
+ Expression* val = body->perform(this);
307
+ if (val) return val;
308
+ }
309
+ return 0;
310
+ }
311
+
312
+ Expression* Eval::operator()(Return* r)
313
+ {
314
+ return r->value()->perform(this);
315
+ }
316
+
317
+ Expression* Eval::operator()(Warning* w)
318
+ {
319
+ Expression* message = w->message()->perform(this);
320
+ To_String to_string(&ctx);
321
+ Env* env = exp.environment();
322
+
323
+ // try to use generic function
324
+ if (env->has("@warn[f]")) {
325
+
326
+ Definition* def = static_cast<Definition*>((*env)["@warn[f]"]);
327
+ // Block* body = def->block();
328
+ // Native_Function func = def->native_function();
329
+ Sass_Function_Entry c_function = def->c_function();
330
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
331
+
332
+ To_C to_c;
333
+ union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
334
+ sass_list_set_value(c_args, 0, message->perform(&to_c));
335
+ union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
336
+ sass_delete_value(c_args);
337
+ sass_delete_value(c_val);
338
+ return 0;
339
+
340
+ }
341
+
342
+ std::string result(unquote(message->perform(&to_string)));
343
+ Backtrace top(backtrace(), w->pstate(), "");
344
+ std::cerr << "WARNING: " << result;
345
+ std::cerr << top.to_string(true);
346
+ std::cerr << std::endl << std::endl;
347
+ return 0;
348
+ }
349
+
350
+ Expression* Eval::operator()(Error* e)
351
+ {
352
+ Expression* message = e->message()->perform(this);
353
+ To_String to_string(&ctx);
354
+ Env* env = exp.environment();
355
+
356
+ // try to use generic function
357
+ if (env->has("@error[f]")) {
358
+
359
+ Definition* def = static_cast<Definition*>((*env)["@error[f]"]);
360
+ // Block* body = def->block();
361
+ // Native_Function func = def->native_function();
362
+ Sass_Function_Entry c_function = def->c_function();
363
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
364
+
365
+ To_C to_c;
366
+ union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
367
+ sass_list_set_value(c_args, 0, message->perform(&to_c));
368
+ union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
369
+ sass_delete_value(c_args);
370
+ sass_delete_value(c_val);
371
+ return 0;
372
+
373
+ }
374
+
375
+ std::string result(unquote(message->perform(&to_string)));
376
+ error(result, e->pstate());
377
+ return 0;
378
+ }
379
+
380
+ Expression* Eval::operator()(Debug* d)
381
+ {
382
+ Expression* message = d->value()->perform(this);
383
+ To_String to_string(&ctx);
384
+ Env* env = exp.environment();
385
+
386
+ // try to use generic function
387
+ if (env->has("@debug[f]")) {
388
+
389
+ Definition* def = static_cast<Definition*>((*env)["@debug[f]"]);
390
+ // Block* body = def->block();
391
+ // Native_Function func = def->native_function();
392
+ Sass_Function_Entry c_function = def->c_function();
393
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
394
+
395
+ To_C to_c;
396
+ union Sass_Value* c_args = sass_make_list(1, SASS_COMMA);
397
+ sass_list_set_value(c_args, 0, message->perform(&to_c));
398
+ union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
399
+ sass_delete_value(c_args);
400
+ sass_delete_value(c_val);
401
+ return 0;
402
+
403
+ }
404
+
405
+ std::string cwd(ctx.get_cwd());
406
+ std::string result(unquote(message->perform(&to_string)));
407
+ std::string rel_path(Sass::File::resolve_relative_path(d->pstate().path, cwd, cwd));
408
+ std::cerr << rel_path << ":" << d->pstate().line+1 << " DEBUG: " << result;
409
+ std::cerr << std::endl;
410
+ return 0;
411
+ }
412
+
413
+ Expression* Eval::operator()(List* l)
414
+ {
415
+ if (l->is_expanded()) return l;
416
+ List* ll = SASS_MEMORY_NEW(ctx.mem, List,
417
+ l->pstate(),
418
+ l->length(),
419
+ l->separator(),
420
+ l->is_arglist());
421
+ for (size_t i = 0, L = l->length(); i < L; ++i) {
422
+ *ll << (*l)[i]->perform(this);
423
+ }
424
+ ll->is_expanded(true);
425
+ return ll;
426
+ }
427
+
428
+ Expression* Eval::operator()(Map* m)
429
+ {
430
+ if (m->is_expanded()) return m;
431
+
432
+ // make sure we're not starting with duplicate keys.
433
+ // the duplicate key state will have been set in the parser phase.
434
+ if (m->has_duplicate_key()) {
435
+ To_String to_string(&ctx);
436
+ error("Duplicate key \"" + m->get_duplicate_key()->perform(&to_string) + "\" in map " + m->perform(&to_string) + ".", m->pstate());
437
+ }
438
+
439
+ Map* mm = SASS_MEMORY_NEW(ctx.mem, Map,
440
+ m->pstate(),
441
+ m->length());
442
+ for (auto key : m->keys()) {
443
+ Expression* ex_key = key->perform(this);
444
+ Expression* ex_val = m->at(key)->perform(this);
445
+ *mm << std::make_pair(ex_key, ex_val);
446
+ }
447
+
448
+ // check the evaluated keys aren't duplicates.
449
+ if (mm->has_duplicate_key()) {
450
+ To_String to_string(&ctx);
451
+ error("Duplicate key \"" + mm->get_duplicate_key()->perform(&to_string) + "\" in map " + mm->perform(&to_string) + ".", mm->pstate());
452
+ }
453
+
454
+ mm->is_expanded(true);
455
+ return mm;
456
+ }
457
+
458
+ Expression* Eval::operator()(Binary_Expression* b)
459
+ {
460
+ enum Sass_OP op_type = b->type();
461
+ // don't eval delayed expressions (the '/' when used as a separator)
462
+ if (op_type == Sass_OP::DIV && b->is_delayed()) return b;
463
+ b->is_delayed(false);
464
+ // if one of the operands is a '/' then make sure it's evaluated
465
+ Expression* lhs = b->left()->perform(this);
466
+ lhs->is_delayed(false);
467
+ while (typeid(*lhs) == typeid(Binary_Expression)) lhs = lhs->perform(this);
468
+
469
+ switch (op_type) {
470
+ case Sass_OP::AND:
471
+ return *lhs ? b->right()->perform(this) : lhs;
472
+ break;
473
+
474
+ case Sass_OP::OR:
475
+ return *lhs ? lhs : b->right()->perform(this);
476
+ break;
477
+
478
+ default:
479
+ break;
480
+ }
481
+ // not a logical connective, so go ahead and eval the rhs
482
+ Expression* rhs = b->right()->perform(this);
483
+ // maybe fully evaluate structure
484
+ if (op_type == Sass_OP::EQ ||
485
+ op_type == Sass_OP::NEQ ||
486
+ op_type == Sass_OP::GT ||
487
+ op_type == Sass_OP::GTE ||
488
+ op_type == Sass_OP::LT ||
489
+ op_type == Sass_OP::LTE)
490
+ {
491
+ rhs->is_expanded(false);
492
+ rhs->set_delayed(false);
493
+ rhs = rhs->perform(this);
494
+ }
495
+ else
496
+ {
497
+ // rhs->set_delayed(false);
498
+ // rhs = rhs->perform(this);
499
+ }
500
+
501
+ // upgrade string to number if possible (issue #948)
502
+ if (op_type == Sass_OP::DIV || op_type == Sass_OP::MUL) {
503
+ if (String_Constant* str = dynamic_cast<String_Constant*>(rhs)) {
504
+ std::string value(str->value());
505
+ const char* start = value.c_str();
506
+ if (Prelexer::sequence < Prelexer::number >(start) != 0) {
507
+ rhs = SASS_MEMORY_NEW(ctx.mem, Textual, rhs->pstate(), Textual::DIMENSION, str->value());
508
+ rhs->is_delayed(false); rhs = rhs->perform(this);
509
+ }
510
+ }
511
+ }
512
+
513
+ // see if it's a relational expression
514
+ switch(op_type) {
515
+ case Sass_OP::EQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), eq(lhs, rhs));
516
+ case Sass_OP::NEQ: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !eq(lhs, rhs));
517
+ case Sass_OP::GT: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs) && !eq(lhs, rhs));
518
+ case Sass_OP::GTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), !lt(lhs, rhs));
519
+ case Sass_OP::LT: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs));
520
+ case Sass_OP::LTE: return SASS_MEMORY_NEW(ctx.mem, Boolean, b->pstate(), lt(lhs, rhs) || eq(lhs, rhs));
521
+
522
+ default: break;
523
+ }
524
+
525
+ Expression::Concrete_Type l_type = lhs->concrete_type();
526
+ Expression::Concrete_Type r_type = rhs->concrete_type();
527
+
528
+ int precision = (int)ctx.precision;
529
+ bool compressed = ctx.output_style == COMPRESSED;
530
+ if (l_type == Expression::NUMBER && r_type == Expression::NUMBER) {
531
+ const Number* l_n = dynamic_cast<const Number*>(lhs);
532
+ const Number* r_n = dynamic_cast<const Number*>(rhs);
533
+ return op_numbers(ctx.mem, op_type, *l_n, *r_n, compressed, precision);
534
+ }
535
+ if (l_type == Expression::NUMBER && r_type == Expression::COLOR) {
536
+ const Number* l_n = dynamic_cast<const Number*>(lhs);
537
+ const Color* r_c = dynamic_cast<const Color*>(rhs);
538
+ return op_number_color(ctx.mem, op_type, *l_n, *r_c, compressed, precision);
539
+ }
540
+ if (l_type == Expression::COLOR && r_type == Expression::NUMBER) {
541
+ const Color* l_c = dynamic_cast<const Color*>(lhs);
542
+ const Number* r_n = dynamic_cast<const Number*>(rhs);
543
+ return op_color_number(ctx.mem, op_type, *l_c, *r_n, compressed, precision);
544
+ }
545
+ if (l_type == Expression::COLOR && r_type == Expression::COLOR) {
546
+ const Color* l_c = dynamic_cast<const Color*>(lhs);
547
+ const Color* r_c = dynamic_cast<const Color*>(rhs);
548
+ return op_colors(ctx.mem, op_type, *l_c, *r_c, compressed, precision);
549
+ }
550
+
551
+ To_Value to_value(ctx, ctx.mem);
552
+ Value* v_l = dynamic_cast<Value*>(lhs->perform(&to_value));
553
+ Value* v_r = dynamic_cast<Value*>(rhs->perform(&to_value));
554
+ Value* ex = op_strings(ctx.mem, op_type, *v_l, *v_r, compressed, precision);
555
+ if (String_Constant* str = dynamic_cast<String_Constant*>(ex))
556
+ {
557
+ if (str->concrete_type() != Expression::STRING) return ex;
558
+ String_Constant* lstr = dynamic_cast<String_Constant*>(lhs);
559
+ String_Constant* rstr = dynamic_cast<String_Constant*>(rhs);
560
+ if (String_Constant* org = lstr ? lstr : rstr)
561
+ { str->quote_mark(org->quote_mark()); }
562
+ }
563
+ return ex;
564
+
565
+ }
566
+
567
+ Expression* Eval::operator()(Unary_Expression* u)
568
+ {
569
+ Expression* operand = u->operand()->perform(this);
570
+ if (u->type() == Unary_Expression::NOT) {
571
+ Boolean* result = SASS_MEMORY_NEW(ctx.mem, Boolean, u->pstate(), (bool)*operand);
572
+ result->value(!result->value());
573
+ return result;
574
+ }
575
+ else if (operand->concrete_type() == Expression::NUMBER) {
576
+ Number* result = SASS_MEMORY_NEW(ctx.mem, Number, *static_cast<Number*>(operand));
577
+ result->value(u->type() == Unary_Expression::MINUS
578
+ ? -result->value()
579
+ : result->value());
580
+ return result;
581
+ }
582
+ else {
583
+ To_String to_string(&ctx);
584
+ // Special cases: +/- variables which evaluate to null ouput just +/-,
585
+ // but +/- null itself outputs the string
586
+ if (operand->concrete_type() == Expression::NULL_VAL && typeid(*(u->operand())) == typeid(Variable)) {
587
+ u->operand(SASS_MEMORY_NEW(ctx.mem, String_Quoted, u->pstate(), ""));
588
+ }
589
+ else u->operand(operand);
590
+ String_Constant* result = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
591
+ u->pstate(),
592
+ u->perform(&to_string));
593
+ return result;
594
+ }
595
+ // unreachable
596
+ return u;
597
+ }
598
+
599
+ Expression* Eval::operator()(Function_Call* c)
600
+ {
601
+ if (backtrace()->parent != NULL && backtrace()->depth() > Constants::MaxCallStack) {
602
+ std::ostringstream stm;
603
+ stm << "Stack depth exceeded max of " << Constants::MaxCallStack;
604
+ error(stm.str(), c->pstate(), backtrace());
605
+ }
606
+ std::string name(Util::normalize_underscores(c->name()));
607
+ std::string full_name(name + "[f]");
608
+ Arguments* args = c->arguments();
609
+ if (full_name != "if[f]") {
610
+ args = static_cast<Arguments*>(args->perform(this));
611
+ }
612
+
613
+ Env* env = environment();
614
+ if (!env->has(full_name)) {
615
+ if (!env->has("*[f]")) {
616
+ // just pass it through as a literal
617
+ Function_Call* lit = SASS_MEMORY_NEW(ctx.mem, Function_Call,
618
+ c->pstate(),
619
+ c->name(),
620
+ args);
621
+ To_String to_string(&ctx);
622
+ if (args->has_named_arguments()) {
623
+ error("Function " + c->name() + " doesn't support keyword arguments", c->pstate());
624
+ }
625
+ return SASS_MEMORY_NEW(ctx.mem, String_Quoted,
626
+ c->pstate(),
627
+ lit->perform(&to_string));
628
+ } else {
629
+ // call generic function
630
+ full_name = "*[f]";
631
+ }
632
+ }
633
+
634
+ Definition* def = static_cast<Definition*>((*env)[full_name]);
635
+
636
+ if (def->is_overload_stub()) {
637
+ std::stringstream ss;
638
+ ss << full_name
639
+ << args->length();
640
+ full_name = ss.str();
641
+ std::string resolved_name(full_name);
642
+ if (!env->has(resolved_name)) error("overloaded function `" + std::string(c->name()) + "` given wrong number of arguments", c->pstate());
643
+ def = static_cast<Definition*>((*env)[resolved_name]);
644
+ }
645
+
646
+ Expression* result = c;
647
+ Block* body = def->block();
648
+ Native_Function func = def->native_function();
649
+ Sass_Function_Entry c_function = def->c_function();
650
+
651
+ Parameters* params = def->parameters();
652
+ Env fn_env(def->environment());
653
+ exp.env_stack.push_back(&fn_env);
654
+
655
+ if (func || body) {
656
+ bind("function " + c->name(), params, args, ctx, &fn_env, this);
657
+ Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`");
658
+ exp.backtrace_stack.push_back(&here);
659
+ // if it's user-defined, eval the body
660
+ if (body) result = body->perform(this);
661
+ // if it's native, invoke the underlying CPP function
662
+ else result = func(fn_env, *env, ctx, def->signature(), c->pstate(), backtrace());
663
+ if (!result) error(std::string("function ") + c->name() + " did not return a value", c->pstate());
664
+ exp.backtrace_stack.pop_back();
665
+ }
666
+
667
+ // else if it's a user-defined c function
668
+ // convert call into C-API compatible form
669
+ else if (c_function) {
670
+ Sass_Function_Fn c_func = sass_function_get_function(c_function);
671
+ if (full_name == "*[f]") {
672
+ String_Quoted *str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, c->pstate(), c->name());
673
+ Arguments* new_args = SASS_MEMORY_NEW(ctx.mem, Arguments, c->pstate());
674
+ *new_args << SASS_MEMORY_NEW(ctx.mem, Argument, c->pstate(), str);
675
+ *new_args += args;
676
+ args = new_args;
677
+ }
678
+
679
+ // populates env with default values for params
680
+ bind("function " + c->name(), params, args, ctx, &fn_env, this);
681
+
682
+ Backtrace here(backtrace(), c->pstate(), ", in function `" + c->name() + "`");
683
+ exp.backtrace_stack.push_back(&here);
684
+
685
+ To_C to_c;
686
+ union Sass_Value* c_args = sass_make_list(params[0].length(), SASS_COMMA);
687
+ for(size_t i = 0; i < params[0].length(); i++) {
688
+ std::string key = params[0][i]->name();
689
+ AST_Node* node = fn_env.get_local(key);
690
+ Expression* arg = static_cast<Expression*>(node);
691
+ sass_list_set_value(c_args, i, arg->perform(&to_c));
692
+ }
693
+ union Sass_Value* c_val = c_func(c_args, c_function, ctx.c_options);
694
+ if (sass_value_get_tag(c_val) == SASS_ERROR) {
695
+ error("error in C function " + c->name() + ": " + sass_error_get_message(c_val), c->pstate(), backtrace());
696
+ } else if (sass_value_get_tag(c_val) == SASS_WARNING) {
697
+ error("warning in C function " + c->name() + ": " + sass_warning_get_message(c_val), c->pstate(), backtrace());
698
+ }
699
+ result = cval_to_astnode(ctx.mem, c_val, ctx, backtrace(), c->pstate());
700
+
701
+ exp.backtrace_stack.pop_back();
702
+ sass_delete_value(c_args);
703
+ if (c_val != c_args)
704
+ sass_delete_value(c_val);
705
+ }
706
+
707
+ // link back to function definition
708
+ // only do this for custom functions
709
+ if (result->pstate().file == std::string::npos)
710
+ result->pstate(c->pstate());
711
+
712
+ result->is_delayed(result->concrete_type() == Expression::STRING);
713
+ if (!result->is_delayed()) result = result->perform(this);
714
+ exp.env_stack.pop_back();
715
+ return result;
716
+ }
717
+
718
+ Expression* Eval::operator()(Function_Call_Schema* s)
719
+ {
720
+ Expression* evaluated_name = s->name()->perform(this);
721
+ Expression* evaluated_args = s->arguments()->perform(this);
722
+ String_Schema* ss = SASS_MEMORY_NEW(ctx.mem, String_Schema, s->pstate(), 2);
723
+ (*ss) << evaluated_name << evaluated_args;
724
+ return ss->perform(this);
725
+ }
726
+
727
+ Expression* Eval::operator()(Variable* v)
728
+ {
729
+ To_String to_string(&ctx);
730
+ std::string name(v->name());
731
+ Expression* value = 0;
732
+ Env* env = environment();
733
+ if (env->has(name)) value = static_cast<Expression*>((*env)[name]);
734
+ else error("Undefined variable: \"" + v->name() + "\".", v->pstate());
735
+ // std::cerr << "name: " << v->name() << "; type: " << typeid(*value).name() << "; value: " << value->perform(&to_string) << std::endl;
736
+ if (typeid(*value) == typeid(Argument)) value = static_cast<Argument*>(value)->value();
737
+
738
+ // behave according to as ruby sass (add leading zero)
739
+ if (value->concrete_type() == Expression::NUMBER) {
740
+ value = SASS_MEMORY_NEW(ctx.mem, Number, *static_cast<Number*>(value));
741
+ static_cast<Number*>(value)->zero(true);
742
+ }
743
+ else if (value->concrete_type() == Expression::STRING) {
744
+ if (auto str = dynamic_cast<String_Quoted*>(value)) {
745
+ value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, *str);
746
+ } else if (auto str = dynamic_cast<String_Constant*>(value)) {
747
+ value = SASS_MEMORY_NEW(ctx.mem, String_Quoted, str->pstate(), str->perform(&to_string));
748
+ }
749
+ }
750
+ else if (value->concrete_type() == Expression::LIST) {
751
+ value = SASS_MEMORY_NEW(ctx.mem, List, *static_cast<List*>(value));
752
+ }
753
+ else if (value->concrete_type() == Expression::MAP) {
754
+ value = SASS_MEMORY_NEW(ctx.mem, Map, *static_cast<Map*>(value));
755
+ }
756
+ else if (value->concrete_type() == Expression::BOOLEAN) {
757
+ value = SASS_MEMORY_NEW(ctx.mem, Boolean, *static_cast<Boolean*>(value));
758
+ }
759
+ else if (value->concrete_type() == Expression::COLOR) {
760
+ value = SASS_MEMORY_NEW(ctx.mem, Color, *static_cast<Color*>(value));
761
+ }
762
+ else if (value->concrete_type() == Expression::NULL_VAL) {
763
+ value = SASS_MEMORY_NEW(ctx.mem, Null, value->pstate());
764
+ }
765
+ else if (value->concrete_type() == Expression::SELECTOR) {
766
+ value = value->perform(this)->perform(&listize);
767
+ }
768
+
769
+ // std::cerr << "\ttype is now: " << typeid(*value).name() << std::endl << std::endl;
770
+ return value;
771
+ }
772
+
773
+ Expression* Eval::operator()(Textual* t)
774
+ {
775
+ using Prelexer::number;
776
+ Expression* result = 0;
777
+ bool zero = !( t->value().substr(0, 1) == "." ||
778
+ t->value().substr(0, 2) == "-." );
779
+
780
+ const std::string& text = t->value();
781
+ size_t num_pos = text.find_first_not_of(" \n\r\t");
782
+ if (num_pos == std::string::npos) num_pos = text.length();
783
+ size_t unit_pos = text.find_first_not_of("-+0123456789.", num_pos);
784
+ if (unit_pos == std::string::npos) unit_pos = text.length();
785
+ const std::string& num = text.substr(num_pos, unit_pos - num_pos);
786
+
787
+ switch (t->type())
788
+ {
789
+ case Textual::NUMBER:
790
+ result = SASS_MEMORY_NEW(ctx.mem, Number,
791
+ t->pstate(),
792
+ sass_atof(num.c_str()),
793
+ "",
794
+ zero);
795
+ break;
796
+ case Textual::PERCENTAGE:
797
+ result = SASS_MEMORY_NEW(ctx.mem, Number,
798
+ t->pstate(),
799
+ sass_atof(num.c_str()),
800
+ "%",
801
+ zero);
802
+ break;
803
+ case Textual::DIMENSION:
804
+ result = SASS_MEMORY_NEW(ctx.mem, Number,
805
+ t->pstate(),
806
+ sass_atof(num.c_str()),
807
+ Token(number(text.c_str())),
808
+ zero);
809
+ break;
810
+ case Textual::HEX: {
811
+ if (t->value().substr(0, 1) != "#") {
812
+ result = SASS_MEMORY_NEW(ctx.mem, String_Quoted, t->pstate(), t->value());
813
+ break;
814
+ }
815
+ std::string hext(t->value().substr(1)); // chop off the '#'
816
+ if (hext.length() == 6) {
817
+ std::string r(hext.substr(0,2));
818
+ std::string g(hext.substr(2,2));
819
+ std::string b(hext.substr(4,2));
820
+ result = SASS_MEMORY_NEW(ctx.mem, Color,
821
+ t->pstate(),
822
+ static_cast<double>(strtol(r.c_str(), NULL, 16)),
823
+ static_cast<double>(strtol(g.c_str(), NULL, 16)),
824
+ static_cast<double>(strtol(b.c_str(), NULL, 16)),
825
+ 1, true,
826
+ t->value());
827
+ }
828
+ else {
829
+ result = SASS_MEMORY_NEW(ctx.mem, Color,
830
+ t->pstate(),
831
+ static_cast<double>(strtol(std::string(2,hext[0]).c_str(), NULL, 16)),
832
+ static_cast<double>(strtol(std::string(2,hext[1]).c_str(), NULL, 16)),
833
+ static_cast<double>(strtol(std::string(2,hext[2]).c_str(), NULL, 16)),
834
+ 1, false,
835
+ t->value());
836
+ }
837
+ } break;
838
+ }
839
+ return result;
840
+ }
841
+
842
+ Expression* Eval::operator()(Number* n)
843
+ {
844
+ return n;
845
+ }
846
+
847
+ Expression* Eval::operator()(Boolean* b)
848
+ {
849
+ return b;
850
+ }
851
+
852
+ char is_quoted(std::string str)
853
+ {
854
+ size_t len = str.length();
855
+ if (len < 2) return 0;
856
+ if ((str[0] == '"' && str[len-1] == '"') || (str[0] == '\'' && str[len-1] == '\'')) {
857
+ return str[0];
858
+ }
859
+ else {
860
+ return 0;
861
+ }
862
+ }
863
+
864
+ std::string Eval::interpolation(Expression* s, bool into_quotes) {
865
+ Env* env = environment();
866
+ if (String_Quoted* str_quoted = dynamic_cast<String_Quoted*>(s)) {
867
+ if (str_quoted->quote_mark()) {
868
+ if (str_quoted->quote_mark() == '*' || str_quoted->is_delayed()) {
869
+ return evacuate_escapes(str_quoted->value());
870
+ } else {
871
+ return string_escape(quote(str_quoted->value(), str_quoted->quote_mark()));
872
+ }
873
+ } else {
874
+ return evacuate_escapes(str_quoted->value());
875
+ }
876
+ } else if (String_Constant* str_constant = dynamic_cast<String_Constant*>(s)) {
877
+ if (into_quotes && !str_constant->is_interpolant()) return str_constant->value();
878
+ return evacuate_escapes(str_constant->value());
879
+ } else if (dynamic_cast<Parent_Selector*>(s)) {
880
+ To_String to_string(&ctx);
881
+ Expression* sel = s->perform(this);
882
+ return evacuate_quotes(sel ? sel->perform(&to_string) : "");
883
+
884
+ } else if (String_Schema* str_schema = dynamic_cast<String_Schema*>(s)) {
885
+ // To_String to_string(&ctx);
886
+ // return evacuate_quotes(str_schema->perform(&to_string));
887
+
888
+ std::string res = "";
889
+ for(auto i : str_schema->elements())
890
+ res += (interpolation(i));
891
+ //ToDo: do this in one step
892
+ auto esc = evacuate_escapes(res);
893
+ auto unq = unquote(esc);
894
+ if (unq == esc) {
895
+ return string_to_output(res);
896
+ } else {
897
+ return evacuate_quotes(unq);
898
+ }
899
+ } else if (List* list = dynamic_cast<List*>(s)) {
900
+ std::string acc = ""; // ToDo: different output styles
901
+ std::string sep = list->separator() == SASS_COMMA ? "," : " ";
902
+ if (ctx.output_style != COMPRESSED && sep == ",") sep += " ";
903
+ bool initial = false;
904
+ for(auto item : list->elements()) {
905
+ if (item->concrete_type() != Expression::NULL_VAL) {
906
+ if (initial) acc += sep;
907
+ acc += interpolation(item);
908
+ initial = true;
909
+ }
910
+ }
911
+ return evacuate_quotes(acc);
912
+ } else if (Variable* var = dynamic_cast<Variable*>(s)) {
913
+ std::string name(var->name());
914
+ if (!env->has(name)) error("Undefined variable: \"" + var->name() + "\".", var->pstate());
915
+ Expression* value = static_cast<Expression*>((*env)[name]);
916
+ return evacuate_quotes(interpolation(value));
917
+ } else if (dynamic_cast<Binary_Expression*>(s)) {
918
+ Expression* ex = s->perform(this);
919
+ return evacuate_quotes(interpolation(ex));
920
+ } else if (dynamic_cast<Function_Call*>(s)) {
921
+ Expression* ex = s->perform(this);
922
+ return evacuate_quotes(interpolation(ex));
923
+ } else if (dynamic_cast<Unary_Expression*>(s)) {
924
+ Expression* ex = s->perform(this);
925
+ return evacuate_quotes(interpolation(ex));
926
+ } else if (dynamic_cast<Map*>(s)) {
927
+ To_String to_string(&ctx);
928
+ std::string dbg(s->perform(&to_string));
929
+ error(dbg + " isn't a valid CSS value.", s->pstate());
930
+ return dbg;
931
+ } else {
932
+ To_String to_string(&ctx);
933
+ return evacuate_quotes(s->perform(&to_string));
934
+ }
935
+ }
936
+
937
+ Expression* Eval::operator()(String_Schema* s)
938
+ {
939
+ std::string acc;
940
+ bool into_quotes = false;
941
+ size_t L = s->length();
942
+ if (L > 1) {
943
+ if (String_Constant* l = dynamic_cast<String_Constant*>((*s)[0])) {
944
+ if (String_Constant* r = dynamic_cast<String_Constant*>((*s)[L - 1])) {
945
+ if (l->value()[0] == '"' && r->value()[r->value().size() - 1] == '"') into_quotes = true;
946
+ if (l->value()[0] == '\'' && r->value()[r->value().size() - 1] == '\'') into_quotes = true;
947
+ }
948
+ }
949
+ }
950
+ for (size_t i = 0; i < L; ++i) {
951
+ // really a very special fix, but this is the logic I got from
952
+ // analyzing the ruby sass behavior and it actually seems to work
953
+ // https://github.com/sass/libsass/issues/1333
954
+ if (i == 0 && L > 1 && dynamic_cast<Function_Call*>((*s)[i])) {
955
+ Expression* ex = (*s)[i]->perform(this);
956
+ if (auto sq = dynamic_cast<String_Quoted*>(ex)) {
957
+ if (sq->is_delayed() && ! s->has_interpolants()) {
958
+ acc += string_escape(quote(sq->value(), sq->quote_mark()));
959
+ } else {
960
+ acc += interpolation((*s)[i], into_quotes);
961
+ }
962
+ } else if (ex) {
963
+ acc += interpolation((*s)[i], into_quotes);
964
+ }
965
+ } else if ((*s)[i]) {
966
+ acc += interpolation((*s)[i], into_quotes);
967
+ }
968
+ }
969
+ String_Quoted* str = SASS_MEMORY_NEW(ctx.mem, String_Quoted, s->pstate(), acc);
970
+ if (!str->quote_mark()) {
971
+ str->value(string_unescape(str->value()));
972
+ } else if (str->quote_mark()) {
973
+ str->quote_mark('*');
974
+ }
975
+ str->is_delayed(true);
976
+ return str;
977
+ }
978
+
979
+ Expression* Eval::operator()(String_Constant* s)
980
+ {
981
+ if (!s->is_delayed() && name_to_color(s->value())) {
982
+ Color* c = SASS_MEMORY_NEW(ctx.mem, Color, *name_to_color(s->value()));
983
+ c->pstate(s->pstate());
984
+ c->disp(s->value());
985
+ return c;
986
+ }
987
+ return s;
988
+ }
989
+
990
+ Expression* Eval::operator()(String_Quoted* s)
991
+ {
992
+ return s;
993
+ }
994
+
995
+ Expression* Eval::operator()(Supports_Operator* c)
996
+ {
997
+ Expression* left = c->left()->perform(this);
998
+ Expression* right = c->right()->perform(this);
999
+ Supports_Operator* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Operator,
1000
+ c->pstate(),
1001
+ static_cast<Supports_Condition*>(left),
1002
+ static_cast<Supports_Condition*>(right),
1003
+ c->operand());
1004
+ return cc;
1005
+ }
1006
+
1007
+ Expression* Eval::operator()(Supports_Negation* c)
1008
+ {
1009
+ Expression* condition = c->condition()->perform(this);
1010
+ Supports_Negation* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Negation,
1011
+ c->pstate(),
1012
+ static_cast<Supports_Condition*>(condition));
1013
+ return cc;
1014
+ }
1015
+
1016
+ Expression* Eval::operator()(Supports_Declaration* c)
1017
+ {
1018
+ Expression* feature = c->feature()->perform(this);
1019
+ Expression* value = c->value()->perform(this);
1020
+ Supports_Declaration* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Declaration,
1021
+ c->pstate(),
1022
+ feature,
1023
+ value);
1024
+ return cc;
1025
+ }
1026
+
1027
+ Expression* Eval::operator()(Supports_Interpolation* c)
1028
+ {
1029
+ Expression* value = c->value()->perform(this);
1030
+ Supports_Interpolation* cc = SASS_MEMORY_NEW(ctx.mem, Supports_Interpolation,
1031
+ c->pstate(),
1032
+ value);
1033
+ return cc;
1034
+ }
1035
+
1036
+ Expression* Eval::operator()(At_Root_Expression* e)
1037
+ {
1038
+ Expression* feature = e->feature();
1039
+ feature = (feature ? feature->perform(this) : 0);
1040
+ Expression* value = e->value();
1041
+ value = (value ? value->perform(this) : 0);
1042
+ Expression* ee = SASS_MEMORY_NEW(ctx.mem, At_Root_Expression,
1043
+ e->pstate(),
1044
+ static_cast<String*>(feature),
1045
+ value,
1046
+ e->is_interpolated());
1047
+ return ee;
1048
+ }
1049
+
1050
+ Expression* Eval::operator()(Media_Query* q)
1051
+ {
1052
+ To_String to_string(&ctx);
1053
+ String* t = q->media_type();
1054
+ t = static_cast<String*>(t ? t->perform(this) : 0);
1055
+ Media_Query* qq = SASS_MEMORY_NEW(ctx.mem, Media_Query,
1056
+ q->pstate(),
1057
+ t,
1058
+ q->length(),
1059
+ q->is_negated(),
1060
+ q->is_restricted());
1061
+ for (size_t i = 0, L = q->length(); i < L; ++i) {
1062
+ *qq << static_cast<Media_Query_Expression*>((*q)[i]->perform(this));
1063
+ }
1064
+ return qq;
1065
+ }
1066
+
1067
+ Expression* Eval::operator()(Media_Query_Expression* e)
1068
+ {
1069
+ Expression* feature = e->feature();
1070
+ feature = (feature ? feature->perform(this) : 0);
1071
+ if (feature && dynamic_cast<String_Quoted*>(feature)) {
1072
+ feature = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
1073
+ feature->pstate(),
1074
+ dynamic_cast<String_Quoted*>(feature)->value());
1075
+ }
1076
+ Expression* value = e->value();
1077
+ value = (value ? value->perform(this) : 0);
1078
+ if (value && dynamic_cast<String_Quoted*>(value)) {
1079
+ value = SASS_MEMORY_NEW(ctx.mem, String_Quoted,
1080
+ value->pstate(),
1081
+ dynamic_cast<String_Quoted*>(value)->value());
1082
+ }
1083
+ return SASS_MEMORY_NEW(ctx.mem, Media_Query_Expression,
1084
+ e->pstate(),
1085
+ feature,
1086
+ value,
1087
+ e->is_interpolated());
1088
+ }
1089
+
1090
+ Expression* Eval::operator()(Null* n)
1091
+ {
1092
+ return n;
1093
+ }
1094
+
1095
+ Expression* Eval::operator()(Argument* a)
1096
+ {
1097
+ Expression* val = a->value();
1098
+ val->is_delayed(false);
1099
+ val = val->perform(this);
1100
+ val->is_delayed(false);
1101
+
1102
+ bool is_rest_argument = a->is_rest_argument();
1103
+ bool is_keyword_argument = a->is_keyword_argument();
1104
+
1105
+ if (a->is_rest_argument()) {
1106
+ if (val->concrete_type() == Expression::MAP) {
1107
+ is_rest_argument = false;
1108
+ is_keyword_argument = true;
1109
+ }
1110
+ else if(val->concrete_type() != Expression::LIST) {
1111
+ List* wrapper = SASS_MEMORY_NEW(ctx.mem, List,
1112
+ val->pstate(),
1113
+ 0,
1114
+ SASS_COMMA,
1115
+ true);
1116
+ *wrapper << val;
1117
+ val = wrapper;
1118
+ }
1119
+ }
1120
+ return SASS_MEMORY_NEW(ctx.mem, Argument,
1121
+ a->pstate(),
1122
+ val,
1123
+ a->name(),
1124
+ is_rest_argument,
1125
+ is_keyword_argument);
1126
+ }
1127
+
1128
+ Expression* Eval::operator()(Arguments* a)
1129
+ {
1130
+ Arguments* aa = SASS_MEMORY_NEW(ctx.mem, Arguments, a->pstate());
1131
+ for (size_t i = 0, L = a->length(); i < L; ++i) {
1132
+ *aa << static_cast<Argument*>((*a)[i]->perform(this));
1133
+ }
1134
+ return aa;
1135
+ }
1136
+
1137
+ Expression* Eval::operator()(Comment* c)
1138
+ {
1139
+ return 0;
1140
+ }
1141
+
1142
+ inline Expression* Eval::fallback_impl(AST_Node* n)
1143
+ {
1144
+ return static_cast<Expression*>(n);
1145
+ }
1146
+
1147
+ // All the binary helpers.
1148
+
1149
+ bool Eval::eq(Expression* lhs, Expression* rhs)
1150
+ {
1151
+ // use compare operator from ast node
1152
+ return lhs && rhs && *lhs == *rhs;
1153
+ }
1154
+
1155
+ bool Eval::lt(Expression* lhs, Expression* rhs)
1156
+ {
1157
+ Number* l = dynamic_cast<Number*>(lhs);
1158
+ Number* r = dynamic_cast<Number*>(rhs);
1159
+ if (!l) error("may only compare numbers", lhs->pstate());
1160
+ if (!r) error("may only compare numbers", rhs->pstate());
1161
+ // use compare operator from ast node
1162
+ return *l < *r;
1163
+ }
1164
+
1165
+ Value* Eval::op_numbers(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Number& r, bool compressed, int precision)
1166
+ {
1167
+ double lv = l.value();
1168
+ double rv = r.value();
1169
+ if (op == Sass_OP::DIV && !rv) {
1170
+ return SASS_MEMORY_NEW(mem, String_Quoted, l.pstate(), "Infinity");
1171
+ }
1172
+ if (op == Sass_OP::MOD && !rv) {
1173
+ error("division by zero", r.pstate());
1174
+ }
1175
+
1176
+ Number tmp(r);
1177
+ bool strict = op != Sass_OP::MUL && op != Sass_OP::DIV;
1178
+ tmp.normalize(l.find_convertible_unit(), strict);
1179
+ std::string l_unit(l.unit());
1180
+ std::string r_unit(tmp.unit());
1181
+ if (l_unit != r_unit && !l_unit.empty() && !r_unit.empty() &&
1182
+ (op == Sass_OP::ADD || op == Sass_OP::SUB)) {
1183
+ error("Incompatible units: '"+r_unit+"' and '"+l_unit+"'.", l.pstate());
1184
+ }
1185
+ Number* v = SASS_MEMORY_NEW(mem, Number, l);
1186
+ v->pstate(l.pstate());
1187
+ if (l_unit.empty() && (op == Sass_OP::ADD || op == Sass_OP::SUB || op == Sass_OP::MOD)) {
1188
+ v->numerator_units() = r.numerator_units();
1189
+ v->denominator_units() = r.denominator_units();
1190
+ }
1191
+
1192
+ if (op == Sass_OP::MUL) {
1193
+ v->value(ops[op](lv, rv));
1194
+ for (size_t i = 0, S = r.numerator_units().size(); i < S; ++i) {
1195
+ v->numerator_units().push_back(r.numerator_units()[i]);
1196
+ }
1197
+ for (size_t i = 0, S = r.denominator_units().size(); i < S; ++i) {
1198
+ v->denominator_units().push_back(r.denominator_units()[i]);
1199
+ }
1200
+ }
1201
+ else if (op == Sass_OP::DIV) {
1202
+ v->value(ops[op](lv, rv));
1203
+ for (size_t i = 0, S = r.numerator_units().size(); i < S; ++i) {
1204
+ v->denominator_units().push_back(r.numerator_units()[i]);
1205
+ }
1206
+ for (size_t i = 0, S = r.denominator_units().size(); i < S; ++i) {
1207
+ v->numerator_units().push_back(r.denominator_units()[i]);
1208
+ }
1209
+ } else {
1210
+ v->value(ops[op](lv, tmp.value()));
1211
+ }
1212
+ v->normalize();
1213
+ return v;
1214
+ }
1215
+
1216
+ Value* Eval::op_number_color(Memory_Manager& mem, enum Sass_OP op, const Number& l, const Color& rh, bool compressed, int precision)
1217
+ {
1218
+ Color r(rh);
1219
+ r.disp("");
1220
+ double lv = l.value();
1221
+ switch (op) {
1222
+ case Sass_OP::ADD:
1223
+ case Sass_OP::MUL: {
1224
+ return SASS_MEMORY_NEW(mem, Color,
1225
+ l.pstate(),
1226
+ ops[op](lv, r.r()),
1227
+ ops[op](lv, r.g()),
1228
+ ops[op](lv, r.b()),
1229
+ r.a());
1230
+ } break;
1231
+ case Sass_OP::SUB:
1232
+ case Sass_OP::DIV: {
1233
+ std::string sep(op == Sass_OP::SUB ? "-" : "/");
1234
+ std::string color(r.to_string(compressed||!r.sixtuplet(), precision));
1235
+ return SASS_MEMORY_NEW(mem, String_Quoted,
1236
+ l.pstate(),
1237
+ l.to_string(compressed, precision)
1238
+ + sep
1239
+ + color);
1240
+ } break;
1241
+ case Sass_OP::MOD: {
1242
+ error("cannot divide a number by a color", r.pstate());
1243
+ } break;
1244
+ default: break; // caller should ensure that we don't get here
1245
+ }
1246
+ // unreachable
1247
+ return SASS_MEMORY_NEW(mem, Color, rh);
1248
+ }
1249
+
1250
+ Value* Eval::op_color_number(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Number& r, bool compressed, int precision)
1251
+ {
1252
+ double rv = r.value();
1253
+ if (op == Sass_OP::DIV && !rv) error("division by zero", r.pstate());
1254
+ return SASS_MEMORY_NEW(mem, Color,
1255
+ l.pstate(),
1256
+ ops[op](l.r(), rv),
1257
+ ops[op](l.g(), rv),
1258
+ ops[op](l.b(), rv),
1259
+ l.a());
1260
+ }
1261
+
1262
+ Value* Eval::op_colors(Memory_Manager& mem, enum Sass_OP op, const Color& l, const Color& r, bool compressed, int precision)
1263
+ {
1264
+ if (l.a() != r.a()) {
1265
+ error("alpha channels must be equal when combining colors", r.pstate());
1266
+ }
1267
+ if (op == Sass_OP::DIV && (!r.r() || !r.g() ||!r.b())) {
1268
+ error("division by zero", r.pstate());
1269
+ }
1270
+ return SASS_MEMORY_NEW(mem, Color,
1271
+ l.pstate(),
1272
+ ops[op](l.r(), r.r()),
1273
+ ops[op](l.g(), r.g()),
1274
+ ops[op](l.b(), r.b()),
1275
+ l.a());
1276
+ }
1277
+
1278
+ Value* Eval::op_strings(Memory_Manager& mem, enum Sass_OP op, Value& lhs, Value& rhs, bool compressed, int precision)
1279
+ {
1280
+ Expression::Concrete_Type ltype = lhs.concrete_type();
1281
+ Expression::Concrete_Type rtype = rhs.concrete_type();
1282
+
1283
+ String_Quoted* lqstr = dynamic_cast<String_Quoted*>(&lhs);
1284
+ String_Quoted* rqstr = dynamic_cast<String_Quoted*>(&rhs);
1285
+
1286
+ std::string lstr(lqstr ? lqstr->value() : lhs.to_string(compressed, precision));
1287
+ std::string rstr(rqstr ? rqstr->value() : rhs.to_string(compressed, precision));
1288
+
1289
+ bool l_str_quoted = ((Sass::String*)&lhs) && ((Sass::String*)&lhs)->sass_fix_1291();
1290
+ bool r_str_quoted = ((Sass::String*)&rhs) && ((Sass::String*)&rhs)->sass_fix_1291();
1291
+ bool l_str_color = ltype == Expression::STRING && name_to_color(lstr) && !l_str_quoted;
1292
+ bool r_str_color = rtype == Expression::STRING && name_to_color(rstr) && !r_str_quoted;
1293
+
1294
+ if (l_str_color && r_str_color) {
1295
+ const Color* c_l = name_to_color(lstr);
1296
+ const Color* c_r = name_to_color(rstr);
1297
+ return op_colors(mem, op,*c_l, *c_r, compressed, precision);
1298
+ }
1299
+ else if (l_str_color && rtype == Expression::COLOR) {
1300
+ const Color* c_l = name_to_color(lstr);
1301
+ const Color* c_r = dynamic_cast<const Color*>(&rhs);
1302
+ return op_colors(mem, op, *c_l, *c_r, compressed, precision);
1303
+ }
1304
+ else if (ltype == Expression::COLOR && r_str_color) {
1305
+ const Color* c_l = dynamic_cast<const Color*>(&lhs);
1306
+ const Color* c_r = name_to_color(rstr);
1307
+ return op_colors(mem, op, *c_l, *c_r, compressed, precision);
1308
+ }
1309
+ else if (l_str_color && rtype == Expression::NUMBER) {
1310
+ const Color* c_l = name_to_color(lstr);
1311
+ const Number* n_r = dynamic_cast<const Number*>(&rhs);
1312
+ return op_color_number(mem, op, *c_l, *n_r, compressed, precision);
1313
+ }
1314
+ else if (ltype == Expression::NUMBER && r_str_color) {
1315
+ const Number* n_l = dynamic_cast<const Number*>(&lhs);
1316
+ const Color* c_r = name_to_color(rstr);
1317
+ return op_number_color(mem, op, *n_l, *c_r, compressed, precision);
1318
+ }
1319
+ if (op == Sass_OP::MUL) error("invalid operands for multiplication", lhs.pstate());
1320
+ if (op == Sass_OP::MOD) error("invalid operands for modulo", lhs.pstate());
1321
+ std::string sep;
1322
+ switch (op) {
1323
+ case Sass_OP::SUB: sep = "-"; break;
1324
+ case Sass_OP::DIV: sep = "/"; break;
1325
+ default: break;
1326
+ }
1327
+ if (ltype == Expression::NULL_VAL) error("Invalid null operation: \"null plus "+quote(unquote(rstr), '"')+"\".", lhs.pstate());
1328
+ if (rtype == Expression::NULL_VAL) error("Invalid null operation: \""+quote(unquote(lstr), '"')+" plus null\".", rhs.pstate());
1329
+
1330
+ if ( (ltype == Expression::STRING || sep == "") &&
1331
+ (sep != "/" || !rqstr || !rqstr->quote_mark())
1332
+ ) {
1333
+ char quote_mark = 0;
1334
+ std::string unq(unquote(lstr + sep + rstr, &quote_mark, true));
1335
+ if (quote_mark && quote_mark != '*') {
1336
+ return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), quote_mark + unq + quote_mark);
1337
+ }
1338
+ return SASS_MEMORY_NEW(mem, String_Quoted, lhs.pstate(), lstr + sep + rstr);
1339
+ }
1340
+ return SASS_MEMORY_NEW(mem, String_Constant, lhs.pstate(), (lstr) + sep + quote(rstr));
1341
+ }
1342
+
1343
+ Expression* cval_to_astnode(Memory_Manager& mem, union Sass_Value* v, Context& ctx, Backtrace* backtrace, ParserState pstate)
1344
+ {
1345
+ using std::strlen;
1346
+ using std::strcpy;
1347
+ Expression* e = 0;
1348
+ switch (sass_value_get_tag(v)) {
1349
+ case SASS_BOOLEAN: {
1350
+ e = SASS_MEMORY_NEW(mem, Boolean, pstate, !!sass_boolean_get_value(v));
1351
+ } break;
1352
+ case SASS_NUMBER: {
1353
+ e = SASS_MEMORY_NEW(mem, Number, pstate, sass_number_get_value(v), sass_number_get_unit(v));
1354
+ } break;
1355
+ case SASS_COLOR: {
1356
+ e = SASS_MEMORY_NEW(mem, Color, pstate, sass_color_get_r(v), sass_color_get_g(v), sass_color_get_b(v), sass_color_get_a(v));
1357
+ } break;
1358
+ case SASS_STRING: {
1359
+ if (sass_string_is_quoted(v))
1360
+ e = SASS_MEMORY_NEW(mem, String_Quoted, pstate, sass_string_get_value(v));
1361
+ else {
1362
+ e = SASS_MEMORY_NEW(mem, String_Constant, pstate, sass_string_get_value(v));
1363
+ }
1364
+ } break;
1365
+ case SASS_LIST: {
1366
+ List* l = SASS_MEMORY_NEW(mem, List, pstate, sass_list_get_length(v), sass_list_get_separator(v));
1367
+ for (size_t i = 0, L = sass_list_get_length(v); i < L; ++i) {
1368
+ *l << cval_to_astnode(mem, sass_list_get_value(v, i), ctx, backtrace, pstate);
1369
+ }
1370
+ e = l;
1371
+ } break;
1372
+ case SASS_MAP: {
1373
+ Map* m = SASS_MEMORY_NEW(mem, Map, pstate);
1374
+ for (size_t i = 0, L = sass_map_get_length(v); i < L; ++i) {
1375
+ *m << std::make_pair(
1376
+ cval_to_astnode(mem, sass_map_get_key(v, i), ctx, backtrace, pstate),
1377
+ cval_to_astnode(mem, sass_map_get_value(v, i), ctx, backtrace, pstate));
1378
+ }
1379
+ e = m;
1380
+ } break;
1381
+ case SASS_NULL: {
1382
+ e = SASS_MEMORY_NEW(mem, Null, pstate);
1383
+ } break;
1384
+ case SASS_ERROR: {
1385
+ error("Error in C function: " + std::string(sass_error_get_message(v)), pstate, backtrace);
1386
+ } break;
1387
+ case SASS_WARNING: {
1388
+ error("Warning in C function: " + std::string(sass_warning_get_message(v)), pstate, backtrace);
1389
+ } break;
1390
+ }
1391
+ return e;
1392
+ }
1393
+
1394
+ Selector_List* Eval::operator()(Selector_List* s)
1395
+ {
1396
+ std::vector<Selector_List*> rv;
1397
+ Selector_List* sl = SASS_MEMORY_NEW(ctx.mem, Selector_List, s->pstate());
1398
+ sl->media_block(s->media_block());
1399
+ for (size_t i = 0, iL = s->length(); i < iL; ++i) {
1400
+ rv.push_back(operator()((*s)[i]));
1401
+ }
1402
+
1403
+ // we should actually permutate parent first
1404
+ // but here we have permutated the selector first
1405
+ size_t round = 0;
1406
+ while (round != std::string::npos) {
1407
+ bool abort = true;
1408
+ for (size_t i = 0, iL = rv.size(); i < iL; ++i) {
1409
+ if (rv[i]->length() > round) {
1410
+ *sl << (*rv[i])[round];
1411
+ abort = false;
1412
+ }
1413
+ }
1414
+ if (abort) {
1415
+ round = std::string::npos;
1416
+ } else {
1417
+ ++ round;
1418
+ }
1419
+
1420
+ }
1421
+ return sl;
1422
+ }
1423
+
1424
+
1425
+ Selector_List* Eval::operator()(Complex_Selector* s)
1426
+ {
1427
+ return s->parentize(selector(), ctx);
1428
+
1429
+ }
1430
+
1431
+ Attribute_Selector* Eval::operator()(Attribute_Selector* s)
1432
+ {
1433
+ String* attr = s->value();
1434
+ if (attr) { attr = static_cast<String*>(attr->perform(this)); }
1435
+ Attribute_Selector* ss = SASS_MEMORY_NEW(ctx.mem, Attribute_Selector, *s);
1436
+ ss->value(attr);
1437
+ return ss;
1438
+ }
1439
+
1440
+ Selector_List* Eval::operator()(Selector_Schema* s)
1441
+ {
1442
+ To_String to_string;
1443
+ // the parser will look for a brace to end the selector
1444
+ std::string result_str(s->contents()->perform(this)->perform(&to_string) + "{");
1445
+ Parser p = Parser::from_c_str(result_str.c_str(), ctx, s->pstate());
1446
+ return operator()(p.parse_selector_list(exp.block_stack.back()->is_root()));
1447
+ }
1448
+
1449
+ Expression* Eval::operator()(Parent_Selector* p)
1450
+ {
1451
+ Selector_List* pr = selector();
1452
+ if (pr) {
1453
+ exp.selector_stack.pop_back();
1454
+ pr = operator()(pr);
1455
+ exp.selector_stack.push_back(pr);
1456
+ return pr;
1457
+ } else {
1458
+ return SASS_MEMORY_NEW(ctx.mem, Null, p->pstate());
1459
+ }
1460
+ }
1461
+
1462
+ }